From 37226273a7a5b2119daaab06d253f93b6813b881 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Nov 2014 13:23:40 +0530 Subject: init cargo --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/lib.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000000..a93251b65da --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +#[test] +fn it_works() { +} -- cgit 1.4.1-3-g733a5 From 92f13d823138ce3a22acef0db7818627ad5dee27 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Nov 2014 14:27:34 +0530 Subject: boxvec --- examples/boxvec.rs | 12 +++++++++++ src/lib.rs | 24 +++++++++++++++++++--- src/types.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 examples/boxvec.rs create mode 100644 src/types.rs (limited to 'src') diff --git a/examples/boxvec.rs b/examples/boxvec.rs new file mode 100644 index 00000000000..468da46f028 --- /dev/null +++ b/examples/boxvec.rs @@ -0,0 +1,12 @@ +#![feature(phase)] + +#[phase(plugin)] +extern crate rust_clippy; + +pub fn test(foo: Box>) { + println!("{}", foo) +} + +fn main(){ + test(box Vec::new()); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index a93251b65da..934232dceec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,21 @@ -#[test] -fn it_works() { -} +#![feature(globs, phase, plugin_registrar)] + + +#[phase(plugin,link)] +extern crate syntax; +#[phase(plugin, link)] +extern crate rustc; + + + +use rustc::plugin::Registry; +use rustc::lint::LintPassObject; + +pub mod types; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + //reg.register_syntax_extension(intern("jstraceable"), base::ItemDecorator(box expand_jstraceable)); + //reg.register_macro("factorial", expand) + reg.register_lint_pass(box types::TypePass as LintPassObject); +} \ No newline at end of file diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 00000000000..ffea017ec00 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,59 @@ + + +use syntax::ptr::P; +use syntax::ast; +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use syntax::codemap::Span; + + +pub struct TypePass; + +declare_lint!(CLIPPY_BOX_VEC, Warn, + "Warn on usage of Box>") + + +pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { + match ty.node { + TyPath(Path {segments: ref seg, ..}, _, _) => { + // So ast::Path isn't the full path, just the tokens that were provided. + // I could muck around with the maps and find the full path + // however the more efficient way is to simply reverse the iterators and zip them + // which will compare them in reverse until one of them runs out of segments + if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) { + match seg.as_slice().last() { + Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => { + Some(a.types.as_slice()) + } + _ => None + } + } else { + None + } + }, + _ => None + } +} + + +fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) { + cx.span_lint(lint, span, msg); + if cx.current_level(lint) != Level::Allow { + cx.sess().span_note(span, note); + } +} +impl LintPass for TypePass { + fn get_lints(&self) -> LintArray { + lint_array!(CLIPPY_BOX_VEC) + } + + fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { + match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.head()) + .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) + .map(|_| { + span_note_and_lint(cx, CLIPPY_BOX_VEC, ty.span, + "Detected Box>. Did you mean to use Vec?", + "Vec is already on the heap, Box> makes an extra allocation"); + }); + } +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 9341427b0ac71253395c8c177002a0c4e0bb274e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Nov 2014 14:32:47 +0530 Subject: docs --- src/types.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index ffea017ec00..930223de770 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,13 +6,13 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use syntax::codemap::Span; - +/// Handles all the linting of funky types pub struct TypePass; declare_lint!(CLIPPY_BOX_VEC, Warn, "Warn on usage of Box>") - +/// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { match ty.node { TyPath(Path {segments: ref seg, ..}, _, _) => { @@ -35,13 +35,14 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> } } - -fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) { +/// Lets me span a note only if the lint is shown +pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) { cx.span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { cx.sess().span_note(span, note); } } + impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(CLIPPY_BOX_VEC) -- cgit 1.4.1-3-g733a5 From 767bd168c19b261ee0952a5ae9c2b0858234cf0a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 19 Nov 2014 14:34:18 +0530 Subject: moar clippylike --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 930223de770..1b3c4f73c77 100644 --- a/src/types.rs +++ b/src/types.rs @@ -53,7 +53,7 @@ impl LintPass for TypePass { .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { span_note_and_lint(cx, CLIPPY_BOX_VEC, ty.span, - "Detected Box>. Did you mean to use Vec?", + "You seem to be trying to use Box>. Did you mean to use Vec?", "Vec is already on the heap, Box> makes an extra allocation"); }); } -- cgit 1.4.1-3-g733a5 From 542bfe357015e24504377c7347a8811797126ee3 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 20 Nov 2014 00:18:31 +0530 Subject: +match_if_let --- src/lib.rs | 7 ++++--- src/misc.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/misc.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 934232dceec..4528585c82c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ -#![feature(globs, phase, plugin_registrar)] +#![feature(globs, phase, plugin_registrar, if_let)] +#![allow(unused_imports)] #[phase(plugin,link)] extern crate syntax; @@ -12,10 +13,10 @@ use rustc::plugin::Registry; use rustc::lint::LintPassObject; pub mod types; +pub mod misc; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - //reg.register_syntax_extension(intern("jstraceable"), base::ItemDecorator(box expand_jstraceable)); - //reg.register_macro("factorial", expand) reg.register_lint_pass(box types::TypePass as LintPassObject); + reg.register_lint_pass(box misc::MiscPass as LintPassObject); } \ No newline at end of file diff --git a/src/misc.rs b/src/misc.rs new file mode 100644 index 00000000000..c70d4b48c1c --- /dev/null +++ b/src/misc.rs @@ -0,0 +1,46 @@ +use syntax::ptr::P; +use syntax::ast; +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use syntax::codemap::Span; + +use types::span_note_and_lint; + +/// Handles uncategorized lints +/// Currently handles linting of if-let-able matches +pub struct MiscPass; + + +declare_lint!(CLIPPY_SINGLE_MATCH, Warn, + "Warn on usage of matches with a single nontrivial arm") + +impl LintPass for MiscPass { + fn get_lints(&self) -> LintArray { + lint_array!(CLIPPY_SINGLE_MATCH) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprMatch(ref ex, ref arms, MatchNormal) = expr.node { + if arms.len() == 2 { + if arms[0].guard.is_none() && arms[1].pats.len() == 1 { + match arms[1].body.node { + ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (), + ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (), + _ => return + } + // In some cases, an exhaustive match is preferred to catch situations when + // an enum is extended. So we only consider cases where a `_` wildcard is used + if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { + let map = cx.sess().codemap(); + span_note_and_lint(cx, CLIPPY_SINGLE_MATCH, expr.span, + "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?", + format!("Try if let {} = {} {{ ... }}", + map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), + map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice() + ); + } + } + } + } + } +} -- cgit 1.4.1-3-g733a5 From ca7ad5fa805ee3e2ddd7181734ed0166fe168713 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 20 Nov 2014 12:37:37 +0530 Subject: Add DList lint (fixes #2) --- src/lib.rs | 3 ++- src/types.rs | 26 +++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4528585c82c..6166767378a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,8 @@ extern crate syntax; #[phase(plugin, link)] extern crate rustc; - +// Only for the compile time checking of paths +extern crate collections; use rustc::plugin::Registry; use rustc::lint::LintPassObject; diff --git a/src/types.rs b/src/types.rs index 1b3c4f73c77..625baec78fe 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,6 +11,8 @@ pub struct TypePass; declare_lint!(CLIPPY_BOX_VEC, Warn, "Warn on usage of Box>") +declare_lint!(CLIPPY_DLIST, Warn, + "Warn on usage of DList") /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { @@ -45,10 +47,15 @@ pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &s impl LintPass for TypePass { fn get_lints(&self) -> LintArray { - lint_array!(CLIPPY_BOX_VEC) + lint_array!(CLIPPY_BOX_VEC, CLIPPY_DLIST) } fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { + { + // In case stuff gets moved around + use std::boxed::Box; + use std::vec::Vec; + } match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.head()) .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { @@ -56,5 +63,22 @@ impl LintPass for TypePass { "You seem to be trying to use Box>. Did you mean to use Vec?", "Vec is already on the heap, Box> makes an extra allocation"); }); + { + // In case stuff gets moved around + use collections::dlist::DList as DL1; + use std::collections::dlist::DList as DL2; + use std::collections::DList as DL3; + } + let dlists = [vec!["std","collections","dlist","DList"], + vec!["std","collections","DList"], + vec!["collections","dlist","DList"]]; + for path in dlists.iter() { + if match_ty_unwrap(ty, path.as_slice()).is_some() { + span_note_and_lint(cx, CLIPPY_DLIST, ty.span, + "You seem to be trying to use a DList. Perhaps you meant some other data structure?", + "A RingBuf might work."); + return; + } + } } } \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 7bb411c239b219a063c065b744eec00dac11c6a4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 20 Nov 2014 12:38:27 +0530 Subject: more clippylike (from issue title) --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 625baec78fe..36513339f74 100644 --- a/src/types.rs +++ b/src/types.rs @@ -75,7 +75,7 @@ impl LintPass for TypePass { for path in dlists.iter() { if match_ty_unwrap(ty, path.as_slice()).is_some() { span_note_and_lint(cx, CLIPPY_DLIST, ty.span, - "You seem to be trying to use a DList. Perhaps you meant some other data structure?", + "I see you're using a DList! Perhaps you meant some other data structure?", "A RingBuf might work."); return; } -- cgit 1.4.1-3-g733a5 From 3a9fda7c7b0ef888298bffb71018e2a4dc26e877 Mon Sep 17 00:00:00 2001 From: Rohan Prinja Date: Thu, 4 Dec 2014 18:05:49 +0530 Subject: Path has only 2 fields now See also: https://github.com/phildawes/racer/pull/72 --- src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 36513339f74..c3fd333a5b8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,7 +17,7 @@ declare_lint!(CLIPPY_DLIST, Warn, /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { match ty.node { - TyPath(Path {segments: ref seg, ..}, _, _) => { + TyPath(Path {segments: ref seg, ..}, _) => { // So ast::Path isn't the full path, just the tokens that were provided. // I could muck around with the maps and find the full path // however the more efficient way is to simply reverse the iterators and zip them @@ -81,4 +81,4 @@ impl LintPass for TypePass { } } } -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From 98d88e7eb415000160b9c3f9c96b1b1907f638cb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 11 Dec 2014 03:04:58 +0530 Subject: rm if_let gate --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 6166767378a..380a530283c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(globs, phase, plugin_registrar, if_let)] +#![feature(globs, phase, plugin_registrar)] #![allow(unused_imports)] @@ -20,4 +20,4 @@ pub mod misc; pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); reg.register_lint_pass(box misc::MiscPass as LintPassObject); -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From 2703038f937f169090754c4b19ce7a3ddd457f05 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 15 Dec 2014 20:23:45 +0530 Subject: Add seanmonstar's StrToString lint --- README.md | 1 + src/lib.rs | 1 + src/misc.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) (limited to 'src') diff --git a/README.md b/README.md index 0e04459bbd1..91caaeba41a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Lints included in this crate: - `clippy_single_match`: Warns when a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used, and recommends `if let` instead. - `clippy_box_vec`: Warns on usage of `Box>` - `clippy_dlist`: Warns on usage of `DList` + - `clippy_str_to_string`: Warns on usage of `str::to_string()` More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/lib.rs b/src/lib.rs index 380a530283c..386e8180c22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,4 +20,5 @@ pub mod misc; pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); reg.register_lint_pass(box misc::MiscPass as LintPassObject); + reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); } diff --git a/src/misc.rs b/src/misc.rs index c70d4b48c1c..2a77ecc3467 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -2,6 +2,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr}; use syntax::codemap::Span; use types::span_note_and_lint; @@ -44,3 +45,39 @@ impl LintPass for MiscPass { } } } + + +declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()") + +pub struct StrToStringPass; + +impl LintPass for StrToStringPass { + fn get_lints(&self) -> LintArray { + lint_array!(CLIPPY_STR_TO_STRING) + } + + fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) { + match expr.node { + ast::ExprMethodCall(ref method, _, ref args) + if method.node.as_str() == "to_string" + && is_str(cx, &*args[0]) => { + cx.span_lint(CLIPPY_STR_TO_STRING, expr.span, "str.into_string() is faster"); + }, + _ => () + } + + fn is_str(cx: &Context, expr: &ast::Expr) -> bool { + fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { + //println!("{}: -> {}", depth, ty); + match ty.sty { + ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty), + _ => ty + } + } + match walk_ty(expr_ty(cx.tcx, expr)).sty { + ty_str => true, + _ => false + } + } + } +} -- cgit 1.4.1-3-g733a5 From 467b1ad9a44146e98fd86f6b0450c16d7b42468f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 19 Dec 2014 14:41:00 +0530 Subject: rustup --- src/misc.rs | 4 ++-- src/types.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 2a77ecc3467..68195994907 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -13,7 +13,7 @@ pub struct MiscPass; declare_lint!(CLIPPY_SINGLE_MATCH, Warn, - "Warn on usage of matches with a single nontrivial arm") + "Warn on usage of matches with a single nontrivial arm"); impl LintPass for MiscPass { fn get_lints(&self) -> LintArray { @@ -47,7 +47,7 @@ impl LintPass for MiscPass { } -declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()") +declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); pub struct StrToStringPass; diff --git a/src/types.rs b/src/types.rs index c3fd333a5b8..c418fdb7fe8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -10,9 +10,9 @@ use syntax::codemap::Span; pub struct TypePass; declare_lint!(CLIPPY_BOX_VEC, Warn, - "Warn on usage of Box>") + "Warn on usage of Box>"); declare_lint!(CLIPPY_DLIST, Warn, - "Warn on usage of DList") + "Warn on usage of DList"); /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { -- cgit 1.4.1-3-g733a5 From 1431fc04afe4e7cc2110fc9e9a59b0976b5e64ff Mon Sep 17 00:00:00 2001 From: Jonathan Castello Date: Wed, 24 Dec 2014 15:15:22 -0800 Subject: Implement a lint to check for args like `fn foo(ref x: u8)`, as the `ref` is effectively ignored by rustc. --- src/lib.rs | 5 +++-- src/misc.rs | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 386e8180c22..9ac74eb2320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ -#![feature(globs, phase, plugin_registrar)] +#![feature(globs, phase, plugin_registrar)] #![allow(unused_imports)] -#[phase(plugin,link)] +#[phase(plugin, link)] extern crate syntax; #[phase(plugin, link)] extern crate rustc; @@ -21,4 +21,5 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); + reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); } diff --git a/src/misc.rs b/src/misc.rs index 68195994907..47e8733abfb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,6 +1,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; +use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr}; use syntax::codemap::Span; @@ -38,7 +39,7 @@ impl LintPass for MiscPass { format!("Try if let {} = {} {{ ... }}", map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice() - ); + ); } } } @@ -81,3 +82,26 @@ impl LintPass for StrToStringPass { } } } + + +declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); + +pub struct TopLevelRefPass; + +impl LintPass for TopLevelRefPass { + fn get_lints(&self) -> LintArray { + lint_array!(CLIPPY_TOPLEVEL_REF_ARG) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + for ref arg in decl.inputs.iter() { + if let PatIdent(BindByRef(_), _, _) = arg.pat.node { + cx.span_lint( + CLIPPY_TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" + ); + } + } + } +} -- cgit 1.4.1-3-g733a5 From 39481a521c626148b88385dca5197af8b07358e3 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 26 Dec 2014 04:34:49 +0530 Subject: rustup (MatchSource rename, missing copy) --- src/misc.rs | 4 +++- src/types.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 68195994907..8c4fbe0597c 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -9,6 +9,7 @@ use types::span_note_and_lint; /// Handles uncategorized lints /// Currently handles linting of if-let-able matches +#[allow(missing_copy_implementations)] pub struct MiscPass; @@ -21,7 +22,7 @@ impl LintPass for MiscPass { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprMatch(ref ex, ref arms, MatchNormal) = expr.node { + if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { if arms.len() == 2 { if arms[0].guard.is_none() && arms[1].pats.len() == 1 { match arms[1].body.node { @@ -49,6 +50,7 @@ impl LintPass for MiscPass { declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); +#[allow(missing_copy_implementations)] pub struct StrToStringPass; impl LintPass for StrToStringPass { diff --git a/src/types.rs b/src/types.rs index c418fdb7fe8..f2bedad56a2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,6 +7,7 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use syntax::codemap::Span; /// Handles all the linting of funky types +#[allow(missing_copy_implementations)] pub struct TypePass; declare_lint!(CLIPPY_BOX_VEC, Warn, -- cgit 1.4.1-3-g733a5 From 32d060ae1134d05738824019dc79c29225b32308 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 26 Dec 2014 04:52:18 +0530 Subject: more rustup --- src/misc.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index c72f39ba315..4fb0a159a8b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -88,6 +88,7 @@ impl LintPass for StrToStringPass { declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); +#[allow(missing_copy_implementations)] pub struct TopLevelRefPass; impl LintPass for TopLevelRefPass { -- cgit 1.4.1-3-g733a5 From ccf996c348a9b591aad7f0b484dd02ac15a37b43 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 26 Dec 2014 05:12:05 +0530 Subject: clippy lint group --- src/lib.rs | 3 +++ src/misc.rs | 6 +++--- src/types.rs | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 9ac74eb2320..a70327c468b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,4 +22,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); + reg.register_lint_group("clippy", vec![types::CLIPPY_BOX_VEC, types::CLIPPY_DLIST, + misc::CLIPPY_SINGLE_MATCH, misc::CLIPPY_STR_TO_STRING, + misc::CLIPPY_TOPLEVEL_REF_ARG]); } diff --git a/src/misc.rs b/src/misc.rs index 4fb0a159a8b..77520e02da7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -14,7 +14,7 @@ use types::span_note_and_lint; pub struct MiscPass; -declare_lint!(CLIPPY_SINGLE_MATCH, Warn, +declare_lint!(pub CLIPPY_SINGLE_MATCH, Warn, "Warn on usage of matches with a single nontrivial arm"); impl LintPass for MiscPass { @@ -49,7 +49,7 @@ impl LintPass for MiscPass { } -declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); +declare_lint!(pub CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); #[allow(missing_copy_implementations)] pub struct StrToStringPass; @@ -86,7 +86,7 @@ impl LintPass for StrToStringPass { } -declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); +declare_lint!(pub CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); #[allow(missing_copy_implementations)] pub struct TopLevelRefPass; diff --git a/src/types.rs b/src/types.rs index f2bedad56a2..c189e1c389c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -10,9 +10,9 @@ use syntax::codemap::Span; #[allow(missing_copy_implementations)] pub struct TypePass; -declare_lint!(CLIPPY_BOX_VEC, Warn, +declare_lint!(pub CLIPPY_BOX_VEC, Warn, "Warn on usage of Box>"); -declare_lint!(CLIPPY_DLIST, Warn, +declare_lint!(pub CLIPPY_DLIST, Warn, "Warn on usage of DList"); /// Matches a type with a provided string, and returns its type parameters if successful -- cgit 1.4.1-3-g733a5 From e57396bc5212137b95e29664917f4383f8ca123f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 26 Dec 2014 05:24:44 +0530 Subject: Remove namespacing --- src/lib.rs | 6 +++--- src/misc.rs | 18 +++++++++--------- src/types.rs | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a70327c468b..3b556ff2c63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); - reg.register_lint_group("clippy", vec![types::CLIPPY_BOX_VEC, types::CLIPPY_DLIST, - misc::CLIPPY_SINGLE_MATCH, misc::CLIPPY_STR_TO_STRING, - misc::CLIPPY_TOPLEVEL_REF_ARG]); + reg.register_lint_group("clippy", vec![types::BOX_VEC, types::DLIST, + misc::SINGLE_MATCH, misc::STR_TO_STRING, + misc::TOPLEVEL_REF_ARG]); } diff --git a/src/misc.rs b/src/misc.rs index 77520e02da7..d69a7db0f55 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -14,12 +14,12 @@ use types::span_note_and_lint; pub struct MiscPass; -declare_lint!(pub CLIPPY_SINGLE_MATCH, Warn, +declare_lint!(pub SINGLE_MATCH, Warn, "Warn on usage of matches with a single nontrivial arm"); impl LintPass for MiscPass { fn get_lints(&self) -> LintArray { - lint_array!(CLIPPY_SINGLE_MATCH) + lint_array!(SINGLE_MATCH) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -35,7 +35,7 @@ impl LintPass for MiscPass { // an enum is extended. So we only consider cases where a `_` wildcard is used if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { let map = cx.sess().codemap(); - span_note_and_lint(cx, CLIPPY_SINGLE_MATCH, expr.span, + span_note_and_lint(cx, SINGLE_MATCH, expr.span, "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?", format!("Try if let {} = {} {{ ... }}", map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), @@ -49,14 +49,14 @@ impl LintPass for MiscPass { } -declare_lint!(pub CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); +declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); #[allow(missing_copy_implementations)] pub struct StrToStringPass; impl LintPass for StrToStringPass { fn get_lints(&self) -> LintArray { - lint_array!(CLIPPY_STR_TO_STRING) + lint_array!(STR_TO_STRING) } fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) { @@ -64,7 +64,7 @@ impl LintPass for StrToStringPass { ast::ExprMethodCall(ref method, _, ref args) if method.node.as_str() == "to_string" && is_str(cx, &*args[0]) => { - cx.span_lint(CLIPPY_STR_TO_STRING, expr.span, "str.into_string() is faster"); + cx.span_lint(STR_TO_STRING, expr.span, "str.into_string() is faster"); }, _ => () } @@ -86,21 +86,21 @@ impl LintPass for StrToStringPass { } -declare_lint!(pub CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); +declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); #[allow(missing_copy_implementations)] pub struct TopLevelRefPass; impl LintPass for TopLevelRefPass { fn get_lints(&self) -> LintArray { - lint_array!(CLIPPY_TOPLEVEL_REF_ARG) + lint_array!(TOPLEVEL_REF_ARG) } fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { for ref arg in decl.inputs.iter() { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { cx.span_lint( - CLIPPY_TOPLEVEL_REF_ARG, + TOPLEVEL_REF_ARG, arg.pat.span, "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" ); diff --git a/src/types.rs b/src/types.rs index c189e1c389c..8754c1348b1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -10,9 +10,9 @@ use syntax::codemap::Span; #[allow(missing_copy_implementations)] pub struct TypePass; -declare_lint!(pub CLIPPY_BOX_VEC, Warn, +declare_lint!(pub BOX_VEC, Warn, "Warn on usage of Box>"); -declare_lint!(pub CLIPPY_DLIST, Warn, +declare_lint!(pub DLIST, Warn, "Warn on usage of DList"); /// Matches a type with a provided string, and returns its type parameters if successful @@ -48,7 +48,7 @@ pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &s impl LintPass for TypePass { fn get_lints(&self) -> LintArray { - lint_array!(CLIPPY_BOX_VEC, CLIPPY_DLIST) + lint_array!(BOX_VEC, DLIST) } fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { @@ -60,7 +60,7 @@ impl LintPass for TypePass { match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.head()) .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { - span_note_and_lint(cx, CLIPPY_BOX_VEC, ty.span, + span_note_and_lint(cx, BOX_VEC, ty.span, "You seem to be trying to use Box>. Did you mean to use Vec?", "Vec is already on the heap, Box> makes an extra allocation"); }); @@ -75,7 +75,7 @@ impl LintPass for TypePass { vec!["collections","dlist","DList"]]; for path in dlists.iter() { if match_ty_unwrap(ty, path.as_slice()).is_some() { - span_note_and_lint(cx, CLIPPY_DLIST, ty.span, + span_note_and_lint(cx, DLIST, ty.span, "I see you're using a DList! Perhaps you meant some other data structure?", "A RingBuf might work."); return; -- cgit 1.4.1-3-g733a5 From b7ecb6e7c72e00fe377560baf3c971b7457219d4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 7 Jan 2015 09:35:34 +0530 Subject: rustup --- src/misc.rs | 2 +- src/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index d69a7db0f55..763c78bf278 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -3,7 +3,7 @@ use syntax::ast; use syntax::ast::*; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr}; +use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr}; use syntax::codemap::Span; use types::span_note_and_lint; diff --git a/src/types.rs b/src/types.rs index 8754c1348b1..17f030c950f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -57,7 +57,7 @@ impl LintPass for TypePass { use std::boxed::Box; use std::vec::Vec; } - match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.head()) + match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first()) .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { span_note_and_lint(cx, BOX_VEC, ty.span, -- cgit 1.4.1-3-g733a5 From 538db34e6028b89425a9d59e55d65d7ac6f1c556 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 10 Jan 2015 10:52:03 +0530 Subject: into_string() -> to_owned() (fix #27) --- src/misc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 763c78bf278..3fb88e431da 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -49,7 +49,7 @@ impl LintPass for MiscPass { } -declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()"); +declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()"); #[allow(missing_copy_implementations)] pub struct StrToStringPass; @@ -64,7 +64,7 @@ impl LintPass for StrToStringPass { ast::ExprMethodCall(ref method, _, ref args) if method.node.as_str() == "to_string" && is_str(cx, &*args[0]) => { - cx.span_lint(STR_TO_STRING, expr.span, "str.into_string() is faster"); + cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster"); }, _ => () } -- cgit 1.4.1-3-g733a5 From f428b18c47b1bf5385fd5178081df8abc4a2abe8 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 10 Jan 2015 11:56:58 +0530 Subject: rustup (fixes #28) --- examples/box_vec.rs | 10 +++++----- examples/dlist.rs | 7 ++++--- examples/match_if_let.rs | 11 +++++------ examples/toplevel_ref_arg.rs | 4 ++-- src/lib.rs | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/examples/box_vec.rs b/examples/box_vec.rs index acc47dd0fb5..874b9e8663c 100644 --- a/examples/box_vec.rs +++ b/examples/box_vec.rs @@ -1,12 +1,12 @@ -#![feature(phase)] +#![feature(plugin)] -#[phase(plugin)] +#[plugin] extern crate clippy; -pub fn test(foo: Box>) { - println!("{}", foo) +pub fn test(foo: Box>) { + println!("{:?}", foo.get(0)) } fn main(){ - test(box Vec::new()); + test(Box::new(Vec::new())); } \ No newline at end of file diff --git a/examples/dlist.rs b/examples/dlist.rs index 9efa92fd63a..05b71eabdcc 100644 --- a/examples/dlist.rs +++ b/examples/dlist.rs @@ -1,12 +1,13 @@ -#![feature(phase)] +#![feature(plugin)] -#[phase(plugin)] +#[plugin] extern crate clippy; + extern crate collections; use collections::dlist::DList; pub fn test(foo: DList) { - println!("{}", foo) + println!("{:?}", foo) } fn main(){ diff --git a/examples/match_if_let.rs b/examples/match_if_let.rs index b437424101d..5de96dd9951 100644 --- a/examples/match_if_let.rs +++ b/examples/match_if_let.rs @@ -1,23 +1,22 @@ -#![feature(phase)] +#![feature(plugin)] -#[phase(plugin)] +#[plugin] extern crate clippy; - fn main(){ let x = Some(1u); match x { - Some(y) => println!("{}", y), + Some(y) => println!("{:?}", y), _ => () } // Not linted match x { - Some(y) => println!("{}", y), + Some(y) => println!("{:?}", y), None => () } let z = (1u,1u); match z { - (2...3, 7...9) => println!("{}", z), + (2...3, 7...9) => println!("{:?}", z), _ => {} } } \ No newline at end of file diff --git a/examples/toplevel_ref_arg.rs b/examples/toplevel_ref_arg.rs index 4180ccce9aa..538e377c74f 100644 --- a/examples/toplevel_ref_arg.rs +++ b/examples/toplevel_ref_arg.rs @@ -1,6 +1,6 @@ -#![feature(phase)] +#![feature(plugin)] -#[phase(plugin)] +#[plugin] extern crate clippy; fn the_answer(ref mut x: u8) { diff --git a/src/lib.rs b/src/lib.rs index 3b556ff2c63..da79e5ce9e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ -#![feature(globs, phase, plugin_registrar)] +#![feature(plugin_registrar, box_syntax)] -#![allow(unused_imports)] +#![allow(unused_imports, unstable)] -#[phase(plugin, link)] +#[macro_use] extern crate syntax; -#[phase(plugin, link)] +#[macro_use] extern crate rustc; // Only for the compile time checking of paths -- cgit 1.4.1-3-g733a5 From 67701e00629ff2a0bb5a3b75628d23e102a95348 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 18 Feb 2015 17:54:22 +0530 Subject: -warnings --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index da79e5ce9e5..36802d1a329 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(plugin_registrar, box_syntax)] +#![feature(rustc_private, core, collections)] -#![allow(unused_imports, unstable)] +#![allow(unused_imports)] #[macro_use] extern crate syntax; -- cgit 1.4.1-3-g733a5 From 426a3ee1e7a9832d9f3cd1ac0aba0bcf5a3caa0d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 2 Mar 2015 16:13:44 +0530 Subject: Rustup --- examples/box_vec.rs | 3 +-- examples/dlist.rs | 9 ++++----- examples/match_if_let.rs | 5 ++--- examples/toplevel_ref_arg.rs | 3 +-- src/lib.rs | 2 +- src/types.rs | 22 +++++++++++----------- 6 files changed, 20 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/examples/box_vec.rs b/examples/box_vec.rs index 874b9e8663c..a93b53270bd 100644 --- a/examples/box_vec.rs +++ b/examples/box_vec.rs @@ -1,7 +1,6 @@ #![feature(plugin)] -#[plugin] -extern crate clippy; +#![plugin(clippy)] pub fn test(foo: Box>) { println!("{:?}", foo.get(0)) diff --git a/examples/dlist.rs b/examples/dlist.rs index 05b71eabdcc..d4c543b8e9f 100644 --- a/examples/dlist.rs +++ b/examples/dlist.rs @@ -1,15 +1,14 @@ #![feature(plugin)] -#[plugin] -extern crate clippy; +#![plugin(clippy)] extern crate collections; -use collections::dlist::DList; +use collections::linked_list::LinkedList; -pub fn test(foo: DList) { +pub fn test(foo: LinkedList) { println!("{:?}", foo) } fn main(){ - test(DList::new()); + test(LinkedList::new()); } \ No newline at end of file diff --git a/examples/match_if_let.rs b/examples/match_if_let.rs index 5de96dd9951..255bea7d73f 100644 --- a/examples/match_if_let.rs +++ b/examples/match_if_let.rs @@ -1,7 +1,6 @@ #![feature(plugin)] -#[plugin] -extern crate clippy; +#![plugin(clippy)] fn main(){ let x = Some(1u); @@ -19,4 +18,4 @@ fn main(){ (2...3, 7...9) => println!("{:?}", z), _ => {} } -} \ No newline at end of file +} diff --git a/examples/toplevel_ref_arg.rs b/examples/toplevel_ref_arg.rs index 538e377c74f..3ebb354142a 100644 --- a/examples/toplevel_ref_arg.rs +++ b/examples/toplevel_ref_arg.rs @@ -1,7 +1,6 @@ #![feature(plugin)] -#[plugin] -extern crate clippy; +#![plugin(clippy)] fn the_answer(ref mut x: u8) { *x = 42; diff --git a/src/lib.rs b/src/lib.rs index 36802d1a329..b3f395e5a13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); - reg.register_lint_group("clippy", vec![types::BOX_VEC, types::DLIST, + reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG]); } diff --git a/src/types.rs b/src/types.rs index 17f030c950f..dceae401a2e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -12,8 +12,8 @@ pub struct TypePass; declare_lint!(pub BOX_VEC, Warn, "Warn on usage of Box>"); -declare_lint!(pub DLIST, Warn, - "Warn on usage of DList"); +declare_lint!(pub LINKEDLIST, Warn, + "Warn on usage of LinkedList"); /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { @@ -48,7 +48,7 @@ pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &s impl LintPass for TypePass { fn get_lints(&self) -> LintArray { - lint_array!(BOX_VEC, DLIST) + lint_array!(BOX_VEC, LINKEDLIST) } fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { @@ -66,17 +66,17 @@ impl LintPass for TypePass { }); { // In case stuff gets moved around - use collections::dlist::DList as DL1; - use std::collections::dlist::DList as DL2; - use std::collections::DList as DL3; + use collections::linked_list::LinkedList as DL1; + use std::collections::linked_list::LinkedList as DL2; + use std::collections::linked_list::LinkedList as DL3; } - let dlists = [vec!["std","collections","dlist","DList"], - vec!["std","collections","DList"], - vec!["collections","dlist","DList"]]; + let dlists = [vec!["std","collections","linked_list","LinkedList"], + vec!["std","collections","linked_list","LinkedList"], + vec!["collections","linked_list","LinkedList"]]; for path in dlists.iter() { if match_ty_unwrap(ty, path.as_slice()).is_some() { - span_note_and_lint(cx, DLIST, ty.span, - "I see you're using a DList! Perhaps you meant some other data structure?", + span_note_and_lint(cx, LINKEDLIST, ty.span, + "I see you're using a LinkedList! Perhaps you meant some other data structure?", "A RingBuf might work."); return; } -- cgit 1.4.1-3-g733a5 From 2756ebe056e03aa38ef6048d800d035d13e61c5c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 13 Apr 2015 23:14:45 +0530 Subject: rustup --- src/types.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index dceae401a2e..c966c49be85 100644 --- a/src/types.rs +++ b/src/types.rs @@ -18,15 +18,15 @@ declare_lint!(pub LINKEDLIST, Warn, /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { match ty.node { - TyPath(Path {segments: ref seg, ..}, _) => { + TyPath(_, Path {segments: ref seg, ..}) => { // So ast::Path isn't the full path, just the tokens that were provided. // I could muck around with the maps and find the full path // however the more efficient way is to simply reverse the iterators and zip them // which will compare them in reverse until one of them runs out of segments if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) { - match seg.as_slice().last() { + match seg[..].last() { Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => { - Some(a.types.as_slice()) + Some(&a.types[..]) } _ => None } @@ -74,7 +74,7 @@ impl LintPass for TypePass { vec!["std","collections","linked_list","LinkedList"], vec!["collections","linked_list","LinkedList"]]; for path in dlists.iter() { - if match_ty_unwrap(ty, path.as_slice()).is_some() { + if match_ty_unwrap(ty, &path[..]).is_some() { span_note_and_lint(cx, LINKEDLIST, ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", "A RingBuf might work."); -- cgit 1.4.1-3-g733a5 From 2935c31692b49e5b2ffde2d33427a90be336eba6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 20 Apr 2015 16:18:35 +0530 Subject: rustup (rustc 1.0.0-nightly (00978a987 2015-04-18) (built 2015-04-19)) --- src/lib.rs | 2 +- src/misc.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index b3f395e5a13..ee137230f5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![feature(plugin_registrar, box_syntax)] -#![feature(rustc_private, core, collections)] +#![feature(rustc_private, collections)] #![allow(unused_imports)] diff --git a/src/misc.rs b/src/misc.rs index 3fb88e431da..04accaaa8bc 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -37,9 +37,9 @@ impl LintPass for MiscPass { let map = cx.sess().codemap(); span_note_and_lint(cx, SINGLE_MATCH, expr.span, "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?", - format!("Try if let {} = {} {{ ... }}", - map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), - map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice() + &*format!("Try if let {} = {} {{ ... }}", + &*map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), + &*map.span_to_snippet(ex.span).unwrap_or("..".to_string())) ); } } -- cgit 1.4.1-3-g733a5 From 441b55b328220cf02b0f7b2cb7a6e0f3e752aa56 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 30 Apr 2015 11:48:43 +0200 Subject: Added eq_op and bad_bit_mask from the extra_lints project (mostly plain copy, need to refactor to integrate better) --- Cargo.toml | 8 +- README.md | 14 +-- src/bit_mask.rs | 111 +++++++++++++++++++++ src/eq_op.rs | 214 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +- tests/compile-fail/bit_masks.rs | 19 ++++ tests/compile-fail/eq_op.rs | 36 +++++++ tests/compile-test.rs | 4 - 8 files changed, 398 insertions(+), 15 deletions(-) create mode 100644 src/bit_mask.rs create mode 100644 src/eq_op.rs create mode 100644 tests/compile-fail/bit_masks.rs create mode 100644 tests/compile-fail/eq_op.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 6a599adcc46..27ff93982b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] - name = "clippy" version = "0.0.1" -authors = ["Manish Goregaokar "] +authors = [ + "Manish Goregaokar ", + "Andre Bogus " +] [lib] name = "clippy" crate_type = ["dylib"] - - [dev-dependencies.compiletest] git = "https://github.com/laumann/compiletest-rs.git" diff --git a/README.md b/README.md index 12f7557a8d4..577de498dab 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ rust-clippy =========== -A collection of lints that give helpful tips to newbies. +A collection of lints that give helpful tips to newbies and catch oversights. Lints included in this crate: - - `clippy_single_match`: Warns when a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used, and recommends `if let` instead. - - `clippy_box_vec`: Warns on usage of `Box>` - - `clippy_dlist`: Warns on usage of `DList` - - `clippy_str_to_string`: Warns on usage of `str::to_string()` - - `clippy_toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`). + - `single_match`: Warns when a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used, and recommends `if let` instead. + - `box_vec`: Warns on usage of `Box>` + - `dlist`: Warns on usage of `DList` + - `str_to_string`: Warns on usage of `str::to_string()` + - `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`). + - `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination + - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) You can allow/warn/deny the whole set using the `clippy` lint group (`#[allow(clippy)]`, etc) diff --git a/src/bit_mask.rs b/src/bit_mask.rs new file mode 100644 index 00000000000..313bfb1ac0b --- /dev/null +++ b/src/bit_mask.rs @@ -0,0 +1,111 @@ +//! Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. This cannot work because the bit that makes up +//! the value two was zeroed out by the bit-and with 1. So the formula for detecting if an expression of the type +//! `_ m c` (where `` is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` ,`!=`, `>=`, +//! `>`}) can be determined from the following table: +//! +//! |Comparison |Bit-Op|Example |is always|Formula | +//! |------------|------|------------|---------|----------------------| +//! |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +//! |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +//! |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +//! |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +//! |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +//! |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +//! +//! *TODO*: There is the open question if things like `x | 1 > 1` should be caught by this lint, because it is basically +//! an obfuscated version of `x > 1`. +//! +//! This lint is **deny** by default + +use rustc::plugin::Registry; +use rustc::lint::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; + +declare_lint! { + pub BAD_BIT_MASK, + Deny, + "Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'" +} + +#[derive(Copy,Clone)] +pub struct BitMask; + +impl LintPass for BitMask { + fn get_lints(&self) -> LintArray { + lint_array!(BAD_BIT_MASK) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + if is_comparison_binop(cmp.node) { + fetch_int_literal(&right.node).map(|cmp_value| check_compare(cx, left, cmp.node, cmp_value, &e.span)); + } + } + } +} + +fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { + match &bit_op.node { + &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), + &ExprBinary(ref op, ref left, ref right) => { + if op.node != BiBitAnd && op.node != BiBitOr { return; } + if let Some(mask_value) = fetch_int_literal(&right.node) { + check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); + } else if let Some(mask_value) = fetch_int_literal(&left.node) { + check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); + } + }, + _ => () + } +} + +fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { + match cmp_op { + BiEq | BiNe => match bit_op { + BiBitAnd => if mask_value & cmp_value != mask_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value, + cmp_value)); + }, + BiBitOr => if mask_value | cmp_value != cmp_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value, + cmp_value)); + }, + _ => () + }, + BiLt | BiGe => match bit_op { + BiBitAnd => if mask_value < cmp_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value, + cmp_value)); + }, + BiBitOr => if mask_value >= cmp_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value, + cmp_value)); + }, + _ => () + }, + BiLe | BiGt => match bit_op { + BiBitAnd => if mask_value <= cmp_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value, + cmp_value)); + }, + BiBitOr => if mask_value > cmp_value { + cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value, + cmp_value)); + }, + _ => () + }, + _ => () + } +} + +fn fetch_int_literal(lit : &Expr_) -> Option { + if let &ExprLit(ref lit_ptr) = lit { + if let &LitInt(value, _) = &lit_ptr.node { + return Option::Some(value); //TODO: Handle sign + } + } + Option::None +} diff --git a/src/eq_op.rs b/src/eq_op.rs new file mode 100644 index 00000000000..e0b722a0a18 --- /dev/null +++ b/src/eq_op.rs @@ -0,0 +1,214 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::ast_util as ast_util; +use syntax::ptr::P; +use syntax::codemap as code; + +declare_lint! { + pub EQ_OP, + Warn, + "warn about comparing equal expressions (e.g. x == x)" +} + +#[derive(Copy,Clone)] +pub struct EqOp; + +impl LintPass for EqOp { + fn get_lints(&self) -> LintArray { + lint_array!(EQ_OP) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let ExprBinary(ref op, ref left, ref right) = e.node { + if is_cmp_or_bit(op) && is_exp_equal(left, right) { + cx.span_lint(EQ_OP, e.span, &format!("equal expressions as operands to {}", ast_util::binop_to_string(op.node))); + } + } + } +} + +fn is_exp_equal(left : &Expr, right : &Expr) -> bool { + match (&left.node, &right.node) { + (&ExprBinary(ref lop, ref ll, ref lr), &ExprBinary(ref rop, ref rl, ref rr)) => + lop.node == rop.node && is_exp_equal(ll, rl) && is_exp_equal(lr, rr), + (&ExprBox(ref lpl, ref lboxedpl), &ExprBox(ref rpl, ref rboxedpl)) => + both(lpl, rpl, |l, r| is_exp_equal(l, r)) && is_exp_equal(lboxedpl, rboxedpl), + (&ExprCall(ref lcallee, ref largs), &ExprCall(ref rcallee, ref rargs)) => + is_exp_equal(lcallee, rcallee) && is_exp_vec_equal(largs, rargs), + (&ExprCast(ref lcast, ref lty), &ExprCast(ref rcast, ref rty)) => + is_ty_equal(lty, rty) && is_exp_equal(lcast, rcast), + (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => + lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), + (&ExprLit(ref llit), &ExprLit(ref rlit)) => llit.node == rlit.node, + (&ExprMethodCall(ref lident, ref lcty, ref lmargs), &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => + lident.node == rident.node && is_ty_vec_equal(lcty, rcty) && is_exp_vec_equal(lmargs, rmargs), + (&ExprParen(ref lparen), &ExprParen(ref rparen)) => is_exp_equal(lparen, rparen), + (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), + (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), + (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => + both(lqself, rqself, |l, r| is_qself_equal(l, r)) && is_path_equal(lsubpath, rsubpath), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exp_vec_equal(ltup, rtup), + (&ExprUnary(lunop, ref lparam), &ExprUnary(runop, ref rparam)) => lunop == runop && is_exp_equal(lparam, rparam), + (&ExprVec(ref lvec), &ExprVec(ref rvec)) => is_exp_vec_equal(lvec, rvec), + _ => false + } +} + +fn is_exp_vec_equal(left : &Vec>, right : &Vec>) -> bool { + over(left, right, |l, r| is_exp_equal(l, r)) +} + +fn is_path_equal(left : &Path, right : &Path) -> bool { + left.global == right.global && left.segments == right.segments +} + +fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { + left.ty.node == right.ty.node && left.position == right.position +} + +fn is_ty_equal(left : &Ty, right : &Ty) -> bool { + match (&left.node, &right.node) { + (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), + (&TyFixedLengthVec(ref lfvty, ref lfvexp), &TyFixedLengthVec(ref rfvty, ref rfvexp)) => + is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), + (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => + both(ltime, rtime, is_lifetime_equal) && is_mut_ty_equal(lrmut, rrmut), + (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => is_bare_fn_ty_equal(lbare, rbare), + (&TyTup(ref ltup), &TyTup(ref rtup)) => is_ty_vec_equal(ltup, rtup), + (&TyPath(Option::None, ref lpath), &TyPath(Option::None, ref rpath)) => is_path_equal(lpath, rpath), + (&TyPath(Option::Some(ref lqself), ref lsubpath), &TyPath(Option::Some(ref rqself), ref rsubpath)) => + is_qself_equal(lqself, rqself) && is_path_equal(lsubpath, rsubpath), + (&TyObjectSum(ref lsumty, ref lobounds), &TyObjectSum(ref rsumty, ref robounds)) => + is_ty_equal(lsumty, rsumty) && is_param_bounds_equal(lobounds, robounds), + (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => is_param_bounds_equal(ltbounds, rtbounds), + (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), + (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof), + (&TyInfer, &TyInfer) => true, + _ => false + } +} + +fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) -> bool { + match(left, right) { + (&TraitTyParamBound(ref lpoly, ref lmod), &TraitTyParamBound(ref rpoly, ref rmod)) => + lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), + (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => is_lifetime_equal(ltime, rtime), + _ => false + } +} + +fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) -> bool { + is_lifetimedef_vec_equal(&left.bound_lifetimes, &right.bound_lifetimes) && + is_path_equal(&left.trait_ref.path, &right.trait_ref.path) +} + +fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) -> bool { + over(left, right, is_param_bound_equal) +} + +fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool { + left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty) +} + +fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { + left.unsafety == right.unsafety && left.abi == right.abi && + is_lifetimedef_vec_equal(&left.lifetimes, &right.lifetimes) && is_fndecl_equal(&left.decl, &right.decl) +} + +fn is_fndecl_equal(left : &P, right : &P) -> bool { + left.variadic == right.variadic && is_arg_vec_equal(&left.inputs, &right.inputs) && + is_fnret_ty_equal(&left.output, &right.output) +} + +fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) -> bool { + match (left, right) { + (&NoReturn(_), &NoReturn(_)) | (&DefaultReturn(_), &DefaultReturn(_)) => true, + (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), + _ => false + } +} + +fn is_arg_equal(left : &Arg, right : &Arg) -> bool { + is_ty_equal(&left.ty, &right.ty) && is_pat_equal(&left.pat, &right.pat) +} + +fn is_arg_vec_equal(left : &Vec, right : &Vec) -> bool { + over(left, right, is_arg_equal) +} + +fn is_pat_equal(left : &Pat, right : &Pat) -> bool { + match(&left.node, &right.node) { + (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, + (&PatIdent(ref lmode, ref lident, Option::None), &PatIdent(ref rmode, ref rident, Option::None)) => + lmode == rmode && is_ident_equal(&lident.node, &rident.node), + (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), + &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => + lmode == rmode && is_ident_equal(&lident.node, &rident.node) && is_pat_equal(lpat, rpat), + (&PatEnum(ref lpath, Option::None), &PatEnum(ref rpath, Option::None)) => is_path_equal(lpath, rpath), + (&PatEnum(ref lpath, Option::Some(ref lenum)), &PatEnum(ref rpath, Option::Some(ref renum))) => + is_path_equal(lpath, rpath) && is_pat_vec_equal(lenum, renum), + (&PatStruct(ref lpath, ref lfieldpat, lbool), &PatStruct(ref rpath, ref rfieldpat, rbool)) => + lbool == rbool && is_path_equal(lpath, rpath) && is_spanned_fieldpat_vec_equal(lfieldpat, rfieldpat), + (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pat_vec_equal(ltup, rtup), + (&PatBox(ref lboxed), &PatBox(ref rboxed)) => is_pat_equal(lboxed, rboxed), + (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => is_pat_equal(lpat, rpat) && lmut == rmut, + (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), + (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => + is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), + (&PatVec(ref lfirst, Option::None, ref llast), &PatVec(ref rfirst, Option::None, ref rlast)) => + is_pat_vec_equal(lfirst, rfirst) && is_pat_vec_equal(llast, rlast), + (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => + is_pat_vec_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && is_pat_vec_equal(llast, rlast), + // I don't match macros for now, the code is slow enough as is ;-) + _ => false + } +} + +fn is_spanned_fieldpat_vec_equal(left : &Vec>, right : &Vec>) -> bool { + over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) +} + +fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool { + left.is_shorthand == right.is_shorthand && is_ident_equal(&left.ident, &right.ident) && + is_pat_equal(&left.pat, &right.pat) +} + +fn is_ident_equal(left : &Ident, right : &Ident) -> bool { + &left.name == &right.name && left.ctxt == right.ctxt +} + +fn is_pat_vec_equal(left : &Vec>, right : &Vec>) -> bool { + over(left, right, |l, r| is_pat_equal(l, r)) +} + +fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) -> bool { + is_lifetime_equal(&left.lifetime, &right.lifetime) && over(&left.bounds, &right.bounds, is_lifetime_equal) +} + +fn is_lifetimedef_vec_equal(left : &Vec, right : &Vec) -> bool { + over(left, right, is_lifetimedef_equal) +} + +fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool { + left.name == right.name +} + +fn is_ty_vec_equal(left : &Vec>, right : &Vec>) -> bool { + over(left, right, |l, r| is_ty_equal(l, r)) +} + +fn over(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) +} + +fn both(l: &Option, r: &Option, mut eq_fn : F) -> bool where F: FnMut(&X, &X) -> bool { + if l.is_none() { r.is_none() } else { r.is_some() && eq_fn(l.as_ref().unwrap(), &r.as_ref().unwrap()) } +} + +fn is_cmp_or_bit(op : &BinOp) -> bool { + match op.node { + BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true, + _ => false + } +} diff --git a/src/lib.rs b/src/lib.rs index ee137230f5c..ad477a21042 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ use rustc::lint::LintPassObject; pub mod types; pub mod misc; +pub mod eq_op; +pub mod bit_mask; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -23,7 +25,10 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); + reg.register_lint_pass(box eq_op::EqOp as LintPassObject); + reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, - misc::TOPLEVEL_REF_ARG]); + misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, + bit_mask::BAD_BIT_MASK]); } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs new file mode 100644 index 00000000000..0c1fd348234 --- /dev/null +++ b/tests/compile-fail/bit_masks.rs @@ -0,0 +1,19 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(bad_bit_mask)] +fn main() { + let x = 5; + x & 1 == 1; //ok, distinguishes bit 0 + x & 2 == 1; //~ERROR + x | 1 == 3; //ok, equals x == 2 || x == 3 + x | 3 == 3; //ok, equals x <= 3 + x | 3 == 2; //~ERROR + + x & 1 > 1; //~ERROR + x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 + x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 + x | 1 > 1; // ok (if a bit silly), equals x > 1 + x | 2 > 1; //~ERROR + x | 2 <= 2; // ok (if a bit silly), equals x <= 2 +} diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs new file mode 100644 index 00000000000..910b5e84816 --- /dev/null +++ b/tests/compile-fail/eq_op.rs @@ -0,0 +1,36 @@ +#![feature(plugin)] +#![plugin(clippy)] + +fn id(x: X) -> X { + x +} + +#[deny(eq_op)] +fn main() { + // simple values and comparisons + 1 == 1; //~ERROR + "no" == "no"; //~ERROR + // even though I agree that no means no ;-) + false != false; //~ERROR + 1.5 < 1.5; //~ERROR + 1u64 >= 1u64; //~ERROR + + // casts, methods, parenthesis + (1 as u64) & (1 as u64); //~ERROR + 1 ^ ((((((1)))))); //~ERROR + id((1)) | id(1); //~ERROR + + // unary and binary operators + (-(2) < -(2)); //~ERROR + ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); + //~^ ERROR + //~^^ ERROR + //~^^^ ERROR + (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR + + // various other things + ([1] != [1]); //~ERROR + ((1, 2) != (1, 2)); //~ERROR + [1].len() == [1].len(); //~ERROR + vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros +} diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 3fd219dfb44..5008c2aa704 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,11 +1,8 @@ extern crate compiletest; -use std::env; -use std::process::Command; use std::path::PathBuf; fn run_mode(mode: &'static str) { - let mut config = compiletest::default_config(); let cfg_mode = mode.parse().ok().expect("Invalid mode"); config.target_rustcflags = Some("-L target/debug/".to_string()); @@ -19,5 +16,4 @@ fn run_mode(mode: &'static str) { #[test] fn compile_test() { run_mode("compile-fail"); - // run_mode("run-pass"); } -- cgit 1.4.1-3-g733a5 From 3a9bf24bb3d0fbcc8cabfecb03bb60c3cfa8babe Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 30 Apr 2015 15:17:06 +0200 Subject: Added constant lookup (with help from Manish) to bad_bit_mask --- src/bit_mask.rs | 31 ++++++++++++++++++++++--------- tests/compile-fail/bit_masks.rs | 9 ++++++++- 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 313bfb1ac0b..881eafa310e 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -19,6 +19,8 @@ use rustc::plugin::Registry; use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; @@ -41,7 +43,7 @@ impl LintPass for BitMask { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { - fetch_int_literal(&right.node).map(|cmp_value| check_compare(cx, left, cmp.node, cmp_value, &e.span)); + fetch_int_literal(cx, right).map(|cmp_value| check_compare(cx, left, cmp.node, cmp_value, &e.span)); } } } @@ -52,9 +54,9 @@ fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, sp &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), &ExprBinary(ref op, ref left, ref right) => { if op.node != BiBitAnd && op.node != BiBitOr { return; } - if let Some(mask_value) = fetch_int_literal(&right.node) { + if let Some(mask_value) = fetch_int_literal(cx, right) { check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); - } else if let Some(mask_value) = fetch_int_literal(&left.node) { + } else if let Some(mask_value) = fetch_int_literal(cx, left) { check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); } }, @@ -101,11 +103,22 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, } } -fn fetch_int_literal(lit : &Expr_) -> Option { - if let &ExprLit(ref lit_ptr) = lit { - if let &LitInt(value, _) = &lit_ptr.node { - return Option::Some(value); //TODO: Handle sign - } +fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option { + match &lit.node { + &ExprLit(ref lit_ptr) => { + if let &LitInt(value, _) = &lit_ptr.node { + Option::Some(value) //TODO: Handle sign + } else { Option::None } + }, + &ExprPath(_, _) => { + let def_map = cx.tcx.def_map.borrow(); + let path_res_op = def_map.get(&lit.id); + path_res_op.as_ref().and_then(|x| { + if let &DefConst(def_id) = &x.base_def { + lookup_const_by_id(cx.tcx, def_id, Option::None).and_then(|l| fetch_int_literal(cx, l)) + } else { Option::None } + }) + }, + _ => Option::None } - Option::None } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index 0c1fd348234..7cf8709c575 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -1,7 +1,10 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(bad_bit_mask)] +const THREE_BITS : i64 = 7; +const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; + +#[deny(bad_bit_mask)] fn main() { let x = 5; x & 1 == 1; //ok, distinguishes bit 0 @@ -16,4 +19,8 @@ fn main() { x | 1 > 1; // ok (if a bit silly), equals x > 1 x | 2 > 1; //~ERROR x | 2 <= 2; // ok (if a bit silly), equals x <= 2 + + // this also now works with constants + x & THREE_BITS == 8; //~ERROR + x | EVEN_MORE_REDIRECTION < 7; //~ERROR } -- cgit 1.4.1-3-g733a5 From 53fa76dff968787fc39e7a6b96059f151bab6b2e Mon Sep 17 00:00:00 2001 From: llogiq Date: Sat, 2 May 2015 00:35:49 +0200 Subject: new lint: needless_bool (TODO: The warnings could give more specific directions) --- README.md | 4 +-- src/lib.rs | 5 +++- src/needless_bool.rs | 51 +++++++++++++++++++++++++++++++++++++ tests/compile-fail/needless_bool.rs | 12 +++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/needless_bool.rs create mode 100644 tests/compile-fail/needless_bool.rs (limited to 'src') diff --git a/README.md b/README.md index 577de498dab..0fc9a6c8869 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ Lints included in this crate: - `box_vec`: Warns on usage of `Box>` - `dlist`: Warns on usage of `DList` - `str_to_string`: Warns on usage of `str::to_string()` - - `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`). + - `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) - `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) + - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` You can allow/warn/deny the whole set using the `clippy` lint group (`#[allow(clippy)]`, etc) - More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! Licensed under [MPL](https://www.mozilla.org/MPL/2.0/). If you're having issues with the license, let me know and I'll try to change it to something more permissive. diff --git a/src/lib.rs b/src/lib.rs index ad477a21042..ea8a3962810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub mod types; pub mod misc; pub mod eq_op; pub mod bit_mask; +pub mod needless_bool; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -27,8 +28,10 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); + reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, - bit_mask::BAD_BIT_MASK]); + bit_mask::BAD_BIT_MASK, + needless_bool::NEEDLESS_BOOL]); } diff --git a/src/needless_bool.rs b/src/needless_bool.rs new file mode 100644 index 00000000000..5b14e2fe1f3 --- /dev/null +++ b/src/needless_bool.rs @@ -0,0 +1,51 @@ +//! Checks for needless boolean results of if-else expressions +//! +//! This lint is **deny** by default + +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; + +declare_lint! { + pub NEEDLESS_BOOL, + Warn, + "Warn on needless use of if x { true } else { false } (or vice versa)" +} + +#[derive(Copy,Clone)] +pub struct NeedlessBool; + +impl LintPass for NeedlessBool { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_BOOL) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node { + match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { + (Option::Some(true), Option::Some(true)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "your if-then-else expression will always return true"); }, + (Option::Some(true), Option::Some(false)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "you can reduce your if-statement to its predicate"); }, + (Option::Some(false), Option::Some(true)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "you can reduce your if-statement to '!' + your predicate"); }, + (Option::Some(false), Option::Some(false)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "your if-then-else expression will always return false"); }, + _ => () + } + } + } +} + +fn fetch_bool_block(block: &Block) -> Option { + if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) } else { Option::None } +} + +fn fetch_bool_expr(expr: &Expr) -> Option { + match &expr.node { + &ExprBlock(ref block) => fetch_bool_block(block), + &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { Option::Some(value) } else { Option::None }, + _ => Option::None + } +} diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs new file mode 100644 index 00000000000..97a478ee410 --- /dev/null +++ b/tests/compile-fail/needless_bool.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(needless_bool)] +fn main() { + let x = true; + if x { true } else { true }; //~ERROR + if x { false } else { false }; //~ERROR + if x { true } else { false }; //~ERROR + if x { false } else { true }; //~ERROR + if x { x } else { false }; // would also be questionable, but we don't catch this yet +} -- cgit 1.4.1-3-g733a5 From 07adeee6e942a639af81f7cd4c035e066433cef0 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 4 May 2015 07:17:15 +0200 Subject: Added check for zero bitmask and uncommon directions, wrong comment in needless_bool corrected, added new lint vec_ptr_arg + test --- src/bit_mask.rs | 33 +++++++++++++++++++- src/lib.rs | 7 ++++- src/needless_bool.rs | 2 +- src/vec_ptr_arg.rs | 65 +++++++++++++++++++++++++++++++++++++++ tests/compile-fail/bit_masks.rs | 13 +++++++- tests/compile-fail/vec_ptr_arg.rs | 14 +++++++++ 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/vec_ptr_arg.rs create mode 100644 tests/compile-fail/vec_ptr_arg.rs (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 881eafa310e..d4cdc952661 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -43,12 +43,31 @@ impl LintPass for BitMask { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { - fetch_int_literal(cx, right).map(|cmp_value| check_compare(cx, left, cmp.node, cmp_value, &e.span)); + let cmp_opt = fetch_int_literal(cx, right); + if cmp_opt.is_some() { + check_compare(cx, left, cmp.node, cmp_opt.unwrap(), &e.span); + } else { + fetch_int_literal(cx, left).map(|cmp_val| + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, &e.span)); + } } } } } +fn invert_cmp(cmp : BinOp_) -> BinOp_ { + match cmp { + BiEq => BiEq, + BiNe => BiNe, + BiLt => BiGt, + BiGt => BiLt, + BiLe => BiGe, + BiGe => BiLe, + _ => BiOr // Dummy + } +} + + fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { match &bit_op.node { &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), @@ -70,6 +89,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, BiBitAnd => if mask_value & cmp_value != mask_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value, cmp_value)); + } else { + if mask_value == 0 { + cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + } }, BiBitOr => if mask_value | cmp_value != cmp_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value, @@ -81,6 +104,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, BiBitAnd => if mask_value < cmp_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value, cmp_value)); + } else { + if mask_value == 0 { + cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + } }, BiBitOr => if mask_value >= cmp_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value, @@ -92,6 +119,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, BiBitAnd => if mask_value <= cmp_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value, cmp_value)); + } else { + if mask_value == 0 { + cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + } }, BiBitOr => if mask_value > cmp_value { cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value, diff --git a/src/lib.rs b/src/lib.rs index ea8a3962810..a9faf199863 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub mod misc; pub mod eq_op; pub mod bit_mask; pub mod needless_bool; +pub mod vec_ptr_arg; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -29,9 +30,13 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box eq_op::EqOp as LintPassObject); reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); + reg.register_lint_pass(box vec_ptr_arg::VecPtrArg as LintPassObject); + reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, - needless_bool::NEEDLESS_BOOL]); + needless_bool::NEEDLESS_BOOL, + vec_ptr_arg::VEC_PTR_ARG + ]); } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 5b14e2fe1f3..fe35e6ee3bd 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -1,6 +1,6 @@ //! Checks for needless boolean results of if-else expressions //! -//! This lint is **deny** by default +//! This lint is **warn** by default use rustc::plugin::Registry; use rustc::lint::*; diff --git a/src/vec_ptr_arg.rs b/src/vec_ptr_arg.rs new file mode 100644 index 00000000000..88fdc5cf065 --- /dev/null +++ b/src/vec_ptr_arg.rs @@ -0,0 +1,65 @@ +//! Checks for usage of &Vec[_] and &String +//! +//! This lint is **warn** by default + +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; +use types::match_ty_unwrap; + +declare_lint! { + pub VEC_PTR_ARG, + Allow, + "Warn on declaration of a &Vec-typed method argument" +} + + +#[derive(Copy,Clone)] +pub struct VecPtrArg; + +impl LintPass for VecPtrArg { + fn get_lints(&self) -> LintArray { + lint_array!(VEC_PTR_ARG) + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + if let &ItemFn(ref decl, _, _, _, _) = &item.node { + check_fn(cx, decl); + } + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + if let &MethodImplItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + if let &MethodTraitItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } +} + +fn check_fn(cx: &Context, decl: &FnDecl) { + for arg in &decl.inputs { + let ty = &arg.ty; + match ty.node { + TyPtr(ref pty) => check_ptr_subtype(cx, ty.span, &pty.ty), + TyRptr(_, ref rpty) => check_ptr_subtype(cx, ty.span, &rpty.ty), + _ => () + } + } +} + +fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { + if match_ty_unwrap(ty, &["Vec"]).is_some() { + cx.span_lint(VEC_PTR_ARG, span, + "Writing '&Vec<_>' instead of '&[_]' involves one more reference and cannot be used with non-vec-based slices. Consider changing the type to &[...]"); + } +} diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index 7cf8709c575..b575dbc4e25 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -7,12 +7,15 @@ const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] fn main() { let x = 5; + + x & 0 == 0; //~ERROR &-masking with zero x & 1 == 1; //ok, distinguishes bit 0 x & 2 == 1; //~ERROR + x | 0 == 0; //ok, equals x == 0 (maybe warn?) x | 1 == 3; //ok, equals x == 2 || x == 3 x | 3 == 3; //ok, equals x <= 3 x | 3 == 2; //~ERROR - + x & 1 > 1; //~ERROR x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 @@ -23,4 +26,12 @@ fn main() { // this also now works with constants x & THREE_BITS == 8; //~ERROR x | EVEN_MORE_REDIRECTION < 7; //~ERROR + + 0 & x == 0; //~ERROR + 1 | x > 1; + + // and should now also match uncommon usage + 1 < 2 | x; //~ERROR + 2 == 3 | x; //~ERROR + 1 == x & 2; //~ERROR } diff --git a/tests/compile-fail/vec_ptr_arg.rs b/tests/compile-fail/vec_ptr_arg.rs new file mode 100644 index 00000000000..5c4338e356f --- /dev/null +++ b/tests/compile-fail/vec_ptr_arg.rs @@ -0,0 +1,14 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(vec_ptr_arg)] +#[allow(unused)] +fn go(x: &Vec) { //~ERROR: Writing '&Vec<_>' instead of '&[_]' + //Nothing here +} + + +fn main() { + let x = vec![1i64, 2, 3]; + go(&x); +} -- cgit 1.4.1-3-g733a5 From 8d2328d9a5ed45bf20739b0164dfad2bc97da9a7 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 4 May 2015 08:15:24 +0200 Subject: Added &String matching and renamed to vec_ptr_arg to ptr_arg, also added README section --- README.md | 3 ++ src/lib.rs | 9 +++-- src/ptr_arg.rs | 69 +++++++++++++++++++++++++++++++++++++++ src/vec_ptr_arg.rs | 65 ------------------------------------ tests/compile-fail/ptr_arg.rs | 20 ++++++++++++ tests/compile-fail/vec_ptr_arg.rs | 14 -------- 6 files changed, 96 insertions(+), 84 deletions(-) create mode 100644 src/ptr_arg.rs delete mode 100644 src/vec_ptr_arg.rs create mode 100644 tests/compile-fail/ptr_arg.rs delete mode 100644 tests/compile-fail/vec_ptr_arg.rs (limited to 'src') diff --git a/README.md b/README.md index 0fc9a6c8869..32249163211 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ Lints included in this crate: - `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` + - `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively + +In your code, you may add `#![plugin(clippy)]` to use it (you may also need to include a `#![feature(plugin)]` line) You can allow/warn/deny the whole set using the `clippy` lint group (`#[allow(clippy)]`, etc) diff --git a/src/lib.rs b/src/lib.rs index a9faf199863..8cf8650c80a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,8 @@ pub mod types; pub mod misc; pub mod eq_op; pub mod bit_mask; +pub mod ptr_arg; pub mod needless_bool; -pub mod vec_ptr_arg; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -29,14 +29,13 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); + reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); - reg.register_lint_pass(box vec_ptr_arg::VecPtrArg as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, - bit_mask::BAD_BIT_MASK, - needless_bool::NEEDLESS_BOOL, - vec_ptr_arg::VEC_PTR_ARG + bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, + needless_bool::NEEDLESS_BOOL ]); } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs new file mode 100644 index 00000000000..378d30de57a --- /dev/null +++ b/src/ptr_arg.rs @@ -0,0 +1,69 @@ +//! Checks for usage of &Vec[_] and &String +//! +//! This lint is **warn** by default + +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; +use types::match_ty_unwrap; + +declare_lint! { + pub PTR_ARG, + Allow, + "Warn on declaration of a &Vec- or &String-typed method argument" +} + + +#[derive(Copy,Clone)] +pub struct PtrArg; + +impl LintPass for PtrArg { + fn get_lints(&self) -> LintArray { + lint_array!(PTR_ARG) + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + if let &ItemFn(ref decl, _, _, _, _) = &item.node { + check_fn(cx, decl); + } + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + if let &MethodImplItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + if let &MethodTraitItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } +} + +fn check_fn(cx: &Context, decl: &FnDecl) { + for arg in &decl.inputs { + let ty = &arg.ty; + match ty.node { + TyPtr(ref pty) => check_ptr_subtype(cx, ty.span, &pty.ty), + TyRptr(_, ref rpty) => check_ptr_subtype(cx, ty.span, &rpty.ty), + _ => () + } + } +} + +fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { + if match_ty_unwrap(ty, &["Vec"]).is_some() { + cx.span_lint(PTR_ARG, span, + "Writing '&Vec<_>' instead of '&[_]' involves one more reference and cannot be used with non-vec-based slices. Consider changing the type to &[...]"); + } else { if match_ty_unwrap(ty, &["String"]).is_some() { + cx.span_lint(PTR_ARG, span, + "Writing '&String' instead of '&str' involves a new Object where a slices will do. Consider changing the type to &str"); + } + } +} diff --git a/src/vec_ptr_arg.rs b/src/vec_ptr_arg.rs deleted file mode 100644 index 88fdc5cf065..00000000000 --- a/src/vec_ptr_arg.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Checks for usage of &Vec[_] and &String -//! -//! This lint is **warn** by default - -use rustc::plugin::Registry; -use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; -use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; -use syntax::codemap::Span; -use types::match_ty_unwrap; - -declare_lint! { - pub VEC_PTR_ARG, - Allow, - "Warn on declaration of a &Vec-typed method argument" -} - - -#[derive(Copy,Clone)] -pub struct VecPtrArg; - -impl LintPass for VecPtrArg { - fn get_lints(&self) -> LintArray { - lint_array!(VEC_PTR_ARG) - } - - fn check_item(&mut self, cx: &Context, item: &Item) { - if let &ItemFn(ref decl, _, _, _, _) = &item.node { - check_fn(cx, decl); - } - } - - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { - if let &MethodImplItem(ref sig, _) = &item.node { - check_fn(cx, &sig.decl); - } - } - - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { - if let &MethodTraitItem(ref sig, _) = &item.node { - check_fn(cx, &sig.decl); - } - } -} - -fn check_fn(cx: &Context, decl: &FnDecl) { - for arg in &decl.inputs { - let ty = &arg.ty; - match ty.node { - TyPtr(ref pty) => check_ptr_subtype(cx, ty.span, &pty.ty), - TyRptr(_, ref rpty) => check_ptr_subtype(cx, ty.span, &rpty.ty), - _ => () - } - } -} - -fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { - if match_ty_unwrap(ty, &["Vec"]).is_some() { - cx.span_lint(VEC_PTR_ARG, span, - "Writing '&Vec<_>' instead of '&[_]' involves one more reference and cannot be used with non-vec-based slices. Consider changing the type to &[...]"); - } -} diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs new file mode 100644 index 00000000000..2fe36eafa6c --- /dev/null +++ b/tests/compile-fail/ptr_arg.rs @@ -0,0 +1,20 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(ptr_arg)] +#[allow(unused)] +fn do_vec(x: &Vec) { //~ERROR: Writing '&Vec<_>' instead of '&[_]' + //Nothing here +} + +#[deny(ptr_arg)] +#[allow(unused)] +fn do_str(x: &String) { //~ERROR + //Nothing here either +} + +fn main() { + let x = vec![1i64, 2, 3]; + do_vec(&x); + do_str(&"hello".to_owned()); +} diff --git a/tests/compile-fail/vec_ptr_arg.rs b/tests/compile-fail/vec_ptr_arg.rs deleted file mode 100644 index 5c4338e356f..00000000000 --- a/tests/compile-fail/vec_ptr_arg.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -#[deny(vec_ptr_arg)] -#[allow(unused)] -fn go(x: &Vec) { //~ERROR: Writing '&Vec<_>' instead of '&[_]' - //Nothing here -} - - -fn main() { - let x = vec![1i64, 2, 3]; - go(&x); -} -- cgit 1.4.1-3-g733a5 From 2cb84b9d15b0cf821fc6ad0b90fb7d731f4a1910 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 4 May 2015 12:01:34 +0200 Subject: New lint: approx_const --- README.md | 1 + src/approx_const.rs | 63 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 ++- tests/compile-fail/approx_const.rs | 56 +++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/approx_const.rs create mode 100644 tests/compile-fail/approx_const.rs (limited to 'src') diff --git a/README.md b/README.md index 32249163211..211833bacce 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Lints included in this crate: - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` - `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively + - `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant In your code, you may add `#![plugin(clippy)]` to use it (you may also need to include a `#![feature(plugin)]` line) diff --git a/src/approx_const.rs b/src/approx_const.rs new file mode 100644 index 00000000000..8a93bbfa933 --- /dev/null +++ b/src/approx_const.rs @@ -0,0 +1,63 @@ +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; +use std::f64::consts as f64; + +declare_lint! { + pub APPROX_CONSTANT, + Warn, + "Warn if a user writes an approximate known constant in their code" +} + +const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"), + (f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"), + (f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"), + (f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")]; + +const EPSILON_DIVISOR : f64 = 8192f64; //TODO: test to find a good value + +#[derive(Copy,Clone)] +pub struct ApproxConstant; + +impl LintPass for ApproxConstant { + fn get_lints(&self) -> LintArray { + lint_array!(APPROX_CONSTANT) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let &ExprLit(ref lit) = &e.node { + check_lit(cx, lit, e.span); + } + } +} + +fn check_lit(cx: &Context, lit: &Lit, span: Span) { + match &lit.node { + &LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), + &LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), + &LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), + _ => () + } +} + +fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { + if let Ok(value) = str.parse::() { + for &(constant, name) in KNOWN_CONSTS { + if within_epsilon(constant, value) { + cx.span_lint(APPROX_CONSTANT, span, &format!( + "Approximate value of {}::{} found, consider using it directly.", module, &name)); + } + } + } +} + +fn within_epsilon(target: f64, value: f64) -> bool { + f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR +} diff --git a/src/lib.rs b/src/lib.rs index 8cf8650c80a..b2a750f5cc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ pub mod eq_op; pub mod bit_mask; pub mod ptr_arg; pub mod needless_bool; +pub mod approx_const; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -31,11 +32,13 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); + reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, - needless_bool::NEEDLESS_BOOL + needless_bool::NEEDLESS_BOOL, + approx_const::APPROX_CONSTANT ]); } diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs new file mode 100644 index 00000000000..488c8f16f5b --- /dev/null +++ b/tests/compile-fail/approx_const.rs @@ -0,0 +1,56 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(approx_constant)] +#[allow(unused)] +fn main() { + let my_e = 2.7182; //~ERROR + let almost_e = 2.718; //~ERROR + let no_e = 2.71; + + let my_1_frac_pi = 0.3183; //~ERROR + let no_1_frac_pi = 0.31; + + let my_frac_1_sqrt_2 = 0.70710678; //~ERROR + let almost_frac_1_sqrt_2 = 0.70711; //~ERROR + let my_frac_1_sqrt_2 = 0.707; + + let my_frac_2_pi = 0.63661977; //~ERROR + let no_frac_2_pi = 0.636; + + let my_frac_2_sq_pi = 1.128379; //~ERROR + let no_frac_2_sq_pi = 1.128; + + let my_frac_2_pi = 1.57079632679; //~ERROR + let no_frac_2_pi = 1.5705; + + let my_frac_3_pi = 1.04719755119; //~ERROR + let no_frac_3_pi = 1.047; + + let my_frac_4_pi = 0.785398163397; //~ERROR + let no_frac_4_pi = 0.785; + + let my_frac_6_pi = 0.523598775598; //~ERROR + let no_frac_6_pi = 0.523; + + let my_frac_8_pi = 0.3926990816987; //~ERROR + let no_frac_8_pi = 0.392; + + let my_ln_10 = 2.302585092994046; //~ERROR + let no_ln_10 = 2.303; + + let my_ln_2 = 0.6931471805599453; //~ERROR + let no_ln_2 = 0.693; + + let my_log10_e = 0.43429448190325176; //~ERROR + let no_log10_e = 0.434; + + let my_log2_e = 1.4426950408889634; //~ERROR + let no_log2_e = 1.442; + + let my_pi = 3.1415; //~ERROR + let almost_pi = 3.141; + + let my_sq2 = 1.4142; //~ERROR + let no_sq2 = 1.414; +} -- cgit 1.4.1-3-g733a5 From 0936e0617a38727b78a76f7671fd382b128b5218 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 4 May 2015 14:11:15 +0200 Subject: new lint to check for doomed comparisons to NAN --- src/lib.rs | 4 +++- src/misc.rs | 31 +++++++++++++++++++++++++++++++ tests/compile-fail/cmp_nan.rs | 21 +++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/cmp_nan.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index b2a750f5cc1..8137eccf13f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); + reg.register_lint_pass(box misc::CmpNan as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); @@ -39,6 +40,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, - approx_const::APPROX_CONSTANT + approx_const::APPROX_CONSTANT, + misc::CMP_NAN ]); } diff --git a/src/misc.rs b/src/misc.rs index 04accaaa8bc..17de26807c2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,6 +1,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; +use syntax::ast_util::is_comparison_binop; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr}; @@ -108,3 +109,33 @@ impl LintPass for TopLevelRefPass { } } } + +declare_lint!(pub CMP_NAN, Allow, "Deny comparisons to std::f32::NAN or std::f64::NAN"); + +#[derive(Copy,Clone)] +pub struct CmpNan; + +impl LintPass for CmpNan { + fn get_lints(&self) -> LintArray { + lint_array!(CMP_NAN) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if is_comparison_binop(cmp.node) { + if let &ExprPath(_, ref path) = &left.node { + check_nan(cx, path, expr.span); + } + if let &ExprPath(_, ref path) = &right.node { + check_nan(cx, path, expr.span); + } + } + } + } +} + +fn check_nan(cx: &Context, path: &Path, span: Span) { + path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" { + cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + }); +} diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs new file mode 100644 index 00000000000..b876bfcc63c --- /dev/null +++ b/tests/compile-fail/cmp_nan.rs @@ -0,0 +1,21 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(cmp_nan)] +fn main() { + let x = 5f32; + x == std::f32::NAN; //~ERROR + x != std::f32::NAN; //~ERROR + x < std::f32::NAN; //~ERROR + x > std::f32::NAN; //~ERROR + x <= std::f32::NAN; //~ERROR + x >= std::f32::NAN; //~ERROR + + let y = 0f64; + y == std::f64::NAN; //~ERROR + y != std::f64::NAN; //~ERROR + y < std::f64::NAN; //~ERROR + y > std::f64::NAN; //~ERROR + y <= std::f64::NAN; //~ERROR + y >= std::f64::NAN; //~ERROR +} -- cgit 1.4.1-3-g733a5 From ac151bb1f0f5069e36a10c8ff6dbf0f81601b317 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 6 May 2015 10:01:49 +0200 Subject: Added new 'float_cmp' lint (see issue #46) --- README.md | 9 ++++++++ src/lib.rs | 3 ++- src/misc.rs | 50 ++++++++++++++++++++++++++++++++--------- tests/compile-fail/cmp_nan.rs | 1 + tests/compile-fail/float_cmp.rs | 35 +++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/float_cmp.rs (limited to 'src') diff --git a/README.md b/README.md index 211833bacce..3014a1a3ecd 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ Lints included in this crate: - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` - `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively - `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant + - `cmp_nan`: Denies comparisons to NAN (which will always return false, which is probably not intended) + - `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds + +To use, add the following lines to your Cargo.toml: + +``` +[dev-dependencies.rust-clippy] +git = "https://github.com/Manishearth/rust-clippy" +``` In your code, you may add `#![plugin(clippy)]` to use it (you may also need to include a `#![feature(plugin)]` line) diff --git a/src/lib.rs b/src/lib.rs index 8137eccf13f..5b2f71bb4fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); + reg.register_lint_pass(box misc::FloatCmp as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -41,6 +42,6 @@ pub fn plugin_registrar(reg: &mut Registry) { bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, approx_const::APPROX_CONSTANT, - misc::CMP_NAN + misc::CMP_NAN, misc::FLOAT_CMP, ]); } diff --git a/src/misc.rs b/src/misc.rs index 17de26807c2..cdc39a4b819 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,14 +1,22 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; -use syntax::ast_util::is_comparison_binop; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr}; +use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; use syntax::codemap::Span; + use types::span_note_and_lint; +fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { + match ty.sty { + ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty), + _ => ty + } +} + /// Handles uncategorized lints /// Currently handles linting of if-let-able matches #[allow(missing_copy_implementations)] @@ -71,13 +79,6 @@ impl LintPass for StrToStringPass { } fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { - //println!("{}: -> {}", depth, ty); - match ty.sty { - ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty), - _ => ty - } - } match walk_ty(expr_ty(cx.tcx, expr)).sty { ty_str => true, _ => false @@ -110,7 +111,7 @@ impl LintPass for TopLevelRefPass { } } -declare_lint!(pub CMP_NAN, Allow, "Deny comparisons to std::f32::NAN or std::f64::NAN"); +declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64::NAN"); #[derive(Copy,Clone)] pub struct CmpNan; @@ -139,3 +140,32 @@ fn check_nan(cx: &Context, path: &Path, span: Span) { cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); }); } + +declare_lint!(pub FLOAT_CMP, Warn, + "Warn on ==/!= comparison of floaty values"); + +#[derive(Copy,Clone)] +pub struct FloatCmp; + +impl LintPass for FloatCmp { + fn get_lints(&self) -> LintArray { + lint_array!(FLOAT_CMP) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + let op = cmp.node; + if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { + let map = cx.sess().codemap(); + cx.span_lint(FLOAT_CMP, expr.span, &format!( + "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", + binop_to_string(op), &*map.span_to_snippet(left.span).unwrap_or("..".to_string()), + &*map.span_to_snippet(right.span).unwrap_or("..".to_string()))); + } + } + } +} + +fn is_float(cx: &Context, expr: &Expr) -> bool { + if let ty_float(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { true } else { false } +} diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs index b876bfcc63c..69631331467 100644 --- a/tests/compile-fail/cmp_nan.rs +++ b/tests/compile-fail/cmp_nan.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #[deny(cmp_nan)] +#[allow(float_cmp)] fn main() { let x = 5f32; x == std::f32::NAN; //~ERROR diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs new file mode 100644 index 00000000000..dce8dba1ebe --- /dev/null +++ b/tests/compile-fail/float_cmp.rs @@ -0,0 +1,35 @@ +#![feature(plugin)] +#![plugin(clippy)] + +use std::ops::Add; + +const ZERO : f32 = 0.0; +const ONE : f32 = ZERO + 1.0; + +fn twice(x : T) -> T where T : Add, T : Copy { + x + x +} + +#[deny(float_cmp)] +#[allow(unused)] +fn main() { + ZERO == 0f32; //~ERROR + ZERO == 0.0; //~ERROR + ZERO + ZERO != 1.0; //~ERROR + + ONE != 0.0; //~ERROR + twice(ONE) != ONE; //~ERROR + ONE as f64 != 0.0; //~ERROR + + let x : f64 = 1.0; + + x == 1.0; //~ERROR + x != 0f64; //~ERROR + + twice(x) != twice(ONE as f64); //~ERROR + + x < 0.0; + x > 0.0; + x <= 0.0; + x >= 0.0; +} -- cgit 1.4.1-3-g733a5 From 17bcf0e86519fa6147dec7271660e278cda98404 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 6 May 2015 12:59:08 +0200 Subject: New lint: precedence, see issue #41 --- README.md | 1 + src/lib.rs | 2 ++ src/misc.rs | 46 +++++++++++++++++++++++++++++++++++++++- tests/compile-fail/precedence.rs | 15 +++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/precedence.rs (limited to 'src') diff --git a/README.md b/README.md index 3014a1a3ecd..7d3e3fd8c65 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Lints included in this crate: - `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant - `cmp_nan`: Denies comparisons to NAN (which will always return false, which is probably not intended) - `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds + - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index 5b2f71bb4fb..ffee122f776 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); reg.register_lint_pass(box misc::FloatCmp as LintPassObject); + reg.register_lint_pass(box misc::Precedence as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -43,5 +44,6 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_bool::NEEDLESS_BOOL, approx_const::APPROX_CONSTANT, misc::CMP_NAN, misc::FLOAT_CMP, + misc::PRECEDENCE, ]); } diff --git a/src/misc.rs b/src/misc.rs index cdc39a4b819..eae6d518950 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -5,7 +5,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; -use syntax::codemap::Span; +use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; @@ -169,3 +169,47 @@ impl LintPass for FloatCmp { fn is_float(cx: &Context, expr: &Expr) -> bool { if let ty_float(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { true } else { false } } + +declare_lint!(pub PRECEDENCE, Warn, + "Warn on mixing bit ops with integer arithmetic without parenthesis"); + +#[derive(Copy,Clone)] +pub struct Precedence; + +impl LintPass for Precedence { + fn get_lints(&self) -> LintArray { + lint_array!(PRECEDENCE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { + if is_bit_op(op) { + if let ExprBinary(Spanned { node: lop, ..}, _, _) = left.node { + if is_arith_op(lop) { + cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear."); + } + } else { + if let ExprBinary(Spanned { node: rop, ..}, _, _) = right.node { + if is_arith_op(rop) { + cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear."); + } + } + } + } + } + } +} + +fn is_bit_op(op : BinOp_) -> bool { + match op { + BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, + _ => false + } +} + +fn is_arith_op(op : BinOp_) -> bool { + match op { + BiAdd | BiSub | BiMul | BiDiv | BiRem => true, + _ => false + } +} diff --git a/tests/compile-fail/precedence.rs b/tests/compile-fail/precedence.rs new file mode 100644 index 00000000000..7969be0f371 --- /dev/null +++ b/tests/compile-fail/precedence.rs @@ -0,0 +1,15 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(precedence)] +#[allow(eq_op)] +fn main() { + format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR + format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR + format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR + format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR + format!("{} vs. {}", 1 ^ 1 - 1, (1 ^ 1) - 1); //~ERROR + format!("{} vs. {}", 3 | 2 - 1, (3 | 2) - 1); //~ERROR + format!("{} vs. {}", 3 & 5 - 2, (3 & 5) - 2); //~ERROR + +} -- cgit 1.4.1-3-g733a5 From 7a8de35abc32478fa84406b0939137333fe9a6b5 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 6 May 2015 13:20:47 +0200 Subject: refactored precedence lint --- src/misc.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index eae6d518950..5059a87bccf 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -183,23 +183,21 @@ impl LintPass for Precedence { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { - if is_bit_op(op) { - if let ExprBinary(Spanned { node: lop, ..}, _, _) = left.node { - if is_arith_op(lop) { - cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear."); - } - } else { - if let ExprBinary(Spanned { node: rop, ..}, _, _) = right.node { - if is_arith_op(rop) { - cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear."); - } - } - } + if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { + cx.span_lint(PRECEDENCE, expr.span, + "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); } } } } +fn is_arith_expr(expr : &Expr) -> bool { + match expr.node { + ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(lop), + _ => false + } +} + fn is_bit_op(op : BinOp_) -> bool { match op { BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, -- cgit 1.4.1-3-g733a5 From 23525081f951c92e4c8ad0b0bfed7a2b03c0531e Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 6 May 2015 14:19:02 +0200 Subject: fixed typo from last commit --- src/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 5059a87bccf..8cde5104ff7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -193,7 +193,7 @@ impl LintPass for Precedence { fn is_arith_expr(expr : &Expr) -> bool { match expr.node { - ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(lop), + ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), _ => false } } -- cgit 1.4.1-3-g733a5 From a175463acce7dde5c65d6919d4d2e3ebc9edded0 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Wed, 6 May 2015 21:41:54 -0700 Subject: Fix panic during constant lookup. --- src/bit_mask.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index d4cdc952661..6aece62420e 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -142,14 +142,16 @@ fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option { } else { Option::None } }, &ExprPath(_, _) => { - let def_map = cx.tcx.def_map.borrow(); - let path_res_op = def_map.get(&lit.id); - path_res_op.as_ref().and_then(|x| { - if let &DefConst(def_id) = &x.base_def { - lookup_const_by_id(cx.tcx, def_id, Option::None).and_then(|l| fetch_int_literal(cx, l)) - } else { Option::None } - }) - }, + // 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: DefConst(def_id), ..}) => Some(def_id), + _ => None + } + } + .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None)) + .and_then(|l| fetch_int_literal(cx, l)), _ => Option::None } } -- cgit 1.4.1-3-g733a5 From 11dea785955881b3f5461e7e22f96af151aa4fc0 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Wed, 6 May 2015 22:52:16 -0700 Subject: Fix Box> test. --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index c966c49be85..f0c91dc18b5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -58,7 +58,7 @@ impl LintPass for TypePass { use std::vec::Vec; } match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first()) - .map(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) + .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { span_note_and_lint(cx, BOX_VEC, ty.span, "You seem to be trying to use Box>. Did you mean to use Vec?", -- cgit 1.4.1-3-g733a5 From 2447e1d5bef3ea762a2e91dc7c121a3d7092fce5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 10 May 2015 10:39:04 +0530 Subject: Add eta reduction (fixes #29) --- .gitignore | 3 +++ Cargo.toml | 2 +- README.md | 1 + src/eta_reduction.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ tests/compile-fail/eta.rs | 21 +++++++++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/eta_reduction.rs create mode 100644 tests/compile-fail/eta.rs (limited to 'src') diff --git a/.gitignore b/.gitignore index 37727f91cbe..ac98a7d842f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ # Generated by Cargo /target/ + +# We don't pin yet +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 3c3e700eea5..95de98e8ee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.3" +version = "0.0.4" authors = [ "Manish Goregaokar ", "Andre Bogus " diff --git a/README.md b/README.md index 7d3e3fd8c65..004520f5bd7 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Lints included in this crate: - `cmp_nan`: Denies comparisons to NAN (which will always return false, which is probably not intended) - `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` + - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) To use, add the following lines to your Cargo.toml: diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs new file mode 100644 index 00000000000..b89eef8c8bb --- /dev/null +++ b/src/eta_reduction.rs @@ -0,0 +1,59 @@ +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use syntax::codemap::{Span, Spanned}; +use syntax::print::pprust::expr_to_string; + + +#[allow(missing_copy_implementations)] +pub struct EtaPass; + + +declare_lint!(pub REDUNDANT_CLOSURE, Warn, + "Warn on usage of redundant closures, i.e. `|a| foo(a)`"); + +impl LintPass for EtaPass { + fn get_lints(&self) -> LintArray { + lint_array!(REDUNDANT_CLOSURE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprClosure(_, ref decl, ref blk) = expr.node { + if blk.stmts.len() != 0 { + // || {foo(); bar()}; can't be reduced here + return; + } + if let Some(ref ex) = blk.expr { + if let ExprCall(ref caller, ref args) = ex.node { + if args.len() != decl.inputs.len() { + // Not the same number of arguments, there + // is no way the closure is the same as the function + return; + } + for (ref a1, ref a2) in decl.inputs.iter().zip(args) { + if let PatIdent(_, ident, _) = a1.pat.node { + // XXXManishearth Should I be checking the binding mode here? + if let ExprPath(None, ref p) = a2.node { + if p.segments.len() != 1 { + // If it's a proper path, it can't be a local variable + return; + } + if p.segments[0].identifier != ident.node { + // The two idents should be the same + return + } + } else { + return + } + } else { + return + } + } + cx.span_lint(REDUNDANT_CLOSURE, expr.span, + &format!("Redundant closure found, consider using `{}` in its place", + expr_to_string(caller))[..]) + } + } + } + } +} + diff --git a/src/lib.rs b/src/lib.rs index ffee122f776..7e21a72dcf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod bit_mask; pub mod ptr_arg; pub mod needless_bool; pub mod approx_const; +pub mod eta_reduction; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -36,6 +37,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); reg.register_lint_pass(box misc::FloatCmp as LintPassObject); reg.register_lint_pass(box misc::Precedence as LintPassObject); + reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -45,5 +47,6 @@ pub fn plugin_registrar(reg: &mut Registry) { approx_const::APPROX_CONSTANT, misc::CMP_NAN, misc::FLOAT_CMP, misc::PRECEDENCE, + eta_reduction::REDUNDANT_CLOSURE, ]); } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs new file mode 100644 index 00000000000..8ca88eecbd2 --- /dev/null +++ b/tests/compile-fail/eta.rs @@ -0,0 +1,21 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unknown_lints, unused)] +#![deny(redundant_closure)] + +fn main() { + let a = |a, b| foo(a, b); + //~^ ERROR Redundant closure found, consider using `foo` in its place + let c = |a, b| {1+2; foo}(a, b); + //~^ ERROR Redundant closure found, consider using `{ 1 + 2; foo }` in its place + let d = |a, b| foo((|c, d| foo2(c,d))(a,b), b); + //~^ ERROR Redundant closure found, consider using `foo2` in its place +} + +fn foo(_: u8, _: u8) { + +} + +fn foo2(_: u8, _: u8) -> u8 { + 1u8 +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 6bec4f35dff0d0fe58d4bfdeeb63ed4695d62c5a Mon Sep 17 00:00:00 2001 From: llogiq Date: Fri, 15 May 2015 14:09:29 +0200 Subject: Added 'ineffective bit mask' lint --- README.md | 1 + src/bit_mask.rs | 40 +++++++++++++++++++++++++++++++--------- src/lib.rs | 4 +++- tests/compile-fail/bit_masks.rs | 15 +++++++++++++++ 4 files changed, 50 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 96d615d7b96..3ea3659dd1d 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Lints included in this crate: - `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) - `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) + - `ineffective_bit_mask`: Warns on expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` - `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively - `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 6aece62420e..42e3003d336 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -32,12 +32,18 @@ declare_lint! { "Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'" } +declare_lint! { + pub INEFFECTIVE_BIT_MASK, + Warn, + "Warn on the use of an ineffective bit mask in comparisons, e.g. '(a & 1) > 2'" +} + #[derive(Copy,Clone)] pub struct BitMask; impl LintPass for BitMask { fn get_lints(&self) -> LintArray { - lint_array!(BAD_BIT_MASK) + lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) } fn check_expr(&mut self, cx: &Context, e: &Expr) { @@ -102,31 +108,47 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, }, BiLt | BiGe => match bit_op { BiBitAnd => if mask_value < cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value, - cmp_value)); + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} will always be lower than {}", + mask_value, cmp_value)); } else { if mask_value == 0 { cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); } }, BiBitOr => if mask_value >= cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value, - cmp_value)); + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} will never be lower than {}", + mask_value, cmp_value)); + } else { + if mask_value < cmp_value { + cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!( + "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + mask_value, cmp_value)); + } }, _ => () }, BiLe | BiGt => match bit_op { BiBitAnd => if mask_value <= cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value, - cmp_value)); + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} will never be higher than {}", + mask_value, cmp_value)); } else { if mask_value == 0 { cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); } }, BiBitOr => if mask_value > cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value, - cmp_value)); + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} will always be higher than {}", + mask_value, cmp_value)); + } else { + if mask_value < cmp_value { + cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!( + "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + mask_value, cmp_value)); + } }, _ => () }, diff --git a/src/lib.rs b/src/lib.rs index 7e21a72dcf2..1655faaf8b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,9 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, - bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, approx_const::APPROX_CONSTANT, misc::CMP_NAN, misc::FLOAT_CMP, diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index b575dbc4e25..d2646d2589e 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -5,6 +5,7 @@ const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] +#[allow(ineffective_bit_mask)] fn main() { let x = 5; @@ -34,4 +35,18 @@ fn main() { 1 < 2 | x; //~ERROR 2 == 3 | x; //~ERROR 1 == x & 2; //~ERROR + + x | 1 > 2; // no error, because we allowed ineffective bit masks + ineffective(); +} + +#[deny(ineffective_bit_mask)] +#[allow(bad_bit_mask)] +fn ineffective() { + let x = 5; + + x | 1 > 2; //~ERROR + x | 1 < 3; //~ERROR + x | 1 <= 3; //~ERROR + x | 1 >= 2; //~ERROR } -- cgit 1.4.1-3-g733a5 From edf747ab7617c38381e791f56c0376f0f8fea559 Mon Sep 17 00:00:00 2001 From: llogiq Date: Fri, 15 May 2015 18:46:43 +0200 Subject: new lint: identity_op, refactored bit_masks a bit --- README.md | 1 + src/identity_op.rs | 82 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ tests/compile-fail/bit_masks.rs | 2 +- tests/compile-fail/eq_op.rs | 1 + tests/compile-fail/identity_op.rs | 24 ++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/identity_op.rs create mode 100644 tests/compile-fail/identity_op.rs (limited to 'src') diff --git a/README.md b/README.md index 3ea3659dd1d..47747d86e26 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Lints included in this crate: - `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) + - `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively) To use, add the following lines to your Cargo.toml: diff --git a/src/identity_op.rs b/src/identity_op.rs new file mode 100644 index 00000000000..ec4495539d2 --- /dev/null +++ b/src/identity_op.rs @@ -0,0 +1,82 @@ +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::ptr::P; +use syntax::codemap::Span; + +declare_lint! { pub IDENTITY_OP, Warn, + "Warn on identity operations, e.g. '_ + 0'"} + +#[derive(Copy,Clone)] +pub struct IdentityOp; + +impl LintPass for IdentityOp { + fn get_lints(&self) -> LintArray { + lint_array!(IDENTITY_OP) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + match cmp.node { + 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); + }, + _ => () + } + } + } +} + + +fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { + if have_lit(cx, e, m) { + let map = cx.sess().codemap(); + cx.span_lint(IDENTITY_OP, span, &format!( + "The operation is ineffective. Consider reducing it to '{}'", + &*map.span_to_snippet(arg).unwrap_or("..".to_string()))); + } +} + +fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool { + match &e.node { + &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), + &ExprLit(ref lit) => { + match (&lit.node, m) { + (&LitInt(0, _), 0) => true, + (&LitInt(1, SignedIntLit(_, Plus)), 1) => true, + (&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true, + (&LitInt(1, SignedIntLit(_, Minus)), -1) => true, + (&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true, + _ => false + } + }, + &ExprParen(ref p) => have_lit(cx, p, m), + &ExprPath(_, _) => { + match cx.tcx.def_map.borrow().get(&e.id) { + Some(&PathResolution { base_def: DefConst(def_id), ..}) => + match lookup_const_by_id(cx.tcx, def_id, Option::None) { + Some(l) => have_lit(cx, l, m), + None => false + }, + _ => false + } + } + _ => false + } +} diff --git a/src/lib.rs b/src/lib.rs index 1655faaf8b0..c9585d2ebba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub mod ptr_arg; pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; +pub mod identity_op; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -38,6 +39,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::FloatCmp as LintPassObject); reg.register_lint_pass(box misc::Precedence as LintPassObject); reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); + reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -50,5 +52,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::CMP_NAN, misc::FLOAT_CMP, misc::PRECEDENCE, eta_reduction::REDUNDANT_CLOSURE, + identity_op::IDENTITY_OP, ]); } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index d2646d2589e..e45b789800e 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -5,7 +5,7 @@ const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] -#[allow(ineffective_bit_mask)] +#[allow(ineffective_bit_mask, identity_op)] fn main() { let x = 5; diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 910b5e84816..07b15625b2c 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -6,6 +6,7 @@ fn id(x: X) -> X { } #[deny(eq_op)] +#[allow(identity_op)] fn main() { // simple values and comparisons 1 == 1; //~ERROR diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs new file mode 100644 index 00000000000..6c17d30fac4 --- /dev/null +++ b/tests/compile-fail/identity_op.rs @@ -0,0 +1,24 @@ +#![feature(plugin)] +#![plugin(clippy)] + +const ONE : i64 = 1; +const NEG_ONE : i64 = -1; +const ZERO : i64 = 0; + +#[deny(identity_op)] +fn main() { + let x = 0; + + x + 0; //~ERROR + 0 + x; //~ERROR + x - ZERO; //~ERROR + x | (0); //~ERROR + ((ZERO)) | x; //~ERROR + + x * 1; //~ERROR + 1 * x; //~ERROR + x / ONE; //~ERROR + + x & NEG_ONE; //~ERROR + -1 & x; //~ERROR +} -- cgit 1.4.1-3-g733a5 From 96bfade4f13af23f95c7381a3b08168f9e852f99 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 18 May 2015 09:02:24 +0200 Subject: New lint: mut_mut (closes issue #9) --- README.md | 1 + src/lib.rs | 3 +++ src/mut_mut.rs | 51 +++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/mut_mut.rs | 20 +++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/mut_mut.rs create mode 100644 tests/compile-fail/mut_mut.rs (limited to 'src') diff --git a/README.md b/README.md index 47747d86e26..ddc28a95f03 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Lints included in this crate: - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) - `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively) + - `mut_mut`: Warns on `&mut &mut` which is either a copy'n'paste error, or shows a fundamental misunderstanding of references To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index c9585d2ebba..cd918bff459 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; pub mod identity_op; +pub mod mut_mut; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -40,6 +41,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::Precedence as LintPassObject); reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); + reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -53,5 +55,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::PRECEDENCE, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, + mut_mut::MUT_MUT, ]); } diff --git a/src/mut_mut.rs b/src/mut_mut.rs new file mode 100644 index 00000000000..0a58e293915 --- /dev/null +++ b/src/mut_mut.rs @@ -0,0 +1,51 @@ +use syntax::ptr::P; +use syntax::ast; +use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::visit::{FnKind}; +use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; +use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; +use syntax::codemap::{Span, Spanned}; + +declare_lint!(pub MUT_MUT, Warn, + "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); + +#[derive(Copy,Clone)] +pub struct MutMut; + +impl LintPass for MutMut { + fn get_lints(&self) -> LintArray { + lint_array!(MUT_MUT) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + + fn unwrap_addr(expr : &Expr) -> Option<&Expr> { + match expr.node { + ExprAddrOf(MutMutable, ref e) => Option::Some(e), + _ => Option::None + } + } + + if unwrap_addr(expr).and_then(unwrap_addr).is_some() { + cx.span_lint(MUT_MUT, expr.span, + "We're not sure what this means, so if you know, please tell us.") + } + } + + fn check_ty(&mut self, cx: &Context, ty: &Ty) { + + fn unwrap_mut(ty : &Ty) -> Option<&Ty> { + match ty.node { + TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + _ => Option::None + } + } + + if unwrap_mut(ty).and_then(unwrap_mut).is_some() { + cx.span_lint(MUT_MUT, ty.span, + "We're not sure what this means, so if you know, please tell us.") + } + } +} diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs new file mode 100644 index 00000000000..7d1dad44a90 --- /dev/null +++ b/tests/compile-fail/mut_mut.rs @@ -0,0 +1,20 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(mut_mut)] +fn fun(x : &mut &mut u32) -> bool { //~ERROR + **x > 0 +} + +#[deny(mut_mut)] +fn main() { + let mut x = &mut &mut 1u32; //~ERROR + if fun(x) { + let y : &mut &mut &mut u32 = &mut &mut &mut 2; + //~^ ERROR + //~^^ ERROR + //~^^^ ERROR + //~^^^^ ERROR + ***y + **x; + } +} -- cgit 1.4.1-3-g733a5 From 1f8453ab73ef40a33e04c95349c6d3c638e576ae Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 18 May 2015 10:41:15 +0200 Subject: mut_mut now more robust (thanks to Manishearth, see issue #9) --- src/mut_mut.rs | 43 ++++++++++++++++++++++++------------------- tests/compile-fail/mut_mut.rs | 5 +++++ 2 files changed, 29 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 0a58e293915..d77a40a4ea5 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,11 +1,7 @@ use syntax::ptr::P; -use syntax::ast; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::visit::{FnKind}; -use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; -use syntax::codemap::{Span, Spanned}; +use rustc::lint::{Context, LintPass, LintArray, Lint}; +use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt}; declare_lint!(pub MUT_MUT, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -27,25 +23,34 @@ impl LintPass for MutMut { } } - if unwrap_addr(expr).and_then(unwrap_addr).is_some() { - cx.span_lint(MUT_MUT, expr.span, - "We're not sure what this means, so if you know, please tell us.") - } + unwrap_addr(expr).map(|e| { + if unwrap_addr(e).is_some() { + cx.span_lint(MUT_MUT, expr.span, + "We're not sure what this means, so if you know, please tell us.") + } else { + match expr_ty(cx.tcx, e).sty { + ty_ptr(mt{ty: _, mutbl: MutMutable}) | + ty_rptr(_, mt{ty: _, mutbl: MutMutable}) => + cx.span_lint(MUT_MUT, expr.span, + "This expression mutably borrows a mutable reference. Consider direct reborrowing"), + _ => () + } + } + }); } fn check_ty(&mut self, cx: &Context, ty: &Ty) { - - fn unwrap_mut(ty : &Ty) -> Option<&Ty> { - match ty.node { - TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), - TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), - _ => Option::None - } - } - if unwrap_mut(ty).and_then(unwrap_mut).is_some() { cx.span_lint(MUT_MUT, ty.span, "We're not sure what this means, so if you know, please tell us.") } } } + +fn unwrap_mut(ty : &Ty) -> Option<&Ty> { + match ty.node { + TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + _ => Option::None + } +} diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 7d1dad44a90..65e3762e2c4 100644 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -7,8 +7,13 @@ fn fun(x : &mut &mut u32) -> bool { //~ERROR } #[deny(mut_mut)] +#[allow(unused_mut, unused_variables)] fn main() { let mut x = &mut &mut 1u32; //~ERROR + { + let mut y = &mut x; //~ERROR + } + if fun(x) { let y : &mut &mut &mut u32 = &mut &mut &mut 2; //~^ ERROR -- cgit 1.4.1-3-g733a5 From b9414637e238c94048b0f752c6c4f32953806ce1 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 18 May 2015 10:52:43 +0200 Subject: better messages --- src/mut_mut.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index d77a40a4ea5..5d50e351353 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -26,13 +26,13 @@ impl LintPass for MutMut { unwrap_addr(expr).map(|e| { if unwrap_addr(e).is_some() { cx.span_lint(MUT_MUT, expr.span, - "We're not sure what this means, so if you know, please tell us.") + "Generally you want to avoid &mut &mut _ if possible.") } else { match expr_ty(cx.tcx, e).sty { ty_ptr(mt{ty: _, mutbl: MutMutable}) | ty_rptr(_, mt{ty: _, mutbl: MutMutable}) => cx.span_lint(MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. Consider direct reborrowing"), + "This expression mutably borrows a mutable reference. Consider reborrowing"), _ => () } } @@ -42,7 +42,7 @@ impl LintPass for MutMut { fn check_ty(&mut self, cx: &Context, ty: &Ty) { if unwrap_mut(ty).and_then(unwrap_mut).is_some() { cx.span_lint(MUT_MUT, ty.span, - "We're not sure what this means, so if you know, please tell us.") + "Generally you want to avoid &mut &mut _ if possible.") } } } -- cgit 1.4.1-3-g733a5 From 5556d89f560ae2948f2bb3ce5415ba6aff6aca4f Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 18 May 2015 11:36:56 +0200 Subject: removed ty_ptr match --- src/mut_mut.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 5d50e351353..2a71b938d71 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -28,12 +28,9 @@ impl LintPass for MutMut { cx.span_lint(MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") } else { - match expr_ty(cx.tcx, e).sty { - ty_ptr(mt{ty: _, mutbl: MutMutable}) | - ty_rptr(_, mt{ty: _, mutbl: MutMutable}) => - cx.span_lint(MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. Consider reborrowing"), - _ => () + if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = expr_ty(cx.tcx, e).sty { + cx.span_lint(MUT_MUT, expr.span, + "This expression mutably borrows a mutable reference. Consider reborrowing") } } }); -- cgit 1.4.1-3-g733a5 From e8ca3c6eae160310c310b15002587b1f2579d4e5 Mon Sep 17 00:00:00 2001 From: llogiq Date: Wed, 20 May 2015 08:52:19 +0200 Subject: new lints len_zero and len_without_is_empty --- README.md | 2 + src/len_zero.rs | 101 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 ++ tests/compile-fail/len_zero.rs | 56 +++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 src/len_zero.rs create mode 100644 tests/compile-fail/len_zero.rs (limited to 'src') diff --git a/README.md b/README.md index ddc28a95f03..e081630326f 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ Lints included in this crate: - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) - `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively) - `mut_mut`: Warns on `&mut &mut` which is either a copy'n'paste error, or shows a fundamental misunderstanding of references + - `len_zero`: Warns on `_.len() == 0` and suggests using `_.is_empty()` (or similar comparisons with `>` or `!=`) + - `len_without_is_empty`: Warns on traits or impls that have a `.len()` but no `.is_empty()` method To use, add the following lines to your Cargo.toml: diff --git a/src/len_zero.rs b/src/len_zero.rs new file mode 100644 index 00000000000..18ddbccc9a2 --- /dev/null +++ b/src/len_zero.rs @@ -0,0 +1,101 @@ +extern crate rustc_typeck as typeck; + +use syntax::ptr::P; +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray, Lint}; +use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, mt, MethodTraitItemId}; +use rustc::middle::def::{DefTy, DefStruct, DefTrait}; +use syntax::codemap::{Span, Spanned}; + +declare_lint!(pub LEN_ZERO, Warn, + "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); + +declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, + "Warn on traits and impls that have .len() but not .is_empty()"); + +#[derive(Copy,Clone)] +pub struct LenZero; + +impl LintPass for LenZero { + fn get_lints(&self) -> LintArray { + lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + match &item.node { + &ItemTrait(_, _, _, ref trait_items) => + check_trait_items(cx, item, trait_items), + &ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait + check_impl_items(cx, item, impl_items), + _ => () + } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = + &expr.node { + match cmp { + BiEq => check_cmp(cx, expr.span, left, right, ""), + BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), + _ => () + } + } + } +} + +fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P]) { + fn is_named_self(item: &TraitItem, name: &str) -> bool { + item.ident.as_str() == name && item.attrs.len() == 0 + } + + if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { + //cx.span_lint(LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); + for i in trait_items { + if is_named_self(i, "len") { + cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span, + &format!("Trait '{}' has a '.len()' method, but no \ + '.is_empty()' method. Consider adding one.", + item.ident.as_str())); + } + }; + } +} + +fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P]) { + fn is_named_self(item: &ImplItem, name: &str) -> bool { + item.ident.as_str() == name && item.attrs.len() == 0 + } + + if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { + for i in impl_items { + if is_named_self(i, "len") { + cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span, + &format!("Item '{}' has a '.len()' method, but no \ + '.is_empty()' method. Consider adding one.", + item.ident.as_str())); + return; + } + } + } +} + +fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { + match (&left.node, &right.node) { + (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => + check_len_zero(cx, span, method, args, lit, empty), + (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => + check_len_zero(cx, span, method, args, lit, empty), + _ => () + } +} + +fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, + args: &[P], lit: &Lit, empty: &str) { + if let &Spanned{node: LitInt(0, _), ..} = lit { + if method.node.as_str() == "len" && args.len() == 1 { + cx.span_lint(LEN_ZERO, span, &format!( + "Consider replacing the len comparison with '{}_.is_empty()' if available", + empty)) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index cd918bff459..e22ee28e77e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ pub mod approx_const; pub mod eta_reduction; pub mod identity_op; pub mod mut_mut; +pub mod len_zero; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -42,6 +43,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); + reg.register_lint_pass(box len_zero::LenZero as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -56,5 +58,7 @@ pub fn plugin_registrar(reg: &mut Registry) { eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, mut_mut::MUT_MUT, + len_zero::LEN_ZERO, + len_zero::LEN_WITHOUT_IS_EMPTY, ]); } diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs new file mode 100644 index 00000000000..7b1aafd409d --- /dev/null +++ b/tests/compile-fail/len_zero.rs @@ -0,0 +1,56 @@ +#![feature(plugin)] +#![plugin(clippy)] + +struct One; + +#[deny(len_without_is_empty)] +impl One { + fn len(self: &Self) -> isize { //~ERROR + 1 + } +} + +#[deny(len_without_is_empty)] +trait TraitsToo { + fn len(self: &Self) -> isize; //~ERROR +} + +impl TraitsToo for One { + fn len(self: &Self) -> isize { + 0 + } +} + +#[allow(dead_code)] +struct HasIsEmpty; + +#[deny(len_without_is_empty)] +#[allow(dead_code)] +impl HasIsEmpty { + fn len(self: &Self) -> isize { + 1 + } + + fn is_empty() -> bool { + false + } +} + +#[deny(len_zero)] +fn main() { + let x = [1, 2]; + if x.len() == 0 { //~ERROR + println!("This should not happen!"); + } + + let y = One; + // false positives here + if y.len() == 0 { //~ERROR + println!("This should not happen either!"); + } + + let z : &TraitsToo = &y; + if z.len() > 0 { //~ERROR + println!("Nor should this!"); + } +} -- cgit 1.4.1-3-g733a5 From 4292dc77a737c4f8f8210f4448ec2ef94c2b03f3 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 21 May 2015 14:51:43 +0200 Subject: new lint: cmp_owned --- src/lib.rs | 3 ++- src/misc.rs | 49 +++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/cmp_owned.rs | 17 ++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/cmp_owned.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index e22ee28e77e..cf5def800a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); reg.register_lint_pass(box len_zero::LenZero as LintPassObject); + reg.register_lint_pass(box misc::CmpOwned as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -54,7 +55,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_bool::NEEDLESS_BOOL, approx_const::APPROX_CONSTANT, misc::CMP_NAN, misc::FLOAT_CMP, - misc::PRECEDENCE, + misc::PRECEDENCE, misc::CMP_OWNED, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, mut_mut::MUT_MUT, diff --git a/src/misc.rs b/src/misc.rs index 8cde5104ff7..5f5b07a15b7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -211,3 +211,52 @@ fn is_arith_op(op : BinOp_) -> bool { _ => false } } + +declare_lint!(pub CMP_OWNED, Warn, + "Warn on creating an owned string just for comparison"); + +#[derive(Copy,Clone)] +pub struct CmpOwned; + +impl LintPass for CmpOwned { + fn get_lints(&self) -> LintArray { + lint_array!(CMP_OWNED) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if is_comparison_binop(cmp.node) { + check_to_owned(cx, left, right.span); + check_to_owned(cx, right, left.span) + } + } + } +} + +fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { + match &expr.node { + &ExprMethodCall(Spanned{node: ref ident, ..}, _, _) => { + let name = ident.as_str(); + if name == "to_string" || name == "to_owned" { + cx.span_lint(CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. + Consider using {}.as_slice() to compare without allocation", + cx.sess().codemap().span_to_snippet(other_span).unwrap_or( + "..".to_string()))) + } + }, + &ExprCall(ref path, _) => { + if let &ExprPath(None, ref path) = &path.node { + if path.segments.iter().zip(["String", "from_str"].iter()).all( + |(seg, name)| &seg.identifier.as_str() == name) { + cx.span_lint(CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. + Consider using {}.as_slice() to compare without allocation", + cx.sess().codemap().span_to_snippet(other_span).unwrap_or( + "..".to_string()))) + } + } + }, + _ => () + } +} diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs new file mode 100644 index 00000000000..a8b0cb32f6f --- /dev/null +++ b/tests/compile-fail/cmp_owned.rs @@ -0,0 +1,17 @@ +#![feature(plugin, collections)] +#![plugin(clippy)] + +#[deny(cmp_owned)] +fn main() { + let x = "oh"; + + #[allow(str_to_string)] + fn with_to_string(x : &str) { + x != "foo".to_string(); //~ERROR this creates an owned instance + } + with_to_string(x); + + x != "foo".to_owned(); //~ERROR this creates an owned instance + + x != String::from_str("foo"); //~ERROR this creates an owned instance +} -- cgit 1.4.1-3-g733a5 From 158935a38d043a90e8f67ab3ae9363c65543d157 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 21 May 2015 15:59:38 +0200 Subject: refactored Option usage and fn argument types, improved formatting --- src/bit_mask.rs | 12 +++-- src/eq_op.rs | 135 +++++++++++++++++++++++++++++++++++--------------------- src/misc.rs | 4 +- src/mut_mut.rs | 21 ++++----- src/ptr_arg.rs | 18 ++++---- 5 files changed, 112 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 42e3003d336..d84da654eb4 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -49,13 +49,11 @@ impl LintPass for BitMask { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { - let cmp_opt = fetch_int_literal(cx, right); - if cmp_opt.is_some() { - check_compare(cx, left, cmp.node, cmp_opt.unwrap(), &e.span); - } else { - fetch_int_literal(cx, left).map(|cmp_val| - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, &e.span)); - } + fetch_int_literal(cx, right).map(|cmp_opt| + check_compare(cx, left, cmp.node, cmp_opt, &e.span)) + .unwrap_or_else(|| fetch_int_literal(cx, left).map(|cmp_val| + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, + &e.span)).unwrap_or(())) } } } diff --git a/src/eq_op.rs b/src/eq_op.rs index e0b722a0a18..0223820447d 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -21,7 +21,9 @@ impl LintPass for EqOp { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(left, right) { - cx.span_lint(EQ_OP, e.span, &format!("equal expressions as operands to {}", ast_util::binop_to_string(op.node))); + cx.span_lint(EQ_OP, e.span, &format!( + "equal expressions as operands to {}", + ast_util::binop_to_string(op.node))); } } } @@ -29,32 +31,39 @@ impl LintPass for EqOp { fn is_exp_equal(left : &Expr, right : &Expr) -> bool { match (&left.node, &right.node) { - (&ExprBinary(ref lop, ref ll, ref lr), &ExprBinary(ref rop, ref rl, ref rr)) => + (&ExprBinary(ref lop, ref ll, ref lr), + &ExprBinary(ref rop, ref rl, ref rr)) => lop.node == rop.node && is_exp_equal(ll, rl) && is_exp_equal(lr, rr), (&ExprBox(ref lpl, ref lboxedpl), &ExprBox(ref rpl, ref rboxedpl)) => - both(lpl, rpl, |l, r| is_exp_equal(l, r)) && is_exp_equal(lboxedpl, rboxedpl), + both(lpl, rpl, |l, r| is_exp_equal(l, r)) && + is_exp_equal(lboxedpl, rboxedpl), (&ExprCall(ref lcallee, ref largs), &ExprCall(ref rcallee, ref rargs)) => - is_exp_equal(lcallee, rcallee) && is_exp_vec_equal(largs, rargs), + is_exp_equal(lcallee, rcallee) && is_exps_equal(largs, rargs), (&ExprCast(ref lcast, ref lty), &ExprCast(ref rcast, ref rty)) => is_ty_equal(lty, rty) && is_exp_equal(lcast, rcast), - (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => + (&ExprField(ref lfexp, ref lfident), + &ExprField(ref rfexp, ref rfident)) => lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), (&ExprLit(ref llit), &ExprLit(ref rlit)) => llit.node == rlit.node, - (&ExprMethodCall(ref lident, ref lcty, ref lmargs), &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => - lident.node == rident.node && is_ty_vec_equal(lcty, rcty) && is_exp_vec_equal(lmargs, rmargs), - (&ExprParen(ref lparen), &ExprParen(ref rparen)) => is_exp_equal(lparen, rparen), + (&ExprMethodCall(ref lident, ref lcty, ref lmargs), + &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => + lident.node == rident.node && is_tys_equal(lcty, rcty) && + is_exps_equal(lmargs, rmargs), (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), - (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, |l, r| is_qself_equal(l, r)) && is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exp_vec_equal(ltup, rtup), - (&ExprUnary(lunop, ref lparam), &ExprUnary(runop, ref rparam)) => lunop == runop && is_exp_equal(lparam, rparam), - (&ExprVec(ref lvec), &ExprVec(ref rvec)) => is_exp_vec_equal(lvec, rvec), + (&ExprPath(ref lqself, ref lsubpath), + &ExprPath(ref rqself, ref rsubpath)) => + both(lqself, rqself, |l, r| is_qself_equal(l, r)) && + is_path_equal(lsubpath, rsubpath), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(ltup, rtup), + (&ExprUnary(lunop, ref lparam), &ExprUnary(runop, ref rparam)) => + lunop == runop && is_exp_equal(lparam, rparam), + (&ExprVec(ref lvec), &ExprVec(ref rvec)) => is_exps_equal(lvec, rvec), _ => false } } -fn is_exp_vec_equal(left : &Vec>, right : &Vec>) -> bool { +fn is_exps_equal(left : &[P], right : &[P]) -> bool { over(left, right, |l, r| is_exp_equal(l, r)) } @@ -69,19 +78,25 @@ fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { fn is_ty_equal(left : &Ty, right : &Ty) -> bool { match (&left.node, &right.node) { (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), - (&TyFixedLengthVec(ref lfvty, ref lfvexp), &TyFixedLengthVec(ref rfvty, ref rfvexp)) => + (&TyFixedLengthVec(ref lfvty, ref lfvexp), + &TyFixedLengthVec(ref rfvty, ref rfvexp)) => is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => both(ltime, rtime, is_lifetime_equal) && is_mut_ty_equal(lrmut, rrmut), - (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => is_bare_fn_ty_equal(lbare, rbare), - (&TyTup(ref ltup), &TyTup(ref rtup)) => is_ty_vec_equal(ltup, rtup), - (&TyPath(Option::None, ref lpath), &TyPath(Option::None, ref rpath)) => is_path_equal(lpath, rpath), - (&TyPath(Option::Some(ref lqself), ref lsubpath), &TyPath(Option::Some(ref rqself), ref rsubpath)) => + (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => + is_bare_fn_ty_equal(lbare, rbare), + (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup), + (&TyPath(Option::None, ref lpath), &TyPath(Option::None, ref rpath)) => + is_path_equal(lpath, rpath), + (&TyPath(Option::Some(ref lqself), ref lsubpath), + &TyPath(Option::Some(ref rqself), ref rsubpath)) => is_qself_equal(lqself, rqself) && is_path_equal(lsubpath, rsubpath), - (&TyObjectSum(ref lsumty, ref lobounds), &TyObjectSum(ref rsumty, ref robounds)) => + (&TyObjectSum(ref lsumty, ref lobounds), + &TyObjectSum(ref rsumty, ref robounds)) => is_ty_equal(lsumty, rsumty) && is_param_bounds_equal(lobounds, robounds), - (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => is_param_bounds_equal(ltbounds, rtbounds), + (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => + is_param_bounds_equal(ltbounds, rtbounds), (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof), (&TyInfer, &TyInfer) => true, @@ -91,15 +106,17 @@ fn is_ty_equal(left : &Ty, right : &Ty) -> bool { fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) -> bool { match(left, right) { - (&TraitTyParamBound(ref lpoly, ref lmod), &TraitTyParamBound(ref rpoly, ref rmod)) => + (&TraitTyParamBound(ref lpoly, ref lmod), + &TraitTyParamBound(ref rpoly, ref rmod)) => lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), - (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => is_lifetime_equal(ltime, rtime), + (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => + is_lifetime_equal(ltime, rtime), _ => false } } fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) -> bool { - is_lifetimedef_vec_equal(&left.bound_lifetimes, &right.bound_lifetimes) && + is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) && is_path_equal(&left.trait_ref.path, &right.trait_ref.path) } @@ -113,11 +130,12 @@ fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool { fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { left.unsafety == right.unsafety && left.abi == right.abi && - is_lifetimedef_vec_equal(&left.lifetimes, &right.lifetimes) && is_fndecl_equal(&left.decl, &right.decl) + is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && + is_fndecl_equal(&left.decl, &right.decl) } fn is_fndecl_equal(left : &P, right : &P) -> bool { - left.variadic == right.variadic && is_arg_vec_equal(&left.inputs, &right.inputs) && + left.variadic == right.variadic && is_args_equal(&left.inputs, &right.inputs) && is_fnret_ty_equal(&left.output, &right.output) } @@ -133,44 +151,56 @@ fn is_arg_equal(left : &Arg, right : &Arg) -> bool { is_ty_equal(&left.ty, &right.ty) && is_pat_equal(&left.pat, &right.pat) } -fn is_arg_vec_equal(left : &Vec, right : &Vec) -> bool { +fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool { over(left, right, is_arg_equal) } fn is_pat_equal(left : &Pat, right : &Pat) -> bool { match(&left.node, &right.node) { (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, - (&PatIdent(ref lmode, ref lident, Option::None), &PatIdent(ref rmode, ref rident, Option::None)) => + (&PatIdent(ref lmode, ref lident, Option::None), + &PatIdent(ref rmode, ref rident, Option::None)) => lmode == rmode && is_ident_equal(&lident.node, &rident.node), (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node) && is_pat_equal(lpat, rpat), - (&PatEnum(ref lpath, Option::None), &PatEnum(ref rpath, Option::None)) => is_path_equal(lpath, rpath), - (&PatEnum(ref lpath, Option::Some(ref lenum)), &PatEnum(ref rpath, Option::Some(ref renum))) => - is_path_equal(lpath, rpath) && is_pat_vec_equal(lenum, renum), - (&PatStruct(ref lpath, ref lfieldpat, lbool), &PatStruct(ref rpath, ref rfieldpat, rbool)) => - lbool == rbool && is_path_equal(lpath, rpath) && is_spanned_fieldpat_vec_equal(lfieldpat, rfieldpat), - (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pat_vec_equal(ltup, rtup), + lmode == rmode && is_ident_equal(&lident.node, &rident.node) && + is_pat_equal(lpat, rpat), + (&PatEnum(ref lpath, Option::None), &PatEnum(ref rpath, Option::None)) => + is_path_equal(lpath, rpath), + (&PatEnum(ref lpath, Option::Some(ref lenum)), + &PatEnum(ref rpath, Option::Some(ref renum))) => + is_path_equal(lpath, rpath) && is_pats_equal(lenum, renum), + (&PatStruct(ref lpath, ref lfieldpat, lbool), + &PatStruct(ref rpath, ref rfieldpat, rbool)) => + lbool == rbool && is_path_equal(lpath, rpath) && + is_spanned_fieldpats_equal(lfieldpat, rfieldpat), + (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), (&PatBox(ref lboxed), &PatBox(ref rboxed)) => is_pat_equal(lboxed, rboxed), - (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => is_pat_equal(lpat, rpat) && lmut == rmut, + (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => + is_pat_equal(lpat, rpat) && lmut == rmut, (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), - (&PatVec(ref lfirst, Option::None, ref llast), &PatVec(ref rfirst, Option::None, ref rlast)) => - is_pat_vec_equal(lfirst, rfirst) && is_pat_vec_equal(llast, rlast), - (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => - is_pat_vec_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && is_pat_vec_equal(llast, rlast), + (&PatVec(ref lfirst, Option::None, ref llast), + &PatVec(ref rfirst, Option::None, ref rlast)) => + is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast), + (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), + &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => + is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && + is_pats_equal(llast, rlast), // I don't match macros for now, the code is slow enough as is ;-) _ => false } } -fn is_spanned_fieldpat_vec_equal(left : &Vec>, right : &Vec>) -> bool { +fn is_spanned_fieldpats_equal(left : &[code::Spanned], + right : &[code::Spanned]) -> bool { over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) } fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool { - left.is_shorthand == right.is_shorthand && is_ident_equal(&left.ident, &right.ident) && + left.is_shorthand == right.is_shorthand && + is_ident_equal(&left.ident, &right.ident) && is_pat_equal(&left.pat, &right.pat) } @@ -178,15 +208,16 @@ fn is_ident_equal(left : &Ident, right : &Ident) -> bool { &left.name == &right.name && left.ctxt == right.ctxt } -fn is_pat_vec_equal(left : &Vec>, right : &Vec>) -> bool { +fn is_pats_equal(left : &[P], right : &[P]) -> bool { over(left, right, |l, r| is_pat_equal(l, r)) } fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) -> bool { - is_lifetime_equal(&left.lifetime, &right.lifetime) && over(&left.bounds, &right.bounds, is_lifetime_equal) + is_lifetime_equal(&left.lifetime, &right.lifetime) && + over(&left.bounds, &right.bounds, is_lifetime_equal) } -fn is_lifetimedef_vec_equal(left : &Vec, right : &Vec) -> bool { +fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) -> bool { over(left, right, is_lifetimedef_equal) } @@ -194,21 +225,25 @@ fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool { left.name == right.name } -fn is_ty_vec_equal(left : &Vec>, right : &Vec>) -> bool { +fn is_tys_equal(left : &[P], right : &[P]) -> bool { over(left, right, |l, r| is_ty_equal(l, r)) } -fn over(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { +fn over(left: &[X], right: &[X], mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -fn both(l: &Option, r: &Option, mut eq_fn : F) -> bool where F: FnMut(&X, &X) -> bool { - if l.is_none() { r.is_none() } else { r.is_some() && eq_fn(l.as_ref().unwrap(), &r.as_ref().unwrap()) } +fn both(l: &Option, r: &Option, mut eq_fn : F) -> bool + where F: FnMut(&X, &X) -> bool { + l.as_ref().map(|x| r.as_ref().map(|y| eq_fn(x, y)).unwrap_or(false)) + .unwrap_or_else(|| r.is_none()) } fn is_cmp_or_bit(op : &BinOp) -> bool { match op.node { - BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true, + BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | + BiBitAnd | BiBitOr => true, _ => false } } diff --git a/src/misc.rs b/src/misc.rs index 5f5b07a15b7..c225c83bae2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -239,7 +239,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { let name = ident.as_str(); if name == "to_string" || name == "to_owned" { cx.span_lint(CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. + "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", cx.sess().codemap().span_to_snippet(other_span).unwrap_or( "..".to_string()))) @@ -250,7 +250,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { if path.segments.iter().zip(["String", "from_str"].iter()).all( |(seg, name)| &seg.identifier.as_str() == name) { cx.span_lint(CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. + "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", cx.sess().codemap().span_to_snippet(other_span).unwrap_or( "..".to_string()))) diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 2a71b938d71..569f7b81344 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -24,23 +24,24 @@ impl LintPass for MutMut { } unwrap_addr(expr).map(|e| { - if unwrap_addr(e).is_some() { + unwrap_addr(e).map(|_| { cx.span_lint(MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") - } else { - if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = expr_ty(cx.tcx, e).sty { + }).unwrap_or_else(|| { + if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = + expr_ty(cx.tcx, e).sty { cx.span_lint(MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. Consider reborrowing") + "This expression mutably borrows a mutable reference. \ + Consider reborrowing") } - } - }); + }) + }).unwrap_or(()) } fn check_ty(&mut self, cx: &Context, ty: &Ty) { - if unwrap_mut(ty).and_then(unwrap_mut).is_some() { - cx.span_lint(MUT_MUT, ty.span, - "Generally you want to avoid &mut &mut _ if possible.") - } + unwrap_mut(ty).and_then(unwrap_mut).map(|_| cx.span_lint(MUT_MUT, + ty.span, "Generally you want to avoid &mut &mut _ if possible.")). + unwrap_or(()) } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 378d30de57a..f8f056e7928 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -18,7 +18,6 @@ declare_lint! { "Warn on declaration of a &Vec- or &String-typed method argument" } - #[derive(Copy,Clone)] pub struct PtrArg; @@ -58,12 +57,13 @@ fn check_fn(cx: &Context, decl: &FnDecl) { } fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { - if match_ty_unwrap(ty, &["Vec"]).is_some() { - cx.span_lint(PTR_ARG, span, - "Writing '&Vec<_>' instead of '&[_]' involves one more reference and cannot be used with non-vec-based slices. Consider changing the type to &[...]"); - } else { if match_ty_unwrap(ty, &["String"]).is_some() { - cx.span_lint(PTR_ARG, span, - "Writing '&String' instead of '&str' involves a new Object where a slices will do. Consider changing the type to &str"); - } - } + match_ty_unwrap(ty, &["Vec"]).map(|_| { + cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of '&[_]' \ + involves one more reference and cannot be used with non-vec-based \ + slices. Consider changing the type to &[...]") + }).unwrap_or_else(|| match_ty_unwrap(ty, &["String"]).map(|_| { + cx.span_lint(PTR_ARG, span, + "Writing '&String' instead of '&str' involves a new Object \ + where a slices will do. Consider changing the type to &str") + }).unwrap_or(())); } -- cgit 1.4.1-3-g733a5 From 4b1c72c949328fb12d8eb72579b4ab9fa6243078 Mon Sep 17 00:00:00 2001 From: llogiq Date: Thu, 21 May 2015 16:37:38 +0200 Subject: check for str type of .to_owned() callee --- src/misc.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 5f5b07a15b7..b8ce6d725f4 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -235,11 +235,12 @@ impl LintPass for CmpOwned { fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { match &expr.node { - &ExprMethodCall(Spanned{node: ref ident, ..}, _, _) => { + &ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { let name = ident.as_str(); - if name == "to_string" || name == "to_owned" { + if name == "to_string" || + name == "to_owned" && is_str_arg(cx, args) { cx.span_lint(CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. + "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", cx.sess().codemap().span_to_snippet(other_span).unwrap_or( "..".to_string()))) @@ -250,7 +251,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { if path.segments.iter().zip(["String", "from_str"].iter()).all( |(seg, name)| &seg.identifier.as_str() == name) { cx.span_lint(CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. + "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", cx.sess().codemap().span_to_snippet(other_span).unwrap_or( "..".to_string()))) @@ -260,3 +261,8 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { _ => () } } + +fn is_str_arg(cx: &Context, args: &[P]) -> bool { + args.len() == 1 && if let ty_str = + walk_ty(expr_ty(cx.tcx, &*args[0])).sty { true } else { false } +} -- cgit 1.4.1-3-g733a5 From 0ed8e4e9683a7900b71f055d9460f42b8baa468e Mon Sep 17 00:00:00 2001 From: llogiq Date: Sat, 23 May 2015 00:49:13 +0200 Subject: another refactoring, using more fitting Option methods, improving formatting, etc. --- src/bit_mask.rs | 64 +++++++++++++++++---------------- src/eq_op.rs | 94 ++++++++++++++++++++++++++---------------------- src/identity_op.rs | 102 ++++++++++++++++++++++++++--------------------------- src/mut_mut.rs | 9 +++-- src/ptr_arg.rs | 19 +++++----- 5 files changed, 148 insertions(+), 140 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index d84da654eb4..fcf8b6cb462 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,22 +1,3 @@ -//! Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. This cannot work because the bit that makes up -//! the value two was zeroed out by the bit-and with 1. So the formula for detecting if an expression of the type -//! `_ m c` (where `` is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` ,`!=`, `>=`, -//! `>`}) can be determined from the following table: -//! -//! |Comparison |Bit-Op|Example |is always|Formula | -//! |------------|------|------------|---------|----------------------| -//! |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -//! |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -//! |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -//! |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -//! |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -//! |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | -//! -//! *TODO*: There is the open question if things like `x | 1 > 1` should be caught by this lint, because it is basically -//! an obfuscated version of `x > 1`. -//! -//! This lint is **deny** by default - use rustc::plugin::Registry; use rustc::lint::*; use rustc::middle::const_eval::lookup_const_by_id; @@ -29,15 +10,37 @@ use syntax::codemap::Span; declare_lint! { pub BAD_BIT_MASK, Deny, - "Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'" + "Deny the use of incompatible bit masks in comparisons, e.g. \ + '(a & 1) == 2'" } declare_lint! { pub INEFFECTIVE_BIT_MASK, Warn, - "Warn on the use of an ineffective bit mask in comparisons, e.g. '(a & 1) > 2'" + "Warn on the use of an ineffective bit mask in comparisons, e.g. \ + '(a & 1) > 2'" } +/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. +/// This cannot work because the bit that makes up the value two was +/// zeroed out by the bit-and with 1. So the formula for detecting if an +/// expression of the type `_ m c` (where `` +/// is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` , +/// `!=`, `>=`, `>`}) can be determined from the following table: +/// +/// |Comparison |Bit-Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// +/// This lint is **deny** by default +/// +/// There is also a lint that warns on ineffective masks that is *warn* +/// by default #[derive(Copy,Clone)] pub struct BitMask; @@ -49,11 +52,12 @@ impl LintPass for BitMask { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { - fetch_int_literal(cx, right).map(|cmp_opt| - check_compare(cx, left, cmp.node, cmp_opt, &e.span)) - .unwrap_or_else(|| fetch_int_literal(cx, left).map(|cmp_val| - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, - &e.span)).unwrap_or(())) + fetch_int_literal(cx, right).map_or_else(|| + fetch_int_literal(cx, left).map_or((), |cmp_val| + check_compare(cx, right, invert_cmp(cmp.node), + cmp_val, &e.span)), + |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, + &e.span)) } } } @@ -77,11 +81,9 @@ fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, sp &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), &ExprBinary(ref op, ref left, ref right) => { if op.node != BiBitAnd && op.node != BiBitOr { return; } - if let Some(mask_value) = fetch_int_literal(cx, right) { - check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); - } else if let Some(mask_value) = fetch_int_literal(cx, left) { - check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span); - } + fetch_int_literal(cx, right).or_else(|| fetch_int_literal( + cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, + cmp_op, mask, cmp_value, span)) }, _ => () } diff --git a/src/eq_op.rs b/src/eq_op.rs index 0223820447d..94a49e748e2 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -33,18 +33,20 @@ fn is_exp_equal(left : &Expr, right : &Expr) -> bool { match (&left.node, &right.node) { (&ExprBinary(ref lop, ref ll, ref lr), &ExprBinary(ref rop, ref rl, ref rr)) => - lop.node == rop.node && is_exp_equal(ll, rl) && is_exp_equal(lr, rr), - (&ExprBox(ref lpl, ref lboxedpl), &ExprBox(ref rpl, ref rboxedpl)) => + lop.node == rop.node && + is_exp_equal(ll, rl) && is_exp_equal(lr, rr), + (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => both(lpl, rpl, |l, r| is_exp_equal(l, r)) && - is_exp_equal(lboxedpl, rboxedpl), - (&ExprCall(ref lcallee, ref largs), &ExprCall(ref rcallee, ref rargs)) => - is_exp_equal(lcallee, rcallee) && is_exps_equal(largs, rargs), - (&ExprCast(ref lcast, ref lty), &ExprCast(ref rcast, ref rty)) => - is_ty_equal(lty, rty) && is_exp_equal(lcast, rcast), + is_exp_equal(lbox, rbox), + (&ExprCall(ref lcallee, ref largs), + &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, + rcallee) && is_exps_equal(largs, rargs), + (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => + is_ty_equal(lty, rty) && is_exp_equal(lc, rc), (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), - (&ExprLit(ref llit), &ExprLit(ref rlit)) => llit.node == rlit.node, + (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprMethodCall(ref lident, ref lcty, ref lmargs), &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => lident.node == rident.node && is_tys_equal(lcty, rcty) && @@ -55,10 +57,11 @@ fn is_exp_equal(left : &Expr, right : &Expr) -> bool { &ExprPath(ref rqself, ref rsubpath)) => both(lqself, rqself, |l, r| is_qself_equal(l, r)) && is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(ltup, rtup), - (&ExprUnary(lunop, ref lparam), &ExprUnary(runop, ref rparam)) => - lunop == runop && is_exp_equal(lparam, rparam), - (&ExprVec(ref lvec), &ExprVec(ref rvec)) => is_exps_equal(lvec, rvec), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => + is_exps_equal(ltup, rtup), + (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => + lunop == runop && is_exp_equal(l, r), + (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r), _ => false } } @@ -83,18 +86,17 @@ fn is_ty_equal(left : &Ty, right : &Ty) -> bool { is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => - both(ltime, rtime, is_lifetime_equal) && is_mut_ty_equal(lrmut, rrmut), + both(ltime, rtime, is_lifetime_equal) && + is_mut_ty_equal(lrmut, rrmut), (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => is_bare_fn_ty_equal(lbare, rbare), (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup), - (&TyPath(Option::None, ref lpath), &TyPath(Option::None, ref rpath)) => - is_path_equal(lpath, rpath), - (&TyPath(Option::Some(ref lqself), ref lsubpath), - &TyPath(Option::Some(ref rqself), ref rsubpath)) => - is_qself_equal(lqself, rqself) && is_path_equal(lsubpath, rsubpath), + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => + both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), (&TyObjectSum(ref lsumty, ref lobounds), &TyObjectSum(ref rsumty, ref robounds)) => - is_ty_equal(lsumty, rsumty) && is_param_bounds_equal(lobounds, robounds), + is_ty_equal(lsumty, rsumty) && + is_param_bounds_equal(lobounds, robounds), (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => is_param_bounds_equal(ltbounds, rtbounds), (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), @@ -104,7 +106,8 @@ fn is_ty_equal(left : &Ty, right : &Ty) -> bool { } } -fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) -> bool { +fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) + -> bool { match(left, right) { (&TraitTyParamBound(ref lpoly, ref lmod), &TraitTyParamBound(ref rpoly, ref rmod)) => @@ -115,12 +118,14 @@ fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) -> bool { } } -fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) -> bool { - is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) && - is_path_equal(&left.trait_ref.path, &right.trait_ref.path) +fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) + -> bool { + is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) + && is_path_equal(&left.trait_ref.path, &right.trait_ref.path) } -fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) -> bool { +fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) + -> bool { over(left, right, is_param_bound_equal) } @@ -135,20 +140,23 @@ fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { } fn is_fndecl_equal(left : &P, right : &P) -> bool { - left.variadic == right.variadic && is_args_equal(&left.inputs, &right.inputs) && + left.variadic == right.variadic && + is_args_equal(&left.inputs, &right.inputs) && is_fnret_ty_equal(&left.output, &right.output) } -fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) -> bool { +fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) + -> bool { match (left, right) { - (&NoReturn(_), &NoReturn(_)) | (&DefaultReturn(_), &DefaultReturn(_)) => true, + (&NoReturn(_), &NoReturn(_)) | + (&DefaultReturn(_), &DefaultReturn(_)) => true, (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), _ => false } } -fn is_arg_equal(left : &Arg, right : &Arg) -> bool { - is_ty_equal(&left.ty, &right.ty) && is_pat_equal(&left.pat, &right.pat) +fn is_arg_equal(l: &Arg, r : &Arg) -> bool { + is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat) } fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool { @@ -165,17 +173,16 @@ fn is_pat_equal(left : &Pat, right : &Pat) -> bool { &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => lmode == rmode && is_ident_equal(&lident.node, &rident.node) && is_pat_equal(lpat, rpat), - (&PatEnum(ref lpath, Option::None), &PatEnum(ref rpath, Option::None)) => - is_path_equal(lpath, rpath), - (&PatEnum(ref lpath, Option::Some(ref lenum)), - &PatEnum(ref rpath, Option::Some(ref renum))) => - is_path_equal(lpath, rpath) && is_pats_equal(lenum, renum), + (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => + is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| + is_pats_equal(l, r)), (&PatStruct(ref lpath, ref lfieldpat, lbool), &PatStruct(ref rpath, ref rfieldpat, rbool)) => lbool == rbool && is_path_equal(lpath, rpath) && is_spanned_fieldpats_equal(lfieldpat, rfieldpat), (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), - (&PatBox(ref lboxed), &PatBox(ref rboxed)) => is_pat_equal(lboxed, rboxed), + (&PatBox(ref lboxed), &PatBox(ref rboxed)) => + is_pat_equal(lboxed, rboxed), (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => is_pat_equal(lpat, rpat) && lmut == rmut, (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), @@ -212,12 +219,14 @@ fn is_pats_equal(left : &[P], right : &[P]) -> bool { over(left, right, |l, r| is_pat_equal(l, r)) } -fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) -> bool { +fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) + -> bool { is_lifetime_equal(&left.lifetime, &right.lifetime) && over(&left.bounds, &right.bounds, is_lifetime_equal) } -fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) -> bool { +fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) + -> bool { over(left, right, is_lifetimedef_equal) } @@ -231,19 +240,20 @@ fn is_tys_equal(left : &[P], right : &[P]) -> bool { fn over(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| + eq_fn(x, y)) } fn both(l: &Option, r: &Option, mut eq_fn : F) -> bool where F: FnMut(&X, &X) -> bool { - l.as_ref().map(|x| r.as_ref().map(|y| eq_fn(x, y)).unwrap_or(false)) - .unwrap_or_else(|| r.is_none()) + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, + |y| eq_fn(x, y))) } fn is_cmp_or_bit(op : &BinOp) -> bool { match op.node { - BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | - BiBitAnd | BiBitOr => true, + BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | + BiBitXor | BiBitAnd | BiBitOr => true, _ => false } } diff --git a/src/identity_op.rs b/src/identity_op.rs index ec4495539d2..25697199dc3 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -17,66 +17,64 @@ impl LintPass for IdentityOp { fn get_lints(&self) -> LintArray { lint_array!(IDENTITY_OP) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = e.node { - match cmp.node { - 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); - }, - _ => () - } - } + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + match cmp.node { + 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); + }, + _ => () + } + } } } fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { - if have_lit(cx, e, m) { - let map = cx.sess().codemap(); - cx.span_lint(IDENTITY_OP, span, &format!( - "The operation is ineffective. Consider reducing it to '{}'", - &*map.span_to_snippet(arg).unwrap_or("..".to_string()))); - } + if have_lit(cx, e, m) { + let map = cx.sess().codemap(); + cx.span_lint(IDENTITY_OP, span, &format!( + "The operation is ineffective. Consider reducing it to '{}'", + &*map.span_to_snippet(arg).unwrap_or("..".to_string()))); + } } fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool { - match &e.node { - &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), - &ExprLit(ref lit) => { - match (&lit.node, m) { - (&LitInt(0, _), 0) => true, - (&LitInt(1, SignedIntLit(_, Plus)), 1) => true, - (&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true, - (&LitInt(1, SignedIntLit(_, Minus)), -1) => true, - (&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true, - _ => false - } - }, - &ExprParen(ref p) => have_lit(cx, p, m), - &ExprPath(_, _) => { - match cx.tcx.def_map.borrow().get(&e.id) { - Some(&PathResolution { base_def: DefConst(def_id), ..}) => - match lookup_const_by_id(cx.tcx, def_id, Option::None) { - Some(l) => have_lit(cx, l, m), - None => false - }, - _ => false - } + match &e.node { + &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), + &ExprLit(ref lit) => { + match (&lit.node, m) { + (&LitInt(0, _), 0) => true, + (&LitInt(1, SignedIntLit(_, Plus)), 1) => true, + (&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true, + (&LitInt(1, SignedIntLit(_, Minus)), -1) => true, + (&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true, + _ => false + } + }, + &ExprParen(ref p) => have_lit(cx, p, m), + &ExprPath(_, _) => { + match cx.tcx.def_map.borrow().get(&e.id) { + Some(&PathResolution { base_def: DefConst(id), ..}) => + lookup_const_by_id(cx.tcx, id, Option::None) + .map_or(false, |l| have_lit(cx, l, m)), + _ => false } - _ => false - } + }, + _ => false + } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 569f7b81344..bf8155b5c3c 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -23,7 +23,7 @@ impl LintPass for MutMut { } } - unwrap_addr(expr).map(|e| { + unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map(|_| { cx.span_lint(MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") @@ -35,13 +35,12 @@ impl LintPass for MutMut { Consider reborrowing") } }) - }).unwrap_or(()) + }) } fn check_ty(&mut self, cx: &Context, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map(|_| cx.span_lint(MUT_MUT, - ty.span, "Generally you want to avoid &mut &mut _ if possible.")). - unwrap_or(()) + unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| cx.span_lint(MUT_MUT, + ty.span, "Generally you want to avoid &mut &mut _ if possible.")) } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index f8f056e7928..86b87a942be 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -47,23 +47,22 @@ impl LintPass for PtrArg { fn check_fn(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - let ty = &arg.ty; - match ty.node { - TyPtr(ref pty) => check_ptr_subtype(cx, ty.span, &pty.ty), - TyRptr(_, ref rpty) => check_ptr_subtype(cx, ty.span, &rpty.ty), + match &arg.ty.node { + &TyPtr(ref p) | &TyRptr(_, ref p) => + check_ptr_subtype(cx, arg.ty.span, &p.ty), _ => () } } } fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { - match_ty_unwrap(ty, &["Vec"]).map(|_| { - cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of '&[_]' \ - involves one more reference and cannot be used with non-vec-based \ - slices. Consider changing the type to &[...]") - }).unwrap_or_else(|| match_ty_unwrap(ty, &["String"]).map(|_| { + match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, + &["String"]).map_or((), |_| { cx.span_lint(PTR_ARG, span, "Writing '&String' instead of '&str' involves a new Object \ where a slices will do. Consider changing the type to &str") - }).unwrap_or(())); + }), |_| cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of \ + '&[_]' involves one more reference and cannot be used with \ + non-vec-based slices. Consider changing the type to &[...]") + ) } -- cgit 1.4.1-3-g733a5 From b51ca1c3db2c4d2195f325c28bdff83c771705ca Mon Sep 17 00:00:00 2001 From: llogiq Date: Sat, 23 May 2015 12:32:29 +0200 Subject: Formatting fixed --- src/bit_mask.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index fcf8b6cb462..352826dffae 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -34,7 +34,7 @@ declare_lint! { /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | /// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | /// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// /// This lint is **deny** by default -- cgit 1.4.1-3-g733a5 From a133dc445164438b86f9d89f012839820ea0bdb7 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sun, 24 May 2015 19:06:54 +0100 Subject: Fix copy+paste in description of LEN_ZERO --- src/len_zero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 18ddbccc9a2..2ed0a6a9fab 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -8,7 +8,7 @@ use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; declare_lint!(pub LEN_ZERO, Warn, - "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); + "Warn when .is_empty() could be used instead of checking .len()"); declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, "Warn on traits and impls that have .len() but not .is_empty()"); -- cgit 1.4.1-3-g733a5 From a67e0f6e2f088f930c2f7447b9a8f407cc830c94 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 25 May 2015 07:22:41 +0200 Subject: first prototype of macro expn detection in mut_mut.rs --- src/mut_mut.rs | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index bf8155b5c3c..b1e21def574 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -2,6 +2,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt}; +use syntax::codemap::ExpnInfo; declare_lint!(pub MUT_MUT, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -15,27 +16,8 @@ impl LintPass for MutMut { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - - fn unwrap_addr(expr : &Expr) -> Option<&Expr> { - match expr.node { - ExprAddrOf(MutMutable, ref e) => Option::Some(e), - _ => Option::None - } - } - - unwrap_addr(expr).map_or((), |e| { - unwrap_addr(e).map(|_| { - cx.span_lint(MUT_MUT, expr.span, - "Generally you want to avoid &mut &mut _ if possible.") - }).unwrap_or_else(|| { - if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = - expr_ty(cx.tcx, e).sty { - cx.span_lint(MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. \ - Consider reborrowing") - } - }) - }) + cx.sess().codemap().with_expn_info(expr.span.expn_id, + |info| check_expr_expd(cx, expr, info)) } fn check_ty(&mut self, cx: &Context, ty: &Ty) { @@ -44,6 +26,35 @@ impl LintPass for MutMut { } } +fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { + if in_external_macro(info) { return; } + + fn unwrap_addr(expr : &Expr) -> Option<&Expr> { + match expr.node { + ExprAddrOf(MutMutable, ref e) => Option::Some(e), + _ => Option::None + } + } + + unwrap_addr(expr).map_or((), |e| { + unwrap_addr(e).map(|_| { + cx.span_lint(MUT_MUT, expr.span, + "Generally you want to avoid &mut &mut _ if possible.") + }).unwrap_or_else(|| { + if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = + expr_ty(cx.tcx, e).sty { + cx.span_lint(MUT_MUT, expr.span, + "This expression mutably borrows a mutable reference. \ + Consider reborrowing") + } + }) + }) +} + +fn in_external_macro(info: Option<&ExpnInfo>) -> bool { + info.map_or(false, |i| i.callee.span.is_some()) +} + fn unwrap_mut(ty : &Ty) -> Option<&Ty> { match ty.node { TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), -- cgit 1.4.1-3-g733a5 From 73e3ef6d0e2c1da8b5eb8b5b13bdd6d2929bfa5f Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 25 May 2015 22:50:41 +0200 Subject: fixed issue #69 --- src/ptr_arg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 86b87a942be..64c3c84c7b6 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -27,7 +27,7 @@ impl LintPass for PtrArg { } fn check_item(&mut self, cx: &Context, item: &Item) { - if let &ItemFn(ref decl, _, _, _, _) = &item.node { + if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { check_fn(cx, decl); } } -- cgit 1.4.1-3-g733a5 From 0d651c72ff4c8833046dbdad0049893fbc57bef2 Mon Sep 17 00:00:00 2001 From: llogiq Date: Tue, 26 May 2015 01:45:15 +0200 Subject: made macro test even simpler, added a few tests --- Cargo.toml | 2 ++ src/lib.rs | 1 - src/mut_mut.rs | 6 +++--- src/ptr_arg.rs | 2 +- tests/compile-fail/mut_mut.rs | 9 +++++++++ tests/compile-test.rs | 2 +- tests/run-pass.rs | 11 +++++++++++ 7 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 95de98e8ee5..3c7d9be64e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,5 @@ plugin = true [dev-dependencies] compiletest_rs = "*" +regex = "*" +regex_macros = "*" diff --git a/src/lib.rs b/src/lib.rs index cf5def800a2..92cc7ef254c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] - #![allow(unused_imports)] #[macro_use] diff --git a/src/mut_mut.rs b/src/mut_mut.rs index b1e21def574..160b99a1d15 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -27,7 +27,7 @@ impl LintPass for MutMut { } fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { - if in_external_macro(info) { return; } + if in_macro(info) { return; } fn unwrap_addr(expr : &Expr) -> Option<&Expr> { match expr.node { @@ -51,8 +51,8 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { }) } -fn in_external_macro(info: Option<&ExpnInfo>) -> bool { - info.map_or(false, |i| i.callee.span.is_some()) +fn in_macro(info: Option<&ExpnInfo>) -> bool { + info.is_some() } fn unwrap_mut(ty : &Ty) -> Option<&Ty> { diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 86b87a942be..64c3c84c7b6 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -27,7 +27,7 @@ impl LintPass for PtrArg { } fn check_item(&mut self, cx: &Context, item: &Item) { - if let &ItemFn(ref decl, _, _, _, _) = &item.node { + if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { check_fn(cx, decl); } } diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 65e3762e2c4..d7adc067740 100644 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -1,11 +1,18 @@ #![feature(plugin)] #![plugin(clippy)] +//#![plugin(regex_macros)] +//extern crate regex; + #[deny(mut_mut)] fn fun(x : &mut &mut u32) -> bool { //~ERROR **x > 0 } +macro_rules! mut_ptr { + ($p:expr) => { &mut $p } +} + #[deny(mut_mut)] #[allow(unused_mut, unused_variables)] fn main() { @@ -22,4 +29,6 @@ fn main() { //~^^^^ ERROR ***y + **x; } + + let mut z = mut_ptr!(&mut 3u32); //~ERROR } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 04f3fc16b1b..6fcf71d38ad 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; fn run_mode(mode: &'static str) { let mut config = compiletest::default_config(); let cfg_mode = mode.parse().ok().expect("Invalid mode"); - config.target_rustcflags = Some("-L target/debug/".to_string()); + config.target_rustcflags = Some("-l regex_macros -L target/debug/".to_string()); config.mode = cfg_mode; config.src_base = PathBuf::from(format!("tests/{}", mode)); diff --git a/tests/run-pass.rs b/tests/run-pass.rs new file mode 100644 index 00000000000..bc39278606c --- /dev/null +++ b/tests/run-pass.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy, regex_macros)] + +extern crate regex; + +#[test] +#[deny(mut_mut)] +fn test_regex() { + let pattern = regex!(r"^(?P[#]+)\s(?P.+)$"); + assert!(pattern.is_match("# headline")); +} -- cgit 1.4.1-3-g733a5 From cd2e621c60b897a2f37fab36bc357da30aa9cc54 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 26 May 2015 13:52:40 +0200 Subject: made in_macro distinguish intra-crate and extra-crate macros, as the latter have no working source (note: may fail in the face of compiler plugins doing whatever they like with spans), also one more run-pass test --- Cargo.toml | 1 + src/mut_mut.rs | 14 ++++++++++---- tests/run-pass.rs | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 3c7d9be64e3..e1308fb9cb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ plugin = true compiletest_rs = "*" regex = "*" regex_macros = "*" +lazy_static = "*" diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 160b99a1d15..a4c2d3932a3 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -2,7 +2,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt}; -use syntax::codemap::ExpnInfo; +use syntax::codemap::{BytePos, ExpnInfo, MacroFormat, Span}; declare_lint!(pub MUT_MUT, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -27,7 +27,7 @@ impl LintPass for MutMut { } fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { - if in_macro(info) { return; } + if in_macro(cx, info) { return; } fn unwrap_addr(expr : &Expr) -> Option<&Expr> { match expr.node { @@ -51,8 +51,14 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { }) } -fn in_macro(info: Option<&ExpnInfo>) -> bool { - info.is_some() +fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { + opt_info.map_or(false, |info| { + info.callee.span.map_or(true, |span| { + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + !code.starts_with("macro_rules") + ) + }) + }) } fn unwrap_mut(ty : &Ty) -> Option<&Ty> { diff --git a/tests/run-pass.rs b/tests/run-pass.rs index bc39278606c..32fdea3a340 100644 --- a/tests/run-pass.rs +++ b/tests/run-pass.rs @@ -1,11 +1,31 @@ #![feature(plugin)] #![plugin(clippy, regex_macros)] +#[macro_use] +extern crate lazy_static; extern crate regex; +use std::collections::HashMap; + #[test] #[deny(mut_mut)] fn test_regex() { let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); assert!(pattern.is_match("# headline")); } + +#[test] +#[deny(mut_mut)] +#[allow(unused_variables, unused_mut)] +fn test_lazy_static() { + lazy_static! { + static ref MUT_MAP : HashMap<usize, &'static str> = { + let mut m = HashMap::new(); + let mut zero = &mut &mut "zero"; + m.insert(0, "zero"); + m + }; + static ref MUT_COUNT : usize = MUT_MAP.len(); + } + assert!(*MUT_COUNT == 1); +} -- cgit 1.4.1-3-g733a5 From 7e16822925380d4c4236caec116c8076b8ca150a Mon Sep 17 00:00:00 2001 From: Matthew Hall <matthew@quickbeam.me.uk> Date: Fri, 29 May 2015 15:07:34 +0100 Subject: Add lint for ifs that could be collapsed "Collapsible" ifs are ones which contain only a then block, and the then block consists of an if that only has a then block. --- src/collapsible_if.rs | 80 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ tests/compile-fail/collapsible_if.rs | 37 +++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/collapsible_if.rs create mode 100644 tests/compile-fail/collapsible_if.rs (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs new file mode 100644 index 00000000000..31ac1e62be6 --- /dev/null +++ b/src/collapsible_if.rs @@ -0,0 +1,80 @@ +//! Checks for if expressions that contain only an if expression. +//! +//! For example, the lint would catch: +//! +//! ``` +//! if x { +//! if y { +//! println!("Hello world"); +//! } +//! } +//! ``` +//! +//! This lint is **warn** by default + +use rustc::plugin::Registry; +use rustc::lint::*; +use rustc::middle::def::*; +use syntax::ast::*; +use syntax::ptr::P; +use syntax::codemap::{Span, Spanned}; +use syntax::print::pprust::expr_to_string; + +declare_lint! { + pub COLLAPSIBLE_IF, + Warn, + "Warn on if expressions that can be collapsed" +} + +#[derive(Copy,Clone)] +pub struct CollapsibleIf; + +impl LintPass for CollapsibleIf { + fn get_lints(&self) -> LintArray { + lint_array!(COLLAPSIBLE_IF) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let ExprIf(ref check, ref then_block, None) = e.node { + let expr = check_block(then_block); + let expr = match expr { + Some(e) => e, + None => return + }; + if let ExprIf(ref check_inner, _, None) = expr.node { + let (check, check_inner) = (check_to_string(check), check_to_string(check_inner)); + cx.span_lint(COLLAPSIBLE_IF, e.span, + &format!("This if statement can be collapsed. Try: if {} && {}", check, check_inner)); + } + } + } +} + +fn requires_brackets(e: &Expr) -> bool { + match e.node { + ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false, + _ => true + } +} + +fn check_to_string(e: &Expr) -> String { + if requires_brackets(e) { + format!("({})", expr_to_string(e)) + } else { + format!("{}", expr_to_string(e)) + } +} + +fn check_block(b: &Block) -> Option<&P<Expr>> { + if b.stmts.len() == 1 && b.expr.is_none() { + let stmt = &b.stmts[0]; + return match stmt.node { + StmtExpr(ref e, _) => Some(e), + _ => None + }; + } + if let Some(ref e) = b.expr { + return Some(e); + } + None +} diff --git a/src/lib.rs b/src/lib.rs index cf5def800a2..00d28deeed9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ pub mod eta_reduction; pub mod identity_op; pub mod mut_mut; pub mod len_zero; +pub mod collapsible_if; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -45,6 +46,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); reg.register_lint_pass(box len_zero::LenZero as LintPassObject); reg.register_lint_pass(box misc::CmpOwned as LintPassObject); + reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -61,5 +63,6 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_mut::MUT_MUT, len_zero::LEN_ZERO, len_zero::LEN_WITHOUT_IS_EMPTY, + collapsible_if::COLLAPSIBLE_IF, ]); } diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs new file mode 100644 index 00000000000..3aa86c893c6 --- /dev/null +++ b/tests/compile-fail/collapsible_if.rs @@ -0,0 +1,37 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(collapsible_if)] +fn main() { + let x = "hello"; + let y = "world"; + if x == "hello" { //~ERROR This if statement can be collapsed + if y == "world" { + println!("Hello world!"); + } + } + + if x == "hello" || x == "world" { //~ERROR This if statement can be collapsed + if y == "world" || y == "hello" { + println!("Hello world!"); + } + } + + // Works because any if with an else statement cannot be collapsed. + if x == "hello" { + if y == "world" { + println!("Hello world!"); + } + } else { + println!("Not Hello world"); + } + + if x == "hello" { + if y == "world" { + println!("Hello world!"); + } else { + println!("Hello something else"); + } + } + +} -- cgit 1.4.1-3-g733a5 From 77838d6ba78c23fdc337da7ece974beda95280df Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 30 May 2015 15:10:19 +0200 Subject: New lint for issue #72 --- src/attrs.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ tests/compile-fail/attrs.rs | 12 ++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/attrs.rs create mode 100644 tests/compile-fail/attrs.rs (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs new file mode 100644 index 00000000000..3ad3889f9db --- /dev/null +++ b/src/attrs.rs @@ -0,0 +1,48 @@ +/// checks for attributes + +use rustc::plugin::Registry; +use rustc::lint::*; +use syntax::ast::*; +use syntax::ptr::P; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; + +declare_lint! { pub INLINE_ALWAYS, Warn, + "#[inline(always)] is usually a bad idea."} + + +#[derive(Copy,Clone)] +pub struct AttrPass; + +impl LintPass for AttrPass { + fn get_lints(&self) -> LintArray { + lint_array!(INLINE_ALWAYS) + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + check_attrs(cx, &item.ident, &item.attrs) + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + check_attrs(cx, &item.ident, &item.attrs) + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + check_attrs(cx, &item.ident, &item.attrs) + } +} + +fn check_attrs(cx: &Context, ident: &Ident, attrs: &[Attribute]) { + for attr in attrs { + if let MetaList(ref inline, ref values) = attr.node.value.node { + if values.len() != 1 || inline != &"inline" { continue; } + if let MetaWord(ref always) = values[0].node { + if always != &"always" { continue; } + cx.span_lint(INLINE_ALWAYS, attr.span, &format!( + "You have declared #[inline(always)] on {}. This \ + is usually a bad idea. Are you sure?", + ident.as_str())); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 92cc7ef254c..918f8813cd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ pub mod eta_reduction; pub mod identity_op; pub mod mut_mut; pub mod len_zero; +pub mod attrs; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -44,6 +45,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); reg.register_lint_pass(box len_zero::LenZero as LintPassObject); reg.register_lint_pass(box misc::CmpOwned as LintPassObject); + reg.register_lint_pass(box attrs::AttrPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -60,5 +62,6 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_mut::MUT_MUT, len_zero::LEN_ZERO, len_zero::LEN_WITHOUT_IS_EMPTY, + attrs::INLINE_ALWAYS, ]); } diff --git a/tests/compile-fail/attrs.rs b/tests/compile-fail/attrs.rs new file mode 100644 index 00000000000..30ce191d3db --- /dev/null +++ b/tests/compile-fail/attrs.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(inline_always)] +#[inline(always)] //~ERROR You have declared #[inline(always)] on test_attr_lint. +fn test_attr_lint() { + assert!(true) +} + +fn main() { + test_attr_lint() +} -- cgit 1.4.1-3-g733a5 From 423a9666ca5c688dfd333cc7e6a93944b23a9f6f Mon Sep 17 00:00:00 2001 From: Matthew Hall <matthew@quickbeam.me.uk> Date: Sun, 31 May 2015 13:17:31 +0100 Subject: Implements #45 - any number mod 1 will be 0 --- src/lib.rs | 2 ++ src/misc.rs | 31 +++++++++++++++++++++++++++++++ tests/compile-fail/modulo_one.rs | 8 ++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/compile-fail/modulo_one.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 00d28deeed9..1d760bde99a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box len_zero::LenZero as LintPassObject); reg.register_lint_pass(box misc::CmpOwned as LintPassObject); reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); + reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -64,5 +65,6 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_ZERO, len_zero::LEN_WITHOUT_IS_EMPTY, collapsible_if::COLLAPSIBLE_IF, + misc::MODULO_ONE, ]); } diff --git a/src/misc.rs b/src/misc.rs index b8ce6d725f4..590ebbc3f9f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -266,3 +266,34 @@ fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty_str = walk_ty(expr_ty(cx.tcx, &*args[0])).sty { true } else { false } } + + +declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0"); + +#[derive(Copy,Clone)] +pub struct ModuloOne; + +impl LintPass for ModuloOne { + fn get_lints(&self) -> LintArray { + lint_array!(MODULO_ONE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, _, ref right) = expr.node { + if let &Spanned {node: BinOp_::BiRem, ..} = cmp { + if is_lit_one(right) { + cx.span_lint(MODULO_ONE, expr.span, "Any number modulo 1 will be 0"); + } + } + } + } +} + +fn is_lit_one(expr: &Expr) -> bool { + if let ExprLit(ref spanned) = expr.node { + if let LitInt(1, _) = spanned.node { + return true; + } + } + false +} diff --git a/tests/compile-fail/modulo_one.rs b/tests/compile-fail/modulo_one.rs new file mode 100644 index 00000000000..26c7de855e5 --- /dev/null +++ b/tests/compile-fail/modulo_one.rs @@ -0,0 +1,8 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(modulo_one)] + +fn main() { + 10 % 1; //~ERROR Any number modulo 1 will be 0 + 10 % 2; +} -- cgit 1.4.1-3-g733a5 From 21cd0c7e703c1303930f1b6735384ae806fd7c01 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Jun 2015 07:40:33 +0200 Subject: check for is_empty() method to get rid of false positives --- src/len_zero.rs | 36 +++++++++++++++++++++++++++++++----- tests/compile-fail/len_zero.rs | 3 +-- 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 18ddbccc9a2..621cee57328 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,11 +1,15 @@ extern crate rustc_typeck as typeck; +use std::rc::Rc; +use std::cell::RefCell; use syntax::ptr::P; -use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, mt, MethodTraitItemId}; +use rustc::util::nodemap::DefIdMap; +use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, expr_ty, + mt, ty_to_def_id, impl_or_trait_item, MethodTraitItemId, ImplOrTraitItemId}; use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; +use syntax::ast::*; declare_lint!(pub LEN_ZERO, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -69,7 +73,9 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { for i in impl_items { if is_named_self(i, "len") { - cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span, + let s = i.span; + cx.span_lint(LEN_WITHOUT_IS_EMPTY, + Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, &format!("Item '{}' has a '.len()' method, but no \ '.is_empty()' method. Consider adding one.", item.ident.as_str())); @@ -92,10 +98,30 @@ fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, empty: &str) { if let &Spanned{node: LitInt(0, _), ..} = lit { - if method.node.as_str() == "len" && args.len() == 1 { + if method.node.as_str() == "len" && args.len() == 1 && + has_is_empty(cx, &expr_ty(cx.tcx, &*args[0])) { cx.span_lint(LEN_ZERO, span, &format!( - "Consider replacing the len comparison with '{}_.is_empty()' if available", + "Consider replacing the len comparison with \ + '{}_.is_empty()' if available", empty)) } } } + +fn has_is_empty(cx: &Context, ty: &::rustc::middle::ty::Ty) -> bool { + fn check_item(cx: &Context, id: &ImplOrTraitItemId) -> bool { + if let &MethodTraitItemId(ref def_id) = id { + if let ty::MethodTraitItem(ref method) = ty::impl_or_trait_item( + cx.tcx, *def_id) { + method.name.as_str() == "is_empty" + } else { false } + } else { false } + } + + ::rustc::middle::ty::ty_to_def_id(ty).map_or(true, |id| { + cx.tcx.impl_items.borrow().get(&id).map_or(false, |item_ids| { + item_ids.iter().any(|i| check_item(cx, i)) + }) || cx.tcx.trait_item_def_ids.borrow().get(&id).map_or(false, + |item_ids| { item_ids.iter().any(|i| check_item(cx, i)) }) + }) +} diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 14f2506ec8b..39fcb3c1804 100644 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -44,8 +44,7 @@ fn main() { } let y = One; - // false positives here - if y.len() == 0 { //~ERROR Consider replacing the len comparison + if y.len() == 0 { //no error because One does not have .is_empty() println!("This should not happen either!"); } -- cgit 1.4.1-3-g733a5 From cdca2c93c1949fcb9a4e3dd696fff01f3ff3dcf1 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Jun 2015 12:49:36 +0200 Subject: now the method lookup actually works (and I understand why! :smile:), reduces unnecessary loops, and has a few comments --- src/len_zero.rs | 64 +++++++++++++++++++++++++++++------------- src/misc.rs | 2 +- tests/compile-fail/len_zero.rs | 59 ++++++++++++++++++++++++++++++++++---- tests/mut_mut_macro.rs | 11 ++++++++ tests/run-pass.rs | 11 -------- 5 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 tests/mut_mut_macro.rs delete mode 100644 tests/run-pass.rs (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 621cee57328..fef280199bd 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -10,6 +10,7 @@ use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, expr_ty, use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; +use misc::walk_ty; declare_lint!(pub LEN_ZERO, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -49,7 +50,8 @@ impl LintPass for LenZero { fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.ident.as_str() == name && item.attrs.len() == 0 + item.ident.as_str() == name && if let MethodTraitItem(ref sig, _) = + item.node { is_self_sig(sig) } else { false } } if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { @@ -57,8 +59,8 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { for i in trait_items { if is_named_self(i, "len") { cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span, - &format!("Trait '{}' has a '.len()' method, but no \ - '.is_empty()' method. Consider adding one.", + &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ + '.is_empty(_: &Self)' method. Consider adding one.", item.ident.as_str())); } }; @@ -67,7 +69,8 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.ident.as_str() == name && item.attrs.len() == 0 + item.ident.as_str() == name && if let MethodImplItem(ref sig, _) = + item.node { is_self_sig(sig) } else { false } } if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { @@ -76,8 +79,8 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { let s = i.span; cx.span_lint(LEN_WITHOUT_IS_EMPTY, Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, - &format!("Item '{}' has a '.len()' method, but no \ - '.is_empty()' method. Consider adding one.", + &format!("Item '{}' has a '.len(_: &Self)' method, but no \ + '.is_empty(_: &Self)' method. Consider adding one.", item.ident.as_str())); return; } @@ -85,6 +88,11 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { } } +fn is_self_sig(sig: &MethodSig) -> bool { + if let SelfStatic = sig.explicit_self.node { + false } else { sig.decl.inputs.len() == 1 } +} + fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => @@ -99,29 +107,45 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, empty: &str) { if let &Spanned{node: LitInt(0, _), ..} = lit { if method.node.as_str() == "len" && args.len() == 1 && - has_is_empty(cx, &expr_ty(cx.tcx, &*args[0])) { + has_is_empty(cx, &*args[0]) { cx.span_lint(LEN_ZERO, span, &format!( - "Consider replacing the len comparison with \ - '{}_.is_empty()' if available", + "Consider replacing the len comparison with '{}_.is_empty()'", empty)) } } } -fn has_is_empty(cx: &Context, ty: &::rustc::middle::ty::Ty) -> bool { - fn check_item(cx: &Context, id: &ImplOrTraitItemId) -> bool { - if let &MethodTraitItemId(ref def_id) = id { - if let ty::MethodTraitItem(ref method) = ty::impl_or_trait_item( - cx.tcx, *def_id) { +/// check if this type has an is_empty method +fn has_is_empty(cx: &Context, expr: &Expr) -> bool { + /// get a ImplOrTraitItem and return true if it matches is_empty(self) + fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool { + if let &MethodTraitItemId(def_id) = id { + if let ty::MethodTraitItem(ref method) = + ty::impl_or_trait_item(cx.tcx, def_id) { method.name.as_str() == "is_empty" + && method.fty.sig.skip_binder().inputs.len() == 1 } else { false } } else { false } } - ::rustc::middle::ty::ty_to_def_id(ty).map_or(true, |id| { - cx.tcx.impl_items.borrow().get(&id).map_or(false, |item_ids| { - item_ids.iter().any(|i| check_item(cx, i)) - }) || cx.tcx.trait_item_def_ids.borrow().get(&id).map_or(false, - |item_ids| { item_ids.iter().any(|i| check_item(cx, i)) }) - }) + /// check the inherent impl's items for an is_empty(self) method + fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool { + let impl_items = cx.tcx.impl_items.borrow(); + cx.tcx.inherent_impls.borrow().get(id).map_or(false, + |ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false, + |iids| iids.iter().any(|i| is_is_empty(cx, i))))) + } + + let ty = &walk_ty(&expr_ty(cx.tcx, expr)); + match ty.sty { + ty::ty_trait(_) => cx.tcx.trait_item_def_ids.borrow().get( + &ty::ty_to_def_id(ty).expect("trait impl not found")).map_or(false, + |ids| ids.iter().any(|i| is_is_empty(cx, i))), + ty::ty_projection(_) => ty::ty_to_def_id(ty).map_or(false, + |id| has_is_empty_impl(cx, &id)), + ty::ty_enum(ref id, _) | ty::ty_struct(ref id, _) => + has_is_empty_impl(cx, id), + ty::ty_vec(..) => true, + _ => false, + } } diff --git a/src/misc.rs b/src/misc.rs index b8ce6d725f4..5d0d79544e9 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -10,7 +10,7 @@ use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; -fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { +pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { match ty.sty { ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty), _ => ty diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 39fcb3c1804..e64010d334d 100644 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -5,14 +5,14 @@ struct One; #[deny(len_without_is_empty)] impl One { - fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len()' method + fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)' 1 } } #[deny(len_without_is_empty)] trait TraitsToo { - fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len()' method, + fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_: } impl TraitsToo for One { @@ -21,17 +21,47 @@ impl TraitsToo for One { } } -#[allow(dead_code)] struct HasIsEmpty; #[deny(len_without_is_empty)] -#[allow(dead_code)] impl HasIsEmpty { fn len(self: &Self) -> isize { 1 } + + fn is_empty(self: &Self) -> bool { + false + } +} + +struct Wither; + +#[deny(len_without_is_empty)] +trait WithIsEmpty { + fn len(self: &Self) -> isize; + fn is_empty(self: &Self) -> bool; +} + +impl WithIsEmpty for Wither { + fn len(self: &Self) -> isize { + 1 + } + + fn is_empty(self: &Self) -> bool { + false + } +} + +struct HasWrongIsEmpty; + +#[deny(len_without_is_empty)] +impl HasWrongIsEmpty { + fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)' + 1 + } - fn is_empty() -> bool { + #[allow(dead_code, unused)] + fn is_empty(self: &Self, x : u32) -> bool { false } } @@ -49,7 +79,24 @@ fn main() { } let z : &TraitsToo = &y; - if z.len() > 0 { //~ERROR Consider replacing the len comparison + if z.len() > 0 { //no error, because TraitsToo has no .is_empty() method println!("Nor should this!"); } + + let hie = HasIsEmpty; + if hie.len() == 0 { //~ERROR Consider replacing the len comparison + println!("Or this!"); + } + assert!(!hie.is_empty()); + + let wie : &WithIsEmpty = &Wither; + if wie.len() == 0 { //~ERROR Consider replacing the len comparison + println!("Or this!"); + } + assert!(!wie.is_empty()); + + let hwie = HasWrongIsEmpty; + if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty() + println!("Or this!"); + } } diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs new file mode 100644 index 00000000000..bc39278606c --- /dev/null +++ b/tests/mut_mut_macro.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy, regex_macros)] + +extern crate regex; + +#[test] +#[deny(mut_mut)] +fn test_regex() { + let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); + assert!(pattern.is_match("# headline")); +} diff --git a/tests/run-pass.rs b/tests/run-pass.rs deleted file mode 100644 index bc39278606c..00000000000 --- a/tests/run-pass.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy, regex_macros)] - -extern crate regex; - -#[test] -#[deny(mut_mut)] -fn test_regex() { - let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); - assert!(pattern.is_match("# headline")); -} -- cgit 1.4.1-3-g733a5 From 1ee2e4ffe8a4ca40676fe6b372570d4e51c2f375 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Jun 2015 15:09:17 +0200 Subject: Fixed block check, also added macro test to collapsible_if and inline_always --- src/attrs.rs | 17 +++++++--- src/collapsible_if.rs | 60 ++++++++++++++++++++---------------- src/mut_mut.rs | 2 +- tests/compile-fail/collapsible_if.rs | 6 ++++ tests/compile-test.rs | 2 +- 5 files changed, 54 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 3ad3889f9db..f056ac6ee8c 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -4,8 +4,9 @@ use rustc::plugin::Registry; use rustc::lint::*; use syntax::ast::*; use syntax::ptr::P; -use syntax::codemap::Span; +use syntax::codemap::{Span, ExpnInfo}; use syntax::parse::token::InternedString; +use mut_mut::in_macro; declare_lint! { pub INLINE_ALWAYS, Warn, "#[inline(always)] is usually a bad idea."} @@ -20,19 +21,25 @@ impl LintPass for AttrPass { } fn check_item(&mut self, cx: &Context, item: &Item) { - check_attrs(cx, &item.ident, &item.attrs) + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) } fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { - check_attrs(cx, &item.ident, &item.attrs) + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { - check_attrs(cx, &item.ident, &item.attrs) + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) } } -fn check_attrs(cx: &Context, ident: &Ident, attrs: &[Attribute]) { +fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, + attrs: &[Attribute]) { + if in_macro(cx, info) { return; } + for attr in attrs { if let MetaList(ref inline, ref values) = attr.node.value.node { if values.len() != 1 || inline != &"inline" { continue; } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 31ac1e62be6..b9ebeed01de 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -17,8 +17,9 @@ use rustc::lint::*; use rustc::middle::def::*; use syntax::ast::*; use syntax::ptr::P; -use syntax::codemap::{Span, Spanned}; +use syntax::codemap::{Span, Spanned, ExpnInfo}; use syntax::print::pprust::expr_to_string; +use mut_mut::in_macro; declare_lint! { pub COLLAPSIBLE_IF, @@ -34,20 +35,23 @@ impl LintPass for CollapsibleIf { lint_array!(COLLAPSIBLE_IF) } - fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let ExprIf(ref check, ref then_block, None) = e.node { - let expr = check_block(then_block); - let expr = match expr { - Some(e) => e, - None => return - }; - if let ExprIf(ref check_inner, _, None) = expr.node { - let (check, check_inner) = (check_to_string(check), check_to_string(check_inner)); - cx.span_lint(COLLAPSIBLE_IF, e.span, - &format!("This if statement can be collapsed. Try: if {} && {}", check, check_inner)); - } - } - } + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + cx.sess().codemap().with_expn_info(expr.span.expn_id, + |info| check_expr_expd(cx, expr, info)) + } +} + +fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { + if in_macro(cx, info) { return; } + + if let ExprIf(ref check, ref then, None) = e.node { + if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = + single_stmt_of_block(then) { + cx.span_lint(COLLAPSIBLE_IF, e.span, &format!( + "This if statement can be collapsed. Try: if {} && {}\n{:?}", + check_to_string(check), check_to_string(check_inner), e)); + } + } } fn requires_brackets(e: &Expr) -> bool { @@ -65,16 +69,20 @@ fn check_to_string(e: &Expr) -> String { } } -fn check_block(b: &Block) -> Option<&P<Expr>> { - if b.stmts.len() == 1 && b.expr.is_none() { - let stmt = &b.stmts[0]; - return match stmt.node { - StmtExpr(ref e, _) => Some(e), - _ => None - }; - } - if let Some(ref e) = b.expr { - return Some(e); +fn single_stmt_of_block(block: &Block) -> Option<&Expr> { + if block.stmts.len() == 1 && block.expr.is_none() { + if let StmtExpr(ref expr, _) = block.stmts[0].node { + single_stmt_of_expr(expr) + } else { None } + } else { + if block.stmts.is_empty() { + if let Some(ref p) = block.expr { Some(&*p) } else { None } + } else { None } } - None +} + +fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> { + if let ExprBlock(ref block) = expr.node { + single_stmt_of_block(block) + } else { Some(expr) } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index a4c2d3932a3..3ba9c47e7fe 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -51,7 +51,7 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { }) } -fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { +pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { opt_info.map_or(false, |info| { info.callee.span.map_or(true, |span| { cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs index 3aa86c893c6..7b7ff13f24b 100644 --- a/tests/compile-fail/collapsible_if.rs +++ b/tests/compile-fail/collapsible_if.rs @@ -34,4 +34,10 @@ fn main() { } } + if x == "hello" { + print!("Hello "); + if y == "world" { + println!("world!") + } + } } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 6fcf71d38ad..04f3fc16b1b 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; fn run_mode(mode: &'static str) { let mut config = compiletest::default_config(); let cfg_mode = mode.parse().ok().expect("Invalid mode"); - config.target_rustcflags = Some("-l regex_macros -L target/debug/".to_string()); + config.target_rustcflags = Some("-L target/debug/".to_string()); config.mode = cfg_mode; config.src_base = PathBuf::from(format!("tests/{}", mode)); -- cgit 1.4.1-3-g733a5 From 30de91d3e9e724c8ebc5d3df342aa4e66a88dd47 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Jun 2015 22:30:34 +0200 Subject: moved in_macro to (new) utils.rs --- src/attrs.rs | 2 +- src/collapsible_if.rs | 2 +- src/mut_mut.rs | 11 +---------- src/utils.rs | 12 ++++++++++++ 4 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 src/utils.rs (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index f056ac6ee8c..5ee8745c33e 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, ExpnInfo}; use syntax::parse::token::InternedString; -use mut_mut::in_macro; +use utils::in_macro; declare_lint! { pub INLINE_ALWAYS, Warn, "#[inline(always)] is usually a bad idea."} diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index b9ebeed01de..85c1b25a673 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -19,7 +19,7 @@ use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned, ExpnInfo}; use syntax::print::pprust::expr_to_string; -use mut_mut::in_macro; +use utils::in_macro; declare_lint! { pub COLLAPSIBLE_IF, diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 3ba9c47e7fe..202b5600dbe 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -3,6 +3,7 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt}; use syntax::codemap::{BytePos, ExpnInfo, MacroFormat, Span}; +use utils::in_macro; declare_lint!(pub MUT_MUT, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -51,16 +52,6 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { }) } -pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { - opt_info.map_or(false, |info| { - info.callee.span.map_or(true, |span| { - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| - !code.starts_with("macro_rules") - ) - }) - }) -} - fn unwrap_mut(ty : &Ty) -> Option<&Ty> { match ty.node { TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 00000000000..e6e0c0e4868 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,12 @@ +use rustc::lint::Context; +use syntax::codemap::ExpnInfo; + +fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { + opt_info.map_or(false, |info| { + info.callee.span.map_or(true, |span| { + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + !code.starts_with("macro_rules") + ) + }) + }) +} -- cgit 1.4.1-3-g733a5 From e8ca19da244e2dce17c599fd35565f6e47ff19e9 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Jun 2015 22:36:56 +0200 Subject: fixed modules/visibility --- src/lib.rs | 1 + src/utils.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 37cdf6a9c58..06922ef5674 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ pub mod mut_mut; pub mod len_zero; pub mod attrs; pub mod collapsible_if; +pub mod utils; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { diff --git a/src/utils.rs b/src/utils.rs index e6e0c0e4868..c67ded3d93d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use rustc::lint::Context; use syntax::codemap::ExpnInfo; -fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { +pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { opt_info.map_or(false, |info| { info.callee.span.map_or(true, |span| { cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| -- cgit 1.4.1-3-g733a5 From 8563ee60ecf02be54c39dad0c063763c9dce4e91 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 6 Jun 2015 02:27:48 +0200 Subject: fixed issue #88 in bit_mask --- src/bit_mask.rs | 24 ++++++++++++++++-------- tests/compile-fail/bit_masks.rs | 1 + 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 352826dffae..f3f95f92d9a 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -89,20 +89,26 @@ fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, sp } } -fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { +fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, + mask_value: u64, cmp_value: u64, span: &Span) { match cmp_op { BiEq | BiNe => match bit_op { BiBitAnd => if mask_value & cmp_value != mask_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value, - cmp_value)); + if cmp_value != 0 { + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} can never be equal to {}", + mask_value, cmp_value)); + } } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + cx.span_lint(BAD_BIT_MASK, *span, + &format!("&-masking with zero")); } }, BiBitOr => if mask_value | cmp_value != cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value, - cmp_value)); + cx.span_lint(BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} can never be equal to {}", + mask_value, cmp_value)); }, _ => () }, @@ -113,7 +119,8 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, mask_value, cmp_value)); } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + cx.span_lint(BAD_BIT_MASK, *span, + &format!("&-masking with zero")); } }, BiBitOr => if mask_value >= cmp_value { @@ -136,7 +143,8 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, mask_value, cmp_value)); } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero")); + cx.span_lint(BAD_BIT_MASK, *span, + &format!("&-masking with zero")); } }, BiBitOr => if mask_value > cmp_value { diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index e45b789800e..e6b89b98564 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -11,6 +11,7 @@ fn main() { x & 0 == 0; //~ERROR &-masking with zero x & 1 == 1; //ok, distinguishes bit 0 + x & 1 == 0; //ok, compared with zero x & 2 == 1; //~ERROR x | 0 == 0; //ok, equals x == 0 (maybe warn?) x | 1 == 3; //ok, equals x == 2 || x == 3 -- cgit 1.4.1-3-g733a5 From 1f74c4b3597d9062f3e6d8f908758598b3f904db Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 7 Jun 2015 12:03:56 +0200 Subject: removed false positives from inline_always (issue #84) --- src/attrs.rs | 71 ++++++++++++++++++++++++++++++++++++++++----- tests/compile-fail/attrs.rs | 25 ++++++++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 5ee8745c33e..d5a56b1547f 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, ExpnInfo}; use syntax::parse::token::InternedString; -use utils::in_macro; +use utils::{in_macro, match_path}; declare_lint! { pub INLINE_ALWAYS, Warn, "#[inline(always)] is usually a bad idea."} @@ -21,18 +21,73 @@ impl LintPass for AttrPass { } fn check_item(&mut self, cx: &Context, item: &Item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + if is_relevant_item(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } } - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + if is_relevant_impl(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + if is_relevant_trait(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } + } +} + +fn is_relevant_item(item: &Item) -> bool { + if let &ItemFn(_, _, _, _, _, ref block) = &item.node { + is_relevant_block(block) + } else { false } +} + +fn is_relevant_impl(item: &ImplItem) -> bool { + match item.node { + MethodImplItem(_, ref block) => is_relevant_block(block), + _ => false + } +} + +fn is_relevant_trait(item: &TraitItem) -> bool { + match item.node { + MethodTraitItem(_, None) => true, + MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), + _ => false + } +} + +fn is_relevant_block(block: &Block) -> bool { + for stmt in block.stmts.iter() { + match stmt.node { + StmtDecl(_, _) => return true, + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { + return is_relevant_expr(expr); + } + _ => () + } + } + block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e)) +} + +fn is_relevant_expr(expr: &Expr) -> bool { + match expr.node { + ExprBlock(ref block) => is_relevant_block(block), + ExprRet(Some(ref e)) | ExprParen(ref e) => + is_relevant_expr(&*e), + ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, + ExprCall(ref path_expr, _) => { + if let ExprPath(_, ref path) = path_expr.node { + !match_path(path, &["std", "rt", "begin_unwind"]) + } else { true } + } + _ => true } } diff --git a/tests/compile-fail/attrs.rs b/tests/compile-fail/attrs.rs index 30ce191d3db..9b648a517e0 100644 --- a/tests/compile-fail/attrs.rs +++ b/tests/compile-fail/attrs.rs @@ -1,12 +1,33 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(inline_always)] +#![deny(inline_always)] + #[inline(always)] //~ERROR You have declared #[inline(always)] on test_attr_lint. fn test_attr_lint() { assert!(true) } +#[inline(always)] +fn false_positive_expr() { + unreachable!() +} + +#[inline(always)] +fn false_positive_stmt() { + unreachable!(); +} + +#[inline(always)] +fn empty_and_false_positive_stmt() { + ; + unreachable!(); +} + + fn main() { - test_attr_lint() + test_attr_lint(); + if false { false_positive_expr() } + if false { false_positive_stmt() } + if false { empty_and_false_positive_stmt() } } -- cgit 1.4.1-3-g733a5 From 19e718966d0d3660df374f60022f219f5bf48469 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 7 Jun 2015 12:05:14 +0200 Subject: forgot to update utils, there are a few new s --- src/utils.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index c67ded3d93d..b99ed45b3c3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,12 +1,42 @@ use rustc::lint::Context; -use syntax::codemap::ExpnInfo; +use syntax::ast::{DefId, Name, Path}; +use syntax::codemap::{ExpnInfo, Span}; +use rustc::middle::ty; +/// returns true if the macro that expanded the crate was outside of +/// the current crate or was a compiler plugin pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { + // no ExpnInfo = no macro opt_info.map_or(false, |info| { + // no span for the callee = external macro info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + // macro doesn't start with "macro_rules" + // = compiler plugin !code.starts_with("macro_rules") ) }) }) } + +/// invokes in_macro with the expansion info of the given span +pub fn in_external_macro(cx: &Context, span: Span) -> bool { + cx.sess().codemap().with_expn_info(span.expn_id, + |info| in_macro(cx, info)) +} + +/// check if a DefId's path matches the given absolute type path +/// usage e.g. with +/// `match_def_path(cx, id, &["core", "option", "Option"])` +pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { + ty::with_path(cx.tcx, def_id, |iter| iter.map(|elem| elem.name()) + .zip(path.iter()).all(|(nm, p)| &nm.as_str() == p)) +} + +/// match a Path against a slice of segment string literals, e.g. +/// `match_path(path, &["std", "rt", "begin_unwind"])` +pub fn match_path(path: &Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all( + |(a,b)| a.identifier.as_str() == *b) +} -- cgit 1.4.1-3-g733a5 From 23caf3cccc598dbe3228e407cc5864e9c5b6d5b8 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 11 Jun 2015 11:35:00 +0200 Subject: first unicode lint: zero_width_space --- README.md | 1 + src/lib.rs | 3 +++ src/unicode.rs | 45 +++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/unicode.rs | 25 ++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 src/unicode.rs create mode 100644 tests/compile-fail/unicode.rs (limited to 'src') diff --git a/README.md b/README.md index 3efeb748b9e..979fb47985a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Lints included in this crate: - `redundant_closure` warns on creating a closure where none is needed, e.g. `|x| foo(x)`, where `foo` can be used directly - `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` + - `zero_width_space`: Warns on encountering a unicode zero-width space To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index 06922ef5674..647128e0f0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ pub mod mut_mut; pub mod len_zero; pub mod attrs; pub mod collapsible_if; +pub mod unicode; pub mod utils; #[plugin_registrar] @@ -49,6 +50,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::CmpOwned as LintPassObject); reg.register_lint_pass(box attrs::AttrPass as LintPassObject); reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); + reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -67,5 +69,6 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, attrs::INLINE_ALWAYS, collapsible_if::COLLAPSIBLE_IF, + unicode::ZERO_WIDTH_SPACE, ]); } diff --git a/src/unicode.rs b/src/unicode.rs new file mode 100644 index 00000000000..3ffcf699c26 --- /dev/null +++ b/src/unicode.rs @@ -0,0 +1,45 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::codemap::{BytePos, Span}; + +declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" } + +#[derive(Copy, Clone)] +pub struct Unicode; + +impl LintPass for Unicode { + fn get_lints(&self) -> LintArray { + lint_array!(ZERO_WIDTH_SPACE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprLit(ref lit) = expr.node { + if let LitStr(ref string, _) = lit.node { + check_str(cx, string, lit.span) + } + } + } +} + +fn check_str(cx: &Context, string: &str, span: Span) { + let mut start: Option<usize> = None; + for (i, c) in string.char_indices() { + if c == '\u{200B}' { + if start.is_none() { start = Some(i); } + } else { + lint_zero_width(cx, span, start); + start = None; + } + } + lint_zero_width(cx, span, start); +} + +fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) { + start.map(|index| { + cx.span_lint(ZERO_WIDTH_SPACE, Span { + lo: span.lo + BytePos(index as u32), + hi: span.lo + BytePos(index as u32), + expn_id: span.expn_id, + }, "Zero-width space detected. Consider using \\u{200B}") + }); +} diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs new file mode 100644 index 00000000000..0385f45cc5e --- /dev/null +++ b/tests/compile-fail/unicode.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(zero_width_space)] +fn zero() { + print!("Here >​< is a ZWS, and ​another"); + //~^ ERROR Zero-width space detected. Consider using \u{200B} + //~^^ ERROR Zero-width space detected. Consider using \u{200B} +} + +//#[deny(unicode_canon)] +fn canon() { + print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à +} + +//#[deny(ascii_only)] +fn uni() { + println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC} +} + +fn main() { + zero(); + uni(); + canon(); +} -- cgit 1.4.1-3-g733a5 From 0e5b62c8d83046595f1be9231af3564644c4cfc1 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 11 Jun 2015 16:53:23 +0200 Subject: also included String::from in cmp_owned and fixed deprecation in test --- src/misc.rs | 6 +++--- tests/compile-fail/cmp_owned.rs | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 5d0d79544e9..ec609fd2618 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,8 +7,8 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; use syntax::codemap::{Span, Spanned}; - use types::span_note_and_lint; +use utils::match_path; pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { match ty.sty { @@ -248,8 +248,8 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { }, &ExprCall(ref path, _) => { if let &ExprPath(None, ref path) = &path.node { - if path.segments.iter().zip(["String", "from_str"].iter()).all( - |(seg, name)| &seg.identifier.as_str() == name) { + if match_path(path, &["String", "from_str"]) || + match_path(path, &["String", "from"]) { cx.span_lint(CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index a8b0cb32f6f..d7399e6d3aa 100644 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -13,5 +13,11 @@ fn main() { x != "foo".to_owned(); //~ERROR this creates an owned instance - x != String::from_str("foo"); //~ERROR this creates an owned instance + #[allow(deprecated)] // for from_str + fn old_timey(x : &str) { + x != String::from_str("foo"); //~ERROR this creates an owned instance + } + old_timey(x); + + x != String::from("foo"); //~ERROR this creates an owned instance } -- cgit 1.4.1-3-g733a5 From 9a3dcaabe8753ba7bdc687c4937d3ccb58d5d42f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 15 Jun 2015 13:27:24 +0200 Subject: fixed renaming of rustc::middle::ty enums --- src/len_zero.rs | 10 +++++----- src/misc.rs | 20 ++++++++++++-------- src/mut_mut.rs | 4 ++-- 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 5d97efdf02c..0974e8f21e2 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use syntax::ptr::P; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::util::nodemap::DefIdMap; -use rustc::middle::ty::{self, node_id_to_type, sty, ty_ptr, ty_rptr, expr_ty, +use rustc::middle::ty::{self, node_id_to_type, TypeVariants, expr_ty, mt, ty_to_def_id, impl_or_trait_item, MethodTraitItemId, ImplOrTraitItemId}; use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; @@ -138,14 +138,14 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { let ty = &walk_ty(&expr_ty(cx.tcx, expr)); match ty.sty { - ty::ty_trait(_) => cx.tcx.trait_item_def_ids.borrow().get( + ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( &ty::ty_to_def_id(ty).expect("trait impl not found")).map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))), - ty::ty_projection(_) => ty::ty_to_def_id(ty).map_or(false, + ty::TyProjection(_) => ty::ty_to_def_id(ty).map_or(false, |id| has_is_empty_impl(cx, &id)), - ty::ty_enum(ref id, _) | ty::ty_struct(ref id, _) => + ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, id), - ty::ty_vec(..) => true, + ty::TyArray(..) => true, _ => false, } } diff --git a/src/misc.rs b/src/misc.rs index ec609fd2618..f2492cf187d 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -4,7 +4,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float}; +use rustc::middle::ty::{self, expr_ty}; use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; @@ -12,7 +12,7 @@ use utils::match_path; pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { match ty.sty { - ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty), + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ty(tm.ty), _ => ty } } @@ -79,10 +79,10 @@ impl LintPass for StrToStringPass { } fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - match walk_ty(expr_ty(cx.tcx, expr)).sty { - ty_str => true, - _ => false - } + match walk_ty(expr_ty(cx.tcx, expr)).sty { + ty::TyStr => true, + _ => false + } } } } @@ -167,7 +167,11 @@ impl LintPass for FloatCmp { } fn is_float(cx: &Context, expr: &Expr) -> bool { - if let ty_float(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { true } else { false } + if let ty::TyFloat(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { + true + } else { + false + } } declare_lint!(pub PRECEDENCE, Warn, @@ -263,6 +267,6 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { } fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { - args.len() == 1 && if let ty_str = + args.len() == 1 && if let ty::TyStr = walk_ty(expr_ty(cx.tcx, &*args[0])).sty { true } else { false } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 202b5600dbe..fc5de44542f 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,7 +1,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt}; +use rustc::middle::ty::{expr_ty, TypeVariants, mt, TyRef}; use syntax::codemap::{BytePos, ExpnInfo, MacroFormat, Span}; use utils::in_macro; @@ -42,7 +42,7 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { cx.span_lint(MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") }).unwrap_or_else(|| { - if let ty_rptr(_, mt{ty: _, mutbl: MutMutable}) = + if let TyRef(_, mt{ty: _, mutbl: MutMutable}) = expr_ty(cx.tcx, e).sty { cx.span_lint(MUT_MUT, expr.span, "This expression mutably borrows a mutable reference. \ -- cgit 1.4.1-3-g733a5 From 0ffbdf2f8adc4d355dee96c4f2b462bc0e7ba255 Mon Sep 17 00:00:00 2001 From: Zachary Bush <zachary.bush@meraki.net> Date: Thu, 18 Jun 2015 15:29:13 -0700 Subject: Fix build with rustc 1.2.0-nightly (20d23d8e5 2015-06-18) In https://github.com/rust-lang/rust/pull/26347, MacroFormat was renamed to ExpnFormat. MacroFormat wasn't being used in src/mut_mut.rs, so I removed it. --- src/mut_mut.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index fc5de44542f..d2baded73ac 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -2,7 +2,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::middle::ty::{expr_ty, TypeVariants, mt, TyRef}; -use syntax::codemap::{BytePos, ExpnInfo, MacroFormat, Span}; +use syntax::codemap::{BytePos, ExpnInfo, Span}; use utils::in_macro; declare_lint!(pub MUT_MUT, Warn, -- cgit 1.4.1-3-g733a5 From 038d540ab1f7ae3ab4be0118bc4517d186f54ec6 Mon Sep 17 00:00:00 2001 From: Zachary Bush <zachary.bush@meraki.net> Date: Wed, 1 Jul 2015 09:21:46 -0700 Subject: Fix build for rustc 1.3.0-nightly (bf3c979ec 2015-06-30) --- src/len_zero.rs | 11 +++++------ src/misc.rs | 8 ++++---- src/mut_mut.rs | 4 ++-- src/utils.rs | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 0974e8f21e2..f2fe21f88ff 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,8 +5,7 @@ use std::cell::RefCell; use syntax::ptr::P; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::util::nodemap::DefIdMap; -use rustc::middle::ty::{self, node_id_to_type, TypeVariants, expr_ty, - mt, ty_to_def_id, impl_or_trait_item, MethodTraitItemId, ImplOrTraitItemId}; +use rustc::middle::ty::{self, TypeVariants, mt, MethodTraitItemId, ImplOrTraitItemId}; use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; @@ -121,7 +120,7 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool { if let &MethodTraitItemId(def_id) = id { if let ty::MethodTraitItem(ref method) = - ty::impl_or_trait_item(cx.tcx, def_id) { + cx.tcx.impl_or_trait_item(def_id) { method.name.as_str() == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 } else { false } @@ -136,12 +135,12 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { |iids| iids.iter().any(|i| is_is_empty(cx, i))))) } - let ty = &walk_ty(&expr_ty(cx.tcx, expr)); + let ty = &walk_ty(&cx.tcx.expr_ty(expr)); match ty.sty { ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( - &ty::ty_to_def_id(ty).expect("trait impl not found")).map_or(false, + &ty.ty_to_def_id().expect("trait impl not found")).map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))), - ty::TyProjection(_) => ty::ty_to_def_id(ty).map_or(false, + ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, id), diff --git a/src/misc.rs b/src/misc.rs index f2492cf187d..646b6308e4a 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -4,7 +4,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty::{self, expr_ty}; +use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; @@ -79,7 +79,7 @@ impl LintPass for StrToStringPass { } fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - match walk_ty(expr_ty(cx.tcx, expr)).sty { + match walk_ty(cx.tcx.expr_ty(expr)).sty { ty::TyStr => true, _ => false } @@ -167,7 +167,7 @@ impl LintPass for FloatCmp { } fn is_float(cx: &Context, expr: &Expr) -> bool { - if let ty::TyFloat(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { + if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { true } else { false @@ -268,5 +268,5 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = - walk_ty(expr_ty(cx.tcx, &*args[0])).sty { true } else { false } + walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index d2baded73ac..10888d99075 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,7 +1,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::middle::ty::{expr_ty, TypeVariants, mt, TyRef}; +use rustc::middle::ty::{TypeVariants, mt, TyRef}; use syntax::codemap::{BytePos, ExpnInfo, Span}; use utils::in_macro; @@ -43,7 +43,7 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { "Generally you want to avoid &mut &mut _ if possible.") }).unwrap_or_else(|| { if let TyRef(_, mt{ty: _, mutbl: MutMutable}) = - expr_ty(cx.tcx, e).sty { + cx.tcx.expr_ty(e).sty { cx.span_lint(MUT_MUT, expr.span, "This expression mutably borrows a mutable reference. \ Consider reborrowing") diff --git a/src/utils.rs b/src/utils.rs index b99ed45b3c3..d754c85f7b5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -30,7 +30,7 @@ pub fn in_external_macro(cx: &Context, span: Span) -> bool { /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { - ty::with_path(cx.tcx, def_id, |iter| iter.map(|elem| elem.name()) + cx.tcx.with_path(def_id, |iter| iter.map(|elem| elem.name()) .zip(path.iter()).all(|(nm, p)| &nm.as_str() == p)) } -- cgit 1.4.1-3-g733a5 From a24475093954141168d30ef510f20171db4843ac Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 9 Jul 2015 17:02:21 +0200 Subject: new 'snippet' utils method, used where applicable --- src/identity_op.rs | 5 +++-- src/misc.rs | 18 +++++++----------- src/utils.rs | 8 ++++++++ 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/identity_op.rs b/src/identity_op.rs index 25697199dc3..9511bcdee8d 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -7,6 +7,8 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; +use utils::snippet; + declare_lint! { pub IDENTITY_OP, Warn, "Warn on identity operations, e.g. '_ + 0'"} @@ -46,10 +48,9 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if have_lit(cx, e, m) { - let map = cx.sess().codemap(); cx.span_lint(IDENTITY_OP, span, &format!( "The operation is ineffective. Consider reducing it to '{}'", - &*map.span_to_snippet(arg).unwrap_or("..".to_string()))); + snippet(cx, arg, ".."))); } } diff --git a/src/misc.rs b/src/misc.rs index 646b6308e4a..ffa16543f25 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -8,7 +8,7 @@ use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; -use utils::match_path; +use utils::{match_path, snippet}; pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { match ty.sty { @@ -43,12 +43,11 @@ impl LintPass for MiscPass { // In some cases, an exhaustive match is preferred to catch situations when // an enum is extended. So we only consider cases where a `_` wildcard is used if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { - let map = cx.sess().codemap(); span_note_and_lint(cx, SINGLE_MATCH, expr.span, "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?", &*format!("Try if let {} = {} {{ ... }}", - &*map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), - &*map.span_to_snippet(ex.span).unwrap_or("..".to_string())) + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, "..")) ); } } @@ -156,11 +155,10 @@ impl LintPass for FloatCmp { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - let map = cx.sess().codemap(); cx.span_lint(FLOAT_CMP, expr.span, &format!( "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", - binop_to_string(op), &*map.span_to_snippet(left.span).unwrap_or("..".to_string()), - &*map.span_to_snippet(right.span).unwrap_or("..".to_string()))); + binop_to_string(op), snippet(cx, left.span, ".."), + snippet(cx, right.span, ".."))); } } } @@ -246,8 +244,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { cx.span_lint(CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", - cx.sess().codemap().span_to_snippet(other_span).unwrap_or( - "..".to_string()))) + snippet(cx, other_span, ".."))) } }, &ExprCall(ref path, _) => { @@ -257,8 +254,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { cx.span_lint(CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", - cx.sess().codemap().span_to_snippet(other_span).unwrap_or( - "..".to_string()))) + snippet(cx, other_span, ".."))) } } }, diff --git a/src/utils.rs b/src/utils.rs index d754c85f7b5..7d61316367b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,6 +2,8 @@ use rustc::lint::Context; use syntax::ast::{DefId, Name, Path}; use syntax::codemap::{ExpnInfo, Span}; use rustc::middle::ty; +use std::borrow::{Cow, IntoCow}; +use std::convert::From; /// returns true if the macro that expanded the crate was outside of /// the current crate or was a compiler plugin @@ -40,3 +42,9 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all( |(a,b)| a.identifier.as_str() == *b) } + +/// convert a span to a code snippet if available, otherwise use default, e.g. +/// `snippet(cx, expr.span, "..")` +pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { + cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) +} -- cgit 1.4.1-3-g733a5 From 251c5cfffdc04e91bb421334a2a8117db66027f6 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 16 Jul 2015 08:53:02 +0200 Subject: rustup, also first time clippy was used on itself, which led to a small refactoring --- README.md | 7 +++++++ src/eta_reduction.rs | 2 +- src/len_zero.rs | 2 +- src/misc.rs | 4 ++-- src/mut_mut.rs | 4 ++-- src/needless_bool.rs | 21 ++++++++++++++++----- src/utils.rs | 4 ++++ 7 files changed, 33 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 271b19a18cf..87339f46464 100644 --- a/README.md +++ b/README.md @@ -86,5 +86,12 @@ You can add options to `allow`/`warn`/`deny`: *`deny` produces error instead of warnings* +To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` +in your code, you can use: + +``` +cargo rustc -- -L /path/to/clippy_so -Z extra-plugins=clippy +``` + ##License Licensed under [MPL](https://www.mozilla.org/MPL/2.0/). If you're having issues with the license, let me know and I'll try to change it to something more permissive. diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index b89eef8c8bb..17dac5930c4 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -18,7 +18,7 @@ impl LintPass for EtaPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprClosure(_, ref decl, ref blk) = expr.node { - if blk.stmts.len() != 0 { + if !blk.stmts.is_empty() { // || {foo(); bar()}; can't be reduced here return; } diff --git a/src/len_zero.rs b/src/len_zero.rs index f2fe21f88ff..35e11dfdcb9 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use syntax::ptr::P; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::util::nodemap::DefIdMap; -use rustc::middle::ty::{self, TypeVariants, mt, MethodTraitItemId, ImplOrTraitItemId}; +use rustc::middle::ty::{self, TypeVariants, TypeAndMut, MethodTraitItemId, ImplOrTraitItemId}; use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; diff --git a/src/misc.rs b/src/misc.rs index ffa16543f25..da2df2cc820 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -36,8 +36,8 @@ impl LintPass for MiscPass { if arms.len() == 2 { if arms[0].guard.is_none() && arms[1].pats.len() == 1 { match arms[1].body.node { - ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (), - ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (), + ExprTup(ref v) if v.is_empty() && arms[1].guard.is_none() => (), + ExprBlock(ref b) if b.stmts.is_empty() && arms[1].guard.is_none() => (), _ => return } // In some cases, an exhaustive match is preferred to catch situations when diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 10888d99075..cfa040ddb04 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,7 +1,7 @@ use syntax::ptr::P; use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::middle::ty::{TypeVariants, mt, TyRef}; +use rustc::middle::ty::{TypeVariants, TypeAndMut, TyRef}; use syntax::codemap::{BytePos, ExpnInfo, Span}; use utils::in_macro; @@ -42,7 +42,7 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { cx.span_lint(MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") }).unwrap_or_else(|| { - if let TyRef(_, mt{ty: _, mutbl: MutMutable}) = + if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = cx.tcx.expr_ty(e).sty { cx.span_lint(MUT_MUT, expr.span, "This expression mutably borrows a mutable reference. \ diff --git a/src/needless_bool.rs b/src/needless_bool.rs index fe35e6ee3bd..9b52771d8af 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -10,6 +10,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; +use utils::de_p; declare_lint! { pub NEEDLESS_BOOL, @@ -28,10 +29,18 @@ impl LintPass for NeedlessBool { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (Option::Some(true), Option::Some(true)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "your if-then-else expression will always return true"); }, - (Option::Some(true), Option::Some(false)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "you can reduce your if-statement to its predicate"); }, - (Option::Some(false), Option::Some(true)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "you can reduce your if-statement to '!' + your predicate"); }, - (Option::Some(false), Option::Some(false)) => { cx.span_lint(NEEDLESS_BOOL, e.span, "your if-then-else expression will always return false"); }, + (Option::Some(true), Option::Some(true)) => { + cx.span_lint(NEEDLESS_BOOL, e.span, + "your if-then-else expression will always return true"); }, + (Option::Some(true), Option::Some(false)) => { + cx.span_lint(NEEDLESS_BOOL, e.span, + "you can reduce your if-statement to its predicate"); }, + (Option::Some(false), Option::Some(true)) => { + cx.span_lint(NEEDLESS_BOOL, e.span, + "you can reduce your if-statement to '!' + your predicate"); }, + (Option::Some(false), Option::Some(false)) => { + cx.span_lint(NEEDLESS_BOOL, e.span, + "your if-then-else expression will always return false"); }, _ => () } } @@ -39,7 +48,9 @@ impl LintPass for NeedlessBool { } fn fetch_bool_block(block: &Block) -> Option<bool> { - if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) } else { Option::None } + if block.stmts.is_empty() { + block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) + } else { Option::None } } fn fetch_bool_expr(expr: &Expr) -> Option<bool> { diff --git a/src/utils.rs b/src/utils.rs index 7d61316367b..065c20717a1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,7 @@ use rustc::lint::Context; use syntax::ast::{DefId, Name, Path}; use syntax::codemap::{ExpnInfo, Span}; +use syntax::ptr::P; use rustc::middle::ty; use std::borrow::{Cow, IntoCow}; use std::convert::From; @@ -48,3 +49,6 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) } + +/// dereference a P<T> and return a ref on the result +pub fn de_p<T>(p: &P<T>) -> &T { &*p } -- cgit 1.4.1-3-g733a5 From 0e8e8cfc9be642311be9995934bb864560b8c553 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 26 Jul 2015 20:23:11 +0530 Subject: Basic framework for structured logging --- Cargo.toml | 4 ++++ src/approx_const.rs | 3 ++- src/attrs.rs | 4 ++-- src/bit_mask.rs | 23 ++++++++++++----------- src/collapsible_if.rs | 4 ++-- src/eq_op.rs | 3 ++- src/eta_reduction.rs | 4 +++- src/identity_op.rs | 4 ++-- src/len_zero.rs | 9 +++++---- src/misc.rs | 16 ++++++++-------- src/mut_mut.rs | 8 ++++---- src/needless_bool.rs | 10 +++++----- src/ptr_arg.rs | 5 +++-- src/types.rs | 4 +++- src/unicode.rs | 3 ++- src/utils.rs | 15 ++++++++++++++- 16 files changed, 73 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 2d00f863e29..bd4be213b91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,7 @@ compiletest_rs = "*" regex = "*" regex_macros = "*" lazy_static = "*" + +[features] + +structured_logging = [] \ No newline at end of file diff --git a/src/approx_const.rs b/src/approx_const.rs index 8a93bbfa933..03d4da1ab7f 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -7,6 +7,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; use std::f64::consts as f64; +use utils::span_lint; declare_lint! { pub APPROX_CONSTANT, @@ -51,7 +52,7 @@ fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { if let Ok(value) = str.parse::<f64>() { for &(constant, name) in KNOWN_CONSTS { if within_epsilon(constant, value) { - cx.span_lint(APPROX_CONSTANT, span, &format!( + span_lint(cx, APPROX_CONSTANT, span, &format!( "Approximate value of {}::{} found, consider using it directly.", module, &name)); } } diff --git a/src/attrs.rs b/src/attrs.rs index d5a56b1547f..647e471c45e 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, ExpnInfo}; use syntax::parse::token::InternedString; -use utils::{in_macro, match_path}; +use utils::{in_macro, match_path, span_lint}; declare_lint! { pub INLINE_ALWAYS, Warn, "#[inline(always)] is usually a bad idea."} @@ -100,7 +100,7 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, if values.len() != 1 || inline != &"inline" { continue; } if let MetaWord(ref always) = values[0].node { if always != &"always" { continue; } - cx.span_lint(INLINE_ALWAYS, attr.span, &format!( + span_lint(cx, INLINE_ALWAYS, attr.span, &format!( "You have declared #[inline(always)] on {}. This \ is usually a bad idea. Are you sure?", ident.as_str())); diff --git a/src/bit_mask.rs b/src/bit_mask.rs index f3f95f92d9a..5ce574007bc 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -6,6 +6,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; +use utils::span_lint; declare_lint! { pub BAD_BIT_MASK, @@ -95,18 +96,18 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, BiEq | BiNe => match bit_op { BiBitAnd => if mask_value & cmp_value != mask_value { if cmp_value != 0 { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ & {} can never be equal to {}", mask_value, cmp_value)); } } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, + span_lint(cx, BAD_BIT_MASK, *span, &format!("&-masking with zero")); } }, BiBitOr => if mask_value | cmp_value != cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ | {} can never be equal to {}", mask_value, cmp_value)); }, @@ -114,22 +115,22 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiLt | BiGe => match bit_op { BiBitAnd => if mask_value < cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ & {} will always be lower than {}", mask_value, cmp_value)); } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, + span_lint(cx, BAD_BIT_MASK, *span, &format!("&-masking with zero")); } }, BiBitOr => if mask_value >= cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ | {} will never be lower than {}", mask_value, cmp_value)); } else { if mask_value < cmp_value { - cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!( + span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( "ineffective bit mask: x | {} compared to {} is the same as x compared directly", mask_value, cmp_value)); } @@ -138,22 +139,22 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiLe | BiGt => match bit_op { BiBitAnd => if mask_value <= cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ & {} will never be higher than {}", mask_value, cmp_value)); } else { if mask_value == 0 { - cx.span_lint(BAD_BIT_MASK, *span, + span_lint(cx, BAD_BIT_MASK, *span, &format!("&-masking with zero")); } }, BiBitOr => if mask_value > cmp_value { - cx.span_lint(BAD_BIT_MASK, *span, &format!( + span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: _ | {} will always be higher than {}", mask_value, cmp_value)); } else { if mask_value < cmp_value { - cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!( + span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( "ineffective bit mask: x | {} compared to {} is the same as x compared directly", mask_value, cmp_value)); } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 85c1b25a673..dc2d3852237 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -19,7 +19,7 @@ use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned, ExpnInfo}; use syntax::print::pprust::expr_to_string; -use utils::in_macro; +use utils::{in_macro, span_lint}; declare_lint! { pub COLLAPSIBLE_IF, @@ -47,7 +47,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if let ExprIf(ref check, ref then, None) = e.node { if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = single_stmt_of_block(then) { - cx.span_lint(COLLAPSIBLE_IF, e.span, &format!( + span_lint(cx, COLLAPSIBLE_IF, e.span, &format!( "This if statement can be collapsed. Try: if {} && {}\n{:?}", check_to_string(check), check_to_string(check_inner), e)); } diff --git a/src/eq_op.rs b/src/eq_op.rs index 94a49e748e2..10dbca2cf3c 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -3,6 +3,7 @@ use syntax::ast::*; use syntax::ast_util as ast_util; use syntax::ptr::P; use syntax::codemap as code; +use utils::span_lint; declare_lint! { pub EQ_OP, @@ -21,7 +22,7 @@ impl LintPass for EqOp { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(left, right) { - cx.span_lint(EQ_OP, e.span, &format!( + span_lint(cx, EQ_OP, e.span, &format!( "equal expressions as operands to {}", ast_util::binop_to_string(op.node))); } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 17dac5930c4..18011c61831 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -3,6 +3,8 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use syntax::codemap::{Span, Spanned}; use syntax::print::pprust::expr_to_string; +use utils::span_lint; + #[allow(missing_copy_implementations)] pub struct EtaPass; @@ -48,7 +50,7 @@ impl LintPass for EtaPass { return } } - cx.span_lint(REDUNDANT_CLOSURE, expr.span, + span_lint(cx, REDUNDANT_CLOSURE, expr.span, &format!("Redundant closure found, consider using `{}` in its place", expr_to_string(caller))[..]) } diff --git a/src/identity_op.rs b/src/identity_op.rs index 9511bcdee8d..b3fb3e05447 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -7,7 +7,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; -use utils::snippet; +use utils::{span_lint, snippet}; declare_lint! { pub IDENTITY_OP, Warn, "Warn on identity operations, e.g. '_ + 0'"} @@ -48,7 +48,7 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if have_lit(cx, e, m) { - cx.span_lint(IDENTITY_OP, span, &format!( + span_lint(cx, IDENTITY_OP, span, &format!( "The operation is ineffective. Consider reducing it to '{}'", snippet(cx, arg, ".."))); } diff --git a/src/len_zero.rs b/src/len_zero.rs index 35e11dfdcb9..7e71df2dd79 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -10,6 +10,7 @@ use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; use misc::walk_ty; +use utils::span_lint; declare_lint!(pub LEN_ZERO, Warn, "Warn when .is_empty() could be used instead of checking .len()"); @@ -54,10 +55,10 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { } if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - //cx.span_lint(LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); + //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); for i in trait_items { if is_named_self(i, "len") { - cx.span_lint(LEN_WITHOUT_IS_EMPTY, i.span, + span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ '.is_empty(_: &Self)' method. Consider adding one.", item.ident.as_str())); @@ -76,7 +77,7 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { for i in impl_items { if is_named_self(i, "len") { let s = i.span; - cx.span_lint(LEN_WITHOUT_IS_EMPTY, + span_lint(cx, LEN_WITHOUT_IS_EMPTY, Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, &format!("Item '{}' has a '.len(_: &Self)' method, but no \ '.is_empty(_: &Self)' method. Consider adding one.", @@ -107,7 +108,7 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, if let &Spanned{node: LitInt(0, _), ..} = lit { if method.node.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &*args[0]) { - cx.span_lint(LEN_ZERO, span, &format!( + span_lint(cx, LEN_ZERO, span, &format!( "Consider replacing the len comparison with '{}_.is_empty()'", empty)) } diff --git a/src/misc.rs b/src/misc.rs index da2df2cc820..a140671b1bb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -8,7 +8,7 @@ use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; use types::span_note_and_lint; -use utils::{match_path, snippet}; +use utils::{match_path, snippet, span_lint}; pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { match ty.sty { @@ -72,7 +72,7 @@ impl LintPass for StrToStringPass { ast::ExprMethodCall(ref method, _, ref args) if method.node.as_str() == "to_string" && is_str(cx, &*args[0]) => { - cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster"); + span_lint(cx, STR_TO_STRING, expr.span, "str.to_owned() is faster"); }, _ => () } @@ -100,7 +100,7 @@ impl LintPass for TopLevelRefPass { fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { for ref arg in decl.inputs.iter() { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { - cx.span_lint( + span_lint(cx, TOPLEVEL_REF_ARG, arg.pat.span, "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" @@ -136,7 +136,7 @@ impl LintPass for CmpNan { fn check_nan(cx: &Context, path: &Path, span: Span) { path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" { - cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + span_lint(cx, CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); }); } @@ -155,7 +155,7 @@ impl LintPass for FloatCmp { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - cx.span_lint(FLOAT_CMP, expr.span, &format!( + span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", binop_to_string(op), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); @@ -186,7 +186,7 @@ impl LintPass for Precedence { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - cx.span_lint(PRECEDENCE, expr.span, + span_lint(cx, PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); } } @@ -241,7 +241,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { let name = ident.as_str(); if name == "to_string" || name == "to_owned" && is_str_arg(cx, args) { - cx.span_lint(CMP_OWNED, expr.span, &format!( + span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", snippet(cx, other_span, ".."))) @@ -251,7 +251,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { if let &ExprPath(None, ref path) = &path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { - cx.span_lint(CMP_OWNED, expr.span, &format!( + span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using {}.as_slice() to compare without allocation", snippet(cx, other_span, ".."))) diff --git a/src/mut_mut.rs b/src/mut_mut.rs index cfa040ddb04..73e97ae31f4 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -3,7 +3,7 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use rustc::middle::ty::{TypeVariants, TypeAndMut, TyRef}; use syntax::codemap::{BytePos, ExpnInfo, Span}; -use utils::in_macro; +use utils::{in_macro, span_lint}; declare_lint!(pub MUT_MUT, Warn, "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); @@ -22,7 +22,7 @@ impl LintPass for MutMut { } fn check_ty(&mut self, cx: &Context, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| cx.span_lint(MUT_MUT, + unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, ty.span, "Generally you want to avoid &mut &mut _ if possible.")) } } @@ -39,12 +39,12 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map(|_| { - cx.span_lint(MUT_MUT, expr.span, + span_lint(cx, MUT_MUT, expr.span, "Generally you want to avoid &mut &mut _ if possible.") }).unwrap_or_else(|| { if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = cx.tcx.expr_ty(e).sty { - cx.span_lint(MUT_MUT, expr.span, + span_lint(cx, MUT_MUT, expr.span, "This expression mutably borrows a mutable reference. \ Consider reborrowing") } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 9b52771d8af..35d921e8fa1 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -10,7 +10,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; -use utils::de_p; +use utils::{de_p, span_lint}; declare_lint! { pub NEEDLESS_BOOL, @@ -30,16 +30,16 @@ impl LintPass for NeedlessBool { if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (Option::Some(true), Option::Some(true)) => { - cx.span_lint(NEEDLESS_BOOL, e.span, + span_lint(cx, NEEDLESS_BOOL, e.span, "your if-then-else expression will always return true"); }, (Option::Some(true), Option::Some(false)) => { - cx.span_lint(NEEDLESS_BOOL, e.span, + span_lint(cx, NEEDLESS_BOOL, e.span, "you can reduce your if-statement to its predicate"); }, (Option::Some(false), Option::Some(true)) => { - cx.span_lint(NEEDLESS_BOOL, e.span, + span_lint(cx, NEEDLESS_BOOL, e.span, "you can reduce your if-statement to '!' + your predicate"); }, (Option::Some(false), Option::Some(false)) => { - cx.span_lint(NEEDLESS_BOOL, e.span, + span_lint(cx, NEEDLESS_BOOL, e.span, "your if-then-else expression will always return false"); }, _ => () } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 64c3c84c7b6..dad4e48c832 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -11,6 +11,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; use types::match_ty_unwrap; +use utils::span_lint; declare_lint! { pub PTR_ARG, @@ -58,10 +59,10 @@ fn check_fn(cx: &Context, decl: &FnDecl) { fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, &["String"]).map_or((), |_| { - cx.span_lint(PTR_ARG, span, + span_lint(cx, PTR_ARG, span, "Writing '&String' instead of '&str' involves a new Object \ where a slices will do. Consider changing the type to &str") - }), |_| cx.span_lint(PTR_ARG, span, "Writing '&Vec<_>' instead of \ + }), |_| span_lint(cx, PTR_ARG, span, "Writing '&Vec<_>' instead of \ '&[_]' involves one more reference and cannot be used with \ non-vec-based slices. Consider changing the type to &[...]") ) diff --git a/src/types.rs b/src/types.rs index f0c91dc18b5..8c46fed2c1f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,6 +6,8 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use syntax::codemap::Span; +use utils::span_lint; + /// Handles all the linting of funky types #[allow(missing_copy_implementations)] pub struct TypePass; @@ -40,7 +42,7 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> /// Lets me span a note only if the lint is shown pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) { - cx.span_lint(lint, span, msg); + span_lint(cx, lint, span, msg); if cx.current_level(lint) != Level::Allow { cx.sess().span_note(span, note); } diff --git a/src/unicode.rs b/src/unicode.rs index 3ffcf699c26..9b908c3f94f 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,6 +1,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{BytePos, Span}; +use utils::span_lint; declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" } @@ -36,7 +37,7 @@ fn check_str(cx: &Context, string: &str, span: Span) { fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) { start.map(|index| { - cx.span_lint(ZERO_WIDTH_SPACE, Span { + span_lint(cx, ZERO_WIDTH_SPACE, Span { lo: span.lo + BytePos(index as u32), hi: span.lo + BytePos(index as u32), expn_id: span.expn_id, diff --git a/src/utils.rs b/src/utils.rs index 065c20717a1..e3cafc700a5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -use rustc::lint::Context; +use rustc::lint::{Context, Lint}; use syntax::ast::{DefId, Name, Path}; use syntax::codemap::{ExpnInfo, Span}; use syntax::ptr::P; @@ -52,3 +52,16 @@ pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { /// dereference a P<T> and return a ref on the result pub fn de_p<T>(p: &P<T>) -> &T { &*p } + +#[cfg(not(feature="structured_logging"))] +pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { + cx.span_lint(lint, sp, msg); +} + +#[cfg(feature="structured_logging")] +pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { + // lint.name / lint.desc is can give details of the lint + // cx.sess().codemap() has all these nice functions for line/column/snippet details + // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string + cx.span_lint(lint, sp, msg); +} -- cgit 1.4.1-3-g733a5 From de5ccdfab68a5e37689f3c950ed1532ba9d652a0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 31 Jul 2015 12:00:06 +0530 Subject: Upgrade to rustc 1.3.0-nightly (4d52d7c85 2015-07-30) --- Cargo.toml | 4 ++-- src/attrs.rs | 2 +- src/len_zero.rs | 10 +++++----- src/misc.rs | 6 +++--- src/types.rs | 2 +- src/utils.rs | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index bd4be213b91..d0955c313e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.6" +version = "0.0.7" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>" @@ -23,4 +23,4 @@ lazy_static = "*" [features] -structured_logging = [] \ No newline at end of file +structured_logging = [] diff --git a/src/attrs.rs b/src/attrs.rs index 647e471c45e..8d9e289fada 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -103,7 +103,7 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, span_lint(cx, INLINE_ALWAYS, attr.span, &format!( "You have declared #[inline(always)] on {}. This \ is usually a bad idea. Are you sure?", - ident.as_str())); + ident.name.as_str())); } } } diff --git a/src/len_zero.rs b/src/len_zero.rs index 7e71df2dd79..0e139983bbf 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -50,7 +50,7 @@ impl LintPass for LenZero { fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.ident.as_str() == name && if let MethodTraitItem(ref sig, _) = + item.ident.name == name && if let MethodTraitItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -61,7 +61,7 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ '.is_empty(_: &Self)' method. Consider adding one.", - item.ident.as_str())); + item.ident.name)); } }; } @@ -69,7 +69,7 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.ident.as_str() == name && if let MethodImplItem(ref sig, _) = + item.ident.name == name && if let MethodImplItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -81,7 +81,7 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, &format!("Item '{}' has a '.len(_: &Self)' method, but no \ '.is_empty(_: &Self)' method. Consider adding one.", - item.ident.as_str())); + item.ident.name)); return; } } @@ -106,7 +106,7 @@ fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, empty: &str) { if let &Spanned{node: LitInt(0, _), ..} = lit { - if method.node.as_str() == "len" && args.len() == 1 && + if method.node.name == "len" && args.len() == 1 && has_is_empty(cx, &*args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "Consider replacing the len comparison with '{}_.is_empty()'", diff --git a/src/misc.rs b/src/misc.rs index a140671b1bb..73b94875b30 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -70,7 +70,7 @@ impl LintPass for StrToStringPass { fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) { match expr.node { ast::ExprMethodCall(ref method, _, ref args) - if method.node.as_str() == "to_string" + if method.node.name == "to_string" && is_str(cx, &*args[0]) => { span_lint(cx, STR_TO_STRING, expr.span, "str.to_owned() is faster"); }, @@ -135,7 +135,7 @@ impl LintPass for CmpNan { } fn check_nan(cx: &Context, path: &Path, span: Span) { - path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" { + path.segments.last().map(|seg| if seg.identifier.name == "NAN" { span_lint(cx, CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); }); } @@ -238,7 +238,7 @@ impl LintPass for CmpOwned { fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { match &expr.node { &ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { - let name = ident.as_str(); + let name = ident.name; if name == "to_string" || name == "to_owned" && is_str_arg(cx, args) { span_lint(cx, CMP_OWNED, expr.span, &format!( diff --git a/src/types.rs b/src/types.rs index 8c46fed2c1f..d138239b5a7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -25,7 +25,7 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> // I could muck around with the maps and find the full path // however the more efficient way is to simply reverse the iterators and zip them // which will compare them in reverse until one of them runs out of segments - if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.as_str() == *b) { + if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) { match seg[..].last() { Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => { Some(&a.types[..]) diff --git a/src/utils.rs b/src/utils.rs index e3cafc700a5..d62e082c1fc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -41,7 +41,7 @@ pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a,b)| a.identifier.as_str() == *b) + |(a,b)| a.identifier.name == b) } /// convert a span to a code snippet if available, otherwise use default, e.g. -- cgit 1.4.1-3-g733a5 From 6ebb9b1551de419369e0272623ca5763d54ccc81 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 2 Aug 2015 20:59:12 +0530 Subject: Fix crash with idents from different contexts --- Cargo.toml | 2 +- src/eq_op.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index d0955c313e9..c94e1b38526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.7" +version = "0.0.8" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>" diff --git a/src/eq_op.rs b/src/eq_op.rs index 10dbca2cf3c..bd9787bd51c 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -72,7 +72,13 @@ fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool { } fn is_path_equal(left : &Path, right : &Path) -> bool { - left.global == right.global && left.segments == right.segments + // The == of idents doesn't work with different contexts, + // we have to be explicit about hygeine + left.global == right.global + && left.segments.iter().zip(right.segments.iter()) + .all( |(l,r)| l.identifier.name == r.identifier.name + && l.identifier.ctxt == r.identifier.ctxt + && l.parameters == r.parameters) } fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { -- cgit 1.4.1-3-g733a5 From b393752814e55726932a281249e5380643685986 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 5 Aug 2015 15:10:45 +0200 Subject: New string_add_assign lint (first part of #121), also formatting & refactoring --- README.md | 1 + src/eq_op.rs | 277 +++++++++++++++++++++--------------------- src/lib.rs | 3 + src/strings.rs | 55 +++++++++ src/utils.rs | 2 +- tests/compile-fail/strings.rs | 12 ++ 6 files changed, 210 insertions(+), 140 deletions(-) create mode 100644 src/strings.rs create mode 100644 tests/compile-fail/strings.rs (limited to 'src') diff --git a/README.md b/README.md index 87339f46464..fcd8d38a3b3 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Lints included in this crate: - `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` - `zero_width_space`: Warns on encountering a unicode zero-width space + - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. To use, add the following lines to your Cargo.toml: diff --git a/src/eq_op.rs b/src/eq_op.rs index bd9787bd51c..1000d310e39 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -23,238 +23,237 @@ impl LintPass for EqOp { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(left, right) { span_lint(cx, EQ_OP, e.span, &format!( - "equal expressions as operands to {}", - ast_util::binop_to_string(op.node))); + "equal expressions as operands to {}", + ast_util::binop_to_string(op.node))); } } } } -fn is_exp_equal(left : &Expr, right : &Expr) -> bool { - match (&left.node, &right.node) { - (&ExprBinary(ref lop, ref ll, ref lr), - &ExprBinary(ref rop, ref rl, ref rr)) => - lop.node == rop.node && - is_exp_equal(ll, rl) && is_exp_equal(lr, rr), - (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => - both(lpl, rpl, |l, r| is_exp_equal(l, r)) && - is_exp_equal(lbox, rbox), - (&ExprCall(ref lcallee, ref largs), - &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, - rcallee) && is_exps_equal(largs, rargs), - (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => - is_ty_equal(lty, rty) && is_exp_equal(lc, rc), - (&ExprField(ref lfexp, ref lfident), - &ExprField(ref rfexp, ref rfident)) => - lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), - (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprMethodCall(ref lident, ref lcty, ref lmargs), - &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => - lident.node == rident.node && is_tys_equal(lcty, rcty) && - is_exps_equal(lmargs, rmargs), - (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), - (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), - (&ExprPath(ref lqself, ref lsubpath), - &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, |l, r| is_qself_equal(l, r)) && - is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => - is_exps_equal(ltup, rtup), - (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => - lunop == runop && is_exp_equal(l, r), - (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r), - _ => false - } +pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool { + match (&left.node, &right.node) { + (&ExprBinary(ref lop, ref ll, ref lr), + &ExprBinary(ref rop, ref rl, ref rr)) => + lop.node == rop.node && + is_exp_equal(ll, rl) && is_exp_equal(lr, rr), + (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => + both(lpl, rpl, |l, r| is_exp_equal(l, r)) && + is_exp_equal(lbox, rbox), + (&ExprCall(ref lcallee, ref largs), + &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, + rcallee) && is_exps_equal(largs, rargs), + (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => + is_ty_equal(lty, rty) && is_exp_equal(lc, rc), + (&ExprField(ref lfexp, ref lfident), + &ExprField(ref rfexp, ref rfident)) => + lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), + (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, + (&ExprMethodCall(ref lident, ref lcty, ref lmargs), + &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => + lident.node == rident.node && is_tys_equal(lcty, rcty) && + is_exps_equal(lmargs, rmargs), + (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), + (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), + (&ExprPath(ref lqself, ref lsubpath), + &ExprPath(ref rqself, ref rsubpath)) => + both(lqself, rqself, |l, r| is_qself_equal(l, r)) && + is_path_equal(lsubpath, rsubpath), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => + is_exps_equal(ltup, rtup), + (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => + lunop == runop && is_exp_equal(l, r), + (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r), + _ => false + } } fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool { - over(left, right, |l, r| is_exp_equal(l, r)) + over(left, right, |l, r| is_exp_equal(l, r)) } fn is_path_equal(left : &Path, right : &Path) -> bool { // The == of idents doesn't work with different contexts, - // we have to be explicit about hygeine - left.global == right.global - && left.segments.iter().zip(right.segments.iter()) - .all( |(l,r)| l.identifier.name == r.identifier.name - && l.identifier.ctxt == r.identifier.ctxt - && l.parameters == r.parameters) + // we have to be explicit about hygiene + left.global == right.global && over(&left.segments, &right.segments, + |l, r| l.identifier.name == r.identifier.name + && l.identifier.ctxt == r.identifier.ctxt + && l.parameters == r.parameters) } fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { - left.ty.node == right.ty.node && left.position == right.position + left.ty.node == right.ty.node && left.position == right.position } fn is_ty_equal(left : &Ty, right : &Ty) -> bool { - match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), - (&TyFixedLengthVec(ref lfvty, ref lfvexp), - &TyFixedLengthVec(ref rfvty, ref rfvexp)) => - is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), - (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => - both(ltime, rtime, is_lifetime_equal) && - is_mut_ty_equal(lrmut, rrmut), - (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => - is_bare_fn_ty_equal(lbare, rbare), + match (&left.node, &right.node) { + (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), + (&TyFixedLengthVec(ref lfvty, ref lfvexp), + &TyFixedLengthVec(ref rfvty, ref rfvexp)) => + is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), + (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => + both(ltime, rtime, is_lifetime_equal) && + is_mut_ty_equal(lrmut, rrmut), + (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => + is_bare_fn_ty_equal(lbare, rbare), (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup), - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => - both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => + both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), (&TyObjectSum(ref lsumty, ref lobounds), - &TyObjectSum(ref rsumty, ref robounds)) => - is_ty_equal(lsumty, rsumty) && - is_param_bounds_equal(lobounds, robounds), - (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => - is_param_bounds_equal(ltbounds, rtbounds), + &TyObjectSum(ref rsumty, ref robounds)) => + is_ty_equal(lsumty, rsumty) && + is_param_bounds_equal(lobounds, robounds), + (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => + is_param_bounds_equal(ltbounds, rtbounds), (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof), - (&TyInfer, &TyInfer) => true, - _ => false - } + (&TyInfer, &TyInfer) => true, + _ => false + } } fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) - -> bool { - match(left, right) { - (&TraitTyParamBound(ref lpoly, ref lmod), - &TraitTyParamBound(ref rpoly, ref rmod)) => - lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), + -> bool { + match(left, right) { + (&TraitTyParamBound(ref lpoly, ref lmod), + &TraitTyParamBound(ref rpoly, ref rmod)) => + lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => - is_lifetime_equal(ltime, rtime), + is_lifetime_equal(ltime, rtime), _ => false - } + } } fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) - -> bool { - is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) - && is_path_equal(&left.trait_ref.path, &right.trait_ref.path) + -> bool { + is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) + && is_path_equal(&left.trait_ref.path, &right.trait_ref.path) } fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) - -> bool { - over(left, right, is_param_bound_equal) + -> bool { + over(left, right, is_param_bound_equal) } fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool { - left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty) + left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty) } fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { - left.unsafety == right.unsafety && left.abi == right.abi && - is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && - is_fndecl_equal(&left.decl, &right.decl) + left.unsafety == right.unsafety && left.abi == right.abi && + is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && + is_fndecl_equal(&left.decl, &right.decl) } fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool { - left.variadic == right.variadic && - is_args_equal(&left.inputs, &right.inputs) && - is_fnret_ty_equal(&left.output, &right.output) + left.variadic == right.variadic && + is_args_equal(&left.inputs, &right.inputs) && + is_fnret_ty_equal(&left.output, &right.output) } fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) - -> bool { - match (left, right) { - (&NoReturn(_), &NoReturn(_)) | - (&DefaultReturn(_), &DefaultReturn(_)) => true, - (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), - _ => false - } + -> bool { + match (left, right) { + (&NoReturn(_), &NoReturn(_)) | + (&DefaultReturn(_), &DefaultReturn(_)) => true, + (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), + _ => false + } } fn is_arg_equal(l: &Arg, r : &Arg) -> bool { - is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat) + is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat) } fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool { - over(left, right, is_arg_equal) + over(left, right, is_arg_equal) } fn is_pat_equal(left : &Pat, right : &Pat) -> bool { - match(&left.node, &right.node) { - (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, - (&PatIdent(ref lmode, ref lident, Option::None), - &PatIdent(ref rmode, ref rident, Option::None)) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node), - (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), - &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node) && - is_pat_equal(lpat, rpat), + match(&left.node, &right.node) { + (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, + (&PatIdent(ref lmode, ref lident, Option::None), + &PatIdent(ref rmode, ref rident, Option::None)) => + lmode == rmode && is_ident_equal(&lident.node, &rident.node), + (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), + &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => + lmode == rmode && is_ident_equal(&lident.node, &rident.node) && + is_pat_equal(lpat, rpat), (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => - is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| - is_pats_equal(l, r)), + is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| + is_pats_equal(l, r)), (&PatStruct(ref lpath, ref lfieldpat, lbool), - &PatStruct(ref rpath, ref rfieldpat, rbool)) => - lbool == rbool && is_path_equal(lpath, rpath) && - is_spanned_fieldpats_equal(lfieldpat, rfieldpat), + &PatStruct(ref rpath, ref rfieldpat, rbool)) => + lbool == rbool && is_path_equal(lpath, rpath) && + is_spanned_fieldpats_equal(lfieldpat, rfieldpat), (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), (&PatBox(ref lboxed), &PatBox(ref rboxed)) => - is_pat_equal(lboxed, rboxed), + is_pat_equal(lboxed, rboxed), (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => - is_pat_equal(lpat, rpat) && lmut == rmut, - (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), + is_pat_equal(lpat, rpat) && lmut == rmut, + (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => - is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), + is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), (&PatVec(ref lfirst, Option::None, ref llast), - &PatVec(ref rfirst, Option::None, ref rlast)) => - is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast), + &PatVec(ref rfirst, Option::None, ref rlast)) => + is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast), (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), - &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => - is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && - is_pats_equal(llast, rlast), - // I don't match macros for now, the code is slow enough as is ;-) - _ => false - } + &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => + is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && + is_pats_equal(llast, rlast), + // I don't match macros for now, the code is slow enough as is ;-) + _ => false + } } fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>], - right : &[code::Spanned<FieldPat>]) -> bool { - over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) + right : &[code::Spanned<FieldPat>]) -> bool { + over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) } fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool { - left.is_shorthand == right.is_shorthand && - is_ident_equal(&left.ident, &right.ident) && - is_pat_equal(&left.pat, &right.pat) + left.is_shorthand == right.is_shorthand && + is_ident_equal(&left.ident, &right.ident) && + is_pat_equal(&left.pat, &right.pat) } fn is_ident_equal(left : &Ident, right : &Ident) -> bool { - &left.name == &right.name && left.ctxt == right.ctxt + &left.name == &right.name && left.ctxt == right.ctxt } fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool { - over(left, right, |l, r| is_pat_equal(l, r)) + over(left, right, |l, r| is_pat_equal(l, r)) } fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) - -> bool { - is_lifetime_equal(&left.lifetime, &right.lifetime) && - over(&left.bounds, &right.bounds, is_lifetime_equal) + -> bool { + is_lifetime_equal(&left.lifetime, &right.lifetime) && + over(&left.bounds, &right.bounds, is_lifetime_equal) } fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) - -> bool { - over(left, right, is_lifetimedef_equal) + -> bool { + over(left, right, is_lifetimedef_equal) } fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool { - left.name == right.name + left.name == right.name } fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool { - over(left, right, |l, r| is_ty_equal(l, r)) + over(left, right, |l, r| is_ty_equal(l, r)) } fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool { + where F: FnMut(&X, &X) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| - eq_fn(x, y)) + eq_fn(x, y)) } fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool - where F: FnMut(&X, &X) -> bool { - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, - |y| eq_fn(x, y))) + where F: FnMut(&X, &X) -> bool { + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, + |y| eq_fn(x, y))) } fn is_cmp_or_bit(op : &BinOp) -> bool { diff --git a/src/lib.rs b/src/lib.rs index 647128e0f0c..d0d0b637468 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub mod attrs; pub mod collapsible_if; pub mod unicode; pub mod utils; +pub mod strings; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -51,6 +52,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box attrs::AttrPass as LintPassObject); reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); + reg.register_lint_pass(box strings::StringAdd as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -70,5 +72,6 @@ pub fn plugin_registrar(reg: &mut Registry) { attrs::INLINE_ALWAYS, collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, + strings::STRING_ADD_ASSIGN, ]); } diff --git a/src/strings.rs b/src/strings.rs new file mode 100644 index 00000000000..8bd882cada2 --- /dev/null +++ b/src/strings.rs @@ -0,0 +1,55 @@ +//! This LintPass catches both string addition and string addition + assignment +//! +//! Note that since we have two lints where one subsumes the other, we try to +//! disable the subsumed lint unless it has a higher level + +use rustc::lint::*; +use rustc::middle::ty::TypeVariants::TyStruct; +use syntax::ast::*; +use syntax::codemap::{Span, Spanned}; +use eq_op::is_exp_equal; +use misc::walk_ty; +use types::match_ty_unwrap; +use utils::{match_def_path, span_lint}; + +declare_lint! { + pub STRING_ADD_ASSIGN, + Warn, + "Warn on `x = x + ..` where x is a `String`" +} + +#[derive(Copy,Clone)] +pub struct StringAdd; + +impl LintPass for StringAdd { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_ADD_ASSIGN) + } + + fn check_expr(&mut self, cx: &Context, e: &Expr) { + if let &ExprAssign(ref target, ref src) =&e.node { + if is_string(cx, target) && is_add(src, target) { + span_lint(cx, STRING_ADD_ASSIGN, e.span, + "You assign the result of adding something to this string. \ + Consider using `String::push_str(..) instead.") + } + } + } +} + +fn is_string(cx: &Context, e: &Expr) -> bool { + if let TyStruct(def_id, _) = walk_ty(cx.tcx.expr_ty(e)).sty { + match_def_path(cx, def_id, &["std", "string", "String"]) + } else { false } +} + +fn is_add(src: &Expr, target: &Expr) -> bool { + match &src.node { + &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => + is_exp_equal(target, left), + &ExprBlock(ref block) => block.stmts.is_empty() && + block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)), + &ExprParen(ref expr) => is_add(&*expr, target), + _ => false + } +} diff --git a/src/utils.rs b/src/utils.rs index d62e082c1fc..4a87f4b3a2e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -41,7 +41,7 @@ pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a,b)| a.identifier.name == b) + |(a,b)| &a.identifier.name.as_str() == b) } /// convert a span to a code snippet if available, otherwise use default, e.g. diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs new file mode 100644 index 00000000000..2b200f1d07e --- /dev/null +++ b/tests/compile-fail/strings.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(string_add_assign)] + +fn main() { + let x = "".to_owned(); + + for i in (1..3) { + x = x + "."; //~ERROR + } +} -- cgit 1.4.1-3-g733a5 From 27f8fa75e19a5f821776aa06e40c03652ff28d86 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 7 Aug 2015 09:33:54 +0200 Subject: whitespace --- src/strings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index 8bd882cada2..75133ec1254 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -27,7 +27,7 @@ impl LintPass for StringAdd { } fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let &ExprAssign(ref target, ref src) =&e.node { + if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "You assign the result of adding something to this string. \ -- cgit 1.4.1-3-g733a5 From 228f06a960d761e62f55b432b910642d31e8e26a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 9 Aug 2015 22:13:56 +0530 Subject: Upgrade Rust to rustc 1.4.0-nightly (a5d33d891 2015-08-08) (fixes #123) --- Cargo.toml | 2 +- src/len_zero.rs | 2 +- src/strings.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index c94e1b38526..ce9ea2b3ed3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.8" +version = "0.0.9" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>" diff --git a/src/len_zero.rs b/src/len_zero.rs index 0e139983bbf..37683bbfa53 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -144,7 +144,7 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => - has_is_empty_impl(cx, id), + has_is_empty_impl(cx, &id.did), ty::TyArray(..) => true, _ => false, } diff --git a/src/strings.rs b/src/strings.rs index 75133ec1254..511d123b58d 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -38,8 +38,8 @@ impl LintPass for StringAdd { } fn is_string(cx: &Context, e: &Expr) -> bool { - if let TyStruct(def_id, _) = walk_ty(cx.tcx.expr_ty(e)).sty { - match_def_path(cx, def_id, &["std", "string", "String"]) + if let TyStruct(did, _) = walk_ty(cx.tcx.expr_ty(e)).sty { + match_def_path(cx, did.did, &["std", "string", "String"]) } else { false } } -- cgit 1.4.1-3-g733a5 From f0eb36c2af5cd6b92fafb7ed386f75618958f857 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 11 Aug 2015 15:07:21 +0200 Subject: added parent method, also changed match-if-let note to help --- src/misc.rs | 181 +++++++++++++++++++------------------ src/utils.rs | 71 +++++++++------ tests/compile-fail/match_if_let.rs | 4 +- 3 files changed, 139 insertions(+), 117 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 73b94875b30..0f0405a835a 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,14 +7,13 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; -use types::span_note_and_lint; -use utils::{match_path, snippet, span_lint}; +use utils::{match_path, snippet, span_lint, span_help_and_lint}; pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { - match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ty(tm.ty), - _ => ty - } + match ty.sty { + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ty(tm.ty), + _ => ty + } } /// Handles uncategorized lints @@ -42,9 +41,12 @@ impl LintPass for MiscPass { } // In some cases, an exhaustive match is preferred to catch situations when // an enum is extended. So we only consider cases where a `_` wildcard is used - if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { - span_note_and_lint(cx, SINGLE_MATCH, expr.span, - "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?", + if arms[1].pats[0].node == PatWild(PatWildSingle) && + arms[0].pats.len() == 1 { + span_help_and_lint(cx, SINGLE_MATCH, expr.span, + "You seem to be trying to use match for \ + destructuring a single type. Did you mean to \ + use `if let`?", &*format!("Try if let {} = {} {{ ... }}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, "..")) @@ -79,9 +81,9 @@ impl LintPass for StrToStringPass { fn is_str(cx: &Context, expr: &ast::Expr) -> bool { match walk_ty(cx.tcx.expr_ty(expr)).sty { - ty::TyStr => true, - _ => false - } + ty::TyStr => true, + _ => false + } } } } @@ -116,123 +118,124 @@ declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64: pub struct CmpNan; impl LintPass for CmpNan { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(CMP_NAN) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if is_comparison_binop(cmp.node) { - if let &ExprPath(_, ref path) = &left.node { - check_nan(cx, path, expr.span); - } - if let &ExprPath(_, ref path) = &right.node { - check_nan(cx, path, expr.span); - } - } - } - } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if is_comparison_binop(cmp.node) { + if let &ExprPath(_, ref path) = &left.node { + check_nan(cx, path, expr.span); + } + if let &ExprPath(_, ref path) = &right.node { + check_nan(cx, path, expr.span); + } + } + } + } } fn check_nan(cx: &Context, path: &Path, span: Span) { path.segments.last().map(|seg| if seg.identifier.name == "NAN" { - span_lint(cx, CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + span_lint(cx, CMP_NAN, span, + "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); }); } declare_lint!(pub FLOAT_CMP, Warn, - "Warn on ==/!= comparison of floaty values"); - + "Warn on ==/!= comparison of floaty values"); + #[derive(Copy,Clone)] pub struct FloatCmp; impl LintPass for FloatCmp { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(FLOAT_CMP) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - let op = cmp.node; - if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - span_lint(cx, FLOAT_CMP, expr.span, &format!( - "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", - binop_to_string(op), snippet(cx, left.span, ".."), - snippet(cx, right.span, ".."))); - } - } - } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + let op = cmp.node; + if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { + span_lint(cx, FLOAT_CMP, expr.span, &format!( + "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", + binop_to_string(op), snippet(cx, left.span, ".."), + snippet(cx, right.span, ".."))); + } + } + } } fn is_float(cx: &Context, expr: &Expr) -> bool { - if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { - true - } else { - false - } + if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { + true + } else { + false + } } declare_lint!(pub PRECEDENCE, Warn, - "Warn on mixing bit ops with integer arithmetic without parenthesis"); - + "Warn on mixing bit ops with integer arithmetic without parenthesis"); + #[derive(Copy,Clone)] pub struct Precedence; impl LintPass for Precedence { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(PRECEDENCE) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { - if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - span_lint(cx, PRECEDENCE, expr.span, - "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); - } - } - } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { + if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { + span_lint(cx, PRECEDENCE, expr.span, + "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); + } + } + } } fn is_arith_expr(expr : &Expr) -> bool { - match expr.node { - ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), - _ => false - } + match expr.node { + ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), + _ => false + } } fn is_bit_op(op : BinOp_) -> bool { - match op { - BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, - _ => false - } + match op { + BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, + _ => false + } } fn is_arith_op(op : BinOp_) -> bool { - match op { - BiAdd | BiSub | BiMul | BiDiv | BiRem => true, - _ => false - } + match op { + BiAdd | BiSub | BiMul | BiDiv | BiRem => true, + _ => false + } } declare_lint!(pub CMP_OWNED, Warn, - "Warn on creating an owned string just for comparison"); - + "Warn on creating an owned string just for comparison"); + #[derive(Copy,Clone)] pub struct CmpOwned; impl LintPass for CmpOwned { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(CMP_OWNED) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if is_comparison_binop(cmp.node) { - check_to_owned(cx, left, right.span); - check_to_owned(cx, right, left.span) - } - } - } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if is_comparison_binop(cmp.node) { + check_to_owned(cx, left, right.span); + check_to_owned(cx, right, left.span) + } + } + } } fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { @@ -263,6 +266,6 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { } fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { - args.len() == 1 && if let ty::TyStr = - walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } + args.len() == 1 && if let ty::TyStr = + walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } diff --git a/src/utils.rs b/src/utils.rs index 4a87f4b3a2e..a231171aee5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,8 @@ -use rustc::lint::{Context, Lint}; -use syntax::ast::{DefId, Name, Path}; +use rustc::lint::{Context, Lint, Level}; +use syntax::ast::{DefId, Expr, Name, NodeId, Path}; use syntax::codemap::{ExpnInfo, Span}; use syntax::ptr::P; +use rustc::ast_map::Node::NodeExpr; use rustc::middle::ty; use std::borrow::{Cow, IntoCow}; use std::convert::From; @@ -9,45 +10,55 @@ use std::convert::From; /// returns true if the macro that expanded the crate was outside of /// the current crate or was a compiler plugin pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { - // no ExpnInfo = no macro - opt_info.map_or(false, |info| { - // no span for the callee = external macro - info.callee.span.map_or(true, |span| { - // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| - // macro doesn't start with "macro_rules" - // = compiler plugin - !code.starts_with("macro_rules") - ) - }) - }) + // no ExpnInfo = no macro + opt_info.map_or(false, |info| { + // no span for the callee = external macro + info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + // macro doesn't start with "macro_rules" + // = compiler plugin + !code.starts_with("macro_rules") + ) + }) + }) } /// invokes in_macro with the expansion info of the given span pub fn in_external_macro(cx: &Context, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, - |info| in_macro(cx, info)) + cx.sess().codemap().with_expn_info(span.expn_id, + |info| in_macro(cx, info)) } /// check if a DefId's path matches the given absolute type path /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| iter.map(|elem| elem.name()) - .zip(path.iter()).all(|(nm, p)| &nm.as_str() == p)) + cx.tcx.with_path(def_id, |iter| iter.map(|elem| elem.name()) + .zip(path.iter()).all(|(nm, p)| &nm.as_str() == p)) } /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a,b)| &a.identifier.name.as_str() == b) + path.segments.iter().rev().zip(segments.iter().rev()).all( + |(a,b)| &a.identifier.name.as_str() == b) } /// convert a span to a code snippet if available, otherwise use default, e.g. /// `snippet(cx, expr.span, "..")` pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { - cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) + cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) +} + +/// get a parent expr if any – this is useful to constrain a lint +pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { + let map = &cx.tcx.map; + let node_id : NodeId = e.id; + let parent_id : NodeId = map.get_parent_node(node_id); + if node_id == parent_id { return None; } + map.find(parent_id).and_then(|node| + if let NodeExpr(parent) = node { Some(parent) } else { None } ) } /// dereference a P<T> and return a ref on the result @@ -55,13 +66,21 @@ pub fn de_p<T>(p: &P<T>) -> &T { &*p } #[cfg(not(feature="structured_logging"))] pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { - cx.span_lint(lint, sp, msg); + cx.span_lint(lint, sp, msg); } #[cfg(feature="structured_logging")] pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { - // lint.name / lint.desc is can give details of the lint - // cx.sess().codemap() has all these nice functions for line/column/snippet details - // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string - cx.span_lint(lint, sp, msg); + // lint.name / lint.desc is can give details of the lint + // cx.sess().codemap() has all these nice functions for line/column/snippet details + // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string + cx.span_lint(lint, sp, msg); +} + +pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, + msg: &str, help: &str) { + span_lint(cx, lint, span, msg); + if cx.current_level(lint) != Level::Allow { + cx.sess().span_help(span, help); + } } diff --git a/tests/compile-fail/match_if_let.rs b/tests/compile-fail/match_if_let.rs index b03c6e1140a..f1864f9d7f7 100644 --- a/tests/compile-fail/match_if_let.rs +++ b/tests/compile-fail/match_if_let.rs @@ -6,7 +6,7 @@ fn main(){ let x = Some(1u8); match x { //~ ERROR You seem to be trying to use match - //~^ NOTE Try if let Some(y) = x { ... } + //~^ HELP Try if let Some(y) = x { ... } Some(y) => println!("{:?}", y), _ => () } @@ -17,7 +17,7 @@ fn main(){ } let z = (1u8,1u8); match z { //~ ERROR You seem to be trying to use match - //~^ NOTE Try if let (2...3, 7...9) = z { ... } + //~^ HELP Try if let (2...3, 7...9) = z { ... } (2...3, 7...9) => println!("{:?}", z), _ => {} } -- cgit 1.4.1-3-g733a5 From 7b074d3ac7118a3f30c1f8782f15bfb081fbcaba Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 17:02:04 +0200 Subject: Remove tabs and trailing whitespace from lib and misc. --- src/lib.rs | 4 +-- src/misc.rs | 88 ++++++++++++++++++++++++++++++------------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) mode change 100644 => 100755 src/lib.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs old mode 100644 new mode 100755 index d0d0b637468..54f3bb11d26 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,11 +53,11 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); - + reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, - bit_mask::BAD_BIT_MASK, + bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, diff --git a/src/misc.rs b/src/misc.rs index 0f0405a835a..ff0594b2b5a 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -41,7 +41,7 @@ impl LintPass for MiscPass { } // In some cases, an exhaustive match is preferred to catch situations when // an enum is extended. So we only consider cases where a `_` wildcard is used - if arms[1].pats[0].node == PatWild(PatWildSingle) && + if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { span_help_and_lint(cx, SINGLE_MATCH, expr.span, "You seem to be trying to use match for \ @@ -80,7 +80,7 @@ impl LintPass for StrToStringPass { } fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - match walk_ty(cx.tcx.expr_ty(expr)).sty { + match walk_ty(cx.tcx.expr_ty(expr)).sty { ty::TyStr => true, _ => false } @@ -102,7 +102,7 @@ impl LintPass for TopLevelRefPass { fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { for ref arg in decl.inputs.iter() { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { - span_lint(cx, + span_lint(cx, TOPLEVEL_REF_ARG, arg.pat.span, "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" @@ -121,7 +121,7 @@ impl LintPass for CmpNan { fn get_lints(&self) -> LintArray { lint_array!(CMP_NAN) } - + fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { @@ -137,15 +137,15 @@ impl LintPass for CmpNan { } fn check_nan(cx: &Context, path: &Path, span: Span) { - path.segments.last().map(|seg| if seg.identifier.name == "NAN" { - span_lint(cx, CMP_NAN, span, - "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); - }); + path.segments.last().map(|seg| if seg.identifier.name == "NAN" { + span_lint(cx, CMP_NAN, span, + "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + }); } declare_lint!(pub FLOAT_CMP, Warn, "Warn on ==/!= comparison of floaty values"); - + #[derive(Copy,Clone)] pub struct FloatCmp; @@ -153,14 +153,14 @@ impl LintPass for FloatCmp { fn get_lints(&self) -> LintArray { lint_array!(FLOAT_CMP) } - + fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", - binop_to_string(op), snippet(cx, left.span, ".."), + binop_to_string(op), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); } } @@ -168,16 +168,16 @@ impl LintPass for FloatCmp { } fn is_float(cx: &Context, expr: &Expr) -> bool { - if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { + if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { true - } else { - false + } else { + false } } declare_lint!(pub PRECEDENCE, Warn, "Warn on mixing bit ops with integer arithmetic without parenthesis"); - + #[derive(Copy,Clone)] pub struct Precedence; @@ -185,11 +185,11 @@ impl LintPass for Precedence { fn get_lints(&self) -> LintArray { lint_array!(PRECEDENCE) } - + fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - span_lint(cx, PRECEDENCE, expr.span, + span_lint(cx, PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); } } @@ -219,7 +219,7 @@ fn is_arith_op(op : BinOp_) -> bool { declare_lint!(pub CMP_OWNED, Warn, "Warn on creating an owned string just for comparison"); - + #[derive(Copy,Clone)] pub struct CmpOwned; @@ -227,7 +227,7 @@ impl LintPass for CmpOwned { fn get_lints(&self) -> LintArray { lint_array!(CMP_OWNED) } - + fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { @@ -239,33 +239,33 @@ impl LintPass for CmpOwned { } fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { - match &expr.node { - &ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { - let name = ident.name; - if name == "to_string" || - name == "to_owned" && is_str_arg(cx, args) { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. \ - Consider using {}.as_slice() to compare without allocation", - snippet(cx, other_span, ".."))) - } - }, - &ExprCall(ref path, _) => { - if let &ExprPath(None, ref path) = &path.node { - if match_path(path, &["String", "from_str"]) || - match_path(path, &["String", "from"]) { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. \ - Consider using {}.as_slice() to compare without allocation", - snippet(cx, other_span, ".."))) - } - } - }, - _ => () - } + match &expr.node { + &ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { + let name = ident.name; + if name == "to_string" || + name == "to_owned" && is_str_arg(cx, args) { + span_lint(cx, CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. \ + Consider using {}.as_slice() to compare without allocation", + snippet(cx, other_span, ".."))) + } + }, + &ExprCall(ref path, _) => { + if let &ExprPath(None, ref path) = &path.node { + if match_path(path, &["String", "from_str"]) || + match_path(path, &["String", "from"]) { + span_lint(cx, CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. \ + Consider using {}.as_slice() to compare without allocation", + snippet(cx, other_span, ".."))) + } + } + }, + _ => () + } } fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { - args.len() == 1 && if let ty::TyStr = + args.len() == 1 && if let ty::TyStr = walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } -- cgit 1.4.1-3-g733a5 From 0ff476b529aa0ba11135aa2f3cf7c7779b5da2de Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 18:55:07 +0200 Subject: new lint for unneeded return stmts --- src/lib.rs | 2 ++ src/misc.rs | 68 +++++++++++++++++++++++++++++++++++ tests/compile-fail/needless_return.rs | 49 +++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100755 tests/compile-fail/needless_return.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 54f3bb11d26..7d29d96637d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); + reg.register_lint_pass(box misc::NeedlessReturn as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -73,5 +74,6 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, strings::STRING_ADD_ASSIGN, + misc::NEEDLESS_RETURN, ]); } diff --git a/src/misc.rs b/src/misc.rs index ff0594b2b5a..305a11abe23 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -269,3 +269,71 @@ fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } + +declare_lint!(pub NEEDLESS_RETURN, Warn, + "Warn on using a return statement where an expression would be enough"); + +#[derive(Copy,Clone)] +pub struct NeedlessReturn; + +impl NeedlessReturn { + // Check the final stmt or expr in a block for unnecessary return. + fn check_block_return(&mut self, cx: &Context, block: &Block) { + if let Some(ref expr) = block.expr { + self.check_final_expr(cx, expr); + } else if let Some(stmt) = block.stmts.last() { + if let StmtSemi(ref expr, _) = stmt.node { + if let ExprRet(Some(ref inner)) = expr.node { + self.emit_lint(cx, (expr.span, inner.span)); + } + } + } + } + + // Check a the final expression in a block if it's a return. + fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { + match expr.node { + // simple return is always "bad" + ExprRet(Some(ref inner)) => { + self.emit_lint(cx, (expr.span, inner.span)); + } + // a whole block? check it! + ExprBlock(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 + ExprIf(_, ref ifblock, Some(ref elsexpr)) | + ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { + self.check_block_return(cx, ifblock); + self.check_final_expr(cx, elsexpr); + } + // a match expr, check all arms + ExprMatch(_, ref arms, _) => { + for arm in arms { + self.check_final_expr(cx, &*arm.body); + } + } + _ => { } + } + } + + fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { + span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( + "unneeded return statement. Consider using {} \ + without trailing semicolon", + snippet(cx, spans.1, ".."))) + } +} + +impl LintPass for NeedlessReturn { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RETURN) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, + block: &Block, _: Span, _: ast::NodeId) { + self.check_block_return(cx, block); + } +} diff --git a/tests/compile-fail/needless_return.rs b/tests/compile-fail/needless_return.rs new file mode 100755 index 00000000000..34d57127996 --- /dev/null +++ b/tests/compile-fail/needless_return.rs @@ -0,0 +1,49 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(needless_return)] + +fn test_end_of_fn() -> bool { + if true { + // no error! + return true; + } + return true; //~ERROR +} + +fn test_no_semicolon() -> bool { + return true //~ERROR +} + +fn test_if_block() -> bool { + if true { + return true; //~ERROR + } else { + return false; //~ERROR + } +} + +fn test_match(x: bool) -> bool { + match x { + true => { + return false; //~ERROR + } + false => { + return true //~ERROR + } + } +} + +fn test_closure() { + let _ = || { + return true; //~ERROR + }; +} + +fn main() { + let _ = test_end_of_fn(); + let _ = test_no_semicolon(); + let _ = test_if_block(); + let _ = test_match(true); + test_closure(); +} -- cgit 1.4.1-3-g733a5 From cab9905705a56df245cce9e0f71ebeddf9daad89 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 19:26:33 +0200 Subject: better help text for "match -> if let" lint Implements the suggestion from #87. Changes span_help_and_lint(), which is only used for this lint, to use fileline_help() instead of span_help() to avoid printing the span twice. Also adds complete suggested new code. I had to distinguish between blocks, which need no additionals braces, and other exprs. --- src/misc.rs | 15 +++++++++++---- src/utils.rs | 4 ++-- tests/compile-fail/match_if_let.rs | 8 +++++--- 3 files changed, 18 insertions(+), 9 deletions(-) mode change 100644 => 100755 tests/compile-fail/match_if_let.rs (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 0f0405a835a..24f0d8afeb6 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -43,13 +43,20 @@ impl LintPass for MiscPass { // an enum is extended. So we only consider cases where a `_` wildcard is used if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { + let body_code = snippet(cx, arms[0].body.span, ".."); + let suggestion = if let ExprBlock(_) = arms[0].body.node { + body_code.into_owned() + } else { + format!("{{ {} }}", body_code) + }; span_help_and_lint(cx, SINGLE_MATCH, expr.span, "You seem to be trying to use match for \ - destructuring a single type. Did you mean to \ + destructuring a single pattern. Did you mean to \ use `if let`?", - &*format!("Try if let {} = {} {{ ... }}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, "..")) + &*format!("Try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + suggestion) ); } } diff --git a/src/utils.rs b/src/utils.rs index a231171aee5..5ec1033b8ea 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -77,10 +77,10 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); } -pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, +pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, help: &str) { span_lint(cx, lint, span, msg); if cx.current_level(lint) != Level::Allow { - cx.sess().span_help(span, help); + cx.sess().fileline_help(span, help); } } diff --git a/tests/compile-fail/match_if_let.rs b/tests/compile-fail/match_if_let.rs old mode 100644 new mode 100755 index f1864f9d7f7..47b8b18a5ec --- a/tests/compile-fail/match_if_let.rs +++ b/tests/compile-fail/match_if_let.rs @@ -6,8 +6,10 @@ fn main(){ let x = Some(1u8); match x { //~ ERROR You seem to be trying to use match - //~^ HELP Try if let Some(y) = x { ... } - Some(y) => println!("{:?}", y), + //~^ HELP Try + Some(y) => { + println!("{:?}", y); + } _ => () } // Not linted @@ -17,7 +19,7 @@ fn main(){ } let z = (1u8,1u8); match z { //~ ERROR You seem to be trying to use match - //~^ HELP Try if let (2...3, 7...9) = z { ... } + //~^ HELP Try (2...3, 7...9) => println!("{:?}", z), _ => {} } -- cgit 1.4.1-3-g733a5 From efdbfe0d3126b953eece0843e1177e086c594555 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 11 Aug 2015 23:11:20 +0530 Subject: nit --- src/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 305a11abe23..b3a74194552 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -322,7 +322,7 @@ impl NeedlessReturn { fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using {} \ - without trailing semicolon", + without the trailing semicolon", snippet(cx, spans.1, ".."))) } } -- cgit 1.4.1-3-g733a5 From e318328d63e122b5b3e516a0592367eaa2b6ea93 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 20:22:20 +0200 Subject: all: whitespace cleanup * 4-space indentation * no trailing whitespace * no tabs --- README.md | 2 +- src/approx_const.rs | 50 +++---- src/attrs.rs | 138 +++++++++---------- src/bit_mask.rs | 260 +++++++++++++++++------------------ src/collapsible_if.rs | 30 ++-- src/eq_op.rs | 136 +++++++++--------- src/eta_reduction.rs | 1 - src/identity_op.rs | 12 +- src/len_zero.rs | 214 ++++++++++++++-------------- src/mut_mut.rs | 78 +++++------ src/needless_bool.rs | 53 +++---- src/ptr_arg.rs | 66 ++++----- src/strings.rs | 10 +- src/unicode.rs | 50 +++---- src/utils.rs | 8 +- tests/compile-fail/approx_const.rs | 98 ++++++------- tests/compile-fail/attrs.rs | 18 +-- tests/compile-fail/bit_masks.rs | 76 +++++----- tests/compile-fail/box_vec.rs | 2 +- tests/compile-fail/cmp_nan.rs | 28 ++-- tests/compile-fail/cmp_owned.rs | 34 ++--- tests/compile-fail/collapsible_if.rs | 12 +- tests/compile-fail/eq_op.rs | 40 +++--- tests/compile-fail/float_cmp.rs | 40 +++--- tests/compile-fail/identity_op.rs | 28 ++-- tests/compile-fail/len_zero.rs | 120 ++++++++-------- tests/compile-fail/mut_mut.rs | 36 ++--- tests/compile-fail/needless_bool.rs | 12 +- tests/compile-fail/precedence.rs | 2 +- tests/compile-fail/ptr_arg.rs | 10 +- tests/compile-fail/strings.rs | 10 +- tests/compile-fail/unicode.rs | 16 +-- tests/compile-test.rs | 10 +- tests/mut_mut_macro.rs | 24 ++-- 34 files changed, 862 insertions(+), 862 deletions(-) mode change 100644 => 100755 tests/compile-fail/approx_const.rs mode change 100644 => 100755 tests/compile-fail/attrs.rs mode change 100644 => 100755 tests/compile-fail/bit_masks.rs mode change 100644 => 100755 tests/compile-fail/box_vec.rs mode change 100644 => 100755 tests/compile-fail/cmp_nan.rs mode change 100644 => 100755 tests/compile-fail/cmp_owned.rs mode change 100644 => 100755 tests/compile-fail/collapsible_if.rs mode change 100644 => 100755 tests/compile-fail/eq_op.rs mode change 100644 => 100755 tests/compile-fail/float_cmp.rs mode change 100644 => 100755 tests/compile-fail/identity_op.rs mode change 100644 => 100755 tests/compile-fail/len_zero.rs mode change 100644 => 100755 tests/compile-fail/mut_mut.rs mode change 100644 => 100755 tests/compile-fail/needless_bool.rs mode change 100644 => 100755 tests/compile-fail/precedence.rs mode change 100644 => 100755 tests/compile-fail/ptr_arg.rs mode change 100644 => 100755 tests/compile-fail/strings.rs mode change 100644 => 100755 tests/compile-fail/unicode.rs mode change 100644 => 100755 tests/mut_mut_macro.rs (limited to 'src') diff --git a/README.md b/README.md index fcd8d38a3b3..62367b8a26e 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ You can add options to `allow`/`warn`/`deny`: *`deny` produces error instead of warnings* -To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` +To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` in your code, you can use: ``` diff --git a/src/approx_const.rs b/src/approx_const.rs index 03d4da1ab7f..3ae579a74b9 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -15,12 +15,12 @@ declare_lint! { "Warn if a user writes an approximate known constant in their code" } -const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"), - (f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"), - (f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"), - (f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")]; +const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"), + (f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"), + (f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"), + (f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")]; const EPSILON_DIVISOR : f64 = 8192f64; //TODO: test to find a good value @@ -31,34 +31,34 @@ impl LintPass for ApproxConstant { fn get_lints(&self) -> LintArray { lint_array!(APPROX_CONSTANT) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let &ExprLit(ref lit) = &e.node { - check_lit(cx, lit, e.span); - } + if let &ExprLit(ref lit) = &e.node { + check_lit(cx, lit, e.span); + } } } fn check_lit(cx: &Context, lit: &Lit, span: Span) { - match &lit.node { - &LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), - &LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), - &LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), - _ => () - } + match &lit.node { + &LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), + &LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), + &LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), + _ => () + } } fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { - if let Ok(value) = str.parse::<f64>() { - for &(constant, name) in KNOWN_CONSTS { - if within_epsilon(constant, value) { - span_lint(cx, APPROX_CONSTANT, span, &format!( - "Approximate value of {}::{} found, consider using it directly.", module, &name)); - } - } - } + if let Ok(value) = str.parse::<f64>() { + for &(constant, name) in KNOWN_CONSTS { + if within_epsilon(constant, value) { + span_lint(cx, APPROX_CONSTANT, span, &format!( + "Approximate value of {}::{} found, consider using it directly.", module, &name)); + } + } + } } fn within_epsilon(target: f64, value: f64) -> bool { - f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR + f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR } diff --git a/src/attrs.rs b/src/attrs.rs index 8d9e289fada..6d73f1de964 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -19,92 +19,92 @@ impl LintPass for AttrPass { fn get_lints(&self) -> LintArray { lint_array!(INLINE_ALWAYS) } - + fn check_item(&mut self, cx: &Context, item: &Item) { - if is_relevant_item(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) - } - } - + if is_relevant_item(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } + } + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { - if is_relevant_impl(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) - } - } - - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { - if is_relevant_trait(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) - } - } + if is_relevant_impl(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + if is_relevant_trait(item) { + cx.sess().codemap().with_expn_info(item.span.expn_id, + |info| check_attrs(cx, info, &item.ident, &item.attrs)) + } + } } fn is_relevant_item(item: &Item) -> bool { - if let &ItemFn(_, _, _, _, _, ref block) = &item.node { - is_relevant_block(block) - } else { false } + if let &ItemFn(_, _, _, _, _, ref block) = &item.node { + is_relevant_block(block) + } else { false } } fn is_relevant_impl(item: &ImplItem) -> bool { - match item.node { - MethodImplItem(_, ref block) => is_relevant_block(block), - _ => false - } + match item.node { + MethodImplItem(_, ref block) => is_relevant_block(block), + _ => false + } } fn is_relevant_trait(item: &TraitItem) -> bool { - match item.node { - MethodTraitItem(_, None) => true, - MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), - _ => false - } + match item.node { + MethodTraitItem(_, None) => true, + MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), + _ => false + } } fn is_relevant_block(block: &Block) -> bool { - for stmt in block.stmts.iter() { - match stmt.node { - StmtDecl(_, _) => return true, - StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { - return is_relevant_expr(expr); - } - _ => () - } - } - block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e)) + for stmt in block.stmts.iter() { + match stmt.node { + StmtDecl(_, _) => return true, + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { + return is_relevant_expr(expr); + } + _ => () + } + } + block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e)) } fn is_relevant_expr(expr: &Expr) -> bool { - match expr.node { - ExprBlock(ref block) => is_relevant_block(block), - ExprRet(Some(ref e)) | ExprParen(ref e) => - is_relevant_expr(&*e), - ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, - ExprCall(ref path_expr, _) => { - if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &["std", "rt", "begin_unwind"]) - } else { true } - } - _ => true - } + match expr.node { + ExprBlock(ref block) => is_relevant_block(block), + ExprRet(Some(ref e)) | ExprParen(ref e) => + is_relevant_expr(&*e), + ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, + ExprCall(ref path_expr, _) => { + if let ExprPath(_, ref path) = path_expr.node { + !match_path(path, &["std", "rt", "begin_unwind"]) + } else { true } + } + _ => true + } } -fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, - attrs: &[Attribute]) { - if in_macro(cx, info) { return; } - - for attr in attrs { - if let MetaList(ref inline, ref values) = attr.node.value.node { - if values.len() != 1 || inline != &"inline" { continue; } - if let MetaWord(ref always) = values[0].node { - if always != &"always" { continue; } - span_lint(cx, INLINE_ALWAYS, attr.span, &format!( - "You have declared #[inline(always)] on {}. This \ - is usually a bad idea. Are you sure?", - ident.name.as_str())); - } - } - } +fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, + attrs: &[Attribute]) { + if in_macro(cx, info) { return; } + + for attr in attrs { + if let MetaList(ref inline, ref values) = attr.node.value.node { + if values.len() != 1 || inline != &"inline" { continue; } + if let MetaWord(ref always) = values[0].node { + if always != &"always" { continue; } + span_lint(cx, INLINE_ALWAYS, attr.span, &format!( + "You have declared #[inline(always)] on {}. This \ + is usually a bad idea. Are you sure?", + ident.name.as_str())); + } + } + } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 5ce574007bc..ad6facfb199 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -12,23 +12,23 @@ declare_lint! { pub BAD_BIT_MASK, Deny, "Deny the use of incompatible bit masks in comparisons, e.g. \ - '(a & 1) == 2'" + '(a & 1) == 2'" } declare_lint! { - pub INEFFECTIVE_BIT_MASK, - Warn, - "Warn on the use of an ineffective bit mask in comparisons, e.g. \ - '(a & 1) > 2'" + pub INEFFECTIVE_BIT_MASK, + Warn, + "Warn on the use of an ineffective bit mask in comparisons, e.g. \ + '(a & 1) > 2'" } -/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. +/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. /// This cannot work because the bit that makes up the value two was /// zeroed out by the bit-and with 1. So the formula for detecting if an -/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` -/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , +/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , /// `!=`, `>=`, `>`}) can be determined from the following table: -/// +/// /// |Comparison |Bit-Op|Example |is always|Formula | /// |------------|------|------------|---------|----------------------| /// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | @@ -37,7 +37,7 @@ declare_lint! { /// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | /// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | /// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | -/// +/// /// This lint is **deny** by default /// /// There is also a lint that warns on ineffective masks that is *warn* @@ -49,140 +49,140 @@ impl LintPass for BitMask { fn get_lints(&self) -> LintArray { lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { - if is_comparison_binop(cmp.node) { - fetch_int_literal(cx, right).map_or_else(|| - fetch_int_literal(cx, left).map_or((), |cmp_val| - check_compare(cx, right, invert_cmp(cmp.node), - cmp_val, &e.span)), - |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, - &e.span)) - } - } + if is_comparison_binop(cmp.node) { + fetch_int_literal(cx, right).map_or_else(|| + fetch_int_literal(cx, left).map_or((), |cmp_val| + check_compare(cx, right, invert_cmp(cmp.node), + cmp_val, &e.span)), + |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, + &e.span)) + } + } } } fn invert_cmp(cmp : BinOp_) -> BinOp_ { - match cmp { - BiEq => BiEq, - BiNe => BiNe, - BiLt => BiGt, - BiGt => BiLt, - BiLe => BiGe, - BiGe => BiLe, - _ => BiOr // Dummy - } + match cmp { + BiEq => BiEq, + BiNe => BiNe, + BiLt => BiGt, + BiGt => BiLt, + BiLe => BiGe, + BiGe => BiLe, + _ => BiOr // Dummy + } } fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { - match &bit_op.node { - &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), - &ExprBinary(ref op, ref left, ref right) => { - if op.node != BiBitAnd && op.node != BiBitOr { return; } - fetch_int_literal(cx, right).or_else(|| fetch_int_literal( - cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, - cmp_op, mask, cmp_value, span)) - }, - _ => () - } + match &bit_op.node { + &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), + &ExprBinary(ref op, ref left, ref right) => { + if op.node != BiBitAnd && op.node != BiBitOr { return; } + fetch_int_literal(cx, right).or_else(|| fetch_int_literal( + cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, + cmp_op, mask, cmp_value, span)) + }, + _ => () + } } -fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, - mask_value: u64, cmp_value: u64, span: &Span) { - match cmp_op { - BiEq | BiNe => match bit_op { - BiBitAnd => if mask_value & cmp_value != mask_value { - if cmp_value != 0 { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} can never be equal to {}", - mask_value, cmp_value)); - } - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); - } - }, - BiBitOr => if mask_value | cmp_value != cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} can never be equal to {}", - mask_value, cmp_value)); - }, - _ => () - }, - BiLt | BiGe => match bit_op { - BiBitAnd => if mask_value < cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} will always be lower than {}", - mask_value, cmp_value)); - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); - } - }, - BiBitOr => if mask_value >= cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} will never be lower than {}", - mask_value, cmp_value)); - } else { - if mask_value < cmp_value { - span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: x | {} compared to {} is the same as x compared directly", - mask_value, cmp_value)); - } - }, - _ => () - }, - BiLe | BiGt => match bit_op { - BiBitAnd => if mask_value <= cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} will never be higher than {}", - mask_value, cmp_value)); - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); - } - }, - BiBitOr => if mask_value > cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} will always be higher than {}", - mask_value, cmp_value)); - } else { - if mask_value < cmp_value { - span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: x | {} compared to {} is the same as x compared directly", - mask_value, cmp_value)); - } - }, - _ => () - }, - _ => () - } +fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, + mask_value: u64, cmp_value: u64, span: &Span) { + match cmp_op { + BiEq | BiNe => match bit_op { + BiBitAnd => if mask_value & cmp_value != mask_value { + if cmp_value != 0 { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} can never be equal to {}", + mask_value, cmp_value)); + } + } else { + if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, + &format!("&-masking with zero")); + } + }, + BiBitOr => if mask_value | cmp_value != cmp_value { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} can never be equal to {}", + mask_value, cmp_value)); + }, + _ => () + }, + BiLt | BiGe => match bit_op { + BiBitAnd => if mask_value < cmp_value { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} will always be lower than {}", + mask_value, cmp_value)); + } else { + if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, + &format!("&-masking with zero")); + } + }, + BiBitOr => if mask_value >= cmp_value { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} will never be lower than {}", + mask_value, cmp_value)); + } else { + if mask_value < cmp_value { + span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( + "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + mask_value, cmp_value)); + } + }, + _ => () + }, + BiLe | BiGt => match bit_op { + BiBitAnd => if mask_value <= cmp_value { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ & {} will never be higher than {}", + mask_value, cmp_value)); + } else { + if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, + &format!("&-masking with zero")); + } + }, + BiBitOr => if mask_value > cmp_value { + span_lint(cx, BAD_BIT_MASK, *span, &format!( + "incompatible bit mask: _ | {} will always be higher than {}", + mask_value, cmp_value)); + } else { + if mask_value < cmp_value { + span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( + "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + mask_value, cmp_value)); + } + }, + _ => () + }, + _ => () + } } fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> { - match &lit.node { - &ExprLit(ref lit_ptr) => { - if let &LitInt(value, _) = &lit_ptr.node { - Option::Some(value) //TODO: Handle sign - } else { Option::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: DefConst(def_id), ..}) => Some(def_id), - _ => None - } + match &lit.node { + &ExprLit(ref lit_ptr) => { + if let &LitInt(value, _) = &lit_ptr.node { + Option::Some(value) //TODO: Handle sign + } else { Option::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: DefConst(def_id), ..}) => Some(def_id), + _ => None } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None)) - .and_then(|l| fetch_int_literal(cx, l)), - _ => Option::None - } + } + .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None)) + .and_then(|l| fetch_int_literal(cx, l)), + _ => Option::None + } } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index dc2d3852237..eae3222945c 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -34,24 +34,24 @@ impl LintPass for CollapsibleIf { fn get_lints(&self) -> LintArray { lint_array!(COLLAPSIBLE_IF) } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - cx.sess().codemap().with_expn_info(expr.span.expn_id, - |info| check_expr_expd(cx, expr, info)) - } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + cx.sess().codemap().with_expn_info(expr.span.expn_id, + |info| check_expr_expd(cx, expr, info)) + } } fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { - if in_macro(cx, info) { return; } - - if let ExprIf(ref check, ref then, None) = e.node { - if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = - single_stmt_of_block(then) { - span_lint(cx, COLLAPSIBLE_IF, e.span, &format!( - "This if statement can be collapsed. Try: if {} && {}\n{:?}", - check_to_string(check), check_to_string(check_inner), e)); - } - } + if in_macro(cx, info) { return; } + + if let ExprIf(ref check, ref then, None) = e.node { + if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = + single_stmt_of_block(then) { + span_lint(cx, COLLAPSIBLE_IF, e.span, &format!( + "This if statement can be collapsed. Try: if {} && {}\n{:?}", + check_to_string(check), check_to_string(check_inner), e)); + } + } } fn requires_brackets(e: &Expr) -> bool { diff --git a/src/eq_op.rs b/src/eq_op.rs index 1000d310e39..6ad0e0658df 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -18,12 +18,12 @@ impl LintPass for EqOp { fn get_lints(&self) -> LintArray { lint_array!(EQ_OP) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(left, right) { span_lint(cx, EQ_OP, e.span, &format!( - "equal expressions as operands to {}", + "equal expressions as operands to {}", ast_util::binop_to_string(op.node))); } } @@ -32,36 +32,36 @@ impl LintPass for EqOp { pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool { match (&left.node, &right.node) { - (&ExprBinary(ref lop, ref ll, ref lr), - &ExprBinary(ref rop, ref rl, ref rr)) => - lop.node == rop.node && + (&ExprBinary(ref lop, ref ll, ref lr), + &ExprBinary(ref rop, ref rl, ref rr)) => + lop.node == rop.node && is_exp_equal(ll, rl) && is_exp_equal(lr, rr), - (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => - both(lpl, rpl, |l, r| is_exp_equal(l, r)) && + (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => + both(lpl, rpl, |l, r| is_exp_equal(l, r)) && is_exp_equal(lbox, rbox), - (&ExprCall(ref lcallee, ref largs), - &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, + (&ExprCall(ref lcallee, ref largs), + &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, rcallee) && is_exps_equal(largs, rargs), - (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => + (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => is_ty_equal(lty, rty) && is_exp_equal(lc, rc), - (&ExprField(ref lfexp, ref lfident), - &ExprField(ref rfexp, ref rfident)) => + (&ExprField(ref lfexp, ref lfident), + &ExprField(ref rfexp, ref rfident)) => lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprMethodCall(ref lident, ref lcty, ref lmargs), - &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => - lident.node == rident.node && is_tys_equal(lcty, rcty) && + (&ExprMethodCall(ref lident, ref lcty, ref lmargs), + &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => + lident.node == rident.node && is_tys_equal(lcty, rcty) && is_exps_equal(lmargs, rmargs), (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), - (&ExprPath(ref lqself, ref lsubpath), - &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, |l, r| is_qself_equal(l, r)) && - is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => + (&ExprPath(ref lqself, ref lsubpath), + &ExprPath(ref rqself, ref rsubpath)) => + both(lqself, rqself, |l, r| is_qself_equal(l, r)) && + is_path_equal(lsubpath, rsubpath), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(ltup, rtup), - (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => - lunop == runop && is_exp_equal(l, r), + (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => + lunop == runop && is_exp_equal(l, r), (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r), _ => false } @@ -74,7 +74,7 @@ fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool { fn is_path_equal(left : &Path, right : &Path) -> bool { // The == of idents doesn't work with different contexts, // we have to be explicit about hygiene - left.global == right.global && over(&left.segments, &right.segments, + left.global == right.global && over(&left.segments, &right.segments, |l, r| l.identifier.name == r.identifier.name && l.identifier.ctxt == r.identifier.ctxt && l.parameters == r.parameters) @@ -87,23 +87,23 @@ fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { fn is_ty_equal(left : &Ty, right : &Ty) -> bool { match (&left.node, &right.node) { (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), - (&TyFixedLengthVec(ref lfvty, ref lfvexp), - &TyFixedLengthVec(ref rfvty, ref rfvexp)) => + (&TyFixedLengthVec(ref lfvty, ref lfvexp), + &TyFixedLengthVec(ref rfvty, ref rfvexp)) => is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), - (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => - both(ltime, rtime, is_lifetime_equal) && + (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => + both(ltime, rtime, is_lifetime_equal) && is_mut_ty_equal(lrmut, rrmut), - (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => + (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => is_bare_fn_ty_equal(lbare, rbare), (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup), - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), - (&TyObjectSum(ref lsumty, ref lobounds), - &TyObjectSum(ref rsumty, ref robounds)) => - is_ty_equal(lsumty, rsumty) && + (&TyObjectSum(ref lsumty, ref lobounds), + &TyObjectSum(ref rsumty, ref robounds)) => + is_ty_equal(lsumty, rsumty) && is_param_bounds_equal(lobounds, robounds), - (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => + (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => is_param_bounds_equal(ltbounds, rtbounds), (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof), @@ -112,13 +112,13 @@ fn is_ty_equal(left : &Ty, right : &Ty) -> bool { } } -fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) +fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) -> bool { match(left, right) { - (&TraitTyParamBound(ref lpoly, ref lmod), - &TraitTyParamBound(ref rpoly, ref rmod)) => + (&TraitTyParamBound(ref lpoly, ref lmod), + &TraitTyParamBound(ref rpoly, ref rmod)) => lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), - (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => + (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => is_lifetime_equal(ltime, rtime), _ => false } @@ -140,24 +140,24 @@ fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool { } fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { - left.unsafety == right.unsafety && left.abi == right.abi && - is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && + left.unsafety == right.unsafety && left.abi == right.abi && + is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && is_fndecl_equal(&left.decl, &right.decl) -} +} fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool { - left.variadic == right.variadic && - is_args_equal(&left.inputs, &right.inputs) && + left.variadic == right.variadic && + is_args_equal(&left.inputs, &right.inputs) && is_fnret_ty_equal(&left.output, &right.output) } -fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) +fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) -> bool { match (left, right) { - (&NoReturn(_), &NoReturn(_)) | + (&NoReturn(_), &NoReturn(_)) | (&DefaultReturn(_), &DefaultReturn(_)) => true, (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), - _ => false + _ => false } } @@ -172,49 +172,49 @@ fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool { fn is_pat_equal(left : &Pat, right : &Pat) -> bool { match(&left.node, &right.node) { (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, - (&PatIdent(ref lmode, ref lident, Option::None), + (&PatIdent(ref lmode, ref lident, Option::None), &PatIdent(ref rmode, ref rident, Option::None)) => lmode == rmode && is_ident_equal(&lident.node, &rident.node), - (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), + (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node) && + lmode == rmode && is_ident_equal(&lident.node, &rident.node) && is_pat_equal(lpat, rpat), - (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => - is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| + (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => + is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| is_pats_equal(l, r)), - (&PatStruct(ref lpath, ref lfieldpat, lbool), + (&PatStruct(ref lpath, ref lfieldpat, lbool), &PatStruct(ref rpath, ref rfieldpat, rbool)) => - lbool == rbool && is_path_equal(lpath, rpath) && + lbool == rbool && is_path_equal(lpath, rpath) && is_spanned_fieldpats_equal(lfieldpat, rfieldpat), - (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), - (&PatBox(ref lboxed), &PatBox(ref rboxed)) => + (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), + (&PatBox(ref lboxed), &PatBox(ref rboxed)) => is_pat_equal(lboxed, rboxed), - (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => + (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => is_pat_equal(lpat, rpat) && lmut == rmut, (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), - (&PatVec(ref lfirst, Option::None, ref llast), + (&PatVec(ref lfirst, Option::None, ref llast), &PatVec(ref rfirst, Option::None, ref rlast)) => is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast), - (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), + (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => - is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && + is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && is_pats_equal(llast, rlast), // I don't match macros for now, the code is slow enough as is ;-) _ => false } } -fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>], +fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>], right : &[code::Spanned<FieldPat>]) -> bool { over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) } fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool { - left.is_shorthand == right.is_shorthand && - is_ident_equal(&left.ident, &right.ident) && - is_pat_equal(&left.pat, &right.pat) + left.is_shorthand == right.is_shorthand && + is_ident_equal(&left.ident, &right.ident) && + is_pat_equal(&left.pat, &right.pat) } fn is_ident_equal(left : &Ident, right : &Ident) -> bool { @@ -227,11 +227,11 @@ fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool { fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) -> bool { - is_lifetime_equal(&left.lifetime, &right.lifetime) && + is_lifetime_equal(&left.lifetime, &right.lifetime) && over(&left.bounds, &right.bounds, is_lifetime_equal) } -fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) +fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) -> bool { over(left, right, is_lifetimedef_equal) } @@ -244,13 +244,13 @@ fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool { over(left, right, |l, r| is_ty_equal(l, r)) } -fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool +fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool +fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool where F: FnMut(&X, &X) -> bool { l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) @@ -258,7 +258,7 @@ fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool fn is_cmp_or_bit(op : &BinOp) -> bool { match op.node { - BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | + BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true, _ => false } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 18011c61831..6948c1b22ab 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -58,4 +58,3 @@ impl LintPass for EtaPass { } } } - diff --git a/src/identity_op.rs b/src/identity_op.rs index b3fb3e05447..56d01c52b1d 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -11,7 +11,7 @@ use utils::{span_lint, snippet}; declare_lint! { pub IDENTITY_OP, Warn, "Warn on identity operations, e.g. '_ + 0'"} - + #[derive(Copy,Clone)] pub struct IdentityOp; @@ -27,7 +27,7 @@ impl LintPass for IdentityOp { check(cx, left, 0, e.span, right.span); check(cx, right, 0, e.span, left.span); }, - BiShl | BiShr | BiSub => + BiShl | BiShr | BiSub => check(cx, right, 0, e.span, left.span), BiMul => { check(cx, left, 1, e.span, right.span); @@ -49,14 +49,14 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if have_lit(cx, e, m) { span_lint(cx, IDENTITY_OP, span, &format!( - "The operation is ineffective. Consider reducing it to '{}'", + "The operation is ineffective. Consider reducing it to '{}'", snippet(cx, arg, ".."))); } } fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool { match &e.node { - &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), + &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), &ExprLit(ref lit) => { match (&lit.node, m) { (&LitInt(0, _), 0) => true, @@ -68,9 +68,9 @@ fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool { } }, &ExprParen(ref p) => have_lit(cx, p, m), - &ExprPath(_, _) => { + &ExprPath(_, _) => { match cx.tcx.def_map.borrow().get(&e.id) { - Some(&PathResolution { base_def: DefConst(id), ..}) => + Some(&PathResolution { base_def: DefConst(id), ..}) => lookup_const_by_id(cx.tcx, id, Option::None) .map_or(false, |l| have_lit(cx, l, m)), _ => false diff --git a/src/len_zero.rs b/src/len_zero.rs index 37683bbfa53..0877fa95238 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -22,130 +22,130 @@ declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, pub struct LenZero; impl LintPass for LenZero { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) - } - - fn check_item(&mut self, cx: &Context, item: &Item) { - match &item.node { - &ItemTrait(_, _, _, ref trait_items) => - check_trait_items(cx, item, trait_items), - &ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait - check_impl_items(cx, item, impl_items), - _ => () - } - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = - &expr.node { - match cmp { - BiEq => check_cmp(cx, expr.span, left, right, ""), - BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), - _ => () - } - } - } + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + match &item.node { + &ItemTrait(_, _, _, ref trait_items) => + check_trait_items(cx, item, trait_items), + &ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait + check_impl_items(cx, item, impl_items), + _ => () + } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = + &expr.node { + match cmp { + BiEq => check_cmp(cx, expr.span, left, right, ""), + BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), + _ => () + } + } + } } fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { - fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.ident.name == name && if let MethodTraitItem(ref sig, _) = - item.node { is_self_sig(sig) } else { false } - } - - if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); - for i in trait_items { - if is_named_self(i, "len") { - span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, - &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ - '.is_empty(_: &Self)' method. Consider adding one.", - item.ident.name)); - } - }; - } + fn is_named_self(item: &TraitItem, name: &str) -> bool { + item.ident.name == name && if let MethodTraitItem(ref sig, _) = + item.node { is_self_sig(sig) } else { false } + } + + if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { + //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); + for i in trait_items { + if is_named_self(i, "len") { + span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, + &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ + '.is_empty(_: &Self)' method. Consider adding one.", + item.ident.name)); + } + }; + } } fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { - fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.ident.name == name && if let MethodImplItem(ref sig, _) = - item.node { is_self_sig(sig) } else { false } - } - - if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { - for i in impl_items { - if is_named_self(i, "len") { - let s = i.span; - span_lint(cx, LEN_WITHOUT_IS_EMPTY, - Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, - &format!("Item '{}' has a '.len(_: &Self)' method, but no \ - '.is_empty(_: &Self)' method. Consider adding one.", - item.ident.name)); - return; - } - } - } + fn is_named_self(item: &ImplItem, name: &str) -> bool { + item.ident.name == name && if let MethodImplItem(ref sig, _) = + item.node { is_self_sig(sig) } else { false } + } + + if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { + for i in impl_items { + if is_named_self(i, "len") { + let s = i.span; + span_lint(cx, LEN_WITHOUT_IS_EMPTY, + Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, + &format!("Item '{}' has a '.len(_: &Self)' method, but no \ + '.is_empty(_: &Self)' method. Consider adding one.", + item.ident.name)); + return; + } + } + } } fn is_self_sig(sig: &MethodSig) -> bool { - if let SelfStatic = sig.explicit_self.node { - false } else { sig.decl.inputs.len() == 1 } + if let SelfStatic = sig.explicit_self.node { + false } else { sig.decl.inputs.len() == 1 } } fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { - match (&left.node, &right.node) { - (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => - check_len_zero(cx, span, method, args, lit, empty), - (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => - check_len_zero(cx, span, method, args, lit, empty), - _ => () - } + match (&left.node, &right.node) { + (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => + check_len_zero(cx, span, method, args, lit, empty), + (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => + check_len_zero(cx, span, method, args, lit, empty), + _ => () + } } -fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, - args: &[P<Expr>], lit: &Lit, empty: &str) { - if let &Spanned{node: LitInt(0, _), ..} = lit { - if method.node.name == "len" && args.len() == 1 && - has_is_empty(cx, &*args[0]) { - span_lint(cx, LEN_ZERO, span, &format!( - "Consider replacing the len comparison with '{}_.is_empty()'", - empty)) - } - } +fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, + args: &[P<Expr>], lit: &Lit, empty: &str) { + if let &Spanned{node: LitInt(0, _), ..} = lit { + if method.node.name == "len" && args.len() == 1 && + has_is_empty(cx, &*args[0]) { + span_lint(cx, LEN_ZERO, span, &format!( + "Consider replacing the len comparison with '{}_.is_empty()'", + empty)) + } + } } /// check if this type has an is_empty method fn has_is_empty(cx: &Context, expr: &Expr) -> bool { - /// get a ImplOrTraitItem and return true if it matches is_empty(self) - fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool { - if let &MethodTraitItemId(def_id) = id { - if let ty::MethodTraitItem(ref method) = - cx.tcx.impl_or_trait_item(def_id) { - method.name.as_str() == "is_empty" - && method.fty.sig.skip_binder().inputs.len() == 1 - } else { false } - } else { false } - } - - /// check the inherent impl's items for an is_empty(self) method - fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool { - let impl_items = cx.tcx.impl_items.borrow(); - cx.tcx.inherent_impls.borrow().get(id).map_or(false, - |ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false, - |iids| iids.iter().any(|i| is_is_empty(cx, i))))) - } - - let ty = &walk_ty(&cx.tcx.expr_ty(expr)); - match ty.sty { - ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( - &ty.ty_to_def_id().expect("trait impl not found")).map_or(false, - |ids| ids.iter().any(|i| is_is_empty(cx, i))), - ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, - |id| has_is_empty_impl(cx, &id)), - ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => - has_is_empty_impl(cx, &id.did), - ty::TyArray(..) => true, - _ => false, - } + /// get a ImplOrTraitItem and return true if it matches is_empty(self) + fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool { + if let &MethodTraitItemId(def_id) = id { + if let ty::MethodTraitItem(ref method) = + cx.tcx.impl_or_trait_item(def_id) { + method.name.as_str() == "is_empty" + && method.fty.sig.skip_binder().inputs.len() == 1 + } else { false } + } else { false } + } + + /// check the inherent impl's items for an is_empty(self) method + fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool { + let impl_items = cx.tcx.impl_items.borrow(); + cx.tcx.inherent_impls.borrow().get(id).map_or(false, + |ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false, + |iids| iids.iter().any(|i| is_is_empty(cx, i))))) + } + + let ty = &walk_ty(&cx.tcx.expr_ty(expr)); + match ty.sty { + ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( + &ty.ty_to_def_id().expect("trait impl not found")).map_or(false, + |ids| ids.iter().any(|i| is_is_empty(cx, i))), + ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, + |id| has_is_empty_impl(cx, &id)), + ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => + has_is_empty_impl(cx, &id.did), + ty::TyArray(..) => true, + _ => false, + } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 73e97ae31f4..16ea422f77f 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -12,50 +12,50 @@ declare_lint!(pub MUT_MUT, Warn, pub struct MutMut; impl LintPass for MutMut { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(MUT_MUT) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - cx.sess().codemap().with_expn_info(expr.span.expn_id, - |info| check_expr_expd(cx, expr, info)) - } - - fn check_ty(&mut self, cx: &Context, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, - ty.span, "Generally you want to avoid &mut &mut _ if possible.")) - } + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + cx.sess().codemap().with_expn_info(expr.span.expn_id, + |info| check_expr_expd(cx, expr, info)) + } + + fn check_ty(&mut self, cx: &Context, ty: &Ty) { + unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, + ty.span, "Generally you want to avoid &mut &mut _ if possible.")) + } } fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { - if in_macro(cx, info) { return; } - - fn unwrap_addr(expr : &Expr) -> Option<&Expr> { - match expr.node { - ExprAddrOf(MutMutable, ref e) => Option::Some(e), - _ => Option::None - } - } - - unwrap_addr(expr).map_or((), |e| { - unwrap_addr(e).map(|_| { - span_lint(cx, MUT_MUT, expr.span, - "Generally you want to avoid &mut &mut _ if possible.") - }).unwrap_or_else(|| { - if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = - cx.tcx.expr_ty(e).sty { - span_lint(cx, MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. \ - Consider reborrowing") - } - }) - }) + if in_macro(cx, info) { return; } + + fn unwrap_addr(expr : &Expr) -> Option<&Expr> { + match expr.node { + ExprAddrOf(MutMutable, ref e) => Option::Some(e), + _ => Option::None + } + } + + unwrap_addr(expr).map_or((), |e| { + unwrap_addr(e).map(|_| { + span_lint(cx, MUT_MUT, expr.span, + "Generally you want to avoid &mut &mut _ if possible.") + }).unwrap_or_else(|| { + if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = + cx.tcx.expr_ty(e).sty { + span_lint(cx, MUT_MUT, expr.span, + "This expression mutably borrows a mutable reference. \ + Consider reborrowing") + } + }) + }) } fn unwrap_mut(ty : &Ty) -> Option<&Ty> { - match ty.node { - TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), - TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), - _ => Option::None - } + match ty.node { + TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), + _ => Option::None + } } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 35d921e8fa1..3296bdeca87 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -25,38 +25,39 @@ impl LintPass for NeedlessBool { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_BOOL) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node { - match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (Option::Some(true), Option::Some(true)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "your if-then-else expression will always return true"); }, - (Option::Some(true), Option::Some(false)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if-statement to its predicate"); }, - (Option::Some(false), Option::Some(true)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if-statement to '!' + your predicate"); }, - (Option::Some(false), Option::Some(false)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "your if-then-else expression will always return false"); }, - _ => () - } - } + match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { + (Option::Some(true), Option::Some(true)) => { + span_lint(cx, NEEDLESS_BOOL, e.span, + "your if-then-else expression will always return true"); }, + (Option::Some(true), Option::Some(false)) => { + span_lint(cx, NEEDLESS_BOOL, e.span, + "you can reduce your if-statement to its predicate"); }, + (Option::Some(false), Option::Some(true)) => { + span_lint(cx, NEEDLESS_BOOL, e.span, + "you can reduce your if-statement to '!' + your predicate"); }, + (Option::Some(false), Option::Some(false)) => { + span_lint(cx, NEEDLESS_BOOL, e.span, + "your if-then-else expression will always return false"); }, + _ => () + } + } } } fn fetch_bool_block(block: &Block) -> Option<bool> { - if block.stmts.is_empty() { - block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) - } else { Option::None } + if block.stmts.is_empty() { + block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) + } else { Option::None } } - + fn fetch_bool_expr(expr: &Expr) -> Option<bool> { - match &expr.node { - &ExprBlock(ref block) => fetch_bool_block(block), - &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { Option::Some(value) } else { Option::None }, - _ => Option::None - } + match &expr.node { + &ExprBlock(ref block) => fetch_bool_block(block), + &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { + Option::Some(value) } else { Option::None }, + _ => Option::None + } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index dad4e48c832..939277fe66c 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -26,44 +26,44 @@ impl LintPass for PtrArg { fn get_lints(&self) -> LintArray { lint_array!(PTR_ARG) } - + fn check_item(&mut self, cx: &Context, item: &Item) { - if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { - check_fn(cx, decl); - } - } - - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { - if let &MethodImplItem(ref sig, _) = &item.node { - check_fn(cx, &sig.decl); - } - } - - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { - if let &MethodTraitItem(ref sig, _) = &item.node { - check_fn(cx, &sig.decl); - } - } + if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { + check_fn(cx, decl); + } + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + if let &MethodImplItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + if let &MethodTraitItem(ref sig, _) = &item.node { + check_fn(cx, &sig.decl); + } + } } fn check_fn(cx: &Context, decl: &FnDecl) { - for arg in &decl.inputs { - match &arg.ty.node { - &TyPtr(ref p) | &TyRptr(_, ref p) => - check_ptr_subtype(cx, arg.ty.span, &p.ty), - _ => () - } - } + for arg in &decl.inputs { + match &arg.ty.node { + &TyPtr(ref p) | &TyRptr(_, ref p) => + check_ptr_subtype(cx, arg.ty.span, &p.ty), + _ => () + } + } } fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { - match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, - &["String"]).map_or((), |_| { - span_lint(cx, PTR_ARG, span, - "Writing '&String' instead of '&str' involves a new Object \ - where a slices will do. Consider changing the type to &str") - }), |_| span_lint(cx, PTR_ARG, span, "Writing '&Vec<_>' instead of \ - '&[_]' involves one more reference and cannot be used with \ - non-vec-based slices. Consider changing the type to &[...]") - ) + match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, + &["String"]).map_or((), |_| { + span_lint(cx, PTR_ARG, span, + "Writing '&String' instead of '&str' involves a new Object \ + where a slices will do. Consider changing the type to &str") + }), |_| span_lint(cx, PTR_ARG, span, + "Writing '&Vec<_>' instead of \ + '&[_]' involves one more reference and cannot be used with \ + non-vec-based slices. Consider changing the type to &[...]")) } diff --git a/src/strings.rs b/src/strings.rs index 511d123b58d..3384eed8da5 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -1,5 +1,5 @@ //! This LintPass catches both string addition and string addition + assignment -//! +//! //! Note that since we have two lints where one subsumes the other, we try to //! disable the subsumed lint unless it has a higher level @@ -25,11 +25,11 @@ impl LintPass for StringAdd { fn get_lints(&self) -> LintArray { lint_array!(STRING_ADD_ASSIGN) } - + fn check_expr(&mut self, cx: &Context, e: &Expr) { if let &ExprAssign(ref target, ref src) = &e.node { - if is_string(cx, target) && is_add(src, target) { - span_lint(cx, STRING_ADD_ASSIGN, e.span, + if is_string(cx, target) && is_add(src, target) { + span_lint(cx, STRING_ADD_ASSIGN, e.span, "You assign the result of adding something to this string. \ Consider using `String::push_str(..) instead.") } @@ -47,7 +47,7 @@ fn is_add(src: &Expr, target: &Expr) -> bool { match &src.node { &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(target, left), - &ExprBlock(ref block) => block.stmts.is_empty() && + &ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)), &ExprParen(ref expr) => is_add(&*expr, target), _ => false diff --git a/src/unicode.rs b/src/unicode.rs index 9b908c3f94f..1854d5be7ff 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -9,38 +9,38 @@ declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" } pub struct Unicode; impl LintPass for Unicode { - fn get_lints(&self) -> LintArray { + fn get_lints(&self) -> LintArray { lint_array!(ZERO_WIDTH_SPACE) } - + fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprLit(ref lit) = expr.node { - if let LitStr(ref string, _) = lit.node { - check_str(cx, string, lit.span) - } - } - } + if let ExprLit(ref lit) = expr.node { + if let LitStr(ref string, _) = lit.node { + check_str(cx, string, lit.span) + } + } + } } fn check_str(cx: &Context, string: &str, span: Span) { - let mut start: Option<usize> = None; - for (i, c) in string.char_indices() { - if c == '\u{200B}' { - if start.is_none() { start = Some(i); } - } else { - lint_zero_width(cx, span, start); - start = None; - } - } - lint_zero_width(cx, span, start); + let mut start: Option<usize> = None; + for (i, c) in string.char_indices() { + if c == '\u{200B}' { + if start.is_none() { start = Some(i); } + } else { + lint_zero_width(cx, span, start); + start = None; + } + } + lint_zero_width(cx, span, start); } fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) { - start.map(|index| { - span_lint(cx, ZERO_WIDTH_SPACE, Span { - lo: span.lo + BytePos(index as u32), - hi: span.lo + BytePos(index as u32), - expn_id: span.expn_id, - }, "Zero-width space detected. Consider using \\u{200B}") - }); + start.map(|index| { + span_lint(cx, ZERO_WIDTH_SPACE, Span { + lo: span.lo + BytePos(index as u32), + hi: span.lo + BytePos(index as u32), + expn_id: span.expn_id, + }, "Zero-width space detected. Consider using \\u{200B}") + }); } diff --git a/src/utils.rs b/src/utils.rs index a231171aee5..4f5763b1491 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -15,7 +15,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { // no span for the callee = external macro info.callee.span.map_or(true, |span| { // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| // macro doesn't start with "macro_rules" // = compiler plugin !code.starts_with("macro_rules") @@ -26,7 +26,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { /// invokes in_macro with the expansion info of the given span pub fn in_external_macro(cx: &Context, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, + cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro(cx, info)) } @@ -57,7 +57,7 @@ pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { let node_id : NodeId = e.id; let parent_id : NodeId = map.get_parent_node(node_id); if node_id == parent_id { return None; } - map.find(parent_id).and_then(|node| + map.find(parent_id).and_then(|node| if let NodeExpr(parent) = node { Some(parent) } else { None } ) } @@ -77,7 +77,7 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); } -pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, +pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, help: &str) { span_lint(cx, lint, span, msg); if cx.current_level(lint) != Level::Allow { diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs old mode 100644 new mode 100755 index 488c8f16f5b..3eb170b295b --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -4,53 +4,53 @@ #[deny(approx_constant)] #[allow(unused)] fn main() { - let my_e = 2.7182; //~ERROR - let almost_e = 2.718; //~ERROR - let no_e = 2.71; - - let my_1_frac_pi = 0.3183; //~ERROR - let no_1_frac_pi = 0.31; - - let my_frac_1_sqrt_2 = 0.70710678; //~ERROR - let almost_frac_1_sqrt_2 = 0.70711; //~ERROR - let my_frac_1_sqrt_2 = 0.707; - - let my_frac_2_pi = 0.63661977; //~ERROR - let no_frac_2_pi = 0.636; - - let my_frac_2_sq_pi = 1.128379; //~ERROR - let no_frac_2_sq_pi = 1.128; - - let my_frac_2_pi = 1.57079632679; //~ERROR - let no_frac_2_pi = 1.5705; - - let my_frac_3_pi = 1.04719755119; //~ERROR - let no_frac_3_pi = 1.047; - - let my_frac_4_pi = 0.785398163397; //~ERROR - let no_frac_4_pi = 0.785; - - let my_frac_6_pi = 0.523598775598; //~ERROR - let no_frac_6_pi = 0.523; - - let my_frac_8_pi = 0.3926990816987; //~ERROR - let no_frac_8_pi = 0.392; - - let my_ln_10 = 2.302585092994046; //~ERROR - let no_ln_10 = 2.303; - - let my_ln_2 = 0.6931471805599453; //~ERROR - let no_ln_2 = 0.693; - - let my_log10_e = 0.43429448190325176; //~ERROR - let no_log10_e = 0.434; - - let my_log2_e = 1.4426950408889634; //~ERROR - let no_log2_e = 1.442; - - let my_pi = 3.1415; //~ERROR - let almost_pi = 3.141; - - let my_sq2 = 1.4142; //~ERROR - let no_sq2 = 1.414; + let my_e = 2.7182; //~ERROR + let almost_e = 2.718; //~ERROR + let no_e = 2.71; + + let my_1_frac_pi = 0.3183; //~ERROR + let no_1_frac_pi = 0.31; + + let my_frac_1_sqrt_2 = 0.70710678; //~ERROR + let almost_frac_1_sqrt_2 = 0.70711; //~ERROR + let my_frac_1_sqrt_2 = 0.707; + + let my_frac_2_pi = 0.63661977; //~ERROR + let no_frac_2_pi = 0.636; + + let my_frac_2_sq_pi = 1.128379; //~ERROR + let no_frac_2_sq_pi = 1.128; + + let my_frac_2_pi = 1.57079632679; //~ERROR + let no_frac_2_pi = 1.5705; + + let my_frac_3_pi = 1.04719755119; //~ERROR + let no_frac_3_pi = 1.047; + + let my_frac_4_pi = 0.785398163397; //~ERROR + let no_frac_4_pi = 0.785; + + let my_frac_6_pi = 0.523598775598; //~ERROR + let no_frac_6_pi = 0.523; + + let my_frac_8_pi = 0.3926990816987; //~ERROR + let no_frac_8_pi = 0.392; + + let my_ln_10 = 2.302585092994046; //~ERROR + let no_ln_10 = 2.303; + + let my_ln_2 = 0.6931471805599453; //~ERROR + let no_ln_2 = 0.693; + + let my_log10_e = 0.43429448190325176; //~ERROR + let no_log10_e = 0.434; + + let my_log2_e = 1.4426950408889634; //~ERROR + let no_log2_e = 1.442; + + let my_pi = 3.1415; //~ERROR + let almost_pi = 3.141; + + let my_sq2 = 1.4142; //~ERROR + let no_sq2 = 1.414; } diff --git a/tests/compile-fail/attrs.rs b/tests/compile-fail/attrs.rs old mode 100644 new mode 100755 index 9b648a517e0..42bb0fca6dc --- a/tests/compile-fail/attrs.rs +++ b/tests/compile-fail/attrs.rs @@ -5,29 +5,29 @@ #[inline(always)] //~ERROR You have declared #[inline(always)] on test_attr_lint. fn test_attr_lint() { - assert!(true) + assert!(true) } #[inline(always)] fn false_positive_expr() { - unreachable!() + unreachable!() } #[inline(always)] fn false_positive_stmt() { - unreachable!(); + unreachable!(); } #[inline(always)] fn empty_and_false_positive_stmt() { - ; - unreachable!(); + ; + unreachable!(); } fn main() { - test_attr_lint(); - if false { false_positive_expr() } - if false { false_positive_stmt() } - if false { empty_and_false_positive_stmt() } + test_attr_lint(); + if false { false_positive_expr() } + if false { false_positive_stmt() } + if false { empty_and_false_positive_stmt() } } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs old mode 100644 new mode 100755 index e6b89b98564..c2a82483005 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -7,47 +7,47 @@ const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] #[allow(ineffective_bit_mask, identity_op)] fn main() { - let x = 5; - - x & 0 == 0; //~ERROR &-masking with zero - x & 1 == 1; //ok, distinguishes bit 0 - x & 1 == 0; //ok, compared with zero - x & 2 == 1; //~ERROR - x | 0 == 0; //ok, equals x == 0 (maybe warn?) - x | 1 == 3; //ok, equals x == 2 || x == 3 - x | 3 == 3; //ok, equals x <= 3 - x | 3 == 2; //~ERROR - - x & 1 > 1; //~ERROR - x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 - x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 - x | 1 > 1; // ok (if a bit silly), equals x > 1 - x | 2 > 1; //~ERROR - x | 2 <= 2; // ok (if a bit silly), equals x <= 2 - - // this also now works with constants - x & THREE_BITS == 8; //~ERROR - x | EVEN_MORE_REDIRECTION < 7; //~ERROR - - 0 & x == 0; //~ERROR - 1 | x > 1; - - // and should now also match uncommon usage - 1 < 2 | x; //~ERROR - 2 == 3 | x; //~ERROR - 1 == x & 2; //~ERROR - - x | 1 > 2; // no error, because we allowed ineffective bit masks - ineffective(); + let x = 5; + + x & 0 == 0; //~ERROR &-masking with zero + x & 1 == 1; //ok, distinguishes bit 0 + x & 1 == 0; //ok, compared with zero + x & 2 == 1; //~ERROR + x | 0 == 0; //ok, equals x == 0 (maybe warn?) + x | 1 == 3; //ok, equals x == 2 || x == 3 + x | 3 == 3; //ok, equals x <= 3 + x | 3 == 2; //~ERROR + + x & 1 > 1; //~ERROR + x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 + x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 + x | 1 > 1; // ok (if a bit silly), equals x > 1 + x | 2 > 1; //~ERROR + x | 2 <= 2; // ok (if a bit silly), equals x <= 2 + + // this also now works with constants + x & THREE_BITS == 8; //~ERROR + x | EVEN_MORE_REDIRECTION < 7; //~ERROR + + 0 & x == 0; //~ERROR + 1 | x > 1; + + // and should now also match uncommon usage + 1 < 2 | x; //~ERROR + 2 == 3 | x; //~ERROR + 1 == x & 2; //~ERROR + + x | 1 > 2; // no error, because we allowed ineffective bit masks + ineffective(); } #[deny(ineffective_bit_mask)] #[allow(bad_bit_mask)] fn ineffective() { - let x = 5; - - x | 1 > 2; //~ERROR - x | 1 < 3; //~ERROR - x | 1 <= 3; //~ERROR - x | 1 >= 2; //~ERROR + let x = 5; + + x | 1 > 2; //~ERROR + x | 1 < 3; //~ERROR + x | 1 <= 3; //~ERROR + x | 1 >= 2; //~ERROR } diff --git a/tests/compile-fail/box_vec.rs b/tests/compile-fail/box_vec.rs old mode 100644 new mode 100755 index 51d21f5537a..7d80dd86d22 --- a/tests/compile-fail/box_vec.rs +++ b/tests/compile-fail/box_vec.rs @@ -8,7 +8,7 @@ pub fn test(foo: Box<Vec<bool>>) { //~ ERROR You seem to be trying to use Box<Ve } pub fn test2(foo: Box<Fn(Vec<u32>)>) { // pass if #31 is fixed - foo(vec![1, 2, 3]) + foo(vec![1, 2, 3]) } fn main(){ diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs old mode 100644 new mode 100755 index 69631331467..b6549c2c1fb --- a/tests/compile-fail/cmp_nan.rs +++ b/tests/compile-fail/cmp_nan.rs @@ -4,19 +4,19 @@ #[deny(cmp_nan)] #[allow(float_cmp)] fn main() { - let x = 5f32; - x == std::f32::NAN; //~ERROR - x != std::f32::NAN; //~ERROR - x < std::f32::NAN; //~ERROR - x > std::f32::NAN; //~ERROR - x <= std::f32::NAN; //~ERROR - x >= std::f32::NAN; //~ERROR + let x = 5f32; + x == std::f32::NAN; //~ERROR + x != std::f32::NAN; //~ERROR + x < std::f32::NAN; //~ERROR + x > std::f32::NAN; //~ERROR + x <= std::f32::NAN; //~ERROR + x >= std::f32::NAN; //~ERROR - let y = 0f64; - y == std::f64::NAN; //~ERROR - y != std::f64::NAN; //~ERROR - y < std::f64::NAN; //~ERROR - y > std::f64::NAN; //~ERROR - y <= std::f64::NAN; //~ERROR - y >= std::f64::NAN; //~ERROR + let y = 0f64; + y == std::f64::NAN; //~ERROR + y != std::f64::NAN; //~ERROR + y < std::f64::NAN; //~ERROR + y > std::f64::NAN; //~ERROR + y <= std::f64::NAN; //~ERROR + y >= std::f64::NAN; //~ERROR } diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs old mode 100644 new mode 100755 index d7399e6d3aa..5951dc1bbd7 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -3,21 +3,21 @@ #[deny(cmp_owned)] fn main() { - let x = "oh"; - - #[allow(str_to_string)] - fn with_to_string(x : &str) { - x != "foo".to_string(); //~ERROR this creates an owned instance - } - with_to_string(x); - - x != "foo".to_owned(); //~ERROR this creates an owned instance - - #[allow(deprecated)] // for from_str - fn old_timey(x : &str) { - x != String::from_str("foo"); //~ERROR this creates an owned instance - } - old_timey(x); - - x != String::from("foo"); //~ERROR this creates an owned instance + let x = "oh"; + + #[allow(str_to_string)] + fn with_to_string(x : &str) { + x != "foo".to_string(); //~ERROR this creates an owned instance + } + with_to_string(x); + + x != "foo".to_owned(); //~ERROR this creates an owned instance + + #[allow(deprecated)] // for from_str + fn old_timey(x : &str) { + x != String::from_str("foo"); //~ERROR this creates an owned instance + } + old_timey(x); + + x != String::from("foo"); //~ERROR this creates an owned instance } diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs old mode 100644 new mode 100755 index 7b7ff13f24b..280744b5b45 --- a/tests/compile-fail/collapsible_if.rs +++ b/tests/compile-fail/collapsible_if.rs @@ -34,10 +34,10 @@ fn main() { } } - if x == "hello" { - print!("Hello "); - if y == "world" { - println!("world!") - } - } + if x == "hello" { + print!("Hello "); + if y == "world" { + println!("world!") + } + } } diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs old mode 100644 new mode 100755 index 07b15625b2c..45fce0c0bb3 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -2,35 +2,35 @@ #![plugin(clippy)] fn id<X>(x: X) -> X { - x + x } #[deny(eq_op)] #[allow(identity_op)] fn main() { - // simple values and comparisons - 1 == 1; //~ERROR - "no" == "no"; //~ERROR - // even though I agree that no means no ;-) - false != false; //~ERROR - 1.5 < 1.5; //~ERROR - 1u64 >= 1u64; //~ERROR - - // casts, methods, parenthesis - (1 as u64) & (1 as u64); //~ERROR - 1 ^ ((((((1)))))); //~ERROR - id((1)) | id(1); //~ERROR - - // unary and binary operators - (-(2) < -(2)); //~ERROR + // simple values and comparisons + 1 == 1; //~ERROR + "no" == "no"; //~ERROR + // even though I agree that no means no ;-) + false != false; //~ERROR + 1.5 < 1.5; //~ERROR + 1u64 >= 1u64; //~ERROR + + // casts, methods, parenthesis + (1 as u64) & (1 as u64); //~ERROR + 1 ^ ((((((1)))))); //~ERROR + id((1)) | id(1); //~ERROR + + // unary and binary operators + (-(2) < -(2)); //~ERROR ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); //~^ ERROR //~^^ ERROR //~^^^ ERROR - (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR - - // various other things - ([1] != [1]); //~ERROR + (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR + + // various other things + ([1] != [1]); //~ERROR ((1, 2) != (1, 2)); //~ERROR [1].len() == [1].len(); //~ERROR vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs old mode 100644 new mode 100755 index dce8dba1ebe..2305e42161a --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -7,29 +7,29 @@ const ZERO : f32 = 0.0; const ONE : f32 = ZERO + 1.0; fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy { - x + x + x + x } #[deny(float_cmp)] #[allow(unused)] fn main() { - ZERO == 0f32; //~ERROR - ZERO == 0.0; //~ERROR - ZERO + ZERO != 1.0; //~ERROR - - ONE != 0.0; //~ERROR - twice(ONE) != ONE; //~ERROR - ONE as f64 != 0.0; //~ERROR - - let x : f64 = 1.0; - - x == 1.0; //~ERROR - x != 0f64; //~ERROR - - twice(x) != twice(ONE as f64); //~ERROR - - x < 0.0; - x > 0.0; - x <= 0.0; - x >= 0.0; + ZERO == 0f32; //~ERROR + ZERO == 0.0; //~ERROR + ZERO + ZERO != 1.0; //~ERROR + + ONE != 0.0; //~ERROR + twice(ONE) != ONE; //~ERROR + ONE as f64 != 0.0; //~ERROR + + let x : f64 = 1.0; + + x == 1.0; //~ERROR + x != 0f64; //~ERROR + + twice(x) != twice(ONE as f64); //~ERROR + + x < 0.0; + x > 0.0; + x <= 0.0; + x >= 0.0; } diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs old mode 100644 new mode 100755 index 6c17d30fac4..cde4a615b25 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -7,18 +7,18 @@ const ZERO : i64 = 0; #[deny(identity_op)] fn main() { - let x = 0; - - x + 0; //~ERROR - 0 + x; //~ERROR - x - ZERO; //~ERROR - x | (0); //~ERROR - ((ZERO)) | x; //~ERROR - - x * 1; //~ERROR - 1 * x; //~ERROR - x / ONE; //~ERROR - - x & NEG_ONE; //~ERROR - -1 & x; //~ERROR + let x = 0; + + x + 0; //~ERROR + 0 + x; //~ERROR + x - ZERO; //~ERROR + x | (0); //~ERROR + ((ZERO)) | x; //~ERROR + + x * 1; //~ERROR + 1 * x; //~ERROR + x / ONE; //~ERROR + + x & NEG_ONE; //~ERROR + -1 & x; //~ERROR } diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs old mode 100644 new mode 100755 index e64010d334d..48a10042658 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -5,98 +5,98 @@ struct One; #[deny(len_without_is_empty)] impl One { - fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)' - 1 - } + fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)' + 1 + } } #[deny(len_without_is_empty)] trait TraitsToo { - fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_: + fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_: } impl TraitsToo for One { - fn len(self: &Self) -> isize { - 0 - } + fn len(self: &Self) -> isize { + 0 + } } struct HasIsEmpty; #[deny(len_without_is_empty)] impl HasIsEmpty { - fn len(self: &Self) -> isize { - 1 - } + fn len(self: &Self) -> isize { + 1 + } - fn is_empty(self: &Self) -> bool { - false - } + fn is_empty(self: &Self) -> bool { + false + } } struct Wither; #[deny(len_without_is_empty)] trait WithIsEmpty { - fn len(self: &Self) -> isize; - fn is_empty(self: &Self) -> bool; + fn len(self: &Self) -> isize; + fn is_empty(self: &Self) -> bool; } impl WithIsEmpty for Wither { - fn len(self: &Self) -> isize { - 1 - } + fn len(self: &Self) -> isize { + 1 + } - fn is_empty(self: &Self) -> bool { - false - } + fn is_empty(self: &Self) -> bool { + false + } } struct HasWrongIsEmpty; #[deny(len_without_is_empty)] impl HasWrongIsEmpty { - fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)' - 1 - } - - #[allow(dead_code, unused)] - fn is_empty(self: &Self, x : u32) -> bool { - false - } + fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)' + 1 + } + + #[allow(dead_code, unused)] + fn is_empty(self: &Self, x : u32) -> bool { + false + } } #[deny(len_zero)] fn main() { - let x = [1, 2]; - if x.len() == 0 { //~ERROR Consider replacing the len comparison - println!("This should not happen!"); - } - - let y = One; - if y.len() == 0 { //no error because One does not have .is_empty() - println!("This should not happen either!"); - } - - let z : &TraitsToo = &y; - if z.len() > 0 { //no error, because TraitsToo has no .is_empty() method - println!("Nor should this!"); - } - - let hie = HasIsEmpty; - if hie.len() == 0 { //~ERROR Consider replacing the len comparison - println!("Or this!"); - } - assert!(!hie.is_empty()); - - let wie : &WithIsEmpty = &Wither; - if wie.len() == 0 { //~ERROR Consider replacing the len comparison - println!("Or this!"); - } - assert!(!wie.is_empty()); - - let hwie = HasWrongIsEmpty; - if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty() - println!("Or this!"); - } + let x = [1, 2]; + if x.len() == 0 { //~ERROR Consider replacing the len comparison + println!("This should not happen!"); + } + + let y = One; + if y.len() == 0 { //no error because One does not have .is_empty() + println!("This should not happen either!"); + } + + let z : &TraitsToo = &y; + if z.len() > 0 { //no error, because TraitsToo has no .is_empty() method + println!("Nor should this!"); + } + + let hie = HasIsEmpty; + if hie.len() == 0 { //~ERROR Consider replacing the len comparison + println!("Or this!"); + } + assert!(!hie.is_empty()); + + let wie : &WithIsEmpty = &Wither; + if wie.len() == 0 { //~ERROR Consider replacing the len comparison + println!("Or this!"); + } + assert!(!wie.is_empty()); + + let hwie = HasWrongIsEmpty; + if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty() + println!("Or this!"); + } } diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs old mode 100644 new mode 100755 index d7adc067740..2a3f7e3958c --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -6,29 +6,29 @@ #[deny(mut_mut)] fn fun(x : &mut &mut u32) -> bool { //~ERROR - **x > 0 + **x > 0 } macro_rules! mut_ptr { - ($p:expr) => { &mut $p } -} + ($p:expr) => { &mut $p } +} #[deny(mut_mut)] #[allow(unused_mut, unused_variables)] fn main() { - let mut x = &mut &mut 1u32; //~ERROR - { - let mut y = &mut x; //~ERROR - } - - if fun(x) { - let y : &mut &mut &mut u32 = &mut &mut &mut 2; - //~^ ERROR - //~^^ ERROR - //~^^^ ERROR - //~^^^^ ERROR - ***y + **x; - } - - let mut z = mut_ptr!(&mut 3u32); //~ERROR + let mut x = &mut &mut 1u32; //~ERROR + { + let mut y = &mut x; //~ERROR + } + + if fun(x) { + let y : &mut &mut &mut u32 = &mut &mut &mut 2; + //~^ ERROR + //~^^ ERROR + //~^^^ ERROR + //~^^^^ ERROR + ***y + **x; + } + + let mut z = mut_ptr!(&mut 3u32); //~ERROR } diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs old mode 100644 new mode 100755 index 97a478ee410..88919f39d6d --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -3,10 +3,10 @@ #[deny(needless_bool)] fn main() { - let x = true; - if x { true } else { true }; //~ERROR - if x { false } else { false }; //~ERROR - if x { true } else { false }; //~ERROR - if x { false } else { true }; //~ERROR - if x { x } else { false }; // would also be questionable, but we don't catch this yet + let x = true; + if x { true } else { true }; //~ERROR + if x { false } else { false }; //~ERROR + if x { true } else { false }; //~ERROR + if x { false } else { true }; //~ERROR + if x { x } else { false }; // would also be questionable, but we don't catch this yet } diff --git a/tests/compile-fail/precedence.rs b/tests/compile-fail/precedence.rs old mode 100644 new mode 100755 index 7969be0f371..fb7d06214a2 --- a/tests/compile-fail/precedence.rs +++ b/tests/compile-fail/precedence.rs @@ -4,7 +4,7 @@ #[deny(precedence)] #[allow(eq_op)] fn main() { - format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR + format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs old mode 100644 new mode 100755 index 2fe36eafa6c..7ba291b1439 --- a/tests/compile-fail/ptr_arg.rs +++ b/tests/compile-fail/ptr_arg.rs @@ -4,17 +4,17 @@ #[deny(ptr_arg)] #[allow(unused)] fn do_vec(x: &Vec<i64>) { //~ERROR: Writing '&Vec<_>' instead of '&[_]' - //Nothing here + //Nothing here } #[deny(ptr_arg)] #[allow(unused)] fn do_str(x: &String) { //~ERROR - //Nothing here either + //Nothing here either } fn main() { - let x = vec![1i64, 2, 3]; - do_vec(&x); - do_str(&"hello".to_owned()); + let x = vec![1i64, 2, 3]; + do_vec(&x); + do_str(&"hello".to_owned()); } diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs old mode 100644 new mode 100755 index 2b200f1d07e..4b6f0bc884f --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -4,9 +4,9 @@ #![deny(string_add_assign)] fn main() { - let x = "".to_owned(); - - for i in (1..3) { - x = x + "."; //~ERROR - } + let x = "".to_owned(); + + for i in (1..3) { + x = x + "."; //~ERROR + } } diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs old mode 100644 new mode 100755 index 0385f45cc5e..a121b985f09 --- a/tests/compile-fail/unicode.rs +++ b/tests/compile-fail/unicode.rs @@ -3,23 +3,23 @@ #[deny(zero_width_space)] fn zero() { - print!("Here >​< is a ZWS, and ​another"); - //~^ ERROR Zero-width space detected. Consider using \u{200B} - //~^^ ERROR Zero-width space detected. Consider using \u{200B} + print!("Here >​< is a ZWS, and ​another"); + //~^ ERROR Zero-width space detected. Consider using \u{200B} + //~^^ ERROR Zero-width space detected. Consider using \u{200B} } //#[deny(unicode_canon)] fn canon() { - print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à + print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à } //#[deny(ascii_only)] fn uni() { - println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC} + println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC} } fn main() { - zero(); - uni(); - canon(); + zero(); + uni(); + canon(); } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 4af4ea7673a..602937a40af 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -5,13 +5,13 @@ use std::env::var; fn run_mode(mode: &'static str) { let mut config = compiletest::default_config(); - + let cfg_mode = mode.parse().ok().expect("Invalid mode"); config.target_rustcflags = Some("-L target/debug/".to_owned()); - if let Ok(name) = var::<&str>("TESTNAME") { - let s : String = name.to_owned(); - config.filter = Some(s) - } + if let Ok(name) = var::<&str>("TESTNAME") { + let s : String = name.to_owned(); + config.filter = Some(s) + } config.mode = cfg_mode; config.src_base = PathBuf::from(format!("tests/{}", mode)); diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs old mode 100644 new mode 100755 index 32fdea3a340..ebfd3ed2e1f --- a/tests/mut_mut_macro.rs +++ b/tests/mut_mut_macro.rs @@ -10,22 +10,22 @@ use std::collections::HashMap; #[test] #[deny(mut_mut)] fn test_regex() { - let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); - assert!(pattern.is_match("# headline")); + let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); + assert!(pattern.is_match("# headline")); } #[test] #[deny(mut_mut)] #[allow(unused_variables, unused_mut)] fn test_lazy_static() { - lazy_static! { - static ref MUT_MAP : HashMap<usize, &'static str> = { - let mut m = HashMap::new(); - let mut zero = &mut &mut "zero"; - m.insert(0, "zero"); - m - }; - static ref MUT_COUNT : usize = MUT_MAP.len(); - } - assert!(*MUT_COUNT == 1); + lazy_static! { + static ref MUT_MAP : HashMap<usize, &'static str> = { + let mut m = HashMap::new(); + let mut zero = &mut &mut "zero"; + m.insert(0, "zero"); + m + }; + static ref MUT_COUNT : usize = MUT_MAP.len(); + } + assert!(*MUT_COUNT == 1); } -- cgit 1.4.1-3-g733a5 From cf96042c65b4c232d0a73f6a8514e59e0358719b Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 20:57:21 +0200 Subject: move walk_ty() to utils module and rename to walk_ptrs_ty --- src/len_zero.rs | 5 ++--- src/misc.rs | 15 ++++----------- src/strings.rs | 5 ++--- src/utils.rs | 8 ++++++++ 4 files changed, 16 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 0877fa95238..8aa4c626760 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -9,8 +9,7 @@ use rustc::middle::ty::{self, TypeVariants, TypeAndMut, MethodTraitItemId, ImplO use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; -use misc::walk_ty; -use utils::span_lint; +use utils::{span_lint, walk_ptrs_ty}; declare_lint!(pub LEN_ZERO, Warn, "Warn when .is_empty() could be used instead of checking .len()"); @@ -136,7 +135,7 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { |iids| iids.iter().any(|i| is_is_empty(cx, i))))) } - let ty = &walk_ty(&cx.tcx.expr_ty(expr)); + let ty = &walk_ptrs_ty(&cx.tcx.expr_ty(expr)); match ty.sty { ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( &ty.ty_to_def_id().expect("trait impl not found")).map_or(false, diff --git a/src/misc.rs b/src/misc.rs index 444062a5919..a1b3dcb32b8 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,14 +7,7 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; -use utils::{match_path, snippet, span_lint, span_help_and_lint}; - -pub fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { - match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ty(tm.ty), - _ => ty - } -} +use utils::{match_path, snippet, span_lint, span_help_and_lint, walk_ptrs_ty}; /// Handles uncategorized lints /// Currently handles linting of if-let-able matches @@ -87,7 +80,7 @@ impl LintPass for StrToStringPass { } fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - match walk_ty(cx.tcx.expr_ty(expr)).sty { + match walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { ty::TyStr => true, _ => false } @@ -175,7 +168,7 @@ impl LintPass for FloatCmp { } fn is_float(cx: &Context, expr: &Expr) -> bool { - if let ty::TyFloat(_) = walk_ty(cx.tcx.expr_ty(expr)).sty { + if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { true } else { false @@ -274,7 +267,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = - walk_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } + walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } declare_lint!(pub NEEDLESS_RETURN, Warn, diff --git a/src/strings.rs b/src/strings.rs index 3384eed8da5..b6bc7654e47 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -8,9 +8,8 @@ use rustc::middle::ty::TypeVariants::TyStruct; use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use eq_op::is_exp_equal; -use misc::walk_ty; use types::match_ty_unwrap; -use utils::{match_def_path, span_lint}; +use utils::{match_def_path, span_lint, walk_ptrs_ty}; declare_lint! { pub STRING_ADD_ASSIGN, @@ -38,7 +37,7 @@ impl LintPass for StringAdd { } fn is_string(cx: &Context, e: &Expr) -> bool { - if let TyStruct(did, _) = walk_ty(cx.tcx.expr_ty(e)).sty { + if let TyStruct(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(e)).sty { match_def_path(cx, did.did, &["std", "string", "String"]) } else { false } } diff --git a/src/utils.rs b/src/utils.rs index 9b3b94e113e..107f5c6f99b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -84,3 +84,11 @@ pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, cx.sess().fileline_help(span, help); } } + +/// return the base type for references and raw pointers +pub fn walk_ptrs_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { + match ty.sty { + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), + _ => ty + } +} -- cgit 1.4.1-3-g733a5 From 2bcc15188854ff184c85426b5aa60535ed1bd8a8 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 20:53:50 +0200 Subject: new lint for Option.unwrap() and Result.unwrap() The latter is set to Allow by default (fixes #24) --- src/lib.rs | 4 ++++ src/methods.rs | 39 +++++++++++++++++++++++++++++++++++++++ tests/compile-fail/methods.rs | 11 +++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/methods.rs create mode 100755 tests/compile-fail/methods.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 80ba04031fa..4009aa1cf8d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub mod collapsible_if; pub mod unicode; pub mod utils; pub mod strings; +pub mod methods; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -55,6 +56,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); reg.register_lint_pass(box misc::NeedlessReturn as LintPassObject); + reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -77,5 +79,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_ADD_ASSIGN, misc::NEEDLESS_RETURN, misc::MODULO_ONE, + methods::OPTION_UNWRAP_USED, + methods::RESULT_UNWRAP_USED, ]); } diff --git a/src/methods.rs b/src/methods.rs new file mode 100644 index 00000000000..3d9aa8c6ffc --- /dev/null +++ b/src/methods.rs @@ -0,0 +1,39 @@ +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray}; +use rustc::middle::ty; + +use utils::{span_lint, match_def_path, walk_ptrs_ty}; + +#[derive(Copy,Clone)] +pub struct MethodsPass; + +declare_lint!(pub OPTION_UNWRAP_USED, Warn, + "Warn on using unwrap() on an Option value"); +declare_lint!(pub RESULT_UNWRAP_USED, Allow, + "Warn on using unwrap() on a Result value"); + +impl LintPass for MethodsPass { + fn get_lints(&self) -> LintArray { + lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprMethodCall(ref ident, _, ref args) = expr.node { + if ident.node.name == "unwrap" { + if let ty::TyEnum(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { + if match_def_path(cx, did.did, &["core", "option", "Option"]) { + span_lint(cx, OPTION_UNWRAP_USED, expr.span, + "used unwrap() on an Option value. If you don't want \ + to handle the None case gracefully, consider using + expect() to provide a better panic message."); + } + else if match_def_path(cx, did.did, &["core", "result", "Result"]) { + span_lint(cx, RESULT_UNWRAP_USED, expr.span, + "used unwrap() on a Result value. Graceful handling \ + of Err values is preferred."); + } + } + } + } + } +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs new file mode 100755 index 00000000000..e989dffe5a7 --- /dev/null +++ b/tests/compile-fail/methods.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(option_unwrap_used, result_unwrap_used)] +fn main() { + let opt = Some(0); + let _ = opt.unwrap(); //~ERROR + + let res: Result<i32, ()> = Ok(0); + let _ = res.unwrap(); //~ERROR +} -- cgit 1.4.1-3-g733a5 From 4350dab7618bfdd58ea6eca45dca8151434dc4a4 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 21:25:24 +0200 Subject: types: remove almost duplicate helper function I guess "help" instead of "note" is fine as well, so we can get rid of the extra function. --- src/types.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index d138239b5a7..f6d7749f160 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,7 +6,7 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use syntax::codemap::Span; -use utils::span_lint; +use utils::{span_lint, span_help_and_lint}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -40,14 +40,6 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> } } -/// Lets me span a note only if the lint is shown -pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, note: &str) { - span_lint(cx, lint, span, msg); - if cx.current_level(lint) != Level::Allow { - cx.sess().span_note(span, note); - } -} - impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) @@ -62,7 +54,7 @@ impl LintPass for TypePass { match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first()) .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { - span_note_and_lint(cx, BOX_VEC, ty.span, + span_help_and_lint(cx, BOX_VEC, ty.span, "You seem to be trying to use Box<Vec<T>>. Did you mean to use Vec<T>?", "Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation"); }); @@ -77,7 +69,7 @@ impl LintPass for TypePass { vec!["collections","linked_list","LinkedList"]]; for path in dlists.iter() { if match_ty_unwrap(ty, &path[..]).is_some() { - span_note_and_lint(cx, LINKEDLIST, ty.span, + span_help_and_lint(cx, LINKEDLIST, ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", "A RingBuf might work."); return; -- cgit 1.4.1-3-g733a5 From 02c0cafa146759f908201467d0a758f8f3d75325 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 21:47:34 +0200 Subject: move NeedlessReturn pass out to its own module and rename to ReturnPass --- src/lib.rs | 5 ++-- src/misc.rs | 69 ----------------------------------------------------- src/returns.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 71 deletions(-) create mode 100644 src/returns.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4009aa1cf8d..c5469c19858 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub mod unicode; pub mod utils; pub mod strings; pub mod methods; +pub mod returns; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -55,7 +56,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); - reg.register_lint_pass(box misc::NeedlessReturn as LintPassObject); + reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, @@ -77,7 +78,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, strings::STRING_ADD_ASSIGN, - misc::NEEDLESS_RETURN, + returns::NEEDLESS_RETURN, misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/src/misc.rs b/src/misc.rs index a1b3dcb32b8..934e8a7fb77 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -270,75 +270,6 @@ fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } -declare_lint!(pub NEEDLESS_RETURN, Warn, - "Warn on using a return statement where an expression would be enough"); - -#[derive(Copy,Clone)] -pub struct NeedlessReturn; - -impl NeedlessReturn { - // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &Context, block: &Block) { - if let Some(ref expr) = block.expr { - self.check_final_expr(cx, expr); - } else if let Some(stmt) = block.stmts.last() { - if let StmtSemi(ref expr, _) = stmt.node { - if let ExprRet(Some(ref inner)) = expr.node { - self.emit_lint(cx, (expr.span, inner.span)); - } - } - } - } - - // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { - match expr.node { - // simple return is always "bad" - ExprRet(Some(ref inner)) => { - self.emit_lint(cx, (expr.span, inner.span)); - } - // a whole block? check it! - ExprBlock(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 - ExprIf(_, ref ifblock, Some(ref elsexpr)) | - ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { - self.check_block_return(cx, ifblock); - self.check_final_expr(cx, elsexpr); - } - // a match expr, check all arms - ExprMatch(_, ref arms, _) => { - for arm in arms { - self.check_final_expr(cx, &*arm.body); - } - } - _ => { } - } - } - - fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { - span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( - "unneeded return statement. Consider using {} \ - without the trailing semicolon", - snippet(cx, spans.1, ".."))) - } -} - -impl LintPass for NeedlessReturn { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RETURN) - } - - fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, - block: &Block, _: Span, _: ast::NodeId) { - self.check_block_return(cx, block); - } -} - - declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0"); #[derive(Copy,Clone)] diff --git a/src/returns.rs b/src/returns.rs new file mode 100644 index 00000000000..d6a4b33b6d1 --- /dev/null +++ b/src/returns.rs @@ -0,0 +1,75 @@ +use syntax::ast; +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::visit::FnKind; +use rustc::lint::{Context, LintPass, LintArray}; + +use utils::{span_lint, snippet}; + +declare_lint!(pub NEEDLESS_RETURN, Warn, + "Warn on using a return statement where an expression would be enough"); + +#[derive(Copy,Clone)] +pub struct ReturnPass; + +impl ReturnPass { + // Check the final stmt or expr in a block for unnecessary return. + fn check_block_return(&mut self, cx: &Context, block: &Block) { + if let Some(ref expr) = block.expr { + self.check_final_expr(cx, expr); + } else if let Some(stmt) = block.stmts.last() { + if let StmtSemi(ref expr, _) = stmt.node { + if let ExprRet(Some(ref inner)) = expr.node { + self.emit_lint(cx, (expr.span, inner.span)); + } + } + } + } + + // Check a the final expression in a block if it's a return. + fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { + match expr.node { + // simple return is always "bad" + ExprRet(Some(ref inner)) => { + self.emit_lint(cx, (expr.span, inner.span)); + } + // a whole block? check it! + ExprBlock(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 + ExprIf(_, ref ifblock, Some(ref elsexpr)) | + ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { + self.check_block_return(cx, ifblock); + self.check_final_expr(cx, elsexpr); + } + // a match expr, check all arms + ExprMatch(_, ref arms, _) => { + for arm in arms { + self.check_final_expr(cx, &*arm.body); + } + } + _ => { } + } + } + + fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { + span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( + "unneeded return statement. Consider using {} \ + without the trailing semicolon", + snippet(cx, spans.1, ".."))) + } +} + +impl LintPass for ReturnPass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RETURN) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, + block: &Block, _: Span, _: ast::NodeId) { + self.check_block_return(cx, block); + } +} -- cgit 1.4.1-3-g733a5 From f6dc48fe3a0ec30b6db132b6848f6908f987af14 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 11 Aug 2015 22:06:30 +0200 Subject: new lint for "let x = EXPR; x" at the end of functions (fixes #104) --- README.md | 1 + src/returns.rs | 49 ++++++++++++++++++++++++++++++++++------ tests/compile-fail/let_return.rs | 34 ++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100755 tests/compile-fail/let_return.rs (limited to 'src') diff --git a/README.md b/README.md index f0d282e450a..1176841ca20 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Lints included in this crate: - `zero_width_space`: Warns on encountering a unicode zero-width space - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. - `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice. + - `let_and_return`: Warns on doing `let x = expr; x` at the end of a function. - `option_unwrap_used`: Warns when `Option.unwrap()` is used, and suggests `.expect()`. - `result_unwrap_used`: Warns when `Result.unwrap()` is used (silent by default). - `modulo_one`: Warns on taking a number modulo 1, which always has a result of 0. diff --git a/src/returns.rs b/src/returns.rs index d6a4b33b6d1..9bfc99972c9 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,13 +1,15 @@ use syntax::ast; use syntax::ast::*; -use syntax::codemap::Span; +use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; -use rustc::lint::{Context, LintPass, LintArray}; +use rustc::lint::{Context, LintPass, LintArray, Level}; -use utils::{span_lint, snippet}; +use utils::{span_lint, snippet, match_path}; declare_lint!(pub NEEDLESS_RETURN, Warn, "Warn on using a return statement where an expression would be enough"); +declare_lint!(pub LET_AND_RETURN, Warn, + "Warn on creating a let-binding and then immediately returning it"); #[derive(Copy,Clone)] pub struct ReturnPass; @@ -20,7 +22,7 @@ impl ReturnPass { } else if let Some(stmt) = block.stmts.last() { if let StmtSemi(ref expr, _) = stmt.node { if let ExprRet(Some(ref inner)) = expr.node { - self.emit_lint(cx, (expr.span, inner.span)); + self.emit_return_lint(cx, (expr.span, inner.span)); } } } @@ -31,7 +33,7 @@ impl ReturnPass { match expr.node { // simple return is always "bad" ExprRet(Some(ref inner)) => { - self.emit_lint(cx, (expr.span, inner.span)); + self.emit_return_lint(cx, (expr.span, inner.span)); } // a whole block? check it! ExprBlock(ref block) => { @@ -55,21 +57,54 @@ impl ReturnPass { } } - fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { + fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) { span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using {} \ without the trailing semicolon", snippet(cx, spans.1, ".."))) } + + // Check for "let x = EXPR; x" + fn check_let_return(&mut self, cx: &Context, block: &Block) { + // we need both a let-binding stmt and an expr + if let Some(stmt) = block.stmts.last() { + if let StmtDecl(ref decl, _) = stmt.node { + if let DeclLocal(ref local) = decl.node { + if let Some(ref initexpr) = local.init { + if let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node { + if let Some(ref retexpr) = block.expr { + if let ExprPath(_, ref path) = retexpr.node { + if match_path(path, &[&*id.name.as_str()]) { + self.emit_let_lint(cx, retexpr.span, initexpr.span); + } + } + } + } + } + } + } + } + } + + fn emit_let_lint(&mut self, cx: &Context, lint_span: Span, note_span: Span) { + span_lint(cx, LET_AND_RETURN, lint_span, + "returning the result of a let binding. \ + Consider returning the expression directly."); + if cx.current_level(LET_AND_RETURN) != Level::Allow { + cx.sess().span_note(note_span, + "this expression can be directly returned"); + } + } } impl LintPass for ReturnPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RETURN) + lint_array!(NEEDLESS_RETURN, LET_AND_RETURN) } fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: ast::NodeId) { self.check_block_return(cx, block); + self.check_let_return(cx, block); } } diff --git a/tests/compile-fail/let_return.rs b/tests/compile-fail/let_return.rs new file mode 100755 index 00000000000..8ea4653ef0f --- /dev/null +++ b/tests/compile-fail/let_return.rs @@ -0,0 +1,34 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(let_and_return)] + +fn test() -> i32 { + let _y = 0; // no warning + let x = 5; //~NOTE + x //~ERROR: +} + +fn test_nowarn_1() -> i32 { + let mut x = 5; + x += 1; + x +} + +fn test_nowarn_2() -> i32 { + let x = 5; + x + 1 +} + +fn test_nowarn_3() -> (i32, i32) { + // this should technically warn, but we do not compare complex patterns + let (x, y) = (5, 9); + (x, y) +} + +fn main() { + test(); + test_nowarn_1(); + test_nowarn_2(); + test_nowarn_3(); +} -- cgit 1.4.1-3-g733a5 From 6d5f9478b22da27dc59d204cf94060bf949b6746 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 07:48:00 +0200 Subject: utils: implement if_let_chain macro as suggested by isHavvy --- src/lib.rs | 3 ++- src/returns.rs | 26 ++++++++++++-------------- src/utils.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c5469c19858..fef678f668d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,8 @@ extern crate collections; use rustc::plugin::Registry; use rustc::lint::LintPassObject; +#[macro_use] +pub mod utils; pub mod types; pub mod misc; pub mod eq_op; @@ -27,7 +29,6 @@ pub mod len_zero; pub mod attrs; pub mod collapsible_if; pub mod unicode; -pub mod utils; pub mod strings; pub mod methods; pub mod returns; diff --git a/src/returns.rs b/src/returns.rs index 9bfc99972c9..5a361d3a7dc 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -67,20 +67,18 @@ impl ReturnPass { // Check for "let x = EXPR; x" fn check_let_return(&mut self, cx: &Context, block: &Block) { // we need both a let-binding stmt and an expr - if let Some(stmt) = block.stmts.last() { - if let StmtDecl(ref decl, _) = stmt.node { - if let DeclLocal(ref local) = decl.node { - if let Some(ref initexpr) = local.init { - if let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node { - if let Some(ref retexpr) = block.expr { - if let ExprPath(_, ref path) = retexpr.node { - if match_path(path, &[&*id.name.as_str()]) { - self.emit_let_lint(cx, retexpr.span, initexpr.span); - } - } - } - } - } + if_let_chain! { + [ + Some(stmt) = block.stmts.last(), + StmtDecl(ref decl, _) = stmt.node, + DeclLocal(ref local) = decl.node, + Some(ref initexpr) = local.init, + PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, + Some(ref retexpr) = block.expr, + ExprPath(_, ref path) = retexpr.node + ], { + if match_path(path, &[&*id.name.as_str()]) { + self.emit_let_lint(cx, retexpr.span, initexpr.span); } } } diff --git a/src/utils.rs b/src/utils.rs index 107f5c6f99b..575d39b0c23 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -92,3 +92,32 @@ pub fn walk_ptrs_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { _ => ty } } + +/// Produce a nested chain of if-lets from the patterns: +/// +/// if_let_chain! {[Some(y) = x, Some(z) = y], +/// { +/// block +/// } +/// } +/// +/// becomes +/// +/// if let Some(y) = x { +/// if let Some(z) = y { +/// block +/// } +/// } +#[macro_export] +macro_rules! if_let_chain { + ([$pat:pat = $expr:expr, $($p2:pat = $e2:expr),+], $block:block) => { + if let $pat = $expr { + if_let_chain!{ [$($p2 = $e2),+], $block } + } + }; + ([$pat:pat = $expr:expr], $block:block) => { + if let $pat = $expr { + $block + } + }; +} -- cgit 1.4.1-3-g733a5 From bcd95aec1ce4f2a328a2b1d4b2a1e44d36e02436 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 10:46:49 +0200 Subject: all: make style of lint messages consistent * start first sentence lowercased * use backticks to delimit code snippets * use "this is wrong. Consider doing X." consistently --- src/approx_const.rs | 2 +- src/attrs.rs | 2 +- src/bit_mask.rs | 16 ++++++++-------- src/collapsible_if.rs | 2 +- src/eta_reduction.rs | 2 +- src/identity_op.rs | 2 +- src/len_zero.rs | 10 +++++----- src/misc.rs | 20 ++++++++++---------- src/mut_mut.rs | 8 ++++---- src/needless_bool.rs | 4 ++-- src/ptr_arg.rs | 10 +++++----- src/returns.rs | 2 +- src/strings.rs | 4 ++-- src/types.rs | 8 +++----- src/unicode.rs | 2 +- tests/compile-fail/attrs.rs | 2 +- tests/compile-fail/box_vec.rs | 2 +- tests/compile-fail/collapsible_if.rs | 4 ++-- tests/compile-fail/eta.rs | 8 ++++---- tests/compile-fail/len_zero.rs | 12 ++++++------ tests/compile-fail/match_if_let.rs | 8 ++++---- tests/compile-fail/modulo_one.rs | 2 +- tests/compile-fail/ptr_arg.rs | 2 +- tests/compile-fail/unicode.rs | 6 +++--- 24 files changed, 69 insertions(+), 71 deletions(-) mode change 100644 => 100755 tests/compile-fail/eta.rs mode change 100644 => 100755 tests/compile-fail/modulo_one.rs (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 3ae579a74b9..594348bf93f 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -53,7 +53,7 @@ fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { for &(constant, name) in KNOWN_CONSTS { if within_epsilon(constant, value) { span_lint(cx, APPROX_CONSTANT, span, &format!( - "Approximate value of {}::{} found, consider using it directly.", module, &name)); + "approximate value of `{}::{}` found. Consider using it directly.", module, &name)); } } } diff --git a/src/attrs.rs b/src/attrs.rs index 6d73f1de964..789a992e3a5 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -101,7 +101,7 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, if let MetaWord(ref always) = values[0].node { if always != &"always" { continue; } span_lint(cx, INLINE_ALWAYS, attr.span, &format!( - "You have declared #[inline(always)] on {}. This \ + "you have declared `#[inline(always)]` on `{}`. This \ is usually a bad idea. Are you sure?", ident.name.as_str())); } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index ad6facfb199..b5f088c23ef 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -97,7 +97,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, BiBitAnd => if mask_value & cmp_value != mask_value { if cmp_value != 0 { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} can never be equal to {}", + "incompatible bit mask: `_ & {}` can never be equal to `{}`", mask_value, cmp_value)); } } else { @@ -108,7 +108,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiBitOr => if mask_value | cmp_value != cmp_value { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} can never be equal to {}", + "incompatible bit mask: `_ | {}` can never be equal to `{}`", mask_value, cmp_value)); }, _ => () @@ -116,7 +116,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, BiLt | BiGe => match bit_op { BiBitAnd => if mask_value < cmp_value { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} will always be lower than {}", + "incompatible bit mask: `_ & {}` will always be lower than `{}`", mask_value, cmp_value)); } else { if mask_value == 0 { @@ -126,12 +126,12 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiBitOr => if mask_value >= cmp_value { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} will never be lower than {}", + "incompatible bit mask: `_ | {}` will never be lower than `{}`", mask_value, cmp_value)); } else { if mask_value < cmp_value { span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + "ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly", mask_value, cmp_value)); } }, @@ -140,7 +140,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, BiLe | BiGt => match bit_op { BiBitAnd => if mask_value <= cmp_value { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ & {} will never be higher than {}", + "incompatible bit mask: `_ & {}` will never be higher than `{}`", mask_value, cmp_value)); } else { if mask_value == 0 { @@ -150,12 +150,12 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiBitOr => if mask_value > cmp_value { span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: _ | {} will always be higher than {}", + "incompatible bit mask: `_ | {}` will always be higher than `{}`", mask_value, cmp_value)); } else { if mask_value < cmp_value { span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: x | {} compared to {} is the same as x compared directly", + "ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly", mask_value, cmp_value)); } }, diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index eae3222945c..f1c82f3eef8 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -48,7 +48,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = single_stmt_of_block(then) { span_lint(cx, COLLAPSIBLE_IF, e.span, &format!( - "This if statement can be collapsed. Try: if {} && {}\n{:?}", + "this if statement can be collapsed. Try: `if {} && {}`\n{:?}", check_to_string(check), check_to_string(check_inner), e)); } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 6948c1b22ab..00c5a523981 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -51,7 +51,7 @@ impl LintPass for EtaPass { } } span_lint(cx, REDUNDANT_CLOSURE, expr.span, - &format!("Redundant closure found, consider using `{}` in its place", + &format!("redundant closure found. Consider using `{}` in its place.", expr_to_string(caller))[..]) } } diff --git a/src/identity_op.rs b/src/identity_op.rs index 56d01c52b1d..e043ac63026 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -49,7 +49,7 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if have_lit(cx, e, m) { span_lint(cx, IDENTITY_OP, span, &format!( - "The operation is ineffective. Consider reducing it to '{}'", + "the operation is ineffective. Consider reducing it to `{}`.", snippet(cx, arg, ".."))); } } diff --git a/src/len_zero.rs b/src/len_zero.rs index 8aa4c626760..dea713180f5 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -58,8 +58,8 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { for i in trait_items { if is_named_self(i, "len") { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, - &format!("Trait '{}' has a '.len(_: &Self)' method, but no \ - '.is_empty(_: &Self)' method. Consider adding one.", + &format!("trait `{}` has a `.len(_: &Self)` method, but no \ + `.is_empty(_: &Self)` method. Consider adding one.", item.ident.name)); } }; @@ -78,8 +78,8 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { let s = i.span; span_lint(cx, LEN_WITHOUT_IS_EMPTY, Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, - &format!("Item '{}' has a '.len(_: &Self)' method, but no \ - '.is_empty(_: &Self)' method. Consider adding one.", + &format!("item `{}` has a `.len(_: &Self)` method, but no \ + `.is_empty(_: &Self)` method. Consider adding one.", item.ident.name)); return; } @@ -108,7 +108,7 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, if method.node.name == "len" && args.len() == 1 && has_is_empty(cx, &*args[0]) { span_lint(cx, LEN_ZERO, span, &format!( - "Consider replacing the len comparison with '{}_.is_empty()'", + "consider replacing the len comparison with `{}_.is_empty()`", empty)) } } diff --git a/src/misc.rs b/src/misc.rs index 934e8a7fb77..fa1847aad9a 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -43,10 +43,10 @@ impl LintPass for MiscPass { format!("{{ {} }}", body_code) }; span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "You seem to be trying to use match for \ + "you seem to be trying to use match for \ destructuring a single pattern. Did you mean to \ use `if let`?", - &*format!("Try\nif let {} = {} {}", + &*format!("try\nif let {} = {} {}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), suggestion) @@ -74,7 +74,7 @@ impl LintPass for StrToStringPass { ast::ExprMethodCall(ref method, _, ref args) if method.node.name == "to_string" && is_str(cx, &*args[0]) => { - span_lint(cx, STR_TO_STRING, expr.span, "str.to_owned() is faster"); + span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); }, _ => () } @@ -105,7 +105,7 @@ impl LintPass for TopLevelRefPass { span_lint(cx, TOPLEVEL_REF_ARG, arg.pat.span, - "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" + "`ref` directly on a function argument is ignored. Consider using a reference type instead." ); } } @@ -139,7 +139,7 @@ impl LintPass for CmpNan { fn check_nan(cx: &Context, path: &Path, span: Span) { path.segments.last().map(|seg| if seg.identifier.name == "NAN" { span_lint(cx, CMP_NAN, span, - "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); }); } @@ -159,7 +159,7 @@ impl LintPass for FloatCmp { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { span_lint(cx, FLOAT_CMP, expr.span, &format!( - "{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon", + "{}-comparison of f32 or f64 detected. Consider changing this to `abs({} - {}) < epsilon` for some suitable value of epsilon.", binop_to_string(op), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); } @@ -190,7 +190,7 @@ impl LintPass for Precedence { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { span_lint(cx, PRECEDENCE, expr.span, - "Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); + "operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); } } } @@ -246,7 +246,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { name == "to_owned" && is_str_arg(cx, args) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ - Consider using {}.as_slice() to compare without allocation", + Consider using `{}.as_slice()` to compare without allocation.", snippet(cx, other_span, ".."))) } }, @@ -256,7 +256,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { match_path(path, &["String", "from"]) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ - Consider using {}.as_slice() to compare without allocation", + Consider using `{}.as_slice()` to compare without allocation.", snippet(cx, other_span, ".."))) } } @@ -284,7 +284,7 @@ impl LintPass for ModuloOne { if let ExprBinary(ref cmp, _, ref right) = expr.node { if let &Spanned {node: BinOp_::BiRem, ..} = cmp { if is_lit_one(right) { - cx.span_lint(MODULO_ONE, expr.span, "Any number modulo 1 will be 0"); + cx.span_lint(MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 16ea422f77f..469a14a9452 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -23,7 +23,7 @@ impl LintPass for MutMut { fn check_ty(&mut self, cx: &Context, ty: &Ty) { unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, - ty.span, "Generally you want to avoid &mut &mut _ if possible.")) + ty.span, "generally you want to avoid `&mut &mut _` if possible")) } } @@ -40,13 +40,13 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map(|_| { span_lint(cx, MUT_MUT, expr.span, - "Generally you want to avoid &mut &mut _ if possible.") + "generally you want to avoid `&mut &mut _` if possible") }).unwrap_or_else(|| { if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = cx.tcx.expr_ty(e).sty { span_lint(cx, MUT_MUT, expr.span, - "This expression mutably borrows a mutable reference. \ - Consider reborrowing") + "this expression mutably borrows a mutable reference. \ + Consider reborrowing.") } }) }) diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 3296bdeca87..fcbc287e30f 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -34,10 +34,10 @@ impl LintPass for NeedlessBool { "your if-then-else expression will always return true"); }, (Option::Some(true), Option::Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if-statement to its predicate"); }, + "you can reduce your if statement to its predicate"); }, (Option::Some(false), Option::Some(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if-statement to '!' + your predicate"); }, + "you can reduce your if statement to `!` + your predicate"); }, (Option::Some(false), Option::Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, "your if-then-else expression will always return false"); }, diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 939277fe66c..ed37c112040 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -60,10 +60,10 @@ fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, &["String"]).map_or((), |_| { span_lint(cx, PTR_ARG, span, - "Writing '&String' instead of '&str' involves a new Object \ - where a slices will do. Consider changing the type to &str") + "writing `&String` instead of `&str` involves a new object \ + where a slice will do. Consider changing the type to `&str`.") }), |_| span_lint(cx, PTR_ARG, span, - "Writing '&Vec<_>' instead of \ - '&[_]' involves one more reference and cannot be used with \ - non-vec-based slices. Consider changing the type to &[...]")) + "writing `&Vec<_>` instead of \ + `&[_]` involves one more reference and cannot be used with \ + non-Vec-based slices. Consider changing the type to `&[...]`.")) } diff --git a/src/returns.rs b/src/returns.rs index 5a361d3a7dc..70af37d5181 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -59,7 +59,7 @@ impl ReturnPass { fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) { span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( - "unneeded return statement. Consider using {} \ + "unneeded return statement. Consider using `{}` \ without the trailing semicolon", snippet(cx, spans.1, ".."))) } diff --git a/src/strings.rs b/src/strings.rs index b6bc7654e47..97016f36268 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -29,8 +29,8 @@ impl LintPass for StringAdd { if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, - "You assign the result of adding something to this string. \ - Consider using `String::push_str(..) instead.") + "you assign the result of adding something to this string. \ + Consider using `String::push_str()` instead.") } } } diff --git a/src/types.rs b/src/types.rs index f6d7749f160..b03829660dc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,3 @@ - - use syntax::ptr::P; use syntax::ast; use syntax::ast::*; @@ -55,8 +53,8 @@ impl LintPass for TypePass { .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) .map(|_| { span_help_and_lint(cx, BOX_VEC, ty.span, - "You seem to be trying to use Box<Vec<T>>. Did you mean to use Vec<T>?", - "Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation"); + "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); }); { // In case stuff gets moved around @@ -71,7 +69,7 @@ impl LintPass for TypePass { if match_ty_unwrap(ty, &path[..]).is_some() { span_help_and_lint(cx, LINKEDLIST, ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "A RingBuf might work."); + "a RingBuf might work"); return; } } diff --git a/src/unicode.rs b/src/unicode.rs index 1854d5be7ff..af48c9b99ad 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -41,6 +41,6 @@ fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) { lo: span.lo + BytePos(index as u32), hi: span.lo + BytePos(index as u32), expn_id: span.expn_id, - }, "Zero-width space detected. Consider using \\u{200B}") + }, "zero-width space detected. Consider using `\\u{200B}`.") }); } diff --git a/tests/compile-fail/attrs.rs b/tests/compile-fail/attrs.rs index 42bb0fca6dc..ca7a0d5c07b 100755 --- a/tests/compile-fail/attrs.rs +++ b/tests/compile-fail/attrs.rs @@ -3,7 +3,7 @@ #![deny(inline_always)] -#[inline(always)] //~ERROR You have declared #[inline(always)] on test_attr_lint. +#[inline(always)] //~ERROR you have declared `#[inline(always)]` on `test_attr_lint`. fn test_attr_lint() { assert!(true) } diff --git a/tests/compile-fail/box_vec.rs b/tests/compile-fail/box_vec.rs index 7d80dd86d22..58e780f190c 100755 --- a/tests/compile-fail/box_vec.rs +++ b/tests/compile-fail/box_vec.rs @@ -3,7 +3,7 @@ #![plugin(clippy)] #![deny(clippy)] -pub fn test(foo: Box<Vec<bool>>) { //~ ERROR You seem to be trying to use Box<Vec<T>> +pub fn test(foo: Box<Vec<bool>>) { //~ ERROR you seem to be trying to use `Box<Vec<T>>` println!("{:?}", foo.get(0)) } diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs index 280744b5b45..cc63e895f1c 100755 --- a/tests/compile-fail/collapsible_if.rs +++ b/tests/compile-fail/collapsible_if.rs @@ -5,13 +5,13 @@ fn main() { let x = "hello"; let y = "world"; - if x == "hello" { //~ERROR This if statement can be collapsed + if x == "hello" { //~ERROR this if statement can be collapsed if y == "world" { println!("Hello world!"); } } - if x == "hello" || x == "world" { //~ERROR This if statement can be collapsed + if x == "hello" || x == "world" { //~ERROR this if statement can be collapsed if y == "world" || y == "hello" { println!("Hello world!"); } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs old mode 100644 new mode 100755 index 8ca88eecbd2..9e48ec1c3a5 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -5,11 +5,11 @@ fn main() { let a = |a, b| foo(a, b); - //~^ ERROR Redundant closure found, consider using `foo` in its place + //~^ ERROR redundant closure found. Consider using `foo` in its place let c = |a, b| {1+2; foo}(a, b); - //~^ ERROR Redundant closure found, consider using `{ 1 + 2; foo }` in its place + //~^ ERROR redundant closure found. Consider using `{ 1 + 2; foo }` in its place let d = |a, b| foo((|c, d| foo2(c,d))(a,b), b); - //~^ ERROR Redundant closure found, consider using `foo2` in its place + //~^ ERROR redundant closure found. Consider using `foo2` in its place } fn foo(_: u8, _: u8) { @@ -18,4 +18,4 @@ fn foo(_: u8, _: u8) { fn foo2(_: u8, _: u8) -> u8 { 1u8 -} \ No newline at end of file +} diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 48a10042658..3785a518e2b 100755 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -5,14 +5,14 @@ struct One; #[deny(len_without_is_empty)] impl One { - fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len(_: &Self)' + fn len(self: &Self) -> isize { //~ERROR item `One` has a `.len(_: &Self)` 1 } } #[deny(len_without_is_empty)] trait TraitsToo { - fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len(_: + fn len(self: &Self) -> isize; //~ERROR trait `TraitsToo` has a `.len(_: } impl TraitsToo for One { @@ -56,7 +56,7 @@ struct HasWrongIsEmpty; #[deny(len_without_is_empty)] impl HasWrongIsEmpty { - fn len(self: &Self) -> isize { //~ERROR Item 'HasWrongIsEmpty' has a '.len(_: &Self)' + fn len(self: &Self) -> isize { //~ERROR item `HasWrongIsEmpty` has a `.len(_: &Self)` 1 } @@ -69,7 +69,7 @@ impl HasWrongIsEmpty { #[deny(len_zero)] fn main() { let x = [1, 2]; - if x.len() == 0 { //~ERROR Consider replacing the len comparison + if x.len() == 0 { //~ERROR consider replacing the len comparison println!("This should not happen!"); } @@ -84,13 +84,13 @@ fn main() { } let hie = HasIsEmpty; - if hie.len() == 0 { //~ERROR Consider replacing the len comparison + if hie.len() == 0 { //~ERROR consider replacing the len comparison println!("Or this!"); } assert!(!hie.is_empty()); let wie : &WithIsEmpty = &Wither; - if wie.len() == 0 { //~ERROR Consider replacing the len comparison + if wie.len() == 0 { //~ERROR consider replacing the len comparison println!("Or this!"); } assert!(!wie.is_empty()); diff --git a/tests/compile-fail/match_if_let.rs b/tests/compile-fail/match_if_let.rs index 47b8b18a5ec..01bfe744713 100755 --- a/tests/compile-fail/match_if_let.rs +++ b/tests/compile-fail/match_if_let.rs @@ -5,8 +5,8 @@ fn main(){ let x = Some(1u8); - match x { //~ ERROR You seem to be trying to use match - //~^ HELP Try + match x { //~ ERROR you seem to be trying to use match + //~^ HELP try Some(y) => { println!("{:?}", y); } @@ -18,8 +18,8 @@ fn main(){ None => () } let z = (1u8,1u8); - match z { //~ ERROR You seem to be trying to use match - //~^ HELP Try + match z { //~ ERROR you seem to be trying to use match + //~^ HELP try (2...3, 7...9) => println!("{:?}", z), _ => {} } diff --git a/tests/compile-fail/modulo_one.rs b/tests/compile-fail/modulo_one.rs old mode 100644 new mode 100755 index 26c7de855e5..1301b4e499c --- a/tests/compile-fail/modulo_one.rs +++ b/tests/compile-fail/modulo_one.rs @@ -3,6 +3,6 @@ #![deny(modulo_one)] fn main() { - 10 % 1; //~ERROR Any number modulo 1 will be 0 + 10 % 1; //~ERROR any number modulo 1 will be 0 10 % 2; } diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs index 7ba291b1439..d56ea735a1d 100755 --- a/tests/compile-fail/ptr_arg.rs +++ b/tests/compile-fail/ptr_arg.rs @@ -3,7 +3,7 @@ #[deny(ptr_arg)] #[allow(unused)] -fn do_vec(x: &Vec<i64>) { //~ERROR: Writing '&Vec<_>' instead of '&[_]' +fn do_vec(x: &Vec<i64>) { //~ERROR: writing `&Vec<_>` instead of `&[_]` //Nothing here } diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs index a121b985f09..60edf2577e7 100755 --- a/tests/compile-fail/unicode.rs +++ b/tests/compile-fail/unicode.rs @@ -4,13 +4,13 @@ #[deny(zero_width_space)] fn zero() { print!("Here >​< is a ZWS, and ​another"); - //~^ ERROR Zero-width space detected. Consider using \u{200B} - //~^^ ERROR Zero-width space detected. Consider using \u{200B} + //~^ ERROR zero-width space detected. Consider using `\u{200B}` + //~^^ ERROR zero-width space detected. Consider using `\u{200B}` } //#[deny(unicode_canon)] fn canon() { - print!("̀ah?"); //not yet ~ERROR Non-canonical unicode sequence detected. Consider using à + print!("̀ah?"); //not yet ~ERROR non-canonical unicode sequence detected. Consider using à } //#[deny(ascii_only)] -- cgit 1.4.1-3-g733a5 From b831bd1d1d16c2733b2c26196163f68c74f3c271 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 10:53:14 +0200 Subject: len_zero: display full suggested expr in message --- src/len_zero.rs | 14 +++++++------- tests/compile-fail/len_zero.rs | 6 ++++++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index dea713180f5..298522ed24c 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -9,7 +9,7 @@ use rustc::middle::ty::{self, TypeVariants, TypeAndMut, MethodTraitItemId, ImplO use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; use syntax::ast::*; -use utils::{span_lint, walk_ptrs_ty}; +use utils::{span_lint, walk_ptrs_ty, snippet}; declare_lint!(pub LEN_ZERO, Warn, "Warn when .is_empty() could be used instead of checking .len()"); @@ -92,24 +92,24 @@ fn is_self_sig(sig: &MethodSig) -> bool { false } else { sig.decl.inputs.len() == 1 } } -fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, empty: &str) { +fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => - check_len_zero(cx, span, method, args, lit, empty), + check_len_zero(cx, span, method, args, lit, op), (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => - check_len_zero(cx, span, method, args, lit, empty), + check_len_zero(cx, span, method, args, lit, op), _ => () } } fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, - args: &[P<Expr>], lit: &Lit, empty: &str) { + args: &[P<Expr>], lit: &Lit, op: &str) { if let &Spanned{node: LitInt(0, _), ..} = lit { if method.node.name == "len" && args.len() == 1 && has_is_empty(cx, &*args[0]) { span_lint(cx, LEN_ZERO, span, &format!( - "consider replacing the len comparison with `{}_.is_empty()`", - empty)) + "consider replacing the len comparison with `{}{}.is_empty()`", + op, snippet(cx, args[0].span, "_"))) } } } diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 3785a518e2b..626e5557fb6 100755 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -87,6 +87,12 @@ fn main() { if hie.len() == 0 { //~ERROR consider replacing the len comparison println!("Or this!"); } + if hie.len() != 0 { //~ERROR consider replacing the len comparison + println!("Or this!"); + } + if hie.len() > 0 { //~ERROR consider replacing the len comparison + println!("Or this!"); + } assert!(!hie.is_empty()); let wie : &WithIsEmpty = &Wither; -- cgit 1.4.1-3-g733a5 From 7b3299e0094cdf407a3b745894a3949383c700f3 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 11:00:08 +0200 Subject: collapsible_if: do not show Debug display of expression Instead, pretty-print the inner block and use the same style as for the "single match => if let" lint. --- src/collapsible_if.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index f1c82f3eef8..c30acc02a4e 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -18,8 +18,8 @@ use rustc::middle::def::*; use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned, ExpnInfo}; -use syntax::print::pprust::expr_to_string; -use utils::{in_macro, span_lint}; +use syntax::print::pprust::{block_to_string, expr_to_string}; +use utils::{in_macro, span_help_and_lint}; declare_lint! { pub COLLAPSIBLE_IF, @@ -45,11 +45,13 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if in_macro(cx, info) { return; } if let ExprIf(ref check, ref then, None) = e.node { - if let Some(&Expr{ node: ExprIf(ref check_inner, _, None), ..}) = + if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), ..}) = single_stmt_of_block(then) { - span_lint(cx, COLLAPSIBLE_IF, e.span, &format!( - "this if statement can be collapsed. Try: `if {} && {}`\n{:?}", - check_to_string(check), check_to_string(check_inner), e)); + span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, + "this if statement can be collapsed", + &format!("try\nif {} && {} {}", + check_to_string(check), check_to_string(check_inner), + block_to_string(&*content))); } } } -- cgit 1.4.1-3-g733a5 From ca3b4330f1c033033ea876a1074168071239f81d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 12 Aug 2015 15:19:57 +0530 Subject: Use snippet, pprust methods expand AST --- src/collapsible_if.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index c30acc02a4e..0350db8163a 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -18,8 +18,7 @@ use rustc::middle::def::*; use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned, ExpnInfo}; -use syntax::print::pprust::{block_to_string, expr_to_string}; -use utils::{in_macro, span_help_and_lint}; +use utils::{in_macro, span_help_and_lint, snippet}; declare_lint! { pub COLLAPSIBLE_IF, @@ -50,8 +49,8 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", &format!("try\nif {} && {} {}", - check_to_string(check), check_to_string(check_inner), - block_to_string(&*content))); + check_to_string(cx, check), check_to_string(cx, check_inner), + snippet(cx, content.span, ".."))); } } } @@ -63,11 +62,11 @@ fn requires_brackets(e: &Expr) -> bool { } } -fn check_to_string(e: &Expr) -> String { +fn check_to_string(cx: &Context, e: &Expr) -> String { if requires_brackets(e) { - format!("({})", expr_to_string(e)) + format!("({})", snippet(cx, e.span, "..")) } else { - format!("{}", expr_to_string(e)) + format!("{}", snippet(cx, e.span, "..")) } } -- cgit 1.4.1-3-g733a5 From e8fed074cfd8623dfe070f86f0cc3040ac33b9b4 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 11:31:09 +0200 Subject: new lint: warn if let-binding has unit value (fixes #74) --- src/lib.rs | 2 ++ src/types.rs | 36 ++++++++++++++++++++++++++++++++++-- tests/compile-fail/let_unit.rs | 13 +++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100755 tests/compile-fail/let_unit.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index fef678f668d..27302b51bbd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box strings::StringAdd as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); + reg.register_lint_pass(box types::LetPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -83,5 +84,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, + types::LET_UNIT_VALUE, ]); } diff --git a/src/types.rs b/src/types.rs index b03829660dc..4980046e01b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,10 +1,11 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; +use rustc::middle::ty; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use syntax::codemap::Span; +use syntax::codemap::{ExpnInfo, Span}; -use utils::{span_lint, span_help_and_lint}; +use utils::{in_macro, snippet, span_lint, span_help_and_lint}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -75,3 +76,34 @@ impl LintPass for TypePass { } } } + +#[allow(missing_copy_implementations)] +pub struct LetPass; + +declare_lint!(pub LET_UNIT_VALUE, Warn, + "Warn on let-binding a value of unit type"); + + +fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { + if in_macro(cx, info) { return; } + if let DeclLocal(ref local) = decl.node { + let bindtype = &cx.tcx.pat_ty(&*local.pat).sty; + if *bindtype == ty::TyTuple(vec![]) { + span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( + "this let-binding has unit value. Consider omitting `let {} =`.", + snippet(cx, local.pat.span, ".."))); + } + } +} + +impl LintPass for LetPass { + fn get_lints(&self) -> LintArray { + lint_array!(LET_UNIT_VALUE) + } + + fn check_decl(&mut self, cx: &Context, decl: &Decl) { + cx.sess().codemap().with_expn_info( + decl.span.expn_id, + |info| check_let_unit(cx, decl, info)); + } +} diff --git a/tests/compile-fail/let_unit.rs b/tests/compile-fail/let_unit.rs new file mode 100755 index 00000000000..e8620f862a2 --- /dev/null +++ b/tests/compile-fail/let_unit.rs @@ -0,0 +1,13 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(let_unit_value)] + +fn main() { + let _x = println!("x"); //~ERROR this let-binding has unit value + let _y = 1; // this is fine + let _z = ((), 1); // this as well + if true { + let _a = (); //~ERROR + } +} -- cgit 1.4.1-3-g733a5 From 225969e8a3b8025dac6d577f6b23af85485be7d0 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 13:58:55 +0200 Subject: methods: move misc.StrToStringPass to MethodsPass --- src/lib.rs | 4 ++-- src/methods.rs | 12 ++++++++++-- src/misc.rs | 30 ------------------------------ 3 files changed, 12 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index fef678f668d..7b47edaa496 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,6 @@ pub mod returns; pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); reg.register_lint_pass(box misc::MiscPass as LintPassObject); - reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); reg.register_lint_pass(box misc::CmpNan as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); @@ -61,7 +60,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, - misc::SINGLE_MATCH, misc::STR_TO_STRING, + misc::SINGLE_MATCH, misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, @@ -83,5 +82,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, + methods::STR_TO_STRING, ]); } diff --git a/src/methods.rs b/src/methods.rs index 3d9aa8c6ffc..f02e0664092 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -11,16 +11,19 @@ declare_lint!(pub OPTION_UNWRAP_USED, Warn, "Warn on using unwrap() on an Option value"); declare_lint!(pub RESULT_UNWRAP_USED, Allow, "Warn on using unwrap() on a Result value"); +declare_lint!(pub STR_TO_STRING, Warn, + "Warn when a String could use to_owned() instead of to_string()"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED) + lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { + let ref obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty; if ident.node.name == "unwrap" { - if let ty::TyEnum(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { + if let ty::TyEnum(did, _) = *obj_ty { if match_def_path(cx, did.did, &["core", "option", "Option"]) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ @@ -34,6 +37,11 @@ impl LintPass for MethodsPass { } } } + else if ident.node.name == "to_string" { + if let ty::TyStr = *obj_ty { + span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); + } + } } } } diff --git a/src/misc.rs b/src/misc.rs index fa1847aad9a..d5e1efe2cc3 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -59,36 +59,6 @@ impl LintPass for MiscPass { } -declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()"); - -#[allow(missing_copy_implementations)] -pub struct StrToStringPass; - -impl LintPass for StrToStringPass { - fn get_lints(&self) -> LintArray { - lint_array!(STR_TO_STRING) - } - - fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) { - match expr.node { - ast::ExprMethodCall(ref method, _, ref args) - if method.node.name == "to_string" - && is_str(cx, &*args[0]) => { - span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); - }, - _ => () - } - - fn is_str(cx: &Context, expr: &ast::Expr) -> bool { - match walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { - ty::TyStr => true, - _ => false - } - } - } -} - - declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); #[allow(missing_copy_implementations)] -- cgit 1.4.1-3-g733a5 From 2d55381a9698694fe74438ff7ab28f9f99a45ecd Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 15:50:56 +0200 Subject: added string_add lint and fixed string_add_assign + test --- README.md | 1 + src/lib.rs | 1 + src/strings.rs | 47 +++++++++++++++++++++++++++++++++++++++---- tests/compile-fail/strings.rs | 13 ++++++++---- 4 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 0a947e12ecf..4644bac94cd 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Lints included in this crate: - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` - `zero_width_space`: Warns on encountering a unicode zero-width space - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. + - `string_add`: Matches `x + ..` where `x` is a `String` and where `string_add_assign` doesn't warn. Allowed by default. - `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice. - `let_and_return`: Warns on doing `let x = expr; x` at the end of a function. - `option_unwrap_used`: Warns when `Option.unwrap()` is used, and suggests `.expect()`. diff --git a/src/lib.rs b/src/lib.rs index 7b47edaa496..f2872a17b56 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); + reg.register_lint_pass(box strings::StringAddAssign as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); diff --git a/src/strings.rs b/src/strings.rs index 97016f36268..60ea23556ac 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -9,7 +9,7 @@ use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use eq_op::is_exp_equal; use types::match_ty_unwrap; -use utils::{match_def_path, span_lint, walk_ptrs_ty}; +use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { pub STRING_ADD_ASSIGN, @@ -17,10 +17,48 @@ declare_lint! { "Warn on `x = x + ..` where x is a `String`" } -#[derive(Copy,Clone)] +declare_lint! { + pub STRING_ADD, + Allow, + "Warn on `x + ..` where x is a `String`" +} + +#[derive(Copy, Clone)] pub struct StringAdd; impl LintPass for StringAdd { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_ADD) + } + + fn check_expr(&mut self, cx: &Context, e: &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) { + // the string_add_assign is allow, so no duplicates + } else { + let parent = get_parent_expr(cx, e); + if let Some(ref p) = parent { + if let &ExprAssign(ref target, _) = &p.node { + // avoid duplicate matches + if is_exp_equal(target, left) { return; } + } + } + } + //TODO check for duplicates + span_lint(cx, STRING_ADD, e.span, + "you add something to a string. \ + Consider using `String::push_str()` instead.") + } + } + } +} + + +#[derive(Copy, Clone)] +pub struct StringAddAssign; + +impl LintPass for StringAddAssign { fn get_lints(&self) -> LintArray { lint_array!(STRING_ADD_ASSIGN) } @@ -37,8 +75,9 @@ impl LintPass for StringAdd { } fn is_string(cx: &Context, e: &Expr) -> bool { - if let TyStruct(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(e)).sty { - match_def_path(cx, did.did, &["std", "string", "String"]) + let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + if let TyStruct(did, _) = ty.sty { + match_def_path(cx, did.did, &["collections", "string", "String"]) } else { false } } diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 4b6f0bc884f..e898a087d08 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -2,11 +2,16 @@ #![plugin(clippy)] #![deny(string_add_assign)] - +#![deny(string_add)] fn main() { - let x = "".to_owned(); + let mut x = "".to_owned(); - for i in (1..3) { - x = x + "."; //~ERROR + for _ in (1..3) { + x = x + "."; //~ERROR you assign the result of adding something to this string. } + + let y = "".to_owned(); + let z = y + "..."; //~ERROR you add something to a string. + + assert_eq!(&x, &z); } -- cgit 1.4.1-3-g733a5 From f0182ca6c809279843784d9669159157eedd2954 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 15:57:50 +0200 Subject: fixed formatting --- src/strings.rs | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index 60ea23556ac..47af63e6dea 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -18,9 +18,9 @@ declare_lint! { } declare_lint! { - pub STRING_ADD, - Allow, - "Warn on `x + ..` where x is a `String`" + pub STRING_ADD, + Allow, + "Warn on `x + ..` where x is a `String`" } #[derive(Copy, Clone)] @@ -32,26 +32,26 @@ impl LintPass for StringAdd { } fn check_expr(&mut self, cx: &Context, e: &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) { - // the string_add_assign is allow, so no duplicates - } else { - let parent = get_parent_expr(cx, e); - if let Some(ref p) = parent { - if let &ExprAssign(ref target, _) = &p.node { - // avoid duplicate matches - if is_exp_equal(target, left) { return; } - } - } - } - //TODO check for duplicates - span_lint(cx, STRING_ADD, e.span, - "you add something to a string. \ - Consider using `String::push_str()` instead.") - } - } - } + if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node { + if is_string(cx, left) { + if let Allow = cx.current_level(STRING_ADD_ASSIGN) { + // the string_add_assign is allow, so no duplicates + } else { + let parent = get_parent_expr(cx, e); + if let Some(ref p) = parent { + if let &ExprAssign(ref target, _) = &p.node { + // avoid duplicate matches + if is_exp_equal(target, left) { return; } + } + } + } + //TODO check for duplicates + span_lint(cx, STRING_ADD, e.span, + "you add something to a string. \ + Consider using `String::push_str()` instead.") + } + } + } } @@ -75,7 +75,7 @@ impl LintPass for StringAddAssign { } fn is_string(cx: &Context, e: &Expr) -> bool { - let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); if let TyStruct(did, _) = ty.sty { match_def_path(cx, did.did, &["collections", "string", "String"]) } else { false } -- cgit 1.4.1-3-g733a5 From e6e036ec20d2646c5682e4a7e18039b8925ce575 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 16:42:42 +0200 Subject: pulled strings passes together, added more tests --- src/lib.rs | 1 - src/strings.rs | 18 ++--------------- tests/compile-fail/strings.rs | 45 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f2872a17b56..7b47edaa496 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,6 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); - reg.register_lint_pass(box strings::StringAddAssign as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); diff --git a/src/strings.rs b/src/strings.rs index 47af63e6dea..aa0e8499f3e 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -28,7 +28,7 @@ pub struct StringAdd; impl LintPass for StringAdd { fn get_lints(&self) -> LintArray { - lint_array!(STRING_ADD) + lint_array!(STRING_ADD, STRING_ADD_ASSIGN) } fn check_expr(&mut self, cx: &Context, e: &Expr) { @@ -50,21 +50,7 @@ impl LintPass for StringAdd { "you add something to a string. \ Consider using `String::push_str()` instead.") } - } - } -} - - -#[derive(Copy, Clone)] -pub struct StringAddAssign; - -impl LintPass for StringAddAssign { - fn get_lints(&self) -> LintArray { - lint_array!(STRING_ADD_ASSIGN) - } - - fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let &ExprAssign(ref target, ref src) = &e.node { + } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assign the result of adding something to this string. \ diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index e898a087d08..02ebca2fe07 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -1,9 +1,37 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(string_add_assign)] -#![deny(string_add)] -fn main() { +#[deny(string_add)] +#[allow(string_add_assign)] +fn add_only() { // ignores assignment distinction + let mut x = "".to_owned(); + + for _ in (1..3) { + x = x + "."; //~ERROR you add something to a string. + } + + let y = "".to_owned(); + let z = y + "..."; //~ERROR you add something to a string. + + assert_eq!(&x, &z); +} + +#[deny(string_add_assign)] +fn add_assign_only() { + let mut x = "".to_owned(); + + for _ in (1..3) { + x = x + "."; //~ERROR you assign the result of adding something to this string. + } + + let y = "".to_owned(); + let z = y + "..."; + + assert_eq!(&x, &z); +} + +#[deny(string_add, string_add_assign)] +fn both() { let mut x = "".to_owned(); for _ in (1..3) { @@ -15,3 +43,14 @@ fn main() { assert_eq!(&x, &z); } + +fn main() { + add_only(); + add_assign_only(); + both(); + + // the add is only caught for String + let mut x = 1; + x = x + 1; + assert_eq!(2, x); +} -- cgit 1.4.1-3-g733a5 From 801f01d0012d48873050c27cf9876b3fc56509c5 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 16:50:43 +0200 Subject: added `string_add` to `clippy` lint group --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 7b47edaa496..46cc85e8559 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, strings::STRING_ADD_ASSIGN, + strings::STRING_ADD, returns::NEEDLESS_RETURN, misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, -- cgit 1.4.1-3-g733a5 From 4074c1f968d5bd37b3dec36bc21cbf656de65907 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 17:02:49 +0200 Subject: methods: lint against String.to_string (fixes #100) --- src/lib.rs | 1 + src/methods.rs | 10 +++++++++- tests/compile-fail/methods.rs | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 7b47edaa496..3299debbe0d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,5 +83,6 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::STR_TO_STRING, + methods::STRING_TO_STRING, ]); } diff --git a/src/methods.rs b/src/methods.rs index f02e0664092..a5b12e52bdf 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -13,10 +13,12 @@ declare_lint!(pub RESULT_UNWRAP_USED, Allow, "Warn on using unwrap() on a Result value"); declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()"); +declare_lint!(pub STRING_TO_STRING, Warn, + "Warn when calling String.to_string()"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING) + lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -41,6 +43,12 @@ impl LintPass for MethodsPass { if let ty::TyStr = *obj_ty { span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); } + else if let ty::TyStruct(did, _) = *obj_ty { + if match_def_path(cx, did.did, &["collections", "string", "String"]) { + span_lint(cx, STRING_TO_STRING, expr.span, + "`String.to_string()` is a no-op") + } + } } } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index e989dffe5a7..facf0378392 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -2,10 +2,14 @@ #![plugin(clippy)] #[deny(option_unwrap_used, result_unwrap_used)] +#[deny(str_to_string, string_to_string)] fn main() { let opt = Some(0); let _ = opt.unwrap(); //~ERROR let res: Result<i32, ()> = Ok(0); let _ = res.unwrap(); //~ERROR + + let string = "str".to_string(); //~ERROR + let _again = string.to_string(); //~ERROR } -- cgit 1.4.1-3-g733a5 From 3044d3d6333f92a9958b64420d9893403d4aea97 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 20:36:10 +0200 Subject: unicode: add lint against non-ascii chars in literals (Allow by default), #85 --- src/lib.rs | 1 + src/unicode.rs | 28 +++++++++++++--------------- tests/compile-fail/unicode.rs | 8 ++++---- 3 files changed, 18 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a7ed0320da8..7d7eff35545 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ pub fn plugin_registrar(reg: &mut Registry) { attrs::INLINE_ALWAYS, collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, + unicode::NON_ASCII_LITERAL, strings::STRING_ADD_ASSIGN, returns::NEEDLESS_RETURN, misc::MODULO_ONE, diff --git a/src/unicode.rs b/src/unicode.rs index af48c9b99ad..ca6abaf01b4 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -4,13 +4,14 @@ use syntax::codemap::{BytePos, Span}; use utils::span_lint; declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" } +declare_lint!{ pub NON_ASCII_LITERAL, Allow, "Lint literal non-ASCII chars in literals" } #[derive(Copy, Clone)] pub struct Unicode; impl LintPass for Unicode { fn get_lints(&self) -> LintArray { - lint_array!(ZERO_WIDTH_SPACE) + lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -23,24 +24,21 @@ impl LintPass for Unicode { } fn check_str(cx: &Context, string: &str, span: Span) { - let mut start: Option<usize> = None; for (i, c) in string.char_indices() { if c == '\u{200B}' { - if start.is_none() { start = Some(i); } - } else { - lint_zero_width(cx, span, start); - start = None; + str_pos_lint(cx, ZERO_WIDTH_SPACE, span, i, + "zero-width space detected. Consider using `\\u{200B}`."); + } + if c as u32 > 0x7F { + str_pos_lint(cx, NON_ASCII_LITERAL, span, i, &format!( + "literal non-ASCII character detected. Consider using `\\u{{{:X}}}`.", c as u32)); } } - lint_zero_width(cx, span, start); } -fn lint_zero_width(cx: &Context, span: Span, start: Option<usize>) { - start.map(|index| { - span_lint(cx, ZERO_WIDTH_SPACE, Span { - lo: span.lo + BytePos(index as u32), - hi: span.lo + BytePos(index as u32), - expn_id: span.expn_id, - }, "zero-width space detected. Consider using `\\u{200B}`.") - }); +fn str_pos_lint(cx: &Context, lint: &'static Lint, span: Span, index: usize, msg: &str) { + span_lint(cx, lint, Span { lo: span.lo + BytePos((1 + index) as u32), + hi: span.lo + BytePos((1 + index) as u32), + expn_id: span.expn_id }, msg); + } diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs index 60edf2577e7..e4730f60de8 100755 --- a/tests/compile-fail/unicode.rs +++ b/tests/compile-fail/unicode.rs @@ -4,8 +4,8 @@ #[deny(zero_width_space)] fn zero() { print!("Here >​< is a ZWS, and ​another"); - //~^ ERROR zero-width space detected. Consider using `\u{200B}` - //~^^ ERROR zero-width space detected. Consider using `\u{200B}` + //~^ ERROR zero-width space detected. Consider using `\u{200B}` + //~^^ ERROR zero-width space detected. Consider using `\u{200B}` } //#[deny(unicode_canon)] @@ -13,9 +13,9 @@ fn canon() { print!("̀ah?"); //not yet ~ERROR non-canonical unicode sequence detected. Consider using à } -//#[deny(ascii_only)] +#[deny(non_ascii_literal)] fn uni() { - println!("Üben!"); //not yet ~ERROR Unicode literal detected. Consider using \u{FC} + print!("Üben!"); //~ERROR literal non-ASCII character detected. Consider using `\u{DC}` } fn main() { -- cgit 1.4.1-3-g733a5 From 30a6764adb44ac93b389128aa10089546c3c65c1 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 21:17:21 +0200 Subject: grammar --- src/strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index aa0e8499f3e..33db980c065 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -47,13 +47,13 @@ impl LintPass for StringAdd { } //TODO check for duplicates span_lint(cx, STRING_ADD, e.span, - "you add something to a string. \ + "you added something to a string. \ Consider using `String::push_str()` instead.") } } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, - "you assign the result of adding something to this string. \ + "you assigned the result of adding something to this string. \ Consider using `String::push_str()` instead.") } } -- cgit 1.4.1-3-g733a5 From 4400aaed4363e7955f4d45770c4add7b147c1022 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 21:11:32 +0200 Subject: if_let_chain: allow mixing in normal ifs as well --- src/returns.rs | 19 +++++++++---------- src/utils.rs | 31 ++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/returns.rs b/src/returns.rs index 70af37d5181..be28e14001c 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -69,17 +69,16 @@ impl ReturnPass { // we need both a let-binding stmt and an expr if_let_chain! { [ - Some(stmt) = block.stmts.last(), - StmtDecl(ref decl, _) = stmt.node, - DeclLocal(ref local) = decl.node, - Some(ref initexpr) = local.init, - PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, - Some(ref retexpr) = block.expr, - ExprPath(_, ref path) = retexpr.node + let Some(stmt) = block.stmts.last(), + let StmtDecl(ref decl, _) = stmt.node, + let DeclLocal(ref local) = decl.node, + let Some(ref initexpr) = local.init, + let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, + let Some(ref retexpr) = block.expr, + let ExprPath(_, ref path) = retexpr.node, + match_path(path, &[&*id.name.as_str()]) ], { - if match_path(path, &[&*id.name.as_str()]) { - self.emit_let_lint(cx, retexpr.span, initexpr.span); - } + self.emit_let_lint(cx, retexpr.span, initexpr.span); } } } diff --git a/src/utils.rs b/src/utils.rs index 575d39b0c23..220dc6215fd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -93,9 +93,14 @@ pub fn walk_ptrs_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { } } -/// Produce a nested chain of if-lets from the patterns: +/// Produce a nested chain of if-lets and ifs from the patterns: /// -/// if_let_chain! {[Some(y) = x, Some(z) = y], +/// if_let_chain! { +/// [ +/// Some(y) = x, +/// y.len() == 2, +/// Some(z) = y, +/// ], /// { /// block /// } @@ -104,20 +109,32 @@ pub fn walk_ptrs_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { /// becomes /// /// if let Some(y) = x { -/// if let Some(z) = y { -/// block +/// if y.len() == 2 { +/// if let Some(z) = y { +/// block +/// } /// } /// } #[macro_export] macro_rules! if_let_chain { - ([$pat:pat = $expr:expr, $($p2:pat = $e2:expr),+], $block:block) => { + ([let $pat:pat = $expr:expr, $($tt:tt)+], $block:block) => { if let $pat = $expr { - if_let_chain!{ [$($p2 = $e2),+], $block } + if_let_chain!{ [$($tt)+], $block } } }; - ([$pat:pat = $expr:expr], $block:block) => { + ([let $pat:pat = $expr:expr], $block:block) => { if let $pat = $expr { $block } }; + ([$expr:expr, $($tt:tt)+], $block:block) => { + if $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([$expr:expr], $block:block) => { + if $expr { + $block + } + }; } -- cgit 1.4.1-3-g733a5 From f6090909d3e7654b9244fff937d78e3e17b5f3e2 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 21:56:27 +0200 Subject: new lint: using `for i in 0..x { .. vec[i] .. }` instead of iterator (fixes #3) --- src/lib.rs | 3 ++ src/loops.rs | 105 +++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/for_loop.rs | 17 +++++++ 3 files changed, 125 insertions(+) create mode 100644 src/loops.rs create mode 100755 tests/compile-fail/for_loop.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 7d7eff35545..33ce163a326 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod unicode; pub mod strings; pub mod methods; pub mod returns; +pub mod loops; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -59,6 +60,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); + reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, @@ -87,5 +89,6 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::STR_TO_STRING, methods::STRING_TO_STRING, types::LET_UNIT_VALUE, + loops::NEEDLESS_RANGE_LOOP, ]); } diff --git a/src/loops.rs b/src/loops.rs new file mode 100644 index 00000000000..83d7ca4eccb --- /dev/null +++ b/src/loops.rs @@ -0,0 +1,105 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::visit::{Visitor, walk_expr}; +use std::collections::HashSet; + +use utils::{span_lint, get_parent_expr}; + +declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, + "Warn about looping over a range of indices if a normal iterator would do" } + +#[derive(Copy, Clone)] +pub struct LoopsPass; + +impl LintPass for LoopsPass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RANGE_LOOP) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let Some((pat, arg, body)) = recover_for_loop(expr) { + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { + // the iteratee must be a range literal + if let ExprRange(_, _) = arg.node { + let mut visitor = VarVisitor { cx: cx, var: ident.node.name, + indexed: HashSet::new(), nonindex: false }; + walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable + if visitor.indexed.len() == 1 { + let indexed = visitor.indexed.into_iter().next().unwrap(); + if visitor.nonindex { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is used to index `{}`. Consider using \ + `for ({}, item) in {}.iter().enumerate()` or similar iterators.", + ident.node.name.as_str(), indexed.as_str(), + ident.node.name.as_str(), indexed.as_str())); + } else { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in &{}` or similar iterators.", + ident.node.name.as_str(), indexed.as_str(), indexed.as_str())); + } + } + } + } + } + } +} + +/// Recover the essential nodes of a desugared for loop: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. +fn recover_for_loop<'a>(expr: &'a Expr) -> Option<(&'a Pat, &'a Expr, &'a Expr)> { + if_let_chain! { + [ + let ExprMatch(ref iterexpr, ref arms, _) = expr.node, + let ExprCall(_, ref iterargs) = iterexpr.node, + iterargs.len() == 1, + arms.len() == 1 && arms[0].guard.is_none(), + let ExprLoop(ref block, _) = arms[0].body.node, + block.stmts.is_empty(), + let Some(ref loopexpr) = block.expr, + let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, + innerarms.len() == 2 && innerarms[0].pats.len() == 1, + let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node, + somepats.len() == 1 + ], { + return Some((&*somepats[0], + &*iterargs[0], + &*innerarms[0].body)); + } + } + None +} + +struct VarVisitor<'v, 't: 'v> { + cx: &'v Context<'v, 't>, // context reference + var: Name, // var name to look for as index + indexed: HashSet<Name>, // indexed variables + 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 && path.segments[0].identifier.name == 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 + ], { + self.indexed.insert(seqvar.segments[0].identifier.name); + return; // no need to walk further + } + } + // we are not indexing anything, record that + self.nonindex = true; + return; + } + } + walk_expr(self, expr); + } +} diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs new file mode 100755 index 00000000000..318e6fc8588 --- /dev/null +++ b/tests/compile-fail/for_loop.rs @@ -0,0 +1,17 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(needless_range_loop)] +fn main() { + let vec = vec![1, 2, 3, 4]; + let vec2 = vec![1, 2, 3, 4]; + for i in 0..vec.len() { //~ERROR the loop variable `i` is only used to index `vec`. + println!("{}", vec[i]); + } + for i in 0..vec.len() { //~ERROR the loop variable `i` is used to index `vec`. + println!("{} {}", vec[i], i); + } + for i in 0..vec.len() { // not an error, indexing more than one variable + println!("{} {}", vec[i], vec2[i]); + } +} -- cgit 1.4.1-3-g733a5 From b349f9e88dfd5269af69ef3096dabb71742a9737 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 13:16:09 +0200 Subject: new lint for needless lifetimes (fixes #115) --- src/lib.rs | 3 + src/lifetimes.rs | 126 ++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/lifetimes.rs | 62 ++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 src/lifetimes.rs create mode 100755 tests/compile-fail/lifetimes.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 7d7eff35545..69a373b21bb 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod unicode; pub mod strings; pub mod methods; pub mod returns; +pub mod lifetimes; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -59,6 +60,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); + reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, @@ -87,5 +89,6 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::STR_TO_STRING, methods::STRING_TO_STRING, types::LET_UNIT_VALUE, + lifetimes::NEEDLESS_LIFETIMES, ]); } diff --git a/src/lifetimes.rs b/src/lifetimes.rs new file mode 100644 index 00000000000..602eea1ae5e --- /dev/null +++ b/src/lifetimes.rs @@ -0,0 +1,126 @@ +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray, Lint}; +use syntax::codemap::Span; +use syntax::visit::{Visitor, FnKind, walk_ty}; +use utils::{in_macro, span_lint}; +use std::collections::HashSet; +use std::iter::FromIterator; + +declare_lint!(pub NEEDLESS_LIFETIMES, Warn, + "Warn on explicit lifetimes when elision rules would apply"); + +#[derive(Copy,Clone)] +pub struct LifetimePass; + +impl LintPass for LifetimePass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_LIFETIMES) + } + + fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, + _: &Block, span: Span, _: NodeId) { + if cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro(cx, info)) { + return; + } + if could_use_elision(kind, decl) { + span_lint(cx, NEEDLESS_LIFETIMES, span, + "explicit lifetimes given where they could be inferred"); + } + } +} + +#[derive(PartialEq, Eq, Hash, Debug)] +enum RefLt { + Unnamed, + Static, + Named(Name), +} +use self::RefLt::*; + +fn could_use_elision(kind: FnKind, func: &FnDecl) -> 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 + + let mut input_visitor = RefVisitor(Vec::new()); + let mut output_visitor = RefVisitor(Vec::new()); + + // extract lifetimes of input argument types + for arg in &func.inputs { + walk_ty(&mut input_visitor, &*arg.ty); + } + // extract lifetime of "self" argument for methods + if let FnKind::FkMethod(_, sig, _) = kind { + match sig.explicit_self.node { + SelfRegion(ref lt_opt, _, _) => + input_visitor.visit_opt_lifetime_ref(sig.explicit_self.span, lt_opt), + SelfExplicit(ref ty, _) => + walk_ty(&mut input_visitor, ty), + _ => { } + } + } + // extract lifetimes of output type + if let Return(ref ty) = func.output { + walk_ty(&mut output_visitor, ty); + } + + let input_lts = input_visitor.into_vec(); + let output_lts = output_visitor.into_vec(); + + // no input lifetimes? easy case! + if input_lts.is_empty() { + return false; + } else if output_lts.is_empty() { + // no output lifetimes, check distinctness of input lifetimes + + // only one reference with unnamed lifetime, ok + if input_lts.len() == 1 && input_lts[0] == Unnamed { + return false; + } + // we have no output reference, so we only need all distinct lifetimes + if input_lts.len() == unique_lifetimes(&input_lts) { + return true; + } + } else { + // we have output references, so we need one input reference, + // and all output lifetimes must be the same + if unique_lifetimes(&output_lts) > 1 { + return false; + } + if input_lts.len() == 1 { + match (&input_lts[0], &output_lts[0]) { + (&Named(n1), &Named(n2)) if n1 == n2 => { return true; } + (&Named(_), &Unnamed) => { return true; } + (&Unnamed, &Named(_)) => { return true; } + _ => { } // already elided, different named lifetimes + // or something static going on + } + } + } + false +} + +fn unique_lifetimes(lts: &Vec<RefLt>) -> usize { + let set: HashSet<&RefLt> = HashSet::from_iter(lts.iter()); + set.len() +} + +struct RefVisitor(Vec<RefLt>); + +impl RefVisitor { + fn into_vec(self) -> Vec<RefLt> { self.0 } +} + +impl<'v> Visitor<'v> for RefVisitor { + fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { + if let &Some(ref lt) = lifetime { + if lt.name.as_str() == "'static" { + self.0.push(Static); + } else { + self.0.push(Named(lt.name)); + } + } else { + self.0.push(Unnamed); + } + } +} diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs new file mode 100755 index 00000000000..9f2a3ee99af --- /dev/null +++ b/tests/compile-fail/lifetimes.rs @@ -0,0 +1,62 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(needless_lifetimes)] + +fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } //~ERROR + +fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { } //~ERROR + +fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same lifetime on two params + +fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved + +fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x } //~ERROR + +fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x } // no error, multiple input refs + +fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } // no error, multiple input refs + +fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x } // no error, static involved + +fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error + +fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // no error, two input refs + +fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } //~ERROR + +struct X { + x: u8, +} + +impl X { + fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x } //~ERROR + + fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs + + fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { } //~ERROR + + fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params +} + +static STATIC: u8 = 1; + +fn main() { + distinct_lifetimes(&1, &2, 3); + distinct_and_static(&1, &2, &STATIC); + same_lifetime_on_input(&1, &2); + only_static_on_input(&1, &2, &STATIC); + in_and_out(&1, 2); + multiple_in_and_out_1(&1, &2); + multiple_in_and_out_2(&1, &2); + in_static_and_out(&1, &STATIC); + let _ = deep_reference_1(&1, &2); + let _ = deep_reference_2(Ok(&1)); + let _ = deep_reference_3(&1, 2); + + let foo = X { x: 1 }; + foo.self_and_out(); + foo.self_and_in_out(&1); + foo.distinct_self_and_in(&1); + foo.self_and_same_in(&1); +} -- cgit 1.4.1-3-g733a5 From 6603299f3f9f7fccde7dacbfd93e3cedd7e30e75 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 12 Aug 2015 20:13:14 +0200 Subject: lifetimes lint: straighten some code, add a few comments --- src/lifetimes.rs | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 602eea1ae5e..83f6d0eecdb 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -2,7 +2,7 @@ use syntax::ast::*; use rustc::lint::{Context, LintPass, LintArray, Lint}; use syntax::codemap::Span; use syntax::visit::{Visitor, FnKind, walk_ty}; -use utils::{in_macro, span_lint}; +use utils::{in_external_macro, span_lint}; use std::collections::HashSet; use std::iter::FromIterator; @@ -19,16 +19,17 @@ impl LintPass for LifetimePass { fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, _: &Block, span: Span, _: NodeId) { - if cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro(cx, info)) { + if in_external_macro(cx, span) { return; } if could_use_elision(kind, decl) { span_lint(cx, NEEDLESS_LIFETIMES, span, - "explicit lifetimes given where they could be inferred"); + "explicit lifetimes given in parameter types where they could be elided"); } } } +/// The lifetime of a &-reference. #[derive(PartialEq, Eq, Hash, Debug)] enum RefLt { Unnamed, @@ -42,24 +43,24 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { // * no output references, all input references have different LT // * output references, exactly one input reference with same LT + // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor(Vec::new()); let mut output_visitor = RefVisitor(Vec::new()); - // extract lifetimes of input argument types - for arg in &func.inputs { - walk_ty(&mut input_visitor, &*arg.ty); - } - // extract lifetime of "self" argument for methods + // extract lifetime in "self" argument for methods (there is a "self" argument + // in func.inputs, but its type is TyInfer) if let FnKind::FkMethod(_, sig, _) = kind { match sig.explicit_self.node { - SelfRegion(ref lt_opt, _, _) => - input_visitor.visit_opt_lifetime_ref(sig.explicit_self.span, lt_opt), - SelfExplicit(ref ty, _) => - walk_ty(&mut input_visitor, ty), + SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt), + SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty), _ => { } } } - // extract lifetimes of output type + // extract lifetimes in input argument types + for arg in &func.inputs { + walk_ty(&mut input_visitor, &*arg.ty); + } + // extract lifetimes in output type if let Return(ref ty) = func.output { walk_ty(&mut output_visitor, ty); } @@ -100,19 +101,16 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { false } +/// Number of unique lifetimes in the given vector. fn unique_lifetimes(lts: &Vec<RefLt>) -> usize { - let set: HashSet<&RefLt> = HashSet::from_iter(lts.iter()); - set.len() + lts.iter().collect::<HashSet<_>>().len() } +/// A visitor usable for syntax::visit::walk_ty(). struct RefVisitor(Vec<RefLt>); impl RefVisitor { - fn into_vec(self) -> Vec<RefLt> { self.0 } -} - -impl<'v> Visitor<'v> for RefVisitor { - fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { + fn record(&mut self, lifetime: &Option<Lifetime>) { if let &Some(ref lt) = lifetime { if lt.name.as_str() == "'static" { self.0.push(Static); @@ -123,4 +121,14 @@ impl<'v> Visitor<'v> for RefVisitor { self.0.push(Unnamed); } } + + fn into_vec(self) -> Vec<RefLt> { + self.0 + } +} + +impl<'v> Visitor<'v> for RefVisitor { + fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { + self.record(lifetime); + } } -- cgit 1.4.1-3-g733a5 From 2f7693094f5c112174ae5e3aa7e9525bb35ac469 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 06:43:25 +0200 Subject: lifetimes lint: include support for lifetimes as generic params --- src/lifetimes.rs | 9 +++++++++ tests/compile-fail/lifetimes.rs | 8 ++++++++ 2 files changed, 17 insertions(+) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 83f6d0eecdb..b510173e753 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -128,7 +128,16 @@ impl RefVisitor { } impl<'v> Visitor<'v> for RefVisitor { + // for lifetimes of references fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { self.record(lifetime); } + + // for lifetimes as parameters of generics + fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + self.record(&Some(*lifetime)); + } + + // for lifetime bounds; the default impl calls visit_lifetime_ref + fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { } } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 9f2a3ee99af..0f0f95ac5f5 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -25,6 +25,12 @@ fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // n fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } //~ERROR +type Ref<'r> = &'r u8; + +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } + +fn lifetime_param_2<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } //~ERROR + struct X { x: u8, } @@ -53,6 +59,8 @@ fn main() { let _ = deep_reference_1(&1, &2); let _ = deep_reference_2(Ok(&1)); let _ = deep_reference_3(&1, 2); + lifetime_param_1(&1, &2); + lifetime_param_2(&1, &2); let foo = X { x: 1 }; foo.self_and_out(); -- cgit 1.4.1-3-g733a5 From 7aee04878f5228f15d94b04addadfa9fe5ccc307 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 08:12:07 +0200 Subject: tests: use fragment of lint text for error checking (Did not touch strings.rs, which is fixed by @llogiq's PR) --- src/needless_bool.rs | 2 +- tests/compile-fail/approx_const.rs | 46 +++++++++++++++++------------------ tests/compile-fail/bit_masks.rs | 28 ++++++++++----------- tests/compile-fail/cmp_nan.rs | 24 +++++++++--------- tests/compile-fail/eq_op.rs | 32 ++++++++++++------------ tests/compile-fail/float_cmp.rs | 16 ++++++------ tests/compile-fail/identity_op.rs | 20 +++++++-------- tests/compile-fail/let_return.rs | 2 +- tests/compile-fail/let_unit.rs | 2 +- tests/compile-fail/methods.rs | 8 +++--- tests/compile-fail/mut_mut.rs | 16 ++++++------ tests/compile-fail/needless_bool.rs | 8 +++--- tests/compile-fail/needless_return.rs | 14 +++++------ tests/compile-fail/precedence.rs | 14 +++++------ tests/compile-fail/ptr_arg.rs | 4 +-- 15 files changed, 118 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/needless_bool.rs b/src/needless_bool.rs index fcbc287e30f..d97e819077a 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -37,7 +37,7 @@ impl LintPass for NeedlessBool { "you can reduce your if statement to its predicate"); }, (Option::Some(false), Option::Some(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if statement to `!` + your predicate"); }, + "you can reduce your if statement to `!` + its predicate"); }, (Option::Some(false), Option::Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, "your if-then-else expression will always return false"); }, diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index 3eb170b295b..799795becbd 100755 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -4,53 +4,53 @@ #[deny(approx_constant)] #[allow(unused)] fn main() { - let my_e = 2.7182; //~ERROR - let almost_e = 2.718; //~ERROR + let my_e = 2.7182; //~ERROR approximate value of `f{32, 64}::E` found + let almost_e = 2.718; //~ERROR approximate value of `f{32, 64}::E` found let no_e = 2.71; - let my_1_frac_pi = 0.3183; //~ERROR + let my_1_frac_pi = 0.3183; //~ERROR approximate value of `f{32, 64}::FRAC_1_PI` found let no_1_frac_pi = 0.31; - let my_frac_1_sqrt_2 = 0.70710678; //~ERROR - let almost_frac_1_sqrt_2 = 0.70711; //~ERROR + let my_frac_1_sqrt_2 = 0.70710678; //~ERROR approximate value of `f{32, 64}::FRAC_1_SQRT_2` found + let almost_frac_1_sqrt_2 = 0.70711; //~ERROR approximate value of `f{32, 64}::FRAC_1_SQRT_2` found let my_frac_1_sqrt_2 = 0.707; - let my_frac_2_pi = 0.63661977; //~ERROR + let my_frac_2_pi = 0.63661977; //~ERROR approximate value of `f{32, 64}::FRAC_2_PI` found let no_frac_2_pi = 0.636; - let my_frac_2_sq_pi = 1.128379; //~ERROR + let my_frac_2_sq_pi = 1.128379; //~ERROR approximate value of `f{32, 64}::FRAC_2_SQRT_PI` found let no_frac_2_sq_pi = 1.128; - let my_frac_2_pi = 1.57079632679; //~ERROR - let no_frac_2_pi = 1.5705; + let my_frac_pi_2 = 1.57079632679; //~ERROR approximate value of `f{32, 64}::FRAC_PI_2` found + let no_frac_pi_2 = 1.5705; - let my_frac_3_pi = 1.04719755119; //~ERROR - let no_frac_3_pi = 1.047; + let my_frac_pi_3 = 1.04719755119; //~ERROR approximate value of `f{32, 64}::FRAC_PI_3` found + let no_frac_pi_3 = 1.047; - let my_frac_4_pi = 0.785398163397; //~ERROR - let no_frac_4_pi = 0.785; + let my_frac_pi_4 = 0.785398163397; //~ERROR approximate value of `f{32, 64}::FRAC_PI_4` found + let no_frac_pi_4 = 0.785; - let my_frac_6_pi = 0.523598775598; //~ERROR - let no_frac_6_pi = 0.523; + let my_frac_pi_6 = 0.523598775598; //~ERROR approximate value of `f{32, 64}::FRAC_PI_6` found + let no_frac_pi_6 = 0.523; - let my_frac_8_pi = 0.3926990816987; //~ERROR - let no_frac_8_pi = 0.392; + let my_frac_pi_8 = 0.3926990816987; //~ERROR approximate value of `f{32, 64}::FRAC_PI_8` found + let no_frac_pi_8 = 0.392; - let my_ln_10 = 2.302585092994046; //~ERROR + let my_ln_10 = 2.302585092994046; //~ERROR approximate value of `f{32, 64}::LN_10` found let no_ln_10 = 2.303; - let my_ln_2 = 0.6931471805599453; //~ERROR + let my_ln_2 = 0.6931471805599453; //~ERROR approximate value of `f{32, 64}::LN_2` found let no_ln_2 = 0.693; - let my_log10_e = 0.43429448190325176; //~ERROR + let my_log10_e = 0.43429448190325176; //~ERROR approximate value of `f{32, 64}::LOG10_E` found let no_log10_e = 0.434; - let my_log2_e = 1.4426950408889634; //~ERROR + let my_log2_e = 1.4426950408889634; //~ERROR approximate value of `f{32, 64}::LOG2_E` found let no_log2_e = 1.442; - let my_pi = 3.1415; //~ERROR + let my_pi = 3.1415; //~ERROR approximate value of `f{32, 64}::PI` found let almost_pi = 3.141; - let my_sq2 = 1.4142; //~ERROR + let my_sq2 = 1.4142; //~ERROR approximate value of `f{32, 64}::SQRT_2` found let no_sq2 = 1.414; } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index c2a82483005..bcbfe99e42e 100755 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -12,30 +12,30 @@ fn main() { x & 0 == 0; //~ERROR &-masking with zero x & 1 == 1; //ok, distinguishes bit 0 x & 1 == 0; //ok, compared with zero - x & 2 == 1; //~ERROR + x & 2 == 1; //~ERROR incompatible bit mask x | 0 == 0; //ok, equals x == 0 (maybe warn?) x | 1 == 3; //ok, equals x == 2 || x == 3 x | 3 == 3; //ok, equals x <= 3 - x | 3 == 2; //~ERROR + x | 3 == 2; //~ERROR incompatible bit mask - x & 1 > 1; //~ERROR + x & 1 > 1; //~ERROR incompatible bit mask x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 x | 1 > 1; // ok (if a bit silly), equals x > 1 - x | 2 > 1; //~ERROR + x | 2 > 1; //~ERROR incompatible bit mask x | 2 <= 2; // ok (if a bit silly), equals x <= 2 // this also now works with constants - x & THREE_BITS == 8; //~ERROR - x | EVEN_MORE_REDIRECTION < 7; //~ERROR + x & THREE_BITS == 8; //~ERROR incompatible bit mask + x | EVEN_MORE_REDIRECTION < 7; //~ERROR incompatible bit mask - 0 & x == 0; //~ERROR + 0 & x == 0; //~ERROR &-masking with zero 1 | x > 1; // and should now also match uncommon usage - 1 < 2 | x; //~ERROR - 2 == 3 | x; //~ERROR - 1 == x & 2; //~ERROR + 1 < 2 | x; //~ERROR incompatible bit mask + 2 == 3 | x; //~ERROR incompatible bit mask + 1 == x & 2; //~ERROR incompatible bit mask x | 1 > 2; // no error, because we allowed ineffective bit masks ineffective(); @@ -46,8 +46,8 @@ fn main() { fn ineffective() { let x = 5; - x | 1 > 2; //~ERROR - x | 1 < 3; //~ERROR - x | 1 <= 3; //~ERROR - x | 1 >= 2; //~ERROR + x | 1 > 2; //~ERROR ineffective bit mask + x | 1 < 3; //~ERROR ineffective bit mask + x | 1 <= 3; //~ERROR ineffective bit mask + x | 1 >= 2; //~ERROR ineffective bit mask } diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs index b6549c2c1fb..b2369e164ff 100755 --- a/tests/compile-fail/cmp_nan.rs +++ b/tests/compile-fail/cmp_nan.rs @@ -5,18 +5,18 @@ #[allow(float_cmp)] fn main() { let x = 5f32; - x == std::f32::NAN; //~ERROR - x != std::f32::NAN; //~ERROR - x < std::f32::NAN; //~ERROR - x > std::f32::NAN; //~ERROR - x <= std::f32::NAN; //~ERROR - x >= std::f32::NAN; //~ERROR + x == std::f32::NAN; //~ERROR doomed comparison with NAN + x != std::f32::NAN; //~ERROR doomed comparison with NAN + x < std::f32::NAN; //~ERROR doomed comparison with NAN + x > std::f32::NAN; //~ERROR doomed comparison with NAN + x <= std::f32::NAN; //~ERROR doomed comparison with NAN + x >= std::f32::NAN; //~ERROR doomed comparison with NAN let y = 0f64; - y == std::f64::NAN; //~ERROR - y != std::f64::NAN; //~ERROR - y < std::f64::NAN; //~ERROR - y > std::f64::NAN; //~ERROR - y <= std::f64::NAN; //~ERROR - y >= std::f64::NAN; //~ERROR + y == std::f64::NAN; //~ERROR doomed comparison with NAN + y != std::f64::NAN; //~ERROR doomed comparison with NAN + y < std::f64::NAN; //~ERROR doomed comparison with NAN + y > std::f64::NAN; //~ERROR doomed comparison with NAN + y <= std::f64::NAN; //~ERROR doomed comparison with NAN + y >= std::f64::NAN; //~ERROR doomed comparison with NAN } diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 45fce0c0bb3..298132013a9 100755 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -9,29 +9,29 @@ fn id<X>(x: X) -> X { #[allow(identity_op)] fn main() { // simple values and comparisons - 1 == 1; //~ERROR - "no" == "no"; //~ERROR + 1 == 1; //~ERROR equal expressions + "no" == "no"; //~ERROR equal expressions // even though I agree that no means no ;-) - false != false; //~ERROR - 1.5 < 1.5; //~ERROR - 1u64 >= 1u64; //~ERROR + false != false; //~ERROR equal expressions + 1.5 < 1.5; //~ERROR equal expressions + 1u64 >= 1u64; //~ERROR equal expressions // casts, methods, parenthesis - (1 as u64) & (1 as u64); //~ERROR - 1 ^ ((((((1)))))); //~ERROR - id((1)) | id(1); //~ERROR + (1 as u64) & (1 as u64); //~ERROR equal expressions + 1 ^ ((((((1)))))); //~ERROR equal expressions + id((1)) | id(1); //~ERROR equal expressions // unary and binary operators - (-(2) < -(2)); //~ERROR + (-(2) < -(2)); //~ERROR equal expressions ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); - //~^ ERROR - //~^^ ERROR - //~^^^ ERROR - (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR + //~^ ERROR equal expressions + //~^^ ERROR equal expressions + //~^^^ ERROR equal expressions + (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR equal expressions // various other things - ([1] != [1]); //~ERROR - ((1, 2) != (1, 2)); //~ERROR - [1].len() == [1].len(); //~ERROR + ([1] != [1]); //~ERROR equal expressions + ((1, 2) != (1, 2)); //~ERROR equal expressions + [1].len() == [1].len(); //~ERROR equal expressions vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros } diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index 2305e42161a..419e500d0fc 100755 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -13,20 +13,20 @@ fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy { #[deny(float_cmp)] #[allow(unused)] fn main() { - ZERO == 0f32; //~ERROR - ZERO == 0.0; //~ERROR - ZERO + ZERO != 1.0; //~ERROR + ZERO == 0f32; //~ERROR ==-comparison of f32 or f64 + ZERO == 0.0; //~ERROR ==-comparison of f32 or f64 + ZERO + ZERO != 1.0; //~ERROR !=-comparison of f32 or f64 ONE != 0.0; //~ERROR - twice(ONE) != ONE; //~ERROR - ONE as f64 != 0.0; //~ERROR + twice(ONE) != ONE; //~ERROR !=-comparison of f32 or f64 + ONE as f64 != 0.0; //~ERROR !=-comparison of f32 or f64 let x : f64 = 1.0; - x == 1.0; //~ERROR - x != 0f64; //~ERROR + x == 1.0; //~ERROR ==-comparison of f32 or f64 + x != 0f64; //~ERROR !=-comparison of f32 or f64 - twice(x) != twice(ONE as f64); //~ERROR + twice(x) != twice(ONE as f64); //~ERROR !=-comparison of f32 or f64 x < 0.0; x > 0.0; diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs index cde4a615b25..987bada2ece 100755 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -9,16 +9,16 @@ const ZERO : i64 = 0; fn main() { let x = 0; - x + 0; //~ERROR - 0 + x; //~ERROR - x - ZERO; //~ERROR - x | (0); //~ERROR - ((ZERO)) | x; //~ERROR + x + 0; //~ERROR the operation is ineffective + 0 + x; //~ERROR the operation is ineffective + x - ZERO; //~ERROR the operation is ineffective + x | (0); //~ERROR the operation is ineffective + ((ZERO)) | x; //~ERROR the operation is ineffective - x * 1; //~ERROR - 1 * x; //~ERROR - x / ONE; //~ERROR + x * 1; //~ERROR the operation is ineffective + 1 * x; //~ERROR the operation is ineffective + x / ONE; //~ERROR the operation is ineffective - x & NEG_ONE; //~ERROR - -1 & x; //~ERROR + x & NEG_ONE; //~ERROR the operation is ineffective + -1 & x; //~ERROR the operation is ineffective } diff --git a/tests/compile-fail/let_return.rs b/tests/compile-fail/let_return.rs index 8ea4653ef0f..082378d21e2 100755 --- a/tests/compile-fail/let_return.rs +++ b/tests/compile-fail/let_return.rs @@ -6,7 +6,7 @@ fn test() -> i32 { let _y = 0; // no warning let x = 5; //~NOTE - x //~ERROR: + x //~ERROR returning the result of a let binding } fn test_nowarn_1() -> i32 { diff --git a/tests/compile-fail/let_unit.rs b/tests/compile-fail/let_unit.rs index e8620f862a2..f06a10bfe13 100755 --- a/tests/compile-fail/let_unit.rs +++ b/tests/compile-fail/let_unit.rs @@ -8,6 +8,6 @@ fn main() { let _y = 1; // this is fine let _z = ((), 1); // this as well if true { - let _a = (); //~ERROR + let _a = (); //~ERROR this let-binding has unit value } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index facf0378392..91d3b72de84 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -5,11 +5,11 @@ #[deny(str_to_string, string_to_string)] fn main() { let opt = Some(0); - let _ = opt.unwrap(); //~ERROR + let _ = opt.unwrap(); //~ERROR used unwrap() on an Option let res: Result<i32, ()> = Ok(0); - let _ = res.unwrap(); //~ERROR + let _ = res.unwrap(); //~ERROR used unwrap() on a Result - let string = "str".to_string(); //~ERROR - let _again = string.to_string(); //~ERROR + let string = "str".to_string(); //~ERROR `str.to_owned()` is faster + let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op } diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 2a3f7e3958c..8aa47769539 100755 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -5,7 +5,7 @@ //extern crate regex; #[deny(mut_mut)] -fn fun(x : &mut &mut u32) -> bool { //~ERROR +fn fun(x : &mut &mut u32) -> bool { //~ERROR generally you want to avoid `&mut &mut **x > 0 } @@ -16,19 +16,19 @@ macro_rules! mut_ptr { #[deny(mut_mut)] #[allow(unused_mut, unused_variables)] fn main() { - let mut x = &mut &mut 1u32; //~ERROR + let mut x = &mut &mut 1u32; //~ERROR generally you want to avoid `&mut &mut { - let mut y = &mut x; //~ERROR + let mut y = &mut x; //~ERROR this expression mutably borrows a mutable reference } if fun(x) { let y : &mut &mut &mut u32 = &mut &mut &mut 2; - //~^ ERROR - //~^^ ERROR - //~^^^ ERROR - //~^^^^ ERROR + //~^ ERROR generally you want to avoid `&mut &mut + //~^^ ERROR generally you want to avoid `&mut &mut + //~^^^ ERROR generally you want to avoid `&mut &mut + //~^^^^ ERROR generally you want to avoid `&mut &mut ***y + **x; } - let mut z = mut_ptr!(&mut 3u32); //~ERROR + let mut z = mut_ptr!(&mut 3u32); //~ERROR generally you want to avoid `&mut &mut } diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index 88919f39d6d..6016f79ab03 100755 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -4,9 +4,9 @@ #[deny(needless_bool)] fn main() { let x = true; - if x { true } else { true }; //~ERROR - if x { false } else { false }; //~ERROR - if x { true } else { false }; //~ERROR - if x { false } else { true }; //~ERROR + if x { true } else { true }; //~ERROR your if-then-else expression will always return true + if x { false } else { false }; //~ERROR your if-then-else expression will always return false + if x { true } else { false }; //~ERROR you can reduce your if statement to its predicate + if x { false } else { true }; //~ERROR you can reduce your if statement to `!` + its predicate if x { x } else { false }; // would also be questionable, but we don't catch this yet } diff --git a/tests/compile-fail/needless_return.rs b/tests/compile-fail/needless_return.rs index 34d57127996..e0012942906 100755 --- a/tests/compile-fail/needless_return.rs +++ b/tests/compile-fail/needless_return.rs @@ -8,35 +8,35 @@ fn test_end_of_fn() -> bool { // no error! return true; } - return true; //~ERROR + return true; //~ERROR unneeded return statement } fn test_no_semicolon() -> bool { - return true //~ERROR + return true //~ERROR unneeded return statement } fn test_if_block() -> bool { if true { - return true; //~ERROR + return true; //~ERROR unneeded return statement } else { - return false; //~ERROR + return false; //~ERROR unneeded return statement } } fn test_match(x: bool) -> bool { match x { true => { - return false; //~ERROR + return false; //~ERROR unneeded return statement } false => { - return true //~ERROR + return true //~ERROR unneeded return statement } } } fn test_closure() { let _ = || { - return true; //~ERROR + return true; //~ERROR unneeded return statement }; } diff --git a/tests/compile-fail/precedence.rs b/tests/compile-fail/precedence.rs index fb7d06214a2..4d57f119479 100755 --- a/tests/compile-fail/precedence.rs +++ b/tests/compile-fail/precedence.rs @@ -4,12 +4,12 @@ #[deny(precedence)] #[allow(eq_op)] fn main() { - format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR - format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR - format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR - format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR - format!("{} vs. {}", 1 ^ 1 - 1, (1 ^ 1) - 1); //~ERROR - format!("{} vs. {}", 3 | 2 - 1, (3 | 2) - 1); //~ERROR - format!("{} vs. {}", 3 & 5 - 2, (3 & 5) - 2); //~ERROR + format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR operator precedence can trip + format!("{} vs. {}", 1 + 2 << 3, 1 + (2 << 3)); //~ERROR operator precedence can trip + format!("{} vs. {}", 4 >> 1 + 1, (4 >> 1) + 1); //~ERROR operator precedence can trip + format!("{} vs. {}", 1 + 3 >> 2, 1 + (3 >> 2)); //~ERROR operator precedence can trip + format!("{} vs. {}", 1 ^ 1 - 1, (1 ^ 1) - 1); //~ERROR operator precedence can trip + format!("{} vs. {}", 3 | 2 - 1, (3 | 2) - 1); //~ERROR operator precedence can trip + format!("{} vs. {}", 3 & 5 - 2, (3 & 5) - 2); //~ERROR operator precedence can trip } diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs index d56ea735a1d..d4b6d22608f 100755 --- a/tests/compile-fail/ptr_arg.rs +++ b/tests/compile-fail/ptr_arg.rs @@ -3,13 +3,13 @@ #[deny(ptr_arg)] #[allow(unused)] -fn do_vec(x: &Vec<i64>) { //~ERROR: writing `&Vec<_>` instead of `&[_]` +fn do_vec(x: &Vec<i64>) { //~ERROR writing `&Vec<_>` instead of `&[_]` //Nothing here } #[deny(ptr_arg)] #[allow(unused)] -fn do_str(x: &String) { //~ERROR +fn do_str(x: &String) { //~ERROR writing `&String` instead of `&str` //Nothing here either } -- cgit 1.4.1-3-g733a5 From a67e55f3f07d552233248a63d256535e095c7975 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 08:15:42 +0200 Subject: lint messages: remove trailing period Since lint messages often are suffixed by ", #[warn(xxx)] on by default" this trailing period produces an ugly clash with the comma. --- src/approx_const.rs | 2 +- src/eta_reduction.rs | 2 +- src/identity_op.rs | 2 +- src/len_zero.rs | 4 ++-- src/methods.rs | 4 ++-- src/misc.rs | 10 ++++++---- src/mut_mut.rs | 2 +- src/ptr_arg.rs | 4 ++-- src/strings.rs | 2 +- src/types.rs | 2 +- src/unicode.rs | 4 ++-- 11 files changed, 20 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 594348bf93f..377c7e66ebd 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -53,7 +53,7 @@ fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { for &(constant, name) in KNOWN_CONSTS { if within_epsilon(constant, value) { span_lint(cx, APPROX_CONSTANT, span, &format!( - "approximate value of `{}::{}` found. Consider using it directly.", module, &name)); + "approximate value of `{}::{}` found. Consider using it directly", module, &name)); } } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 00c5a523981..eda38419d4d 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -51,7 +51,7 @@ impl LintPass for EtaPass { } } span_lint(cx, REDUNDANT_CLOSURE, expr.span, - &format!("redundant closure found. Consider using `{}` in its place.", + &format!("redundant closure found. Consider using `{}` in its place", expr_to_string(caller))[..]) } } diff --git a/src/identity_op.rs b/src/identity_op.rs index e043ac63026..8c6940e3df4 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -49,7 +49,7 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if have_lit(cx, e, m) { span_lint(cx, IDENTITY_OP, span, &format!( - "the operation is ineffective. Consider reducing it to `{}`.", + "the operation is ineffective. Consider reducing it to `{}`", snippet(cx, arg, ".."))); } } diff --git a/src/len_zero.rs b/src/len_zero.rs index 298522ed24c..da230c1d28a 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -59,7 +59,7 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { if is_named_self(i, "len") { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, &format!("trait `{}` has a `.len(_: &Self)` method, but no \ - `.is_empty(_: &Self)` method. Consider adding one.", + `.is_empty(_: &Self)` method. Consider adding one", item.ident.name)); } }; @@ -79,7 +79,7 @@ fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { span_lint(cx, LEN_WITHOUT_IS_EMPTY, Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, &format!("item `{}` has a `.len(_: &Self)` method, but no \ - `.is_empty(_: &Self)` method. Consider adding one.", + `.is_empty(_: &Self)` method. Consider adding one", item.ident.name)); return; } diff --git a/src/methods.rs b/src/methods.rs index a5b12e52bdf..403845771a9 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -30,12 +30,12 @@ impl LintPass for MethodsPass { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ to handle the None case gracefully, consider using - expect() to provide a better panic message."); + expect() to provide a better panic message"); } else if match_def_path(cx, did.did, &["core", "result", "Result"]) { span_lint(cx, RESULT_UNWRAP_USED, expr.span, "used unwrap() on a Result value. Graceful handling \ - of Err values is preferred."); + of Err values is preferred"); } } } diff --git a/src/misc.rs b/src/misc.rs index d5e1efe2cc3..82754820f8b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -129,7 +129,8 @@ impl LintPass for FloatCmp { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { span_lint(cx, FLOAT_CMP, expr.span, &format!( - "{}-comparison of f32 or f64 detected. Consider changing this to `abs({} - {}) < epsilon` for some suitable value of epsilon.", + "{}-comparison of f32 or f64 detected. Consider changing this to \ + `abs({} - {}) < epsilon` for some suitable value of epsilon", binop_to_string(op), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); } @@ -160,7 +161,8 @@ impl LintPass for Precedence { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { span_lint(cx, PRECEDENCE, expr.span, - "operator precedence can trip the unwary. Consider adding parenthesis to the subexpression."); + "operator precedence can trip the unwary. Consider adding parenthesis \ + to the subexpression"); } } } @@ -216,7 +218,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { name == "to_owned" && is_str_arg(cx, args) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ - Consider using `{}.as_slice()` to compare without allocation.", + Consider using `{}.as_slice()` to compare without allocation", snippet(cx, other_span, ".."))) } }, @@ -226,7 +228,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { match_path(path, &["String", "from"]) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ - Consider using `{}.as_slice()` to compare without allocation.", + Consider using `{}.as_slice()` to compare without allocation", snippet(cx, other_span, ".."))) } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 469a14a9452..a2055bb655f 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -46,7 +46,7 @@ fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { cx.tcx.expr_ty(e).sty { span_lint(cx, MUT_MUT, expr.span, "this expression mutably borrows a mutable reference. \ - Consider reborrowing.") + Consider reborrowing") } }) }) diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index ed37c112040..3868854c7a1 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -61,9 +61,9 @@ fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { &["String"]).map_or((), |_| { span_lint(cx, PTR_ARG, span, "writing `&String` instead of `&str` involves a new object \ - where a slice will do. Consider changing the type to `&str`.") + where a slice will do. Consider changing the type to `&str`") }), |_| span_lint(cx, PTR_ARG, span, "writing `&Vec<_>` instead of \ `&[_]` involves one more reference and cannot be used with \ - non-Vec-based slices. Consider changing the type to `&[...]`.")) + non-Vec-based slices. Consider changing the type to `&[...]`")) } diff --git a/src/strings.rs b/src/strings.rs index 97016f36268..afc444dd67f 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -30,7 +30,7 @@ impl LintPass for StringAdd { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assign the result of adding something to this string. \ - Consider using `String::push_str()` instead.") + Consider using `String::push_str()` instead") } } } diff --git a/src/types.rs b/src/types.rs index 4980046e01b..c22d088ce5b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -90,7 +90,7 @@ fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { let bindtype = &cx.tcx.pat_ty(&*local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( - "this let-binding has unit value. Consider omitting `let {} =`.", + "this let-binding has unit value. Consider omitting `let {} =`", snippet(cx, local.pat.span, ".."))); } } diff --git a/src/unicode.rs b/src/unicode.rs index ca6abaf01b4..161e90d0f64 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -27,11 +27,11 @@ fn check_str(cx: &Context, string: &str, span: Span) { for (i, c) in string.char_indices() { if c == '\u{200B}' { str_pos_lint(cx, ZERO_WIDTH_SPACE, span, i, - "zero-width space detected. Consider using `\\u{200B}`."); + "zero-width space detected. Consider using `\\u{200B}`"); } if c as u32 > 0x7F { str_pos_lint(cx, NON_ASCII_LITERAL, span, i, &format!( - "literal non-ASCII character detected. Consider using `\\u{{{:X}}}`.", c as u32)); + "literal non-ASCII character detected. Consider using `\\u{{{:X}}}`", c as u32)); } } } -- cgit 1.4.1-3-g733a5 From 8b9c2a79ed9bf4d25f61513017e9a254d0b02d93 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 13:49:28 +0200 Subject: First (incomplete) const folding --- src/const.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/const.rs (limited to 'src') diff --git a/src/const.rs b/src/const.rs new file mode 100644 index 00000000000..924a47f2e5a --- /dev/null +++ b/src/const.rs @@ -0,0 +1,131 @@ +use rustc::lint::Context; +use rustc::middle::const_eval::lookup_const_by_id; +use syntax::ast::*; +use syntax::ptr::P; + +/// a Lit_-like enum to fold constant `Expr`s into +#[derive(PartialEq, Eq, Debug, Clone)] +pub enum Constant { + ConstantStr(&'static str, StrStyle), + ConstantBinary(Rc<Vec<u8>>), + ConstantByte(u8), + ConstantChar(char), + ConstantInt(u64, LitIntType), + ConstantFloat(Cow<'static, str>, FloatTy), + ConstantFloatUnsuffixed(Cow<'static, str>), + ConstantBool(bool), + ConstantVec(Vec<Constant>), + ConstantTuple(Vec<Constant>), +} + +/// simple constant folding +pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { + match e { + &ExprParen(ref inner) => constant(cx, inner), + &ExprPath(_, _) => fetch_path(cx, e), + &ExprBlock(ref block) => constant_block(cx, inner), + &ExprIf(ref cond, ref then, ref otherwise) => + match constant(cx, cond) { + Some(LitBool(true)) => constant(cx, then), + Some(LitBool(false)) => constant(cx, otherwise), + _ => None, + }, + &ExprLit(ref lit) => Some(lit_to_constant(lit)), + &ExprVec(ref vec) => constant_vec(cx, vec), + &ExprTup(ref tup) => constant_tup(cx, tup), + &ExprUnary(op, ref operand) => constant(cx, operand).and_then( + |o| match op { + UnNot => + if let ConstantBool(b) = o { + Some(ConstantBool(!b)) + } else { None }, + UnNeg => + match o { + &ConstantInt(value, ty) => + Some(ConstantInt(value, match ty { + SignedIntLit(ity, sign) => + SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => + UnsuffixedIntLit(neg_sign(sign)), + _ => { return None; }, + })), + &LitFloat(ref is, ref ty) => + Some(ConstantFloat(neg_float_str(is), ty)), + &LitFloatUnsuffixed(ref is) => + Some(ConstantFloatUnsuffixed(neg_float_str(is))), + _ => None, + }, + UnUniq | UnDeref => o, + }), + //TODO: add other expressions + _ => None, + } +} + +fn lit_to_constant(lit: &Lit_) -> Constant { + match lit { + &LitStr(ref is, style) => ConstantStr(&*is, style), + &LitBinary(ref blob) => ConstantBinary(blob.clone()), + &LitByte(b) => ConstantByte(b), + &LitChar(c) => ConstantChar(c), + &LitInt(value, ty) => ConstantInt(value, ty), + &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty), + &LitFloatUnsuffixed(InternedString) => + ConstantFloatUnsuffixed(Cow::Borrowed(&*is)), + &LitBool(b) => ConstantBool(b), + } +} + +/// create `Some(ConstantVec(..))` of all constants, unless there is any +/// non-constant part +fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> { + Vec<Constant> parts = Vec::new(); + for opt_part in vec { + match constant(cx, opt_part) { + Some(ref p) => parts.push(p), + None => { return None; }, + } + } + Some(ConstantVec(parts)) +} + +fn constant_tup(cx, &Context, tup: &[&Expr]) -> Option<Constant> { + Vec<Constant> parts = Vec::new(); + for opt_part in vec { + match constant(cx, opt_part) { + Some(ref p) => parts.push(p), + None => { return None; }, + } + } + Some(ConstantTuple(parts)) +} + +/// lookup a possibly constant expression from a ExprPath +fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { + if let Some(&PathResolution { base_def: DefConst(id), ..}) = + cx.tcx.def_map.borrow().get(&e.id) { + lookup_const_by_id(cx.tcx, id, None).map(|l| constant(cx, l)) + } else { None } +} + +/// A block can only yield a constant if it only has one constant expression +fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { + if block.stmts.is_empty() { + block.expr.map(|b| constant(cx, b)) + } else { None } +} + +fn neg_sign(s: Sign) -> Sign { + match s: + Sign::Plus => Sign::Minus, + Sign::Minus => Sign::Plus, + } +} + +fn neg_float_str(s: &InternedString) -> Cow<'static, str> { + if s.startsWith('-') { + Cow::Borrowed(s[1..]) + } else { + Cow::Owned(format!("-{}", &*s)) + } +} -- cgit 1.4.1-3-g733a5 From 6aeb9552148315641e49d7ab791ef6ffa638fcbe Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 14:02:13 +0200 Subject: fixed if-condition match --- src/const.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/const.rs b/src/const.rs index 924a47f2e5a..a353de218f4 100644 --- a/src/const.rs +++ b/src/const.rs @@ -26,8 +26,8 @@ pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { &ExprBlock(ref block) => constant_block(cx, inner), &ExprIf(ref cond, ref then, ref otherwise) => match constant(cx, cond) { - Some(LitBool(true)) => constant(cx, then), - Some(LitBool(false)) => constant(cx, otherwise), + Some(ConstantBool(true)) => constant(cx, then), + Some(ConstantBool(false)) => constant(cx, otherwise), _ => None, }, &ExprLit(ref lit) => Some(lit_to_constant(lit)), -- cgit 1.4.1-3-g733a5 From a2f19f2a380d1027436c30edc52992edfcd50cb1 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 13 Aug 2015 09:25:44 +0200 Subject: added follow flag --- src/const.rs | 154 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 113 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/const.rs b/src/const.rs index a353de218f4..38044bbea5c 100644 --- a/src/const.rs +++ b/src/const.rs @@ -3,60 +3,74 @@ use rustc::middle::const_eval::lookup_const_by_id; use syntax::ast::*; use syntax::ptr::P; +pub enum FloatWidth { + Fw32, + Fw64, + FwAny +} + +impl From<FloatTy> for FloatWidth { + fn from(ty: FloatTy) -> FloatWidth { + match ty { + TyF32 => Fw32, + TyF64 => Fw64, + } + } +} + /// a Lit_-like enum to fold constant `Expr`s into #[derive(PartialEq, Eq, Debug, Clone)] pub enum Constant { + /// a String "abc" ConstantStr(&'static str, StrStyle), + /// a Binary String b"abc" ConstantBinary(Rc<Vec<u8>>), + /// a single byte b'a' ConstantByte(u8), + /// a single char 'a' ConstantChar(char), + /// an integer ConstantInt(u64, LitIntType), - ConstantFloat(Cow<'static, str>, FloatTy), - ConstantFloatUnsuffixed(Cow<'static, str>), + /// a float with given type + ConstantFloat(Cow<'static, str>, FloatWidth), + /// true or false ConstantBool(bool), + /// an array of constants ConstantVec(Vec<Constant>), + /// also an array, but with only one constant, repeated N times + ConstantRepeat(Constant, usize), + /// a tuple of constants ConstantTuple(Vec<Constant>), } /// simple constant folding -pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { +pub fn constant(cx: &Context, e: &Expr, follow: bool) -> Option<Constant> { match e { - &ExprParen(ref inner) => constant(cx, inner), - &ExprPath(_, _) => fetch_path(cx, e), - &ExprBlock(ref block) => constant_block(cx, inner), - &ExprIf(ref cond, ref then, ref otherwise) => + &ExprParen(ref inner) => constant(cx, inner, follow), + &ExprPath(_, _) => if follow { fetch_path(cx, e) } else { None }, + &ExprBlock(ref block) => constant_block(cx, inner, follow), + &ExprIf(ref cond, ref then, ref otherwise) => match constant(cx, cond) { - Some(ConstantBool(true)) => constant(cx, then), - Some(ConstantBool(false)) => constant(cx, otherwise), + Some(ConstantBool(true)) => constant(cx, then, follow), + Some(ConstantBool(false)) => constant(cx, otherwise, follow), _ => None, }, &ExprLit(ref lit) => Some(lit_to_constant(lit)), - &ExprVec(ref vec) => constant_vec(cx, vec), - &ExprTup(ref tup) => constant_tup(cx, tup), - &ExprUnary(op, ref operand) => constant(cx, operand).and_then( + &ExprVec(ref vec) => constant_vec(cx, vec, follow), + &ExprTup(ref tup) => constant_tup(cx, tup, follow), + &ExprRepeat(ref value, ref number) => + constant_binop_apply(cx, value, number,|v, n| ConstantRepeat(v, n)), + &ExprUnary(op, ref operand) => constant(cx, operand, follow).and_then( |o| match op { UnNot => if let ConstantBool(b) = o { Some(ConstantBool(!b)) } else { None }, - UnNeg => - match o { - &ConstantInt(value, ty) => - Some(ConstantInt(value, match ty { - SignedIntLit(ity, sign) => - SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => - UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; }, - })), - &LitFloat(ref is, ref ty) => - Some(ConstantFloat(neg_float_str(is), ty)), - &LitFloatUnsuffixed(ref is) => - Some(ConstantFloatUnsuffixed(neg_float_str(is))), - _ => None, - }, + UnNeg => constant_negate(o), UnUniq | UnDeref => o, }), + &ExprBinary(op, ref left, ref right) => + constant_binop(cx, op, left, right, follow), //TODO: add other expressions _ => None, } @@ -69,19 +83,19 @@ fn lit_to_constant(lit: &Lit_) -> Constant { &LitByte(b) => ConstantByte(b), &LitChar(c) => ConstantChar(c), &LitInt(value, ty) => ConstantInt(value, ty), - &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty), - &LitFloatUnsuffixed(InternedString) => - ConstantFloatUnsuffixed(Cow::Borrowed(&*is)), + &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty.into()), + &LitFloatUnsuffixed(InternedString) => + ConstantFloat(Cow::Borrowed(&*is), FwAny), &LitBool(b) => ConstantBool(b), } } /// create `Some(ConstantVec(..))` of all constants, unless there is any /// non-constant part -fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> { - Vec<Constant> parts = Vec::new(); +fn constant_vec(cx: &Context, vec: &[&Expr], follow: bool) -> Option<Constant> { + parts = Vec::new(); for opt_part in vec { - match constant(cx, opt_part) { + match constant(cx, opt_part, follow) { Some(ref p) => parts.push(p), None => { return None; }, } @@ -89,10 +103,10 @@ fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> { Some(ConstantVec(parts)) } -fn constant_tup(cx, &Context, tup: &[&Expr]) -> Option<Constant> { - Vec<Constant> parts = Vec::new(); +fn constant_tup(cx: &Context, tup: &[&Expr], follow: bool) -> Option<Constant> { + parts = Vec::new(); for opt_part in vec { - match constant(cx, opt_part) { + match constant(cx, opt_part, follow) { Some(ref p) => parts.push(p), None => { return None; }, } @@ -109,23 +123,81 @@ fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { } /// A block can only yield a constant if it only has one constant expression -fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { +fn constant_block(cx: &Context, block: &Block, follow: bool) -> Option<Constant> { if block.stmts.is_empty() { - block.expr.map(|b| constant(cx, b)) + block.expr.map(|b| constant(cx, b, follow)) } else { None } } +fn constant_negate(o: Constant) -> Option<Constant> { + match o { + &ConstantInt(value, ty) => + Some(ConstantInt(value, match ty { + SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), + _ => { return None; }, + })), + &LitFloat(ref is, ref ty) => Some(ConstantFloat(neg_float_str(is), ty)), + _ => None, + } +} + fn neg_sign(s: Sign) -> Sign { - match s: + match s { Sign::Plus => Sign::Minus, Sign::Minus => Sign::Plus, } } fn neg_float_str(s: &InternedString) -> Cow<'static, str> { - if s.startsWith('-') { + if s.startsWith('-') { Cow::Borrowed(s[1..]) } else { Cow::Owned(format!("-{}", &*s)) } } + +fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr, + follow: bool) -> Option<Constant> { + match op.node { + //BiAdd, + //BiSub, + //BiMul, + //BiDiv, + //BiRem, + BiAnd => constant_short_circuit(cx, left, right, false, follow), + BiOr => constant_short_circuit(cx, left, right, true, follow), + //BiBitXor, + //BiBitAnd, + //BiBitOr, + //BiShl, + //BiShr, + //BiEq, + //BiLt, + //BiLe, + //BiNe, + //BiGe, + //BiGt, + _ => None, + } +} + +fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F, + follow: bool) -> Option<Constant> +where F: FnMut(Constant, Constant) -> Option<Constant> { + constant(cx, left, follow).and_then(|l| constant(cx, right, follow) + .and_then(|r| op(l, r))) +} + +fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool, + follow: bool) -> Option<Constant> { + if let ConstantBool(lbool) = constant(cx, left, follow) { + if l == b { + Some(ConstantBool(b)) + } else { + if let ConstantBool(rbool) = constant(cx, right, follow) { + Some(ConstantBool(rbool)) + } else { None } + } + } else { None } +} -- cgit 1.4.1-3-g733a5 From 1a19d5ef65061338b90336626999eef3497ecbb7 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 13 Aug 2015 10:45:30 +0200 Subject: changed Constant to a struct with 'needed_resolution' bool --- src/const.rs | 202 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 138 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/const.rs b/src/const.rs index 38044bbea5c..cef2cd7f9fc 100644 --- a/src/const.rs +++ b/src/const.rs @@ -18,9 +18,25 @@ impl From<FloatTy> for FloatWidth { } } +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Constant { + constant: ConstantVariant, + needed_resolution: bool +} + +impl Constant { + fn new(variant: ConstantVariant) -> Constant { + Constant { constant: variant, needed_resolution: false } + } + + fn new_resolved(variant: ConstantVariant) -> Constant { + Constant { constant: variant, needed_resolution: true } + } +} + /// a Lit_-like enum to fold constant `Expr`s into #[derive(PartialEq, Eq, Debug, Clone)] -pub enum Constant { +pub enum ConstantVariant { /// a String "abc" ConstantStr(&'static str, StrStyle), /// a Binary String b"abc" @@ -43,34 +59,51 @@ pub enum Constant { ConstantTuple(Vec<Constant>), } -/// simple constant folding -pub fn constant(cx: &Context, e: &Expr, follow: bool) -> Option<Constant> { +impl ConstantVariant { + /// convert to u64 if possible + /// + /// # panics + /// + /// if the constant could not be converted to u64 losslessly + fn as_u64(&self) -> u64 { + if let &ConstantInt(val, _) = self { + val // TODO we may want to check the sign if any + } else { + panic!("Could not convert a {:?} to u64"); + } + } +} + +/// simple constant folding: Insert an expression, get a constant or none. +pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { match e { - &ExprParen(ref inner) => constant(cx, inner, follow), - &ExprPath(_, _) => if follow { fetch_path(cx, e) } else { None }, - &ExprBlock(ref block) => constant_block(cx, inner, follow), + &ExprParen(ref inner) => constant(cx, inner), + &ExprPath(_, _) => fetch_path(cx, e), + &ExprBlock(ref block) => constant_block(cx, inner), &ExprIf(ref cond, ref then, ref otherwise) => - match constant(cx, cond) { - Some(ConstantBool(true)) => constant(cx, then, follow), - Some(ConstantBool(false)) => constant(cx, otherwise, follow), - _ => None, - }, + constant_if(cx, cond, then, otherwise), &ExprLit(ref lit) => Some(lit_to_constant(lit)), - &ExprVec(ref vec) => constant_vec(cx, vec, follow), - &ExprTup(ref tup) => constant_tup(cx, tup, follow), + &ExprVec(ref vec) => constant_vec(cx, vec), + &ExprTup(ref tup) => constant_tup(cx, tup), &ExprRepeat(ref value, ref number) => - constant_binop_apply(cx, value, number,|v, n| ConstantRepeat(v, n)), - &ExprUnary(op, ref operand) => constant(cx, operand, follow).and_then( + constant_binop_apply(cx, value, number,|v, n| Constant { + constant: ConstantRepeat(v, n.constant.as_u64()), + needed_resolution: v.needed_resolution || n.needed_resolution + }), + &ExprUnary(op, ref operand) => constant(cx, operand).and_then( |o| match op { UnNot => - if let ConstantBool(b) = o { - Some(ConstantBool(!b)) + if let ConstantBool(b) = o.variant { + Some(Constant{ + needed_resolution: o.needed_resolution, + constant: ConstantBool(!b), + }) } else { None }, UnNeg => constant_negate(o), UnUniq | UnDeref => o, }), &ExprBinary(op, ref left, ref right) => - constant_binop(cx, op, left, right, follow), + constant_binop(op, left, right), //TODO: add other expressions _ => None, } @@ -78,68 +111,100 @@ pub fn constant(cx: &Context, e: &Expr, follow: bool) -> Option<Constant> { fn lit_to_constant(lit: &Lit_) -> Constant { match lit { - &LitStr(ref is, style) => ConstantStr(&*is, style), - &LitBinary(ref blob) => ConstantBinary(blob.clone()), - &LitByte(b) => ConstantByte(b), - &LitChar(c) => ConstantChar(c), - &LitInt(value, ty) => ConstantInt(value, ty), - &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty.into()), + &LitStr(ref is, style) => Constant::new(ConstantStr(&*is, style)), + &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())), + &LitByte(b) => Constant::new(ConstantByte(b)), + &LitChar(c) => Constant::new(ConstantChar(c)), + &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)), + &LitFloat(ref is, ty) => + Constant::new(ConstantFloat(Cow::Borrowed(&*is), ty.into())), &LitFloatUnsuffixed(InternedString) => - ConstantFloat(Cow::Borrowed(&*is), FwAny), - &LitBool(b) => ConstantBool(b), + Constant::new(ConstantFloat(Cow::Borrowed(&*is), FwAny)), + &LitBool(b) => Constant::new(ConstantBool(b)), } } /// create `Some(ConstantVec(..))` of all constants, unless there is any /// non-constant part -fn constant_vec(cx: &Context, vec: &[&Expr], follow: bool) -> Option<Constant> { - parts = Vec::new(); +fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> { + let mut parts = Vec::new(); + let mut resolved = false; for opt_part in vec { - match constant(cx, opt_part, follow) { - Some(ref p) => parts.push(p), + match constant(cx, opt_part) { + Some(ref p) => { + resolved |= p.needed_resolution; + parts.push(p) + }, None => { return None; }, } } - Some(ConstantVec(parts)) + Some(Constant { + constant: ConstantVec(parts), + needed_resolution: resolved + }) } -fn constant_tup(cx: &Context, tup: &[&Expr], follow: bool) -> Option<Constant> { - parts = Vec::new(); +fn constant_tup(cx: &Context, tup: &[&Expr]) -> Option<Constant> { + let mut parts = Vec::new(); + let mut resolved = false; for opt_part in vec { - match constant(cx, opt_part, follow) { - Some(ref p) => parts.push(p), + match constant(cx, opt_part) { + Some(ref p) => { + resolved |= p.needed_resolution; + parts.push(p) + }, None => { return None; }, } } - Some(ConstantTuple(parts)) + Some(Constant { + constant: ConstantTuple(parts), + needed_resolution: resolved + }) } /// lookup a possibly constant expression from a ExprPath fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { if let Some(&PathResolution { base_def: DefConst(id), ..}) = cx.tcx.def_map.borrow().get(&e.id) { - lookup_const_by_id(cx.tcx, id, None).map(|l| constant(cx, l)) + lookup_const_by_id(cx.tcx, id, None).map( + |l| Constant::new_resolved(constant(cx, l).constant)) } else { None } } /// A block can only yield a constant if it only has one constant expression -fn constant_block(cx: &Context, block: &Block, follow: bool) -> Option<Constant> { +fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { if block.stmts.is_empty() { - block.expr.map(|b| constant(cx, b, follow)) + block.expr.map(|b| constant(cx, b)) + } else { None } +} + +fn constant_if(cx: &Context, cond: &Expr, then: &Expr, otherwise: &Expr) -> + Option<Constant> { + if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) = + constant(cx, cond) { + let part = constant(cx, if b { then } else { otherwise }); + Some(Constant { + constant: part.constant, + needed_resolution: res || part.needed_resolution, + }) } else { None } } fn constant_negate(o: Constant) -> Option<Constant> { - match o { - &ConstantInt(value, ty) => - Some(ConstantInt(value, match ty { - SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; }, - })), - &LitFloat(ref is, ref ty) => Some(ConstantFloat(neg_float_str(is), ty)), - _ => None, - } + Some(Constant{ + needed_resolution: o.needed_resolution, + constant: match o.constant { + &ConstantInt(value, ty) => + ConstantInt(value, match ty { + SignedIntLit(ity, sign) => + SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), + _ => { return None; }, + }), + &LitFloat(ref is, ref ty) => ConstantFloat(neg_float_str(is), ty), + _ => { return None; }, + } + }) } fn neg_sign(s: Sign) -> Sign { @@ -157,16 +222,16 @@ fn neg_float_str(s: &InternedString) -> Cow<'static, str> { } } -fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr, - follow: bool) -> Option<Constant> { +fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) + -> Option<Constant> { match op.node { //BiAdd, //BiSub, //BiMul, //BiDiv, //BiRem, - BiAnd => constant_short_circuit(cx, left, right, false, follow), - BiOr => constant_short_circuit(cx, left, right, true, follow), + BiAnd => constant_short_circuit(cx, left, right, false), + BiOr => constant_short_circuit(cx, left, right, true), //BiBitXor, //BiBitAnd, //BiBitOr, @@ -182,21 +247,30 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr, } } -fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F, - follow: bool) -> Option<Constant> -where F: FnMut(Constant, Constant) -> Option<Constant> { - constant(cx, left, follow).and_then(|l| constant(cx, right, follow) - .and_then(|r| op(l, r))) +fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F) + -> Option<Constant> +where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> { + constant(cx, left).and_then(|l| constant(cx, right).and_then( + |r| Constant { + needed_resolution: l.needed_resolution || r.needed_resolution, + constant: op(l.constant, r.constant) + })) } -fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool, - follow: bool) -> Option<Constant> { - if let ConstantBool(lbool) = constant(cx, left, follow) { +fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) -> + Option<Constant> { + let leftconst = constant(cx, left); + if let ConstantBool(lbool) = leftconst.constant { if l == b { - Some(ConstantBool(b)) + Some(leftconst) } else { - if let ConstantBool(rbool) = constant(cx, right, follow) { - Some(ConstantBool(rbool)) + let rightconst = constant(cx, right); + if let ConstantBool(rbool) = rightconst.constant { + Some(Constant { + constant: rightconst.constant, + needed_resolution: leftconst.needed_resolution || + rightconst.needed_resolution, + }) } else { None } } } else { None } -- cgit 1.4.1-3-g733a5 From 2c2716f04587eb379bf7715f1dd7d7a46c8f7eab Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 10:32:35 +0200 Subject: all: DRY for lint descriptions * use the rustc style for lint descriptions * add a script to parse all lint descriptions and put the generated table into README --- README.md | 65 ++++++++++++++++++++++------------------- src/approx_const.rs | 3 +- src/attrs.rs | 2 +- src/bit_mask.rs | 7 ++--- src/collapsible_if.rs | 3 +- src/eq_op.rs | 2 +- src/eta_reduction.rs | 2 +- src/identity_op.rs | 2 +- src/len_zero.rs | 5 ++-- src/lib.rs | 15 ++++++---- src/lifetimes.rs | 3 +- src/loops.rs | 2 +- src/methods.rs | 8 +++--- src/misc.rs | 21 +++++++++----- src/mut_mut.rs | 3 +- src/needless_bool.rs | 3 +- src/ptr_arg.rs | 3 +- src/returns.rs | 5 ++-- src/strings.rs | 2 +- src/types.rs | 7 +++-- src/unicode.rs | 7 +++-- util/update_readme.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ 22 files changed, 180 insertions(+), 70 deletions(-) create mode 100644 util/update_readme.py (limited to 'src') diff --git a/README.md b/README.md index b61f3561302..193d759ff90 100644 --- a/README.md +++ b/README.md @@ -6,35 +6,42 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints Lints included in this crate: - - `single_match`: Warns when a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used, and recommends `if let` instead. - - `box_vec`: Warns on usage of `Box<Vec<T>>` - - `linkedlist`: Warns on usage of `LinkedList` - - `str_to_string`: Warns on usage of `str::to_string()` - - `toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) - - `eq_op`: Warns on equal operands on both sides of a comparison or bitwise combination - - `bad_bit_mask`: Denies expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) - - `ineffective_bit_mask`: Warns on expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` - - `needless_bool` : Warns on if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` - - `ptr_arg`: Warns on fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively - - `approx_constant`: Warns if the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found and suggests to use the constant - - `cmp_nan`: Denies comparisons to NAN (which will always return false, which is probably not intended) - - `float_cmp`: Warns on `==` or `!=` comparisons of floaty typed values. As floating-point operations usually involve rounding errors, it is always better to check for approximate equality within some small bounds - - `precedence`: Warns on expressions where precedence may trip up the unwary reader of the source and suggests adding parenthesis, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` - - `redundant_closure`: Warns on usage of eta-reducible closures like `|a| foo(a)` (which can be written as just `foo`) - - `identity_op`: Warns on identity operations like `x + 0` or `y / 1` (which can be reduced to `x` and `y`, respectively) - - `mut_mut`: Warns on `&mut &mut` which is either a copy'n'paste error, or shows a fundamental misunderstanding of references - - `len_zero`: Warns on `_.len() == 0` and suggests using `_.is_empty()` (or similar comparisons with `>` or `!=`) - - `len_without_is_empty`: Warns on traits or impls that have a `.len()` but no `.is_empty()` method - - `cmp_owned`: Warns on creating owned instances for comparing with others, e.g. `x == "foo".to_string()` - - `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea - - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` - - `zero_width_space`: Warns on encountering a unicode zero-width space - - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. - - `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice. - - `let_and_return`: Warns on doing `let x = expr; x` at the end of a function. - - `option_unwrap_used`: Warns when `Option.unwrap()` is used, and suggests `.expect()`. - - `result_unwrap_used`: Warns when `Result.unwrap()` is used (silent by default). - - `modulo_one`: Warns on taking a number modulo 1, which always has a result of 0. +name | default | meaning +---------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) +cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` +ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +inline_always | warn | `#[inline(always)]` is a bad idea in most cases +len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` +len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function +let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +modulo_one | warn | taking a number modulo 1, which always returns 0 +mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do +needless_return | warn | using a return statement like `return expr;` where an expression would suffice +non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +option_unwrap_used | warn | using `Option.unwrap()`, which should at least get a better message using `expect()` +precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` +ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled +single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` +string_add_assign | warn | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +string_to_string | warn | calling `String.to_string()` which is a no-op +toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +zero_width_space | deny | using a zero-width space in a string literal, which is confusing To use, add the following lines to your Cargo.toml: diff --git a/src/approx_const.rs b/src/approx_const.rs index 377c7e66ebd..3c39b79885c 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -12,7 +12,8 @@ use utils::span_lint; declare_lint! { pub APPROX_CONSTANT, Warn, - "Warn if a user writes an approximate known constant in their code" + "the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) \ + is found; suggests to use the constant" } const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"), diff --git a/src/attrs.rs b/src/attrs.rs index 789a992e3a5..ca5b6c55ced 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -9,7 +9,7 @@ use syntax::parse::token::InternedString; use utils::{in_macro, match_path, span_lint}; declare_lint! { pub INLINE_ALWAYS, Warn, - "#[inline(always)] is usually a bad idea."} + "`#[inline(always)]` is a bad idea in most cases" } #[derive(Copy,Clone)] diff --git a/src/bit_mask.rs b/src/bit_mask.rs index b5f088c23ef..169975001b9 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -11,15 +11,14 @@ use utils::span_lint; declare_lint! { pub BAD_BIT_MASK, Deny, - "Deny the use of incompatible bit masks in comparisons, e.g. \ - '(a & 1) == 2'" + "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \ + (because in the example `select` containing bits that `mask` doesn't have)" } declare_lint! { pub INEFFECTIVE_BIT_MASK, Warn, - "Warn on the use of an ineffective bit mask in comparisons, e.g. \ - '(a & 1) > 2'" + "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`" } /// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 0350db8163a..f0f53622c47 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -23,7 +23,8 @@ use utils::{in_macro, span_help_and_lint, snippet}; declare_lint! { pub COLLAPSIBLE_IF, Warn, - "Warn on if expressions that can be collapsed" + "two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` \ + can be written as `if x && y { foo() }`" } #[derive(Copy,Clone)] diff --git a/src/eq_op.rs b/src/eq_op.rs index 6ad0e0658df..495696b810c 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -8,7 +8,7 @@ use utils::span_lint; declare_lint! { pub EQ_OP, Warn, - "warn about comparing equal expressions (e.g. x == x)" + "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)" } #[derive(Copy,Clone)] diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index eda38419d4d..484d46ddc21 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -11,7 +11,7 @@ pub struct EtaPass; declare_lint!(pub REDUNDANT_CLOSURE, Warn, - "Warn on usage of redundant closures, i.e. `|a| foo(a)`"); + "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"); impl LintPass for EtaPass { fn get_lints(&self) -> LintArray { diff --git a/src/identity_op.rs b/src/identity_op.rs index 8c6940e3df4..964675b765e 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -10,7 +10,7 @@ use syntax::codemap::Span; use utils::{span_lint, snippet}; declare_lint! { pub IDENTITY_OP, Warn, - "Warn on identity operations, e.g. '_ + 0'"} + "using identity operations, e.g. `x + 0` or `y / 1`" } #[derive(Copy,Clone)] pub struct IdentityOp; diff --git a/src/len_zero.rs b/src/len_zero.rs index da230c1d28a..d5f3d1ad810 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -12,10 +12,11 @@ use syntax::ast::*; use utils::{span_lint, walk_ptrs_ty, snippet}; declare_lint!(pub LEN_ZERO, Warn, - "Warn when .is_empty() could be used instead of checking .len()"); + "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ + could be used instead"); declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, - "Warn on traits and impls that have .len() but not .is_empty()"); + "traits and impls that have `.len()` but not `.is_empty()`"); #[derive(Copy,Clone)] pub struct LenZero; diff --git a/src/lib.rs b/src/lib.rs index f788c72db3c..eb2704cd4bd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,16 +64,21 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); - reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, + reg.register_lint_group("clippy", vec![types::BOX_VEC, + types::LINKEDLIST, + types::LET_UNIT_VALUE, misc::SINGLE_MATCH, - misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, + misc::TOPLEVEL_REF_ARG, + misc::CMP_NAN, + misc::FLOAT_CMP, + misc::PRECEDENCE, + misc::CMP_OWNED, + eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, approx_const::APPROX_CONSTANT, - misc::CMP_NAN, misc::FLOAT_CMP, - misc::PRECEDENCE, misc::CMP_OWNED, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, mut_mut::MUT_MUT, @@ -85,12 +90,12 @@ pub fn plugin_registrar(reg: &mut Registry) { unicode::NON_ASCII_LITERAL, strings::STRING_ADD_ASSIGN, returns::NEEDLESS_RETURN, + returns::LET_AND_RETURN, misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::STR_TO_STRING, methods::STRING_TO_STRING, - types::LET_UNIT_VALUE, lifetimes::NEEDLESS_LIFETIMES, loops::NEEDLESS_RANGE_LOOP, ]); diff --git a/src/lifetimes.rs b/src/lifetimes.rs index b510173e753..644537f9be1 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -7,7 +7,8 @@ use std::collections::HashSet; use std::iter::FromIterator; declare_lint!(pub NEEDLESS_LIFETIMES, Warn, - "Warn on explicit lifetimes when elision rules would apply"); + "using explicit lifetimes for references in function arguments when elision rules \ + would allow omitting them"); #[derive(Copy,Clone)] pub struct LifetimePass; diff --git a/src/loops.rs b/src/loops.rs index 83d7ca4eccb..b406bc67961 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; use utils::{span_lint, get_parent_expr}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, - "Warn about looping over a range of indices if a normal iterator would do" } + "for-looping over a range of indices where an iterator over items would do" } #[derive(Copy, Clone)] pub struct LoopsPass; diff --git a/src/methods.rs b/src/methods.rs index 403845771a9..07b0fdf70e2 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -8,13 +8,13 @@ use utils::{span_lint, match_def_path, walk_ptrs_ty}; pub struct MethodsPass; declare_lint!(pub OPTION_UNWRAP_USED, Warn, - "Warn on using unwrap() on an Option value"); + "using `Option.unwrap()`, which should at least get a better message using `expect()`"); declare_lint!(pub RESULT_UNWRAP_USED, Allow, - "Warn on using unwrap() on a Result value"); + "using `Result.unwrap()`, which might be better handled"); declare_lint!(pub STR_TO_STRING, Warn, - "Warn when a String could use to_owned() instead of to_string()"); + "using `to_string()` on a str, which should be `to_owned()`"); declare_lint!(pub STRING_TO_STRING, Warn, - "Warn when calling String.to_string()"); + "calling `String.to_string()` which is a no-op"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { diff --git a/src/misc.rs b/src/misc.rs index 925843a7046..6c9a7d92ce8 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -16,7 +16,8 @@ pub struct MiscPass; declare_lint!(pub SINGLE_MATCH, Warn, - "Warn on usage of matches with a single nontrivial arm"); + "a match statement with a single nontrivial arm (i.e, where the other arm \ + is `_ => {}`) is used; recommends `if let` instead"); impl LintPass for MiscPass { fn get_lints(&self) -> LintArray { @@ -59,7 +60,9 @@ impl LintPass for MiscPass { } -declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); +declare_lint!(pub TOPLEVEL_REF_ARG, Warn, + "a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not \ + `fn foo((ref x, ref y): (u8, u8))`)"); #[allow(missing_copy_implementations)] pub struct TopLevelRefPass; @@ -82,7 +85,8 @@ impl LintPass for TopLevelRefPass { } } -declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64::NAN"); +declare_lint!(pub CMP_NAN, Deny, + "comparisons to NAN (which will always return false, which is probably not intended)"); #[derive(Copy,Clone)] pub struct CmpNan; @@ -114,7 +118,9 @@ fn check_nan(cx: &Context, path: &Path, span: Span) { } declare_lint!(pub FLOAT_CMP, Warn, - "Warn on ==/!= comparison of floaty values"); + "using `==` or `!=` on float values (as floating-point operations \ + usually involve rounding errors, it is always better to check for approximate \ + equality within small bounds)"); #[derive(Copy,Clone)] pub struct FloatCmp; @@ -147,7 +153,8 @@ fn is_float(cx: &Context, expr: &Expr) -> bool { } declare_lint!(pub PRECEDENCE, Warn, - "Warn on mixing bit ops with integer arithmetic without parentheses"); + "expressions where precedence may trip up the unwary reader of the source; \ + suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)`"); #[derive(Copy,Clone)] pub struct Precedence; @@ -190,7 +197,7 @@ fn is_arith_op(op : BinOp_) -> bool { } declare_lint!(pub CMP_OWNED, Warn, - "Warn on creating an owned string just for comparison"); + "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"); #[derive(Copy,Clone)] pub struct CmpOwned; @@ -242,7 +249,7 @@ fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } -declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0"); +declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); #[derive(Copy,Clone)] pub struct ModuloOne; diff --git a/src/mut_mut.rs b/src/mut_mut.rs index a2055bb655f..a3c40d06f90 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -6,7 +6,8 @@ use syntax::codemap::{BytePos, ExpnInfo, Span}; use utils::{in_macro, span_lint}; declare_lint!(pub MUT_MUT, Warn, - "Warn on usage of double-mut refs, e.g. '&mut &mut ...'"); + "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ + or shows a fundamental misunderstanding of references)"); #[derive(Copy,Clone)] pub struct MutMut; diff --git a/src/needless_bool.rs b/src/needless_bool.rs index d97e819077a..6a4a55aeda5 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -15,7 +15,8 @@ use utils::{de_p, span_lint}; declare_lint! { pub NEEDLESS_BOOL, Warn, - "Warn on needless use of if x { true } else { false } (or vice versa)" + "if-statements with plain booleans in the then- and else-clause, e.g. \ + `if p { true } else { false }`" } #[derive(Copy,Clone)] diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 3868854c7a1..85db4aa7b21 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -16,7 +16,8 @@ use utils::span_lint; declare_lint! { pub PTR_ARG, Allow, - "Warn on declaration of a &Vec- or &String-typed method argument" + "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \ + instead, respectively" } #[derive(Copy,Clone)] diff --git a/src/returns.rs b/src/returns.rs index be28e14001c..94b9ec9650f 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -7,9 +7,10 @@ use rustc::lint::{Context, LintPass, LintArray, Level}; use utils::{span_lint, snippet, match_path}; declare_lint!(pub NEEDLESS_RETURN, Warn, - "Warn on using a return statement where an expression would be enough"); + "using a return statement like `return expr;` where an expression would suffice"); declare_lint!(pub LET_AND_RETURN, Warn, - "Warn on creating a let-binding and then immediately returning it"); + "creating a let-binding and then immediately returning it like `let x = expr; x` at \ + the end of a function"); #[derive(Copy,Clone)] pub struct ReturnPass; diff --git a/src/strings.rs b/src/strings.rs index afc444dd67f..20844be318b 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -14,7 +14,7 @@ use utils::{match_def_path, span_lint, walk_ptrs_ty}; declare_lint! { pub STRING_ADD_ASSIGN, Warn, - "Warn on `x = x + ..` where x is a `String`" + "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" } #[derive(Copy,Clone)] diff --git a/src/types.rs b/src/types.rs index c22d088ce5b..ad7b767d95e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -12,9 +12,10 @@ use utils::{in_macro, snippet, span_lint, span_help_and_lint}; pub struct TypePass; declare_lint!(pub BOX_VEC, Warn, - "Warn on usage of Box<Vec<T>>"); + "usage of `Box<Vec<T>>`, vector elements are already on the heap"); declare_lint!(pub LINKEDLIST, Warn, - "Warn on usage of LinkedList"); + "usage of LinkedList, usually a vector is faster, or a more specialized data \ + structure like a RingBuf"); /// Matches a type with a provided string, and returns its type parameters if successful pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> { @@ -81,7 +82,7 @@ impl LintPass for TypePass { pub struct LetPass; declare_lint!(pub LET_UNIT_VALUE, Warn, - "Warn on let-binding a value of unit type"); + "creating a let binding to a value of unit type, which usually can't be used afterwards"); fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { diff --git a/src/unicode.rs b/src/unicode.rs index 161e90d0f64..62b4a9dadf5 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -3,8 +3,11 @@ use syntax::ast::*; use syntax::codemap::{BytePos, Span}; use utils::span_lint; -declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "Zero-width space is confusing" } -declare_lint!{ pub NON_ASCII_LITERAL, Allow, "Lint literal non-ASCII chars in literals" } +declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, + "using a zero-width space in a string literal, which is confusing" } +declare_lint!{ pub NON_ASCII_LITERAL, Allow, + "using any literal non-ASCII chars in a string literal; suggests \ + using the \\u escape instead" } #[derive(Copy, Clone)] pub struct Unicode; diff --git a/util/update_readme.py b/util/update_readme.py new file mode 100644 index 00000000000..0b54afa83ea --- /dev/null +++ b/util/update_readme.py @@ -0,0 +1,80 @@ +# Generate a Markdown table of all lints, and put it in README.md. +# With -n option, only print the new table to stdout. + +import os +import re +import sys + +declare_lint_re = re.compile(r''' + declare_lint! \s* [{(] \s* + pub \s+ (?P<name>[A-Z_]+) \s*,\s* + (?P<level>Forbid|Deny|Warn|Allow) \s*,\s* + " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] +''', re.X | re.S) + +nl_escape_re = re.compile(r'\\\n\s*') + + +def collect(lints, fp): + code = fp.read() + for match in declare_lint_re.finditer(code): + # remove \-newline escapes from description string + desc = nl_escape_re.sub('', match.group('desc')) + lints.append((match.group('name').lower(), + match.group('level').lower(), + desc.replace('\\"', '"'))) + + +def write_tbl(lints, fp): + # first and third column widths + w_name = max(len(l[0]) for l in lints) + w_desc = max(len(l[2]) for l in lints) + # header and underline + fp.write('%-*s | default | meaning\n' % (w_name, 'name')) + fp.write('%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc)) + # one table row per lint + for (name, default, meaning) in sorted(lints): + fp.write('%-*s | %-7s | %s\n' % (w_name, name, default, meaning)) + + +def main(print_only=False): + lints = [] + + # check directory + if not os.path.isfile('src/lib.rs'): + print('Error: call this script from clippy checkout directory!') + return + + # collect all lints from source files + for root, dirs, files in os.walk('src'): + for fn in files: + if fn.endswith('.rs'): + with open(os.path.join(root, fn)) as fp: + collect(lints, fp) + + if print_only: + write_tbl(lints, sys.stdout) + return + + # read current README.md content + with open('README.md') as fp: + lines = list(fp) + + # replace old table with new table + with open('README.md', 'w') as fp: + in_old_tbl = False + for line in lines: + if line.replace(' ', '').strip() == 'name|default|meaning': + # old table starts here + write_tbl(lints, fp) + in_old_tbl = True + if in_old_tbl: + # the old table is finished by an empty line + if line.strip(): + continue + in_old_tbl = False + fp.write(line) + + +if __name__ == '__main__': + main(print_only='-n' in sys.argv) -- cgit 1.4.1-3-g733a5 From ea0cf2a29685a0939c4ad0a04ea1aada608b8731 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 11:31:09 +0200 Subject: update script: also generate lint list in lib.rs --- src/lib.rs | 71 ++++++++++++++++---------------- util/update_lints.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/update_readme.py | 80 ------------------------------------ 3 files changed, 146 insertions(+), 115 deletions(-) create mode 100644 util/update_lints.py delete mode 100644 util/update_readme.py (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index eb2704cd4bd..9fc5def88c4 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,39 +64,40 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); - reg.register_lint_group("clippy", vec![types::BOX_VEC, - types::LINKEDLIST, - types::LET_UNIT_VALUE, - misc::SINGLE_MATCH, - misc::TOPLEVEL_REF_ARG, - misc::CMP_NAN, - misc::FLOAT_CMP, - misc::PRECEDENCE, - misc::CMP_OWNED, - eq_op::EQ_OP, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - ptr_arg::PTR_ARG, - needless_bool::NEEDLESS_BOOL, - approx_const::APPROX_CONSTANT, - eta_reduction::REDUNDANT_CLOSURE, - identity_op::IDENTITY_OP, - mut_mut::MUT_MUT, - len_zero::LEN_ZERO, - len_zero::LEN_WITHOUT_IS_EMPTY, - attrs::INLINE_ALWAYS, - collapsible_if::COLLAPSIBLE_IF, - unicode::ZERO_WIDTH_SPACE, - unicode::NON_ASCII_LITERAL, - strings::STRING_ADD_ASSIGN, - returns::NEEDLESS_RETURN, - returns::LET_AND_RETURN, - misc::MODULO_ONE, - methods::OPTION_UNWRAP_USED, - methods::RESULT_UNWRAP_USED, - methods::STR_TO_STRING, - methods::STRING_TO_STRING, - lifetimes::NEEDLESS_LIFETIMES, - loops::NEEDLESS_RANGE_LOOP, - ]); + reg.register_lint_group("clippy", vec![ + approx_const::APPROX_CONSTANT, + attrs::INLINE_ALWAYS, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + collapsible_if::COLLAPSIBLE_IF, + eq_op::EQ_OP, + eta_reduction::REDUNDANT_CLOSURE, + identity_op::IDENTITY_OP, + len_zero::LEN_WITHOUT_IS_EMPTY, + len_zero::LEN_ZERO, + lifetimes::NEEDLESS_LIFETIMES, + loops::NEEDLESS_RANGE_LOOP, + methods::OPTION_UNWRAP_USED, + methods::RESULT_UNWRAP_USED, + methods::STR_TO_STRING, + methods::STRING_TO_STRING, + misc::CMP_NAN, + misc::CMP_OWNED, + misc::FLOAT_CMP, + misc::MODULO_ONE, + misc::PRECEDENCE, + misc::SINGLE_MATCH, + misc::TOPLEVEL_REF_ARG, + mut_mut::MUT_MUT, + needless_bool::NEEDLESS_BOOL, + ptr_arg::PTR_ARG, + returns::LET_AND_RETURN, + returns::NEEDLESS_RETURN, + strings::STRING_ADD_ASSIGN, + types::BOX_VEC, + types::LET_UNIT_VALUE, + types::LINKEDLIST, + unicode::NON_ASCII_LITERAL, + unicode::ZERO_WIDTH_SPACE, + ]); } diff --git a/util/update_lints.py b/util/update_lints.py new file mode 100644 index 00000000000..c2a9e08c993 --- /dev/null +++ b/util/update_lints.py @@ -0,0 +1,110 @@ +# Generate a Markdown table of all lints, and put it in README.md. +# With -n option, only print the new table to stdout. + +import os +import re +import sys + +declare_lint_re = re.compile(r''' + declare_lint! \s* [{(] \s* + pub \s+ (?P<name>[A-Z_]+) \s*,\s* + (?P<level>Forbid|Deny|Warn|Allow) \s*,\s* + " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] +''', re.X | re.S) + +nl_escape_re = re.compile(r'\\\n\s*') + + +def collect(lints, fn): + """Collect all lints from a file. + + Adds entries to the lints list as `(module, name, level, desc)`. + """ + with open(fn) as fp: + code = fp.read() + for match in declare_lint_re.finditer(code): + # remove \-newline escapes from description string + desc = nl_escape_re.sub('', match.group('desc')) + lints.append((os.path.splitext(os.path.basename(fn))[0], + match.group('name').lower(), + match.group('level').lower(), + desc.replace('\\"', '"'))) + + +def write_tbl(lints, fp): + """Write lint table in Markdown format.""" + # first and third column widths + w_name = max(len(l[1]) for l in lints) + w_desc = max(len(l[3]) for l in lints) + # header and underline + fp.write('%-*s | default | meaning\n' % (w_name, 'name')) + fp.write('%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc)) + # one table row per lint + for (_, name, default, meaning) in sorted(lints, key=lambda l: l[1]): + fp.write('%-*s | %-7s | %s\n' % (w_name, name, default, meaning)) + + +def write_group(lints, fp): + """Write lint group (list of all lints in the form module::NAME).""" + for (module, name, _, _) in sorted(lints): + fp.write(' %s::%s,\n' % (module, name.upper())) + + +def replace_region(fn, region_start, region_end, callback, + replace_start=True): + """Replace a region in a file delimited by two lines matching regexes. + + A callback is called to write the new region. If `replace_start` is true, + the start delimiter line is replaced as well. The end delimiter line is + never replaced. + """ + # read current content + with open(fn) as fp: + lines = list(fp) + + # replace old region with new region + with open(fn, 'w') as fp: + in_old_region = False + for line in lines: + if in_old_region: + if re.search(region_end, line): + in_old_region = False + fp.write(line) + elif re.search(region_start, line): + if not replace_start: + fp.write(line) + # old region starts here + in_old_region = True + callback(fp) + else: + fp.write(line) + + +def main(print_only=False): + lints = [] + + # check directory + if not os.path.isfile('src/lib.rs'): + print('Error: call this script from clippy checkout directory!') + return + + # collect all lints from source files + for root, dirs, files in os.walk('src'): + for fn in files: + if fn.endswith('.rs'): + collect(lints, os.path.join(root, fn)) + + if print_only: + write_tbl(lints, sys.stdout) + return + + # replace table in README.md + replace_region('README.md', r'^name +\|', '^$', lambda fp: write_tbl(lints, fp)) + + # same for "clippy" lint collection + replace_region('src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', + lambda fp: write_group(lints, fp), replace_start=False) + + +if __name__ == '__main__': + main(print_only='-n' in sys.argv) diff --git a/util/update_readme.py b/util/update_readme.py deleted file mode 100644 index 0b54afa83ea..00000000000 --- a/util/update_readme.py +++ /dev/null @@ -1,80 +0,0 @@ -# Generate a Markdown table of all lints, and put it in README.md. -# With -n option, only print the new table to stdout. - -import os -import re -import sys - -declare_lint_re = re.compile(r''' - declare_lint! \s* [{(] \s* - pub \s+ (?P<name>[A-Z_]+) \s*,\s* - (?P<level>Forbid|Deny|Warn|Allow) \s*,\s* - " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] -''', re.X | re.S) - -nl_escape_re = re.compile(r'\\\n\s*') - - -def collect(lints, fp): - code = fp.read() - for match in declare_lint_re.finditer(code): - # remove \-newline escapes from description string - desc = nl_escape_re.sub('', match.group('desc')) - lints.append((match.group('name').lower(), - match.group('level').lower(), - desc.replace('\\"', '"'))) - - -def write_tbl(lints, fp): - # first and third column widths - w_name = max(len(l[0]) for l in lints) - w_desc = max(len(l[2]) for l in lints) - # header and underline - fp.write('%-*s | default | meaning\n' % (w_name, 'name')) - fp.write('%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc)) - # one table row per lint - for (name, default, meaning) in sorted(lints): - fp.write('%-*s | %-7s | %s\n' % (w_name, name, default, meaning)) - - -def main(print_only=False): - lints = [] - - # check directory - if not os.path.isfile('src/lib.rs'): - print('Error: call this script from clippy checkout directory!') - return - - # collect all lints from source files - for root, dirs, files in os.walk('src'): - for fn in files: - if fn.endswith('.rs'): - with open(os.path.join(root, fn)) as fp: - collect(lints, fp) - - if print_only: - write_tbl(lints, sys.stdout) - return - - # read current README.md content - with open('README.md') as fp: - lines = list(fp) - - # replace old table with new table - with open('README.md', 'w') as fp: - in_old_tbl = False - for line in lines: - if line.replace(' ', '').strip() == 'name|default|meaning': - # old table starts here - write_tbl(lints, fp) - in_old_tbl = True - if in_old_tbl: - # the old table is finished by an empty line - if line.strip(): - continue - in_old_tbl = False - fp.write(line) - - -if __name__ == '__main__': - main(print_only='-n' in sys.argv) -- cgit 1.4.1-3-g733a5 From 71b46d9ecdd4adac122199669596370b14a4bb02 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 13 Aug 2015 11:35:30 +0200 Subject: improved string_add/string_add_assign messages, Allow-by-default string_add_assign --- README.md | 2 +- src/strings.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 4644bac94cd..d2e5049f8e1 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Lints included in this crate: - `inline_always`: Warns on `#[inline(always)]`, because in most cases it is a bad idea - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` - `zero_width_space`: Warns on encountering a unicode zero-width space - - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. + - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. Allowed by default. - `string_add`: Matches `x + ..` where `x` is a `String` and where `string_add_assign` doesn't warn. Allowed by default. - `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice. - `let_and_return`: Warns on doing `let x = expr; x` at the end of a function. diff --git a/src/strings.rs b/src/strings.rs index 33db980c065..226b851e991 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -13,14 +13,15 @@ use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { pub STRING_ADD_ASSIGN, - Warn, - "Warn on `x = x + ..` where x is a `String`" + Allow, + "expressions of the form `x = x + ..` where x is a `String`" } declare_lint! { pub STRING_ADD, Allow, - "Warn on `x + ..` where x is a `String`" + "expressions of the form `x + ..` where x is a `String` \ + unless `string_add_assign` matches" } #[derive(Copy, Clone)] -- cgit 1.4.1-3-g733a5 From 0b08e9e83eb155188a5129f0d01bb09c7306d3b5 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 15:50:56 +0200 Subject: added string_add lint and fixed string_add_assign + test --- README.md | 1 + src/lib.rs | 1 + src/strings.rs | 47 +++++++++++++++++++++++++++++++++++++++---- tests/compile-fail/strings.rs | 13 ++++++++---- 4 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index b61f3561302..1dd8f5eaec6 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Lints included in this crate: - `collapsible_if`: Warns on cases where two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` - `zero_width_space`: Warns on encountering a unicode zero-width space - `string_add_assign`: Warns on `x = x + ..` where `x` is a `String` and suggests using `push_str(..)` instead. + - `string_add`: Matches `x + ..` where `x` is a `String` and where `string_add_assign` doesn't warn. Allowed by default. - `needless_return`: Warns on using `return expr;` when a simple `expr` would suffice. - `let_and_return`: Warns on doing `let x = expr; x` at the end of a function. - `option_unwrap_used`: Warns when `Option.unwrap()` is used, and suggests `.expect()`. diff --git a/src/lib.rs b/src/lib.rs index f788c72db3c..e6703e6bb28 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); + reg.register_lint_pass(box strings::StringAddAssign as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); diff --git a/src/strings.rs b/src/strings.rs index afc444dd67f..89fc18fd0c5 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -9,7 +9,7 @@ use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use eq_op::is_exp_equal; use types::match_ty_unwrap; -use utils::{match_def_path, span_lint, walk_ptrs_ty}; +use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { pub STRING_ADD_ASSIGN, @@ -17,10 +17,48 @@ declare_lint! { "Warn on `x = x + ..` where x is a `String`" } -#[derive(Copy,Clone)] +declare_lint! { + pub STRING_ADD, + Allow, + "Warn on `x + ..` where x is a `String`" +} + +#[derive(Copy, Clone)] pub struct StringAdd; impl LintPass for StringAdd { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_ADD) + } + + fn check_expr(&mut self, cx: &Context, e: &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) { + // the string_add_assign is allow, so no duplicates + } else { + let parent = get_parent_expr(cx, e); + if let Some(ref p) = parent { + if let &ExprAssign(ref target, _) = &p.node { + // avoid duplicate matches + if is_exp_equal(target, left) { return; } + } + } + } + //TODO check for duplicates + span_lint(cx, STRING_ADD, e.span, + "you add something to a string. \ + Consider using `String::push_str()` instead.") + } + } + } +} + + +#[derive(Copy, Clone)] +pub struct StringAddAssign; + +impl LintPass for StringAddAssign { fn get_lints(&self) -> LintArray { lint_array!(STRING_ADD_ASSIGN) } @@ -37,8 +75,9 @@ impl LintPass for StringAdd { } fn is_string(cx: &Context, e: &Expr) -> bool { - if let TyStruct(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(e)).sty { - match_def_path(cx, did.did, &["std", "string", "String"]) + let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + if let TyStruct(did, _) = ty.sty { + match_def_path(cx, did.did, &["collections", "string", "String"]) } else { false } } diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 4b6f0bc884f..e898a087d08 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -2,11 +2,16 @@ #![plugin(clippy)] #![deny(string_add_assign)] - +#![deny(string_add)] fn main() { - let x = "".to_owned(); + let mut x = "".to_owned(); - for i in (1..3) { - x = x + "."; //~ERROR + for _ in (1..3) { + x = x + "."; //~ERROR you assign the result of adding something to this string. } + + let y = "".to_owned(); + let z = y + "..."; //~ERROR you add something to a string. + + assert_eq!(&x, &z); } -- cgit 1.4.1-3-g733a5 From 52c0cf5a9d4076dfe827f33f409e0a4da5069b8b Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 15:57:50 +0200 Subject: fixed formatting --- src/strings.rs | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index 89fc18fd0c5..568b27bd355 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -18,9 +18,9 @@ declare_lint! { } declare_lint! { - pub STRING_ADD, - Allow, - "Warn on `x + ..` where x is a `String`" + pub STRING_ADD, + Allow, + "Warn on `x + ..` where x is a `String`" } #[derive(Copy, Clone)] @@ -32,26 +32,26 @@ impl LintPass for StringAdd { } fn check_expr(&mut self, cx: &Context, e: &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) { - // the string_add_assign is allow, so no duplicates - } else { - let parent = get_parent_expr(cx, e); - if let Some(ref p) = parent { - if let &ExprAssign(ref target, _) = &p.node { - // avoid duplicate matches - if is_exp_equal(target, left) { return; } - } - } - } - //TODO check for duplicates - span_lint(cx, STRING_ADD, e.span, - "you add something to a string. \ - Consider using `String::push_str()` instead.") - } - } - } + if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node { + if is_string(cx, left) { + if let Allow = cx.current_level(STRING_ADD_ASSIGN) { + // the string_add_assign is allow, so no duplicates + } else { + let parent = get_parent_expr(cx, e); + if let Some(ref p) = parent { + if let &ExprAssign(ref target, _) = &p.node { + // avoid duplicate matches + if is_exp_equal(target, left) { return; } + } + } + } + //TODO check for duplicates + span_lint(cx, STRING_ADD, e.span, + "you add something to a string. \ + Consider using `String::push_str()` instead.") + } + } + } } @@ -75,7 +75,7 @@ impl LintPass for StringAddAssign { } fn is_string(cx: &Context, e: &Expr) -> bool { - let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); if let TyStruct(did, _) = ty.sty { match_def_path(cx, did.did, &["collections", "string", "String"]) } else { false } -- cgit 1.4.1-3-g733a5 From f9e851e212e08174917aa724b5e56a92d9584cdf Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 16:42:42 +0200 Subject: pulled strings passes together, added more tests --- src/lib.rs | 1 - src/strings.rs | 18 ++--------------- tests/compile-fail/strings.rs | 45 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index e6703e6bb28..f788c72db3c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,6 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); - reg.register_lint_pass(box strings::StringAddAssign as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); diff --git a/src/strings.rs b/src/strings.rs index 568b27bd355..85e6501d336 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -28,7 +28,7 @@ pub struct StringAdd; impl LintPass for StringAdd { fn get_lints(&self) -> LintArray { - lint_array!(STRING_ADD) + lint_array!(STRING_ADD, STRING_ADD_ASSIGN) } fn check_expr(&mut self, cx: &Context, e: &Expr) { @@ -50,21 +50,7 @@ impl LintPass for StringAdd { "you add something to a string. \ Consider using `String::push_str()` instead.") } - } - } -} - - -#[derive(Copy, Clone)] -pub struct StringAddAssign; - -impl LintPass for StringAddAssign { - fn get_lints(&self) -> LintArray { - lint_array!(STRING_ADD_ASSIGN) - } - - fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let &ExprAssign(ref target, ref src) = &e.node { + } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assign the result of adding something to this string. \ diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index e898a087d08..02ebca2fe07 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -1,9 +1,37 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(string_add_assign)] -#![deny(string_add)] -fn main() { +#[deny(string_add)] +#[allow(string_add_assign)] +fn add_only() { // ignores assignment distinction + let mut x = "".to_owned(); + + for _ in (1..3) { + x = x + "."; //~ERROR you add something to a string. + } + + let y = "".to_owned(); + let z = y + "..."; //~ERROR you add something to a string. + + assert_eq!(&x, &z); +} + +#[deny(string_add_assign)] +fn add_assign_only() { + let mut x = "".to_owned(); + + for _ in (1..3) { + x = x + "."; //~ERROR you assign the result of adding something to this string. + } + + let y = "".to_owned(); + let z = y + "..."; + + assert_eq!(&x, &z); +} + +#[deny(string_add, string_add_assign)] +fn both() { let mut x = "".to_owned(); for _ in (1..3) { @@ -15,3 +43,14 @@ fn main() { assert_eq!(&x, &z); } + +fn main() { + add_only(); + add_assign_only(); + both(); + + // the add is only caught for String + let mut x = 1; + x = x + 1; + assert_eq!(2, x); +} -- cgit 1.4.1-3-g733a5 From 9e786d3956c5500af94c9ae3eddb5fc7e58b0c67 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 16:50:43 +0200 Subject: added `string_add` to `clippy` lint group --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f788c72db3c..436ba6cbf80 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,7 @@ pub fn plugin_registrar(reg: &mut Registry) { unicode::ZERO_WIDTH_SPACE, unicode::NON_ASCII_LITERAL, strings::STRING_ADD_ASSIGN, + strings::STRING_ADD, returns::NEEDLESS_RETURN, misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, -- cgit 1.4.1-3-g733a5 From a00270c5b14013c4129fedfe076d4fea227f6102 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Wed, 12 Aug 2015 21:17:21 +0200 Subject: grammar --- src/strings.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index 85e6501d336..50971962f90 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -13,14 +13,14 @@ use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { pub STRING_ADD_ASSIGN, - Warn, - "Warn on `x = x + ..` where x is a `String`" + Allow, + "expressions of the form `x = x + ..` where x is a `String`" } declare_lint! { pub STRING_ADD, Allow, - "Warn on `x + ..` where x is a `String`" + "expressions of the form on `x + ..` where x is a `String`" } #[derive(Copy, Clone)] @@ -47,14 +47,14 @@ impl LintPass for StringAdd { } //TODO check for duplicates span_lint(cx, STRING_ADD, e.span, - "you add something to a string. \ + "you added something to a string. \ Consider using `String::push_str()` instead.") } } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, - "you assign the result of adding something to this string. \ - Consider using `String::push_str()` instead") + "you assigned the result of adding something to this string. \ + Consider using `String::push_str()` instead.") } } } -- cgit 1.4.1-3-g733a5 From 6aa36e9deb9191ae8414b433d49c71ac37475cea Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 13 Aug 2015 14:22:05 +0200 Subject: initial addition and subtraction for bytes and ints --- src/const.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/const.rs b/src/const.rs index cef2cd7f9fc..bc53c1062dc 100644 --- a/src/const.rs +++ b/src/const.rs @@ -222,11 +222,75 @@ fn neg_float_str(s: &InternedString) -> Cow<'static, str> { } } +fn is_negative(ty: LitIntType) -> bool { + match ty { + SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, + UnsignedIntLit(_) => false, + } +} + +fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option(LitIntType) { + match (l, r) { + (SignedIntLit(lty, _), SignedIntLit(rty, _)) => if lty == rty { + Some(SignedIntLit(lty, s)) } else { None }, + (UnsignedIntLit(lty), UnsignedIntLit(rty)) => + if Sign == Plus && lty == rty { + Some(UnsignedIntLit(lty)) + } else { None }, + (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => UnsuffixedIntLit(s), + (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => SignedIntLit(lty, s), + (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => if rs == Plus { + Some(UnsignedIntLit(lty)) } else { None }, + (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => SignedIntLit(rty, s), + (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => if ls == Plus { + Some(UnsignedIntLit(rty)) } else { None }, + _ => None, + } +} + fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { match op.node { - //BiAdd, - //BiSub, + BiAdd => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => + l8.checked_add(r8).map(|v| ConstantByte(v)), + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + if ln == rn { + unify_int_type(lty, rty, if ln { Minus } else { Plus }) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))) + } else { + if ln { + add_neg_int(r64, rty, l64, lty) + } else { + add_neg_int(l64, lty, r64, rty) + } + } + }, + // TODO: float + _ => None + }), + BiSub => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { + None } else { Some(ConstantByte(l8 - r8)) }, + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + match (ln, rn) { + (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), + (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), + (true, false) => unify_int_type(lty, rty, Minus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + (false, true) => unify_int_type(lty, rty, Plus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + } + }, + _ => None, + }), //BiMul, //BiDiv, //BiRem, @@ -247,6 +311,21 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) } } +fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> + Some(Constant) { + if neg > pos { + unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) + } else { + unify_int_type(nty, pty, Plus).map(|ty| ConstantInt(pos - neg, ty)) + } +} + +fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: Bool) -> + Option<Constant> { + unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( + |ty| l64.checked_sub(r64).map(|v| ConstantInt(v, ty))) +} + fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F) -> Option<Constant> where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> { -- cgit 1.4.1-3-g733a5 From e03b71606ba7682e46603302a679ecdc30ce8373 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 10:32:35 +0200 Subject: update_lints: add a check mode for travis runs --- .travis.yml | 1 + README.md | 4 +-- src/strings.rs | 8 +++--- util/update_lints.py | 77 ++++++++++++++++++++++++++++++++-------------------- 4 files changed, 54 insertions(+), 36 deletions(-) mode change 100644 => 100755 util/update_lints.py (limited to 'src') diff --git a/.travis.yml b/.travis.yml index 0f9d6128eb8..e14785c9211 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,6 @@ rust: nightly sudo: false script: + - python util/update_lints.py -c - cargo build - cargo test diff --git a/README.md b/README.md index 5f9f59c31e5..f6b65b952d4 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (wh result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` -string_add | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -string_add_assign | allow | expressions of the form `x = x + ..` where x is a `String` +string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead string_to_string | warn | calling `String.to_string()` which is a no-op toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) zero_width_space | deny | using a zero-width space in a string literal, which is confusing diff --git a/src/strings.rs b/src/strings.rs index 84512dfe7f8..7b7bab49b5d 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -14,13 +14,13 @@ use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { pub STRING_ADD_ASSIGN, Allow, - "expressions of the form `x = x + ..` where x is a `String`" + "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" } declare_lint! { pub STRING_ADD, Allow, - "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" + "using `x + ..` where x is a `String`; suggests using `push_str()` instead" } #[derive(Copy, Clone)] @@ -48,13 +48,13 @@ impl LintPass for StringAdd { //TODO check for duplicates span_lint(cx, STRING_ADD, e.span, "you added something to a string. \ - Consider using `String::push_str()` instead.") + Consider using `String::push_str()` instead") } } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ - Consider using `String::push_str()` instead.") + Consider using `String::push_str()` instead") } } } diff --git a/util/update_lints.py b/util/update_lints.py old mode 100644 new mode 100755 index c2a9e08c993..ed26637059f --- a/util/update_lints.py +++ b/util/update_lints.py @@ -1,5 +1,7 @@ +#!/usr/bin/env python # Generate a Markdown table of all lints, and put it in README.md. # With -n option, only print the new table to stdout. +# With -c option, print a warning and set exit status to 1 if a file would be changed. import os import re @@ -31,27 +33,27 @@ def collect(lints, fn): desc.replace('\\"', '"'))) -def write_tbl(lints, fp): +def gen_table(lints): """Write lint table in Markdown format.""" # first and third column widths w_name = max(len(l[1]) for l in lints) w_desc = max(len(l[3]) for l in lints) # header and underline - fp.write('%-*s | default | meaning\n' % (w_name, 'name')) - fp.write('%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc)) + yield '%-*s | default | meaning\n' % (w_name, 'name') + yield '%s-|-%s-|-%s\n' % ('-' * w_name, '-' * 7, '-' * w_desc) # one table row per lint for (_, name, default, meaning) in sorted(lints, key=lambda l: l[1]): - fp.write('%-*s | %-7s | %s\n' % (w_name, name, default, meaning)) + yield '%-*s | %-7s | %s\n' % (w_name, name, default, meaning) -def write_group(lints, fp): +def gen_group(lints): """Write lint group (list of all lints in the form module::NAME).""" for (module, name, _, _) in sorted(lints): - fp.write(' %s::%s,\n' % (module, name.upper())) + yield ' %s::%s,\n' % (module, name.upper()) def replace_region(fn, region_start, region_end, callback, - replace_start=True): + replace_start=True, write_back=True): """Replace a region in a file delimited by two lines matching regexes. A callback is called to write the new region. If `replace_start` is true, @@ -63,24 +65,32 @@ def replace_region(fn, region_start, region_end, callback, lines = list(fp) # replace old region with new region - with open(fn, 'w') as fp: - in_old_region = False - for line in lines: - if in_old_region: - if re.search(region_end, line): - in_old_region = False - fp.write(line) - elif re.search(region_start, line): - if not replace_start: - fp.write(line) - # old region starts here - in_old_region = True - callback(fp) - else: - fp.write(line) - - -def main(print_only=False): + new_lines = [] + in_old_region = False + for line in lines: + if in_old_region: + if re.search(region_end, line): + in_old_region = False + new_lines.extend(callback()) + new_lines.append(line) + elif re.search(region_start, line): + if not replace_start: + new_lines.append(line) + # old region starts here + in_old_region = True + else: + new_lines.append(line) + + # write back to file + if write_back: + with open(fn, 'w') as fp: + fp.writelines(new_lines) + + # if something changed, return true + return lines != new_lines + + +def main(print_only=False, check=False): lints = [] # check directory @@ -95,16 +105,23 @@ def main(print_only=False): collect(lints, os.path.join(root, fn)) if print_only: - write_tbl(lints, sys.stdout) + sys.stdout.writelines(gen_table(lints)) return # replace table in README.md - replace_region('README.md', r'^name +\|', '^$', lambda fp: write_tbl(lints, fp)) + changed = replace_region('README.md', r'^name +\|', '^$', + lambda: gen_table(lints), + write_back=not check) # same for "clippy" lint collection - replace_region('src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', - lambda fp: write_group(lints, fp), replace_start=False) + changed |= replace_region('src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', + lambda: gen_group(lints), replace_start=False, + write_back=not check) + + if check and changed: + print('Please run util/update_lints.py to regenerate lints lists.') + return 1 if __name__ == '__main__': - main(print_only='-n' in sys.argv) + sys.exit(main(print_only='-n' in sys.argv, check='-c' in sys.argv)) -- cgit 1.4.1-3-g733a5 From 8a98736f51249befe9d4a4412619490f6cecfa54 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 09:44:03 +0200 Subject: spelling fix, rework needless_bool with snippet (fixes #150) --- src/needless_bool.rs | 40 +++++++++++++++++++++++-------------- tests/compile-fail/eq_op.rs | 2 +- tests/compile-fail/needless_bool.rs | 8 ++++---- 3 files changed, 30 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 6a4a55aeda5..2a4ed50b93d 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -10,7 +10,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; -use utils::{de_p, span_lint}; +use utils::{de_p, span_lint, snippet}; declare_lint! { pub NEEDLESS_BOOL, @@ -28,20 +28,30 @@ impl LintPass for NeedlessBool { } fn check_expr(&mut self, cx: &Context, e: &Expr) { - if let ExprIf(_, ref then_block, Option::Some(ref else_expr)) = e.node { + if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (Option::Some(true), Option::Some(true)) => { + (Some(true), Some(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "your if-then-else expression will always return true"); }, - (Option::Some(true), Option::Some(false)) => { + "this if-then-else expression will always return true"); }, + (Some(false), Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if statement to its predicate"); }, - (Option::Some(false), Option::Some(true)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "you can reduce your if statement to `!` + its predicate"); }, - (Option::Some(false), Option::Some(false)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, - "your if-then-else expression will always return false"); }, + "this if-then-else expression will always return false"); }, + (Some(true), Some(false)) => { + let pred_snip = snippet(cx, pred.span, ".."); + let hint = if pred_snip == ".." { "its predicate".into() } else { + format!("`{}`", pred_snip) + }; + span_lint(cx, NEEDLESS_BOOL, e.span, &format!( + "you can reduce this if-then-else expression to just {}", hint)); + }, + (Some(false), Some(true)) => { + let pred_snip = snippet(cx, pred.span, ".."); + let hint = if pred_snip == ".." { "`!` and its predicate".into() } else { + format!("`!{}`", pred_snip) + }; + span_lint(cx, NEEDLESS_BOOL, e.span, &format!( + "you can reduce this if-then-else expression to just {}", hint)); + }, _ => () } } @@ -51,14 +61,14 @@ impl LintPass for NeedlessBool { fn fetch_bool_block(block: &Block) -> Option<bool> { if block.stmts.is_empty() { block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) - } else { Option::None } + } else { None } } fn fetch_bool_expr(expr: &Expr) -> Option<bool> { match &expr.node { &ExprBlock(ref block) => fetch_bool_block(block), &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { - Option::Some(value) } else { Option::None }, - _ => Option::None + Some(value) } else { None }, + _ => None } } diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 298132013a9..8f61a11aa08 100755 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -16,7 +16,7 @@ fn main() { 1.5 < 1.5; //~ERROR equal expressions 1u64 >= 1u64; //~ERROR equal expressions - // casts, methods, parenthesis + // casts, methods, parentheses (1 as u64) & (1 as u64); //~ERROR equal expressions 1 ^ ((((((1)))))); //~ERROR equal expressions id((1)) | id(1); //~ERROR equal expressions diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index 6016f79ab03..39fdf6353fd 100755 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -4,9 +4,9 @@ #[deny(needless_bool)] fn main() { let x = true; - if x { true } else { true }; //~ERROR your if-then-else expression will always return true - if x { false } else { false }; //~ERROR your if-then-else expression will always return false - if x { true } else { false }; //~ERROR you can reduce your if statement to its predicate - if x { false } else { true }; //~ERROR you can reduce your if statement to `!` + its predicate + if x { true } else { true }; //~ERROR this if-then-else expression will always return true + if x { false } else { false }; //~ERROR this if-then-else expression will always return false + if x { true } else { false }; //~ERROR you can reduce this if-then-else expression to just `x` + if x { false } else { true }; //~ERROR you can reduce this if-then-else expression to just `!x` if x { x } else { false }; // would also be questionable, but we don't catch this yet } -- cgit 1.4.1-3-g733a5 From 957840363802eb817e1285f0879c8474caff465d Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 15:36:31 +0200 Subject: new lint: looping over x.iter() or x.iter_mut() (fixes #157) --- README.md | 1 + src/attrs.rs | 2 +- src/lib.rs | 1 + src/loops.rs | 35 +++++++++++++++++++++++++++++------ src/types.rs | 2 +- tests/compile-fail/for_loop.rs | 10 ++++++++-- 6 files changed, 41 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index f6b65b952d4..dd7d0158f03 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ cmp_nan | deny | comparisons to NAN (which will always return fa cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +explicit_iter_loop | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` diff --git a/src/attrs.rs b/src/attrs.rs index ca5b6c55ced..ef3320d2543 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -64,7 +64,7 @@ fn is_relevant_trait(item: &TraitItem) -> bool { } fn is_relevant_block(block: &Block) -> bool { - for stmt in block.stmts.iter() { + for stmt in &block.stmts { match stmt.node { StmtDecl(_, _) => return true, StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { diff --git a/src/lib.rs b/src/lib.rs index 4c29b8f1b79..7cb2877b2fd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,6 +76,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, + loops::EXPLICIT_ITER_LOOP, loops::NEEDLESS_RANGE_LOOP, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/src/loops.rs b/src/loops.rs index b406bc67961..bfb5ad6861d 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -3,25 +3,29 @@ use syntax::ast::*; use syntax::visit::{Visitor, walk_expr}; use std::collections::HashSet; -use utils::{span_lint, get_parent_expr}; +use utils::{snippet, span_lint, get_parent_expr}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, "for-looping over a range of indices where an iterator over items would do" } +declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, + "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP) + lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let Some((pat, arg, body)) = recover_for_loop(expr) { - // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { - // the iteratee must be a range literal - if let ExprRange(_, _) = arg.node { + // check for looping over a range and then indexing a sequence with it + // -> the iteratee must be a range literal + if let ExprRange(_, _) = arg.node { + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { let mut visitor = VarVisitor { cx: cx, var: ident.node.name, indexed: HashSet::new(), nonindex: false }; walk_expr(&mut visitor, body); @@ -43,6 +47,25 @@ impl LintPass for LoopsPass { } } } + + // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x + if let ExprMethodCall(ref method, _, ref args) = arg.node { + // just the receiver, no arguments to iter() or iter_mut() + if args.len() == 1 { + let method_name = method.node.name.as_str(); + if method_name == "iter" { + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( + "it is more idiomatic to loop over `&{}` instead of `{}.iter()`", + object, object)); + } else if method_name == "iter_mut" { + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( + "it is more idiomatic to loop over `&mut {}` instead of `{}.iter_mut()`", + object, object)); + } + } + } } } } diff --git a/src/types.rs b/src/types.rs index ad7b767d95e..53d8850c59d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -67,7 +67,7 @@ impl LintPass for TypePass { let dlists = [vec!["std","collections","linked_list","LinkedList"], vec!["std","collections","linked_list","LinkedList"], vec!["collections","linked_list","LinkedList"]]; - for path in dlists.iter() { + for path in &dlists { if match_ty_unwrap(ty, &path[..]).is_some() { span_help_and_lint(cx, LINKEDLIST, ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 318e6fc8588..550f9869291 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -1,9 +1,9 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(needless_range_loop)] +#[deny(needless_range_loop, explicit_iter_loop)] fn main() { - let vec = vec![1, 2, 3, 4]; + let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; for i in 0..vec.len() { //~ERROR the loop variable `i` is only used to index `vec`. println!("{}", vec[i]); @@ -14,4 +14,10 @@ fn main() { for i in 0..vec.len() { // not an error, indexing more than one variable println!("{} {}", vec[i], vec2[i]); } + + for _v in vec.iter() { } //~ERROR it is more idiomatic to loop over `&vec` + for _v in vec.iter_mut() { } //~ERROR it is more idiomatic to loop over `&mut vec` + + for _v in &vec { } // these are fine + for _v in &mut vec { } // these are fine } -- cgit 1.4.1-3-g733a5 From 5eab397e7c9840bd01f9ca165428e8eb4156cdc4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 19:58:11 +0530 Subject: Some fixes from dogfooding clippy --- src/eq_op.rs | 1 + src/lib.rs | 2 +- src/lifetimes.rs | 2 +- src/loops.rs | 4 ++-- src/utils.rs | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 495696b810c..0b7511e7dbd 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,3 +1,4 @@ +#![allow(redundant_closure)] // FIXME (#116) use rustc::lint::*; use syntax::ast::*; use syntax::ast_util as ast_util; diff --git a/src/lib.rs b/src/lib.rs index 7cb2877b2fd..9135ecaca6c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] -#![allow(unused_imports)] +#![allow(unused_imports, unknown_lints)] #[macro_use] extern crate syntax; diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 644537f9be1..25be8874691 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -103,7 +103,7 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { } /// Number of unique lifetimes in the given vector. -fn unique_lifetimes(lts: &Vec<RefLt>) -> usize { +fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::<HashSet<_>>().len() } diff --git a/src/loops.rs b/src/loops.rs index bfb5ad6861d..937e95970ef 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -31,7 +31,7 @@ impl LintPass for LoopsPass { walk_expr(&mut visitor, body); // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().unwrap(); + let indexed = visitor.indexed.into_iter().next().expect("Len was nonzero, but no contents found"); if visitor.nonindex { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is used to index `{}`. Consider using \ @@ -72,7 +72,7 @@ impl LintPass for LoopsPass { /// Recover the essential nodes of a desugared for loop: /// `for pat in arg { body }` becomes `(pat, arg, body)`. -fn recover_for_loop<'a>(expr: &'a Expr) -> Option<(&'a Pat, &'a Expr, &'a Expr)> { +fn recover_for_loop<'a>(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { if_let_chain! { [ let ExprMatch(ref iterexpr, ref arms, _) = expr.node, diff --git a/src/utils.rs b/src/utils.rs index 220dc6215fd..c54a7f56f7e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -86,7 +86,7 @@ pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, } /// return the base type for references and raw pointers -pub fn walk_ptrs_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> { +pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), _ => ty -- cgit 1.4.1-3-g733a5 From c2bdc8571552ad74af18f71e8d026846947615e4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 19:59:14 +0530 Subject: oh the irony --- src/lifetimes.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 25be8874691..03b4de6c948 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -130,15 +130,15 @@ impl RefVisitor { impl<'v> Visitor<'v> for RefVisitor { // for lifetimes of references - fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { + fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &Option<Lifetime>) { self.record(lifetime); } // for lifetimes as parameters of generics - fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) { self.record(&Some(*lifetime)); } // for lifetime bounds; the default impl calls visit_lifetime_ref - fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { } + fn visit_lifetime_bound(&mut self, _: &Lifetime) { } } -- cgit 1.4.1-3-g733a5 From 09db7f3fee25684ab0783ae80595fcc227ad0074 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 20:11:51 +0530 Subject: fix --- src/collapsible_if.rs | 6 +++++- src/loops.rs | 5 ++--- src/misc.rs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index f0f53622c47..be34458e0dc 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -45,8 +45,12 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if in_macro(cx, info) { return; } if let ExprIf(ref check, ref then, None) = e.node { - if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), ..}) = + if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = single_stmt_of_block(then) { + if e.span.expn_id != sp.expn_id { + return; + } + cx.sess().note(&format!("{:?} -- {:?}", e.span, sp)); span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", &format!("try\nif {} && {} {}", diff --git a/src/loops.rs b/src/loops.rs index 937e95970ef..74015bdc6be 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -72,13 +72,12 @@ impl LintPass for LoopsPass { /// Recover the essential nodes of a desugared for loop: /// `for pat in arg { body }` becomes `(pat, arg, body)`. -fn recover_for_loop<'a>(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { +fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { if_let_chain! { [ let ExprMatch(ref iterexpr, ref arms, _) = expr.node, let ExprCall(_, ref iterargs) = iterexpr.node, - iterargs.len() == 1, - arms.len() == 1 && arms[0].guard.is_none(), + iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), let ExprLoop(ref block, _) = arms[0].body.node, block.stmts.is_empty(), let Some(ref loopexpr) = block.expr, diff --git a/src/misc.rs b/src/misc.rs index 6c9a7d92ce8..7372bfed6c5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -73,7 +73,7 @@ impl LintPass for TopLevelRefPass { } fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - for ref arg in decl.inputs.iter() { + for ref arg in &decl.inputs { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { span_lint(cx, TOPLEVEL_REF_ARG, -- cgit 1.4.1-3-g733a5 From 49e51fe65a7762841aa7421b4c643b042c4fe4c6 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 13 Aug 2015 17:24:47 +0200 Subject: lifetimes: try to fix w.r.t. lifetimes from parent scopes (fixes #162) --- src/lifetimes.rs | 60 ++++++++++++++++++++++++++++++++++------- tests/compile-fail/lifetimes.rs | 7 +++-- 2 files changed, 55 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 03b4de6c948..c333f04ab44 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -18,14 +18,23 @@ impl LintPass for LifetimePass { lint_array!(NEEDLESS_LIFETIMES) } - fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, - _: &Block, span: Span, _: NodeId) { - if in_external_macro(cx, span) { - return; + fn check_item(&mut self, cx: &Context, item: &Item) { + if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { + check_fn_inner(cx, decl, None, &generics.lifetimes, item.span); } - if could_use_elision(kind, decl) { - span_lint(cx, NEEDLESS_LIFETIMES, span, - "explicit lifetimes given in parameter types where they could be elided"); + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + if let MethodImplItem(ref sig, _) = item.node { + check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + &sig.generics.lifetimes, item.span); + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + if let MethodTraitItem(ref sig, _) = item.node { + check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + &sig.generics.lifetimes, item.span); } } } @@ -39,10 +48,34 @@ enum RefLt { } use self::RefLt::*; -fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { +fn check_fn_inner(cx: &Context, decl: &FnDecl, slf: Option<&ExplicitSelf>, + named_lts: &[LifetimeDef], span: Span) { + if in_external_macro(cx, span) { + return; + } + if could_use_elision(decl, slf, named_lts) { + span_lint(cx, NEEDLESS_LIFETIMES, span, + "explicit lifetimes given in parameter types where they could be elided"); + } +} + +fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, + named_lts: &[LifetimeDef]) -> 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 + // All lifetimes must be unnamed, 'static or defined without bounds on the + // level of the current item. + + // check named LTs + let mut allowed_lts = HashSet::new(); + for lt in named_lts { + if lt.bounds.is_empty() { + allowed_lts.insert(Named(lt.lifetime.name)); + } + } + allowed_lts.insert(Unnamed); + allowed_lts.insert(Static); // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor(Vec::new()); @@ -50,8 +83,8 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { // extract lifetime in "self" argument for methods (there is a "self" argument // in func.inputs, but its type is TyInfer) - if let FnKind::FkMethod(_, sig, _) = kind { - match sig.explicit_self.node { + if let Some(slf) = slf { + match slf.node { SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt), SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty), _ => { } @@ -69,6 +102,13 @@ fn could_use_elision(kind: FnKind, func: &FnDecl) -> bool { let input_lts = input_visitor.into_vec(); let output_lts = output_visitor.into_vec(); + // check for lifetimes from higher scopes + for lt in input_lts.iter().chain(output_lts.iter()) { + if !allowed_lts.contains(lt) { + return false; + } + } + // no input lifetimes? easy case! if input_lts.is_empty() { return false; diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 36daa69fb31..7f463ec70b4 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -31,11 +31,13 @@ fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } type Ref<'r> = &'r u8; -fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params -fn lifetime_param_2<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } +fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { } //~^ERROR explicit lifetimes given +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime + struct X { x: u8, } @@ -68,6 +70,7 @@ fn main() { let _ = deep_reference_3(&1, 2); lifetime_param_1(&1, &2); lifetime_param_2(&1, &2); + lifetime_param_3(&1, &2); let foo = X { x: 1 }; foo.self_and_out(); -- cgit 1.4.1-3-g733a5 From 3cf5c36296d3f6b2203109c6b1757c83a55f09f0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 21:10:45 +0530 Subject: Address review comments, move to travis --- .travis.yml | 1 + src/lifetimes.rs | 6 +++--- tests/compile-fail/lifetimes.rs | 28 +++++++--------------------- util/dogfood.sh | 5 ++++- 4 files changed, 15 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/.travis.yml b/.travis.yml index bd997a0c22e..7eaa61c5572 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,4 @@ sudo: false script: - python util/update_lints.py -c - cargo test + - bash util/dogfood.sh diff --git a/src/lifetimes.rs b/src/lifetimes.rs index c333f04ab44..c3c915ea777 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -170,15 +170,15 @@ impl RefVisitor { impl<'v> Visitor<'v> for RefVisitor { // for lifetimes of references - fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &Option<Lifetime>) { + fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { self.record(lifetime); } // for lifetimes as parameters of generics - fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) { + fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { self.record(&Some(*lifetime)); } // for lifetime bounds; the default impl calls visit_lifetime_ref - fn visit_lifetime_bound(&mut self, _: &Lifetime) { } + fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { } } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 7f463ec70b4..287a8199d2c 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(needless_lifetimes)] - +#![allow(dead_code)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } //~^ERROR explicit lifetimes given @@ -54,27 +54,13 @@ impl X { fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params } +struct Foo<'a>(&'a u8); + +impl<'a> Foo<'a> { + fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method + fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist +} static STATIC: u8 = 1; fn main() { - distinct_lifetimes(&1, &2, 3); - distinct_and_static(&1, &2, &STATIC); - same_lifetime_on_input(&1, &2); - only_static_on_input(&1, &2, &STATIC); - in_and_out(&1, 2); - multiple_in_and_out_1(&1, &2); - multiple_in_and_out_2(&1, &2); - in_static_and_out(&1, &STATIC); - let _ = deep_reference_1(&1, &2); - let _ = deep_reference_2(Ok(&1)); - let _ = deep_reference_3(&1, 2); - lifetime_param_1(&1, &2); - lifetime_param_2(&1, &2); - lifetime_param_3(&1, &2); - - let foo = X { x: 1 }; - foo.self_and_out(); - foo.self_and_in_out(&1); - foo.distinct_self_and_in(&1); - foo.self_and_same_in(&1); } diff --git a/util/dogfood.sh b/util/dogfood.sh index 1fa091c9f39..51dd465a25d 100644 --- a/util/dogfood.sh +++ b/util/dogfood.sh @@ -1 +1,4 @@ -rm -rf target* && cargo build --lib && cp -R target target_recur && cargo rustc -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy \ No newline at end of file +rm -rf target*/*so +cargo build --lib && cp -R target target_recur && cargo rustc -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy || exit 1 +rm -rf target_recur + -- cgit 1.4.1-3-g733a5 From 83487c060ff64498fb9a3eb472ce71af1d26fe89 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 12 Aug 2015 16:44:14 +0530 Subject: Add trim_multiline utility (fixes #139) --- src/collapsible_if.rs | 4 ++-- src/lib.rs | 1 + src/misc.rs | 4 ++-- src/utils.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index be34458e0dc..8a41f208938 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -18,7 +18,7 @@ use rustc::middle::def::*; use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned, ExpnInfo}; -use utils::{in_macro, span_help_and_lint, snippet}; +use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; declare_lint! { pub COLLAPSIBLE_IF, @@ -55,7 +55,7 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { "this if statement can be collapsed", &format!("try\nif {} && {} {}", check_to_string(cx, check), check_to_string(cx, check_inner), - snippet(cx, content.span, ".."))); + snippet_block(cx, content.span, ".."))); } } } diff --git a/src/lib.rs b/src/lib.rs index 9135ecaca6c..01a2d65606c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] +#![feature(str_split_at)] #![allow(unused_imports, unknown_lints)] #[macro_use] diff --git a/src/misc.rs b/src/misc.rs index 7372bfed6c5..861e4a73dd2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,7 +7,7 @@ use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; -use utils::{match_path, snippet, span_lint, span_help_and_lint, walk_ptrs_ty}; +use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty}; /// Handles uncategorized lints /// Currently handles linting of if-let-able matches @@ -37,7 +37,7 @@ impl LintPass for MiscPass { // an enum is extended. So we only consider cases where a `_` wildcard is used if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 { - let body_code = snippet(cx, arms[0].body.span, ".."); + let body_code = snippet_block(cx, arms[0].body.span, ".."); let suggestion = if let ExprBlock(_) = arms[0].body.node { body_code.into_owned() } else { diff --git a/src/utils.rs b/src/utils.rs index c54a7f56f7e..5b9c995589b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -51,6 +51,35 @@ pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) } +/// convert a span (from a block) to a code snippet if available, otherwise use default, e.g. +/// `snippet(cx, expr.span, "..")` +/// This trims the code of indentation, except for the first line +/// Use it for blocks or block-like things which need to be printed as such +pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { + let snip = snippet(cx, span, default); + trim_multiline(snip, true) +} + +/// Trim indentation from a multiline string +/// with possibility of ignoring the first line +pub fn trim_multiline<'a>(s: Cow<'a, str>, ignore_first: bool) -> Cow<'a, str> { + let x = s.lines().skip(ignore_first as usize) + .map(|l| l.char_indices() + .find(|&(_,x)| x != ' ') + .unwrap_or((l.len(),' ')).0) + .min().unwrap_or(0); + if x > 0 { + Cow::Owned(s.lines().enumerate().map(|(i,l)| if ignore_first && i==0 { + l + } else { + l.split_at(x).1 + }).collect::<Vec<_>>() + .join("\n")) + } else { + s + } +} + /// get a parent expr if any – this is useful to constrain a lint pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.map; -- cgit 1.4.1-3-g733a5 From fbbb44d93bb566d5b3346b180a659ebdcd815fe5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 13:27:30 +0530 Subject: Handle tabs --- src/utils.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 5b9c995589b..3be6993b759 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -63,10 +63,16 @@ pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, /// Trim indentation from a multiline string /// with possibility of ignoring the first line pub fn trim_multiline<'a>(s: Cow<'a, str>, ignore_first: bool) -> Cow<'a, str> { + let s = trim_multiline_inner(s, ignore_first, ' '); + let s = trim_multiline_inner(s, ignore_first, '\t'); + trim_multiline_inner(s, ignore_first, ' ') +} + +fn trim_multiline_inner<'a>(s: Cow<'a, str>, ignore_first: bool, ch: char) -> Cow<'a, str> { let x = s.lines().skip(ignore_first as usize) .map(|l| l.char_indices() - .find(|&(_,x)| x != ' ') - .unwrap_or((l.len(),' ')).0) + .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 { -- cgit 1.4.1-3-g733a5 From 5ce8e7ba85fa50e067a5262fccd130e071b679fb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 19:29:12 +0530 Subject: trim_multiline: ignore empty lines --- src/utils.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 3be6993b759..490d2f6d1f6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -70,12 +70,15 @@ pub fn trim_multiline<'a>(s: Cow<'a, str>, ignore_first: bool) -> Cow<'a, str> { fn trim_multiline_inner<'a>(s: Cow<'a, str>, ignore_first: bool, ch: char) -> Cow<'a, str> { let x = s.lines().skip(ignore_first as usize) - .map(|l| l.char_indices() - .find(|&(_,x)| x != ch) - .unwrap_or((l.len(), ch)).0) + .filter_map(|l| { if l.len() > 0 { // ignore empty lines + Some(l.char_indices() + .find(|&(_,x)| x != ch) + .unwrap_or((l.len(), ch)).0) + } else {None}}) .min().unwrap_or(0); if x > 0 { - Cow::Owned(s.lines().enumerate().map(|(i,l)| if ignore_first && i==0 { + Cow::Owned(s.lines().enumerate().map(|(i,l)| if (ignore_first && i == 0) || + l.len() == 0 { l } else { l.split_at(x).1 -- cgit 1.4.1-3-g733a5 From 763ae1f3ae9644110f0af893c79719be00288311 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 13 Aug 2015 23:20:00 +0530 Subject: Fix dogfood --- src/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 490d2f6d1f6..67a89b067e6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -62,13 +62,13 @@ pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, /// Trim indentation from a multiline string /// with possibility of ignoring the first line -pub fn trim_multiline<'a>(s: Cow<'a, str>, ignore_first: bool) -> Cow<'a, str> { +pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { let s = trim_multiline_inner(s, ignore_first, ' '); let s = trim_multiline_inner(s, ignore_first, '\t'); trim_multiline_inner(s, ignore_first, ' ') } -fn trim_multiline_inner<'a>(s: Cow<'a, str>, ignore_first: bool, ch: char) -> Cow<'a, str> { +fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { let x = s.lines().skip(ignore_first as usize) .filter_map(|l| { if l.len() > 0 { // ignore empty lines Some(l.char_indices() -- cgit 1.4.1-3-g733a5 From 5d99ebec72cdedc0e76103b9a93bd9199f9be0ef Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 14 Aug 2015 14:21:05 +0200 Subject: fixed false positives (at the cost of some false negatives) --- src/eta_reduction.rs | 73 +++++++++++++++++++++++++++++------------------ tests/compile-fail/eta.rs | 25 ++++++++++++---- 2 files changed, 64 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 484d46ddc21..e0d4182081f 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -19,41 +19,58 @@ impl LintPass for EtaPass { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprClosure(_, ref decl, ref blk) = expr.node { - if !blk.stmts.is_empty() { - // || {foo(); bar()}; can't be reduced here - return; - } - if let Some(ref ex) = blk.expr { - if let ExprCall(ref caller, ref args) = ex.node { - if args.len() != decl.inputs.len() { - // Not the same number of arguments, there - // is no way the closure is the same as the function - return; - } - for (ref a1, ref a2) in decl.inputs.iter().zip(args) { - if let PatIdent(_, ident, _) = a1.pat.node { - // XXXManishearth Should I be checking the binding mode here? - if let ExprPath(None, ref p) = a2.node { - if p.segments.len() != 1 { - // If it's a proper path, it can't be a local variable - return; - } - if p.segments[0].identifier != ident.node { - // The two idents should be the same - return - } - } else { + match &expr.node { + &ExprCall(_, ref args) | + &ExprMethodCall(_, _, ref args) => { + for arg in args { + check_closure(cx, &*arg) + } + }, + _ => (), + } + } +} + +fn is_adjusted(cx: &Context, e: &Expr) -> bool { + cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() +} + +fn check_closure(cx: &Context, expr: &Expr) { + if let ExprClosure(_, ref decl, ref blk) = expr.node { + if !blk.stmts.is_empty() { + // || {foo(); bar()}; can't be reduced here + return; + } + if let Some(ref ex) = blk.expr { + if let ExprCall(ref caller, ref args) = ex.node { + if args.len() != decl.inputs.len() { + // Not the same number of arguments, there + // is no way the closure is the same as the function + return; + } + if args.iter().any(|arg| is_adjusted(cx, arg)) { return; } + for (ref a1, ref a2) in decl.inputs.iter().zip(args) { + if let PatIdent(_, ident, _) = a1.pat.node { + // XXXManishearth Should I be checking the binding mode here? + if let ExprPath(None, ref p) = a2.node { + if p.segments.len() != 1 { + // If it's a proper path, it can't be a local variable + return; + } + if p.segments[0].identifier != ident.node { + // The two idents should be the same return } } else { return } + } else { + return } - span_lint(cx, REDUNDANT_CLOSURE, expr.span, - &format!("redundant closure found. Consider using `{}` in its place", - expr_to_string(caller))[..]) } + span_lint(cx, REDUNDANT_CLOSURE, expr.span, + &format!("redundant closure found. Consider using `{}` in its place", + expr_to_string(caller))[..]) } } } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index 9e48ec1c3a5..bf6ecd79617 100755 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -4,18 +4,31 @@ #![deny(redundant_closure)] fn main() { - let a = |a, b| foo(a, b); + let a = Some(1u8).map(|a| foo(a)); //~^ ERROR redundant closure found. Consider using `foo` in its place - let c = |a, b| {1+2; foo}(a, b); + meta(|a| foo(a)); + //~^ ERROR redundant closure found. Consider using `foo` in its place + let c = Some(1u8).map(|a| {1+2; foo}(a)); //~^ ERROR redundant closure found. Consider using `{ 1 + 2; foo }` in its place - let d = |a, b| foo((|c, d| foo2(c,d))(a,b), b); - //~^ ERROR redundant closure found. Consider using `foo2` in its place + let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? + all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted +} + +fn meta<F>(f: F) where F: Fn(u8) { + f(1u8) } -fn foo(_: u8, _: u8) { +fn foo(_: u8) { } -fn foo2(_: u8, _: u8) -> u8 { +fn foo2(_: u8) -> u8 { 1u8 } + +fn all<X, F>(x: &[X], y: &X, f: F) -> bool +where F: Fn(&X, &X) -> bool { + x.iter().all(|e| f(e, y)) +} + +fn below(x: &u8, y: &u8) -> bool { x < y } -- cgit 1.4.1-3-g733a5 From b6ac44d5b2ba3a7d20371dd5bc65bbc53c0e2f8b Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 14 Aug 2015 15:00:04 +0200 Subject: Removed #![allow(redundant_closure)] on eq_op --- src/eq_op.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 0b7511e7dbd..495696b810c 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,4 +1,3 @@ -#![allow(redundant_closure)] // FIXME (#116) use rustc::lint::*; use syntax::ast::*; use syntax::ast_util as ast_util; -- cgit 1.4.1-3-g733a5 From f23af0cfd5cb25b1988d628fc41ad4515693c91d Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 14 Aug 2015 17:14:54 +0200 Subject: changed const to consts to avoid keyword, added test, fixed a lot of bugs --- src/const.rs | 356 -------------------------------------------------- src/consts.rs | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + tests/consts.rs | 11 ++ 4 files changed, 408 insertions(+), 356 deletions(-) delete mode 100644 src/const.rs create mode 100644 src/consts.rs create mode 100644 tests/consts.rs (limited to 'src') diff --git a/src/const.rs b/src/const.rs deleted file mode 100644 index bc53c1062dc..00000000000 --- a/src/const.rs +++ /dev/null @@ -1,356 +0,0 @@ -use rustc::lint::Context; -use rustc::middle::const_eval::lookup_const_by_id; -use syntax::ast::*; -use syntax::ptr::P; - -pub enum FloatWidth { - Fw32, - Fw64, - FwAny -} - -impl From<FloatTy> for FloatWidth { - fn from(ty: FloatTy) -> FloatWidth { - match ty { - TyF32 => Fw32, - TyF64 => Fw64, - } - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Constant { - constant: ConstantVariant, - needed_resolution: bool -} - -impl Constant { - fn new(variant: ConstantVariant) -> Constant { - Constant { constant: variant, needed_resolution: false } - } - - fn new_resolved(variant: ConstantVariant) -> Constant { - Constant { constant: variant, needed_resolution: true } - } -} - -/// a Lit_-like enum to fold constant `Expr`s into -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum ConstantVariant { - /// a String "abc" - ConstantStr(&'static str, StrStyle), - /// a Binary String b"abc" - ConstantBinary(Rc<Vec<u8>>), - /// a single byte b'a' - ConstantByte(u8), - /// a single char 'a' - ConstantChar(char), - /// an integer - ConstantInt(u64, LitIntType), - /// a float with given type - ConstantFloat(Cow<'static, str>, FloatWidth), - /// true or false - ConstantBool(bool), - /// an array of constants - ConstantVec(Vec<Constant>), - /// also an array, but with only one constant, repeated N times - ConstantRepeat(Constant, usize), - /// a tuple of constants - ConstantTuple(Vec<Constant>), -} - -impl ConstantVariant { - /// convert to u64 if possible - /// - /// # panics - /// - /// if the constant could not be converted to u64 losslessly - fn as_u64(&self) -> u64 { - if let &ConstantInt(val, _) = self { - val // TODO we may want to check the sign if any - } else { - panic!("Could not convert a {:?} to u64"); - } - } -} - -/// simple constant folding: Insert an expression, get a constant or none. -pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { - match e { - &ExprParen(ref inner) => constant(cx, inner), - &ExprPath(_, _) => fetch_path(cx, e), - &ExprBlock(ref block) => constant_block(cx, inner), - &ExprIf(ref cond, ref then, ref otherwise) => - constant_if(cx, cond, then, otherwise), - &ExprLit(ref lit) => Some(lit_to_constant(lit)), - &ExprVec(ref vec) => constant_vec(cx, vec), - &ExprTup(ref tup) => constant_tup(cx, tup), - &ExprRepeat(ref value, ref number) => - constant_binop_apply(cx, value, number,|v, n| Constant { - constant: ConstantRepeat(v, n.constant.as_u64()), - needed_resolution: v.needed_resolution || n.needed_resolution - }), - &ExprUnary(op, ref operand) => constant(cx, operand).and_then( - |o| match op { - UnNot => - if let ConstantBool(b) = o.variant { - Some(Constant{ - needed_resolution: o.needed_resolution, - constant: ConstantBool(!b), - }) - } else { None }, - UnNeg => constant_negate(o), - UnUniq | UnDeref => o, - }), - &ExprBinary(op, ref left, ref right) => - constant_binop(op, left, right), - //TODO: add other expressions - _ => None, - } -} - -fn lit_to_constant(lit: &Lit_) -> Constant { - match lit { - &LitStr(ref is, style) => Constant::new(ConstantStr(&*is, style)), - &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())), - &LitByte(b) => Constant::new(ConstantByte(b)), - &LitChar(c) => Constant::new(ConstantChar(c)), - &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)), - &LitFloat(ref is, ty) => - Constant::new(ConstantFloat(Cow::Borrowed(&*is), ty.into())), - &LitFloatUnsuffixed(InternedString) => - Constant::new(ConstantFloat(Cow::Borrowed(&*is), FwAny)), - &LitBool(b) => Constant::new(ConstantBool(b)), - } -} - -/// create `Some(ConstantVec(..))` of all constants, unless there is any -/// non-constant part -fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> { - let mut parts = Vec::new(); - let mut resolved = false; - for opt_part in vec { - match constant(cx, opt_part) { - Some(ref p) => { - resolved |= p.needed_resolution; - parts.push(p) - }, - None => { return None; }, - } - } - Some(Constant { - constant: ConstantVec(parts), - needed_resolution: resolved - }) -} - -fn constant_tup(cx: &Context, tup: &[&Expr]) -> Option<Constant> { - let mut parts = Vec::new(); - let mut resolved = false; - for opt_part in vec { - match constant(cx, opt_part) { - Some(ref p) => { - resolved |= p.needed_resolution; - parts.push(p) - }, - None => { return None; }, - } - } - Some(Constant { - constant: ConstantTuple(parts), - needed_resolution: resolved - }) -} - -/// lookup a possibly constant expression from a ExprPath -fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { - if let Some(&PathResolution { base_def: DefConst(id), ..}) = - cx.tcx.def_map.borrow().get(&e.id) { - lookup_const_by_id(cx.tcx, id, None).map( - |l| Constant::new_resolved(constant(cx, l).constant)) - } else { None } -} - -/// A block can only yield a constant if it only has one constant expression -fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.map(|b| constant(cx, b)) - } else { None } -} - -fn constant_if(cx: &Context, cond: &Expr, then: &Expr, otherwise: &Expr) -> - Option<Constant> { - if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) = - constant(cx, cond) { - let part = constant(cx, if b { then } else { otherwise }); - Some(Constant { - constant: part.constant, - needed_resolution: res || part.needed_resolution, - }) - } else { None } -} - -fn constant_negate(o: Constant) -> Option<Constant> { - Some(Constant{ - needed_resolution: o.needed_resolution, - constant: match o.constant { - &ConstantInt(value, ty) => - ConstantInt(value, match ty { - SignedIntLit(ity, sign) => - SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; }, - }), - &LitFloat(ref is, ref ty) => ConstantFloat(neg_float_str(is), ty), - _ => { return None; }, - } - }) -} - -fn neg_sign(s: Sign) -> Sign { - match s { - Sign::Plus => Sign::Minus, - Sign::Minus => Sign::Plus, - } -} - -fn neg_float_str(s: &InternedString) -> Cow<'static, str> { - if s.startsWith('-') { - Cow::Borrowed(s[1..]) - } else { - Cow::Owned(format!("-{}", &*s)) - } -} - -fn is_negative(ty: LitIntType) -> bool { - match ty { - SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, - UnsignedIntLit(_) => false, - } -} - -fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option(LitIntType) { - match (l, r) { - (SignedIntLit(lty, _), SignedIntLit(rty, _)) => if lty == rty { - Some(SignedIntLit(lty, s)) } else { None }, - (UnsignedIntLit(lty), UnsignedIntLit(rty)) => - if Sign == Plus && lty == rty { - Some(UnsignedIntLit(lty)) - } else { None }, - (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => UnsuffixedIntLit(s), - (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => SignedIntLit(lty, s), - (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => if rs == Plus { - Some(UnsignedIntLit(lty)) } else { None }, - (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => SignedIntLit(rty, s), - (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => if ls == Plus { - Some(UnsignedIntLit(rty)) } else { None }, - _ => None, - } -} - -fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) - -> Option<Constant> { - match op.node { - BiAdd => constant_binop_apply(cx, left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => - l8.checked_add(r8).map(|v| ConstantByte(v)), - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - if ln == rn { - unify_int_type(lty, rty, if ln { Minus } else { Plus }) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))) - } else { - if ln { - add_neg_int(r64, rty, l64, lty) - } else { - add_neg_int(l64, lty, r64, rty) - } - } - }, - // TODO: float - _ => None - }), - BiSub => constant_binop_apply(cx, left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { - None } else { Some(ConstantByte(l8 - r8)) }, - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - match (ln, rn) { - (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), - (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), - (true, false) => unify_int_type(lty, rty, Minus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - (false, true) => unify_int_type(lty, rty, Plus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - } - }, - _ => None, - }), - //BiMul, - //BiDiv, - //BiRem, - BiAnd => constant_short_circuit(cx, left, right, false), - BiOr => constant_short_circuit(cx, left, right, true), - //BiBitXor, - //BiBitAnd, - //BiBitOr, - //BiShl, - //BiShr, - //BiEq, - //BiLt, - //BiLe, - //BiNe, - //BiGe, - //BiGt, - _ => None, - } -} - -fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> - Some(Constant) { - if neg > pos { - unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) - } else { - unify_int_type(nty, pty, Plus).map(|ty| ConstantInt(pos - neg, ty)) - } -} - -fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: Bool) -> - Option<Constant> { - unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( - |ty| l64.checked_sub(r64).map(|v| ConstantInt(v, ty))) -} - -fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F) - -> Option<Constant> -where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> { - constant(cx, left).and_then(|l| constant(cx, right).and_then( - |r| Constant { - needed_resolution: l.needed_resolution || r.needed_resolution, - constant: op(l.constant, r.constant) - })) -} - -fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) -> - Option<Constant> { - let leftconst = constant(cx, left); - if let ConstantBool(lbool) = leftconst.constant { - if l == b { - Some(leftconst) - } else { - let rightconst = constant(cx, right); - if let ConstantBool(rbool) = rightconst.constant { - Some(Constant { - constant: rightconst.constant, - needed_resolution: leftconst.needed_resolution || - rightconst.needed_resolution, - }) - } else { None } - } - } else { None } -} diff --git a/src/consts.rs b/src/consts.rs new file mode 100644 index 00000000000..c8d5262abab --- /dev/null +++ b/src/consts.rs @@ -0,0 +1,396 @@ +#[cfg(test)] +use rustc::lint::Context; + +use rustc::middle::const_eval::lookup_const_by_id; +use rustc::middle::def::PathResolution; +use rustc::middle::def::Def::*; +use syntax::ast::*; +use syntax::parse::token::InternedString; +use syntax::ptr::P; +use std::rc::Rc; +use std::ops::Deref; +use self::ConstantVariant::*; +use self::FloatWidth::*; + +#[cfg(not(test))] +pub struct Context; + +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum FloatWidth { + Fw32, + Fw64, + FwAny +} + +impl From<FloatTy> for FloatWidth { + fn from(ty: FloatTy) -> FloatWidth { + match ty { + TyF32 => Fw32, + TyF64 => Fw64, + } + } +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Constant { + constant: ConstantVariant, + needed_resolution: bool +} + +impl Constant { + pub fn new(variant: ConstantVariant) -> Constant { + Constant { constant: variant, needed_resolution: false } + } + + pub fn new_resolved(variant: ConstantVariant) -> Constant { + Constant { constant: variant, needed_resolution: true } + } + + // convert this constant to a f64, if possible + pub fn as_float(&self) -> Option<f64> { + match &self.constant { + &ConstantByte(b) => Some(b as f64), + &ConstantFloat(ref s, _) => s.parse().ok(), + &ConstantInt(i, ty) => Some(if is_negative(ty) { + -(i as f64) } else { i as f64 }), + _ => None + } + } +} + +/// a Lit_-like enum to fold constant `Expr`s into +#[derive(PartialEq, Eq, Debug, Clone)] +pub enum ConstantVariant { + /// a String "abc" + ConstantStr(String, StrStyle), + /// a Binary String b"abc" + ConstantBinary(Rc<Vec<u8>>), + /// a single byte b'a' + ConstantByte(u8), + /// a single char 'a' + ConstantChar(char), + /// an integer + ConstantInt(u64, LitIntType), + /// a float with given type + ConstantFloat(String, FloatWidth), + /// true or false + ConstantBool(bool), + /// an array of constants + ConstantVec(Box<Vec<Constant>>), + /// also an array, but with only one constant, repeated N times + ConstantRepeat(Box<ConstantVariant>, usize), + /// a tuple of constants + ConstantTuple(Box<Vec<Constant>>), +} + +impl ConstantVariant { + /// convert to u64 if possible + /// + /// # panics + /// + /// if the constant could not be converted to u64 losslessly + fn as_u64(&self) -> u64 { + if let &ConstantInt(val, _) = self { + val // TODO we may want to check the sign if any + } else { + panic!("Could not convert a {:?} to u64"); + } + } +} + +/// simple constant folding: Insert an expression, get a constant or none. +pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { + match &e.node { + &ExprParen(ref inner) => constant(cx, inner), + &ExprPath(_, _) => fetch_path(cx, e), + &ExprBlock(ref block) => constant_block(cx, block), + &ExprIf(ref cond, ref then, ref otherwise) => + constant_if(cx, &*cond, &*then, &*otherwise), + &ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), + &ExprVec(ref vec) => constant_vec(cx, &vec[..]), + &ExprTup(ref tup) => constant_tup(cx, &tup[..]), + &ExprRepeat(ref value, ref number) => + constant_binop_apply(cx, value, number,|v, n| + Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), + &ExprUnary(op, ref operand) => constant(cx, operand).and_then( + |o| match op { + UnNot => + if let ConstantBool(b) = o.constant { + Some(Constant{ + needed_resolution: o.needed_resolution, + constant: ConstantBool(!b), + }) + } else { None }, + UnNeg => constant_negate(o), + UnUniq | UnDeref => Some(o), + }), + &ExprBinary(op, ref left, ref right) => + constant_binop(cx, op, left, right), + //TODO: add other expressions + _ => None, + } +} + +fn lit_to_constant(lit: &Lit_) -> Constant { + match lit { + &LitStr(ref is, style) => + Constant::new(ConstantStr(is.to_string(), style)), + &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())), + &LitByte(b) => Constant::new(ConstantByte(b)), + &LitChar(c) => Constant::new(ConstantChar(c)), + &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)), + &LitFloat(ref is, ty) => { + Constant::new(ConstantFloat(is.to_string(), ty.into())) + }, + &LitFloatUnsuffixed(ref is) => { + Constant::new(ConstantFloat(is.to_string(), FwAny)) + }, + &LitBool(b) => Constant::new(ConstantBool(b)), + } +} + +/// create `Some(ConstantVec(..))` of all constants, unless there is any +/// non-constant part +fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Option<Constant> { + let mut parts = Vec::new(); + let mut resolved = false; + for opt_part in vec.iter() { + match constant(cx, opt_part) { + Some(p) => { + resolved |= (&p).needed_resolution; + parts.push(p) + }, + None => { return None; }, + } + } + Some(Constant { + constant: ConstantVec(Box::new(parts)), + needed_resolution: resolved + }) +} + +fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Option<Constant> { + let mut parts = Vec::new(); + let mut resolved = false; + for opt_part in tup.iter() { + match constant(cx, opt_part) { + Some(p) => { + resolved |= (&p).needed_resolution; + parts.push(p) + }, + None => { return None; }, + } + } + Some(Constant { + constant: ConstantTuple(Box::new(parts)), + needed_resolution: resolved + }) +} + +#[cfg(test)] +fn fetch_path(_cx: &Context, _expr: &Expr) -> Option<Constant> { None } + +/// lookup a possibly constant expression from a ExprPath +#[cfg(not(test))] +fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { + if let Some(&PathResolution { base_def: DefConst(id), ..}) = + cx.tcx.def_map.borrow().get(&e.id) { + lookup_const_by_id(cx.tcx, id, None).and_then( + |l| constant(cx, l).map(|c| Constant::new_resolved(c.constant))) + } else { None } +} + +/// A block can only yield a constant if it only has one constant expression +fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { + if block.stmts.is_empty() { + block.expr.as_ref().and_then(|b| constant(cx, &*b)) + } else { None } +} + +fn constant_if(cx: &Context, cond: &Expr, then: &Block, otherwise: + &Option<P<Expr>>) -> Option<Constant> { + if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) = + constant(cx, cond) { + if b { + constant_block(cx, then) + } else { + otherwise.as_ref().and_then(|expr| constant(cx, &*expr)) + }.map(|part| + Constant { + constant: part.constant, + needed_resolution: res || part.needed_resolution, + }) + } else { None } +} + +fn constant_negate(o: Constant) -> Option<Constant> { + Some(Constant{ + needed_resolution: o.needed_resolution, + constant: match o.constant { + ConstantInt(value, ty) => + ConstantInt(value, match ty { + SignedIntLit(ity, sign) => + SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), + _ => { return None; }, + }), + ConstantFloat(ref is, ty) => + ConstantFloat(neg_float_str(is.to_string()), ty), + _ => { return None; }, + } + }) +} + +fn neg_sign(s: Sign) -> Sign { + match s { + Sign::Plus => Sign::Minus, + Sign::Minus => Sign::Plus, + } +} + +fn neg_float_str(s: String) -> String { + if s.starts_with('-') { + s[1..].to_owned() + } else { + format!("-{}", &*s) + } +} + +fn is_negative(ty: LitIntType) -> bool { + match ty { + SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, + UnsignedIntLit(_) => false, + } +} + +fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { + match (l, r) { + (SignedIntLit(lty, _), SignedIntLit(rty, _)) => if lty == rty { + Some(SignedIntLit(lty, s)) } else { None }, + (UnsignedIntLit(lty), UnsignedIntLit(rty)) => + if s == Plus && lty == rty { + Some(UnsignedIntLit(lty)) + } else { None }, + (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => Some(UnsuffixedIntLit(s)), + (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => Some(SignedIntLit(lty, s)), + (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => if rs == Plus { + Some(UnsignedIntLit(lty)) } else { None }, + (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => Some(SignedIntLit(rty, s)), + (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => if ls == Plus { + Some(UnsignedIntLit(rty)) } else { None }, + _ => None, + } +} + +fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) + -> Option<Constant> { + match op.node { + BiAdd => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => + l8.checked_add(r8).map(|v| ConstantByte(v)), + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + if ln == rn { + unify_int_type(lty, rty, if ln { Minus } else { Plus }) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))) + } else { + if ln { + add_neg_int(r64, rty, l64, lty) + } else { + add_neg_int(l64, lty, r64, rty) + } + } + }, + // TODO: float + _ => None + }), + BiSub => constant_binop_apply(cx, left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { + None } else { Some(ConstantByte(l8 - r8)) }, + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + match (ln, rn) { + (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), + (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), + (true, false) => unify_int_type(lty, rty, Minus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + (false, true) => unify_int_type(lty, rty, Plus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + } + }, + _ => None, + }), + //BiMul, + //BiDiv, + //BiRem, + BiAnd => constant_short_circuit(cx, left, right, false), + BiOr => constant_short_circuit(cx, left, right, true), + //BiBitXor, + //BiBitAnd, + //BiBitOr, + //BiShl, + //BiShr, + //BiEq, + //BiLt, + //BiLe, + //BiNe, + //BiGe, + //BiGt, + _ => None, + } +} + +fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> + Option<ConstantVariant> { + if neg > pos { + unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) + } else { + unify_int_type(nty, pty, Plus).map(|ty| ConstantInt(pos - neg, ty)) + } +} + +fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> + Option<ConstantVariant> { + unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( + |ty| l.checked_sub(r).map(|v| ConstantInt(v, ty))) +} + +fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F) + -> Option<Constant> +where F: Fn(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> { + if let (Some(Constant { constant: lc, needed_resolution: ln }), + Some(Constant { constant: rc, needed_resolution: rn })) = + (constant(cx, left), constant(cx, right)) { + op(lc, rc).map(|c| + Constant { + needed_resolution: ln || rn, + constant: c, + }) + } else { None } +} + +fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) -> + Option<Constant> { + constant(cx, left).and_then(|left| + if let &ConstantBool(lbool) = &left.constant { + if lbool == b { + Some(left) + } else { + constant(cx, right).and_then(|right| + if let ConstantBool(_) = right.constant { + Some(Constant { + constant: right.constant, + needed_resolution: left.needed_resolution || + right.needed_resolution, + }) + } else { None } + ) + } + } else { None } + ) +} diff --git a/src/lib.rs b/src/lib.rs index f788c72db3c..8e7cc096c5e 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ use rustc::lint::LintPassObject; #[macro_use] pub mod utils; +pub mod consts; pub mod types; pub mod misc; pub mod eq_op; diff --git a/tests/consts.rs b/tests/consts.rs new file mode 100644 index 00000000000..edbbfa1e2db --- /dev/null +++ b/tests/consts.rs @@ -0,0 +1,11 @@ + +extern crate clippy; + +use clippy::consts; +use syntax::ast::*; + +#[test] +fn test_lit() { + assert_eq!(ConstantBool(true), constant(&Context, + Expr{ node_id: 1, node: ExprLit(LitBool(true)), span: default() })); +} -- cgit 1.4.1-3-g733a5 From 137a9f3def7d4d420e9359d36efe52f8d3e42c9e Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 14 Aug 2015 07:17:10 +0200 Subject: methods: allow Option.unwrap by default --- README.md | 2 +- src/methods.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index dd7d0158f03..d9dea816318 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ needless_lifetimes | warn | using explicit lifetimes for references in func needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do needless_return | warn | using a return statement like `return expr;` where an expression would suffice non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -option_unwrap_used | warn | using `Option.unwrap()`, which should at least get a better message using `expect()` +option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) diff --git a/src/methods.rs b/src/methods.rs index 07b0fdf70e2..02b181a46e7 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -7,7 +7,7 @@ use utils::{span_lint, match_def_path, walk_ptrs_ty}; #[derive(Copy,Clone)] pub struct MethodsPass; -declare_lint!(pub OPTION_UNWRAP_USED, Warn, +declare_lint!(pub OPTION_UNWRAP_USED, Allow, "using `Option.unwrap()`, which should at least get a better message using `expect()`"); declare_lint!(pub RESULT_UNWRAP_USED, Allow, "using `Result.unwrap()`, which might be better handled"); -- cgit 1.4.1-3-g733a5 From b299433de3f3344ab97f426aea8a0bf7d396723a Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 15 Aug 2015 09:36:02 +0200 Subject: lifetimes: fix case with one unnamed and one static ref (fixes #171) --- src/lifetimes.rs | 4 ++-- tests/compile-fail/lifetimes.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index c3c915ea777..0127822dbde 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -115,8 +115,8 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, } else if output_lts.is_empty() { // no output lifetimes, check distinctness of input lifetimes - // only one reference with unnamed lifetime, ok - if input_lts.len() == 1 && input_lts[0] == Unnamed { + // only unnamed and static, ok + if input_lts.iter().all(|lt| *lt == Unnamed || *lt == Static) { return false; } // we have no output reference, so we only need all distinct lifetimes diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 287a8199d2c..a5597e6478f 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -13,6 +13,8 @@ fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same life fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved +fn mut_and_static_input(_x: &mut u8, _y: &'static str) { } + fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x } //~^ERROR explicit lifetimes given @@ -60,7 +62,6 @@ impl<'a> Foo<'a> { fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist } -static STATIC: u8 = 1; fn main() { } -- cgit 1.4.1-3-g733a5 From 542bf8d50ee9edc7754b3977407880640fc0bd68 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 15 Aug 2015 09:22:50 +0200 Subject: misc: fix check for unit body in "match -> if let" lint (fixes #172) --- src/misc.rs | 65 ++++++++++++++++++++++---------------- tests/compile-fail/match_if_let.rs | 12 +++++++ 2 files changed, 49 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 861e4a73dd2..091ea36f2f5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,6 +6,7 @@ use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; +use std::borrow::Cow; use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty}; @@ -26,39 +27,47 @@ impl LintPass for MiscPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { - if arms.len() == 2 { - if arms[0].guard.is_none() && arms[1].pats.len() == 1 { - match arms[1].body.node { - ExprTup(ref v) if v.is_empty() && arms[1].guard.is_none() => (), - ExprBlock(ref b) if b.stmts.is_empty() && arms[1].guard.is_none() => (), - _ => return - } - // In some cases, an exhaustive match is preferred to catch situations when - // an enum is extended. So we only consider cases where a `_` wildcard is used - if arms[1].pats[0].node == PatWild(PatWildSingle) && - arms[0].pats.len() == 1 { - let body_code = snippet_block(cx, arms[0].body.span, ".."); - let suggestion = if let ExprBlock(_) = arms[0].body.node { - body_code.into_owned() - } else { - format!("{{ {} }}", body_code) - }; - span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for \ - destructuring a single pattern. Did you mean to \ - use `if let`?", - &*format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - suggestion) - ); - } - } + // check preconditions: only two arms + if arms.len() == 2 && + // both of the arms have a single pattern and no guard + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + // and the second pattern is a `_` wildcard: this is not strictly necessary, + // since the exhaustiveness check will ensure the last one is a catch-all, + // but in some cases, an explicit match is preferred to catch situations + // when an enum is extended, so we don't consider these cases + arms[1].pats[0].node == PatWild(PatWildSingle) && + // finally, we don't want any content in the second arm (unit or empty block) + is_unit_expr(&*arms[1].body) + { + let body_code = snippet_block(cx, arms[0].body.span, ".."); + let body_code = if let ExprBlock(_) = arms[0].body.node { + body_code + } else { + Cow::Owned(format!("{{ {} }}", body_code)) + }; + span_help_and_lint(cx, SINGLE_MATCH, expr.span, + "you seem to be trying to use match for \ + destructuring a single pattern. Did you mean to \ + use `if let`?", + &*format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + body_code) + ); } } } } +fn is_unit_expr(expr: &Expr) -> bool { + match expr.node { + ExprTup(ref v) if v.is_empty() => true, + ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true, + _ => false, + } +} + declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not \ diff --git a/tests/compile-fail/match_if_let.rs b/tests/compile-fail/match_if_let.rs index 01bfe744713..bf2e7e43a52 100755 --- a/tests/compile-fail/match_if_let.rs +++ b/tests/compile-fail/match_if_let.rs @@ -23,4 +23,16 @@ fn main(){ (2...3, 7...9) => println!("{:?}", z), _ => {} } + + // Not linted (pattern guards used) + match x { + Some(y) if y == 0 => println!("{:?}", y), + _ => () + } + + // Not linted (content in the else) + match z { + (2...3, 7...9) => println!("{:?}", z), + _ => println!("nope"), + } } -- cgit 1.4.1-3-g733a5 From 997f34504685085da149221c5fda4e4cd941ae53 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 16 Aug 2015 08:33:10 +0200 Subject: all: remove unneeded as_str() calls for ast::Name Name has PartialEq and Display impls that do what we want. --- src/attrs.rs | 2 +- src/len_zero.rs | 4 ++-- src/lifetimes.rs | 2 +- src/loops.rs | 7 +++---- src/utils.rs | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index ef3320d2543..850155b28b6 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -103,7 +103,7 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, span_lint(cx, INLINE_ALWAYS, attr.span, &format!( "you have declared `#[inline(always)]` on `{}`. This \ is usually a bad idea. Are you sure?", - ident.name.as_str())); + ident.name)); } } } diff --git a/src/len_zero.rs b/src/len_zero.rs index d5f3d1ad810..94f8d5873ec 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -55,7 +55,7 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { } if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident.as_str())); + //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident)); for i in trait_items { if is_named_self(i, "len") { span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, @@ -122,7 +122,7 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { if let &MethodTraitItemId(def_id) = id { if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { - method.name.as_str() == "is_empty" + method.name == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 } else { false } } else { false } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 0127822dbde..37204f03603 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -153,7 +153,7 @@ struct RefVisitor(Vec<RefLt>); impl RefVisitor { fn record(&mut self, lifetime: &Option<Lifetime>) { if let &Some(ref lt) = lifetime { - if lt.name.as_str() == "'static" { + if lt.name == "'static" { self.0.push(Static); } else { self.0.push(Named(lt.name)); diff --git a/src/loops.rs b/src/loops.rs index 74015bdc6be..092b5ce1196 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -36,13 +36,12 @@ impl LintPass for LoopsPass { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is used to index `{}`. Consider using \ `for ({}, item) in {}.iter().enumerate()` or similar iterators.", - ident.node.name.as_str(), indexed.as_str(), - ident.node.name.as_str(), indexed.as_str())); + ident.node.name, indexed, ident.node.name, indexed)); } else { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is only used to index `{}`. \ Consider using `for item in &{}` or similar iterators.", - ident.node.name.as_str(), indexed.as_str(), indexed.as_str())); + ident.node.name, indexed, indexed)); } } } @@ -52,7 +51,7 @@ impl LintPass for LoopsPass { if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments to iter() or iter_mut() if args.len() == 1 { - let method_name = method.node.name.as_str(); + let method_name = method.node.name; if method_name == "iter" { let object = snippet(cx, args[0].span, "_"); span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( diff --git a/src/utils.rs b/src/utils.rs index 67a89b067e6..a9378da415a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -35,14 +35,14 @@ pub fn in_external_macro(cx: &Context, span: Span) -> bool { /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { cx.tcx.with_path(def_id, |iter| iter.map(|elem| elem.name()) - .zip(path.iter()).all(|(nm, p)| &nm.as_str() == p)) + .zip(path.iter()).all(|(nm, p)| nm == p)) } /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a,b)| &a.identifier.name.as_str() == b) + |(a, b)| &a.identifier.name == b) } /// convert a span to a code snippet if available, otherwise use default, e.g. -- cgit 1.4.1-3-g733a5 From 47b605304db5e1bf3cac3879e11d0ceae9ba9959 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 16 Aug 2015 08:54:43 +0200 Subject: all: organize imports * remove unused imports * separate external and internal imports * consistent import of rustc::lint * move #[allow(unused_imports)] to local impl --- src/approx_const.rs | 6 +----- src/attrs.rs | 8 +++----- src/bit_mask.rs | 5 ++--- src/collapsible_if.rs | 6 ++---- src/eq_op.rs | 1 + src/eta_reduction.rs | 3 +-- src/identity_op.rs | 3 --- src/len_zero.rs | 13 ++++--------- src/lib.rs | 1 - src/lifetimes.rs | 8 ++++---- src/methods.rs | 2 +- src/misc.rs | 6 +++--- src/mut_mut.rs | 8 ++++---- src/needless_bool.rs | 7 +------ src/ptr_arg.rs | 6 +----- src/returns.rs | 5 ++--- src/strings.rs | 4 ++-- src/types.rs | 7 ++++--- src/unicode.rs | 1 + src/utils.rs | 7 +++---- 20 files changed, 40 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 3c39b79885c..cfd646765c9 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,12 +1,8 @@ -use rustc::plugin::Registry; use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; use syntax::codemap::Span; use std::f64::consts as f64; + use utils::span_lint; declare_lint! { diff --git a/src/attrs.rs b/src/attrs.rs index 850155b28b6..3e451ac5eda 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,11 +1,9 @@ -/// checks for attributes +//! checks for attributes -use rustc::plugin::Registry; use rustc::lint::*; use syntax::ast::*; -use syntax::ptr::P; -use syntax::codemap::{Span, ExpnInfo}; -use syntax::parse::token::InternedString; +use syntax::codemap::ExpnInfo; + use utils::{in_macro, match_path, span_lint}; declare_lint! { pub INLINE_ALWAYS, Warn, diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 169975001b9..ec937dbab6c 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,11 +1,10 @@ -use rustc::plugin::Registry; use rustc::lint::*; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::*; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; +use syntax::ast_util::is_comparison_binop; use syntax::codemap::Span; + use utils::span_lint; declare_lint! { diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 8a41f208938..0b6dfc19e6b 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -12,12 +12,10 @@ //! //! This lint is **warn** by default -use rustc::plugin::Registry; use rustc::lint::*; -use rustc::middle::def::*; use syntax::ast::*; -use syntax::ptr::P; -use syntax::codemap::{Span, Spanned, ExpnInfo}; +use syntax::codemap::{Spanned, ExpnInfo}; + use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; declare_lint! { diff --git a/src/eq_op.rs b/src/eq_op.rs index 495696b810c..50b61e23356 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -3,6 +3,7 @@ use syntax::ast::*; use syntax::ast_util as ast_util; use syntax::ptr::P; use syntax::codemap as code; + use utils::span_lint; declare_lint! { diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index e0d4182081f..6712e787278 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,6 +1,5 @@ +use rustc::lint::*; use syntax::ast::*; -use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use syntax::codemap::{Span, Spanned}; use syntax::print::pprust::expr_to_string; use utils::span_lint; diff --git a/src/identity_op.rs b/src/identity_op.rs index 964675b765e..18a475bb737 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,10 +1,7 @@ -use rustc::plugin::Registry; use rustc::lint::*; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::*; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; use syntax::codemap::Span; use utils::{span_lint, snippet}; diff --git a/src/len_zero.rs b/src/len_zero.rs index 94f8d5873ec..073dcea582d 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,14 +1,9 @@ -extern crate rustc_typeck as typeck; - -use std::rc::Rc; -use std::cell::RefCell; +use rustc::lint::*; +use syntax::ast::*; use syntax::ptr::P; -use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::util::nodemap::DefIdMap; -use rustc::middle::ty::{self, TypeVariants, TypeAndMut, MethodTraitItemId, ImplOrTraitItemId}; -use rustc::middle::def::{DefTy, DefStruct, DefTrait}; use syntax::codemap::{Span, Spanned}; -use syntax::ast::*; +use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; + use utils::{span_lint, walk_ptrs_ty, snippet}; declare_lint!(pub LEN_ZERO, Warn, diff --git a/src/lib.rs b/src/lib.rs index 01a2d65606c..3ce5c1f9f3c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] #![feature(str_split_at)] -#![allow(unused_imports, unknown_lints)] #[macro_use] extern crate syntax; diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 37204f03603..9d07df4a3ed 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -1,10 +1,10 @@ use syntax::ast::*; -use rustc::lint::{Context, LintPass, LintArray, Lint}; +use rustc::lint::*; use syntax::codemap::Span; -use syntax::visit::{Visitor, FnKind, walk_ty}; -use utils::{in_external_macro, span_lint}; +use syntax::visit::{Visitor, walk_ty}; use std::collections::HashSet; -use std::iter::FromIterator; + +use utils::{in_external_macro, span_lint}; declare_lint!(pub NEEDLESS_LIFETIMES, Warn, "using explicit lifetimes for references in function arguments when elision rules \ diff --git a/src/methods.rs b/src/methods.rs index 02b181a46e7..6d0707ccbee 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,5 +1,5 @@ use syntax::ast::*; -use rustc::lint::{Context, LintPass, LintArray}; +use rustc::lint::*; use rustc::middle::ty; use utils::{span_lint, match_def_path, walk_ptrs_ty}; diff --git a/src/misc.rs b/src/misc.rs index 091ea36f2f5..1fc41cf4862 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,11 +1,11 @@ +use rustc::lint::*; use syntax::ptr::P; use syntax::ast; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::visit::{FnKind}; -use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use rustc::middle::ty; use syntax::codemap::{Span, Spanned}; +use syntax::visit::FnKind; +use rustc::middle::ty; use std::borrow::Cow; use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty}; diff --git a/src/mut_mut.rs b/src/mut_mut.rs index a3c40d06f90..fbcb70e17d3 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,8 +1,8 @@ -use syntax::ptr::P; +use rustc::lint::*; use syntax::ast::*; -use rustc::lint::{Context, LintPass, LintArray, Lint}; -use rustc::middle::ty::{TypeVariants, TypeAndMut, TyRef}; -use syntax::codemap::{BytePos, ExpnInfo, Span}; +use syntax::codemap::ExpnInfo; +use rustc::middle::ty::{TypeAndMut, TyRef}; + use utils::{in_macro, span_lint}; declare_lint!(pub MUT_MUT, Warn, diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 2a4ed50b93d..18d98f1f063 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -2,14 +2,9 @@ //! //! This lint is **warn** by default -use rustc::plugin::Registry; use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; -use syntax::codemap::Span; + use utils::{de_p, span_lint, snippet}; declare_lint! { diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 85db4aa7b21..2748d187a4e 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -2,14 +2,10 @@ //! //! This lint is **warn** by default -use rustc::plugin::Registry; use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; use syntax::codemap::Span; + use types::match_ty_unwrap; use utils::span_lint; diff --git a/src/returns.rs b/src/returns.rs index 94b9ec9650f..df0b93f301e 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,8 +1,7 @@ -use syntax::ast; +use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; -use rustc::lint::{Context, LintPass, LintArray, Level}; use utils::{span_lint, snippet, match_path}; @@ -101,7 +100,7 @@ impl LintPass for ReturnPass { } fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, - block: &Block, _: Span, _: ast::NodeId) { + block: &Block, _: Span, _: NodeId) { self.check_block_return(cx, block); self.check_let_return(cx, block); } diff --git a/src/strings.rs b/src/strings.rs index 7b7bab49b5d..7981b785850 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -6,9 +6,9 @@ use rustc::lint::*; use rustc::middle::ty::TypeVariants::TyStruct; use syntax::ast::*; -use syntax::codemap::{Span, Spanned}; +use syntax::codemap::Spanned; + use eq_op::is_exp_equal; -use types::match_ty_unwrap; use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; declare_lint! { diff --git a/src/types.rs b/src/types.rs index 53d8850c59d..25af398a0b4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,9 +1,9 @@ -use syntax::ptr::P; +use rustc::lint::*; use syntax::ast; use syntax::ast::*; +use syntax::ptr::P; use rustc::middle::ty; -use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; -use syntax::codemap::{ExpnInfo, Span}; +use syntax::codemap::ExpnInfo; use utils::{in_macro, snippet, span_lint, span_help_and_lint}; @@ -40,6 +40,7 @@ pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> } } +#[allow(unused_imports)] impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) diff --git a/src/unicode.rs b/src/unicode.rs index 62b4a9dadf5..ab48fd1bef2 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,6 +1,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{BytePos, Span}; + use utils::span_lint; declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, diff --git a/src/utils.rs b/src/utils.rs index a9378da415a..47e3a3456d6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,11 +1,10 @@ -use rustc::lint::{Context, Lint, Level}; -use syntax::ast::{DefId, Expr, Name, NodeId, Path}; +use rustc::lint::*; +use syntax::ast::*; use syntax::codemap::{ExpnInfo, Span}; use syntax::ptr::P; use rustc::ast_map::Node::NodeExpr; use rustc::middle::ty; -use std::borrow::{Cow, IntoCow}; -use std::convert::From; +use std::borrow::Cow; /// returns true if the macro that expanded the crate was outside of /// the current crate or was a compiler plugin -- cgit 1.4.1-3-g733a5 From 64954283c12a5c0701fcd805454ca9282cafca51 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 16 Aug 2015 09:03:06 +0200 Subject: add some imports to guard against crate moves --- src/lib.rs | 3 ++- src/methods.rs | 7 +++++++ src/types.rs | 2 -- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 3ce5c1f9f3c..c45227f88f2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![feature(plugin_registrar, box_syntax)] -#![feature(rustc_private, collections)] +#![feature(rustc_private, core, collections)] #![feature(str_split_at)] #[macro_use] @@ -8,6 +8,7 @@ extern crate syntax; extern crate rustc; // Only for the compile time checking of paths +extern crate core; extern crate collections; use rustc::plugin::Registry; diff --git a/src/methods.rs b/src/methods.rs index 6d0707ccbee..f2df736bebc 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -16,12 +16,19 @@ declare_lint!(pub STR_TO_STRING, Warn, declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); +#[allow(unused_imports)] impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { + { + // In case stuff gets moved around + use core::option::Option; + use core::result::Result; + use collections::string::String; + } if let ExprMethodCall(ref ident, _, ref args) = expr.node { let ref obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty; if ident.node.name == "unwrap" { diff --git a/src/types.rs b/src/types.rs index 25af398a0b4..aa5f1d13471 100644 --- a/src/types.rs +++ b/src/types.rs @@ -63,10 +63,8 @@ impl LintPass for TypePass { // In case stuff gets moved around use collections::linked_list::LinkedList as DL1; use std::collections::linked_list::LinkedList as DL2; - use std::collections::linked_list::LinkedList as DL3; } let dlists = [vec!["std","collections","linked_list","LinkedList"], - vec!["std","collections","linked_list","LinkedList"], vec!["collections","linked_list","LinkedList"]]; for path in &dlists { if match_ty_unwrap(ty, &path[..]).is_some() { -- cgit 1.4.1-3-g733a5 From 164907ece2beef1bc067ac1f2753706b65b09f98 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 16 Aug 2015 17:24:03 +0530 Subject: restrict toplevel_ref_arg to only functions (fixes #170) --- src/misc.rs | 6 +++++- tests/compile-fail/toplevel_ref_arg.rs | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 1fc41cf4862..82ea78d97e1 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -81,7 +81,11 @@ impl LintPass for TopLevelRefPass { lint_array!(TOPLEVEL_REF_ARG) } - fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + fn check_fn(&mut self, cx: &Context, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + if let FnKind::FkFnBlock = k { + // Does not apply to closures + return + } for ref arg in &decl.inputs { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { span_lint(cx, diff --git a/tests/compile-fail/toplevel_ref_arg.rs b/tests/compile-fail/toplevel_ref_arg.rs index cd4d46ee327..ea69a8cfa15 100644 --- a/tests/compile-fail/toplevel_ref_arg.rs +++ b/tests/compile-fail/toplevel_ref_arg.rs @@ -11,5 +11,8 @@ fn the_answer(ref mut x: u8) { //~ ERROR `ref` directly on a function argument fn main() { let mut x = 0; the_answer(x); + // Closures should not warn + let y = |ref x| { println!("{:?}", x) }; + y(1u8); println!("The answer is {}.", x); } -- cgit 1.4.1-3-g733a5 From 03c7d7074d4870588769707a1a8775489d29280a Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 16 Aug 2015 15:56:09 +0200 Subject: With working test now --- src/consts.rs | 13 ++----------- tests/consts.rs | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index c8d5262abab..fd6479df299 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,6 +1,4 @@ -#[cfg(test)] use rustc::lint::Context; - use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; @@ -12,9 +10,6 @@ use std::ops::Deref; use self::ConstantVariant::*; use self::FloatWidth::*; -#[cfg(not(test))] -pub struct Context; - #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum FloatWidth { Fw32, @@ -33,8 +28,8 @@ impl From<FloatTy> for FloatWidth { #[derive(PartialEq, Eq, Debug, Clone)] pub struct Constant { - constant: ConstantVariant, - needed_resolution: bool + pub constant: ConstantVariant, + pub needed_resolution: bool } impl Constant { @@ -187,11 +182,7 @@ fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Optio }) } -#[cfg(test)] -fn fetch_path(_cx: &Context, _expr: &Expr) -> Option<Constant> { None } - /// lookup a possibly constant expression from a ExprPath -#[cfg(not(test))] fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { if let Some(&PathResolution { base_def: DefConst(id), ..}) = cx.tcx.def_map.borrow().get(&e.id) { diff --git a/tests/consts.rs b/tests/consts.rs index edbbfa1e2db..db309952be4 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -1,11 +1,34 @@ +#![allow(plugin_as_library)] +#![feature(rustc_private)] extern crate clippy; +extern crate syntax; +extern crate rustc; -use clippy::consts; +use clippy::consts::constant; +use clippy::consts::ConstantVariant::*; use syntax::ast::*; +use syntax::ptr::P; +use syntax::codemap::{Spanned, COMMAND_LINE_SP}; +use std::mem; +use rustc::lint::Context; + +fn ctx() -> &'static Context<'static, 'static> { + unsafe { + let x : *const Context<'static, 'static> = std::ptr::null(); + mem::transmute(x) + } +} #[test] fn test_lit() { - assert_eq!(ConstantBool(true), constant(&Context, - Expr{ node_id: 1, node: ExprLit(LitBool(true)), span: default() })); + assert_eq!(Some(ConstantBool(true)), constant(ctx(), + &Expr{ + id: 1, + node: ExprLit(P(Spanned{ + node: LitBool(true), + span: COMMAND_LINE_SP, + })), + span: COMMAND_LINE_SP, + }).map(|x| x.constant)); } -- cgit 1.4.1-3-g733a5 From fe0de07b28e2e9c1adcb126eea15ff4de14efb5b Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 16 Aug 2015 16:05:51 +0200 Subject: dogfooded --- src/consts.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index fd6479df299..b636fe1e2a8 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,7 +3,6 @@ use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; use syntax::ast::*; -use syntax::parse::token::InternedString; use syntax::ptr::P; use std::rc::Rc; use std::ops::Deref; @@ -71,11 +70,11 @@ pub enum ConstantVariant { /// true or false ConstantBool(bool), /// an array of constants - ConstantVec(Box<Vec<Constant>>), + ConstantVec(Vec<Constant>), /// also an array, but with only one constant, repeated N times ConstantRepeat(Box<ConstantVariant>, usize), /// a tuple of constants - ConstantTuple(Box<Vec<Constant>>), + ConstantTuple(Vec<Constant>), } impl ConstantVariant { @@ -159,7 +158,7 @@ fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Optio } } Some(Constant { - constant: ConstantVec(Box::new(parts)), + constant: ConstantVec(parts), needed_resolution: resolved }) } @@ -177,7 +176,7 @@ fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Optio } } Some(Constant { - constant: ConstantTuple(Box::new(parts)), + constant: ConstantTuple(parts), needed_resolution: resolved }) } -- cgit 1.4.1-3-g733a5 From 4244f2479f5959118fa90d99fc098f3c3fc897c3 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 16 Aug 2015 16:09:00 +0200 Subject: dogfooding, part 2 --- src/consts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index b636fe1e2a8..95232cd8b73 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -148,7 +148,7 @@ fn lit_to_constant(lit: &Lit_) -> Constant { fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Option<Constant> { let mut parts = Vec::new(); let mut resolved = false; - for opt_part in vec.iter() { + for opt_part in vec { match constant(cx, opt_part) { Some(p) => { resolved |= (&p).needed_resolution; @@ -166,7 +166,7 @@ fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Optio fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Option<Constant> { let mut parts = Vec::new(); let mut resolved = false; - for opt_part in tup.iter() { + for opt_part in tup { match constant(cx, opt_part) { Some(p) => { resolved |= (&p).needed_resolution; @@ -224,8 +224,8 @@ fn constant_negate(o: Constant) -> Option<Constant> { UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), _ => { return None; }, }), - ConstantFloat(ref is, ty) => - ConstantFloat(neg_float_str(is.to_string()), ty), + ConstantFloat(is, ty) => + ConstantFloat(neg_float_str(is), ty), _ => { return None; }, } }) @@ -278,7 +278,7 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) BiAdd => constant_binop_apply(cx, left, right, |l, r| match (l, r) { (ConstantByte(l8), ConstantByte(r8)) => - l8.checked_add(r8).map(|v| ConstantByte(v)), + l8.checked_add(r8).map(ConstantByte), (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { let (ln, rn) = (is_negative(lty), is_negative(rty)); if ln == rn { -- cgit 1.4.1-3-g733a5 From 23a38c4170887401b3c75f9ad4443ab1f6beae11 Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Sat, 15 Aug 2015 12:55:25 -0400 Subject: New lint: Range::step_by(0) (fixes #95) Uses type information so it can detect non-literal ranges as well (Range or RangeFrom -- the other range types don't have step_by). --- README.md | 1 + src/lib.rs | 3 +++ src/ranges.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/range.rs | 24 +++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 src/ranges.rs create mode 100644 tests/compile-fail/range.rs (limited to 'src') diff --git a/README.md b/README.md index d9dea816318..bc82b2ee533 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ non_ascii_literal | allow | using any literal non-ASCII chars in a string l option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead diff --git a/src/lib.rs b/src/lib.rs index 01a2d65606c..91859005bf3 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ pub mod methods; pub mod returns; pub mod lifetimes; pub mod loops; +pub mod ranges; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -64,6 +65,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::LetPass as LintPassObject); reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); + reg.register_lint_pass(box ranges::StepByZero as LintPassObject); reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, @@ -93,6 +95,7 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, ptr_arg::PTR_ARG, + ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, strings::STRING_ADD, diff --git a/src/ranges.rs b/src/ranges.rs new file mode 100644 index 00000000000..2981574e502 --- /dev/null +++ b/src/ranges.rs @@ -0,0 +1,52 @@ +use rustc::lint::{Context, LintArray, LintPass}; +use rustc::middle::ty::TypeVariants::TyStruct; +use syntax::ast::*; +use syntax::codemap::Spanned; +use utils::{match_def_path, walk_ptrs_ty}; + +declare_lint! { + pub RANGE_STEP_BY_ZERO, Warn, + "using Range::step_by(0), which produces an infinite iterator" +} + +#[derive(Copy,Clone)] +pub struct StepByZero; + +impl LintPass for StepByZero { + fn get_lints(&self) -> LintArray { + lint_array!(RANGE_STEP_BY_ZERO) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprMethodCall(Spanned { node: ref ident, .. }, _, + ref args) = expr.node { + // Only warn on literal ranges. + if ident.name.as_str() == "step_by" && args.len() == 2 && + is_range(cx, &args[0]) && is_lit_zero(&args[1]) { + cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, + "Range::step_by(0) produces an infinite iterator. \ + Consider using `std::iter::repeat()` instead") + } + } + } +} + +fn is_range(cx: &Context, expr: &Expr) -> bool { + // No need for walk_ptrs_ty here because step_by moves self, so it + // can't be called on a borrowed range. + if let TyStruct(did, _) = cx.tcx.expr_ty(expr).sty { + // Note: RangeTo and RangeFull don't have step_by + match_def_path(cx, did.did, &["core", "ops", "Range"]) || + match_def_path(cx, did.did, &["core", "ops", "RangeFrom"]) + } else { false } +} + +fn is_lit_zero(expr: &Expr) -> bool { + // FIXME: use constant folding + if let ExprLit(ref spanned) = expr.node { + if let LitInt(0, _) = spanned.node { + return true; + } + } + false +} diff --git a/tests/compile-fail/range.rs b/tests/compile-fail/range.rs new file mode 100644 index 00000000000..324f129fafa --- /dev/null +++ b/tests/compile-fail/range.rs @@ -0,0 +1,24 @@ +#![feature(step_by)] +#![feature(plugin)] +#![plugin(clippy)] + +struct NotARange; +impl NotARange { + fn step_by(&self, _: u32) {} +} + +#[deny(range_step_by_zero)] +fn main() { + (0..1).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator + // No warning for non-zero step + (0..1).step_by(1); + + (1..).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator + + let x = 0..1; + x.step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator + + // No error, not a range. + let y = NotARange; + y.step_by(0); +} -- cgit 1.4.1-3-g733a5 From 759b45a46d299f19a10477cc226e70002ac91340 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 16 Aug 2015 23:09:56 +0200 Subject: made is_negative(..) public (+doctest), fixed identity_op and precedence --- src/consts.rs | 9 +++++++- src/identity_op.rs | 44 +++++++++++++-------------------------- tests/compile-fail/cmp_owned.rs | 3 +++ tests/compile-fail/identity_op.rs | 8 +++---- tests/compile-fail/precedence.rs | 1 + 5 files changed, 31 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 95232cd8b73..bb74b3c71d1 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -246,7 +246,14 @@ fn neg_float_str(s: String) -> String { } } -fn is_negative(ty: LitIntType) -> bool { +/// is the given LitIntType negative? +/// +/// Examples +/// +/// ``` +/// assert!(is_negative(UnsuffixedIntLit(Minus))); +/// ``` +pub fn is_negative(ty: LitIntType) -> bool { match ty { SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, UnsignedIntLit(_) => false, diff --git a/src/identity_op.rs b/src/identity_op.rs index 8c6940e3df4..445bef0125b 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -7,6 +7,8 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use syntax::codemap::Span; +use consts::{constant, Constant, is_negative}; +use consts::ConstantVariant::ConstantInt; use utils::{span_lint, snippet}; declare_lint! { pub IDENTITY_OP, Warn, @@ -47,35 +49,19 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { - if have_lit(cx, e, m) { - span_lint(cx, IDENTITY_OP, span, &format!( - "the operation is ineffective. Consider reducing it to `{}`", - snippet(cx, arg, ".."))); - } -} - -fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool { - match &e.node { - &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m), - &ExprLit(ref lit) => { - match (&lit.node, m) { - (&LitInt(0, _), 0) => true, - (&LitInt(1, SignedIntLit(_, Plus)), 1) => true, - (&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true, - (&LitInt(1, SignedIntLit(_, Minus)), -1) => true, - (&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true, - _ => false + if let Some(c) = constant(cx, e) { + if c.needed_resolution { return; } // skip linting w/ lookup for now + if let ConstantInt(v, ty) = c.constant { + if match m { + 0 => v == 0, + -1 => is_negative(ty), + 1 => !is_negative(ty), + _ => unreachable!(), + } { + span_lint(cx, IDENTITY_OP, span, &format!( + "the operation is ineffective. Consider reducing it to `{}`", + snippet(cx, arg, ".."))); } - }, - &ExprParen(ref p) => have_lit(cx, p, m), - &ExprPath(_, _) => { - match cx.tcx.def_map.borrow().get(&e.id) { - Some(&PathResolution { base_def: DefConst(id), ..}) => - lookup_const_by_id(cx.tcx, id, Option::None) - .map_or(false, |l| have_lit(cx, l, m)), - _ => false - } - }, - _ => false + } } } diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index 2e1a8cfd819..2765da5cf23 100755 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -13,5 +13,8 @@ fn main() { x != "foo".to_owned(); //~ERROR this creates an owned instance + // removed String::from_str(..), as it has finally been removed in 1.4.0 + // as of 2015-08-14 + x != String::from("foo"); //~ERROR this creates an owned instance } diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs index 987bada2ece..18e683e8a9e 100755 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -11,14 +11,14 @@ fn main() { x + 0; //~ERROR the operation is ineffective 0 + x; //~ERROR the operation is ineffective - x - ZERO; //~ERROR the operation is ineffective + x - ZERO; //no error, as we skip lookups (for now) x | (0); //~ERROR the operation is ineffective - ((ZERO)) | x; //~ERROR the operation is ineffective + ((ZERO)) | x; //no error, as we skip lookups (for now) x * 1; //~ERROR the operation is ineffective 1 * x; //~ERROR the operation is ineffective - x / ONE; //~ERROR the operation is ineffective + x / ONE; //no error, as we skip lookups (for now) - x & NEG_ONE; //~ERROR the operation is ineffective + x & NEG_ONE; //no error, as we skip lookups (for now) -1 & x; //~ERROR the operation is ineffective } diff --git a/tests/compile-fail/precedence.rs b/tests/compile-fail/precedence.rs index 4d57f119479..ebb25f61b75 100755 --- a/tests/compile-fail/precedence.rs +++ b/tests/compile-fail/precedence.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #[deny(precedence)] +#[allow(identity_op)] #[allow(eq_op)] fn main() { format!("{} vs. {}", 1 << 2 + 3, (1 << 2) + 3); //~ERROR operator precedence can trip -- cgit 1.4.1-3-g733a5 From e9a41e2374878d8537fab4f607f8f1c1401b0389 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 17 Aug 2015 07:23:57 +0200 Subject: new lint: lint when iterating over any Iterator::next() result (fixes #182) --- README.md | 1 + src/lib.rs | 1 + src/loops.rs | 25 +++++++++++++++++++++---- tests/compile-fail/for_loop.rs | 14 +++++++++++++- 4 files changed, 36 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index bc82b2ee533..5ec1040b2c4 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ float_cmp | warn | using `==` or `!=` on float values (as floating identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` inline_always | warn | `#[inline(always)]` is a bad idea in most cases +iter_next_loop | warn | for-looping over `_.next()` which is probably not intended len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function diff --git a/src/lib.rs b/src/lib.rs index 967865b2c0c..4c0617b1696 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, loops::EXPLICIT_ITER_LOOP, + loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/src/loops.rs b/src/loops.rs index 092b5ce1196..44827d08bcd 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,9 +1,10 @@ use rustc::lint::*; use syntax::ast::*; use syntax::visit::{Visitor, walk_expr}; +use rustc::middle::ty; use std::collections::HashSet; -use utils::{snippet, span_lint, get_parent_expr}; +use utils::{snippet, span_lint, get_parent_expr, match_def_path}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, "for-looping over a range of indices where an iterator over items would do" } @@ -11,12 +12,15 @@ declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" } +declare_lint!{ pub ITER_NEXT_LOOP, Warn, + "for-looping over `_.next()` which is probably not intended" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP) + lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -47,11 +51,11 @@ impl LintPass for LoopsPass { } } - // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x if let ExprMethodCall(ref method, _, ref args) = arg.node { - // just the receiver, no arguments to iter() or iter_mut() + // just the receiver, no arguments if args.len() == 1 { let method_name = method.node.name; + // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x if method_name == "iter" { let object = snippet(cx, args[0].span, "_"); span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( @@ -62,6 +66,19 @@ impl LintPass for LoopsPass { span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( "it is more idiomatic to loop over `&mut {}` instead of `{}.iter_mut()`", object, object)); + // check for looping over Iterator::next() which is not what you want + } else if method_name == "next" { + let method_call = ty::MethodCall::expr(arg.id); + let trt_id = cx.tcx.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 { + if match_def_path(cx, trt_id, &["core", "iter", "Iterator"]) { + span_lint(cx, ITER_NEXT_LOOP, expr.span, + "you are iterating over `Iterator::next()` which is an Option; \ + this will compile but is probably not what you want"); + } + } } } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 550f9869291..a4e3cc31a88 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -1,7 +1,14 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(needless_range_loop, explicit_iter_loop)] +struct Unrelated(Vec<u8>); +impl Unrelated { + fn next(&self) -> std::slice::Iter<u8> { + self.0.iter() + } +} + +#[deny(needless_range_loop, explicit_iter_loop, iter_next_loop)] fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; @@ -20,4 +27,9 @@ fn main() { for _v in &vec { } // these are fine for _v in &mut vec { } // these are fine + + for _v in vec.iter().next() { } //~ERROR you are iterating over `Iterator::next()` + + let u = Unrelated(vec![]); + for _v in u.next() { } // no error } -- cgit 1.4.1-3-g733a5 From caeb72c47bacfcc9e8be07470d682a562482f502 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 17 Aug 2015 07:30:33 +0200 Subject: loops: fix two trailing periods in lint msgs --- src/loops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 092b5ce1196..064d1eb3932 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -35,12 +35,12 @@ impl LintPass for LoopsPass { if visitor.nonindex { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is used to index `{}`. Consider using \ - `for ({}, item) in {}.iter().enumerate()` or similar iterators.", + `for ({}, item) in {}.iter().enumerate()` or similar iterators", ident.node.name, indexed, ident.node.name, indexed)); } else { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in &{}` or similar iterators.", + Consider using `for item in &{}` or similar iterators", ident.node.name, indexed, indexed)); } } -- cgit 1.4.1-3-g733a5 From fb715ce45dfb1fbaab94387332bee13f12336a43 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 11:43:36 +0200 Subject: fix 189, fixed a few warnings, ==/!= for consts, refactored consts test --- src/consts.rs | 8 +++++--- src/identity_op.rs | 8 +++----- src/ranges.rs | 2 +- tests/consts.rs | 37 +++++++++++++++++++++++-------------- 4 files changed, 32 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index bb74b3c71d1..c931fb15bb8 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -53,7 +53,7 @@ impl Constant { } /// a Lit_-like enum to fold constant `Expr`s into -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone)] //TODO: A better PartialEq, remove Eq pub enum ConstantVariant { /// a String "abc" ConstantStr(String, StrStyle), @@ -332,10 +332,12 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) //BiBitOr, //BiShl, //BiShr, - //BiEq, + BiEq => constant_binop_apply(cx, left, right, + |l, r| Some(ConstantBool(l == r))), //BiLt, //BiLe, - //BiNe, + BiNe => constant_binop_apply(cx, left, right, + |l, r| Some(ConstantBool(l != r))), //BiGe, //BiGt, _ => None, diff --git a/src/identity_op.rs b/src/identity_op.rs index a429d42c4cc..9f415e5decb 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,10 +1,8 @@ use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; use syntax::ast::*; use syntax::codemap::Span; -use consts::{constant, Constant, is_negative}; +use consts::{constant, is_negative}; use consts::ConstantVariant::ConstantInt; use utils::{span_lint, snippet}; @@ -51,8 +49,8 @@ fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { if let ConstantInt(v, ty) = c.constant { if match m { 0 => v == 0, - -1 => is_negative(ty), - 1 => !is_negative(ty), + -1 => is_negative(ty) && v == 1, + 1 => !is_negative(ty) && v == 1, _ => unreachable!(), } { span_lint(cx, IDENTITY_OP, span, &format!( diff --git a/src/ranges.rs b/src/ranges.rs index 2981574e502..bbe65285d58 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -2,7 +2,7 @@ use rustc::lint::{Context, LintArray, LintPass}; use rustc::middle::ty::TypeVariants::TyStruct; use syntax::ast::*; use syntax::codemap::Spanned; -use utils::{match_def_path, walk_ptrs_ty}; +use utils::{match_def_path}; declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, diff --git a/tests/consts.rs b/tests/consts.rs index db309952be4..4f7b87d5e02 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -5,7 +5,7 @@ extern crate clippy; extern crate syntax; extern crate rustc; -use clippy::consts::constant; +use clippy::consts::{constant, ConstantVariant}; use clippy::consts::ConstantVariant::*; use syntax::ast::*; use syntax::ptr::P; @@ -14,21 +14,30 @@ use std::mem; use rustc::lint::Context; fn ctx() -> &'static Context<'static, 'static> { - unsafe { - let x : *const Context<'static, 'static> = std::ptr::null(); - mem::transmute(x) - } + unsafe { + let x : *const Context<'static, 'static> = std::ptr::null(); + mem::transmute(x) + } +} + +fn lit(l: Lit_) -> Expr { + Expr{ + id: 1, + node: ExprLit(P(Spanned{ + node: l, + span: COMMAND_LINE_SP, + })), + span: COMMAND_LINE_SP, + } +} + +fn check(expect: ConstantVariant, expr: &Expr) { + assert_eq!(Some(expect), constant(ctx(), expr).map(|x| x.constant)) } #[test] fn test_lit() { - assert_eq!(Some(ConstantBool(true)), constant(ctx(), - &Expr{ - id: 1, - node: ExprLit(P(Spanned{ - node: LitBool(true), - span: COMMAND_LINE_SP, - })), - span: COMMAND_LINE_SP, - }).map(|x| x.constant)); + check(ConstantBool(true), &lit(LitBool(true))); + check(ConstantBool(false), &lit(LitBool(false))); + } -- cgit 1.4.1-3-g733a5 From 0e67c0134fbb7764ed7bd1532b0e15f1bfd17044 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 12:06:56 +0200 Subject: make float_cmp check for zero --- src/misc.rs | 5 +++++ tests/compile-fail/float_cmp.rs | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 82ea78d97e1..33c34eb9b84 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -9,6 +9,7 @@ use rustc::middle::ty; use std::borrow::Cow; use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty}; +use consts::constant; /// Handles uncategorized lints /// Currently handles linting of if-let-able matches @@ -147,6 +148,10 @@ impl LintPass for FloatCmp { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { + if constant(cx, left).or_else(|| constant(cx, right)).map_or( + false, |c| c.as_float().map_or(false, |f| f == 0.0)) { + return; + } span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-comparison of f32 or f64 detected. Consider changing this to \ `abs({} - {}) < epsilon` for some suitable value of epsilon", diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index 419e500d0fc..067ec2818bf 100755 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -13,22 +13,30 @@ fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy { #[deny(float_cmp)] #[allow(unused)] fn main() { - ZERO == 0f32; //~ERROR ==-comparison of f32 or f64 - ZERO == 0.0; //~ERROR ==-comparison of f32 or f64 + ZERO == 0f32; //no error, comparison with zero is ok + ZERO == 0.0; //no error, comparison with zero is ok ZERO + ZERO != 1.0; //~ERROR !=-comparison of f32 or f64 - ONE != 0.0; //~ERROR + ONE == 1f32; //~ERROR ==-comparison of f32 or f64 + ONE == (1.0 + 0.0); //~ERROR ==-comparison of f32 or f64 + + ONE + ONE == (ZERO + ONE + ONE); //~ERROR ==-comparison of f32 or f64 + + ONE != 2.0; //~ERROR !=-comparison of f32 or f64 + ONE != 0.0; // no error, comparison with zero is ok twice(ONE) != ONE; //~ERROR !=-comparison of f32 or f64 - ONE as f64 != 0.0; //~ERROR !=-comparison of f32 or f64 + ONE as f64 != 2.0; //~ERROR !=-comparison of f32 or f64 + ONE as f64 != 0.0; // no error, comparison with zero is ok let x : f64 = 1.0; x == 1.0; //~ERROR ==-comparison of f32 or f64 - x != 0f64; //~ERROR !=-comparison of f32 or f64 + x != 0f64; // no error, comparison with zero is ok twice(x) != twice(ONE as f64); //~ERROR !=-comparison of f32 or f64 - x < 0.0; + + x < 0.0; // no errors, lower or greater comparisons need no fuzzyness x > 0.0; x <= 0.0; x >= 0.0; -- cgit 1.4.1-3-g733a5 From 9f134f8e9559a339d5d98f3d3ef9ba3d15ae9b18 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 13:18:14 +0200 Subject: added PartialEq/PartialOrd to ConstantVariant, used to implement comparing binops --- src/consts.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- tests/consts.rs | 6 +++- 2 files changed, 92 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index c931fb15bb8..7cbbec1c451 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -4,6 +4,8 @@ use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; use syntax::ast::*; use syntax::ptr::P; +use std::cmp::PartialOrd; +use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; use self::ConstantVariant::*; @@ -52,8 +54,14 @@ impl Constant { } } +impl PartialOrd for Constant { + fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { + self.constant.partial_cmp(&other.constant) + } +} + /// a Lit_-like enum to fold constant `Expr`s into -#[derive(PartialEq, Eq, Debug, Clone)] //TODO: A better PartialEq, remove Eq +#[derive(Eq, Debug, Clone)] pub enum ConstantVariant { /// a String "abc" ConstantStr(String, StrStyle), @@ -92,6 +100,73 @@ impl ConstantVariant { } } +impl PartialEq for ConstantVariant { + fn eq(&self, other: &ConstantVariant) -> bool { + match (self, other) { + (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => + ls == rs && lsty == rsty, + (&ConstantBinary(ref l),&ConstantBinary(ref r)) => l == r, + (&ConstantByte(l), &ConstantByte(r)) => l == r, + (&ConstantChar(l), &ConstantChar(r)) => l == r, + (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => lv == rv && + is_negative(lty) == is_negative(rty), + (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => + if match (lw, rw) { + (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, + _ => false, + } { + match (ls.parse::<f64>(), rs.parse()) { + (Ok(l), Ok(r)) => l == r, + _ => false, + } + } else { false }, + (&ConstantBool(l), &ConstantBool(r)) => l == r, + (&ConstantVec(ref l), &ConstantVec(ref r)) => l == r, + (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => + ls == rs && lv == rv, + (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l == r, + _ => false, //TODO: Are there inter-type equalities? + } + } +} + +impl PartialOrd for ConstantVariant { + fn partial_cmp(&self, other: &ConstantVariant) -> Option<Ordering> { + match (self, other) { + (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => + if lsty != rsty { None } else { Some(ls.cmp(rs)) }, + (&ConstantByte(ref l), &ConstantByte(ref r)) => Some(l.cmp(r)), + (&ConstantChar(ref l), &ConstantChar(ref r)) => Some(l.cmp(r)), + (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => + Some(match (is_negative(lty), is_negative(rty)) { + (true, true) => lv.cmp(rv), + (false, false) => rv.cmp(lv), + (true, false) => Greater, + (false, true) => Less, + }), + (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => + if match (lw, rw) { + (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, + _ => false, + } { + match (ls.parse::<f64>(), rs.parse::<f64>()) { + (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), + _ => None, + } + } else { None }, + (&ConstantBool(ref l), &ConstantBool(ref r)) => Some(l.cmp(r)), + (&ConstantVec(ref l), &ConstantVec(ref r)) => l.partial_cmp(&r), + (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => + match lv.partial_cmp(rv) { + Some(Equal) => Some(ls.cmp(rs)), + x => x, + }, + (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l.partial_cmp(r), + _ => None, //TODO: Are there any useful inter-type orderings? + } + } +} + /// simple constant folding: Insert an expression, get a constant or none. pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { match &e.node { @@ -300,7 +375,7 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) } } }, - // TODO: float + // TODO: float (would need bignum library?) _ => None }), BiSub => constant_binop_apply(cx, left, right, |l, r| @@ -334,16 +409,22 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) //BiShr, BiEq => constant_binop_apply(cx, left, right, |l, r| Some(ConstantBool(l == r))), - //BiLt, - //BiLe, BiNe => constant_binop_apply(cx, left, right, |l, r| Some(ConstantBool(l != r))), - //BiGe, - //BiGt, + BiLt => constant_cmp(cx, left, right, Less, true), + BiLe => constant_cmp(cx, left, right, Greater, false), + BiGe => constant_cmp(cx, left, right, Less, false), + BiGt => constant_cmp(cx, left, right, Greater, true), _ => None, } } +fn constant_cmp(cx: &Context, left: &Expr, right: &Expr, ordering: Ordering, + b: bool) -> Option<Constant> { + constant_binop_apply(cx, left, right, |l, r| l.partial_cmp(&r).map(|o| + ConstantBool(b == (o == ordering)))) +} + fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> Option<ConstantVariant> { if neg > pos { diff --git a/tests/consts.rs b/tests/consts.rs index 4f7b87d5e02..a7d84ee0ae9 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -8,6 +8,7 @@ extern crate rustc; use clippy::consts::{constant, ConstantVariant}; use clippy::consts::ConstantVariant::*; use syntax::ast::*; +use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; use std::mem; @@ -39,5 +40,8 @@ fn check(expect: ConstantVariant, expr: &Expr) { fn test_lit() { check(ConstantBool(true), &lit(LitBool(true))); check(ConstantBool(false), &lit(LitBool(false))); - + check(ConstantInt(0, UnsuffixedIntLit(Plus)), + &lit(LitInt(0, UnsuffixedIntLit(Plus)))); + check(ConstantStr("cool!".into(), CookedStr), &lit(LitStr( + InternedString::new("cool!"), CookedStr))); } -- cgit 1.4.1-3-g733a5 From 4394362836a2fb8ba0b8c225eb5ef0b441272897 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 13:23:17 +0200 Subject: dogfooding --- src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 7cbbec1c451..e39faf9e39a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -115,8 +115,8 @@ impl PartialEq for ConstantVariant { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, } { - match (ls.parse::<f64>(), rs.parse()) { - (Ok(l), Ok(r)) => l == r, + match (ls.parse::<f64>(), rs.parse::<f64>()) { + (Ok(l), Ok(r)) => l.eq(&r), _ => false, } } else { false }, -- cgit 1.4.1-3-g733a5 From c47402416bf611fa2b7742abfa94ddcef8e5501a Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 15:11:36 +0200 Subject: Added bit operations to const folding --- src/consts.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index e39faf9e39a..01fb3520f2c 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -402,11 +402,11 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) //BiRem, BiAnd => constant_short_circuit(cx, left, right, false), BiOr => constant_short_circuit(cx, left, right, true), - //BiBitXor, - //BiBitAnd, - //BiBitOr, - //BiShl, - //BiShr, + BiBitXor => constant_bitop(cx, left, right, |x, y| x ^ y), + BiBitAnd => constant_bitop(cx, left, right, |x, y| x & y), + BiBitOr => constant_bitop(cx, left, right, |x, y| (x | y)), + BiShl => constant_bitop(cx, left, right, |x, y| x << y), + BiShr => constant_bitop(cx, left, right, |x, y| x >> y), BiEq => constant_binop_apply(cx, left, right, |l, r| Some(ConstantBool(l == r))), BiNe => constant_binop_apply(cx, left, right, @@ -415,10 +415,23 @@ fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) BiLe => constant_cmp(cx, left, right, Greater, false), BiGe => constant_cmp(cx, left, right, Less, false), BiGt => constant_cmp(cx, left, right, Greater, true), - _ => None, + _ => None } } +fn constant_bitop<F>(cx: &Context, left: &Expr, right: &Expr, f: F) + -> Option<Constant> where F: Fn(u64, u64) -> u64 { + constant_binop_apply(cx, left, right, |l, r| match (l, r) { + (ConstantBool(l), ConstantBool(r)) => + Some(ConstantBool(f(l as u64, r as u64) != 0)), + (ConstantByte(l8), ConstantByte(r8)) => + Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), + (ConstantInt(l, lty), ConstantInt(r, rty)) => + unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)), + _ => None + }) +} + fn constant_cmp(cx: &Context, left: &Expr, right: &Expr, ordering: Ordering, b: bool) -> Option<Constant> { constant_binop_apply(cx, left, right, |l, r| l.partial_cmp(&r).map(|o| -- cgit 1.4.1-3-g733a5 From a2ee637be61ef1848e2f5c47a6d3a202057e992f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 17 Aug 2015 16:24:57 +0200 Subject: added test and fixed negativity check in Partial{Eq, Ord} impl --- src/consts.rs | 5 +++-- tests/consts.rs | 44 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 01fb3520f2c..0f212e3b8ef 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -109,7 +109,7 @@ impl PartialEq for ConstantVariant { (&ConstantByte(l), &ConstantByte(r)) => l == r, (&ConstantChar(l), &ConstantChar(r)) => l == r, (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => lv == rv && - is_negative(lty) == is_negative(rty), + (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)), (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, @@ -138,7 +138,8 @@ impl PartialOrd for ConstantVariant { (&ConstantByte(ref l), &ConstantByte(ref r)) => Some(l.cmp(r)), (&ConstantChar(ref l), &ConstantChar(ref r)) => Some(l.cmp(r)), (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => - Some(match (is_negative(lty), is_negative(rty)) { + Some(match (is_negative(lty) && *lv != 0, + is_negative(rty) && *rv != 0) { (true, true) => lv.cmp(rv), (false, false) => rv.cmp(lv), (true, false) => Greater, diff --git a/tests/consts.rs b/tests/consts.rs index a7d84ee0ae9..3b05dd67ad5 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -21,27 +21,53 @@ fn ctx() -> &'static Context<'static, 'static> { } } -fn lit(l: Lit_) -> Expr { +fn spanned<T>(t: T) -> Spanned<T> { + Spanned{ node: t, span: COMMAND_LINE_SP } +} + +fn expr(n: Expr_) -> Expr { Expr{ id: 1, - node: ExprLit(P(Spanned{ - node: l, - span: COMMAND_LINE_SP, - })), + node: n, span: COMMAND_LINE_SP, } } +fn lit(l: Lit_) -> Expr { + expr(ExprLit(P(spanned(l)))) +} + +fn binop(op: BinOp_, l: Expr, r: Expr) -> Expr { + expr(ExprBinary(spanned(op), P(l), P(r))) +} + fn check(expect: ConstantVariant, expr: &Expr) { assert_eq!(Some(expect), constant(ctx(), expr).map(|x| x.constant)) } +const TRUE : ConstantVariant = ConstantBool(true); +const FALSE : ConstantVariant = ConstantBool(false); +const ZERO : ConstantVariant = ConstantInt(0, UnsuffixedIntLit(Plus)); + #[test] fn test_lit() { - check(ConstantBool(true), &lit(LitBool(true))); - check(ConstantBool(false), &lit(LitBool(false))); - check(ConstantInt(0, UnsuffixedIntLit(Plus)), - &lit(LitInt(0, UnsuffixedIntLit(Plus)))); + check(TRUE, &lit(LitBool(true))); + check(FALSE, &lit(LitBool(false))); + check(ZERO, &lit(LitInt(0, UnsuffixedIntLit(Plus)))); check(ConstantStr("cool!".into(), CookedStr), &lit(LitStr( InternedString::new("cool!"), CookedStr))); } + +#[test] +fn test_ops() { + check(TRUE, &binop(BiOr, lit(LitBool(false)), lit(LitBool(true)))); + check(FALSE, &binop(BiAnd, lit(LitBool(false)), lit(LitBool(true)))); + + let litzero = lit(LitInt(0, UnsuffixedIntLit(Plus))); + check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone())); + check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone())); + check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone())); + check(FALSE, &binop(BiNe, litzero.clone(), litzero.clone())); + check(FALSE, &binop(BiGt, litzero.clone(), litzero.clone())); + check(FALSE, &binop(BiLt, litzero.clone(), litzero.clone())); +} -- cgit 1.4.1-3-g733a5 From a2dcbfea65d87a8431a739d38d2a022bc68de15d Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 17 Aug 2015 16:45:50 +0200 Subject: const eval: implement ! for integers --- src/consts.rs | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 0f212e3b8ef..239f72e8774 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -105,7 +105,7 @@ impl PartialEq for ConstantVariant { match (self, other) { (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => ls == rs && lsty == rsty, - (&ConstantBinary(ref l),&ConstantBinary(ref r)) => l == r, + (&ConstantBinary(ref l), &ConstantBinary(ref r)) => l == r, (&ConstantByte(l), &ConstantByte(r)) => l == r, (&ConstantChar(l), &ConstantChar(r)) => l == r, (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => lv == rv && @@ -184,13 +184,7 @@ pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), &ExprUnary(op, ref operand) => constant(cx, operand).and_then( |o| match op { - UnNot => - if let ConstantBool(b) = o.constant { - Some(Constant{ - needed_resolution: o.needed_resolution, - constant: ConstantBool(!b), - }) - } else { None }, + UnNot => constant_not(o), UnNeg => constant_negate(o), UnUniq | UnDeref => Some(o), }), @@ -227,7 +221,7 @@ fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Optio for opt_part in vec { match constant(cx, opt_part) { Some(p) => { - resolved |= (&p).needed_resolution; + resolved |= p.needed_resolution; parts.push(p) }, None => { return None; }, @@ -245,7 +239,7 @@ fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Optio for opt_part in tup { match constant(cx, opt_part) { Some(p) => { - resolved |= (&p).needed_resolution; + resolved |= p.needed_resolution; parts.push(p) }, None => { return None; }, @@ -289,6 +283,43 @@ fn constant_if(cx: &Context, cond: &Expr, then: &Block, otherwise: } else { None } } +fn constant_not(o: Constant) -> Option<Constant> { + Some(Constant { + needed_resolution: o.needed_resolution, + constant: match o.constant { + ConstantBool(b) => ConstantBool(!b), + ConstantInt(value, ty) => { + let (nvalue, nty) = match ty { + SignedIntLit(ity, Plus) => { + if value == ::std::u64::MAX { return None; } + (value + 1, SignedIntLit(ity, Minus)) + }, + SignedIntLit(ity, Minus) => { + if value == 0 { + (1, SignedIntLit(ity, Minus)) + } else { + (value - 1, SignedIntLit(ity, Plus)) + } + } + UnsignedIntLit(ity) => { + let mask = match ity { + UintTy::TyU8 => ::std::u8::MAX as u64, + UintTy::TyU16 => ::std::u16::MAX as u64, + UintTy::TyU32 => ::std::u32::MAX as u64, + UintTy::TyU64 => ::std::u64::MAX, + UintTy::TyUs => { return None; } // refuse to guess + }; + (!value & mask, UnsignedIntLit(ity)) + } + UnsuffixedIntLit(_) => { return None; } // refuse to guess + }; + ConstantInt(nvalue, nty) + }, + _ => { return None; } + } + }) +} + fn constant_negate(o: Constant) -> Option<Constant> { Some(Constant{ needed_resolution: o.needed_resolution, -- cgit 1.4.1-3-g733a5 From 7f52239cab61f58c46f89c1a83616186a873c921 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 17 Aug 2015 17:51:30 +0200 Subject: consts: convert to using a struct with state Struct has the context reference (as an Option) and the needed_resolution flag. --- src/consts.rs | 587 +++++++++++++++++++++++++---------------------------- src/identity_op.rs | 8 +- src/misc.rs | 2 +- tests/consts.rs | 22 +- 4 files changed, 289 insertions(+), 330 deletions(-) mode change 100644 => 100755 tests/consts.rs (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 239f72e8774..df669007b1e 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -8,7 +8,7 @@ use std::cmp::PartialOrd; use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; -use self::ConstantVariant::*; +use self::Constant::*; use self::FloatWidth::*; #[derive(PartialEq, Eq, Debug, Copy, Clone)] @@ -27,42 +27,9 @@ impl From<FloatTy> for FloatWidth { } } -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Constant { - pub constant: ConstantVariant, - pub needed_resolution: bool -} - -impl Constant { - pub fn new(variant: ConstantVariant) -> Constant { - Constant { constant: variant, needed_resolution: false } - } - - pub fn new_resolved(variant: ConstantVariant) -> Constant { - Constant { constant: variant, needed_resolution: true } - } - - // convert this constant to a f64, if possible - pub fn as_float(&self) -> Option<f64> { - match &self.constant { - &ConstantByte(b) => Some(b as f64), - &ConstantFloat(ref s, _) => s.parse().ok(), - &ConstantInt(i, ty) => Some(if is_negative(ty) { - -(i as f64) } else { i as f64 }), - _ => None - } - } -} - -impl PartialOrd for Constant { - fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { - self.constant.partial_cmp(&other.constant) - } -} - /// a Lit_-like enum to fold constant `Expr`s into #[derive(Eq, Debug, Clone)] -pub enum ConstantVariant { +pub enum Constant { /// a String "abc" ConstantStr(String, StrStyle), /// a Binary String b"abc" @@ -80,12 +47,12 @@ pub enum ConstantVariant { /// an array of constants ConstantVec(Vec<Constant>), /// also an array, but with only one constant, repeated N times - ConstantRepeat(Box<ConstantVariant>, usize), + ConstantRepeat(Box<Constant>, usize), /// a tuple of constants ConstantTuple(Vec<Constant>), } -impl ConstantVariant { +impl Constant { /// convert to u64 if possible /// /// # panics @@ -98,10 +65,21 @@ impl ConstantVariant { panic!("Could not convert a {:?} to u64"); } } + + /// convert this constant to a f64, if possible + pub fn as_float(&self) -> Option<f64> { + match *self { + ConstantByte(b) => Some(b as f64), + ConstantFloat(ref s, _) => s.parse().ok(), + ConstantInt(i, ty) => Some(if is_negative(ty) { + -(i as f64) } else { i as f64 }), + _ => None + } + } } -impl PartialEq for ConstantVariant { - fn eq(&self, other: &ConstantVariant) -> bool { +impl PartialEq for Constant { + fn eq(&self, other: &Constant) -> bool { match (self, other) { (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => ls == rs && lsty == rsty, @@ -130,8 +108,8 @@ impl PartialEq for ConstantVariant { } } -impl PartialOrd for ConstantVariant { - fn partial_cmp(&self, other: &ConstantVariant) -> Option<Ordering> { +impl PartialOrd for Constant { + fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => if lsty != rsty { None } else { Some(ls.cmp(rs)) }, @@ -168,173 +146,67 @@ impl PartialOrd for ConstantVariant { } } -/// simple constant folding: Insert an expression, get a constant or none. -pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> { - match &e.node { - &ExprParen(ref inner) => constant(cx, inner), - &ExprPath(_, _) => fetch_path(cx, e), - &ExprBlock(ref block) => constant_block(cx, block), - &ExprIf(ref cond, ref then, ref otherwise) => - constant_if(cx, &*cond, &*then, &*otherwise), - &ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), - &ExprVec(ref vec) => constant_vec(cx, &vec[..]), - &ExprTup(ref tup) => constant_tup(cx, &tup[..]), - &ExprRepeat(ref value, ref number) => - constant_binop_apply(cx, value, number,|v, n| - Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), - &ExprUnary(op, ref operand) => constant(cx, operand).and_then( - |o| match op { - UnNot => constant_not(o), - UnNeg => constant_negate(o), - UnUniq | UnDeref => Some(o), - }), - &ExprBinary(op, ref left, ref right) => - constant_binop(cx, op, left, right), - //TODO: add other expressions - _ => None, - } -} + fn lit_to_constant(lit: &Lit_) -> Constant { match lit { - &LitStr(ref is, style) => - Constant::new(ConstantStr(is.to_string(), style)), - &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())), - &LitByte(b) => Constant::new(ConstantByte(b)), - &LitChar(c) => Constant::new(ConstantChar(c)), - &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)), - &LitFloat(ref is, ty) => { - Constant::new(ConstantFloat(is.to_string(), ty.into())) - }, - &LitFloatUnsuffixed(ref is) => { - Constant::new(ConstantFloat(is.to_string(), FwAny)) - }, - &LitBool(b) => Constant::new(ConstantBool(b)), + &LitStr(ref is, style) => ConstantStr(is.to_string(), style), + &LitBinary(ref blob) => ConstantBinary(blob.clone()), + &LitByte(b) => ConstantByte(b), + &LitChar(c) => ConstantChar(c), + &LitInt(value, ty) => ConstantInt(value, ty), + &LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), + &LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), + &LitBool(b) => ConstantBool(b), } } -/// create `Some(ConstantVec(..))` of all constants, unless there is any -/// non-constant part -fn constant_vec<E: Deref<Target=Expr> + Sized>(cx: &Context, vec: &[E]) -> Option<Constant> { - let mut parts = Vec::new(); - let mut resolved = false; - for opt_part in vec { - match constant(cx, opt_part) { - Some(p) => { - resolved |= p.needed_resolution; - parts.push(p) - }, - None => { return None; }, - } - } - Some(Constant { - constant: ConstantVec(parts), - needed_resolution: resolved - }) -} - -fn constant_tup<E: Deref<Target=Expr> + Sized>(cx: &Context, tup: &[E]) -> Option<Constant> { - let mut parts = Vec::new(); - let mut resolved = false; - for opt_part in tup { - match constant(cx, opt_part) { - Some(p) => { - resolved |= p.needed_resolution; - parts.push(p) - }, - None => { return None; }, - } - } - Some(Constant { - constant: ConstantTuple(parts), - needed_resolution: resolved - }) -} - -/// lookup a possibly constant expression from a ExprPath -fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> { - if let Some(&PathResolution { base_def: DefConst(id), ..}) = - cx.tcx.def_map.borrow().get(&e.id) { - lookup_const_by_id(cx.tcx, id, None).and_then( - |l| constant(cx, l).map(|c| Constant::new_resolved(c.constant))) - } else { None } -} - -/// A block can only yield a constant if it only has one constant expression -fn constant_block(cx: &Context, block: &Block) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| constant(cx, &*b)) - } else { None } -} - -fn constant_if(cx: &Context, cond: &Expr, then: &Block, otherwise: - &Option<P<Expr>>) -> Option<Constant> { - if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) = - constant(cx, cond) { - if b { - constant_block(cx, then) - } else { - otherwise.as_ref().and_then(|expr| constant(cx, &*expr)) - }.map(|part| - Constant { - constant: part.constant, - needed_resolution: res || part.needed_resolution, - }) - } else { None } -} - fn constant_not(o: Constant) -> Option<Constant> { - Some(Constant { - needed_resolution: o.needed_resolution, - constant: match o.constant { - ConstantBool(b) => ConstantBool(!b), - ConstantInt(value, ty) => { - let (nvalue, nty) = match ty { - SignedIntLit(ity, Plus) => { - if value == ::std::u64::MAX { return None; } - (value + 1, SignedIntLit(ity, Minus)) - }, - SignedIntLit(ity, Minus) => { - if value == 0 { - (1, SignedIntLit(ity, Minus)) - } else { - (value - 1, SignedIntLit(ity, Plus)) - } - } - UnsignedIntLit(ity) => { - let mask = match ity { - UintTy::TyU8 => ::std::u8::MAX as u64, - UintTy::TyU16 => ::std::u16::MAX as u64, - UintTy::TyU32 => ::std::u32::MAX as u64, - UintTy::TyU64 => ::std::u64::MAX, - UintTy::TyUs => { return None; } // refuse to guess - }; - (!value & mask, UnsignedIntLit(ity)) + Some(match o { + ConstantBool(b) => ConstantBool(!b), + ConstantInt(value, ty) => { + let (nvalue, nty) = match ty { + SignedIntLit(ity, Plus) => { + if value == ::std::u64::MAX { return None; } + (value + 1, SignedIntLit(ity, Minus)) + }, + SignedIntLit(ity, Minus) => { + if value == 0 { + (1, SignedIntLit(ity, Minus)) + } else { + (value - 1, SignedIntLit(ity, Plus)) } - UnsuffixedIntLit(_) => { return None; } // refuse to guess - }; - ConstantInt(nvalue, nty) - }, - _ => { return None; } - } + } + UnsignedIntLit(ity) => { + let mask = match ity { + UintTy::TyU8 => ::std::u8::MAX as u64, + UintTy::TyU16 => ::std::u16::MAX as u64, + UintTy::TyU32 => ::std::u32::MAX as u64, + UintTy::TyU64 => ::std::u64::MAX, + UintTy::TyUs => { return None; } // refuse to guess + }; + (!value & mask, UnsignedIntLit(ity)) + } + UnsuffixedIntLit(_) => { return None; } // refuse to guess + }; + ConstantInt(nvalue, nty) + }, + _ => { return None; } }) } fn constant_negate(o: Constant) -> Option<Constant> { - Some(Constant{ - needed_resolution: o.needed_resolution, - constant: match o.constant { - ConstantInt(value, ty) => - ConstantInt(value, match ty { - SignedIntLit(ity, sign) => - SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; }, - }), - ConstantFloat(is, ty) => - ConstantFloat(neg_float_str(is), ty), - _ => { return None; }, - } + Some(match o { + ConstantInt(value, ty) => + ConstantInt(value, match ty { + SignedIntLit(ity, sign) => + SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), + _ => { return None; }, + }), + ConstantFloat(is, ty) => + ConstantFloat(neg_float_str(is), ty), + _ => { return None; }, }) } @@ -386,92 +258,8 @@ fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { } } -fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr) - -> Option<Constant> { - match op.node { - BiAdd => constant_binop_apply(cx, left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => - l8.checked_add(r8).map(ConstantByte), - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - if ln == rn { - unify_int_type(lty, rty, if ln { Minus } else { Plus }) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))) - } else { - if ln { - add_neg_int(r64, rty, l64, lty) - } else { - add_neg_int(l64, lty, r64, rty) - } - } - }, - // TODO: float (would need bignum library?) - _ => None - }), - BiSub => constant_binop_apply(cx, left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { - None } else { Some(ConstantByte(l8 - r8)) }, - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - match (ln, rn) { - (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), - (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), - (true, false) => unify_int_type(lty, rty, Minus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - (false, true) => unify_int_type(lty, rty, Plus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - } - }, - _ => None, - }), - //BiMul, - //BiDiv, - //BiRem, - BiAnd => constant_short_circuit(cx, left, right, false), - BiOr => constant_short_circuit(cx, left, right, true), - BiBitXor => constant_bitop(cx, left, right, |x, y| x ^ y), - BiBitAnd => constant_bitop(cx, left, right, |x, y| x & y), - BiBitOr => constant_bitop(cx, left, right, |x, y| (x | y)), - BiShl => constant_bitop(cx, left, right, |x, y| x << y), - BiShr => constant_bitop(cx, left, right, |x, y| x >> y), - BiEq => constant_binop_apply(cx, left, right, - |l, r| Some(ConstantBool(l == r))), - BiNe => constant_binop_apply(cx, left, right, - |l, r| Some(ConstantBool(l != r))), - BiLt => constant_cmp(cx, left, right, Less, true), - BiLe => constant_cmp(cx, left, right, Greater, false), - BiGe => constant_cmp(cx, left, right, Less, false), - BiGt => constant_cmp(cx, left, right, Greater, true), - _ => None - } -} - -fn constant_bitop<F>(cx: &Context, left: &Expr, right: &Expr, f: F) - -> Option<Constant> where F: Fn(u64, u64) -> u64 { - constant_binop_apply(cx, left, right, |l, r| match (l, r) { - (ConstantBool(l), ConstantBool(r)) => - Some(ConstantBool(f(l as u64, r as u64) != 0)), - (ConstantByte(l8), ConstantByte(r8)) => - Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), - (ConstantInt(l, lty), ConstantInt(r, rty)) => - unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)), - _ => None - }) -} - -fn constant_cmp(cx: &Context, left: &Expr, right: &Expr, ordering: Ordering, - b: bool) -> Option<Constant> { - constant_binop_apply(cx, left, right, |l, r| l.partial_cmp(&r).map(|o| - ConstantBool(b == (o == ordering)))) -} - fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> - Option<ConstantVariant> { + Option<Constant> { if neg > pos { unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) } else { @@ -480,42 +268,221 @@ fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> } fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> - Option<ConstantVariant> { + Option<Constant> { unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( |ty| l.checked_sub(r).map(|v| ConstantInt(v, ty))) } -fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F) - -> Option<Constant> -where F: Fn(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> { - if let (Some(Constant { constant: lc, needed_resolution: ln }), - Some(Constant { constant: rc, needed_resolution: rn })) = - (constant(cx, left), constant(cx, right)) { - op(lc, rc).map(|c| - Constant { - needed_resolution: ln || rn, - constant: c, - }) - } else { None } + +pub fn constant(lcx: &Context, e: &Expr) -> Option<(Constant, bool)> { + let mut cx = ConstEvalContext { lcx: Some(lcx), needed_resolution: false }; + cx.expr(e).map(|cst| (cst, cx.needed_resolution)) } -fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) -> - Option<Constant> { - constant(cx, left).and_then(|left| - if let &ConstantBool(lbool) = &left.constant { - if lbool == b { - Some(left) +pub fn constant_simple(e: &Expr) -> Option<Constant> { + let mut cx = ConstEvalContext { lcx: None, needed_resolution: false }; + cx.expr(e) +} + +struct ConstEvalContext<'c, 'cc: 'c> { + lcx: Option<&'c Context<'c, 'cc>>, + needed_resolution: bool +} + +impl<'c, 'cc> ConstEvalContext<'c, 'cc> { + + /// simple constant folding: Insert an expression, get a constant or none. + fn expr(&mut self, e: &Expr) -> Option<Constant> { + match &e.node { + &ExprParen(ref inner) => self.expr(inner), + &ExprPath(_, _) => self.fetch_path(e), + &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)), + &ExprVec(ref vec) => self.vec(&vec[..]), + &ExprTup(ref tup) => self.tup(&tup[..]), + &ExprRepeat(ref value, ref number) => + self.binop_apply(value, number,|v, n| + Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), + &ExprUnary(op, ref operand) => self.expr(operand).and_then( + |o| match op { + UnNot => constant_not(o), + UnNeg => constant_negate(o), + UnUniq | UnDeref => Some(o), + }), + &ExprBinary(op, ref left, ref right) => + self.binop(op, left, right), + //TODO: add other expressions + _ => None, + } + } + + /// create `Some(ConstantVec(..))` of all constants, unless there is any + /// non-constant part + fn vec<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> Option<Constant> { + let mut parts = Vec::new(); + for opt_part in vec { + match self.expr(opt_part) { + Some(p) => { + parts.push(p) + }, + None => { return None; }, + } + } + Some(ConstantVec(parts)) + } + + fn tup<E: Deref<Target=Expr> + Sized>(&mut self, tup: &[E]) -> Option<Constant> { + let mut parts = Vec::new(); + for opt_part in tup { + match self.expr(opt_part) { + Some(p) => { + parts.push(p) + }, + None => { return None; }, + } + } + Some(ConstantTuple(parts),) + } + + /// lookup a possibly constant expression from a ExprPath + fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { + if let Some(lcx) = self.lcx { + if let Some(&PathResolution { base_def: DefConst(id), ..}) = + lcx.tcx.def_map.borrow().get(&e.id) { + if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None) { + let ret = self.expr(const_expr); + if ret.is_some() { + self.needed_resolution = true; + } + return ret; + } + } + } + None + } + + /// A block can only yield a constant if it only has one constant expression + fn block(&mut self, block: &Block) -> Option<Constant> { + if block.stmts.is_empty() { + block.expr.as_ref().and_then(|b| self.expr(&*b)) + } else { None } + } + + fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) + -> Option<Constant> { + if let Some(ConstantBool(b)) = self.expr(cond) { + if b { + self.block(then) } else { - constant(cx, right).and_then(|right| - if let ConstantBool(_) = right.constant { - Some(Constant { - constant: right.constant, - needed_resolution: left.needed_resolution || - right.needed_resolution, - }) - } else { None } - ) + otherwise.as_ref().and_then(|expr| self.expr(&*expr)) } } else { None } - ) + } + + fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { + match op.node { + BiAdd => self.binop_apply(left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => + l8.checked_add(r8).map(ConstantByte), + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + if ln == rn { + unify_int_type(lty, rty, if ln { Minus } else { Plus }) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))) + } else { + if ln { + add_neg_int(r64, rty, l64, lty) + } else { + add_neg_int(l64, lty, r64, rty) + } + } + }, + // TODO: float (would need bignum library?) + _ => None + }), + BiSub => self.binop_apply(left, right, |l, r| + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { + None } else { Some(ConstantByte(l8 - r8)) }, + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + match (ln, rn) { + (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), + (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), + (true, false) => unify_int_type(lty, rty, Minus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + (false, true) => unify_int_type(lty, rty, Plus) + .and_then(|ty| l64.checked_add(r64).map( + |v| ConstantInt(v, ty))), + } + }, + _ => None, + }), + //BiMul, + //BiDiv, + //BiRem, + BiAnd => self.short_circuit(left, right, false), + BiOr => self.short_circuit(left, right, true), + BiBitXor => self.bitop(left, right, |x, y| x ^ y), + BiBitAnd => self.bitop(left, right, |x, y| x & y), + BiBitOr => self.bitop(left, right, |x, y| (x | y)), + BiShl => self.bitop(left, right, |x, y| x << y), + BiShr => self.bitop(left, right, |x, y| x >> y), + BiEq => self.binop_apply(left, right, + |l, r| Some(ConstantBool(l == r))), + BiNe => self.binop_apply(left, right, + |l, r| Some(ConstantBool(l != r))), + BiLt => self.cmp(left, right, Less, true), + BiLe => self.cmp(left, right, Greater, false), + BiGe => self.cmp(left, right, Less, false), + BiGt => self.cmp(left, right, Greater, true), + _ => None + } + } + + fn bitop<F>(&mut self, left: &Expr, right: &Expr, f: F) + -> Option<Constant> where F: Fn(u64, u64) -> u64 { + self.binop_apply(left, right, |l, r| match (l, r) { + (ConstantBool(l), ConstantBool(r)) => + Some(ConstantBool(f(l as u64, r as u64) != 0)), + (ConstantByte(l8), ConstantByte(r8)) => + Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), + (ConstantInt(l, lty), ConstantInt(r, rty)) => + unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)), + _ => None + }) + } + + fn cmp(&mut self, left: &Expr, right: &Expr, ordering: Ordering, b: bool) -> Option<Constant> { + self.binop_apply(left, right, |l, r| l.partial_cmp(&r).map(|o| + ConstantBool(b == (o == ordering)))) + } + + fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> + where F: Fn(Constant, Constant) -> Option<Constant> { + if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) { + op(lc, rc) + } else { None } + } + + fn short_circuit(&mut self, left: &Expr, right: &Expr, b: bool) -> Option<Constant> { + self.expr(left).and_then(|left| + if let &ConstantBool(lbool) = &left { + if lbool == b { + Some(left) + } else { + self.expr(right).and_then(|right| + if let ConstantBool(_) = right { + Some(right) + } else { None } + ) + } + } else { None } + ) + } } diff --git a/src/identity_op.rs b/src/identity_op.rs index 9f415e5decb..cd7d6351c80 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -3,7 +3,7 @@ use syntax::ast::*; use syntax::codemap::Span; use consts::{constant, is_negative}; -use consts::ConstantVariant::ConstantInt; +use consts::Constant::ConstantInt; use utils::{span_lint, snippet}; declare_lint! { pub IDENTITY_OP, Warn, @@ -44,9 +44,9 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(c) = constant(cx, e) { - if c.needed_resolution { return; } // skip linting w/ lookup for now - if let ConstantInt(v, ty) = c.constant { + if let Some((c, needed_resolution)) = constant(cx, e) { + if needed_resolution { return; } // skip linting w/ lookup for now + if let ConstantInt(v, ty) = c { if match m { 0 => v == 0, -1 => is_negative(ty) && v == 1, diff --git a/src/misc.rs b/src/misc.rs index 33c34eb9b84..aca849931bb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -149,7 +149,7 @@ impl LintPass for FloatCmp { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { if constant(cx, left).or_else(|| constant(cx, right)).map_or( - false, |c| c.as_float().map_or(false, |f| f == 0.0)) { + false, |c| c.0.as_float().map_or(false, |f| f == 0.0)) { return; } span_lint(cx, FLOAT_CMP, expr.span, &format!( diff --git a/tests/consts.rs b/tests/consts.rs old mode 100644 new mode 100755 index 3b05dd67ad5..bcc5aa4c30a --- a/tests/consts.rs +++ b/tests/consts.rs @@ -5,21 +5,13 @@ extern crate clippy; extern crate syntax; extern crate rustc; -use clippy::consts::{constant, ConstantVariant}; -use clippy::consts::ConstantVariant::*; use syntax::ast::*; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; -use std::mem; -use rustc::lint::Context; -fn ctx() -> &'static Context<'static, 'static> { - unsafe { - let x : *const Context<'static, 'static> = std::ptr::null(); - mem::transmute(x) - } -} +use clippy::consts::{constant_simple, Constant}; +use clippy::consts::Constant::*; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } @@ -41,13 +33,13 @@ fn binop(op: BinOp_, l: Expr, r: Expr) -> Expr { expr(ExprBinary(spanned(op), P(l), P(r))) } -fn check(expect: ConstantVariant, expr: &Expr) { - assert_eq!(Some(expect), constant(ctx(), expr).map(|x| x.constant)) +fn check(expect: Constant, expr: &Expr) { + assert_eq!(Some(expect), constant_simple(expr)) } -const TRUE : ConstantVariant = ConstantBool(true); -const FALSE : ConstantVariant = ConstantBool(false); -const ZERO : ConstantVariant = ConstantInt(0, UnsuffixedIntLit(Plus)); +const TRUE : Constant = ConstantBool(true); +const FALSE : Constant = ConstantBool(false); +const ZERO : Constant = ConstantInt(0, UnsuffixedIntLit(Plus)); #[test] fn test_lit() { -- cgit 1.4.1-3-g733a5 From 49ad73f6e46b5ac400e1c7dd117646146e1ef722 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 17 Aug 2015 19:55:59 +0200 Subject: consts: minor improvements --- src/consts.rs | 76 ++++++++++++++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index df669007b1e..07bde1d0b08 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -59,7 +59,7 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let &ConstantInt(val, _) = self { + if let ConstantInt(val, _) = *self { val // TODO we may want to check the sign if any } else { panic!("Could not convert a {:?} to u64"); @@ -149,15 +149,15 @@ impl PartialOrd for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { - match lit { - &LitStr(ref is, style) => ConstantStr(is.to_string(), style), - &LitBinary(ref blob) => ConstantBinary(blob.clone()), - &LitByte(b) => ConstantByte(b), - &LitChar(c) => ConstantChar(c), - &LitInt(value, ty) => ConstantInt(value, ty), - &LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), - &LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), - &LitBool(b) => ConstantBool(b), + match *lit { + LitStr(ref is, style) => ConstantStr(is.to_string(), style), + LitBinary(ref blob) => ConstantBinary(blob.clone()), + LitByte(b) => ConstantByte(b), + LitChar(c) => ConstantChar(c), + LitInt(value, ty) => ConstantInt(value, ty), + LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), + LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), + LitBool(b) => ConstantBool(b), } } @@ -293,25 +293,25 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { /// simple constant folding: Insert an expression, get a constant or none. fn expr(&mut self, e: &Expr) -> Option<Constant> { - match &e.node { - &ExprParen(ref inner) => self.expr(inner), - &ExprPath(_, _) => self.fetch_path(e), - &ExprBlock(ref block) => self.block(block), - &ExprIf(ref cond, ref then, ref otherwise) => + match e.node { + ExprParen(ref inner) => self.expr(inner), + ExprPath(_, _) => self.fetch_path(e), + 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)), - &ExprVec(ref vec) => self.vec(&vec[..]), - &ExprTup(ref tup) => self.tup(&tup[..]), - &ExprRepeat(ref value, ref number) => - self.binop_apply(value, number,|v, n| + ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), + ExprVec(ref vec) => self.vec(&vec), + ExprTup(ref tup) => self.tup(&tup), + ExprRepeat(ref value, ref number) => + self.binop_apply(value, number, |v, n| Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), - &ExprUnary(op, ref operand) => self.expr(operand).and_then( + ExprUnary(op, ref operand) => self.expr(operand).and_then( |o| match op { UnNot => constant_not(o), UnNeg => constant_negate(o), UnUniq | UnDeref => Some(o), }), - &ExprBinary(op, ref left, ref right) => + ExprBinary(op, ref left, ref right) => self.binop(op, left, right), //TODO: add other expressions _ => None, @@ -321,29 +321,15 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { /// create `Some(ConstantVec(..))` of all constants, unless there is any /// non-constant part fn vec<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> Option<Constant> { - let mut parts = Vec::new(); - for opt_part in vec { - match self.expr(opt_part) { - Some(p) => { - parts.push(p) - }, - None => { return None; }, - } - } - Some(ConstantVec(parts)) + vec.iter().map(|elem| self.expr(elem)) + .collect::<Option<_>>() + .map(ConstantVec) } fn tup<E: Deref<Target=Expr> + Sized>(&mut self, tup: &[E]) -> Option<Constant> { - let mut parts = Vec::new(); - for opt_part in tup { - match self.expr(opt_part) { - Some(p) => { - parts.push(p) - }, - None => { return None; }, - } - } - Some(ConstantTuple(parts),) + tup.iter().map(|elem| self.expr(elem)) + .collect::<Option<_>>() + .map(ConstantTuple) } /// lookup a possibly constant expression from a ExprPath @@ -366,7 +352,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { /// A block can only yield a constant if it only has one constant expression fn block(&mut self, block: &Block) -> Option<Constant> { if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| self.expr(&*b)) + block.expr.as_ref().and_then(|ref b| self.expr(b)) } else { None } } @@ -376,7 +362,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { if b { self.block(then) } else { - otherwise.as_ref().and_then(|expr| self.expr(&*expr)) + otherwise.as_ref().and_then(|ref expr| self.expr(expr)) } } else { None } } @@ -472,7 +458,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { fn short_circuit(&mut self, left: &Expr, right: &Expr, b: bool) -> Option<Constant> { self.expr(left).and_then(|left| - if let &ConstantBool(lbool) = &left { + if let ConstantBool(lbool) = left { if lbool == b { Some(left) } else { -- cgit 1.4.1-3-g733a5 From 6e0c103133b14fbad4803c87da71fd13aec2269f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 18 Aug 2015 12:26:01 +0200 Subject: more small const improvements --- src/consts.rs | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 07bde1d0b08..4d23ce07df2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -59,7 +59,7 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let ConstantInt(val, _) = *self { + if let &ConstantInt(val, _) = self { val // TODO we may want to check the sign if any } else { panic!("Could not convert a {:?} to u64"); @@ -149,15 +149,15 @@ impl PartialOrd for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { - match *lit { - LitStr(ref is, style) => ConstantStr(is.to_string(), style), - LitBinary(ref blob) => ConstantBinary(blob.clone()), - LitByte(b) => ConstantByte(b), - LitChar(c) => ConstantChar(c), - LitInt(value, ty) => ConstantInt(value, ty), - LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), - LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), - LitBool(b) => ConstantBool(b), + match lit { + &LitStr(ref is, style) => ConstantStr(is.to_string(), style), + &LitBinary(ref blob) => ConstantBinary(blob.clone()), + &LitByte(b) => ConstantByte(b), + &LitChar(c) => ConstantChar(c), + &LitInt(value, ty) => ConstantInt(value, ty), + &LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), + &LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), + &LitBool(b) => ConstantBool(b), } } @@ -300,8 +300,8 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(&*cond, &*then, &*otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), - ExprVec(ref vec) => self.vec(&vec), - ExprTup(ref tup) => self.tup(&tup), + ExprVec(ref vec) => self.multi(&vec[..]).map(ConstantVec), + ExprTup(ref tup) => self.multi(&tup[..]).map(ConstantTuple), ExprRepeat(ref value, ref number) => self.binop_apply(value, number, |v, n| Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), @@ -318,18 +318,12 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { } } - /// create `Some(ConstantVec(..))` of all constants, unless there is any + /// create `Some(Vec![..])` of all constants, unless there is any /// non-constant part - fn vec<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> Option<Constant> { + fn multi<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> + Option<Vec<Constant>> { vec.iter().map(|elem| self.expr(elem)) .collect::<Option<_>>() - .map(ConstantVec) - } - - fn tup<E: Deref<Target=Expr> + Sized>(&mut self, tup: &[E]) -> Option<Constant> { - tup.iter().map(|elem| self.expr(elem)) - .collect::<Option<_>>() - .map(ConstantTuple) } /// lookup a possibly constant expression from a ExprPath -- cgit 1.4.1-3-g733a5 From 9f67ba7f8d588f1d7a39d1b34fa7e2a7e6209bda Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 18 Aug 2015 14:18:36 +0200 Subject: re-applied birkenfeld's improvements --- src/consts.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 4d23ce07df2..c069539a077 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -59,7 +59,7 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let &ConstantInt(val, _) = self { + if let ConstantInt(val, _) = *self { val // TODO we may want to check the sign if any } else { panic!("Could not convert a {:?} to u64"); @@ -149,15 +149,15 @@ impl PartialOrd for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { - match lit { - &LitStr(ref is, style) => ConstantStr(is.to_string(), style), - &LitBinary(ref blob) => ConstantBinary(blob.clone()), - &LitByte(b) => ConstantByte(b), - &LitChar(c) => ConstantChar(c), - &LitInt(value, ty) => ConstantInt(value, ty), - &LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), - &LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), - &LitBool(b) => ConstantBool(b), + match *lit { + LitStr(ref is, style) => ConstantStr(is.to_string(), style), + LitBinary(ref blob) => ConstantBinary(blob.clone()), + LitByte(b) => ConstantByte(b), + LitChar(c) => ConstantChar(c), + LitInt(value, ty) => ConstantInt(value, ty), + LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), + LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), + LitBool(b) => ConstantBool(b), } } @@ -300,8 +300,8 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(&*cond, &*then, &*otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), - ExprVec(ref vec) => self.multi(&vec[..]).map(ConstantVec), - ExprTup(ref tup) => self.multi(&tup[..]).map(ConstantTuple), + ExprVec(ref vec) => self.multi(vec).map(ConstantVec), + ExprTup(ref tup) => self.multi(tup).map(ConstantTuple), ExprRepeat(ref value, ref number) => self.binop_apply(value, number, |v, n| Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), -- cgit 1.4.1-3-g733a5 From 8f4499f3aedd9fabb624318210bd69f0a8de1757 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 19 Aug 2015 06:54:20 +0200 Subject: new lint: comparing unit types (fixes #201) --- README.md | 1 + src/lib.rs | 2 ++ src/types.rs | 29 +++++++++++++++++++++++++++++ tests/compile-fail/unit_cmp.rs | 17 +++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100755 tests/compile-fail/unit_cmp.rs (limited to 'src') diff --git a/README.md b/README.md index 5ec1040b2c4..e6a4d1be514 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ string_add | allow | using `x + ..` where x is a `String`; suggests string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead string_to_string | warn | calling `String.to_string()` which is a no-op toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) zero_width_space | deny | using a zero-width space in a string literal, which is confusing To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index d7a10562df1..50ebbd6d9fd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); + reg.register_lint_pass(box types::UnitCmp as LintPassObject); reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); reg.register_lint_pass(box ranges::StepByZero as LintPassObject); @@ -105,6 +106,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::BOX_VEC, types::LET_UNIT_VALUE, types::LINKEDLIST, + types::UNIT_CMP, unicode::NON_ASCII_LITERAL, unicode::ZERO_WIDTH_SPACE, ]); diff --git a/src/types.rs b/src/types.rs index aa5f1d13471..617c51fd961 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,7 @@ use rustc::lint::*; use syntax::ast; use syntax::ast::*; +use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::ptr::P; use rustc::middle::ty; use syntax::codemap::ExpnInfo; @@ -107,3 +108,31 @@ impl LintPass for LetPass { |info| check_let_unit(cx, decl, info)); } } + +declare_lint!(pub UNIT_CMP, Warn, + "comparing unit values (which is always `true` or `false`, respectively)"); + +#[allow(missing_copy_implementations)] +pub struct UnitCmp; + +impl LintPass for UnitCmp { + fn get_lints(&self) -> LintArray { + lint_array!(UNIT_CMP) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, _) = expr.node { + let op = cmp.node; + let sty = &cx.tcx.expr_ty(left).sty; + if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) { + let result = match op { + BiEq | BiLe | BiGe => "true", + _ => "false" + }; + span_lint(cx, UNIT_CMP, expr.span, &format!( + "{}-comparison of unit values detected. This will always be {}", + binop_to_string(op), result)); + } + } + } +} diff --git a/tests/compile-fail/unit_cmp.rs b/tests/compile-fail/unit_cmp.rs new file mode 100755 index 00000000000..e246d9f3909 --- /dev/null +++ b/tests/compile-fail/unit_cmp.rs @@ -0,0 +1,17 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(unit_cmp)] + +fn main() { + // this is fine + if true == false { + } + + // this warns + if { true; } == { false; } { //~ERROR ==-comparison of unit values detected. This will always be true + } + + if { true; } > { false; } { //~ERROR >-comparison of unit values detected. This will always be false + } +} -- cgit 1.4.1-3-g733a5 From 98d24b5b5601d60f113ea14232416ce545f0cf73 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 19 Aug 2015 09:07:50 +0200 Subject: fixed #203 and #197 --- src/bit_mask.rs | 40 +++++++++++++++++++++++++++++----------- tests/compile-fail/bit_masks.rs | 11 ++++++++--- 2 files changed, 37 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index ec937dbab6c..7789381da23 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -39,7 +39,13 @@ declare_lint! { /// This lint is **deny** by default /// /// There is also a lint that warns on ineffective masks that is *warn* -/// by default +/// by default. +/// +/// |Comparison|Bit-Op |Example |equals |Formula| +/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`| +/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` | +/// +/// `¹ power_of_two(c + 1)` #[derive(Copy,Clone)] pub struct BitMask; @@ -127,12 +133,10 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, "incompatible bit mask: `_ | {}` will never be lower than `{}`", mask_value, cmp_value)); } else { - if mask_value < cmp_value { - span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly", - mask_value, cmp_value)); - } + check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); }, + BiBitXor => + check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"), _ => () }, BiLe | BiGt => match bit_op { @@ -151,18 +155,32 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, "incompatible bit mask: `_ | {}` will always be higher than `{}`", mask_value, cmp_value)); } else { - if mask_value < cmp_value { - span_lint(cx, INEFFECTIVE_BIT_MASK, *span, &format!( - "ineffective bit mask: `x | {}` compared to `{}` is the same as x compared directly", - mask_value, cmp_value)); - } + check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); }, + BiBitXor => + check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), _ => () }, _ => () } } +fn check_ineffective_lt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { + if c.is_power_of_two() && m < c { + span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( + "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, m, c)); + } +} + +fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { + if (c + 1).is_power_of_two() && m <= c { + span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( + "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, m, c)); + } +} + fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> { match &lit.node { &ExprLit(ref lit_ptr) => { diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index bcbfe99e42e..47e9c11138a 100755 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -46,8 +46,13 @@ fn main() { fn ineffective() { let x = 5; - x | 1 > 2; //~ERROR ineffective bit mask - x | 1 < 3; //~ERROR ineffective bit mask + x | 1 > 3; //~ERROR ineffective bit mask + x | 1 < 4; //~ERROR ineffective bit mask x | 1 <= 3; //~ERROR ineffective bit mask - x | 1 >= 2; //~ERROR ineffective bit mask + x | 1 >= 8; //~ERROR ineffective bit mask + + x | 1 > 2; // not an error (yet), better written as x >= 2 + x | 1 >= 7; // not an error (yet), better written as x >= 6 + x | 3 > 4; // not an error (yet), better written as x >= 4 + x | 4 <= 19; } -- cgit 1.4.1-3-g733a5 From 973d5e5c6b58d7b2404f52bbb8b5eb5918defd9c Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 19 Aug 2015 11:58:59 +0200 Subject: Mul and Div for integers --- src/consts.rs | 28 ++++++++++++++++++++-------- tests/consts.rs | 9 +++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index c069539a077..5056cc27a54 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -320,7 +320,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { /// create `Some(Vec![..])` of all constants, unless there is any /// non-constant part - fn multi<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> + fn multi<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> Option<Vec<Constant>> { vec.iter().map(|elem| self.expr(elem)) .collect::<Option<_>>() @@ -388,9 +388,8 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { match (l, r) { (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { None } else { Some(ConstantByte(l8 - r8)) }, - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - match (ln, rn) { + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => + match (is_negative(lty), is_negative(rty)) { (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), (true, false) => unify_int_type(lty, rty, Minus) @@ -399,12 +398,11 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { (false, true) => unify_int_type(lty, rty, Plus) .and_then(|ty| l64.checked_add(r64).map( |v| ConstantInt(v, ty))), - } - }, + }, _ => None, }), - //BiMul, - //BiDiv, + BiMul => self.divmul(left, right, u64::checked_mul), + BiDiv => self.divmul(left, right, u64::checked_div), //BiRem, BiAnd => self.short_circuit(left, right, false), BiOr => self.short_circuit(left, right, true), @@ -425,6 +423,20 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { } } + fn divmul<F>(&mut self, left: &Expr, right: &Expr, f: F) + -> Option<Constant> where F: Fn(u64, u64) -> Option<u64> { + self.binop_apply(left, right, |l, r| + match (l, r) { + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + f(l64, r64).and_then(|value| + unify_int_type(lty, rty, if is_negative(lty) == + is_negative(rty) { Plus } else { Minus }) + .map(|ty| ConstantInt(value, ty))) + }, + _ => None, + }) + } + fn bitop<F>(&mut self, left: &Expr, right: &Expr, f: F) -> Option<Constant> where F: Fn(u64, u64) -> u64 { self.binop_apply(left, right, |l, r| match (l, r) { diff --git a/tests/consts.rs b/tests/consts.rs index bcc5aa4c30a..55270cc6b51 100755 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -40,6 +40,8 @@ fn check(expect: Constant, expr: &Expr) { const TRUE : Constant = ConstantBool(true); const FALSE : Constant = ConstantBool(false); const ZERO : Constant = ConstantInt(0, UnsuffixedIntLit(Plus)); +const ONE : Constant = ConstantInt(1, UnsuffixedIntLit(Plus)); +const TWO : Constant = ConstantInt(2, UnsuffixedIntLit(Plus)); #[test] fn test_lit() { @@ -56,10 +58,17 @@ fn test_ops() { check(FALSE, &binop(BiAnd, lit(LitBool(false)), lit(LitBool(true)))); let litzero = lit(LitInt(0, UnsuffixedIntLit(Plus))); + let litone = lit(LitInt(1, UnsuffixedIntLit(Plus))); check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone())); check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone())); check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone())); check(FALSE, &binop(BiNe, litzero.clone(), litzero.clone())); check(FALSE, &binop(BiGt, litzero.clone(), litzero.clone())); check(FALSE, &binop(BiLt, litzero.clone(), litzero.clone())); + + check(ZERO, &binop(BiAdd, litzero.clone(), litzero.clone())); + check(TWO, &binop(BiAdd, litone.clone(), litone.clone())); + check(ONE, &binop(BiSub, litone.clone(), litzero.clone())); + check(ONE, &binop(BiMul, litone.clone(), litone.clone())); + check(ONE, &binop(BiDiv, litone.clone(), litone.clone())); } -- cgit 1.4.1-3-g733a5 From 993239d33af2b91fcd5e6dbec30f3810c8178ae3 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 00:04:01 +0200 Subject: Initial implementation of lossy cast lints. Introduces 3 lints : cast_possible_overflow cast_precision_loss cast_sign_loss Add a compile-test test case. Fix errors spotted by dogfood script. --- README.md | 85 ++++++++++++++-------------- src/consts.rs | 19 ++++--- src/lib.rs | 4 ++ src/types.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/cast.rs | 31 +++++++++++ 5 files changed, 223 insertions(+), 51 deletions(-) create mode 100644 tests/compile-fail/cast.rs (limited to 'src') diff --git a/README.md b/README.md index e6a4d1be514..df097ca9e3f 100644 --- a/README.md +++ b/README.md @@ -6,47 +6,50 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints Lints included in this crate: -name | default | meaning ----------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) -cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` -eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -explicit_iter_loop | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` -ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -inline_always | warn | `#[inline(always)]` is a bad idea in most cases -iter_next_loop | warn | for-looping over `_.next()` which is probably not intended -len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` -len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function -let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf -modulo_one | warn | taking a number modulo 1, which always returns 0 -mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do -needless_return | warn | using a return statement like `return expr;` where an expression would suffice -non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` -ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively -range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator -redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled -single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` -string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -string_to_string | warn | calling `String.to_string()` which is a no-op -toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) -unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) -zero_width_space | deny | using a zero-width space in a string literal, which is confusing +name | default | meaning +-----------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +cast_possible_overflow | allow | casts that may cause overflow +cast_precision_loss | allow | casts that cause loss of precision +cast_sign_loss | allow | casts from signed types to unsigned types +cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) +cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +explicit_iter_loop | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` +ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +inline_always | warn | `#[inline(always)]` is a bad idea in most cases +iter_next_loop | warn | for-looping over `_.next()` which is probably not intended +len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` +len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function +let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +modulo_one | warn | taking a number modulo 1, which always returns 0 +mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do +needless_return | warn | using a return statement like `return expr;` where an expression would suffice +non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` +ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator +redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled +single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` +string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +string_to_string | warn | calling `String.to_string()` which is a no-op +toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) +zero_width_space | deny | using a zero-width space in a string literal, which is confusing To use, add the following lines to your Cargo.toml: diff --git a/src/consts.rs b/src/consts.rs index 5056cc27a54..c033888e360 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -67,15 +67,16 @@ impl Constant { } /// convert this constant to a f64, if possible - pub fn as_float(&self) -> Option<f64> { - match *self { - ConstantByte(b) => Some(b as f64), - ConstantFloat(ref s, _) => s.parse().ok(), - ConstantInt(i, ty) => Some(if is_negative(ty) { - -(i as f64) } else { i as f64 }), - _ => None - } - } + #[allow(unknown_lints,cast_precision_loss)] + pub fn as_float(&self) -> Option<f64> { + match *self { + ConstantByte(b) => Some(b as f64), + ConstantFloat(ref s, _) => s.parse().ok(), + ConstantInt(i, ty) => Some(if is_negative(ty) { + -(i as f64) } else { i as f64 }), + _ => None + } + } } impl PartialEq for Constant { diff --git a/src/lib.rs b/src/lib.rs index 50ebbd6d9fd..1b4d77dacca 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box loops::LoopsPass as LintPassObject); reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); reg.register_lint_pass(box ranges::StepByZero as LintPassObject); + reg.register_lint_pass(box types::CastPass as LintPassObject); reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, @@ -104,6 +105,9 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::BOX_VEC, + types::CAST_POSSIBLE_OVERFLOW, + types::CAST_PRECISION_LOSS, + types::CAST_SIGN_LOSS, types::LET_UNIT_VALUE, types::LINKEDLIST, types::UNIT_CMP, diff --git a/src/types.rs b/src/types.rs index 617c51fd961..17ebb791c3c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,7 +6,7 @@ use syntax::ptr::P; use rustc::middle::ty; use syntax::codemap::ExpnInfo; -use utils::{in_macro, snippet, span_lint, span_help_and_lint}; +use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -136,3 +136,136 @@ impl LintPass for UnitCmp { } } } + +pub struct CastPass; + +declare_lint!(pub CAST_PRECISION_LOSS, Allow, + "casts that cause loss of precision"); +declare_lint!(pub CAST_SIGN_LOSS, Allow, + "casts from signed types to unsigned types"); +declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow, + "casts that may cause overflow"); + +impl LintPass for CastPass { + fn get_lints(&self) -> LintArray { + lint_array!(CAST_PRECISION_LOSS, + CAST_SIGN_LOSS, + CAST_POSSIBLE_OVERFLOW) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprCast(ref ex, _) = expr.node { + let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr)); + if cast_from.is_numeric() && !in_external_macro(cx, expr.span) { + match (cast_from.is_integral(), cast_to.is_integral()) { + (true, false) => { + match (&cast_from.sty, &cast_to.sty) { + (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyFloat(f)) => { + match (i, f) { + (ast::IntTy::TyI32, ast::FloatTy::TyF32) | + (ast::IntTy::TyI64, ast::FloatTy::TyF32) | + (ast::IntTy::TyI64, ast::FloatTy::TyF64) => { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("converting from {} to {}, which causes a loss of precision", + i, f)); + }, + _ => () + } + } + (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyFloat(f)) => { + match (u, f) { + (ast::UintTy::TyU32, ast::FloatTy::TyF32) | + (ast::UintTy::TyU64, ast::FloatTy::TyF32) | + (ast::UintTy::TyU64, ast::FloatTy::TyF64) => { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("converting from {} to {}, which causes a loss of precision", + u, f)); + }, + _ => () + } + }, + _ => () + } + }, + (false, true) => { + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); + if !cx.tcx.expr_ty(expr).is_signed() { + span_lint(cx, CAST_SIGN_LOSS, expr.span, + &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); + } + }, + (true, true) => { + match (&cast_from.sty, &cast_to.sty) { + (&ty::TypeVariants::TyInt(i1), &ty::TypeVariants::TyInt(i2)) => { + match (i1, i2) { + (ast::IntTy::TyI64, ast::IntTy::TyI32) | + (ast::IntTy::TyI64, ast::IntTy::TyI16) | + (ast::IntTy::TyI64, ast::IntTy::TyI8) | + (ast::IntTy::TyI32, ast::IntTy::TyI16) | + (ast::IntTy::TyI32, ast::IntTy::TyI8) | + (ast::IntTy::TyI16, ast::IntTy::TyI8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", i1, i2)), + _ => () + } + }, + (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyUint(u)) => { + span_lint(cx, CAST_SIGN_LOSS, expr.span, + &format!("casting from {} to {} loses the sign of the value", i, u)); + match (i, u) { + (ast::IntTy::TyI64, ast::UintTy::TyU32) | + (ast::IntTy::TyI64, ast::UintTy::TyU16) | + (ast::IntTy::TyI64, ast::UintTy::TyU8) | + (ast::IntTy::TyI32, ast::UintTy::TyU16) | + (ast::IntTy::TyI32, ast::UintTy::TyU8) | + (ast::IntTy::TyI16, ast::UintTy::TyU8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", i, u)), + _ => () + } + }, + (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyInt(i)) => { + match (u, i) { + (ast::UintTy::TyU64, ast::IntTy::TyI32) | + (ast::UintTy::TyU64, ast::IntTy::TyI64) | + (ast::UintTy::TyU64, ast::IntTy::TyI16) | + (ast::UintTy::TyU64, ast::IntTy::TyI8) | + (ast::UintTy::TyU32, ast::IntTy::TyI32) | + (ast::UintTy::TyU32, ast::IntTy::TyI16) | + (ast::UintTy::TyU32, ast::IntTy::TyI8) | + (ast::UintTy::TyU16, ast::IntTy::TyI16) | + (ast::UintTy::TyU16, ast::IntTy::TyI8) | + (ast::UintTy::TyU8, ast::IntTy::TyI8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", u, i)), + _ => () + } + }, + (&ty::TypeVariants::TyUint(u1), &ty::TypeVariants::TyUint(u2)) => { + match (u1, u2) { + (ast::UintTy::TyU64, ast::UintTy::TyU32) | + (ast::UintTy::TyU64, ast::UintTy::TyU16) | + (ast::UintTy::TyU64, ast::UintTy::TyU8) | + (ast::UintTy::TyU32, ast::UintTy::TyU16) | + (ast::UintTy::TyU32, ast::UintTy::TyU8) | + (ast::UintTy::TyU16, ast::UintTy::TyU8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", u1, u2)), + _ => () + } + }, + _ => () + } + } + (false, false) => { + if let (&ty::TypeVariants::TyFloat(ast::FloatTy::TyF64), + &ty::TypeVariants::TyFloat(ast::FloatTy::TyF32)) = (&cast_from.sty, &cast_to.sty) { + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32"); + } + } + } + } + } + } +} diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs new file mode 100644 index 00000000000..a51ea62a7b8 --- /dev/null +++ b/tests/compile-fail/cast.rs @@ -0,0 +1,31 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(cast_precision_loss, cast_possible_overflow, cast_sign_loss)] +fn main() { + let i : i32 = 42; + let u : u32 = 42; + let f : f32 = 42.0; + + // Test cast_precision_loss + i as f32; //~ERROR converting from i32 to f32, which causes a loss of precision + (i as i64) as f32; //~ERROR converting from i64 to f32, which causes a loss of precision + (i as i64) as f64; //~ERROR converting from i64 to f64, which causes a loss of precision + u as f32; //~ERROR converting from u32 to f32, which causes a loss of precision + (u as u64) as f32; //~ERROR converting from u64 to f32, which causes a loss of precision + (u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision + i as f64; // Should not trigger the lint + u as f64; // Should not trigger the lint + + // Test cast_possible_overflow + f as i32; //~ERROR the contents of a f32 may overflow a i32 + f as u32; //~ERROR the contents of a f32 may overflow a u32 + //~^ERROR casting from f32 to u32 loses the sign of the value + i as u8; //~ERROR the contents of a i32 may overflow a u8 + //~^ERROR casting from i32 to u8 loses the sign of the value + (f as f64) as f32; //~ERROR the contents of a f64 may overflow a f32 + i as i8; //~ERROR the contents of a i32 may overflow a i8 + + // Test cast_sign_loss + i as u32; //~ERROR casting from i32 to u32 loses the sign of the value +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 1846581baace12af85dfda3fffc219b9ceadc7e8 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 14:24:26 +0200 Subject: Added examples to lint descriptions. --- README.md | 6 +++--- src/types.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index df097ca9e3f..6a264034773 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ name | default | meaning approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -cast_possible_overflow | allow | casts that may cause overflow -cast_precision_loss | allow | casts that cause loss of precision -cast_sign_loss | allow | casts from signed types to unsigned types +cast_possible_overflow | allow | casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +cast_precision_loss | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +cast_sign_loss | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` diff --git a/src/types.rs b/src/types.rs index 17ebb791c3c..d6081153f01 100644 --- a/src/types.rs +++ b/src/types.rs @@ -140,11 +140,11 @@ impl LintPass for UnitCmp { pub struct CastPass; declare_lint!(pub CAST_PRECISION_LOSS, Allow, - "casts that cause loss of precision"); + "casts that cause loss of precision, e.g `x as f32` where `x: u64`"); declare_lint!(pub CAST_SIGN_LOSS, Allow, - "casts from signed types to unsigned types"); + "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"); declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow, - "casts that may cause overflow"); + "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); impl LintPass for CastPass { fn get_lints(&self) -> LintArray { -- cgit 1.4.1-3-g733a5 From 93d9249f769f27e2864d5b2d53dfc94a933412a4 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 14:25:08 +0200 Subject: Moved allow(unknown_lints) to crate level. --- src/consts.rs | 2 +- src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index c033888e360..70d5ff4bc17 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -67,7 +67,7 @@ impl Constant { } /// convert this constant to a f64, if possible - #[allow(unknown_lints,cast_precision_loss)] + #[allow(cast_precision_loss)] pub fn as_float(&self) -> Option<f64> { match *self { ConstantByte(b) => Some(b as f64), diff --git a/src/lib.rs b/src/lib.rs index 1b4d77dacca..f4e3ed54c60 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, core, collections)] #![feature(str_split_at)] +#![allow(unknown_lints)] #[macro_use] extern crate syntax; -- cgit 1.4.1-3-g733a5 From b417f01ed82332cd81954ac6d9f5bad615db2bfc Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 14:36:26 +0200 Subject: Also test that the CastExpr's right arm is numeric. --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index d6081153f01..3f7012f6ca8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -156,7 +156,7 @@ impl LintPass for CastPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprCast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr)); - if cast_from.is_numeric() && !in_external_macro(cx, expr.span) { + if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { match (&cast_from.sty, &cast_to.sty) { -- cgit 1.4.1-3-g733a5 From 14528d433af176f36aab475318691676c3de4464 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 14:37:35 +0200 Subject: Simplified reexported ast::* type paths. Also removed trailing whitespaces. --- src/types.rs | 100 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 3f7012f6ca8..2c4d81e361d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -160,11 +160,11 @@ impl LintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { match (&cast_from.sty, &cast_to.sty) { - (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyFloat(f)) => { + (&ty::TyInt(i), &ty::TyFloat(f)) => { match (i, f) { - (ast::IntTy::TyI32, ast::FloatTy::TyF32) | - (ast::IntTy::TyI64, ast::FloatTy::TyF32) | - (ast::IntTy::TyI64, ast::FloatTy::TyF64) => { + (ast::TyI32, ast::TyF32) | + (ast::TyI64, ast::TyF32) | + (ast::TyI64, ast::TyF64) => { span_lint(cx, CAST_PRECISION_LOSS, expr.span, &format!("converting from {} to {}, which causes a loss of precision", i, f)); @@ -172,11 +172,11 @@ impl LintPass for CastPass { _ => () } } - (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyFloat(f)) => { + (&ty::TyUint(u), &ty::TyFloat(f)) => { match (u, f) { - (ast::UintTy::TyU32, ast::FloatTy::TyF32) | - (ast::UintTy::TyU64, ast::FloatTy::TyF32) | - (ast::UintTy::TyU64, ast::FloatTy::TyF64) => { + (ast::TyU32, ast::TyF32) | + (ast::TyU64, ast::TyF32) | + (ast::TyU64, ast::TyF64) => { span_lint(cx, CAST_PRECISION_LOSS, expr.span, &format!("converting from {} to {}, which causes a loss of precision", u, f)); @@ -188,69 +188,69 @@ impl LintPass for CastPass { } }, (false, true) => { - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); if !cx.tcx.expr_ty(expr).is_signed() { - span_lint(cx, CAST_SIGN_LOSS, expr.span, + span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); } }, (true, true) => { match (&cast_from.sty, &cast_to.sty) { - (&ty::TypeVariants::TyInt(i1), &ty::TypeVariants::TyInt(i2)) => { + (&ty::TyInt(i1), &ty::TyInt(i2)) => { match (i1, i2) { - (ast::IntTy::TyI64, ast::IntTy::TyI32) | - (ast::IntTy::TyI64, ast::IntTy::TyI16) | - (ast::IntTy::TyI64, ast::IntTy::TyI8) | - (ast::IntTy::TyI32, ast::IntTy::TyI16) | - (ast::IntTy::TyI32, ast::IntTy::TyI8) | - (ast::IntTy::TyI16, ast::IntTy::TyI8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + (ast::TyI64, ast::TyI32) | + (ast::TyI64, ast::TyI16) | + (ast::TyI64, ast::TyI8) | + (ast::TyI32, ast::TyI16) | + (ast::TyI32, ast::TyI8) | + (ast::TyI16, ast::TyI8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", i1, i2)), _ => () } }, - (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyUint(u)) => { - span_lint(cx, CAST_SIGN_LOSS, expr.span, + (&ty::TyInt(i), &ty::TyUint(u)) => { + span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting from {} to {} loses the sign of the value", i, u)); match (i, u) { - (ast::IntTy::TyI64, ast::UintTy::TyU32) | - (ast::IntTy::TyI64, ast::UintTy::TyU16) | - (ast::IntTy::TyI64, ast::UintTy::TyU8) | - (ast::IntTy::TyI32, ast::UintTy::TyU16) | - (ast::IntTy::TyI32, ast::UintTy::TyU8) | - (ast::IntTy::TyI16, ast::UintTy::TyU8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + (ast::TyI64, ast::TyU32) | + (ast::TyI64, ast::TyU16) | + (ast::TyI64, ast::TyU8) | + (ast::TyI32, ast::TyU16) | + (ast::TyI32, ast::TyU8) | + (ast::TyI16, ast::TyU8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", i, u)), _ => () } }, - (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyInt(i)) => { + (&ty::TyUint(u), &ty::TyInt(i)) => { match (u, i) { - (ast::UintTy::TyU64, ast::IntTy::TyI32) | - (ast::UintTy::TyU64, ast::IntTy::TyI64) | - (ast::UintTy::TyU64, ast::IntTy::TyI16) | - (ast::UintTy::TyU64, ast::IntTy::TyI8) | - (ast::UintTy::TyU32, ast::IntTy::TyI32) | - (ast::UintTy::TyU32, ast::IntTy::TyI16) | - (ast::UintTy::TyU32, ast::IntTy::TyI8) | - (ast::UintTy::TyU16, ast::IntTy::TyI16) | - (ast::UintTy::TyU16, ast::IntTy::TyI8) | - (ast::UintTy::TyU8, ast::IntTy::TyI8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + (ast::TyU64, ast::TyI32) | + (ast::TyU64, ast::TyI64) | + (ast::TyU64, ast::TyI16) | + (ast::TyU64, ast::TyI8) | + (ast::TyU32, ast::TyI32) | + (ast::TyU32, ast::TyI16) | + (ast::TyU32, ast::TyI8) | + (ast::TyU16, ast::TyI16) | + (ast::TyU16, ast::TyI8) | + (ast::TyU8, ast::TyI8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", u, i)), _ => () } }, - (&ty::TypeVariants::TyUint(u1), &ty::TypeVariants::TyUint(u2)) => { + (&ty::TyUint(u1), &ty::TyUint(u2)) => { match (u1, u2) { - (ast::UintTy::TyU64, ast::UintTy::TyU32) | - (ast::UintTy::TyU64, ast::UintTy::TyU16) | - (ast::UintTy::TyU64, ast::UintTy::TyU8) | - (ast::UintTy::TyU32, ast::UintTy::TyU16) | - (ast::UintTy::TyU32, ast::UintTy::TyU8) | - (ast::UintTy::TyU16, ast::UintTy::TyU8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + (ast::TyU64, ast::TyU32) | + (ast::TyU64, ast::TyU16) | + (ast::TyU64, ast::TyU8) | + (ast::TyU32, ast::TyU16) | + (ast::TyU32, ast::TyU8) | + (ast::TyU16, ast::TyU8) => + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", u1, u2)), _ => () } @@ -259,13 +259,13 @@ impl LintPass for CastPass { } } (false, false) => { - if let (&ty::TypeVariants::TyFloat(ast::FloatTy::TyF64), - &ty::TypeVariants::TyFloat(ast::FloatTy::TyF32)) = (&cast_from.sty, &cast_to.sty) { + if let (&ty::TyFloat(ast::TyF64), + &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) { span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32"); } } } } } - } + } } -- cgit 1.4.1-3-g733a5 From ff28dd324ec404285dc61c6a29ceadbf3985d7e0 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 14:50:26 +0200 Subject: Fixed a little oversight. --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 2c4d81e361d..2950a03a036 100644 --- a/src/types.rs +++ b/src/types.rs @@ -190,7 +190,7 @@ impl LintPass for CastPass { (false, true) => { span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); - if !cx.tcx.expr_ty(expr).is_signed() { + if !cast_to.is_signed() { span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); } -- cgit 1.4.1-3-g733a5 From ab481e5cb1cb54005a19044709ac9bebabd74aae Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 21:37:37 +0200 Subject: Refactored the CastPass lints. --- src/types.rs | 121 +++++++++++++++++------------------------------------------ 1 file changed, 35 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 2950a03a036..ea0416e512c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -158,33 +158,24 @@ impl LintPass for CastPass { let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr)); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { - (true, false) => { - match (&cast_from.sty, &cast_to.sty) { - (&ty::TyInt(i), &ty::TyFloat(f)) => { - match (i, f) { - (ast::TyI32, ast::TyF32) | - (ast::TyI64, ast::TyF32) | - (ast::TyI64, ast::TyF64) => { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("converting from {} to {}, which causes a loss of precision", - i, f)); - }, - _ => () - } + (true, false) => { + let from_nbits = match &cast_from.sty { + &ty::TyInt(i) => 4 << (i as usize), + &ty::TyUint(u) => 4 << (u as usize), + _ => 0 + }; + let to_nbits : usize = match &cast_to.sty { + &ty::TyFloat(ast::TyF32) => 32, + &ty::TyFloat(ast::TyF64) => 64, + _ => 0 + }; + if from_nbits != 4 { + // Handle TyIs/TyUs separately (size is arch dependant) + if from_nbits >= to_nbits { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("converting from {} to {}, which causes a loss of precision", + cast_from, cast_to)); } - (&ty::TyUint(u), &ty::TyFloat(f)) => { - match (u, f) { - (ast::TyU32, ast::TyF32) | - (ast::TyU64, ast::TyF32) | - (ast::TyU64, ast::TyF64) => { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("converting from {} to {}, which causes a loss of precision", - u, f)); - }, - _ => () - } - }, - _ => () } }, (false, true) => { @@ -196,66 +187,24 @@ impl LintPass for CastPass { } }, (true, true) => { - match (&cast_from.sty, &cast_to.sty) { - (&ty::TyInt(i1), &ty::TyInt(i2)) => { - match (i1, i2) { - (ast::TyI64, ast::TyI32) | - (ast::TyI64, ast::TyI16) | - (ast::TyI64, ast::TyI8) | - (ast::TyI32, ast::TyI16) | - (ast::TyI32, ast::TyI8) | - (ast::TyI16, ast::TyI8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", i1, i2)), - _ => () - } - }, - (&ty::TyInt(i), &ty::TyUint(u)) => { - span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting from {} to {} loses the sign of the value", i, u)); - match (i, u) { - (ast::TyI64, ast::TyU32) | - (ast::TyI64, ast::TyU16) | - (ast::TyI64, ast::TyU8) | - (ast::TyI32, ast::TyU16) | - (ast::TyI32, ast::TyU8) | - (ast::TyI16, ast::TyU8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", i, u)), - _ => () - } - }, - (&ty::TyUint(u), &ty::TyInt(i)) => { - match (u, i) { - (ast::TyU64, ast::TyI32) | - (ast::TyU64, ast::TyI64) | - (ast::TyU64, ast::TyI16) | - (ast::TyU64, ast::TyI8) | - (ast::TyU32, ast::TyI32) | - (ast::TyU32, ast::TyI16) | - (ast::TyU32, ast::TyI8) | - (ast::TyU16, ast::TyI16) | - (ast::TyU16, ast::TyI8) | - (ast::TyU8, ast::TyI8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", u, i)), - _ => () - } - }, - (&ty::TyUint(u1), &ty::TyUint(u2)) => { - match (u1, u2) { - (ast::TyU64, ast::TyU32) | - (ast::TyU64, ast::TyU16) | - (ast::TyU64, ast::TyU8) | - (ast::TyU32, ast::TyU16) | - (ast::TyU32, ast::TyU8) | - (ast::TyU16, ast::TyU8) => - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", u1, u2)), - _ => () - } - }, - _ => () + if cast_from.is_signed() && !cast_to.is_signed() { + span_lint(cx, CAST_SIGN_LOSS, expr.span, + &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); + } + let from_nbits = match &cast_from.sty { + &ty::TyInt(i) => 4 << (i as usize), + &ty::TyUint(u) => 4 << (u as usize), + _ => 0 + }; + let to_nbits = match &cast_to.sty { + &ty::TyInt(i) => 4 << (i as usize), + &ty::TyUint(u) => 4 << (u as usize), + _ => 0 + }; + if to_nbits < from_nbits || + (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { + span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, + &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); } } (false, false) => { -- cgit 1.4.1-3-g733a5 From dbc9b7f46eb95d2583fc60c09220c0803ba541ee Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Thu, 20 Aug 2015 22:44:40 +0200 Subject: Reworked the error messages for more heplfulness. Renamed the cast_possible_overflow lint to cast_possible_truncation, and updated the error message, readme and crate root accordingly. Added some more information to the message for the cast_precision_loss lint. Updated the test case to reflect changes. --- README.md | 88 +++++++++++++++++++++++----------------------- src/lib.rs | 2 +- src/types.rs | 23 ++++++------ tests/compile-fail/cast.rs | 26 +++++++------- 4 files changed, 70 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 6a264034773..fbb16fcb170 100644 --- a/README.md +++ b/README.md @@ -6,50 +6,50 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints Lints included in this crate: -name | default | meaning ------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -cast_possible_overflow | allow | casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` -cast_precision_loss | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` -cast_sign_loss | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` -cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) -cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` -eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -explicit_iter_loop | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` -ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -inline_always | warn | `#[inline(always)]` is a bad idea in most cases -iter_next_loop | warn | for-looping over `_.next()` which is probably not intended -len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` -len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function -let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf -modulo_one | warn | taking a number modulo 1, which always returns 0 -mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do -needless_return | warn | using a return statement like `return expr;` where an expression would suffice -non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` -ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively -range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator -redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled -single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` -string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -string_to_string | warn | calling `String.to_string()` which is a no-op -toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) -unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) -zero_width_space | deny | using a zero-width space in a string literal, which is confusing +name | default | meaning +-------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +approx_constant | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +cast_possible_truncation | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +cast_precision_loss | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +cast_sign_loss | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) +cmp_owned | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +collapsible_if | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +eq_op | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +explicit_iter_loop | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +float_cmp | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +identity_op | warn | using identity operations, e.g. `x + 0` or `y / 1` +ineffective_bit_mask | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +inline_always | warn | `#[inline(always)]` is a bad idea in most cases +iter_next_loop | warn | for-looping over `_.next()` which is probably not intended +len_without_is_empty | warn | traits and impls that have `.len()` but not `.is_empty()` +len_zero | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function +let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +modulo_one | warn | taking a number modulo 1, which always returns 0 +mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +needless_lifetimes | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +needless_range_loop | warn | for-looping over a range of indices where an iterator over items would do +needless_return | warn | using a return statement like `return expr;` where an expression would suffice +non_ascii_literal | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +option_unwrap_used | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +precedence | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` +ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator +redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled +single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` +string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +string_to_string | warn | calling `String.to_string()` which is a no-op +toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) +zero_width_space | deny | using a zero-width space in a string literal, which is confusing To use, add the following lines to your Cargo.toml: diff --git a/src/lib.rs b/src/lib.rs index f4e3ed54c60..bdb3cb3471a 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,7 +106,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::BOX_VEC, - types::CAST_POSSIBLE_OVERFLOW, + types::CAST_POSSIBLE_TRUNCATION, types::CAST_PRECISION_LOSS, types::CAST_SIGN_LOSS, types::LET_UNIT_VALUE, diff --git a/src/types.rs b/src/types.rs index ea0416e512c..f9949a7b563 100644 --- a/src/types.rs +++ b/src/types.rs @@ -143,14 +143,14 @@ declare_lint!(pub CAST_PRECISION_LOSS, Allow, "casts that cause loss of precision, e.g `x as f32` where `x: u64`"); declare_lint!(pub CAST_SIGN_LOSS, Allow, "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"); -declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow, - "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); +declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, + "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); impl LintPass for CastPass { fn get_lints(&self) -> LintArray { lint_array!(CAST_PRECISION_LOSS, CAST_SIGN_LOSS, - CAST_POSSIBLE_OVERFLOW) + CAST_POSSIBLE_TRUNCATION) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -170,17 +170,18 @@ impl LintPass for CastPass { _ => 0 }; if from_nbits != 4 { - // Handle TyIs/TyUs separately (size is arch dependant) + // Handle TyIs/TyUs separately (pointer size is arch dependant) if from_nbits >= to_nbits { span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("converting from {} to {}, which causes a loss of precision", - cast_from, cast_to)); + &format!("converting from {0} to {1}, which causes a loss of precision \ + ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", + cast_from, cast_to, from_nbits, if to_nbits == 64 {52} else {23} )); } } }, (false, true) => { - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); if !cast_to.is_signed() { span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); @@ -203,14 +204,14 @@ impl LintPass for CastPass { }; if to_nbits < from_nbits || (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, - &format!("the contents of a {} may overflow a {}", cast_from, cast_to)); + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); } } (false, false) => { if let (&ty::TyFloat(ast::TyF64), &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) { - span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32"); + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may cause truncation of the value"); } } } diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index a51ea62a7b8..af6e6089fbf 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -1,30 +1,30 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(cast_precision_loss, cast_possible_overflow, cast_sign_loss)] +#[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss)] fn main() { let i : i32 = 42; let u : u32 = 42; let f : f32 = 42.0; // Test cast_precision_loss - i as f32; //~ERROR converting from i32 to f32, which causes a loss of precision - (i as i64) as f32; //~ERROR converting from i64 to f32, which causes a loss of precision - (i as i64) as f64; //~ERROR converting from i64 to f64, which causes a loss of precision - u as f32; //~ERROR converting from u32 to f32, which causes a loss of precision - (u as u64) as f32; //~ERROR converting from u64 to f32, which causes a loss of precision - (u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision + i as f32; //~ERROR converting from i32 to f32, which causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide) + (i as i64) as f32; //~ERROR converting from i64 to f32, which causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide) + (i as i64) as f64; //~ERROR converting from i64 to f64, which causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide) + u as f32; //~ERROR converting from u32 to f32, which causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide) + (u as u64) as f32; //~ERROR converting from u64 to f32, which causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide) + (u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide) i as f64; // Should not trigger the lint u as f64; // Should not trigger the lint - // Test cast_possible_overflow - f as i32; //~ERROR the contents of a f32 may overflow a i32 - f as u32; //~ERROR the contents of a f32 may overflow a u32 + // Test cast_possible_truncation + f as i32; //~ERROR casting f32 to i32 may cause truncation of the value + f as u32; //~ERROR casting f32 to u32 may cause truncation of the value //~^ERROR casting from f32 to u32 loses the sign of the value - i as u8; //~ERROR the contents of a i32 may overflow a u8 + i as u8; //~ERROR casting i32 to u8 may cause truncation of the value //~^ERROR casting from i32 to u8 loses the sign of the value - (f as f64) as f32; //~ERROR the contents of a f64 may overflow a f32 - i as i8; //~ERROR the contents of a i32 may overflow a i8 + (f as f64) as f32; //~ERROR casting f64 to f32 may cause truncation of the value + i as i8; //~ERROR casting i32 to i8 may cause truncation of the value // Test cast_sign_loss i as u32; //~ERROR casting from i32 to u32 loses the sign of the value -- cgit 1.4.1-3-g733a5 From ad0bc66402eb528aedb1d14235fed9a70bcc0a34 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Fri, 21 Aug 2015 03:03:37 +0200 Subject: Added support for isize/usize in the CastPass lint pass. Extracted the match that determines an integer types's size in a utility function and implemented support for usize/isize. Added a needed feature to the crate root. Added some tests to cover those cases, and a test I previously forgot. Silenced two errors signaled by dogfood.sh in unicode.rs. --- src/lib.rs | 2 +- src/types.rs | 33 ++++++++++++++++----------------- src/unicode.rs | 1 + tests/compile-fail/cast.rs | 30 ++++++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index bdb3cb3471a..9ea1efeed5f 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, core, collections)] -#![feature(str_split_at)] +#![feature(str_split_at, num_bits_bytes)] #![allow(unknown_lints)] #[macro_use] diff --git a/src/types.rs b/src/types.rs index f9949a7b563..915ffb15fe5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -146,6 +146,18 @@ declare_lint!(pub CAST_SIGN_LOSS, Allow, declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); +/// Returns the size in bits of an integral type. +/// Will return 0 if the type is not an int or uint variant +fn int_ty_to_nbits(typ: &ty::TyS) -> usize { + let n = match &typ.sty { + &ty::TyInt(i) => 4 << (i as usize), + &ty::TyUint(u) => 4 << (u as usize), + _ => 0 + }; + // n == 4 is the usize/isize case + if n == 4 { ::std::usize::BITS } else { n } +} + impl LintPass for CastPass { fn get_lints(&self) -> LintArray { lint_array!(CAST_PRECISION_LOSS, @@ -159,18 +171,13 @@ impl LintPass for CastPass { if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { - let from_nbits = match &cast_from.sty { - &ty::TyInt(i) => 4 << (i as usize), - &ty::TyUint(u) => 4 << (u as usize), - _ => 0 - }; + let from_nbits = int_ty_to_nbits(cast_from); let to_nbits : usize = match &cast_to.sty { &ty::TyFloat(ast::TyF32) => 32, &ty::TyFloat(ast::TyF64) => 64, _ => 0 }; - if from_nbits != 4 { - // Handle TyIs/TyUs separately (pointer size is arch dependant) + if from_nbits != 0 { if from_nbits >= to_nbits { span_lint(cx, CAST_PRECISION_LOSS, expr.span, &format!("converting from {0} to {1}, which causes a loss of precision \ @@ -192,16 +199,8 @@ impl LintPass for CastPass { span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); } - let from_nbits = match &cast_from.sty { - &ty::TyInt(i) => 4 << (i as usize), - &ty::TyUint(u) => 4 << (u as usize), - _ => 0 - }; - let to_nbits = match &cast_to.sty { - &ty::TyInt(i) => 4 << (i as usize), - &ty::TyUint(u) => 4 << (u as usize), - _ => 0 - }; + let from_nbits = int_ty_to_nbits(cast_from); + let to_nbits = int_ty_to_nbits(cast_to); if to_nbits < from_nbits || (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, diff --git a/src/unicode.rs b/src/unicode.rs index ab48fd1bef2..8a64f612666 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -40,6 +40,7 @@ fn check_str(cx: &Context, string: &str, span: Span) { } } +#[allow(cast_possible_truncation)] fn str_pos_lint(cx: &Context, lint: &'static Lint, span: Span, index: usize, msg: &str) { span_lint(cx, lint, Span { lo: span.lo + BytePos((1 + index) as u32), hi: span.lo + BytePos((1 + index) as u32), diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index af6e6089fbf..0fa402b3bf7 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss)] +#[allow(dead_code)] fn main() { let i : i32 = 42; let u : u32 = 42; @@ -16,7 +17,7 @@ fn main() { (u as u64) as f64; //~ERROR converting from u64 to f64, which causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide) i as f64; // Should not trigger the lint u as f64; // Should not trigger the lint - + // Test cast_possible_truncation f as i32; //~ERROR casting f32 to i32 may cause truncation of the value f as u32; //~ERROR casting f32 to u32 may cause truncation of the value @@ -25,7 +26,32 @@ fn main() { //~^ERROR casting from i32 to u8 loses the sign of the value (f as f64) as f32; //~ERROR casting f64 to f32 may cause truncation of the value i as i8; //~ERROR casting i32 to i8 may cause truncation of the value - + u as i32; //~ERROR casting u32 to i32 may cause truncation of the value + // Test cast_sign_loss i as u32; //~ERROR casting from i32 to u32 loses the sign of the value + + // Extra checks for usize/isize + let is : isize = -42; + is as usize; //~ERROR casting from isize to usize loses the sign of the value + is as i8; //~ERROR casting isize to i8 may cause truncation of the value + + // FIXME : enable these checks when we figure out a way to make compiletest deal with conditional compilation + /* + #[cfg(target_pointer_width = "64")] + fn check_64() { + let is : isize = -42; + let us : usize = 42; + is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 64 bits wide, but f32's mantissa is only 23 bits wide) + us as u32; //ERROR casting usize to u32 may cause truncation of the value + us as u64; // Should not trigger any lint + } + #[cfg(target_pointer_width = "32")] + fn check_32() { + let is : isize = -42; + let us : usize = 42; + is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 32 bits wide, but f32's mantissa is only 23 bits wide) + us as u32; // Should not trigger any lint + us as u64; // Should not trigger any lint + }*/ } \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 4dcbad1b086368beb97dc9d20b154a634c5c84af Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 12:19:07 +0200 Subject: const folding for eq_op --- src/eq_op.rs | 128 +++++++++++++++++++++++++++++---------------------------- src/strings.rs | 13 +++--- 2 files changed, 73 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 50b61e23356..6202dcc3670 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -4,6 +4,7 @@ use syntax::ast_util as ast_util; use syntax::ptr::P; use syntax::codemap as code; +use consts::constant; use utils::span_lint; declare_lint! { @@ -22,7 +23,7 @@ impl LintPass for EqOp { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { - if is_cmp_or_bit(op) && is_exp_equal(left, right) { + if is_cmp_or_bit(op) && is_exp_equal(cx, left, right) { span_lint(cx, EQ_OP, e.span, &format!( "equal expressions as operands to {}", ast_util::binop_to_string(op.node))); @@ -31,45 +32,48 @@ impl LintPass for EqOp { } } -pub fn is_exp_equal(left : &Expr, right : &Expr) -> bool { +pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { match (&left.node, &right.node) { (&ExprBinary(ref lop, ref ll, ref lr), &ExprBinary(ref rop, ref rl, ref rr)) => lop.node == rop.node && - is_exp_equal(ll, rl) && is_exp_equal(lr, rr), + is_exp_equal(cx, ll, rl) && is_exp_equal(cx, lr, rr), (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => - both(lpl, rpl, |l, r| is_exp_equal(l, r)) && - is_exp_equal(lbox, rbox), + both(lpl, rpl, |l, r| is_exp_equal(cx, l, r)) && + is_exp_equal(cx, lbox, rbox), (&ExprCall(ref lcallee, ref largs), - &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(lcallee, - rcallee) && is_exps_equal(largs, rargs), + &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(cx, lcallee, + rcallee) && is_exps_equal(cx, largs, rargs), (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => - is_ty_equal(lty, rty) && is_exp_equal(lc, rc), + is_ty_equal(cx, lty, rty) && is_exp_equal(cx, lc, rc), (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => - lfident.node == rfident.node && is_exp_equal(lfexp, rfexp), + lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprMethodCall(ref lident, ref lcty, ref lmargs), &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => - lident.node == rident.node && is_tys_equal(lcty, rcty) && - is_exps_equal(lmargs, rmargs), - (&ExprParen(ref lparen), _) => is_exp_equal(lparen, right), - (_, &ExprParen(ref rparen)) => is_exp_equal(left, rparen), + lident.node == rident.node && is_tys_equal(cx, lcty, rcty) && + is_exps_equal(cx, lmargs, rmargs), + (&ExprParen(ref lparen), _) => is_exp_equal(cx, lparen, right), + (_, &ExprParen(ref rparen)) => is_exp_equal(cx, left, rparen), (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => both(lqself, rqself, |l, r| is_qself_equal(l, r)) && is_path_equal(lsubpath, rsubpath), (&ExprTup(ref ltup), &ExprTup(ref rtup)) => - is_exps_equal(ltup, rtup), + is_exps_equal(cx, ltup, rtup), (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => - lunop == runop && is_exp_equal(l, r), - (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(l, r), + lunop == runop && is_exp_equal(cx, l, r), + (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), + _ => false + } || match (constant(cx, left), constant(cx, right)) { + (Some(l), Some(r)) => l == r, _ => false } } -fn is_exps_equal(left : &[P<Expr>], right : &[P<Expr>]) -> bool { - over(left, right, |l, r| is_exp_equal(l, r)) +fn is_exps_equal(cx: &Context, left : &[P<Expr>], right : &[P<Expr>]) -> bool { + over(left, right, |l, r| is_exp_equal(cx, l, r)) } fn is_path_equal(left : &Path, right : &Path) -> bool { @@ -85,29 +89,29 @@ fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { left.ty.node == right.ty.node && left.position == right.position } -fn is_ty_equal(left : &Ty, right : &Ty) -> bool { +fn is_ty_equal(cx: &Context, left : &Ty, right : &Ty) -> bool { match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(lvec, rvec), + (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(cx, lvec, rvec), (&TyFixedLengthVec(ref lfvty, ref lfvexp), &TyFixedLengthVec(ref rfvty, ref rfvexp)) => - is_ty_equal(lfvty, rfvty) && is_exp_equal(lfvexp, rfvexp), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(lmut, rmut), + is_ty_equal(cx, lfvty, rfvty) && is_exp_equal(cx, lfvexp, rfvexp), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(cx, lmut, rmut), (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => both(ltime, rtime, is_lifetime_equal) && - is_mut_ty_equal(lrmut, rrmut), + is_mut_ty_equal(cx, lrmut, rrmut), (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => - is_bare_fn_ty_equal(lbare, rbare), - (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(ltup, rtup), + is_bare_fn_ty_equal(cx, lbare, rbare), + (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(cx, ltup, rtup), (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), (&TyObjectSum(ref lsumty, ref lobounds), &TyObjectSum(ref rsumty, ref robounds)) => - is_ty_equal(lsumty, rsumty) && + is_ty_equal(cx, lsumty, rsumty) && is_param_bounds_equal(lobounds, robounds), (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => is_param_bounds_equal(ltbounds, rtbounds), - (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(lty, rty), - (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(lof, rof), + (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(cx, lty, rty), + (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(cx, lof, rof), (&TyInfer, &TyInfer) => true, _ => false } @@ -136,41 +140,41 @@ fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) over(left, right, is_param_bound_equal) } -fn is_mut_ty_equal(left : &MutTy, right : &MutTy) -> bool { - left.mutbl == right.mutbl && is_ty_equal(&left.ty, &right.ty) +fn is_mut_ty_equal(cx: &Context, left : &MutTy, right : &MutTy) -> bool { + left.mutbl == right.mutbl && is_ty_equal(cx, &left.ty, &right.ty) } -fn is_bare_fn_ty_equal(left : &BareFnTy, right : &BareFnTy) -> bool { +fn is_bare_fn_ty_equal(cx: &Context, left : &BareFnTy, right : &BareFnTy) -> bool { left.unsafety == right.unsafety && left.abi == right.abi && is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && - is_fndecl_equal(&left.decl, &right.decl) + is_fndecl_equal(cx, &left.decl, &right.decl) } -fn is_fndecl_equal(left : &P<FnDecl>, right : &P<FnDecl>) -> bool { +fn is_fndecl_equal(cx: &Context, left : &P<FnDecl>, right : &P<FnDecl>) -> bool { left.variadic == right.variadic && - is_args_equal(&left.inputs, &right.inputs) && - is_fnret_ty_equal(&left.output, &right.output) + is_args_equal(cx, &left.inputs, &right.inputs) && + is_fnret_ty_equal(cx, &left.output, &right.output) } -fn is_fnret_ty_equal(left : &FunctionRetTy, right : &FunctionRetTy) - -> bool { +fn is_fnret_ty_equal(cx: &Context, left : &FunctionRetTy, + right : &FunctionRetTy) -> bool { match (left, right) { (&NoReturn(_), &NoReturn(_)) | (&DefaultReturn(_), &DefaultReturn(_)) => true, - (&Return(ref lty), &Return(ref rty)) => is_ty_equal(lty, rty), + (&Return(ref lty), &Return(ref rty)) => is_ty_equal(cx, lty, rty), _ => false } } -fn is_arg_equal(l: &Arg, r : &Arg) -> bool { - is_ty_equal(&l.ty, &r.ty) && is_pat_equal(&l.pat, &r.pat) +fn is_arg_equal(cx: &Context, l: &Arg, r : &Arg) -> bool { + is_ty_equal(cx, &l.ty, &r.ty) && is_pat_equal(cx, &l.pat, &r.pat) } -fn is_args_equal(left : &[Arg], right : &[Arg]) -> bool { - over(left, right, is_arg_equal) +fn is_args_equal(cx: &Context, left : &[Arg], right : &[Arg]) -> bool { + over(left, right, |l, r| is_arg_equal(cx, l, r)) } -fn is_pat_equal(left : &Pat, right : &Pat) -> bool { +fn is_pat_equal(cx: &Context, left : &Pat, right : &Pat) -> bool { match(&left.node, &right.node) { (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, (&PatIdent(ref lmode, ref lident, Option::None), @@ -179,51 +183,51 @@ fn is_pat_equal(left : &Pat, right : &Pat) -> bool { (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => lmode == rmode && is_ident_equal(&lident.node, &rident.node) && - is_pat_equal(lpat, rpat), + is_pat_equal(cx, lpat, rpat), (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| - is_pats_equal(l, r)), + is_pats_equal(cx, l, r)), (&PatStruct(ref lpath, ref lfieldpat, lbool), &PatStruct(ref rpath, ref rfieldpat, rbool)) => lbool == rbool && is_path_equal(lpath, rpath) && - is_spanned_fieldpats_equal(lfieldpat, rfieldpat), - (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(ltup, rtup), + is_spanned_fieldpats_equal(cx, lfieldpat, rfieldpat), + (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(cx, ltup, rtup), (&PatBox(ref lboxed), &PatBox(ref rboxed)) => - is_pat_equal(lboxed, rboxed), + is_pat_equal(cx, lboxed, rboxed), (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => - is_pat_equal(lpat, rpat) && lmut == rmut, - (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(llit, rlit), + is_pat_equal(cx, lpat, rpat) && lmut == rmut, + (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(cx, llit, rlit), (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => - is_exp_equal(lfrom, rfrom) && is_exp_equal(lto, rto), + is_exp_equal(cx, lfrom, rfrom) && is_exp_equal(cx, lto, rto), (&PatVec(ref lfirst, Option::None, ref llast), &PatVec(ref rfirst, Option::None, ref rlast)) => - is_pats_equal(lfirst, rfirst) && is_pats_equal(llast, rlast), + is_pats_equal(cx, lfirst, rfirst) && is_pats_equal(cx, llast, rlast), (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => - is_pats_equal(lfirst, rfirst) && is_pat_equal(lpat, rpat) && - is_pats_equal(llast, rlast), + is_pats_equal(cx, lfirst, rfirst) && is_pat_equal(cx, lpat, rpat) && + is_pats_equal(cx, llast, rlast), // I don't match macros for now, the code is slow enough as is ;-) _ => false } } -fn is_spanned_fieldpats_equal(left : &[code::Spanned<FieldPat>], +fn is_spanned_fieldpats_equal(cx: &Context, left : &[code::Spanned<FieldPat>], right : &[code::Spanned<FieldPat>]) -> bool { - over(left, right, |l, r| is_fieldpat_equal(&l.node, &r.node)) + over(left, right, |l, r| is_fieldpat_equal(cx, &l.node, &r.node)) } -fn is_fieldpat_equal(left : &FieldPat, right : &FieldPat) -> bool { +fn is_fieldpat_equal(cx: &Context, left : &FieldPat, right : &FieldPat) -> bool { left.is_shorthand == right.is_shorthand && is_ident_equal(&left.ident, &right.ident) && - is_pat_equal(&left.pat, &right.pat) + is_pat_equal(cx, &left.pat, &right.pat) } fn is_ident_equal(left : &Ident, right : &Ident) -> bool { &left.name == &right.name && left.ctxt == right.ctxt } -fn is_pats_equal(left : &[P<Pat>], right : &[P<Pat>]) -> bool { - over(left, right, |l, r| is_pat_equal(l, r)) +fn is_pats_equal(cx: &Context, left : &[P<Pat>], right : &[P<Pat>]) -> bool { + over(left, right, |l, r| is_pat_equal(cx, l, r)) } fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) @@ -241,8 +245,8 @@ fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool { left.name == right.name } -fn is_tys_equal(left : &[P<Ty>], right : &[P<Ty>]) -> bool { - over(left, right, |l, r| is_ty_equal(l, r)) +fn is_tys_equal(cx: &Context, left : &[P<Ty>], right : &[P<Ty>]) -> bool { + over(left, right, |l, r| is_ty_equal(cx, l, r)) } fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool diff --git a/src/strings.rs b/src/strings.rs index 7981b785850..b1da93d71e3 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -41,7 +41,7 @@ impl LintPass for StringAdd { if let Some(ref p) = parent { if let &ExprAssign(ref target, _) = &p.node { // avoid duplicate matches - if is_exp_equal(target, left) { return; } + if is_exp_equal(cx, target, left) { return; } } } } @@ -51,7 +51,7 @@ impl LintPass for StringAdd { Consider using `String::push_str()` instead") } } else if let &ExprAssign(ref target, ref src) = &e.node { - if is_string(cx, target) && is_add(src, target) { + if is_string(cx, target) && is_add(cx, src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ Consider using `String::push_str()` instead") @@ -67,13 +67,14 @@ fn is_string(cx: &Context, e: &Expr) -> bool { } else { false } } -fn is_add(src: &Expr, target: &Expr) -> bool { +fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { match &src.node { &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => - is_exp_equal(target, left), + is_exp_equal(cx, target, left), &ExprBlock(ref block) => block.stmts.is_empty() && - block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)), - &ExprParen(ref expr) => is_add(&*expr, target), + block.expr.as_ref().map_or(false, + |expr| is_add(cx, &*expr, target)), + &ExprParen(ref expr) => is_add(cx, &*expr, target), _ => false } } -- cgit 1.4.1-3-g733a5 From a22b3cdceecb85bf55a21e15959d639d98f6da5e Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 12:26:03 +0200 Subject: const folding for eq_op --- src/eq_op.rs | 5 +++-- tests/compile-fail/eq_op.rs | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 6202dcc3670..ebc6aa17100 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -33,7 +33,7 @@ impl LintPass for EqOp { } pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { - match (&left.node, &right.node) { + if match (&left.node, &right.node) { (&ExprBinary(ref lop, ref ll, ref lr), &ExprBinary(ref rop, ref rl, ref rr)) => lop.node == rop.node && @@ -66,7 +66,8 @@ pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { lunop == runop && is_exp_equal(cx, l, r), (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), _ => false - } || match (constant(cx, left), constant(cx, right)) { + } { return true; } + match (constant(cx, left), constant(cx, right)) { (Some(l), Some(r)) => l == r, _ => false } diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 8f61a11aa08..a1183629344 100755 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -34,4 +34,8 @@ fn main() { ((1, 2) != (1, 2)); //~ERROR equal expressions [1].len() == [1].len(); //~ERROR equal expressions vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros + + // const folding + 1 + 1 == 2; //~ERROR equal expressions + 1 - 1 == 0; //~ERROR equal expressions } -- cgit 1.4.1-3-g733a5 From b2df15d65a7baf1f8d9b8b776027a34dd6e1db10 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 18:28:17 +0200 Subject: ptr_arg improvements (fixes #214) * do not trigger on mutable references * use "real" type from ty, not AST type --- src/ptr_arg.rs | 45 +++++++++++++++++++++++++------------------ tests/compile-fail/ptr_arg.rs | 17 +++++++++------- 2 files changed, 36 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 2748d187a4e..35c61b10266 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -4,10 +4,9 @@ use rustc::lint::*; use syntax::ast::*; -use syntax::codemap::Span; +use rustc::middle::ty; -use types::match_ty_unwrap; -use utils::span_lint; +use utils::{span_lint, match_def_path}; declare_lint! { pub PTR_ARG, @@ -43,24 +42,32 @@ impl LintPass for PtrArg { } } +#[allow(unused_imports)] fn check_fn(cx: &Context, decl: &FnDecl) { + { + // In case stuff gets moved around + use collections::vec::Vec; + use collections::string::String; + } for arg in &decl.inputs { - match &arg.ty.node { - &TyPtr(ref p) | &TyRptr(_, ref p) => - check_ptr_subtype(cx, arg.ty.span, &p.ty), - _ => () + if arg.ty.node == TyInfer { // "self" arguments + continue; + } + let ref sty = cx.tcx.pat_ty(&*arg.pat).sty; + if let &ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = sty { + if let ty::TyStruct(did, _) = ty.sty { + if match_def_path(cx, did.did, &["collections", "vec", "Vec"]) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference \ + and cannot be used with non-Vec-based slices. Consider changing \ + the type to `&[...]`"); + } + else if match_def_path(cx, did.did, &["collections", "string", "String"]) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&String` instead of `&str` involves a new object \ + where a slice will do. Consider changing the type to `&str`"); + } + } } } } - -fn check_ptr_subtype(cx: &Context, span: Span, ty: &Ty) { - match_ty_unwrap(ty, &["Vec"]).map_or_else(|| match_ty_unwrap(ty, - &["String"]).map_or((), |_| { - span_lint(cx, PTR_ARG, span, - "writing `&String` instead of `&str` involves a new object \ - where a slice will do. Consider changing the type to `&str`") - }), |_| span_lint(cx, PTR_ARG, span, - "writing `&Vec<_>` instead of \ - `&[_]` involves one more reference and cannot be used with \ - non-Vec-based slices. Consider changing the type to `&[...]`")) -} diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs index d4b6d22608f..d0615be492b 100755 --- a/tests/compile-fail/ptr_arg.rs +++ b/tests/compile-fail/ptr_arg.rs @@ -1,20 +1,23 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(unused)] +#![deny(ptr_arg)] -#[deny(ptr_arg)] -#[allow(unused)] fn do_vec(x: &Vec<i64>) { //~ERROR writing `&Vec<_>` instead of `&[_]` //Nothing here } -#[deny(ptr_arg)] -#[allow(unused)] +fn do_vec_mut(x: &mut Vec<i64>) { // no error here + //Nothing here +} + fn do_str(x: &String) { //~ERROR writing `&String` instead of `&str` //Nothing here either } +fn do_str_mut(x: &mut String) { // no error here + //Nothing here either +} + fn main() { - let x = vec![1i64, 2, 3]; - do_vec(&x); - do_str(&"hello".to_owned()); } -- cgit 1.4.1-3-g733a5 From 707e95f2e5b9f6e20998508d99959dd1642d26ec Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 18:40:36 +0200 Subject: types: use middle::ty types instead of ast types This gets rid of the match_ty_unwrap function. --- src/types.rs | 71 +++++++++++++++------------------------------ tests/compile-fail/dlist.rs | 2 +- 2 files changed, 24 insertions(+), 49 deletions(-) mode change 100644 => 100755 tests/compile-fail/dlist.rs (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 915ffb15fe5..986fb1016ed 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,11 +2,10 @@ use rustc::lint::*; use syntax::ast; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; use rustc::middle::ty; use syntax::codemap::ExpnInfo; -use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{in_macro, match_def_path, snippet, span_lint, span_help_and_lint, in_external_macro}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -18,61 +17,37 @@ declare_lint!(pub LINKEDLIST, Warn, "usage of LinkedList, usually a vector is faster, or a more specialized data \ structure like a RingBuf"); -/// Matches a type with a provided string, and returns its type parameters if successful -pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> { - match ty.node { - TyPath(_, Path {segments: ref seg, ..}) => { - // So ast::Path isn't the full path, just the tokens that were provided. - // I could muck around with the maps and find the full path - // however the more efficient way is to simply reverse the iterators and zip them - // which will compare them in reverse until one of them runs out of segments - if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) { - match seg[..].last() { - Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => { - Some(&a.types[..]) - } - _ => None - } - } else { - None - } - }, - _ => None - } -} - #[allow(unused_imports)] impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) } - fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { + fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) { { // In case stuff gets moved around - use std::boxed::Box; - use std::vec::Vec; + use collections::vec::Vec; + use collections::linked_list::LinkedList; } - match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first()) - .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) - .map(|_| { - span_help_and_lint(cx, BOX_VEC, ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); - }); - { - // In case stuff gets moved around - use collections::linked_list::LinkedList as DL1; - use std::collections::linked_list::LinkedList as DL2; - } - let dlists = [vec!["std","collections","linked_list","LinkedList"], - vec!["collections","linked_list","LinkedList"]]; - for path in &dlists { - if match_ty_unwrap(ty, &path[..]).is_some() { - span_help_and_lint(cx, LINKEDLIST, ty.span, - "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "a RingBuf might work"); - return; + if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + if let ty::TyBox(ref inner) = ty.sty { + if let ty::TyStruct(did, _) = inner.sty { + if match_def_path(cx, did.did, &["collections", "vec", "Vec"]) { + span_help_and_lint( + cx, BOX_VEC, ast_ty.span, + "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); + } + } + } + if let ty::TyStruct(did, _) = ty.sty { + if match_def_path(cx, did.did, &["collections", "linked_list", "LinkedList"]) { + span_help_and_lint( + cx, LINKEDLIST, ast_ty.span, + "I see you're using a LinkedList! Perhaps you meant some other data structure?", + "a RingBuf might work"); + return; + } } } } diff --git a/tests/compile-fail/dlist.rs b/tests/compile-fail/dlist.rs old mode 100644 new mode 100755 index a2343c339ad..a800c045a50 --- a/tests/compile-fail/dlist.rs +++ b/tests/compile-fail/dlist.rs @@ -12,4 +12,4 @@ pub fn test(foo: LinkedList<u8>) { //~ ERROR I see you're using a LinkedList! fn main(){ test(LinkedList::new()); -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From a437936d49081faa82227c7d216ff3b0d6363ed3 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 18:48:36 +0200 Subject: all: put often used DefPaths into utils as consts Also remove the "use xxx;" blocks to ensure import paths don't change. They don't work anyway since stuff may still be re-exported at the old location, while we need the "canonical" location for the type checks. Plus, the test suite catches all these cases. --- src/methods.rs | 14 ++++---------- src/ptr_arg.rs | 11 +++-------- src/strings.rs | 3 ++- src/types.rs | 11 +++-------- src/utils.rs | 7 +++++++ 5 files changed, 19 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index f2df736bebc..70cf32e5093 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -3,6 +3,7 @@ use rustc::lint::*; use rustc::middle::ty; use utils::{span_lint, match_def_path, walk_ptrs_ty}; +use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; #[derive(Copy,Clone)] pub struct MethodsPass; @@ -16,30 +17,23 @@ declare_lint!(pub STR_TO_STRING, Warn, declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); -#[allow(unused_imports)] impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - { - // In case stuff gets moved around - use core::option::Option; - use core::result::Result; - use collections::string::String; - } if let ExprMethodCall(ref ident, _, ref args) = expr.node { let ref obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty; if ident.node.name == "unwrap" { if let ty::TyEnum(did, _) = *obj_ty { - if match_def_path(cx, did.did, &["core", "option", "Option"]) { + if match_def_path(cx, did.did, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ to handle the None case gracefully, consider using expect() to provide a better panic message"); } - else if match_def_path(cx, did.did, &["core", "result", "Result"]) { + else if match_def_path(cx, did.did, &RESULT_PATH) { span_lint(cx, RESULT_UNWRAP_USED, expr.span, "used unwrap() on a Result value. Graceful handling \ of Err values is preferred"); @@ -51,7 +45,7 @@ impl LintPass for MethodsPass { span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); } else if let ty::TyStruct(did, _) = *obj_ty { - if match_def_path(cx, did.did, &["collections", "string", "String"]) { + if match_def_path(cx, did.did, &STRING_PATH) { span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op") } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 35c61b10266..cdf4ecb48e5 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -7,6 +7,7 @@ use syntax::ast::*; use rustc::middle::ty; use utils::{span_lint, match_def_path}; +use utils::{STRING_PATH, VEC_PATH}; declare_lint! { pub PTR_ARG, @@ -42,13 +43,7 @@ impl LintPass for PtrArg { } } -#[allow(unused_imports)] fn check_fn(cx: &Context, decl: &FnDecl) { - { - // In case stuff gets moved around - use collections::vec::Vec; - use collections::string::String; - } for arg in &decl.inputs { if arg.ty.node == TyInfer { // "self" arguments continue; @@ -56,13 +51,13 @@ fn check_fn(cx: &Context, decl: &FnDecl) { let ref sty = cx.tcx.pat_ty(&*arg.pat).sty; if let &ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = sty { if let ty::TyStruct(did, _) = ty.sty { - if match_def_path(cx, did.did, &["collections", "vec", "Vec"]) { + if match_def_path(cx, did.did, &VEC_PATH) { span_lint(cx, PTR_ARG, arg.ty.span, "writing `&Vec<_>` instead of `&[_]` involves one more reference \ and cannot be used with non-Vec-based slices. Consider changing \ the type to `&[...]`"); } - else if match_def_path(cx, did.did, &["collections", "string", "String"]) { + else if match_def_path(cx, did.did, &STRING_PATH) { span_lint(cx, PTR_ARG, arg.ty.span, "writing `&String` instead of `&str` involves a new object \ where a slice will do. Consider changing the type to `&str`"); diff --git a/src/strings.rs b/src/strings.rs index b1da93d71e3..c4fbca9344f 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -10,6 +10,7 @@ use syntax::codemap::Spanned; use eq_op::is_exp_equal; use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::STRING_PATH; declare_lint! { pub STRING_ADD_ASSIGN, @@ -63,7 +64,7 @@ impl LintPass for StringAdd { fn is_string(cx: &Context, e: &Expr) -> bool { let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); if let TyStruct(did, _) = ty.sty { - match_def_path(cx, did.did, &["collections", "string", "String"]) + match_def_path(cx, did.did, &STRING_PATH) } else { false } } diff --git a/src/types.rs b/src/types.rs index 986fb1016ed..57649adee8b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,6 +6,7 @@ use rustc::middle::ty; use syntax::codemap::ExpnInfo; use utils::{in_macro, match_def_path, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{LL_PATH, VEC_PATH}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -17,22 +18,16 @@ declare_lint!(pub LINKEDLIST, Warn, "usage of LinkedList, usually a vector is faster, or a more specialized data \ structure like a RingBuf"); -#[allow(unused_imports)] impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) } fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) { - { - // In case stuff gets moved around - use collections::vec::Vec; - use collections::linked_list::LinkedList; - } if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { if let ty::TyStruct(did, _) = inner.sty { - if match_def_path(cx, did.did, &["collections", "vec", "Vec"]) { + if match_def_path(cx, did.did, &VEC_PATH) { span_help_and_lint( cx, BOX_VEC, ast_ty.span, "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", @@ -41,7 +36,7 @@ impl LintPass for TypePass { } } if let ty::TyStruct(did, _) = ty.sty { - if match_def_path(cx, did.did, &["collections", "linked_list", "LinkedList"]) { + if match_def_path(cx, did.did, &LL_PATH) { span_help_and_lint( cx, LINKEDLIST, ast_ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", diff --git a/src/utils.rs b/src/utils.rs index 47e3a3456d6..fe5c1433c84 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,6 +6,13 @@ use rustc::ast_map::Node::NodeExpr; use rustc::middle::ty; use std::borrow::Cow; +// module DefPaths for certain structs/enums we check for +pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; + /// returns true if the macro that expanded the crate was outside of /// the current crate or was a compiler plugin pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { -- cgit 1.4.1-3-g733a5 From 8a10440641f7ec89236b1f40129738426ad4d702 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 19:00:33 +0200 Subject: utils: add match_type() helper function which saves one level of matching when checking for type paths --- src/methods.rs | 35 ++++++++++++++--------------------- src/ptr_arg.rs | 23 ++++++++++------------- src/ranges.rs | 11 ++++------- src/strings.rs | 8 ++------ src/types.rs | 27 +++++++++++---------------- src/utils.rs | 12 ++++++++++++ 6 files changed, 53 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 70cf32e5093..df8e35d98fb 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -2,7 +2,7 @@ use syntax::ast::*; use rustc::lint::*; use rustc::middle::ty; -use utils::{span_lint, match_def_path, walk_ptrs_ty}; +use utils::{span_lint, match_type, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; #[derive(Copy,Clone)] @@ -24,31 +24,24 @@ impl LintPass for MethodsPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { - let ref obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty; + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])); if ident.node.name == "unwrap" { - if let ty::TyEnum(did, _) = *obj_ty { - if match_def_path(cx, did.did, &OPTION_PATH) { - span_lint(cx, OPTION_UNWRAP_USED, expr.span, - "used unwrap() on an Option value. If you don't want \ - to handle the None case gracefully, consider using - expect() to provide a better panic message"); - } - else if match_def_path(cx, did.did, &RESULT_PATH) { - span_lint(cx, RESULT_UNWRAP_USED, expr.span, - "used unwrap() on a Result value. Graceful handling \ - of Err values is preferred"); - } + if match_type(cx, obj_ty, &OPTION_PATH) { + span_lint(cx, OPTION_UNWRAP_USED, expr.span, + "used unwrap() on an Option value. If you don't want \ + to handle the None case gracefully, consider using \ + expect() to provide a better panic message"); + } else if match_type(cx, obj_ty, &RESULT_PATH) { + span_lint(cx, RESULT_UNWRAP_USED, expr.span, + "used unwrap() on a Result value. Graceful handling \ + of Err values is preferred"); } } else if ident.node.name == "to_string" { - if let ty::TyStr = *obj_ty { + if obj_ty.sty == ty::TyStr { span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); - } - else if let ty::TyStruct(did, _) = *obj_ty { - if match_def_path(cx, did.did, &STRING_PATH) { - span_lint(cx, STRING_TO_STRING, expr.span, - "`String.to_string()` is a no-op") - } + } else if match_type(cx, obj_ty, &STRING_PATH) { + span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op"); } } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index cdf4ecb48e5..f0a0592f5e2 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -6,7 +6,7 @@ use rustc::lint::*; use syntax::ast::*; use rustc::middle::ty; -use utils::{span_lint, match_def_path}; +use utils::{span_lint, match_type}; use utils::{STRING_PATH, VEC_PATH}; declare_lint! { @@ -50,18 +50,15 @@ fn check_fn(cx: &Context, decl: &FnDecl) { } let ref sty = cx.tcx.pat_ty(&*arg.pat).sty; if let &ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = sty { - if let ty::TyStruct(did, _) = ty.sty { - if match_def_path(cx, did.did, &VEC_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference \ - and cannot be used with non-Vec-based slices. Consider changing \ - the type to `&[...]`"); - } - else if match_def_path(cx, did.did, &STRING_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&String` instead of `&str` involves a new object \ - where a slice will do. Consider changing the type to `&str`"); - } + if match_type(cx, ty, &VEC_PATH) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference \ + and cannot be used with non-Vec-based slices. Consider changing \ + the type to `&[...]`"); + } else if match_type(cx, ty, &STRING_PATH) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&String` instead of `&str` involves a new object \ + where a slice will do. Consider changing the type to `&str`"); } } } diff --git a/src/ranges.rs b/src/ranges.rs index bbe65285d58..d1a0a7e702e 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,8 +1,7 @@ use rustc::lint::{Context, LintArray, LintPass}; -use rustc::middle::ty::TypeVariants::TyStruct; use syntax::ast::*; use syntax::codemap::Spanned; -use utils::{match_def_path}; +use utils::match_type; declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, @@ -34,11 +33,9 @@ impl LintPass for StepByZero { fn is_range(cx: &Context, expr: &Expr) -> bool { // No need for walk_ptrs_ty here because step_by moves self, so it // can't be called on a borrowed range. - if let TyStruct(did, _) = cx.tcx.expr_ty(expr).sty { - // Note: RangeTo and RangeFull don't have step_by - match_def_path(cx, did.did, &["core", "ops", "Range"]) || - match_def_path(cx, did.did, &["core", "ops", "RangeFrom"]) - } else { false } + let ty = cx.tcx.expr_ty(expr); + // Note: RangeTo and RangeFull don't have step_by + match_type(cx, ty, &["core", "ops", "Range"]) || match_type(cx, ty, &["core", "ops", "RangeFrom"]) } fn is_lit_zero(expr: &Expr) -> bool { diff --git a/src/strings.rs b/src/strings.rs index c4fbca9344f..64d18eeb26d 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -4,12 +4,11 @@ //! disable the subsumed lint unless it has a higher level use rustc::lint::*; -use rustc::middle::ty::TypeVariants::TyStruct; use syntax::ast::*; use syntax::codemap::Spanned; use eq_op::is_exp_equal; -use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; declare_lint! { @@ -62,10 +61,7 @@ impl LintPass for StringAdd { } fn is_string(cx: &Context, e: &Expr) -> bool { - let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); - if let TyStruct(did, _) = ty.sty { - match_def_path(cx, did.did, &STRING_PATH) - } else { false } + match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH) } fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { diff --git a/src/types.rs b/src/types.rs index 57649adee8b..622f733f812 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,7 +5,7 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use rustc::middle::ty; use syntax::codemap::ExpnInfo; -use utils::{in_macro, match_def_path, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{in_macro, match_type, snippet, span_lint, span_help_and_lint, in_external_macro}; use utils::{LL_PATH, VEC_PATH}; /// Handles all the linting of funky types @@ -26,24 +26,19 @@ impl LintPass for TypePass { fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) { if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { - if let ty::TyStruct(did, _) = inner.sty { - if match_def_path(cx, did.did, &VEC_PATH) { - span_help_and_lint( - cx, BOX_VEC, ast_ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); - } - } - } - if let ty::TyStruct(did, _) = ty.sty { - if match_def_path(cx, did.did, &LL_PATH) { + if match_type(cx, inner, &VEC_PATH) { span_help_and_lint( - cx, LINKEDLIST, ast_ty.span, - "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "a RingBuf might work"); - return; + cx, BOX_VEC, ast_ty.span, + "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); } } + else if match_type(cx, ty, &LL_PATH) { + span_help_and_lint( + cx, LINKEDLIST, ast_ty.span, + "I see you're using a LinkedList! Perhaps you meant some other data structure?", + "a RingBuf might work"); + } } } } diff --git a/src/utils.rs b/src/utils.rs index fe5c1433c84..4fd36fb91d4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -44,6 +44,18 @@ pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { .zip(path.iter()).all(|(nm, p)| nm == p)) } +/// check if type is struct or enum type with given def path +pub fn match_type(cx: &Context, ty: ty::Ty, path: &[&str]) -> bool { + match ty.sty { + ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => { + match_def_path(cx, adt.did, path) + } + _ => { + false + } + } +} + /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { -- cgit 1.4.1-3-g733a5 From f1255d5f5d9c9d23d039ee3798af4e164563226f Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Sat, 22 Aug 2015 02:44:05 +0200 Subject: Casts : work in progress handling *size separately --- src/types.rs | 37 ++++++++++++++++++++++++++++--------- tests/compile-fail/cast.rs | 28 +++++++--------------------- 2 files changed, 35 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 915ffb15fe5..e8da11ecbe0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -150,14 +150,21 @@ declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: &ty::TyS) -> usize { let n = match &typ.sty { - &ty::TyInt(i) => 4 << (i as usize), - &ty::TyUint(u) => 4 << (u as usize), - _ => 0 + &ty::TyInt(i) => 4 << (i as usize), + &ty::TyUint(u) => 4 << (u as usize), + _ => 0 }; // n == 4 is the usize/isize case if n == 4 { ::std::usize::BITS } else { n } } +fn is_isize_or_usize(typ: &ty::TyS) -> bool { + match &typ.sty { + &ty::TyInt(ast::TyIs) | &ty::TyUint(ast::TyUs) => true, + _ => false + } +} + impl LintPass for CastPass { fn get_lints(&self) -> LintArray { lint_array!(CAST_PRECISION_LOSS, @@ -178,7 +185,14 @@ impl LintPass for CastPass { _ => 0 }; if from_nbits != 0 { - if from_nbits >= to_nbits { + // When casting to f32, precision loss would occur regardless of the arch + if is_isize_or_usize(cast_from) && to_nbits == 64 { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("converting from {0} to f64, which causes a loss of precision on 64-bit architectures \ + ({0} is 64 bits wide, but f64's mantissa is only 52 bits wide)", + cast_from)); + } + else if from_nbits >= to_nbits { span_lint(cx, CAST_PRECISION_LOSS, expr.span, &format!("converting from {0} to {1}, which causes a loss of precision \ ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", @@ -186,7 +200,7 @@ impl LintPass for CastPass { } } }, - (false, true) => { + (false, true) => { // Nothing to add there span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); if !cast_to.is_signed() { @@ -201,10 +215,15 @@ impl LintPass for CastPass { } let from_nbits = int_ty_to_nbits(cast_from); let to_nbits = int_ty_to_nbits(cast_to); - if to_nbits < from_nbits || - (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); + match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => + if to_nbits < from_nbits || + (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); + }, + (true, false) => (), // TODO + (false, true) => () // TODO } } (false, false) => { diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index 0fa402b3bf7..8e854fb21f9 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -32,26 +32,12 @@ fn main() { i as u32; //~ERROR casting from i32 to u32 loses the sign of the value // Extra checks for usize/isize - let is : isize = -42; - is as usize; //~ERROR casting from isize to usize loses the sign of the value - is as i8; //~ERROR casting isize to i8 may cause truncation of the value - - // FIXME : enable these checks when we figure out a way to make compiletest deal with conditional compilation /* - #[cfg(target_pointer_width = "64")] - fn check_64() { - let is : isize = -42; - let us : usize = 42; - is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 64 bits wide, but f32's mantissa is only 23 bits wide) - us as u32; //ERROR casting usize to u32 may cause truncation of the value - us as u64; // Should not trigger any lint - } - #[cfg(target_pointer_width = "32")] - fn check_32() { - let is : isize = -42; - let us : usize = 42; - is as f32; //ERROR converting from isize to f32, which causes a loss of precision (isize is 32 bits wide, but f32's mantissa is only 23 bits wide) - us as u32; // Should not trigger any lint - us as u64; // Should not trigger any lint - }*/ + let is : isize = -42; + let us : usize = 42; + is as usize; //ERROR casting from isize to usize loses the sign of the value + is as i8; //ERROR casting isize to i8 may cause truncation of the value + is as f64; //ERROR converting from isize to f64, which causes a loss of precision on 64-bit architectures (isize is 64 bits wide, but f64's mantissa is only 52 bits wide) + us as f64; //ERROR converting from usize to f64, which causes a loss of precision on 64-bit architectures (usize is 64 bits wide, but f64's mantissa is only 52 bits wide) + */ } \ No newline at end of file -- cgit 1.4.1-3-g733a5 From e92bf84a535b77c65127fadc2b82d762cff8ab66 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 22 Aug 2015 08:57:05 +0200 Subject: ptr_arg: fix panic when pattern type is not in tcx --- src/ptr_arg.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index f0a0592f5e2..2d09fcbcca9 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -45,20 +45,18 @@ impl LintPass for PtrArg { fn check_fn(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - if arg.ty.node == TyInfer { // "self" arguments - continue; - } - let ref sty = cx.tcx.pat_ty(&*arg.pat).sty; - if let &ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = sty { - if match_type(cx, ty, &VEC_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference \ - and cannot be used with non-Vec-based slices. Consider changing \ - the type to `&[...]`"); - } else if match_type(cx, ty, &STRING_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&String` instead of `&str` involves a new object \ - where a slice will do. Consider changing the type to `&str`"); + if let Some(pat_ty) = cx.tcx.pat_ty_opt(&*arg.pat) { + if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = pat_ty.sty { + if match_type(cx, ty, &VEC_PATH) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference \ + and cannot be used with non-Vec-based slices. Consider changing \ + the type to `&[...]`"); + } else if match_type(cx, ty, &STRING_PATH) { + span_lint(cx, PTR_ARG, arg.ty.span, + "writing `&String` instead of `&str` involves a new object \ + where a slice will do. Consider changing the type to `&str`"); + } } } } -- cgit 1.4.1-3-g733a5 From 630bb76f960c49d559efde55030b9a3ccb8b5704 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 22:53:47 +0200 Subject: new lint: type complexity (fixes #93) Still very naive, but it's a start. --- README.md | 1 + src/lib.rs | 2 + src/types.rs | 125 ++++++++++++++++++++++++++++++++++++ tests/compile-fail/complex_types.rs | 44 +++++++++++++ 4 files changed, 172 insertions(+) create mode 100755 tests/compile-fail/complex_types.rs (limited to 'src') diff --git a/README.md b/README.md index fbb16fcb170..55976104058 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ string_add | allow | using `x + ..` where x is a `String`; sugge string_add_assign | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead string_to_string | warn | calling `String.to_string()` which is a no-op toplevel_ref_arg | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +type_complexity | warn | usage of very complex types; recommends factoring out parts into `type` definitions unit_cmp | warn | comparing unit values (which is always `true` or `false`, respectively) zero_width_space | deny | using a zero-width space in a string literal, which is confusing diff --git a/src/lib.rs b/src/lib.rs index 9ea1efeed5f..b0f46ae45ab 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,6 +70,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); reg.register_lint_pass(box ranges::StepByZero as LintPassObject); reg.register_lint_pass(box types::CastPass as LintPassObject); + reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, @@ -111,6 +112,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::CAST_SIGN_LOSS, types::LET_UNIT_VALUE, types::LINKEDLIST, + types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::NON_ASCII_LITERAL, unicode::ZERO_WIDTH_SPACE, diff --git a/src/types.rs b/src/types.rs index 622f733f812..54c36535286 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,6 +2,8 @@ use rustc::lint::*; use syntax::ast; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use syntax::codemap::Span; +use syntax::visit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; use syntax::codemap::ExpnInfo; @@ -183,3 +185,126 @@ impl LintPass for CastPass { } } } + +declare_lint!(pub TYPE_COMPLEXITY, Warn, + "usage of very complex types; recommends factoring out parts into `type` definitions"); + +#[allow(missing_copy_implementations)] +pub struct TypeComplexityPass; + +impl LintPass for TypeComplexityPass { + fn get_lints(&self) -> LintArray { + lint_array!(TYPE_COMPLEXITY) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + check_fndecl(cx, decl); + } + + fn check_struct_field(&mut self, cx: &Context, field: &StructField) { + check_type(cx, &*field.node.ty); + } + + fn check_variant(&mut self, cx: &Context, var: &Variant, _: &Generics) { + // StructVariant is covered by check_struct_field + if let TupleVariantKind(ref args) = var.node.kind { + for arg in args { + check_type(cx, &*arg.ty); + } + } + } + + fn check_item(&mut self, cx: &Context, item: &Item) { + match item.node { + ItemStatic(ref ty, _, _) | + ItemConst(ref ty, _) => check_type(cx, ty), + // functions, enums, structs, impls and traits are covered + _ => () + } + } + + fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + match item.node { + ConstTraitItem(ref ty, _) | + TypeTraitItem(_, Some(ref ty)) => check_type(cx, ty), + MethodTraitItem(MethodSig { ref decl, .. }, None) => check_fndecl(cx, decl), + // methods with default impl are covered by check_fn + _ => () + } + } + + fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + match item.node { + ConstImplItem(ref ty, _) | + TypeImplItem(ref ty) => check_type(cx, ty), + // methods are covered by check_fn + _ => () + } + } + + fn check_local(&mut self, cx: &Context, local: &Local) { + if let Some(ref ty) = local.ty { + check_type(cx, ty); + } + } +} + +fn check_fndecl(cx: &Context, decl: &FnDecl) { + for arg in &decl.inputs { + check_type(cx, &*arg.ty); + } + if let Return(ref ty) = decl.output { + check_type(cx, ty); + } +} + +fn check_type(cx: &Context, ty: &ast::Ty) { + let score = { + let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; + visitor.visit_ty(ty); + visitor.score + }; + // println!("{:?} --> {}", ty, score); + if score > 250 { + span_lint(cx, TYPE_COMPLEXITY, ty.span, &format!( + "very complex type used. Consider factoring parts into `type` definitions")); + } +} + +/// Walks a type and assigns a complexity score to it. +struct TypeComplexityVisitor { + /// total complexity score of the type + score: u32, + /// current nesting level + nest: u32, +} + +impl<'v> Visitor<'v> for TypeComplexityVisitor { + fn visit_ty(&mut self, ty: &'v ast::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(..) | + TyVec(..) | + TyTup(..) | + TyFixedLengthVec(..) => (10 * self.nest, 1), + + // "Sum" of trait bounds + TyObjectSum(..) => (20 * self.nest, 0), + + // function types and "for<...>" bring a lot of overhead + TyBareFn(..) | + TyPolyTraitRef(..) => (50 * self.nest, 1), + + _ => (0, 0) + }; + self.score += add_score; + self.nest += sub_nest; + walk_ty(self, ty); + self.nest -= sub_nest; + } +} diff --git a/tests/compile-fail/complex_types.rs b/tests/compile-fail/complex_types.rs new file mode 100755 index 00000000000..995132ba88c --- /dev/null +++ b/tests/compile-fail/complex_types.rs @@ -0,0 +1,44 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy)] +#![allow(unused)] +#![feature(associated_consts, associated_type_defaults)] + +type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here + +const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type +static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type + +struct S { + f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, //~ERROR very complex type +} + +struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type + +enum E { + V1(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type + V2 { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type +} + +impl S { + const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type + fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type +} + +trait T { + const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type + type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type + fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type + fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type +} + +fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] } //~ERROR very complex type + +fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type + +fn test3() { + let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; //~ERROR very complex type +} + +fn main() { +} -- cgit 1.4.1-3-g733a5 From 1334f2ceaea5e012bba02b6afc0371bf92e976e7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 22 Aug 2015 13:01:54 +0530 Subject: Fix doubleborrow of refcell in consts.rs --- src/consts.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 70d5ff4bc17..e54ac77b599 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -330,8 +330,13 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { /// lookup a possibly constant expression from a ExprPath fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { if let Some(lcx) = self.lcx { + let mut maybe_id = None; if let Some(&PathResolution { base_def: DefConst(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) { + maybe_id = Some(id); + } + // separate if lets to avoid doubleborrowing the defmap + if let Some(id) = maybe_id { if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None) { let ret = self.expr(const_expr); if ret.is_some() { -- cgit 1.4.1-3-g733a5 From 1587256dc4651bbc53793fb461f1a22c6f65fc5c Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 22 Aug 2015 14:30:53 +0200 Subject: types: check for macros in type complexity check --- src/types.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 54c36535286..cd7a5dc3729 100644 --- a/src/types.rs +++ b/src/types.rs @@ -259,6 +259,7 @@ fn check_fndecl(cx: &Context, decl: &FnDecl) { } fn check_type(cx: &Context, ty: &ast::Ty) { + if in_external_macro(cx, ty.span) { return; } let score = { let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; visitor.visit_ty(ty); -- cgit 1.4.1-3-g733a5 From 5403e826818a3c669f476909b24b4470e6e3749c Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 19:32:21 +0200 Subject: matches: new module, move single_match lint there --- src/lib.rs | 5 +++-- src/matches.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/misc.rs | 63 +--------------------------------------------------------- 3 files changed, 65 insertions(+), 64 deletions(-) create mode 100644 src/matches.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index b0f46ae45ab..fbeebb210fe 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,11 +38,11 @@ pub mod returns; pub mod lifetimes; pub mod loops; pub mod ranges; +pub mod matches; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); - reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); reg.register_lint_pass(box misc::CmpNan as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); @@ -71,6 +71,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box ranges::StepByZero as LintPassObject); reg.register_lint_pass(box types::CastPass as LintPassObject); reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); + reg.register_lint_pass(box matches::MatchPass as LintPassObject); reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, @@ -87,6 +88,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, + matches::SINGLE_MATCH, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::STR_TO_STRING, @@ -96,7 +98,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::FLOAT_CMP, misc::MODULO_ONE, misc::PRECEDENCE, - misc::SINGLE_MATCH, misc::TOPLEVEL_REF_ARG, mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, diff --git a/src/matches.rs b/src/matches.rs new file mode 100644 index 00000000000..b9f6cbc4326 --- /dev/null +++ b/src/matches.rs @@ -0,0 +1,61 @@ +use rustc::lint::*; +use syntax::ast; +use syntax::ast::*; +use std::borrow::Cow; + +use utils::{snippet, snippet_block, span_help_and_lint}; + +declare_lint!(pub SINGLE_MATCH, Warn, + "a match statement with a single nontrivial arm (i.e, where the other arm \ + is `_ => {}`) is used; recommends `if let` instead"); + +#[allow(missing_copy_implementations)] +pub struct MatchPass; + +impl LintPass for MatchPass { + fn get_lints(&self) -> LintArray { + lint_array!(SINGLE_MATCH) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { + // check preconditions: only two arms + if arms.len() == 2 && + // both of the arms have a single pattern and no guard + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + // and the second pattern is a `_` wildcard: this is not strictly necessary, + // since the exhaustiveness check will ensure the last one is a catch-all, + // but in some cases, an explicit match is preferred to catch situations + // when an enum is extended, so we don't consider these cases + arms[1].pats[0].node == PatWild(PatWildSingle) && + // finally, we don't want any content in the second arm (unit or empty block) + is_unit_expr(&*arms[1].body) + { + let body_code = snippet_block(cx, arms[0].body.span, ".."); + let body_code = if let ExprBlock(_) = arms[0].body.node { + body_code + } else { + Cow::Owned(format!("{{ {} }}", body_code)) + }; + span_help_and_lint(cx, SINGLE_MATCH, expr.span, + "you seem to be trying to use match for \ + destructuring a single pattern. Did you mean to \ + use `if let`?", + &*format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + body_code) + ); + } + } + } +} + +fn is_unit_expr(expr: &Expr) -> bool { + match expr.node { + ExprTup(ref v) if v.is_empty() => true, + ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true, + _ => false, + } +} diff --git a/src/misc.rs b/src/misc.rs index aca849931bb..49324de8de9 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,75 +1,14 @@ use rustc::lint::*; use syntax::ptr::P; -use syntax::ast; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; use rustc::middle::ty; -use std::borrow::Cow; -use utils::{match_path, snippet, snippet_block, span_lint, span_help_and_lint, walk_ptrs_ty}; +use utils::{match_path, snippet, span_lint, walk_ptrs_ty}; use consts::constant; -/// Handles uncategorized lints -/// Currently handles linting of if-let-able matches -#[allow(missing_copy_implementations)] -pub struct MiscPass; - - -declare_lint!(pub SINGLE_MATCH, Warn, - "a match statement with a single nontrivial arm (i.e, where the other arm \ - is `_ => {}`) is used; recommends `if let` instead"); - -impl LintPass for MiscPass { - fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { - // check preconditions: only two arms - if arms.len() == 2 && - // both of the arms have a single pattern and no guard - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() && - // and the second pattern is a `_` wildcard: this is not strictly necessary, - // since the exhaustiveness check will ensure the last one is a catch-all, - // but in some cases, an explicit match is preferred to catch situations - // when an enum is extended, so we don't consider these cases - arms[1].pats[0].node == PatWild(PatWildSingle) && - // finally, we don't want any content in the second arm (unit or empty block) - is_unit_expr(&*arms[1].body) - { - let body_code = snippet_block(cx, arms[0].body.span, ".."); - let body_code = if let ExprBlock(_) = arms[0].body.node { - body_code - } else { - Cow::Owned(format!("{{ {} }}", body_code)) - }; - span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for \ - destructuring a single pattern. Did you mean to \ - use `if let`?", - &*format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - body_code) - ); - } - } - } -} - -fn is_unit_expr(expr: &Expr) -> bool { - match expr.node { - ExprTup(ref v) if v.is_empty() => true, - ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true, - _ => false, - } -} - - declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not \ `fn foo((ref x, ref y): (u8, u8))`)"); -- cgit 1.4.1-3-g733a5 From 017dac23017e2dcf8fe350b66821a9e50d39bbd1 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 19:49:00 +0200 Subject: new lint: using &Ref patterns instead of matching on *expr (fixes #187) --- README.md | 1 + src/lib.rs | 1 + src/matches.rs | 30 +++++++++++++++++-- tests/compile-fail/match_if_let.rs | 38 ------------------------ tests/compile-fail/matches.rs | 59 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 41 deletions(-) delete mode 100755 tests/compile-fail/match_if_let.rs create mode 100755 tests/compile-fail/matches.rs (limited to 'src') diff --git a/README.md b/README.md index 55976104058..72ce27392a7 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ len_zero | warn | checking `.len() == 0` or `.len() > 0` (or let_and_return | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function let_unit_value | warn | creating a let binding to a value of unit type, which usually can't be used afterwards linkedlist | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +match_ref_pats | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead modulo_one | warn | taking a number modulo 1, which always returns 0 mut_mut | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) needless_bool | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` diff --git a/src/lib.rs b/src/lib.rs index fbeebb210fe..26af063c9a5 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, + matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/src/matches.rs b/src/matches.rs index b9f6cbc4326..b704a2b47bb 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -3,23 +3,27 @@ use syntax::ast; use syntax::ast::*; use std::borrow::Cow; -use utils::{snippet, snippet_block, span_help_and_lint}; +use utils::{snippet, snippet_block, span_lint, span_help_and_lint}; declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ is `_ => {}`) is used; recommends `if let` instead"); +declare_lint!(pub MATCH_REF_PATS, Warn, + "a match has all arms prefixed with `&`; the match expression can be \ + dereferenced instead"); #[allow(missing_copy_implementations)] pub struct MatchPass; impl LintPass for MatchPass { fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH) + lint_array!(SINGLE_MATCH, MATCH_REF_PATS) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { - // check preconditions: only two arms + // check preconditions for SINGLE_MATCH + // only two arms if arms.len() == 2 && // both of the arms have a single pattern and no guard arms[0].pats.len() == 1 && arms[0].guard.is_none() && @@ -48,6 +52,13 @@ impl LintPass for MatchPass { body_code) ); } + + // check preconditions for MATCH_REF_PATS + if has_only_ref_pats(arms) { + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "instead of prefixing all patterns with `&`, you can dereference the \ + expression to match: `match *{} {{ ...`", snippet(cx, ex.span, ".."))); + } } } } @@ -59,3 +70,16 @@ fn is_unit_expr(expr: &Expr) -> bool { _ => false, } } + +fn has_only_ref_pats(arms: &[Arm]) -> bool { + for arm in arms { + for pat in &arm.pats { + match pat.node { + PatRegion(..) => (), // &-patterns + PatWild(..) => (), // an "anything" wildcard is also fine + _ => return false, + } + } + } + true +} diff --git a/tests/compile-fail/match_if_let.rs b/tests/compile-fail/match_if_let.rs deleted file mode 100755 index bf2e7e43a52..00000000000 --- a/tests/compile-fail/match_if_let.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![feature(plugin)] - -#![plugin(clippy)] -#![deny(clippy)] - -fn main(){ - let x = Some(1u8); - match x { //~ ERROR you seem to be trying to use match - //~^ HELP try - Some(y) => { - println!("{:?}", y); - } - _ => () - } - // Not linted - match x { - Some(y) => println!("{:?}", y), - None => () - } - let z = (1u8,1u8); - match z { //~ ERROR you seem to be trying to use match - //~^ HELP try - (2...3, 7...9) => println!("{:?}", z), - _ => {} - } - - // Not linted (pattern guards used) - match x { - Some(y) if y == 0 => println!("{:?}", y), - _ => () - } - - // Not linted (content in the else) - match z { - (2...3, 7...9) => println!("{:?}", z), - _ => println!("nope"), - } -} diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs new file mode 100755 index 00000000000..43cf43b68df --- /dev/null +++ b/tests/compile-fail/matches.rs @@ -0,0 +1,59 @@ +#![feature(plugin)] + +#![plugin(clippy)] +#![deny(clippy)] +#![allow(unused)] + +fn single_match(){ + let x = Some(1u8); + match x { //~ ERROR you seem to be trying to use match + //~^ HELP try + Some(y) => { + println!("{:?}", y); + } + _ => () + } + // Not linted + match x { + Some(y) => println!("{:?}", y), + None => () + } + let z = (1u8,1u8); + match z { //~ ERROR you seem to be trying to use match + //~^ HELP try + (2...3, 7...9) => println!("{:?}", z), + _ => {} + } + + // Not linted (pattern guards used) + match x { + Some(y) if y == 0 => println!("{:?}", y), + _ => () + } + + // Not linted (content in the else) + match z { + (2...3, 7...9) => println!("{:?}", z), + _ => println!("nope"), + } +} + +fn ref_pats() { + let ref v = Some(0); + match v { //~ERROR instead of prefixing all patterns with `&` + &Some(v) => println!("{:?}", v), + &None => println!("none"), + } + match v { // this doesn't trigger, we have a different pattern + &Some(v) => println!("some"), + other => println!("other"), + } + let ref tup = (1, 2); + match tup { //~ERROR instead of prefixing all patterns with `&` + &(v, 1) => println!("{}", v), + _ => println!("none"), + } +} + +fn main() { +} -- cgit 1.4.1-3-g733a5 From 8f1a2374938d77e3ecb713d57241d8209578ed0d Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 20:44:48 +0200 Subject: &-matches: dogfood fixes! --- src/approx_const.rs | 8 ++++---- src/bit_mask.rs | 12 ++++++------ src/eta_reduction.rs | 6 +++--- src/len_zero.rs | 8 ++++---- src/misc.rs | 6 +++--- src/needless_bool.rs | 6 +++--- src/strings.rs | 8 ++++---- src/types.rs | 16 ++++++++-------- 8 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index cfd646765c9..3e0ba4eb669 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -37,10 +37,10 @@ impl LintPass for ApproxConstant { } fn check_lit(cx: &Context, lit: &Lit, span: Span) { - match &lit.node { - &LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), - &LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), - &LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), + match lit.node { + LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), + LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), + LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), _ => () } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 7789381da23..6537fcf4c1a 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -82,9 +82,9 @@ fn invert_cmp(cmp : BinOp_) -> BinOp_ { fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { - match &bit_op.node { - &ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), - &ExprBinary(ref op, ref left, ref right) => { + match bit_op.node { + ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), + ExprBinary(ref op, ref left, ref right) => { if op.node != BiBitAnd && op.node != BiBitOr { return; } fetch_int_literal(cx, right).or_else(|| fetch_int_literal( cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, @@ -182,13 +182,13 @@ fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { } fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> { - match &lit.node { - &ExprLit(ref lit_ptr) => { + match lit.node { + ExprLit(ref lit_ptr) => { if let &LitInt(value, _) = &lit_ptr.node { Option::Some(value) //TODO: Handle sign } else { Option::None } }, - &ExprPath(_, _) => { + ExprPath(_, _) => { // Important to let the borrow expire before the const lookup to avoid double // borrowing. let def_map = cx.tcx.def_map.borrow(); diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 6712e787278..25e967b07e5 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -18,9 +18,9 @@ impl LintPass for EtaPass { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - match &expr.node { - &ExprCall(_, ref args) | - &ExprMethodCall(_, _, ref args) => { + match expr.node { + ExprCall(_, ref args) | + ExprMethodCall(_, _, ref args) => { for arg in args { check_closure(cx, &*arg) } diff --git a/src/len_zero.rs b/src/len_zero.rs index 073dcea582d..5eaa0256402 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -22,10 +22,10 @@ impl LintPass for LenZero { } fn check_item(&mut self, cx: &Context, item: &Item) { - match &item.node { - &ItemTrait(_, _, _, ref trait_items) => + match item.node { + ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), - &ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait + ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait check_impl_items(cx, item, impl_items), _ => () } @@ -100,7 +100,7 @@ fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, op: &str) { - if let &Spanned{node: LitInt(0, _), ..} = lit { + if let Spanned{node: LitInt(0, _), ..} = *lit { if method.node.name == "len" && args.len() == 1 && has_is_empty(cx, &*args[0]) { span_lint(cx, LEN_ZERO, span, &format!( diff --git a/src/misc.rs b/src/misc.rs index 49324de8de9..81b03db5e14 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -175,8 +175,8 @@ impl LintPass for CmpOwned { } fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { - match &expr.node { - &ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { + match expr.node { + ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { let name = ident.name; if name == "to_string" || name == "to_owned" && is_str_arg(cx, args) { @@ -186,7 +186,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { snippet(cx, other_span, ".."))) } }, - &ExprCall(ref path, _) => { + ExprCall(ref path, _) => { if let &ExprPath(None, ref path) = &path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 18d98f1f063..7671d63a35d 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -60,9 +60,9 @@ fn fetch_bool_block(block: &Block) -> Option<bool> { } fn fetch_bool_expr(expr: &Expr) -> Option<bool> { - match &expr.node { - &ExprBlock(ref block) => fetch_bool_block(block), - &ExprLit(ref lit_ptr) => if let &LitBool(value) = &lit_ptr.node { + match expr.node { + ExprBlock(ref block) => fetch_bool_block(block), + ExprLit(ref lit_ptr) => if let LitBool(value) = lit_ptr.node { Some(value) } else { None }, _ => None } diff --git a/src/strings.rs b/src/strings.rs index 64d18eeb26d..b24ea345244 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -65,13 +65,13 @@ fn is_string(cx: &Context, e: &Expr) -> bool { } fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { - match &src.node { - &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => + match src.node { + ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left), - &ExprBlock(ref block) => block.stmts.is_empty() && + ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, &*expr, target)), - &ExprParen(ref expr) => is_add(cx, &*expr, target), + ExprParen(ref expr) => is_add(cx, &*expr, target), _ => false } } diff --git a/src/types.rs b/src/types.rs index 54c36535286..cb85fd6e0c6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -116,10 +116,10 @@ declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: &ty::TyS) -> usize { - let n = match &typ.sty { - &ty::TyInt(i) => 4 << (i as usize), - &ty::TyUint(u) => 4 << (u as usize), - _ => 0 + let n = match typ.sty { + ty::TyInt(i) => 4 << (i as usize), + ty::TyUint(u) => 4 << (u as usize), + _ => 0 }; // n == 4 is the usize/isize case if n == 4 { ::std::usize::BITS } else { n } @@ -139,16 +139,16 @@ impl LintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits : usize = match &cast_to.sty { - &ty::TyFloat(ast::TyF32) => 32, - &ty::TyFloat(ast::TyF64) => 64, + let to_nbits : usize = match cast_to.sty { + ty::TyFloat(ast::TyF32) => 32, + ty::TyFloat(ast::TyF64) => 64, _ => 0 }; if from_nbits != 0 { if from_nbits >= to_nbits { span_lint(cx, CAST_PRECISION_LOSS, expr.span, &format!("converting from {0} to {1}, which causes a loss of precision \ - ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", + ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", cast_from, cast_to, from_nbits, if to_nbits == 64 {52} else {23} )); } } -- cgit 1.4.1-3-g733a5 From 7580da306e338089b1cffedb09a71cb11debddf5 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 21 Aug 2015 20:49:59 +0200 Subject: matches: special message for this case match &e { &Pat1 => {}, &Pat2 => {}, ... } (inspired by dogfood fixes) --- src/matches.rs | 27 ++++++++++++++------------- tests/compile-fail/matches.rs | 6 ++++++ 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index b704a2b47bb..002da07f50b 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -55,9 +55,15 @@ impl LintPass for MatchPass { // check preconditions for MATCH_REF_PATS if has_only_ref_pats(arms) { - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "instead of prefixing all patterns with `&`, you can dereference the \ - expression to match: `match *{} {{ ...`", snippet(cx, ex.span, ".."))); + if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "you don't need to add `&` to both the expression to match \ + and the patterns: use `match {} {{ ...`", snippet(cx, inner.span, ".."))); + } else { + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "instead of prefixing all patterns with `&`, you can dereference the \ + expression to match: `match *{} {{ ...`", snippet(cx, ex.span, ".."))); + } } } } @@ -72,14 +78,9 @@ fn is_unit_expr(expr: &Expr) -> bool { } fn has_only_ref_pats(arms: &[Arm]) -> bool { - for arm in arms { - for pat in &arm.pats { - match pat.node { - PatRegion(..) => (), // &-patterns - PatWild(..) => (), // an "anything" wildcard is also fine - _ => return false, - } - } - } - true + arms.iter().flat_map(|a| &a.pats).all(|p| match p.node { + PatRegion(..) => true, // &-patterns + PatWild(..) => true, // an "anything" wildcard is also fine + _ => false, + }) } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 43cf43b68df..3cc540992c9 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -53,6 +53,12 @@ fn ref_pats() { &(v, 1) => println!("{}", v), _ => println!("none"), } + // special case: using & both in expr and pats + let w = Some(0); + match &w { //~ERROR you don't need to add `&` to both + &Some(v) => println!("{:?}", v), + &None => println!("none"), + } } fn main() { -- cgit 1.4.1-3-g733a5 From 79ef13592e617e58b84146ba568c43bad81e77bf Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Sat, 22 Aug 2015 23:49:03 +0200 Subject: Completed the implementation of *size handling. Added some more cases to the test, and implemented a new lint, cast_possible_wrap, triggered when casting from an unsigned type to a signed type of the same size. --- README.md | 1 + src/lib.rs | 1 + src/types.rs | 86 +++++++++++++++++++++++++++++++++++----------- tests/compile-fail/cast.rs | 8 ++++- 4 files changed, 75 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index fbb16fcb170..7ac5388e0fe 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ approx_constant | warn | the approximate of a known float constant ( bad_bit_mask | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) box_vec | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap cast_possible_truncation | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +cast_possible_wrap | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` cast_precision_loss | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` cast_sign_loss | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` cmp_nan | deny | comparisons to NAN (which will always return false, which is probably not intended) diff --git a/src/lib.rs b/src/lib.rs index 9ea1efeed5f..19a62dd214b 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,6 +107,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_ADD_ASSIGN, types::BOX_VEC, types::CAST_POSSIBLE_TRUNCATION, + types::CAST_POSSIBLE_WRAP, types::CAST_PRECISION_LOSS, types::CAST_SIGN_LOSS, types::LET_UNIT_VALUE, diff --git a/src/types.rs b/src/types.rs index e8da11ecbe0..579527cfff4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -145,6 +145,8 @@ declare_lint!(pub CAST_SIGN_LOSS, Allow, "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"); declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); +declare_lint!(pub CAST_POSSIBLE_WRAP, Allow, + "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`"); /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant @@ -169,7 +171,8 @@ impl LintPass for CastPass { fn get_lints(&self) -> LintArray { lint_array!(CAST_PRECISION_LOSS, CAST_SIGN_LOSS, - CAST_POSSIBLE_TRUNCATION) + CAST_POSSIBLE_TRUNCATION, + CAST_POSSIBLE_WRAP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -186,50 +189,93 @@ impl LintPass for CastPass { }; if from_nbits != 0 { // When casting to f32, precision loss would occur regardless of the arch - if is_isize_or_usize(cast_from) && to_nbits == 64 { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("converting from {0} to f64, which causes a loss of precision on 64-bit architectures \ - ({0} is 64 bits wide, but f64's mantissa is only 52 bits wide)", - cast_from)); + if is_isize_or_usize(cast_from) { + if to_nbits == 64 { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("casting {0} to f64 causes a loss of precision on targets with 64-bit wide pointers \ + ({0} is 64 bits wide, but f64's mantissa is only 52 bits wide)", + cast_from)); + } + else { + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &format!("casting {0} to f32 causes a loss of precision \ + ({0} is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)", + cast_from)); + } } else if from_nbits >= to_nbits { span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("converting from {0} to {1}, which causes a loss of precision \ + &format!("casting {0} to {1} causes a loss of precision \ ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", cast_from, cast_to, from_nbits, if to_nbits == 64 {52} else {23} )); } } }, - (false, true) => { // Nothing to add there + (false, true) => { + // Nothing to add there as long as UB in involved when the cast overflows span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); + &format!("casting {} to {} may truncate the value", cast_from, cast_to)); if !cast_to.is_signed() { span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); + &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); } }, (true, true) => { + let from_nbits = int_ty_to_nbits(cast_from); + let to_nbits = int_ty_to_nbits(cast_to); if cast_from.is_signed() && !cast_to.is_signed() { span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to)); + &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); } - let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = int_ty_to_nbits(cast_to); match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { (true, true) | (false, false) => - if to_nbits < from_nbits || - (!cast_from.is_signed() && cast_to.is_signed() && to_nbits <= from_nbits) { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may cause truncation of the value", cast_from, cast_to)); + if to_nbits < from_nbits { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value", cast_from, cast_to)); + } + else if !cast_from.is_signed() && cast_to.is_signed() && to_nbits == from_nbits { + span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value", cast_from, cast_to)); + }, + (true, false) => + if to_nbits == 32 { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value on targets with 64-bit wide pointers", + cast_from, cast_to)); + if !cast_from.is_signed() && cast_to.is_signed() { + span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value on targets with 32-bit wide pointers", + cast_from, cast_to)); + } + } + else if to_nbits < 32 { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value", cast_from, cast_to)); }, - (true, false) => (), // TODO - (false, true) => () // TODO + (false, true) => + if from_nbits == 64 { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value on targets with 32-bit wide pointers", + cast_from, cast_to)); + if !cast_from.is_signed() && cast_to.is_signed() { + span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value on targets with 64-bit wide pointers", + cast_from, cast_to)); + } + } + else { + if !cast_from.is_signed() && cast_to.is_signed() { + span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value on targets with 32-bit wide pointers", + cast_from, cast_to)); + } + } } } (false, false) => { if let (&ty::TyFloat(ast::TyF64), &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may cause truncation of the value"); + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may truncate the value"); } } } diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index 9be0d501198..b17f5de841b 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -45,8 +45,10 @@ fn main() { 1usize as f32; //~ERROR casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) 1isize as i32; //~ERROR casting isize to i32 may truncate the value on targets with 64-bit wide pointers 1isize as u32; //~ERROR casting isize to u32 may lose the sign of the value - //~^ERROR casting isize to u32 may truncate the value on targets with 64-bit wide pointers + //~^ERROR casting isize to u32 may truncate the value on targets with 64-bit wide pointers 1usize as u32; //~ERROR casting usize to u32 may truncate the value on targets with 64-bit wide pointers + 1usize as i32; //~ERROR casting usize to i32 may truncate the value on targets with 64-bit wide pointers + //~^ERROR casting usize to i32 may wrap around the value on targets with 32-bit wide pointers // Casting to *size 1i64 as isize; //~ERROR casting i64 to isize may truncate the value on targets with 32-bit wide pointers 1i64 as usize; //~ERROR casting i64 to usize may truncate the value on targets with 32-bit wide pointers @@ -54,4 +56,8 @@ fn main() { 1u64 as isize; //~ERROR casting u64 to isize may truncate the value on targets with 32-bit wide pointers //~^ERROR casting u64 to isize may wrap around the value on targets with 64-bit wide pointers 1u64 as usize; //~ERROR casting u64 to usize may truncate the value on targets with 32-bit wide pointers + 1u32 as isize; //~ERROR casting u32 to isize may wrap around the value on targets with 32-bit wide pointers + 1u32 as usize; // Should not trigger any lint + 1i32 as isize; // Neither should this + 1i32 as usize; //~ERROR casting i32 to usize may lose the sign of the value } \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 3af2e3ba857630214d9bc81756be1c07ae305fc4 Mon Sep 17 00:00:00 2001 From: "R.Chavignat" <r.chavignat@gmail.com> Date: Sun, 23 Aug 2015 01:06:31 +0200 Subject: Refactored CastPass. --- src/types.rs | 143 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 47ee51e98ef..4e9dd133ac8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -134,6 +134,72 @@ fn is_isize_or_usize(typ: &ty::TyS) -> bool { } } +fn span_precision_loss_lint(cx: &Context, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: bool) { + let mantissa_nbits = if cast_to_f64 {52} else {23}; + let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; + let arch_dependent_str = "on targets with 64-bit wide pointers "; + let from_nbits_str = if arch_dependent {"64".to_owned()} + else if is_isize_or_usize(cast_from) {"32 or 64".to_owned()} + else {int_ty_to_nbits(cast_from).to_string()}; + span_lint(cx, CAST_PRECISION_LOSS, expr.span, + &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 arch_dependent {arch_dependent_str} else {""}, + from_nbits_str, + mantissa_nbits)); +} + +enum ArchSuffix { + _32, _64, None +} + +fn check_truncation_and_wrapping(cx: &Context, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { + let arch_64_suffix = " on targets with 64-bit wide pointers"; + let arch_32_suffix = " on targets with 32-bit wide pointers"; + let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); + let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to)); + let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = + match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => ( + to_nbits < from_nbits, + 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}, + 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} + ), + }; + if span_truncation { + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value{}", + cast_from, cast_to, + match suffix_truncation { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "" })); + } + if span_wrap { + span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value{}", + cast_from, cast_to, + match suffix_wrap { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "" })); + } +} + impl LintPass for CastPass { fn get_lints(&self) -> LintArray { lint_array!(CAST_PRECISION_LOSS, @@ -149,33 +215,9 @@ impl LintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits : usize = match cast_to.sty { - ty::TyFloat(ast::TyF32) => 32, - ty::TyFloat(ast::TyF64) => 64, - _ => 0 - }; - if from_nbits != 0 { - // When casting to f32, precision loss would occur regardless of the arch - if is_isize_or_usize(cast_from) { - if to_nbits == 64 { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("casting {0} to f64 causes a loss of precision on targets with 64-bit wide pointers \ - ({0} is 64 bits wide, but f64's mantissa is only 52 bits wide)", - cast_from)); - } - else { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("casting {0} to f32 causes a loss of precision \ - ({0} is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)", - cast_from)); - } - } - else if from_nbits >= to_nbits { - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &format!("casting {0} to {1} causes a loss of precision \ - ({0} is {2} bits wide, but {1}'s mantissa is only {3} bits wide)", - cast_from, cast_to, from_nbits, if to_nbits == 64 {52} else {23} )); - } + let to_nbits = if let ty::TyFloat(ast::TyF32) = cast_to.sty {32} else {64}; + if is_isize_or_usize(cast_from) || from_nbits >= to_nbits { + span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64); } }, (false, true) => { @@ -187,56 +229,11 @@ impl LintPass for CastPass { } }, (true, true) => { - let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = int_ty_to_nbits(cast_to); if cast_from.is_signed() && !cast_to.is_signed() { span_lint(cx, CAST_SIGN_LOSS, expr.span, &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); } - match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => - if to_nbits < from_nbits { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value", cast_from, cast_to)); - } - else if !cast_from.is_signed() && cast_to.is_signed() && to_nbits == from_nbits { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value", cast_from, cast_to)); - }, - (true, false) => - if to_nbits == 32 { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value on targets with 64-bit wide pointers", - cast_from, cast_to)); - if !cast_from.is_signed() && cast_to.is_signed() { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value on targets with 32-bit wide pointers", - cast_from, cast_to)); - } - } - else if to_nbits < 32 { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value", cast_from, cast_to)); - }, - (false, true) => - if from_nbits == 64 { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value on targets with 32-bit wide pointers", - cast_from, cast_to)); - if !cast_from.is_signed() && cast_to.is_signed() { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value on targets with 64-bit wide pointers", - cast_from, cast_to)); - } - } - else { - if !cast_from.is_signed() && cast_to.is_signed() { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value on targets with 32-bit wide pointers", - cast_from, cast_to)); - } - } - } + check_truncation_and_wrapping(cx, expr, cast_from, cast_to); } (false, false) => { if let (&ty::TyFloat(ast::TyF64), -- cgit 1.4.1-3-g733a5 From c8a2e848ab249758f79ca048a5b06b8fef56cd87 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 23 Aug 2015 16:32:50 +0200 Subject: utils: extract utility method for matching trait method calls from loops --- src/loops.rs | 17 +++++------------ src/utils.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 36bab550b67..5f18439eafe 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,10 +1,9 @@ use rustc::lint::*; use syntax::ast::*; use syntax::visit::{Visitor, walk_expr}; -use rustc::middle::ty; use std::collections::HashSet; -use utils::{snippet, span_lint, get_parent_expr, match_def_path}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, "for-looping over a range of indices where an iterator over items would do" } @@ -68,16 +67,10 @@ impl LintPass for LoopsPass { object, object)); // check for looping over Iterator::next() which is not what you want } else if method_name == "next" { - let method_call = ty::MethodCall::expr(arg.id); - let trt_id = cx.tcx.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 { - if match_def_path(cx, trt_id, &["core", "iter", "Iterator"]) { - span_lint(cx, ITER_NEXT_LOOP, expr.span, - "you are iterating over `Iterator::next()` which is an Option; \ - this will compile but is probably not what you want"); - } + if match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + span_lint(cx, ITER_NEXT_LOOP, expr.span, + "you are iterating over `Iterator::next()` which is an Option; \ + this will compile but is probably not what you want"); } } } diff --git a/src/utils.rs b/src/utils.rs index 4fd36fb91d4..5e7c63e85d9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -56,6 +56,19 @@ pub fn match_type(cx: &Context, ty: ty::Ty, path: &[&str]) -> bool { } } +/// check if method call given in "expr" belongs to given trait +pub fn match_trait_method(cx: &Context, 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)); + if let Some(trt_id) = trt_id { + match_def_path(cx, trt_id, path) + } else { + false + } +} + /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { -- cgit 1.4.1-3-g733a5 From cc8f33d9152c38ca59cb79ccb89aca70fb3a7420 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 23 Aug 2015 16:34:23 +0200 Subject: ranges: remove unneeded as_str() --- src/ranges.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ranges.rs b/src/ranges.rs index d1a0a7e702e..914b4daa6be 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -20,7 +20,7 @@ impl LintPass for StepByZero { if let ExprMethodCall(Spanned { node: ref ident, .. }, _, ref args) = expr.node { // Only warn on literal ranges. - if ident.name.as_str() == "step_by" && args.len() == 2 && + if ident.name == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && is_lit_zero(&args[1]) { cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, "Range::step_by(0) produces an infinite iterator. \ -- cgit 1.4.1-3-g733a5 From 209e6981a3ec67ddc8d94cb46d876550948f6238 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 17:11:34 +0200 Subject: shadowing detection --- README.md | 5 +- src/lib.rs | 11 ++ src/returns.rs | 2 +- src/shadow.rs | 224 +++++++++++++++++++++++++++++++++++++ src/utils.rs | 6 +- tests/compile-fail/approx_const.rs | 2 +- tests/compile-fail/shadow.rs | 22 ++++ 7 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 src/shadow.rs create mode 100644 tests/compile-fail/shadow.rs (limited to 'src') diff --git a/README.md b/README.md index be7154c8c62..71ca256fb9a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 45 lints included in this crate: +There are 48 lints included in this crate: name | default | meaning -------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -44,6 +44,9 @@ ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&S range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled +shadow_foreign | warn | The name is re-bound without even using the original value +shadow_reuse | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` +shadow_same | allow | rebinding a name to itself, e.g. `let mut x = &mut x` single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead diff --git a/src/lib.rs b/src/lib.rs index 863ba2624dd..e65311133d2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod len_zero; pub mod attrs; pub mod collapsible_if; pub mod unicode; +pub mod shadow; pub mod strings; pub mod methods; pub mod returns; @@ -64,6 +65,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box strings::StringAdd as LintPassObject); reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); + reg.register_lint_pass(box shadow::ShadowPass as LintPassObject); reg.register_lint_pass(box types::LetPass as LintPassObject); reg.register_lint_pass(box types::UnitCmp as LintPassObject); reg.register_lint_pass(box loops::LoopsPass as LintPassObject); @@ -73,6 +75,12 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); reg.register_lint_pass(box matches::MatchPass as LintPassObject); + reg.register_lint_group("shadow", vec![ + shadow::SHADOW_FOREIGN, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, + ]); + reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, attrs::INLINE_ALWAYS, @@ -106,6 +114,9 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, + shadow::SHADOW_FOREIGN, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::BOX_VEC, diff --git a/src/returns.rs b/src/returns.rs index df0b93f301e..a5779984334 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -11,7 +11,7 @@ declare_lint!(pub LET_AND_RETURN, Warn, "creating a let-binding and then immediately returning it like `let x = expr; x` at \ the end of a function"); -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct ReturnPass; impl ReturnPass { diff --git a/src/shadow.rs b/src/shadow.rs new file mode 100644 index 00000000000..bae05c17d7b --- /dev/null +++ b/src/shadow.rs @@ -0,0 +1,224 @@ +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::visit::FnKind; + +use rustc::lint::{Context, LintArray, LintPass}; +use utils::{in_external_macro, snippet, span_lint}; + +declare_lint!(pub SHADOW_SAME, Allow, + "rebinding a name to itself, e.g. `let mut x = &mut x`"); +declare_lint!(pub SHADOW_REUSE, Allow, + "rebinding a name to an expression that re-uses the original value, e.g. \ + `let x = x + 1`"); +declare_lint!(pub SHADOW_FOREIGN, Warn, + "The name is re-bound without even using the original value"); + +#[derive(Copy, Clone)] +pub struct ShadowPass; + +impl LintPass for ShadowPass { + fn get_lints(&self) -> LintArray { + lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_FOREIGN) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, + block: &Block, _: Span, _: NodeId) { + if in_external_macro(cx, block.span) { return; } + check_fn(cx, decl, block); + } +} + +fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) { + let mut bindings = Vec::new(); + for arg in &decl.inputs { + if let PatIdent(_, ident, _) = arg.pat.node { + bindings.push(ident.node.name) + } + } + check_block(cx, block, &mut bindings); +} + +fn named(pat: &Pat) -> Option<Name> { + if let PatIdent(_, ident, _) = pat.node { + Some(ident.node.name) + } else { None } +} + +fn add(bindings: &mut Vec<Name>, pat: &Pat) { + named(pat).map(|name| bindings.push(name)); +} + +fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { + let len = bindings.len(); + for stmt in &block.stmts { + match stmt.node { + StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), + StmtExpr(ref e, _) | StmtSemi(ref e, _) => + check_expr(cx, e, bindings), + _ => () + } + } + if let Some(ref o) = block.expr { check_expr(cx, o, bindings); } + bindings.truncate(len); +} + +fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { + if in_external_macro(cx, decl.span) { return; } + if let DeclLocal(ref local) = decl.node { + let Local{ ref pat, ref ty, ref init, id: _, span: _ } = **local; + if let &Some(ref t) = ty { check_ty(cx, t, bindings); } + named(pat).map(|name| if bindings.contains(&name) { + if let &Some(ref o) = init { + if in_external_macro(cx, o.span) { return; } + check_expr(cx, o, bindings); + bindings.push(name); + lint_shadow(cx, name, decl.span, pat.span, o); + } + }); + add(bindings, pat); + if let &Some(ref o) = init { + check_expr(cx, o, bindings) + } + } +} + +fn lint_shadow(cx: &Context, name: Name, span: Span, lspan: Span, init: &Expr) { + if is_self_shadow(name, init) { + span_lint(cx, SHADOW_SAME, span, &format!( + "{} is shadowed by itself in {}", + snippet(cx, lspan, "_"), + snippet(cx, init.span, ".."))); + } else { + if contains_self(name, init) { + span_lint(cx, SHADOW_REUSE, span, &format!( + "{} is shadowed by {} which reuses the original value", + snippet(cx, lspan, "_"), + snippet(cx, init.span, ".."))); + } else { + span_lint(cx, SHADOW_FOREIGN, span, &format!( + "{} is shadowed by {} in this declaration", + snippet(cx, lspan, "_"), + snippet(cx, init.span, ".."))); + } + } +} + +fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { + if in_external_macro(cx, expr.span) { return; } + match expr.node { + ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | + ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e) + => { check_expr(cx, e, bindings) }, + ExprBox(Some(ref place), ref e) => { + check_expr(cx, place, bindings); check_expr(cx, e, bindings) } + ExprBlock(ref block) | ExprLoop(ref block, _) => + { check_block(cx, block, bindings) }, + ExprVec(ref v) | ExprTup(ref v) => + for ref 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); } + }, + ExprIfLet(ref pat, ref e, ref block, ref otherwise) => { + check_expr(cx, e, bindings); + let len = bindings.len(); + add(bindings, pat); + check_block(cx, block, bindings); + if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); } + bindings.truncate(len); + }, + ExprWhile(ref cond, ref block, _) => { + check_expr(cx, cond, bindings); + check_block(cx, block, bindings); + }, + ExprWhileLet(ref pat, ref e, ref block, _) | + ExprForLoop(ref pat, ref e, ref block, _) => { + check_expr(cx, e, bindings); + let len = bindings.len(); + add(bindings, pat); + check_block(cx, block, bindings); + bindings.truncate(len); + }, + _ => () + } +} + +fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) { + match ty.node { + TyParen(ref sty) | TyObjectSum(ref sty, _) | + TyVec(ref sty) => check_ty(cx, sty, bindings), + TyFixedLengthVec(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 ref t in tup { check_ty(cx, t, bindings) } }, + TyTypeof(ref expr) => check_expr(cx, expr, bindings), + _ => (), + } +} + +fn is_self_shadow(name: Name, expr: &Expr) -> bool { + match expr.node { + ExprBox(_, ref inner) | + ExprParen(ref inner) | + ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), + ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref(). + map_or(false, |ref e| is_self_shadow(name, e)), + ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) && + is_self_shadow(name, inner), + ExprPath(_, ref path) => path.segments.len() == 1 && + path.segments[0].identifier.name == name, + _ => false, + } +} + +fn contains_self(name: Name, expr: &Expr) -> bool { + match expr.node { + ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | + ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e) + => contains_self(name, e), + ExprBinary(_, ref l, ref r) => + contains_self(name, l) || contains_self(name, r), + ExprBlock(ref block) | ExprLoop(ref block, _) => + contains_block_self(name, block), + ExprCall(ref fun, ref args) => contains_self(name, fun) || + args.iter().any(|ref a| contains_self(name, a)), + ExprMethodCall(_, _, ref args) => + args.iter().any(|ref a| contains_self(name, a)), + ExprVec(ref v) | ExprTup(ref v) => + v.iter().any(|ref e| contains_self(name, e)), + ExprIf(ref cond, ref then, ref otherwise) => + contains_self(name, cond) || contains_block_self(name, then) || + otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)), + ExprIfLet(_, ref e, ref block, ref otherwise) => + contains_self(name, e) || contains_block_self(name, block) || + otherwise.as_ref().map_or(false, |ref o| contains_self(name, o)), + ExprWhile(ref e, ref block, _) | + ExprWhileLet(_, ref e, ref block, _) | + ExprForLoop(_, ref e, ref block, _) => + contains_self(name, e) || contains_block_self(name, block), + ExprPath(_, ref path) => path.segments.len() == 1 && + path.segments[0].identifier.name == name, + _ => false + } +} + +fn contains_block_self(name: Name, block: &Block) -> bool { + for stmt in &block.stmts { + match stmt.node { + StmtDecl(ref decl, _) => + if let DeclLocal(ref local) = decl.node { + if let Some(ref init) = local.init { + if contains_self(name, init) { return true; } + } + }, + StmtExpr(ref e, _) | StmtSemi(ref e, _) => + if contains_self(name, e) { return true }, + _ => () + } + } + if let Some(ref e) = block.expr { contains_self(name, e) } else { false } +} diff --git a/src/utils.rs b/src/utils.rs index 5e7c63e85d9..6cb21148356 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -94,9 +94,9 @@ pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, /// Trim indentation from a multiline string /// with possibility of ignoring the first line pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { - let s = trim_multiline_inner(s, ignore_first, ' '); - let s = trim_multiline_inner(s, ignore_first, '\t'); - trim_multiline_inner(s, ignore_first, ' ') + let s_space = trim_multiline_inner(s, ignore_first, ' '); + let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); + trim_multiline_inner(s_tab, ignore_first, ' ') } fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index 799795becbd..4c289b474f7 100755 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(approx_constant)] -#[allow(unused)] +#[allow(unused, shadow_foreign)] fn main() { let my_e = 2.7182; //~ERROR approximate value of `f{32, 64}::E` found let almost_e = 2.718; //~ERROR approximate value of `f{32, 64}::E` found diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs new file mode 100644 index 00000000000..e3213717213 --- /dev/null +++ b/tests/compile-fail/shadow.rs @@ -0,0 +1,22 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(unused_parens, unused_variables)] +#![deny(shadow)] + +fn id<T>(x: T) -> T { x } + +fn first(x: (isize, isize)) -> isize { x.0 } + +fn main() { + let mut x = 1; + let x = &mut x; //~ERROR: x is shadowed by itself in &mut x + let x = { x }; //~ERROR: x is shadowed by itself in { x } + let x = (&*x); //~ERROR: x is shadowed by itself in (&*x) + let x = { *x + 1 }; //~ERROR: x is shadowed by { *x + 1 } which reuses + let x = id(x); //~ERROR: x is shadowed by id(x) which reuses + let x = (1, x); //~ERROR: x is shadowed by (1, x) which reuses + let x = first(x); //~ERROR: x is shadowed by first(x) which reuses + let y = 1; + let x = y; //~ERROR: x is shadowed by y in this declaration +} -- cgit 1.4.1-3-g733a5 From 56e8db476c437590f21be041c0e751ee185d8dd0 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 24 Aug 2015 18:13:02 +0200 Subject: new lint: inherent methods that should be trait impls (fixes #218) --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 118 +++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/methods.rs | 23 +++++++- 4 files changed, 140 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index be7154c8c62..9d86ece99d6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 45 lints included in this crate: +There are 46 lints included in this crate: name | default | meaning -------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -44,6 +44,7 @@ ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&S range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled +should_implement_trait | warn | defining a method that should be implementing a std trait single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead diff --git a/src/lib.rs b/src/lib.rs index 863ba2624dd..bacff19addc 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,6 +92,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::SINGLE_MATCH, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, + methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, misc::CMP_NAN, diff --git a/src/methods.rs b/src/methods.rs index df8e35d98fb..73cf81fbdae 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -2,9 +2,12 @@ use syntax::ast::*; use rustc::lint::*; use rustc::middle::ty; -use utils::{span_lint, match_type, walk_ptrs_ty}; +use utils::{span_lint, match_path, match_type, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; +use self::SelfKind::*; +use self::OutType::*; + #[derive(Copy,Clone)] pub struct MethodsPass; @@ -16,10 +19,13 @@ declare_lint!(pub STR_TO_STRING, Warn, "using `to_string()` on a str, which should be `to_owned()`"); declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); +declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, + "defining a method that should be implementing a std trait"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING) + lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, + SHOULD_IMPLEMENT_TRAIT) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -46,4 +52,112 @@ impl LintPass for MethodsPass { } } } + + fn check_item(&mut self, cx: &Context, item: &Item) { + if let ItemImpl(_, _, _, None, _, ref items) = item.node { + for item in items { + let name = item.ident.name; + for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { + if_let_chain! { + [ + name == method_name, + let MethodImplItem(ref sig, _) = item.node, + sig.decl.inputs.len() == n_args, + out_type.matches(&sig.decl.output), + self_kind.matches(&sig.explicit_self.node) + ], { + span_lint(cx, SHOULD_IMPLEMENT_TRAIT, item.span, &format!( + "defining a method called `{}` on this type; consider implementing \ + the `{}` trait or choosing a less ambiguous name", name, trait_name)); + } + } + } + } + } + } +} + +const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ + ("add", 2, ValueSelf, AnyType, "std::ops::Add`"), + ("sub", 2, ValueSelf, AnyType, "std::ops::Sub"), + ("mul", 2, ValueSelf, AnyType, "std::ops::Mul"), + ("div", 2, ValueSelf, AnyType, "std::ops::Div"), + ("rem", 2, ValueSelf, AnyType, "std::ops::Rem"), + ("shl", 2, ValueSelf, AnyType, "std::ops::Shl"), + ("shr", 2, ValueSelf, AnyType, "std::ops::Shr"), + ("bitand", 2, ValueSelf, AnyType, "std::ops::BitAnd"), + ("bitor", 2, ValueSelf, AnyType, "std::ops::BitOr"), + ("bitxor", 2, ValueSelf, AnyType, "std::ops::BitXor"), + ("neg", 1, ValueSelf, AnyType, "std::ops::Neg"), + ("not", 1, ValueSelf, AnyType, "std::ops::Not"), + ("drop", 1, RefMutSelf, UnitType, "std::ops::Drop"), + ("index", 2, RefSelf, RefType, "std::ops::Index"), + ("index_mut", 2, RefMutSelf, RefType, "std::ops::IndexMut"), + ("deref", 1, RefSelf, RefType, "std::ops::Deref"), + ("deref_mut", 1, RefMutSelf, RefType, "std::ops::DerefMut"), + ("clone", 1, RefSelf, AnyType, "std::clone::Clone"), + ("borrow", 1, RefSelf, RefType, "std::borrow::Borrow"), + ("borrow_mut", 1, RefMutSelf, RefType, "std::borrow::BorrowMut"), + ("as_ref", 1, RefSelf, RefType, "std::convert::AsRef"), + ("as_mut", 1, RefMutSelf, RefType, "std::convert::AsMut"), + ("eq", 2, RefSelf, BoolType, "std::cmp::PartialEq"), + ("cmp", 2, RefSelf, AnyType, "std::cmp::Ord"), + ("default", 0, NoSelf, AnyType, "std::default::Default"), + ("hash", 2, RefSelf, UnitType, "std::hash::Hash"), + ("next", 1, RefMutSelf, AnyType, "std::iter::Iterator"), + ("into_iter", 1, ValueSelf, AnyType, "std::iter::IntoIterator"), + ("from_iter", 1, NoSelf, AnyType, "std::iter::FromIterator"), + ("from_str", 1, NoSelf, AnyType, "std::str::FromStr"), +]; + +#[derive(Clone, Copy)] +enum SelfKind { + ValueSelf, + RefSelf, + RefMutSelf, + NoSelf +} + +impl SelfKind { + fn matches(&self, slf: &ExplicitSelf_) -> bool { + match (self, slf) { + (&ValueSelf, &SelfValue(_)) => true, + (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true, + (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true, + (&NoSelf, &SelfStatic) => true, + _ => false + } + } +} + +#[derive(Clone, Copy)] +enum OutType { + UnitType, + BoolType, + AnyType, + RefType, +} + +impl OutType { + fn matches(&self, ty: &FunctionRetTy) -> bool { + match (self, ty) { + (&UnitType, &DefaultReturn(_)) => true, + (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![]) => true, + (&BoolType, &Return(ref ty)) if is_bool(ty) => true, + (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![]) => true, + (&RefType, &Return(ref ty)) => { + if let TyRptr(_, _) = ty.node { true } else { false } + } + _ => false + } + } +} + +fn is_bool(ty: &Ty) -> bool { + if let TyPath(None, ref p) = ty.node { + if match_path(p, &["bool"]) { + return true; + } + } + false } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 91d3b72de84..cb77d79f0ff 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -1,8 +1,27 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(option_unwrap_used, result_unwrap_used)] -#[deny(str_to_string, string_to_string)] +#![allow(unused)] +#![deny(clippy)] + +use std::ops::Mul; + +struct T; + +impl T { + fn add(self, other: T) -> T { self } //~ERROR defining a method called `add` + fn drop(&mut self) { } //~ERROR defining a method called `drop` + + fn sub(&self, other: T) -> &T { self } // no error, self is a ref + fn div(self) -> T { self } // no error, different #arguments + fn rem(self, other: T) { } // no error, wrong return type +} + +impl Mul<T> for T { + type Output = T; + fn mul(self, other: T) -> T { self } // no error, obviously +} + fn main() { let opt = Some(0); let _ = opt.unwrap(); //~ERROR used unwrap() on an Option -- cgit 1.4.1-3-g733a5 From 64cd1fc6ba266fdcfe96415a293a732df5741a04 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 12:34:27 +0200 Subject: eq_op: cut back to expressions that are guaranteed side effect free fixes #229 --- src/eq_op.rs | 211 ++++++-------------------------------------- tests/compile-fail/eq_op.rs | 6 -- 2 files changed, 26 insertions(+), 191 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index ebc6aa17100..3b4f47b5562 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -2,7 +2,6 @@ use rustc::lint::*; use syntax::ast::*; use syntax::ast_util as ast_util; use syntax::ptr::P; -use syntax::codemap as code; use consts::constant; use utils::span_lint; @@ -33,42 +32,27 @@ impl LintPass for EqOp { } pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { - if match (&left.node, &right.node) { - (&ExprBinary(ref lop, ref ll, ref lr), - &ExprBinary(ref rop, ref rl, ref rr)) => - lop.node == rop.node && - is_exp_equal(cx, ll, rl) && is_exp_equal(cx, lr, rr), - (&ExprBox(ref lpl, ref lbox), &ExprBox(ref rpl, ref rbox)) => - both(lpl, rpl, |l, r| is_exp_equal(cx, l, r)) && - is_exp_equal(cx, lbox, rbox), - (&ExprCall(ref lcallee, ref largs), - &ExprCall(ref rcallee, ref rargs)) => is_exp_equal(cx, lcallee, - rcallee) && is_exps_equal(cx, largs, rargs), - (&ExprCast(ref lc, ref lty), &ExprCast(ref rc, ref rty)) => - is_ty_equal(cx, lty, rty) && is_exp_equal(cx, lc, rc), + if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { + if l == r { + return true; + } + } + match (&left.node, &right.node) { (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprMethodCall(ref lident, ref lcty, ref lmargs), - &ExprMethodCall(ref rident, ref rcty, ref rmargs)) => - lident.node == rident.node && is_tys_equal(cx, lcty, rcty) && - is_exps_equal(cx, lmargs, rmargs), (&ExprParen(ref lparen), _) => is_exp_equal(cx, lparen, right), (_, &ExprParen(ref rparen)) => is_exp_equal(cx, left, rparen), (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, |l, r| is_qself_equal(l, r)) && + both(lqself, rqself, is_qself_equal) && is_path_equal(lsubpath, rsubpath), (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup), - (&ExprUnary(lunop, ref l), &ExprUnary(runop, ref r)) => - lunop == runop && is_exp_equal(cx, l, r), (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), - _ => false - } { return true; } - match (constant(cx, left), constant(cx, right)) { - (Some(l), Some(r)) => l == r, + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => + is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), _ => false } } @@ -90,166 +74,6 @@ fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { left.ty.node == right.ty.node && left.position == right.position } -fn is_ty_equal(cx: &Context, left : &Ty, right : &Ty) -> bool { - match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => is_ty_equal(cx, lvec, rvec), - (&TyFixedLengthVec(ref lfvty, ref lfvexp), - &TyFixedLengthVec(ref rfvty, ref rfvexp)) => - is_ty_equal(cx, lfvty, rfvty) && is_exp_equal(cx, lfvexp, rfvexp), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => is_mut_ty_equal(cx, lmut, rmut), - (&TyRptr(ref ltime, ref lrmut), &TyRptr(ref rtime, ref rrmut)) => - both(ltime, rtime, is_lifetime_equal) && - is_mut_ty_equal(cx, lrmut, rrmut), - (&TyBareFn(ref lbare), &TyBareFn(ref rbare)) => - is_bare_fn_ty_equal(cx, lbare, rbare), - (&TyTup(ref ltup), &TyTup(ref rtup)) => is_tys_equal(cx, ltup, rtup), - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => - both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), - (&TyObjectSum(ref lsumty, ref lobounds), - &TyObjectSum(ref rsumty, ref robounds)) => - is_ty_equal(cx, lsumty, rsumty) && - is_param_bounds_equal(lobounds, robounds), - (&TyPolyTraitRef(ref ltbounds), &TyPolyTraitRef(ref rtbounds)) => - is_param_bounds_equal(ltbounds, rtbounds), - (&TyParen(ref lty), &TyParen(ref rty)) => is_ty_equal(cx, lty, rty), - (&TyTypeof(ref lof), &TyTypeof(ref rof)) => is_exp_equal(cx, lof, rof), - (&TyInfer, &TyInfer) => true, - _ => false - } -} - -fn is_param_bound_equal(left : &TyParamBound, right : &TyParamBound) - -> bool { - match(left, right) { - (&TraitTyParamBound(ref lpoly, ref lmod), - &TraitTyParamBound(ref rpoly, ref rmod)) => - lmod == rmod && is_poly_traitref_equal(lpoly, rpoly), - (&RegionTyParamBound(ref ltime), &RegionTyParamBound(ref rtime)) => - is_lifetime_equal(ltime, rtime), - _ => false - } -} - -fn is_poly_traitref_equal(left : &PolyTraitRef, right : &PolyTraitRef) - -> bool { - is_lifetimedefs_equal(&left.bound_lifetimes, &right.bound_lifetimes) - && is_path_equal(&left.trait_ref.path, &right.trait_ref.path) -} - -fn is_param_bounds_equal(left : &TyParamBounds, right : &TyParamBounds) - -> bool { - over(left, right, is_param_bound_equal) -} - -fn is_mut_ty_equal(cx: &Context, left : &MutTy, right : &MutTy) -> bool { - left.mutbl == right.mutbl && is_ty_equal(cx, &left.ty, &right.ty) -} - -fn is_bare_fn_ty_equal(cx: &Context, left : &BareFnTy, right : &BareFnTy) -> bool { - left.unsafety == right.unsafety && left.abi == right.abi && - is_lifetimedefs_equal(&left.lifetimes, &right.lifetimes) && - is_fndecl_equal(cx, &left.decl, &right.decl) -} - -fn is_fndecl_equal(cx: &Context, left : &P<FnDecl>, right : &P<FnDecl>) -> bool { - left.variadic == right.variadic && - is_args_equal(cx, &left.inputs, &right.inputs) && - is_fnret_ty_equal(cx, &left.output, &right.output) -} - -fn is_fnret_ty_equal(cx: &Context, left : &FunctionRetTy, - right : &FunctionRetTy) -> bool { - match (left, right) { - (&NoReturn(_), &NoReturn(_)) | - (&DefaultReturn(_), &DefaultReturn(_)) => true, - (&Return(ref lty), &Return(ref rty)) => is_ty_equal(cx, lty, rty), - _ => false - } -} - -fn is_arg_equal(cx: &Context, l: &Arg, r : &Arg) -> bool { - is_ty_equal(cx, &l.ty, &r.ty) && is_pat_equal(cx, &l.pat, &r.pat) -} - -fn is_args_equal(cx: &Context, left : &[Arg], right : &[Arg]) -> bool { - over(left, right, |l, r| is_arg_equal(cx, l, r)) -} - -fn is_pat_equal(cx: &Context, left : &Pat, right : &Pat) -> bool { - match(&left.node, &right.node) { - (&PatWild(lwild), &PatWild(rwild)) => lwild == rwild, - (&PatIdent(ref lmode, ref lident, Option::None), - &PatIdent(ref rmode, ref rident, Option::None)) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node), - (&PatIdent(ref lmode, ref lident, Option::Some(ref lpat)), - &PatIdent(ref rmode, ref rident, Option::Some(ref rpat))) => - lmode == rmode && is_ident_equal(&lident.node, &rident.node) && - is_pat_equal(cx, lpat, rpat), - (&PatEnum(ref lpath, ref lenum), &PatEnum(ref rpath, ref renum)) => - is_path_equal(lpath, rpath) && both(lenum, renum, |l, r| - is_pats_equal(cx, l, r)), - (&PatStruct(ref lpath, ref lfieldpat, lbool), - &PatStruct(ref rpath, ref rfieldpat, rbool)) => - lbool == rbool && is_path_equal(lpath, rpath) && - is_spanned_fieldpats_equal(cx, lfieldpat, rfieldpat), - (&PatTup(ref ltup), &PatTup(ref rtup)) => is_pats_equal(cx, ltup, rtup), - (&PatBox(ref lboxed), &PatBox(ref rboxed)) => - is_pat_equal(cx, lboxed, rboxed), - (&PatRegion(ref lpat, ref lmut), &PatRegion(ref rpat, ref rmut)) => - is_pat_equal(cx, lpat, rpat) && lmut == rmut, - (&PatLit(ref llit), &PatLit(ref rlit)) => is_exp_equal(cx, llit, rlit), - (&PatRange(ref lfrom, ref lto), &PatRange(ref rfrom, ref rto)) => - is_exp_equal(cx, lfrom, rfrom) && is_exp_equal(cx, lto, rto), - (&PatVec(ref lfirst, Option::None, ref llast), - &PatVec(ref rfirst, Option::None, ref rlast)) => - is_pats_equal(cx, lfirst, rfirst) && is_pats_equal(cx, llast, rlast), - (&PatVec(ref lfirst, Option::Some(ref lpat), ref llast), - &PatVec(ref rfirst, Option::Some(ref rpat), ref rlast)) => - is_pats_equal(cx, lfirst, rfirst) && is_pat_equal(cx, lpat, rpat) && - is_pats_equal(cx, llast, rlast), - // I don't match macros for now, the code is slow enough as is ;-) - _ => false - } -} - -fn is_spanned_fieldpats_equal(cx: &Context, left : &[code::Spanned<FieldPat>], - right : &[code::Spanned<FieldPat>]) -> bool { - over(left, right, |l, r| is_fieldpat_equal(cx, &l.node, &r.node)) -} - -fn is_fieldpat_equal(cx: &Context, left : &FieldPat, right : &FieldPat) -> bool { - left.is_shorthand == right.is_shorthand && - is_ident_equal(&left.ident, &right.ident) && - is_pat_equal(cx, &left.pat, &right.pat) -} - -fn is_ident_equal(left : &Ident, right : &Ident) -> bool { - &left.name == &right.name && left.ctxt == right.ctxt -} - -fn is_pats_equal(cx: &Context, left : &[P<Pat>], right : &[P<Pat>]) -> bool { - over(left, right, |l, r| is_pat_equal(cx, l, r)) -} - -fn is_lifetimedef_equal(left : &LifetimeDef, right : &LifetimeDef) - -> bool { - is_lifetime_equal(&left.lifetime, &right.lifetime) && - over(&left.bounds, &right.bounds, is_lifetime_equal) -} - -fn is_lifetimedefs_equal(left : &[LifetimeDef], right : &[LifetimeDef]) - -> bool { - over(left, right, is_lifetimedef_equal) -} - -fn is_lifetime_equal(left : &Lifetime, right : &Lifetime) -> bool { - left.name == right.name -} - -fn is_tys_equal(cx: &Context, left : &[P<Ty>], right : &[P<Ty>]) -> bool { - over(left, right, |l, r| is_ty_equal(cx, l, r)) -} - fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| @@ -269,3 +93,20 @@ fn is_cmp_or_bit(op : &BinOp) -> bool { _ => false } } + +fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { + match (&left.node, &right.node) { + (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => + lmut.mutbl == rmut.mutbl && + is_cast_ty_equal(&*lmut.ty, &*rmut.ty), + (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => + lrmut.mutbl == rrmut.mutbl && + is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty), + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => + both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), + (&TyParen(ref lty), &TyParen(ref rty)) => is_cast_ty_equal(lty, rty), + (&TyInfer, &TyInfer) => true, + _ => false + } +} diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index a1183629344..fc59c2739a2 100755 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -1,10 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -fn id<X>(x: X) -> X { - x -} - #[deny(eq_op)] #[allow(identity_op)] fn main() { @@ -19,7 +15,6 @@ fn main() { // casts, methods, parentheses (1 as u64) & (1 as u64); //~ERROR equal expressions 1 ^ ((((((1)))))); //~ERROR equal expressions - id((1)) | id(1); //~ERROR equal expressions // unary and binary operators (-(2) < -(2)); //~ERROR equal expressions @@ -32,7 +27,6 @@ fn main() { // various other things ([1] != [1]); //~ERROR equal expressions ((1, 2) != (1, 2)); //~ERROR equal expressions - [1].len() == [1].len(); //~ERROR equal expressions vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros // const folding -- cgit 1.4.1-3-g733a5 From 81ef3da03cfb00eb16bd01d884fdc38835d9dfe0 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 12:45:52 +0200 Subject: methods: people might be using to_string() to make a copy; add a hint for that --- src/methods.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index df8e35d98fb..40043be109a 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -41,7 +41,8 @@ impl LintPass for MethodsPass { if obj_ty.sty == ty::TyStr { span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); } else if match_type(cx, obj_ty, &STRING_PATH) { - span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op"); + span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \ + `clone()` to make a copy"); } } } -- cgit 1.4.1-3-g733a5 From d5c808acd05d5f91b2358984b0c4c97c33cfc1f9 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 13:26:20 +0200 Subject: collapsible_if: remove extraneous note output This was probably a debug addition. --- src/collapsible_if.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 0b6dfc19e6b..7d654b43f2f 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -48,7 +48,6 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if e.span.expn_id != sp.expn_id { return; } - cx.sess().note(&format!("{:?} -- {:?}", e.span, sp)); span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", &format!("try\nif {} && {} {}", -- cgit 1.4.1-3-g733a5 From 5225feceaa345e55bdd3b45007555f6d477faf55 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 17:11:34 +0200 Subject: shadowing detection --- README.md | 2 +- src/lib.rs | 4 +- src/methods.rs | 3 +- src/shadow.rs | 144 ++++++++++++++++++++++--------------- tests/compile-fail/approx_const.rs | 2 +- 5 files changed, 93 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 71ca256fb9a..66411e432c9 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ ptr_arg | allow | fn arguments of the type `&Vec<...>` or `&S range_step_by_zero | warn | using Range::step_by(0), which produces an infinite iterator redundant_closure | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) result_unwrap_used | allow | using `Result.unwrap()`, which might be better handled -shadow_foreign | warn | The name is re-bound without even using the original value shadow_reuse | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` shadow_same | allow | rebinding a name to itself, e.g. `let mut x = &mut x` +shadow_unrelated | warn | The name is re-bound without even using the original value single_match | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead str_to_string | warn | using `to_string()` on a str, which should be `to_owned()` string_add | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead diff --git a/src/lib.rs b/src/lib.rs index e65311133d2..33788190fd3 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,9 +76,9 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box matches::MatchPass as LintPassObject); reg.register_lint_group("shadow", vec![ - shadow::SHADOW_FOREIGN, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, ]); reg.register_lint_group("clippy", vec![ @@ -114,9 +114,9 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, - shadow::SHADOW_FOREIGN, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::BOX_VEC, diff --git a/src/methods.rs b/src/methods.rs index df8e35d98fb..40043be109a 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -41,7 +41,8 @@ impl LintPass for MethodsPass { if obj_ty.sty == ty::TyStr { span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); } else if match_type(cx, obj_ty, &STRING_PATH) { - span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op"); + span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \ + `clone()` to make a copy"); } } } diff --git a/src/shadow.rs b/src/shadow.rs index bae05c17d7b..bbd146f77a5 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -1,3 +1,4 @@ +use std::ops::Deref; use syntax::ast::*; use syntax::codemap::Span; use syntax::visit::FnKind; @@ -10,7 +11,7 @@ declare_lint!(pub SHADOW_SAME, Allow, declare_lint!(pub SHADOW_REUSE, Allow, "rebinding a name to an expression that re-uses the original value, e.g. \ `let x = x + 1`"); -declare_lint!(pub SHADOW_FOREIGN, Warn, +declare_lint!(pub SHADOW_UNRELATED, Warn, "The name is re-bound without even using the original value"); #[derive(Copy, Clone)] @@ -18,7 +19,7 @@ pub struct ShadowPass; impl LintPass for ShadowPass { fn get_lints(&self) -> LintArray { - lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_FOREIGN) + lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) } fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, @@ -44,10 +45,6 @@ fn named(pat: &Pat) -> Option<Name> { } else { None } } -fn add(bindings: &mut Vec<Name>, pat: &Pat) { - named(pat).map(|name| bindings.push(name)); -} - fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { let len = bindings.len(); for stmt in &block.stmts { @@ -65,41 +62,53 @@ fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { if in_external_macro(cx, decl.span) { return; } if let DeclLocal(ref local) = decl.node { - let Local{ ref pat, ref ty, ref init, id: _, span: _ } = **local; - if let &Some(ref t) = ty { check_ty(cx, t, bindings); } - named(pat).map(|name| if bindings.contains(&name) { - if let &Some(ref o) = init { - if in_external_macro(cx, o.span) { return; } + let Local{ ref pat, ref ty, ref init, id: _, span } = **local; + if let &Some(ref t) = ty { check_ty(cx, t, bindings) } + check_pat(cx, pat, init, span, bindings); + if let &Some(ref o) = init { check_expr(cx, o, bindings) } + } +} + +fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, + bindings: &mut Vec<Name>) where T: Deref<Target=Expr> { + //TODO: match more stuff / destructuring + named(pat).map(|name| { + if let &Some(ref o) = init { + if !in_external_macro(cx, o.span) { check_expr(cx, o, bindings); - bindings.push(name); - lint_shadow(cx, name, decl.span, pat.span, o); } - }); - add(bindings, pat); - if let &Some(ref o) = init { - check_expr(cx, o, bindings) } - } + if bindings.contains(&name) { + lint_shadow(cx, name, span, pat.span, init); + } + bindings.push(name); + }); } -fn lint_shadow(cx: &Context, name: Name, span: Span, lspan: Span, init: &Expr) { - if is_self_shadow(name, init) { - span_lint(cx, SHADOW_SAME, span, &format!( - "{} is shadowed by itself in {}", - snippet(cx, lspan, "_"), - snippet(cx, init.span, ".."))); - } else { - if contains_self(name, init) { - span_lint(cx, SHADOW_REUSE, span, &format!( - "{} is shadowed by {} which reuses the original value", +fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: + &Option<T>) where T: Deref<Target=Expr> { + if let &Some(ref expr) = init { + if is_self_shadow(name, expr) { + span_lint(cx, SHADOW_SAME, span, &format!( + "{} is shadowed by itself in {}", snippet(cx, lspan, "_"), - snippet(cx, init.span, ".."))); + snippet(cx, expr.span, ".."))); } else { - span_lint(cx, SHADOW_FOREIGN, span, &format!( - "{} is shadowed by {} in this declaration", - snippet(cx, lspan, "_"), - snippet(cx, init.span, ".."))); + if contains_self(name, expr) { + span_lint(cx, SHADOW_REUSE, span, &format!( + "{} is shadowed by {} which reuses the original value", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, ".."))); + } else { + span_lint(cx, SHADOW_UNRELATED, span, &format!( + "{} is shadowed by {} in this declaration", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, ".."))); + } } + } else { + span_lint(cx, SHADOW_UNRELATED, span, &format!( + "{} is shadowed in this declaration", snippet(cx, lspan, "_"))); } } @@ -120,26 +129,21 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { check_block(cx, then, bindings); if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); } }, - ExprIfLet(ref pat, ref e, ref block, ref otherwise) => { - check_expr(cx, e, bindings); - let len = bindings.len(); - add(bindings, pat); - check_block(cx, block, bindings); - if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); } - bindings.truncate(len); - }, ExprWhile(ref cond, ref block, _) => { check_expr(cx, cond, bindings); check_block(cx, block, bindings); }, - ExprWhileLet(ref pat, ref e, ref block, _) | - ExprForLoop(ref pat, ref e, ref block, _) => { - check_expr(cx, e, bindings); - let len = bindings.len(); - add(bindings, pat); - check_block(cx, block, bindings); - bindings.truncate(len); - }, + ExprMatch(ref init, ref arms, _) => + for ref arm in arms { + for ref pat in &arm.pats { + //TODO: This is ugly, but needed to get the right type + check_pat(cx, pat, &Some(&**init), pat.span, bindings); + } + if let Some(ref guard) = arm.guard { + check_expr(cx, guard, bindings); + } + check_expr(cx, &*arm.body, bindings); + }, _ => () } } @@ -169,12 +173,15 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { map_or(false, |ref e| is_self_shadow(name, e)), ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) && is_self_shadow(name, inner), - ExprPath(_, ref path) => path.segments.len() == 1 && - path.segments[0].identifier.name == name, + ExprPath(_, ref path) => path_eq_name(name, path), _ => false, } } +fn path_eq_name(name: Name, path: &Path) -> bool { + path.segments.len() == 1 && path.segments[0].identifier.name == name +} + fn contains_self(name: Name, expr: &Expr) -> bool { match expr.node { ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | @@ -193,13 +200,11 @@ fn contains_self(name: Name, expr: &Expr) -> bool { ExprIf(ref cond, ref then, ref otherwise) => contains_self(name, cond) || contains_block_self(name, then) || otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)), - ExprIfLet(_, ref e, ref block, ref otherwise) => - contains_self(name, e) || contains_block_self(name, block) || - otherwise.as_ref().map_or(false, |ref o| contains_self(name, o)), - ExprWhile(ref e, ref block, _) | - ExprWhileLet(_, ref e, ref block, _) | - ExprForLoop(_, ref e, ref block, _) => + ExprWhile(ref e, ref block, _) => contains_self(name, e) || contains_block_self(name, block), + ExprMatch(ref e, ref arms, _) => + arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat| + contains_pat_self(name, pat))) || contains_self(name, e), ExprPath(_, ref path) => path.segments.len() == 1 && path.segments[0].identifier.name == name, _ => false @@ -211,6 +216,9 @@ fn contains_block_self(name: Name, block: &Block) -> bool { match stmt.node { StmtDecl(ref decl, _) => if let DeclLocal(ref local) = decl.node { + //TODO: We don't currently handle the case where the name + //is shadowed wiithin the block; this means code including this + //degenerate pattern will get the wrong warning. if let Some(ref init) = local.init { if contains_self(name, init) { return true; } } @@ -222,3 +230,25 @@ fn contains_block_self(name: Name, block: &Block) -> bool { } if let Some(ref e) = block.expr { contains_self(name, e) } else { false } } + +fn contains_pat_self(name: Name, pat: &Pat) -> bool { + match pat.node { + PatIdent(_, ref ident, ref inner) => name == ident.node.name || + inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)), + PatEnum(_, ref opats) => opats.as_ref().map_or(false, + |pats| pats.iter().any(|p| contains_pat_self(name, p))), + PatQPath(_, ref path) => path_eq_name(name, path), + PatStruct(_, ref fieldpats, _) => fieldpats.iter().any( + |ref fp| contains_pat_self(name, &fp.node.pat)), + PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)), + PatBox(ref p) | + PatRegion(ref p, _) => contains_pat_self(name, p), + PatRange(ref from, ref until) => + contains_self(name, from) || contains_self(name, until), + PatVec(ref pre, ref opt, ref post) => + pre.iter().any(|ref p| contains_pat_self(name, p)) || + opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) || + post.iter().any(|ref p| contains_pat_self(name, p)), + _ => false, + } +} diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index 4c289b474f7..a75cd0bf3f2 100755 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(approx_constant)] -#[allow(unused, shadow_foreign)] +#[allow(unused, shadow_unrelated)] fn main() { let my_e = 2.7182; //~ERROR approximate value of `f{32, 64}::E` found let almost_e = 2.718; //~ERROR approximate value of `f{32, 64}::E` found -- cgit 1.4.1-3-g733a5 From 92a3394065e601f6f4ace7f374f5ce782d7b211d Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 14:41:35 +0200 Subject: all: remove unneeded deref and/or ref operations --- src/attrs.rs | 4 ++-- src/collapsible_if.rs | 2 +- src/consts.rs | 6 +++--- src/eta_reduction.rs | 2 +- src/len_zero.rs | 2 +- src/lifetimes.rs | 6 +++--- src/loops.rs | 6 +++--- src/matches.rs | 10 +++++----- src/methods.rs | 2 +- src/misc.rs | 2 +- src/needless_bool.rs | 4 ++-- src/ptr_arg.rs | 2 +- src/returns.rs | 4 ++-- src/strings.rs | 4 ++-- src/types.rs | 10 +++++----- src/utils.rs | 4 ---- 16 files changed, 33 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 3e451ac5eda..ad021f28a4d 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -71,14 +71,14 @@ fn is_relevant_block(block: &Block) -> bool { _ => () } } - block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e)) + block.expr.as_ref().map_or(false, |e| is_relevant_expr(e)) } fn is_relevant_expr(expr: &Expr) -> bool { match expr.node { ExprBlock(ref block) => is_relevant_block(block), ExprRet(Some(ref e)) | ExprParen(ref e) => - is_relevant_expr(&*e), + is_relevant_expr(e), ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 7d654b43f2f..e0b25b7283b 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -79,7 +79,7 @@ fn single_stmt_of_block(block: &Block) -> Option<&Expr> { } else { None } } else { if block.stmts.is_empty() { - if let Some(ref p) = block.expr { Some(&*p) } else { None } + if let Some(ref p) = block.expr { Some(p) } else { None } } else { None } } } diff --git a/src/consts.rs b/src/consts.rs index e54ac77b599..1a828317fc2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -222,7 +222,7 @@ fn neg_float_str(s: String) -> String { if s.starts_with('-') { s[1..].to_owned() } else { - format!("-{}", &*s) + format!("-{}", s) } } @@ -299,7 +299,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { ExprPath(_, _) => self.fetch_path(e), ExprBlock(ref block) => self.block(block), ExprIf(ref cond, ref then, ref otherwise) => - self.ifthenelse(&*cond, &*then, &*otherwise), + self.ifthenelse(cond, then, otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), ExprVec(ref vec) => self.multi(vec).map(ConstantVec), ExprTup(ref tup) => self.multi(tup).map(ConstantTuple), @@ -362,7 +362,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { if b { self.block(then) } else { - otherwise.as_ref().and_then(|ref expr| self.expr(expr)) + otherwise.as_ref().and_then(|expr| self.expr(expr)) } } else { None } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 25e967b07e5..481512abc62 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -22,7 +22,7 @@ impl LintPass for EtaPass { ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => { for arg in args { - check_closure(cx, &*arg) + check_closure(cx, arg) } }, _ => (), diff --git a/src/len_zero.rs b/src/len_zero.rs index 5eaa0256402..ca3ce51bf7c 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -102,7 +102,7 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { if method.node.name == "len" && args.len() == 1 && - has_is_empty(cx, &*args[0]) { + has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "consider replacing the len comparison with `{}{}.is_empty()`", op, snippet(cx, args[0].span, "_"))) diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 9d07df4a3ed..660d68535bd 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -26,14 +26,14 @@ impl LintPass for LifetimePass { fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { if let MethodImplItem(ref sig, _) = item.node { - check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics.lifetimes, item.span); } } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { - check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics.lifetimes, item.span); } } @@ -92,7 +92,7 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, } // extract lifetimes in input argument types for arg in &func.inputs { - walk_ty(&mut input_visitor, &*arg.ty); + walk_ty(&mut input_visitor, &arg.ty); } // extract lifetimes in output type if let Return(ref ty) = func.output { diff --git a/src/loops.rs b/src/loops.rs index 5f18439eafe..ca8d3990fc5 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -95,9 +95,9 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node, somepats.len() == 1 ], { - return Some((&*somepats[0], - &*iterargs[0], - &*innerarms[0].body)); + return Some((&somepats[0], + &iterargs[0], + &innerarms[0].body)); } } None diff --git a/src/matches.rs b/src/matches.rs index 002da07f50b..d1c74daf2cd 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -34,7 +34,7 @@ impl LintPass for MatchPass { // when an enum is extended, so we don't consider these cases arms[1].pats[0].node == PatWild(PatWildSingle) && // finally, we don't want any content in the second arm (unit or empty block) - is_unit_expr(&*arms[1].body) + is_unit_expr(&arms[1].body) { let body_code = snippet_block(cx, arms[0].body.span, ".."); let body_code = if let ExprBlock(_) = arms[0].body.node { @@ -46,10 +46,10 @@ impl LintPass for MatchPass { "you seem to be trying to use match for \ destructuring a single pattern. Did you mean to \ use `if let`?", - &*format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - body_code) + &format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + body_code) ); } diff --git a/src/methods.rs b/src/methods.rs index 40043be109a..07693e11d99 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -24,7 +24,7 @@ impl LintPass for MethodsPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])); + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])); if ident.node.name == "unwrap" { if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, diff --git a/src/misc.rs b/src/misc.rs index 81b03db5e14..2290af38bb5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -203,7 +203,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = - walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } + walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { true } else { false } } declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 7671d63a35d..0fe52c44189 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -5,7 +5,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::{de_p, span_lint, snippet}; +use utils::{span_lint, snippet}; declare_lint! { pub NEEDLESS_BOOL, @@ -55,7 +55,7 @@ impl LintPass for NeedlessBool { fn fetch_bool_block(block: &Block) -> Option<bool> { if block.stmts.is_empty() { - block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) + block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) } else { None } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 2d09fcbcca9..bcbd8dad68a 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -45,7 +45,7 @@ impl LintPass for PtrArg { fn check_fn(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - if let Some(pat_ty) = cx.tcx.pat_ty_opt(&*arg.pat) { + if let Some(pat_ty) = cx.tcx.pat_ty_opt(&arg.pat) { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = pat_ty.sty { if match_type(cx, ty, &VEC_PATH) { span_lint(cx, PTR_ARG, arg.ty.span, diff --git a/src/returns.rs b/src/returns.rs index df0b93f301e..301072f7912 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -50,7 +50,7 @@ impl ReturnPass { // a match expr, check all arms ExprMatch(_, ref arms, _) => { for arm in arms { - self.check_final_expr(cx, &*arm.body); + self.check_final_expr(cx, &arm.body); } } _ => { } @@ -76,7 +76,7 @@ impl ReturnPass { let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, let Some(ref retexpr) = block.expr, let ExprPath(_, ref path) = retexpr.node, - match_path(path, &[&*id.name.as_str()]) + match_path(path, &[&id.name.as_str()]) ], { self.emit_let_lint(cx, retexpr.span, initexpr.span); } diff --git a/src/strings.rs b/src/strings.rs index b24ea345244..d03f4d53c60 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -70,8 +70,8 @@ fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { is_exp_equal(cx, target, left), ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().map_or(false, - |expr| is_add(cx, &*expr, target)), - ExprParen(ref expr) => is_add(cx, &*expr, target), + |expr| is_add(cx, expr, target)), + ExprParen(ref expr) => is_add(cx, expr, target), _ => false } } diff --git a/src/types.rs b/src/types.rs index 4e9dd133ac8..7479a65b6ee 100644 --- a/src/types.rs +++ b/src/types.rs @@ -55,7 +55,7 @@ declare_lint!(pub LET_UNIT_VALUE, Warn, fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { if in_macro(cx, info) { return; } if let DeclLocal(ref local) = decl.node { - let bindtype = &cx.tcx.pat_ty(&*local.pat).sty; + let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( "this let-binding has unit value. Consider omitting `let {} =`", @@ -210,7 +210,7 @@ impl LintPass for CastPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprCast(ref ex, _) = expr.node { - let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr)); + let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr)); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { @@ -263,14 +263,14 @@ impl LintPass for TypeComplexityPass { } fn check_struct_field(&mut self, cx: &Context, field: &StructField) { - check_type(cx, &*field.node.ty); + check_type(cx, &field.node.ty); } fn check_variant(&mut self, cx: &Context, var: &Variant, _: &Generics) { // StructVariant is covered by check_struct_field if let TupleVariantKind(ref args) = var.node.kind { for arg in args { - check_type(cx, &*arg.ty); + check_type(cx, &arg.ty); } } } @@ -312,7 +312,7 @@ impl LintPass for TypeComplexityPass { fn check_fndecl(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - check_type(cx, &*arg.ty); + check_type(cx, &arg.ty); } if let Return(ref ty) = decl.output { check_type(cx, ty); diff --git a/src/utils.rs b/src/utils.rs index 5e7c63e85d9..394204bedfc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{ExpnInfo, Span}; -use syntax::ptr::P; use rustc::ast_map::Node::NodeExpr; use rustc::middle::ty; use std::borrow::Cow; @@ -130,9 +129,6 @@ pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { if let NodeExpr(parent) = node { Some(parent) } else { None } ) } -/// dereference a P<T> and return a ref on the result -pub fn de_p<T>(p: &P<T>) -> &T { &*p } - #[cfg(not(feature="structured_logging"))] pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); -- cgit 1.4.1-3-g733a5 From 88047a0953d8032db9021a38e60d5c088d8318b0 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 13:26:20 +0200 Subject: collapsible_if: remove extraneous note output This was probably a debug addition. --- src/collapsible_if.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 0b6dfc19e6b..7d654b43f2f 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -48,7 +48,6 @@ fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { if e.span.expn_id != sp.expn_id { return; } - cx.sess().note(&format!("{:?} -- {:?}", e.span, sp)); span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", &format!("try\nif {} && {} {}", -- cgit 1.4.1-3-g733a5 From b13d318f48f181292e8efbdd4fe2d0353e1f51d2 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 14:41:35 +0200 Subject: all: remove unneeded deref and/or ref operations --- src/attrs.rs | 4 ++-- src/collapsible_if.rs | 2 +- src/consts.rs | 6 +++--- src/eta_reduction.rs | 2 +- src/len_zero.rs | 2 +- src/lifetimes.rs | 6 +++--- src/loops.rs | 6 +++--- src/matches.rs | 10 +++++----- src/methods.rs | 2 +- src/misc.rs | 2 +- src/needless_bool.rs | 4 ++-- src/ptr_arg.rs | 2 +- src/returns.rs | 4 ++-- src/strings.rs | 4 ++-- src/types.rs | 10 +++++----- src/utils.rs | 4 ---- 16 files changed, 33 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 3e451ac5eda..ad021f28a4d 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -71,14 +71,14 @@ fn is_relevant_block(block: &Block) -> bool { _ => () } } - block.expr.as_ref().map_or(false, |e| is_relevant_expr(&*e)) + block.expr.as_ref().map_or(false, |e| is_relevant_expr(e)) } fn is_relevant_expr(expr: &Expr) -> bool { match expr.node { ExprBlock(ref block) => is_relevant_block(block), ExprRet(Some(ref e)) | ExprParen(ref e) => - is_relevant_expr(&*e), + is_relevant_expr(e), ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 7d654b43f2f..e0b25b7283b 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -79,7 +79,7 @@ fn single_stmt_of_block(block: &Block) -> Option<&Expr> { } else { None } } else { if block.stmts.is_empty() { - if let Some(ref p) = block.expr { Some(&*p) } else { None } + if let Some(ref p) = block.expr { Some(p) } else { None } } else { None } } } diff --git a/src/consts.rs b/src/consts.rs index e54ac77b599..1a828317fc2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -222,7 +222,7 @@ fn neg_float_str(s: String) -> String { if s.starts_with('-') { s[1..].to_owned() } else { - format!("-{}", &*s) + format!("-{}", s) } } @@ -299,7 +299,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { ExprPath(_, _) => self.fetch_path(e), ExprBlock(ref block) => self.block(block), ExprIf(ref cond, ref then, ref otherwise) => - self.ifthenelse(&*cond, &*then, &*otherwise), + self.ifthenelse(cond, then, otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), ExprVec(ref vec) => self.multi(vec).map(ConstantVec), ExprTup(ref tup) => self.multi(tup).map(ConstantTuple), @@ -362,7 +362,7 @@ impl<'c, 'cc> ConstEvalContext<'c, 'cc> { if b { self.block(then) } else { - otherwise.as_ref().and_then(|ref expr| self.expr(expr)) + otherwise.as_ref().and_then(|expr| self.expr(expr)) } } else { None } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 25e967b07e5..481512abc62 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -22,7 +22,7 @@ impl LintPass for EtaPass { ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => { for arg in args { - check_closure(cx, &*arg) + check_closure(cx, arg) } }, _ => (), diff --git a/src/len_zero.rs b/src/len_zero.rs index 5eaa0256402..ca3ce51bf7c 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -102,7 +102,7 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { if method.node.name == "len" && args.len() == 1 && - has_is_empty(cx, &*args[0]) { + has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "consider replacing the len comparison with `{}{}.is_empty()`", op, snippet(cx, args[0].span, "_"))) diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 9d07df4a3ed..660d68535bd 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -26,14 +26,14 @@ impl LintPass for LifetimePass { fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { if let MethodImplItem(ref sig, _) = item.node { - check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics.lifetimes, item.span); } } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { - check_fn_inner(cx, &*sig.decl, Some(&sig.explicit_self), + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics.lifetimes, item.span); } } @@ -92,7 +92,7 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, } // extract lifetimes in input argument types for arg in &func.inputs { - walk_ty(&mut input_visitor, &*arg.ty); + walk_ty(&mut input_visitor, &arg.ty); } // extract lifetimes in output type if let Return(ref ty) = func.output { diff --git a/src/loops.rs b/src/loops.rs index 5f18439eafe..ca8d3990fc5 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -95,9 +95,9 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node, somepats.len() == 1 ], { - return Some((&*somepats[0], - &*iterargs[0], - &*innerarms[0].body)); + return Some((&somepats[0], + &iterargs[0], + &innerarms[0].body)); } } None diff --git a/src/matches.rs b/src/matches.rs index 002da07f50b..d1c74daf2cd 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -34,7 +34,7 @@ impl LintPass for MatchPass { // when an enum is extended, so we don't consider these cases arms[1].pats[0].node == PatWild(PatWildSingle) && // finally, we don't want any content in the second arm (unit or empty block) - is_unit_expr(&*arms[1].body) + is_unit_expr(&arms[1].body) { let body_code = snippet_block(cx, arms[0].body.span, ".."); let body_code = if let ExprBlock(_) = arms[0].body.node { @@ -46,10 +46,10 @@ impl LintPass for MatchPass { "you seem to be trying to use match for \ destructuring a single pattern. Did you mean to \ use `if let`?", - &*format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - body_code) + &format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + body_code) ); } diff --git a/src/methods.rs b/src/methods.rs index 40043be109a..07693e11d99 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -24,7 +24,7 @@ impl LintPass for MethodsPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])); + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])); if ident.node.name == "unwrap" { if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, diff --git a/src/misc.rs b/src/misc.rs index 81b03db5e14..2290af38bb5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -203,7 +203,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = - walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } + walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { true } else { false } } declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 7671d63a35d..0fe52c44189 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -5,7 +5,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::{de_p, span_lint, snippet}; +use utils::{span_lint, snippet}; declare_lint! { pub NEEDLESS_BOOL, @@ -55,7 +55,7 @@ impl LintPass for NeedlessBool { fn fetch_bool_block(block: &Block) -> Option<bool> { if block.stmts.is_empty() { - block.expr.as_ref().map(de_p).and_then(fetch_bool_expr) + block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) } else { None } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 2d09fcbcca9..bcbd8dad68a 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -45,7 +45,7 @@ impl LintPass for PtrArg { fn check_fn(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - if let Some(pat_ty) = cx.tcx.pat_ty_opt(&*arg.pat) { + if let Some(pat_ty) = cx.tcx.pat_ty_opt(&arg.pat) { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = pat_ty.sty { if match_type(cx, ty, &VEC_PATH) { span_lint(cx, PTR_ARG, arg.ty.span, diff --git a/src/returns.rs b/src/returns.rs index a5779984334..889688cb0c7 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -50,7 +50,7 @@ impl ReturnPass { // a match expr, check all arms ExprMatch(_, ref arms, _) => { for arm in arms { - self.check_final_expr(cx, &*arm.body); + self.check_final_expr(cx, &arm.body); } } _ => { } @@ -76,7 +76,7 @@ impl ReturnPass { let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, let Some(ref retexpr) = block.expr, let ExprPath(_, ref path) = retexpr.node, - match_path(path, &[&*id.name.as_str()]) + match_path(path, &[&id.name.as_str()]) ], { self.emit_let_lint(cx, retexpr.span, initexpr.span); } diff --git a/src/strings.rs b/src/strings.rs index b24ea345244..d03f4d53c60 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -70,8 +70,8 @@ fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { is_exp_equal(cx, target, left), ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().map_or(false, - |expr| is_add(cx, &*expr, target)), - ExprParen(ref expr) => is_add(cx, &*expr, target), + |expr| is_add(cx, expr, target)), + ExprParen(ref expr) => is_add(cx, expr, target), _ => false } } diff --git a/src/types.rs b/src/types.rs index 4e9dd133ac8..7479a65b6ee 100644 --- a/src/types.rs +++ b/src/types.rs @@ -55,7 +55,7 @@ declare_lint!(pub LET_UNIT_VALUE, Warn, fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { if in_macro(cx, info) { return; } if let DeclLocal(ref local) = decl.node { - let bindtype = &cx.tcx.pat_ty(&*local.pat).sty; + let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( "this let-binding has unit value. Consider omitting `let {} =`", @@ -210,7 +210,7 @@ impl LintPass for CastPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprCast(ref ex, _) = expr.node { - let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr)); + let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr)); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { @@ -263,14 +263,14 @@ impl LintPass for TypeComplexityPass { } fn check_struct_field(&mut self, cx: &Context, field: &StructField) { - check_type(cx, &*field.node.ty); + check_type(cx, &field.node.ty); } fn check_variant(&mut self, cx: &Context, var: &Variant, _: &Generics) { // StructVariant is covered by check_struct_field if let TupleVariantKind(ref args) = var.node.kind { for arg in args { - check_type(cx, &*arg.ty); + check_type(cx, &arg.ty); } } } @@ -312,7 +312,7 @@ impl LintPass for TypeComplexityPass { fn check_fndecl(cx: &Context, decl: &FnDecl) { for arg in &decl.inputs { - check_type(cx, &*arg.ty); + check_type(cx, &arg.ty); } if let Return(ref ty) = decl.output { check_type(cx, ty); diff --git a/src/utils.rs b/src/utils.rs index 6cb21148356..c71d61f81e7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{ExpnInfo, Span}; -use syntax::ptr::P; use rustc::ast_map::Node::NodeExpr; use rustc::middle::ty; use std::borrow::Cow; @@ -130,9 +129,6 @@ pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { if let NodeExpr(parent) = node { Some(parent) } else { None } ) } -/// dereference a P<T> and return a ref on the result -pub fn de_p<T>(p: &P<T>) -> &T { &*p } - #[cfg(not(feature="structured_logging"))] pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); -- cgit 1.4.1-3-g733a5 From bd22521af2313bc3e68b228077373a51bc3dda23 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 17:11:34 +0200 Subject: shadowing detection --- src/shadow.rs | 67 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index bbd146f77a5..1c09bffd9e6 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -39,12 +39,6 @@ fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) { check_block(cx, block, &mut bindings); } -fn named(pat: &Pat) -> Option<Name> { - if let PatIdent(_, ident, _) = pat.node { - Some(ident.node.name) - } else { None } -} - fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { let len = bindings.len(); for stmt in &block.stmts { @@ -64,25 +58,46 @@ fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; if let &Some(ref t) = ty { check_ty(cx, t, bindings) } - check_pat(cx, pat, init, span, bindings); if let &Some(ref o) = init { check_expr(cx, o, bindings) } + check_pat(cx, pat, init, span, bindings); } } fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, bindings: &mut Vec<Name>) where T: Deref<Target=Expr> { //TODO: match more stuff / destructuring - named(pat).map(|name| { - if let &Some(ref o) = init { - if !in_external_macro(cx, o.span) { - check_expr(cx, o, bindings); + match pat.node { + PatIdent(_, ref ident, ref inner) => { + let name = ident.node.name; + if pat_is_binding(&cx.tcx.def_map, pat) { + if bindings.contains(&name) { + lint_shadow(cx, name, span, pat.span, init); + } + bindings.push(name); } - } - if bindings.contains(&name) { - lint_shadow(cx, name, span, pat.span, init); - } - bindings.push(name); - }); + if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } + }, + //PatEnum(Path, Option<Vec<P<Pat>>>), + //PatQPath(QSelf, Path), + //PatStruct(Path, Vec<Spanned<FieldPat>>, bool), + //PatTup(Vec<P<Pat>>), + PatBox(ref inner) => { + if let Some(ref initp) = *init { + match initp.node { + ExprBox(_, ref inner_init) => + check_pat(cx, inner, &Some(&**inner_init), span, bindings), + //TODO: ExprCall on Box::new + _ => check_pat(cx, inner, init, span, bindings), + } + } else { + check_pat(cx, inner, init, span, bindings); + } + }, + //PatRegion(P<Pat>, Mutability), + //PatRange(P<Expr>, P<Expr>), + //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), + _ => (), + } } fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: @@ -122,6 +137,8 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { check_expr(cx, place, bindings); check_expr(cx, e, bindings) } ExprBlock(ref block) | ExprLoop(ref block, _) => { check_block(cx, block, bindings) }, + //ExprCall + //ExprMethodCall ExprVec(ref v) | ExprTup(ref v) => for ref e in v { check_expr(cx, e, bindings) }, ExprIf(ref cond, ref then, ref otherwise) => { @@ -133,17 +150,19 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { check_expr(cx, cond, bindings); check_block(cx, block, bindings); }, - ExprMatch(ref init, ref arms, _) => + ExprMatch(ref init, ref arms, _) => { + check_expr(cx, init, bindings); for ref arm in arms { for ref pat in &arm.pats { + check_pat(cx, &pat, &Some(&**init), pat.span, bindings); //TODO: This is ugly, but needed to get the right type - check_pat(cx, pat, &Some(&**init), pat.span, bindings); } if let Some(ref guard) = arm.guard { check_expr(cx, guard, bindings); } - check_expr(cx, &*arm.body, bindings); - }, + check_expr(cx, &arm.body, bindings); + } + }, _ => () } } @@ -179,7 +198,8 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { } fn path_eq_name(name: Name, path: &Path) -> bool { - path.segments.len() == 1 && path.segments[0].identifier.name == name + !path.global && path.segments.len() == 1 && + path.segments[0].identifier.name == name } fn contains_self(name: Name, expr: &Expr) -> bool { @@ -205,8 +225,7 @@ fn contains_self(name: Name, expr: &Expr) -> bool { ExprMatch(ref e, ref arms, _) => arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat| contains_pat_self(name, pat))) || contains_self(name, e), - ExprPath(_, ref path) => path.segments.len() == 1 && - path.segments[0].identifier.name == name, + ExprPath(_, ref path) => path_eq_name(name, path), _ => false } } -- cgit 1.4.1-3-g733a5 From ffed5b0b23ff8b3602a23227ecbfe7c9998d210b Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 18:26:20 +0200 Subject: loops: use a whitelist for the "x.iter() -> &x" lint (fixes #236) --- src/loops.rs | 48 +++++++++++++++++++++++++++++++----------- src/utils.rs | 3 +-- tests/compile-fail/for_loop.rs | 24 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index ca8d3990fc5..d12393dba68 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,9 +1,11 @@ use rustc::lint::*; use syntax::ast::*; use syntax::visit::{Visitor, walk_expr}; +use rustc::middle::ty; use std::collections::HashSet; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty}; +use utils::{VEC_PATH, LL_PATH}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, "for-looping over a range of indices where an iterator over items would do" } @@ -55,18 +57,17 @@ impl LintPass for LoopsPass { if args.len() == 1 { let method_name = method.node.name; // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - if method_name == "iter" { - let object = snippet(cx, args[0].span, "_"); - span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( - "it is more idiomatic to loop over `&{}` instead of `{}.iter()`", - object, object)); - } else if method_name == "iter_mut" { - let object = snippet(cx, args[0].span, "_"); - span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( - "it is more idiomatic to loop over `&mut {}` instead of `{}.iter_mut()`", - object, object)); + if method_name == "iter" || method_name == "iter_mut" { + if is_ref_iterable_type(cx, &args[0]) { + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( + "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", + if method_name == "iter_mut" { "mut " } else { "" }, + object, object, method_name)); + } + } // check for looping over Iterator::next() which is not what you want - } else if method_name == "next" { + else if method_name == "next" { if match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { span_lint(cx, ITER_NEXT_LOOP, expr.span, "you are iterating over `Iterator::next()` which is an Option; \ @@ -134,3 +135,26 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { walk_expr(self, expr); } } + +/// Return true if the type of expr is one that provides IntoIterator impls +/// for &T and &mut T, such as Vec. +fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { + let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + println!("mt {:?} {:?}", e, ty); + is_array(ty) || + match_type(cx, ty, &VEC_PATH) || + match_type(cx, ty, &LL_PATH) || + match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) || + match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || + match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || + match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || + match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || + match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) +} + +fn is_array(ty: ty::Ty) -> bool { + match ty.sty { + ty::TyArray(..) => true, + _ => false + } +} diff --git a/src/utils.rs b/src/utils.rs index 394204bedfc..d3ab2a586ea 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -39,8 +39,7 @@ pub fn in_external_macro(cx: &Context, span: Span) -> bool { /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| iter.map(|elem| elem.name()) - .zip(path.iter()).all(|(nm, p)| nm == p)) + cx.tcx.with_path(def_id, |iter| iter.zip(path).all(|(nm, p)| nm.name() == p)) } /// check if type is struct or enum type with given def path diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index a4e3cc31a88..eb7667b7fbd 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -1,14 +1,21 @@ #![feature(plugin)] #![plugin(clippy)] +use std::collections::*; + struct Unrelated(Vec<u8>); impl Unrelated { fn next(&self) -> std::slice::Iter<u8> { self.0.iter() } + + fn iter(&self) -> std::slice::Iter<u8> { + self.0.iter() + } } #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop)] +#[allow(linkedlist)] fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; @@ -28,8 +35,25 @@ fn main() { for _v in &vec { } // these are fine for _v in &mut vec { } // these are fine + for _v in [1, 2, 3].iter() { } //~ERROR it is more idiomatic to loop over `&[ + let ll: LinkedList<()> = LinkedList::new(); + for _v in ll.iter() { } //~ERROR it is more idiomatic to loop over `&ll` + let vd: VecDeque<()> = VecDeque::new(); + for _v in vd.iter() { } //~ERROR it is more idiomatic to loop over `&vd` + let bh: BinaryHeap<()> = BinaryHeap::new(); + for _v in bh.iter() { } //~ERROR it is more idiomatic to loop over `&bh` + let hm: HashMap<(), ()> = HashMap::new(); + for _v in hm.iter() { } //~ERROR it is more idiomatic to loop over `&hm` + let bt: BTreeMap<(), ()> = BTreeMap::new(); + for _v in bt.iter() { } //~ERROR it is more idiomatic to loop over `&bt` + let hs: HashSet<()> = HashSet::new(); + for _v in hs.iter() { } //~ERROR it is more idiomatic to loop over `&hs` + let bs: BTreeSet<()> = BTreeSet::new(); + for _v in bs.iter() { } //~ERROR it is more idiomatic to loop over `&bs` + for _v in vec.iter().next() { } //~ERROR you are iterating over `Iterator::next()` let u = Unrelated(vec![]); for _v in u.next() { } // no error + for _v in u.iter() { } // no error } -- cgit 1.4.1-3-g733a5 From 6fa34cca291995df922af6c822d0078db88504d5 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 25 Aug 2015 18:38:08 +0200 Subject: methods: suggest correct replacement for `to_string()` (fixes #232) --- src/methods.rs | 16 +++++++++++++--- src/utils.rs | 11 +++++++++++ tests/compile-fail/methods.rs | 5 ++++- tests/compile-fail/strings.rs | 32 ++++++++++++++++---------------- 4 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 07693e11d99..bfe2f7984a9 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,8 +1,10 @@ use syntax::ast::*; use rustc::lint::*; use rustc::middle::ty; +use std::iter; +use std::borrow::Cow; -use utils::{span_lint, match_type, walk_ptrs_ty}; +use utils::{snippet, span_lint, match_type, walk_ptrs_ty_depth}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; #[derive(Copy,Clone)] @@ -24,7 +26,7 @@ impl LintPass for MethodsPass { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])); + let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); if ident.node.name == "unwrap" { if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, @@ -39,7 +41,15 @@ impl LintPass for MethodsPass { } else if ident.node.name == "to_string" { if obj_ty.sty == ty::TyStr { - span_lint(cx, STR_TO_STRING, expr.span, "`str.to_owned()` is faster"); + let mut arg_str = snippet(cx, args[0].span, "_"); + if ptr_depth > 1 { + arg_str = Cow::Owned(format!( + "({}{})", + iter::repeat('*').take(ptr_depth - 1).collect::<String>(), + arg_str)); + } + span_lint(cx, STR_TO_STRING, expr.span, &format!( + "`{}.to_owned()` is faster", arg_str)); } else if match_type(cx, obj_ty, &STRING_PATH) { span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \ `clone()` to make a copy"); diff --git a/src/utils.rs b/src/utils.rs index 394204bedfc..1b01d558094 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -158,6 +158,17 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { } } +/// return the base type for references and raw pointers, and count reference depth +pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { + fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { + match ty.sty { + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), + _ => (ty, depth) + } + } + inner(ty, 0) +} + /// Produce a nested chain of if-lets and ifs from the patterns: /// /// if_let_chain! { diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 91d3b72de84..811c44ef85c 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -10,6 +10,9 @@ fn main() { let res: Result<i32, ()> = Ok(0); let _ = res.unwrap(); //~ERROR used unwrap() on a Result - let string = "str".to_string(); //~ERROR `str.to_owned()` is faster + let _ = "str".to_string(); //~ERROR `"str".to_owned()` is faster + + let v = &"str"; + let string = v.to_string(); //~ERROR `(*v).to_owned()` is faster let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op } diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 680ebb73dea..7e21294a3d1 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -4,29 +4,29 @@ #[deny(string_add)] #[allow(string_add_assign)] fn add_only() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = "".to_owned(); for _ in (1..3) { x = x + "."; //~ERROR you added something to a string. } - + let y = "".to_owned(); let z = y + "..."; //~ERROR you added something to a string. - + assert_eq!(&x, &z); } #[deny(string_add_assign)] fn add_assign_only() { - let mut x = "".to_owned(); + let mut x = "".to_owned(); for _ in (1..3) { x = x + "."; //~ERROR you assigned the result of adding something to this string. } - + let y = "".to_owned(); let z = y + "..."; - + assert_eq!(&x, &z); } @@ -37,20 +37,20 @@ fn both() { for _ in (1..3) { x = x + "."; //~ERROR you assigned the result of adding something to this string. } - + let y = "".to_owned(); let z = y + "..."; //~ERROR you added something to a string. - + assert_eq!(&x, &z); } fn main() { - add_only(); - add_assign_only(); - both(); - - // the add is only caught for String - let mut x = 1; - x = x + 1; - assert_eq!(2, x); + add_only(); + add_assign_only(); + both(); + + // the add is only caught for String + let mut x = 1; + x = x + 1; + assert_eq!(2, x); } -- cgit 1.4.1-3-g733a5 From 974ceefc1e18221b1c01961a34d8866750d7690c Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 21 Aug 2015 17:11:34 +0200 Subject: shadowing detection --- src/shadow.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index 1c09bffd9e6..c4f636ae112 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -4,6 +4,8 @@ use syntax::codemap::Span; use syntax::visit::FnKind; use rustc::lint::{Context, LintArray, LintPass}; +use rustc::middle::def::Def::{DefVariant, DefStruct}; + use utils::{in_external_macro, snippet, span_lint}; declare_lint!(pub SHADOW_SAME, Allow, -- cgit 1.4.1-3-g733a5 From 9012d8f1975829a1440fde6f6fd6158a239595c4 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 25 Aug 2015 20:11:03 +0200 Subject: fixed false positives on structs/enum variants --- src/shadow.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index c4f636ae112..2c16d9d78f4 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -65,13 +65,20 @@ fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { } } +fn is_binding(cx: &Context, pat: &Pat) -> bool { + match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { + Some(DefVariant(..)) | Some(DefStruct(..)) => false, + _ => true + } +} + fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, bindings: &mut Vec<Name>) where T: Deref<Target=Expr> { //TODO: match more stuff / destructuring match pat.node { PatIdent(_, ref ident, ref inner) => { let name = ident.node.name; - if pat_is_binding(&cx.tcx.def_map, pat) { + if is_binding(cx, pat) { if bindings.contains(&name) { lint_shadow(cx, name, span, pat.span, init); } -- cgit 1.4.1-3-g733a5 From 92db00863f8940a2a53db159c8c730d881fd902c Mon Sep 17 00:00:00 2001 From: Frank Denis <github@pureftpd.org> Date: Tue, 25 Aug 2015 23:21:38 +0200 Subject: Changes for rust-nightly after #27856 --- src/len_zero.rs | 1 + src/misc.rs | 2 +- src/utils.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index ca3ce51bf7c..068568cb392 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -2,6 +2,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned}; +use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; use utils::{span_lint, walk_ptrs_ty, snippet}; diff --git a/src/misc.rs b/src/misc.rs index 2290af38bb5..b4385e298f7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -22,7 +22,7 @@ impl LintPass for TopLevelRefPass { } fn check_fn(&mut self, cx: &Context, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - if let FnKind::FkFnBlock = k { + if let FnKind::FkClosure = k { // Does not apply to closures return } diff --git a/src/utils.rs b/src/utils.rs index e4f3cc078de..ca704ebfd58 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,6 +2,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::{ExpnInfo, Span}; use rustc::ast_map::Node::NodeExpr; +use rustc::middle::def_id::DefId; use rustc::middle::ty; use std::borrow::Cow; -- cgit 1.4.1-3-g733a5 From 51a211503d5e62e7abf71a7824871ff5ef81dcab Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 25 Aug 2015 23:48:22 +0200 Subject: correct scoping for shadow lints --- src/shadow.rs | 5 ++++- tests/compile-fail/shadow.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index 2c16d9d78f4..fb840fd3258 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -81,8 +81,9 @@ fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, if is_binding(cx, pat) { if bindings.contains(&name) { lint_shadow(cx, name, span, pat.span, init); + } else { + bindings.push(name); } - bindings.push(name); } if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } }, @@ -161,6 +162,7 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { }, ExprMatch(ref init, ref arms, _) => { check_expr(cx, init, bindings); + let len = bindings.len(); for ref arm in arms { for ref pat in &arm.pats { check_pat(cx, &pat, &Some(&**init), pat.span, bindings); @@ -170,6 +172,7 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { check_expr(cx, guard, bindings); } check_expr(cx, &arm.body, bindings); + bindings.truncate(len); } }, _ => () diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index e3213717213..7098cb38877 100644 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -19,4 +19,12 @@ fn main() { let x = first(x); //~ERROR: x is shadowed by first(x) which reuses let y = 1; let x = y; //~ERROR: x is shadowed by y in this declaration + + let o = Some(1u8); + + if let Some(p) = o { assert_eq!(1, p); } + match o { + Some(p) => p, // no error, because the p above is in its own scope + None => 0, + }; } -- cgit 1.4.1-3-g733a5 From 6984d2bc09b790e762ca4e82f9070dc0fe65c515 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 26 Aug 2015 14:26:43 +0200 Subject: added helpful links to lints that have wiki entries --- src/approx_const.rs | 16 +++++++---- src/attrs.rs | 8 ++++-- src/bit_mask.rs | 68 +++++++++++++++++++++++++++++--------------- src/misc.rs | 14 +++++---- src/returns.rs | 2 +- src/shadow.rs | 26 +++++++++++------ src/strings.rs | 17 ++++++----- src/types.rs | 82 +++++++++++++++++++++++++++++++++-------------------- 8 files changed, 150 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 3e0ba4eb669..0ec2f94cab8 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -3,7 +3,7 @@ use syntax::ast::*; use syntax::codemap::Span; use std::f64::consts as f64; -use utils::span_lint; +use utils::span_help_and_lint; declare_lint! { pub APPROX_CONSTANT, @@ -40,7 +40,8 @@ fn check_lit(cx: &Context, lit: &Lit, span: Span) { match lit.node { LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), - LitFloatUnsuffixed(ref str) => check_known_consts(cx, span, str, "f{32, 64}"), + LitFloatUnsuffixed(ref str) => + check_known_consts(cx, span, str, "f{32, 64}"), _ => () } } @@ -49,13 +50,18 @@ fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { if let Ok(value) = str.parse::<f64>() { for &(constant, name) in KNOWN_CONSTS { if within_epsilon(constant, value) { - span_lint(cx, APPROX_CONSTANT, span, &format!( - "approximate value of `{}::{}` found. Consider using it directly", module, &name)); + span_help_and_lint(cx, APPROX_CONSTANT, span, &format!( + "approximate value of `{}::{}` found. \ + Consider using it directly", module, &name), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#approx_constant"); } } } } fn within_epsilon(target: f64, value: f64) -> bool { - f64::abs(value - target) < f64::abs((if target > value { target } else { value })) / EPSILON_DIVISOR + f64::abs(value - target) < f64::abs(if target > value { + target + } else { value }) / EPSILON_DIVISOR } diff --git a/src/attrs.rs b/src/attrs.rs index ad021f28a4d..a9ee9402e28 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -4,7 +4,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::ExpnInfo; -use utils::{in_macro, match_path, span_lint}; +use utils::{in_macro, match_path, span_help_and_lint}; declare_lint! { pub INLINE_ALWAYS, Warn, "`#[inline(always)]` is a bad idea in most cases" } @@ -98,10 +98,12 @@ fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, if values.len() != 1 || inline != &"inline" { continue; } if let MetaWord(ref always) = values[0].node { if always != &"always" { continue; } - span_lint(cx, INLINE_ALWAYS, attr.span, &format!( + span_help_and_lint(cx, INLINE_ALWAYS, attr.span, &format!( "you have declared `#[inline(always)]` on `{}`. This \ is usually a bad idea. Are you sure?", - ident.name)); + ident.name), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#inline_always"); } } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 6537fcf4c1a..6817dd3d97b 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -5,7 +5,7 @@ use syntax::ast::*; use syntax::ast_util::is_comparison_binop; use syntax::codemap::Span; -use utils::span_lint; +use utils::span_help_and_lint; declare_lint! { pub BAD_BIT_MASK, @@ -100,38 +100,50 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, BiEq | BiNe => match bit_op { BiBitAnd => if mask_value & cmp_value != mask_value { if cmp_value != 0 { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } } else { if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); + span_help_and_lint(cx, BAD_BIT_MASK, *span, + "&-masking with zero", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } }, BiBitOr => if mask_value | cmp_value != cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); }, _ => () }, BiLt | BiGe => match bit_op { BiBitAnd => if mask_value < cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } else { if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); + span_help_and_lint(cx, BAD_BIT_MASK, *span, + "&-masking with zero", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } }, BiBitOr => if mask_value >= cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } else { check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); }, @@ -141,19 +153,25 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, }, BiLe | BiGt => match bit_op { BiBitAnd => if mask_value <= cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } else { if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, - &format!("&-masking with zero")); + span_help_and_lint(cx, BAD_BIT_MASK, *span, + "&-masking with zero", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } }, BiBitOr => if mask_value > cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( + span_help_and_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, cmp_value)); + mask_value, cmp_value), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#bad_bit_mask"); } else { check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); }, @@ -167,17 +185,21 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, fn check_ineffective_lt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { if c.is_power_of_two() && m < c { - span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( + span_help_and_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c)); + op, m, c), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#ineffective_bit_mask"); } } fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { if (c + 1).is_power_of_two() && m <= c { - span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( + span_help_and_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c)); + op, m, c), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#ineffective_bit_mask"); } } diff --git a/src/misc.rs b/src/misc.rs index 2290af38bb5..d3d99e93b0b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,7 +6,7 @@ use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; use rustc::middle::ty; -use utils::{match_path, snippet, span_lint, walk_ptrs_ty}; +use utils::{match_path, snippet, span_lint, span_help_and_lint, walk_ptrs_ty}; use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, @@ -65,8 +65,10 @@ impl LintPass for CmpNan { fn check_nan(cx: &Context, path: &Path, span: Span) { path.segments.last().map(|seg| if seg.identifier.name == "NAN" { - span_lint(cx, CMP_NAN, span, - "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); + span_help_and_lint(cx, CMP_NAN, span, + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cmp_nan"); }); } @@ -124,9 +126,11 @@ impl LintPass for Precedence { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - span_lint(cx, PRECEDENCE, expr.span, + span_help_and_lint(cx, PRECEDENCE, expr.span, "operator precedence can trip the unwary. Consider adding parentheses \ - to the subexpression"); + to the subexpression", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#precedence"); } } } diff --git a/src/returns.rs b/src/returns.rs index 889688cb0c7..e4b14c22115 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -60,7 +60,7 @@ impl ReturnPass { fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) { span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using `{}` \ - without the trailing semicolon", + without the return and trailing semicolon", snippet(cx, spans.1, ".."))) } diff --git a/src/shadow.rs b/src/shadow.rs index fb840fd3258..717c06a4c14 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -6,7 +6,7 @@ use syntax::visit::FnKind; use rustc::lint::{Context, LintArray, LintPass}; use rustc::middle::def::Def::{DefVariant, DefStruct}; -use utils::{in_external_macro, snippet, span_lint}; +use utils::{in_external_macro, snippet, span_help_and_lint}; declare_lint!(pub SHADOW_SAME, Allow, "rebinding a name to itself, e.g. `let mut x = &mut x`"); @@ -114,26 +114,34 @@ fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: &Option<T>) where T: Deref<Target=Expr> { if let &Some(ref expr) = init { if is_self_shadow(name, expr) { - span_lint(cx, SHADOW_SAME, span, &format!( + span_help_and_lint(cx, SHADOW_SAME, span, &format!( "{} is shadowed by itself in {}", snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); + snippet(cx, expr.span, "..")), + "for further information see \ + https://github.com/Manishearth/rust-clippy/wiki#shadow_same"); } else { if contains_self(name, expr) { - span_lint(cx, SHADOW_REUSE, span, &format!( + span_help_and_lint(cx, SHADOW_REUSE, span, &format!( "{} is shadowed by {} which reuses the original value", snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); + snippet(cx, expr.span, "..")), + "for further information see https://\ + github.com/Manishearth/rust-clippy/wiki#shadow_reuse"); } else { - span_lint(cx, SHADOW_UNRELATED, span, &format!( + span_help_and_lint(cx, SHADOW_UNRELATED, span, &format!( "{} is shadowed by {} in this declaration", snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); + snippet(cx, expr.span, "..")), + "for further information see https://github.com\ + /Manishearth/rust-clippy/wiki#shadow_unrelated"); } } } else { - span_lint(cx, SHADOW_UNRELATED, span, &format!( - "{} is shadowed in this declaration", snippet(cx, lspan, "_"))); + span_help_and_lint(cx, SHADOW_UNRELATED, span, &format!( + "{} is shadowed in this declaration", snippet(cx, lspan, "_")), + "for further information see \ + https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated"); } } diff --git a/src/strings.rs b/src/strings.rs index d03f4d53c60..8e10cfaa72c 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -8,7 +8,7 @@ use syntax::ast::*; use syntax::codemap::Spanned; use eq_op::is_exp_equal; -use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::{match_type, span_help_and_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; declare_lint! { @@ -45,16 +45,19 @@ impl LintPass for StringAdd { } } } - //TODO check for duplicates - span_lint(cx, STRING_ADD, e.span, - "you added something to a string. \ - Consider using `String::push_str()` instead") + span_help_and_lint(cx, STRING_ADD, e.span, + "you added something to a string. \ + Consider using `String::push_str()` instead", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#string_add") } } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(cx, src, target) { - span_lint(cx, STRING_ADD_ASSIGN, e.span, + span_help_and_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ - Consider using `String::push_str()` instead") + Consider using `String::push_str()` instead", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#string_add_assign") } } } diff --git a/src/types.rs b/src/types.rs index 7479a65b6ee..700666d0542 100644 --- a/src/types.rs +++ b/src/types.rs @@ -32,14 +32,17 @@ impl LintPass for TypePass { span_help_and_lint( cx, BOX_VEC, ast_ty.span, "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation"); + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation. \ + for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#box_vec"); } } else if match_type(cx, ty, &LL_PATH) { span_help_and_lint( cx, LINKEDLIST, ast_ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "a RingBuf might work"); + "a RingBuf might work; for further information see \ + https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask"); } } } @@ -141,13 +144,15 @@ fn span_precision_loss_lint(cx: &Context, expr: &Expr, cast_from: &ty::TyS, cast let from_nbits_str = if arch_dependent {"64".to_owned()} else if is_isize_or_usize(cast_from) {"32 or 64".to_owned()} else {int_ty_to_nbits(cast_from).to_string()}; - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &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 arch_dependent {arch_dependent_str} else {""}, - from_nbits_str, - mantissa_nbits)); + span_help_and_lint(cx, CAST_PRECISION_LOSS, expr.span, + &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 arch_dependent {arch_dependent_str} else {""}, + from_nbits_str, + mantissa_nbits), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_precision_loss"); } enum ArchSuffix { @@ -181,22 +186,26 @@ fn check_truncation_and_wrapping(cx: &Context, expr: &Expr, cast_from: &ty::TyS, ), }; if span_truncation { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value{}", - cast_from, cast_to, - match suffix_truncation { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "" })); + span_help_and_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value{}", + cast_from, cast_to, + match suffix_truncation { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "" }), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_possible_truncation"); } if span_wrap { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value{}", - cast_from, cast_to, - match suffix_wrap { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "" })); + span_help_and_lint(cx, CAST_POSSIBLE_WRAP, expr.span, + &format!("casting {} to {} may wrap around the value{}", + cast_from, cast_to, + match suffix_wrap { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "" }), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_possible_wrap"); } } @@ -221,24 +230,37 @@ impl LintPass for CastPass { } }, (false, true) => { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value", cast_from, cast_to)); + span_help_and_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, + &format!("casting {} to {} may truncate the value", + cast_from, cast_to), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_possible_truncation"); if !cast_to.is_signed() { - span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); + span_help_and_lint(cx, CAST_SIGN_LOSS, expr.span, + &format!("casting {} to {} may lose the sign of the value", + cast_from, cast_to), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_sign_loss"); } }, (true, true) => { if cast_from.is_signed() && !cast_to.is_signed() { - span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); + span_help_and_lint(cx, CAST_SIGN_LOSS, expr.span, + &format!("casting {} to {} may lose the sign of the value", + cast_from, cast_to), + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_sign_loss"); } check_truncation_and_wrapping(cx, expr, cast_from, cast_to); } (false, false) => { if let (&ty::TyFloat(ast::TyF64), &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may truncate the value"); + span_help_and_lint(cx, CAST_POSSIBLE_TRUNCATION, + expr.span, + "casting f64 to f32 may truncate the value", + "for further information see https://github.com/\ + Manishearth/rust-clippy/wiki#cast_possible_truncation"); } } } -- cgit 1.4.1-3-g733a5 From bb552dc96fc46ff0b33bc48f7c3c48f3acf2a306 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 26 Aug 2015 17:09:37 +0200 Subject: eta_reduction: fix false positive for unsafe fns (fixes #243) --- src/eta_reduction.rs | 22 ++++++++++++++++------ tests/compile-fail/eta.rs | 7 ++++++- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 481512abc62..da2149f0539 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,8 +1,8 @@ use rustc::lint::*; use syntax::ast::*; -use syntax::print::pprust::expr_to_string; +use rustc::middle::ty; -use utils::span_lint; +use utils::{snippet, span_lint}; #[allow(missing_copy_implementations)] @@ -47,7 +47,17 @@ fn check_closure(cx: &Context, expr: &Expr) { // is no way the closure is the same as the function return; } - if args.iter().any(|arg| is_adjusted(cx, arg)) { return; } + if args.iter().any(|arg| is_adjusted(cx, arg)) { + // Are the arguments type-adjusted? Then we need the closure + return; + } + let fn_ty = cx.tcx.expr_ty(caller); + if let ty::TyBareFn(_, fn_ty) = fn_ty.sty { + // Is it an unsafe function? They don't implement the closure traits + if fn_ty.unsafety == Unsafety::Unsafe { + return; + } + } for (ref a1, ref a2) in decl.inputs.iter().zip(args) { if let PatIdent(_, ident, _) = a1.pat.node { // XXXManishearth Should I be checking the binding mode here? @@ -67,9 +77,9 @@ fn check_closure(cx: &Context, expr: &Expr) { return } } - span_lint(cx, REDUNDANT_CLOSURE, expr.span, - &format!("redundant closure found. Consider using `{}` in its place", - expr_to_string(caller))[..]) + span_lint(cx, REDUNDANT_CLOSURE, expr.span, &format!( + "redundant closure found. Consider using `{}` in its place", + snippet(cx, caller.span, ".."))); } } } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index bf6ecd79617..d53ea4e97d7 100755 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -9,9 +9,12 @@ fn main() { meta(|a| foo(a)); //~^ ERROR redundant closure found. Consider using `foo` in its place let c = Some(1u8).map(|a| {1+2; foo}(a)); - //~^ ERROR redundant closure found. Consider using `{ 1 + 2; foo }` in its place + //~^ ERROR redundant closure found. Consider using `{1+2; foo}` in its place let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted + unsafe { + Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn + } } fn meta<F>(f: F) where F: Fn(u8) { @@ -32,3 +35,5 @@ where F: Fn(&X, &X) -> bool { } fn below(x: &u8, y: &u8) -> bool { x < y } + +unsafe fn unsafe_fn(_: u8) { } -- cgit 1.4.1-3-g733a5 From 9ebcd0bf29b00226d83a1bb8b48ee9872cb67848 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 27 Aug 2015 04:01:35 +0530 Subject: More macro checks --- src/identity_op.rs | 3 ++- src/matches.rs | 4 +++- src/returns.rs | 4 +++- src/types.rs | 11 ++++------- src/utils.rs | 11 ++++++++++- 5 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/identity_op.rs b/src/identity_op.rs index cd7d6351c80..bcdd527e407 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -4,7 +4,7 @@ use syntax::codemap::Span; use consts::{constant, is_negative}; use consts::Constant::ConstantInt; -use utils::{span_lint, snippet}; +use utils::{span_lint, snippet, in_external_macro}; declare_lint! { pub IDENTITY_OP, Warn, "using identity operations, e.g. `x + 0` or `y / 1`" } @@ -53,6 +53,7 @@ fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { 1 => !is_negative(ty) && v == 1, _ => unreachable!(), } { + if in_external_macro(cx, e.span) {return;} span_lint(cx, IDENTITY_OP, span, &format!( "the operation is ineffective. Consider reducing it to `{}`", snippet(cx, arg, ".."))); diff --git a/src/matches.rs b/src/matches.rs index d1c74daf2cd..1afb61e9b9e 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -3,7 +3,8 @@ use syntax::ast; use syntax::ast::*; use std::borrow::Cow; -use utils::{snippet, snippet_block, span_lint, span_help_and_lint}; +use utils::{snippet, snippet_block}; +use utils::{span_lint, span_help_and_lint, in_external_macro}; declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ @@ -36,6 +37,7 @@ impl LintPass for MatchPass { // finally, we don't want any content in the second arm (unit or empty block) is_unit_expr(&arms[1].body) { + if in_external_macro(cx, expr.span) {return;} let body_code = snippet_block(cx, arms[0].body.span, ".."); let body_code = if let ExprBlock(_) = arms[0].body.node { body_code diff --git a/src/returns.rs b/src/returns.rs index e4b14c22115..29749b29435 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -3,7 +3,7 @@ use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; -use utils::{span_lint, snippet, match_path}; +use utils::{span_lint, snippet, match_path, in_external_macro}; declare_lint!(pub NEEDLESS_RETURN, Warn, "using a return statement like `return expr;` where an expression would suffice"); @@ -58,6 +58,7 @@ impl ReturnPass { } fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) { + if in_external_macro(cx, spans.1) {return;} span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using `{}` \ without the return and trailing semicolon", @@ -84,6 +85,7 @@ impl ReturnPass { } fn emit_let_lint(&mut self, cx: &Context, lint_span: Span, note_span: Span) { + if in_external_macro(cx, note_span) {return;} span_lint(cx, LET_AND_RETURN, lint_span, "returning the result of a let binding. \ Consider returning the expression directly."); diff --git a/src/types.rs b/src/types.rs index 700666d0542..12f31ae89dd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,9 +5,8 @@ use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; use syntax::visit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; -use syntax::codemap::ExpnInfo; -use utils::{in_macro, match_type, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{match_type, snippet, span_lint, span_help_and_lint, in_external_macro}; use utils::{LL_PATH, VEC_PATH}; /// Handles all the linting of funky types @@ -55,11 +54,11 @@ declare_lint!(pub LET_UNIT_VALUE, Warn, "creating a let binding to a value of unit type, which usually can't be used afterwards"); -fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) { - if in_macro(cx, info) { return; } +fn check_let_unit(cx: &Context, decl: &Decl) { if let DeclLocal(ref local) = decl.node { let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { + if in_external_macro(cx, decl.span) { return; } span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( "this let-binding has unit value. Consider omitting `let {} =`", snippet(cx, local.pat.span, ".."))); @@ -73,9 +72,7 @@ impl LintPass for LetPass { } fn check_decl(&mut self, cx: &Context, decl: &Decl) { - cx.sess().codemap().with_expn_info( - decl.span.expn_id, - |info| check_let_unit(cx, decl, info)); + check_let_unit(cx, decl) } } diff --git a/src/utils.rs b/src/utils.rs index b7bb14bd2f0..ece1eee9050 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use syntax::ast::*; -use syntax::codemap::{ExpnInfo, Span}; +use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use rustc::ast_map::Node::NodeExpr; use rustc::middle::def_id::DefId; use rustc::middle::ty; @@ -18,6 +18,14 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { + if info.callee.format == ExpnFormat::CompilerExpansion { + if info.callee.name == "closure expansion" { + return false; + } + } else if info.callee.format == ExpnFormat::MacroAttribute { + // these are all plugins + return true; + } // no span for the callee = external macro info.callee.span.map_or(true, |span| { // no snippet = external macro or compiler-builtin expansion @@ -31,6 +39,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { } /// invokes in_macro with the expansion info of the given span +/// slightly heavy, try to use this after other checks have already happened pub fn in_external_macro(cx: &Context, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro(cx, info)) -- cgit 1.4.1-3-g733a5 From 5159e034a67587bfecfd3368a9cb9691ab20e440 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 27 Aug 2015 04:40:01 +0530 Subject: appease the dogfood gods --- src/consts.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 1a828317fc2..29b96146db2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,3 +1,5 @@ +#![allow(cast_possible_truncation)] + use rustc::lint::Context; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; -- cgit 1.4.1-3-g733a5 From 621818e6061e693c57a494742ba4094029a855c0 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 28 Aug 2015 14:35:20 +0200 Subject: rustup, the ExpnInfo stuff changed --- src/utils.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 69f5e22c48f..b6fae89fc31 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,13 +18,17 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { - if info.callee.format == ExpnFormat::CompilerExpansion { - if info.callee.name == "closure expansion" { - return false; - } - } else if info.callee.format == ExpnFormat::MacroAttribute { - // these are all plugins - return true; + match info.callee.format { + ExpnFormat::CompilerExpansion(..) => { + if info.callee.name() == "closure expansion" { + return false; + } + }, + ExpnFormat::MacroAttribute(..) => { + // these are all plugins + return true; + }, + _ => (), } // no span for the callee = external macro info.callee.span.map_or(true, |span| { -- cgit 1.4.1-3-g733a5 From 6461fb3308ee52a04b4856896909fb6974ae4a81 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 30 Aug 2015 09:57:52 +0200 Subject: lifetimes lint: take "where" clauses into account (fixes #253) If a where clause is present and has lifetimes mentioned, just bail out. --- src/lifetimes.rs | 30 ++++++++++++++++++++++++------ tests/compile-fail/lifetimes.rs | 6 ++++++ 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 660d68535bd..bff0db14f7b 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -20,21 +20,21 @@ impl LintPass for LifetimePass { fn check_item(&mut self, cx: &Context, item: &Item) { if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { - check_fn_inner(cx, decl, None, &generics.lifetimes, item.span); + check_fn_inner(cx, decl, None, &generics, item.span); } } fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { if let MethodImplItem(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), - &sig.generics.lifetimes, item.span); + &sig.generics, item.span); } } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), - &sig.generics.lifetimes, item.span); + &sig.generics, item.span); } } } @@ -49,11 +49,11 @@ enum RefLt { use self::RefLt::*; fn check_fn_inner(cx: &Context, decl: &FnDecl, slf: Option<&ExplicitSelf>, - named_lts: &[LifetimeDef], span: Span) { - if in_external_macro(cx, span) { + generics: &Generics, span: Span) { + if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) { return; } - if could_use_elision(decl, slf, named_lts) { + if could_use_elision(decl, slf, &generics.lifetimes) { span_lint(cx, NEEDLESS_LIFETIMES, span, "explicit lifetimes given in parameter types where they could be elided"); } @@ -182,3 +182,21 @@ impl<'v> Visitor<'v> for RefVisitor { // for lifetime bounds; the default impl calls visit_lifetime_ref fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { } } + +/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to +/// reason about elision. +fn has_where_lifetimes(where_clause: &WhereClause) -> bool { + let mut where_visitor = RefVisitor(Vec::new()); + for predicate in &where_clause.predicates { + match *predicate { + WherePredicate::RegionPredicate(..) => return true, + WherePredicate::BoundPredicate(ref pred) => { + walk_ty(&mut where_visitor, &pred.bounded_ty); + } + WherePredicate::EqPredicate(ref pred) => { + walk_ty(&mut where_visitor, &pred.ty); + } + } + } + !where_visitor.into_vec().is_empty() +} diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index a5597e6478f..ae115efec04 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -31,6 +31,10 @@ fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // n fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } //~^ERROR explicit lifetimes given +// where clause, but without lifetimes +fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) } +//~^ERROR explicit lifetimes given + type Ref<'r> = &'r u8; fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params @@ -40,6 +44,8 @@ fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { } fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime + struct X { x: u8, } -- cgit 1.4.1-3-g733a5 From b72ef5a1731490778cb8ad7fb42e170a4e46ae13 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 29 Aug 2015 11:41:06 +0200 Subject: new lint: loop-match-break, which could be while-let (fixes #118) --- README.md | 3 +- src/lib.rs | 1 + src/loops.rs | 65 ++++++++++++++++++++++++++++++++++++++-- src/matches.rs | 13 ++------ src/utils.rs | 10 +++++++ tests/compile-fail/while_loop.rs | 52 ++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 15 deletions(-) create mode 100755 tests/compile-fail/while_loop.rs (limited to 'src') diff --git a/README.md b/README.md index 478bb25272f..92a03b31530 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 49 lints included in this crate: +There are 50 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -56,6 +56,7 @@ name [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/lib.rs b/src/lib.rs index 32fc953d1c3..d69d352abc6 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, + loops::WHILE_LET_LOOP, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::OPTION_UNWRAP_USED, diff --git a/src/loops.rs b/src/loops.rs index d12393dba68..eba706ed7e1 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -4,7 +4,8 @@ use syntax::visit::{Visitor, walk_expr}; use rustc::middle::ty; use std::collections::HashSet; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty, + in_external_macro, expr_block, span_help_and_lint}; use utils::{VEC_PATH, LL_PATH}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, @@ -16,12 +17,16 @@ declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } +declare_lint!{ pub WHILE_LET_LOOP, Warn, + "`loop { if let { ... } else break }` can be written as a `while let` loop" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP) + lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, + WHILE_LET_LOOP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -36,7 +41,8 @@ impl LintPass for LoopsPass { walk_expr(&mut visitor, body); // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().expect("Len was nonzero, but no contents found"); + let indexed = visitor.indexed.into_iter().next().expect( + "Len was nonzero, but no contents found"); if visitor.nonindex { span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( "the loop variable `{}` is used to index `{}`. Consider using \ @@ -77,6 +83,34 @@ impl LintPass for LoopsPass { } } } + // check for `loop { if let {} else break }` that could be `while let` + // (also matches explicit "match" instead of "if let") + if let ExprLoop(ref block, _) = expr.node { + // extract a single expression + if let Some(inner) = extract_single_expr(block) { + if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { + // ensure "if let" compatible match structure + match *source { + MatchSource::Normal | MatchSource::IfLetDesugar{..} => if + arms.len() == 2 && + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + // finally, check for "break" in the second clause + is_break_expr(&arms[1].body) + { + if in_external_macro(cx, expr.span) { return; } + span_help_and_lint(cx, WHILE_LET_LOOP, expr.span, + "this loop could be written as a `while let` loop", + &format!("try\nwhile let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, ".."), + expr_block(cx, &arms[0].body, ".."))); + }, + _ => () + } + } + } + } } } @@ -158,3 +192,28 @@ fn is_array(ty: ty::Ty) -> bool { _ => false } } + +/// If block consists of a single expression (with or without semicolon), return it. +fn extract_single_expr(block: &Block) -> Option<&Expr> { + match (&block.stmts.len(), &block.expr) { + (&1, &None) => match block.stmts[0].node { + StmtExpr(ref expr, _) | + StmtSemi(ref expr, _) => Some(expr), + _ => None, + }, + (&0, &Some(ref expr)) => Some(expr), + _ => None + } +} + +/// Return true if expr contains a single break expr (maybe within a block). +fn is_break_expr(expr: &Expr) -> bool { + match expr.node { + ExprBreak(None) => true, + ExprBlock(ref b) => match extract_single_expr(b) { + Some(ref subexpr) => is_break_expr(subexpr), + None => false, + }, + _ => false, + } +} diff --git a/src/matches.rs b/src/matches.rs index 1afb61e9b9e..3d04c9210ce 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,10 +1,8 @@ use rustc::lint::*; use syntax::ast; use syntax::ast::*; -use std::borrow::Cow; -use utils::{snippet, snippet_block}; -use utils::{span_lint, span_help_and_lint, in_external_macro}; +use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ @@ -38,12 +36,6 @@ impl LintPass for MatchPass { is_unit_expr(&arms[1].body) { if in_external_macro(cx, expr.span) {return;} - let body_code = snippet_block(cx, arms[0].body.span, ".."); - let body_code = if let ExprBlock(_) = arms[0].body.node { - body_code - } else { - Cow::Owned(format!("{{ {} }}", body_code)) - }; span_help_and_lint(cx, SINGLE_MATCH, expr.span, "you seem to be trying to use match for \ destructuring a single pattern. Did you mean to \ @@ -51,8 +43,7 @@ impl LintPass for MatchPass { &format!("try\nif let {} = {} {}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), - body_code) - ); + expr_block(cx, &arms[0].body, ".."))); } // check preconditions for MATCH_REF_PATS diff --git a/src/utils.rs b/src/utils.rs index b6fae89fc31..f16387f606d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -103,6 +103,16 @@ pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, trim_multiline(snip, true) } +/// Like snippet_block, but add braces if the expr is not an ExprBlock +pub fn expr_block<'a>(cx: &Context, expr: &Expr, default: &'a str) -> Cow<'a, str> { + let code = snippet_block(cx, expr.span, default); + if let ExprBlock(_) = expr.node { + code + } else { + Cow::Owned(format!("{{ {} }}", code)) + } +} + /// Trim indentation from a multiline string /// with possibility of ignoring the first line pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs new file mode 100755 index 00000000000..bc09168fad0 --- /dev/null +++ b/tests/compile-fail/while_loop.rs @@ -0,0 +1,52 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(while_let_loop)] +fn main() { + let y = Some(true); + loop { //~ERROR + if let Some(_x) = y { + let _v = 1; + } else { + break; + } + } + loop { //~ERROR + if let Some(_x) = y { + let _v = 1; + } else { + break + } + } + loop { // no error, break is not in else clause + if let Some(_x) = y { + let _v = 1; + } + break; + } + loop { //~ERROR + match y { + Some(_x) => true, + None => break + }; + } + loop { // no error, match is not the only statement + match y { + Some(_x) => true, + None => break + }; + let _x = 1; + } + loop { // no error, else branch does something other than break + match y { + Some(_x) => true, + _ => { + let _z = 1; + break; + } + }; + } + while let Some(x) = y { // no error, obviously + println!("{}", x); + } +} -- cgit 1.4.1-3-g733a5 From 16df79a0549ba44afdfcecfbb3cbb210d2a7863f Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 30 Aug 2015 13:10:59 +0200 Subject: new lint: using collect() to just exhaust an iterator Should use a for loop instead. --- README.md | 3 ++- src/lib.rs | 1 + src/loops.rs | 20 +++++++++++++++++++- tests/compile-fail/for_loop.rs | 5 +++++ 4 files changed, 27 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 92a03b31530..4d5c59f2aef 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 50 lints included in this crate: +There are 51 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -56,6 +56,7 @@ name [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing diff --git a/src/lib.rs b/src/lib.rs index d69d352abc6..5e9205e32f9 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, + loops::UNUSED_COLLECT, loops::WHILE_LET_LOOP, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, diff --git a/src/loops.rs b/src/loops.rs index eba706ed7e1..fe901794d6c 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -20,13 +20,17 @@ declare_lint!{ pub ITER_NEXT_LOOP, Warn, declare_lint!{ pub WHILE_LET_LOOP, Warn, "`loop { if let { ... } else break }` can be written as a `while let` loop" } +declare_lint!{ pub UNUSED_COLLECT, Warn, + "`collect()`ing an iterator without using the result; this is usually better \ + written as a for loop" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP) + WHILE_LET_LOOP, UNUSED_COLLECT) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -112,6 +116,20 @@ impl LintPass for LoopsPass { } } } + + fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) { + if let StmtSemi(ref expr, _) = stmt.node { + if let ExprMethodCall(ref method, _, ref args) = expr.node { + if args.len() == 1 && method.node.name == "collect" { + if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + span_lint(cx, UNUSED_COLLECT, expr.span, &format!( + "you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator")); + } + } + } + } + } } /// Recover the essential nodes of a desugared for loop: diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index eb7667b7fbd..66838651356 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -15,6 +15,7 @@ impl Unrelated { } #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop)] +#[deny(unused_collect)] #[allow(linkedlist)] fn main() { let mut vec = vec![1, 2, 3, 4]; @@ -56,4 +57,8 @@ fn main() { let u = Unrelated(vec![]); for _v in u.next() { } // no error for _v in u.iter() { } // no error + + let mut out = vec![]; + vec.iter().map(|x| out.push(x)).collect::<Vec<_>>(); //~ERROR you are collect()ing an iterator + let _y = vec.iter().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine } -- cgit 1.4.1-3-g733a5 From ef0c933550937ed0db47fb9da9f0aa32e75c865b Mon Sep 17 00:00:00 2001 From: Tim Neumann <mail@timnn.me> Date: Sun, 30 Aug 2015 17:32:35 +0200 Subject: add precedence_negative_literal lint --- README.md | 2 +- src/lib.rs | 5 ++-- src/misc.rs | 44 --------------------------- src/precedence.rs | 65 ++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/precedence.rs | 10 +++++++ 5 files changed, 79 insertions(+), 47 deletions(-) create mode 100644 src/precedence.rs (limited to 'src') diff --git a/README.md b/README.md index 4d5c59f2aef..1a1b6fe5956 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ name [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | expressions where precedence may trip up the unwary reader of the source; suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)` +[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively [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 [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) diff --git a/src/lib.rs b/src/lib.rs index 5e9205e32f9..c72c5b1d7a7 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ pub mod lifetimes; pub mod loops; pub mod ranges; pub mod matches; +pub mod precedence; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -52,7 +53,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); reg.register_lint_pass(box misc::FloatCmp as LintPassObject); - reg.register_lint_pass(box misc::Precedence as LintPassObject); + reg.register_lint_pass(box precedence::Precedence as LintPassObject); reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); @@ -109,10 +110,10 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::CMP_OWNED, misc::FLOAT_CMP, misc::MODULO_ONE, - misc::PRECEDENCE, misc::TOPLEVEL_REF_ARG, mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, + precedence::PRECEDENCE, ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, diff --git a/src/misc.rs b/src/misc.rs index 6e438407216..ef9f4248c0c 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -109,50 +109,6 @@ fn is_float(cx: &Context, expr: &Expr) -> bool { } } -declare_lint!(pub PRECEDENCE, Warn, - "expressions where precedence may trip up the unwary reader of the source; \ - suggests adding parentheses, e.g. `x << 2 + y` will be parsed as `x << (2 + y)`"); - -#[derive(Copy,Clone)] -pub struct Precedence; - -impl LintPass for Precedence { - fn get_lints(&self) -> LintArray { - lint_array!(PRECEDENCE) - } - - fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { - if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - span_lint(cx, PRECEDENCE, expr.span, - "operator precedence can trip the unwary. Consider adding parentheses \ - to the subexpression"); - } - } - } -} - -fn is_arith_expr(expr : &Expr) -> bool { - match expr.node { - ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), - _ => false - } -} - -fn is_bit_op(op : BinOp_) -> bool { - match op { - BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, - _ => false - } -} - -fn is_arith_op(op : BinOp_) -> bool { - match op { - BiAdd | BiSub | BiMul | BiDiv | BiRem => true, - _ => false - } -} - declare_lint!(pub CMP_OWNED, Warn, "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"); diff --git a/src/precedence.rs b/src/precedence.rs new file mode 100644 index 00000000000..1d89adf9df8 --- /dev/null +++ b/src/precedence.rs @@ -0,0 +1,65 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::codemap::Spanned; + +use utils::span_lint; + +declare_lint!(pub PRECEDENCE, Warn, + "catches operations where precedence may be unclear. See the wiki for a \ + list of cases caught"); + +#[derive(Copy,Clone)] +pub struct Precedence; + +impl LintPass for Precedence { + fn get_lints(&self) -> LintArray { + lint_array!(PRECEDENCE) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { + if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { + span_lint(cx, PRECEDENCE, expr.span, + "operator precedence can trip the unwary. Consider adding parentheses \ + to the subexpression"); + } + } + + if let ExprUnary(UnNeg, ref rhs) = expr.node { + if let ExprMethodCall(_, _, ref args) = rhs.node { + if let Some(slf) = args.first() { + if let ExprLit(ref lit) = slf.node { + match lit.node { + LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => + span_lint(cx, PRECEDENCE, expr.span, + "unary minus has lower precedence than method call. Consider \ + adding parentheses to clarify your intent"), + _ => () + } + } + } + } + } + } +} + +fn is_arith_expr(expr : &Expr) -> bool { + match expr.node { + ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), + _ => false + } +} + +fn is_bit_op(op : BinOp_) -> bool { + match op { + BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, + _ => false + } +} + +fn is_arith_op(op : BinOp_) -> bool { + match op { + BiAdd | BiSub | BiMul | BiDiv | BiRem => true, + _ => false + } +} diff --git a/tests/compile-fail/precedence.rs b/tests/compile-fail/precedence.rs index ebb25f61b75..71dcd493008 100755 --- a/tests/compile-fail/precedence.rs +++ b/tests/compile-fail/precedence.rs @@ -13,4 +13,14 @@ fn main() { format!("{} vs. {}", 3 | 2 - 1, (3 | 2) - 1); //~ERROR operator precedence can trip format!("{} vs. {}", 3 & 5 - 2, (3 & 5) - 2); //~ERROR operator precedence can trip + format!("{} vs. {}", -1i32.abs(), (-1i32).abs()); //~ERROR unary minus has lower precedence + format!("{} vs. {}", -1f32.abs(), (-1f32).abs()); //~ERROR unary minus has lower precedence + + // These should not trigger an error + let _ = (-1i32).abs(); + let _ = (-1f32).abs(); + let _ = -(1i32).abs(); + let _ = -(1f32).abs(); + let _ = -(1i32.abs()); + let _ = -(1f32.abs()); } -- cgit 1.4.1-3-g733a5 From 03abe275b212890416b3015da8c2b323e946f424 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 30 Aug 2015 19:02:30 +0200 Subject: new lint: unnecessary patterns (x@_ -> x) --- README.md | 3 ++- src/lib.rs | 2 ++ src/misc.rs | 21 +++++++++++++++++++++ tests/compile-fail/patterns.rs | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100755 tests/compile-fail/patterns.rs (limited to 'src') diff --git a/README.md b/README.md index 4d5c59f2aef..cb9ee6671f3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 51 lints included in this crate: +There are 52 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -43,6 +43,7 @@ name [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively [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 [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled [shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` diff --git a/src/lib.rs b/src/lib.rs index 5e9205e32f9..d3f45af0754 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::CastPass as LintPassObject); reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); reg.register_lint_pass(box matches::MatchPass as LintPassObject); + reg.register_lint_pass(box misc::PatternPass as LintPassObject); reg.register_lint_group("shadow", vec![ shadow::SHADOW_REUSE, @@ -110,6 +111,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::FLOAT_CMP, misc::MODULO_ONE, misc::PRECEDENCE, + misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, diff --git a/src/misc.rs b/src/misc.rs index 6e438407216..ccf67b0fae0 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -235,3 +235,24 @@ fn is_lit_one(expr: &Expr) -> bool { } false } + +declare_lint!(pub REDUNDANT_PATTERN, Warn, "using `name @ _` in a pattern"); + +#[derive(Copy,Clone)] +pub struct PatternPass; + +impl LintPass for PatternPass { + fn get_lints(&self) -> LintArray { + lint_array!(REDUNDANT_PATTERN) + } + + fn check_pat(&mut self, cx: &Context, pat: &Pat) { + if let PatIdent(_, ref ident, Some(ref right)) = pat.node { + if right.node == PatWild(PatWildSingle) { + cx.span_lint(REDUNDANT_PATTERN, pat.span, &format!( + "the `{} @ _` pattern can be written as just `{}`", + ident.node.name, ident.node.name)); + } + } + } +} diff --git a/tests/compile-fail/patterns.rs b/tests/compile-fail/patterns.rs new file mode 100755 index 00000000000..62bd2c43cc1 --- /dev/null +++ b/tests/compile-fail/patterns.rs @@ -0,0 +1,16 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused)] +#![deny(clippy)] + +fn main() { + let v = Some(true); + match v { + Some(x) => (), + y @ _ => (), //~ERROR the `y @ _` pattern can be written as just `y` + } + match v { + Some(x) => (), + y @ None => (), // no error + } +} -- cgit 1.4.1-3-g733a5 From d499d2a9a7c481a233fec1bf37245d20a44e7af5 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 31 Aug 2015 08:19:11 +0200 Subject: loops: remove debugging print --- src/loops.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index fe901794d6c..f6247dd8419 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -192,7 +192,6 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { /// for &T and &mut T, such as Vec. fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); - println!("mt {:?} {:?}", e, ty); is_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || -- cgit 1.4.1-3-g733a5 From 0217fb81ee80776899440f997a8b71212dbfe17a Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 31 Aug 2015 08:29:34 +0200 Subject: loops: fix false positives with explicit_iter_loop and references (fixes #261) --- src/loops.rs | 6 ++++-- tests/compile-fail/for_loop.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index f6247dd8419..33401dc67e1 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -4,7 +4,7 @@ use syntax::visit::{Visitor, walk_expr}; use rustc::middle::ty; use std::collections::HashSet; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty, +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint}; use utils::{VEC_PATH, LL_PATH}; @@ -191,7 +191,9 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { /// Return true if the type of expr is one that provides IntoIterator impls /// for &T and &mut T, such as Vec. fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { - let ty = walk_ptrs_ty(cx.tcx.expr_ty(e)); + // no walk_ptrs_ty: calling iter() on a reference can make sense because it + // will allow further borrows afterwards + let ty = cx.tcx.expr_ty(e); is_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 66838651356..f2540bfd595 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -37,6 +37,7 @@ fn main() { for _v in &mut vec { } // these are fine for _v in [1, 2, 3].iter() { } //~ERROR it is more idiomatic to loop over `&[ + for _v in (&mut [1, 2, 3]).iter() { } // no error let ll: LinkedList<()> = LinkedList::new(); for _v in ll.iter() { } //~ERROR it is more idiomatic to loop over `&ll` let vd: VecDeque<()> = VecDeque::new(); -- cgit 1.4.1-3-g733a5 From e33bef685ef43cdefad624e73536927e766dec1e Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 31 Aug 2015 11:11:51 +0200 Subject: lifetimes lint: walk type bounds as well as types (fixes #253, again) --- src/lifetimes.rs | 48 ++++++++++++++++++++++++++++++----------- tests/compile-fail/lifetimes.rs | 12 +++++++++++ 2 files changed, 47 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index bff0db14f7b..de7a39fdb3b 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -1,7 +1,7 @@ use syntax::ast::*; use rustc::lint::*; use syntax::codemap::Span; -use syntax::visit::{Visitor, walk_ty}; +use syntax::visit::{Visitor, walk_ty, walk_ty_param_bound}; use std::collections::HashSet; use utils::{in_external_macro, span_lint}; @@ -68,14 +68,7 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, // level of the current item. // check named LTs - let mut allowed_lts = HashSet::new(); - for lt in named_lts { - if lt.bounds.is_empty() { - allowed_lts.insert(Named(lt.lifetime.name)); - } - } - allowed_lts.insert(Unnamed); - allowed_lts.insert(Static); + let allowed_lts = allowed_lts_from(named_lts); // these will collect all the lifetimes for references in arg/return types let mut input_visitor = RefVisitor(Vec::new()); @@ -142,6 +135,18 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, false } +fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { + let mut allowed_lts = HashSet::new(); + for lt in named_lts { + if lt.bounds.is_empty() { + allowed_lts.insert(Named(lt.lifetime.name)); + } + } + allowed_lts.insert(Unnamed); + allowed_lts.insert(Static); + allowed_lts +} + /// Number of unique lifetimes in the given vector. fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::<HashSet<_>>().len() @@ -186,17 +191,34 @@ impl<'v> Visitor<'v> for RefVisitor { /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to /// reason about elision. fn has_where_lifetimes(where_clause: &WhereClause) -> bool { - let mut where_visitor = RefVisitor(Vec::new()); for predicate in &where_clause.predicates { match *predicate { WherePredicate::RegionPredicate(..) => return true, WherePredicate::BoundPredicate(ref pred) => { - walk_ty(&mut where_visitor, &pred.bounded_ty); + // a predicate like F: Trait or F: for<'a> Trait<'a> + let mut visitor = RefVisitor(Vec::new()); + // walk the type F, it may not contain LT refs + walk_ty(&mut visitor, &pred.bounded_ty); + if !visitor.0.is_empty() { return true; } + // if the bounds define new lifetimes, they are fine to occur + let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); + // now walk the bounds + for bound in pred.bounds.iter() { + walk_ty_param_bound(&mut visitor, bound); + } + // and check that all lifetimes are allowed + for lt in visitor.into_vec() { + if !allowed_lts.contains(<) { + return true; + } + } } WherePredicate::EqPredicate(ref pred) => { - walk_ty(&mut where_visitor, &pred.ty); + let mut visitor = RefVisitor(Vec::new()); + walk_ty(&mut visitor, &pred.ty); + if !visitor.0.is_empty() { return true; } } } } - !where_visitor.into_vec().is_empty() + false } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index ae115efec04..0b24ca65241 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -46,6 +46,18 @@ fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounde fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime +struct Lt<'a, I: 'static> { + x: &'a I +} + +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> + where F: Fn(Lt<'a, I>) -> Lt<'a, I> // no error, fn bound references 'a +{ unreachable!() } + +fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> //~ERROR explicit lifetimes given + where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I> +{ unreachable!() } + struct X { x: u8, } -- cgit 1.4.1-3-g733a5 From 833493cf0711f7ca9ac778c4ea8d1410777be85d Mon Sep 17 00:00:00 2001 From: Frank Denis <github@pureftpd.org> Date: Tue, 1 Sep 2015 14:28:23 +0200 Subject: FnKind::FkClosure -> FnKind::Closure --- src/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 26493080d87..b9d74c645b7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -22,7 +22,7 @@ impl LintPass for TopLevelRefPass { } fn check_fn(&mut self, cx: &Context, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - if let FnKind::FkClosure = k { + if let FnKind::Closure = k { // Does not apply to closures return } -- cgit 1.4.1-3-g733a5 From 88dd38de8771069b44b5ea52917c749d35bbc9b8 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 1 Sep 2015 17:53:56 +0200 Subject: lib: add clippy_pedantic group with all Allow by default lints (fixes #265) --- src/lib.rs | 25 +++++++++++-------------- tests/compile-fail/methods.rs | 2 +- tests/compile-fail/shadow.rs | 6 +++--- util/dogfood.sh | 2 +- util/update_lints.py | 29 ++++++++++++++++++++--------- 5 files changed, 36 insertions(+), 28 deletions(-) mode change 100644 => 100755 tests/compile-fail/shadow.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 7d6876ad839..f4da8b03bc2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,10 +77,19 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box matches::MatchPass as LintPassObject); reg.register_lint_pass(box misc::PatternPass as LintPassObject); - reg.register_lint_group("shadow", vec![ + reg.register_lint_group("clippy_pedantic", vec![ + methods::OPTION_UNWRAP_USED, + methods::RESULT_UNWRAP_USED, + ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, - shadow::SHADOW_UNRELATED, + strings::STRING_ADD, + strings::STRING_ADD_ASSIGN, + types::CAST_POSSIBLE_TRUNCATION, + types::CAST_POSSIBLE_WRAP, + types::CAST_PRECISION_LOSS, + types::CAST_SIGN_LOSS, + unicode::NON_ASCII_LITERAL, ]); reg.register_lint_group("clippy", vec![ @@ -102,8 +111,6 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::WHILE_LET_LOOP, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, - methods::OPTION_UNWRAP_USED, - methods::RESULT_UNWRAP_USED, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, @@ -116,25 +123,15 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, precedence::PRECEDENCE, - ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, - shadow::SHADOW_REUSE, - shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, - strings::STRING_ADD, - strings::STRING_ADD_ASSIGN, types::BOX_VEC, - types::CAST_POSSIBLE_TRUNCATION, - types::CAST_POSSIBLE_WRAP, - types::CAST_PRECISION_LOSS, - types::CAST_SIGN_LOSS, types::LET_UNIT_VALUE, types::LINKEDLIST, types::TYPE_COMPLEXITY, types::UNIT_CMP, - unicode::NON_ASCII_LITERAL, unicode::ZERO_WIDTH_SPACE, ]); } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 05f77c1511e..1c81fefc4e5 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![allow(unused)] -#![deny(clippy)] +#![deny(clippy, clippy_pedantic)] use std::ops::Mul; diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs old mode 100644 new mode 100755 index 7098cb38877..8ac9a93b140 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![allow(unused_parens, unused_variables)] -#![deny(shadow)] +#![deny(clippy, clippy_pedantic)] fn id<T>(x: T) -> T { x } @@ -19,9 +19,9 @@ fn main() { let x = first(x); //~ERROR: x is shadowed by first(x) which reuses let y = 1; let x = y; //~ERROR: x is shadowed by y in this declaration - + let o = Some(1u8); - + if let Some(p) = o { assert_eq!(1, p); } match o { Some(p) => p, // no error, because the p above is in its own scope diff --git a/util/dogfood.sh b/util/dogfood.sh index e98d18c40d5..5ba8b4efa17 100755 --- a/util/dogfood.sh +++ b/util/dogfood.sh @@ -1,5 +1,5 @@ #!/bin/sh rm -rf target*/*so -cargo build --lib && cp -R target target_recur && cargo rustc -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy || exit 1 +cargo build --lib && cp -R target target_recur && cargo rustc -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy || exit 1 rm -rf target_recur diff --git a/util/update_lints.py b/util/update_lints.py index 8c00f1b4f13..94b2a3a57ba 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -38,7 +38,7 @@ def gen_table(lints, link=None): """Write lint table in Markdown format.""" if link: lints = [(p, '[%s](%s#%s)' % (l, link, l), lvl, d) - for (p, l, lvl, d) in lints] + for (p, l, lvl, d) in lints] # first and third column widths w_name = max(len(l[1]) for l in lints) w_desc = max(len(l[3]) for l in lints) @@ -50,8 +50,10 @@ def gen_table(lints, link=None): yield '%-*s | %-7s | %s\n' % (w_name, name, default, meaning) -def gen_group(lints): +def gen_group(lints, levels=None): """Write lint group (list of all lints in the form module::NAME).""" + if levels: + lints = [tup for tup in lints if tup[2] in levels] for (module, name, _, _) in sorted(lints): yield ' %s::%s,\n' % (module, name.upper()) @@ -113,19 +115,28 @@ def main(print_only=False, check=False): return # replace table in README.md - changed = replace_region('README.md', r'^name +\|', '^$', - lambda: gen_table(lints, link=wiki_link), - write_back=not check) + changed = replace_region( + 'README.md', r'^name +\|', '^$', + lambda: gen_table(lints, link=wiki_link), + write_back=not check) - changed |= replace_region('README.md', + changed |= replace_region( + 'README.md', r'^There are \d+ lints included in this crate:', "", lambda: ['There are %d lints included in this crate:\n' % len(lints)], write_back=not check) # same for "clippy" lint collection - changed |= replace_region('src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', - lambda: gen_group(lints), replace_start=False, - write_back=not check) + changed |= replace_region( + 'src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', + lambda: gen_group(lints, levels=('warn', 'deny')), + replace_start=False, write_back=not check) + + # same for "clippy_pedantic" lint collection + changed |= replace_region( + 'src/lib.rs', r'reg.register_lint_group\("clippy_pedantic"', r'\]\);', + lambda: gen_group(lints, levels=('allow',)), + replace_start=False, write_back=not check) if check and changed: print('Please run util/update_lints.py to regenerate lints lists.') -- cgit 1.4.1-3-g733a5 From 100786419807ac5365185b659d46acc67f5b1ccf Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 1 Sep 2015 18:52:48 +0200 Subject: new lint: self conventions for certain method names (fixes #267) --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 68 ++++++++++++++++++++++++++++++++++--------- tests/compile-fail/methods.rs | 3 ++ 4 files changed, 60 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 27be09c6127..1232f526875 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 52 lints included in this crate: +There are 53 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -59,6 +59,7 @@ name [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/lib.rs b/src/lib.rs index f4da8b03bc2..e51732818ba 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,6 +114,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, + methods::WRONG_SELF_CONVENTION, misc::CMP_NAN, misc::CMP_OWNED, misc::FLOAT_CMP, diff --git a/src/methods.rs b/src/methods.rs index 50f3512b4f0..5a20ba06831 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -23,11 +23,14 @@ declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, "defining a method that should be implementing a std trait"); +declare_lint!(pub WRONG_SELF_CONVENTION, Warn, + "defining a method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, - SHOULD_IMPLEMENT_TRAIT) + SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -68,18 +71,28 @@ impl LintPass for MethodsPass { if let ItemImpl(_, _, _, None, _, ref items) = item.node { for item in items { let name = item.ident.name; - for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { - if_let_chain! { - [ - name == method_name, - let MethodImplItem(ref sig, _) = item.node, - sig.decl.inputs.len() == n_args, - out_type.matches(&sig.decl.output), - self_kind.matches(&sig.explicit_self.node) - ], { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, item.span, &format!( - "defining a method called `{}` on this type; consider implementing \ - the `{}` trait or choosing a less ambiguous name", name, trait_name)); + if let MethodImplItem(ref sig, _) = item.node { + // check missing trait implementations + for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { + if_let_chain! { + [ + name == method_name, + sig.decl.inputs.len() == n_args, + out_type.matches(&sig.decl.output), + self_kind.matches(&sig.explicit_self.node) + ], { + span_lint(cx, SHOULD_IMPLEMENT_TRAIT, item.span, &format!( + "defining a method called `{}` on this type; consider implementing \ + the `{}` trait or choosing a less ambiguous name", name, trait_name)); + } + } + } + // check conventions w.r.t. conversion method names and predicates + for &(prefix, self_kind) in &CONVENTIONS { + if name.as_str().starts_with(prefix) && !self_kind.matches(&sig.explicit_self.node) { + span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!( + "methods called `{}*` usually take {}; consider choosing a less \ + ambiguous name", prefix, self_kind.description())); } } } @@ -88,6 +101,14 @@ impl LintPass for MethodsPass { } } +const CONVENTIONS: [(&'static str, SelfKind); 5] = [ + ("into_", ValueSelf), + ("to_", RefSelf), + ("as_", RefSelf), + ("is_", RefSelf), + ("from_", NoSelf), +]; + const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ ("add", 2, ValueSelf, AnyType, "std::ops::Add`"), ("sub", 2, ValueSelf, AnyType, "std::ops::Sub"), @@ -126,7 +147,7 @@ enum SelfKind { ValueSelf, RefSelf, RefMutSelf, - NoSelf + NoSelf, } impl SelfKind { @@ -136,9 +157,28 @@ impl SelfKind { (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true, (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true, (&NoSelf, &SelfStatic) => true, + (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty), _ => false } } + + fn matches_explicit_type(&self, ty: &Ty) -> bool { + match (self, &ty.node) { + (&ValueSelf, &TyPath(..)) => true, + (&RefSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true, + (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, + _ => false + } + } + + fn description(&self) -> &'static str { + match *self { + ValueSelf => "self by value", + RefSelf => "self by reference", + RefMutSelf => "self by mutable reference", + NoSelf => "no self", + } + } } #[derive(Clone, Copy)] diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 1c81fefc4e5..560f36a9d5d 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -15,6 +15,9 @@ impl T { fn sub(&self, other: T) -> &T { self } // no error, self is a ref fn div(self) -> T { self } // no error, different #arguments fn rem(self, other: T) { } // no error, wrong return type + + fn into_u32(self) -> u32 { 0 } // fine + fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value } impl Mul<T> for T { -- cgit 1.4.1-3-g733a5 From 5264196538a36d21d2666b9e5f1584c3806111ba Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Tue, 1 Sep 2015 21:08:49 +0200 Subject: methods: try to allow value self when type is Copy (fixes #273) --- src/methods.rs | 35 +++++++++++++++++++++++++---------- tests/compile-fail/methods.rs | 9 +++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 5a20ba06831..d55cf49daab 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -68,10 +68,10 @@ impl LintPass for MethodsPass { } fn check_item(&mut self, cx: &Context, item: &Item) { - if let ItemImpl(_, _, _, None, _, ref items) = item.node { - for item in items { - let name = item.ident.name; - if let MethodImplItem(ref sig, _) = item.node { + if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { + for implitem in items { + let name = implitem.ident.name; + if let MethodImplItem(ref sig, _) = implitem.node { // check missing trait implementations for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { if_let_chain! { @@ -79,9 +79,9 @@ impl LintPass for MethodsPass { name == method_name, sig.decl.inputs.len() == n_args, out_type.matches(&sig.decl.output), - self_kind.matches(&sig.explicit_self.node) + self_kind.matches(&sig.explicit_self.node, false) ], { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, item.span, &format!( + span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( "defining a method called `{}` on this type; consider implementing \ the `{}` trait or choosing a less ambiguous name", name, trait_name)); } @@ -89,7 +89,8 @@ impl LintPass for MethodsPass { } // check conventions w.r.t. conversion method names and predicates for &(prefix, self_kind) in &CONVENTIONS { - if name.as_str().starts_with(prefix) && !self_kind.matches(&sig.explicit_self.node) { + if name.as_str().starts_with(prefix) && + !self_kind.matches(&sig.explicit_self.node, is_copy(cx, &ty, &item)) { span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!( "methods called `{}*` usually take {}; consider choosing a less \ ambiguous name", prefix, self_kind.description())); @@ -151,22 +152,26 @@ enum SelfKind { } impl SelfKind { - fn matches(&self, slf: &ExplicitSelf_) -> bool { + fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool { match (self, slf) { (&ValueSelf, &SelfValue(_)) => true, (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true, (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true, + (&RefSelf, &SelfValue(_)) => allow_value_for_ref, + (&RefMutSelf, &SelfValue(_)) => allow_value_for_ref, (&NoSelf, &SelfStatic) => true, - (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty), + (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), _ => false } } - fn matches_explicit_type(&self, ty: &Ty) -> bool { + fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool { match (self, &ty.node) { (&ValueSelf, &TyPath(..)) => true, (&RefSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true, (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, + (&RefSelf, &TyPath(..)) => allow_value_for_ref, + (&RefMutSelf, &TyPath(..)) => allow_value_for_ref, _ => false } } @@ -212,3 +217,13 @@ fn is_bool(ty: &Ty) -> bool { } false } + +fn is_copy(cx: &Context, ast_ty: &Ty, item: &Item) -> bool { + match cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + None => false, + Some(ty) => { + let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); + !ty.moves_by_default(&env, ast_ty.span) + } + } +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 560f36a9d5d..314601f6dbd 100755 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -18,6 +18,15 @@ impl T { fn into_u32(self) -> u32 { 0 } // fine fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value + + fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference +} + +#[derive(Clone,Copy)] +struct U; + +impl U { + fn to_something(self) -> u32 { 0 } // ok because U is Copy } impl Mul<T> for T { -- cgit 1.4.1-3-g733a5 From 08fb953e1a9ac43720db6cf1d75bd19f5aa3cff5 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 2 Sep 2015 01:36:37 +0200 Subject: extended pattern matching --- src/shadow.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index eba7a9da187..e7097f9daf6 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -60,8 +60,12 @@ fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; if let &Some(ref t) = ty { check_ty(cx, t, bindings) } - if let &Some(ref o) = init { check_expr(cx, o, bindings) } - check_pat(cx, pat, init, span, bindings); + if let &Some(ref o) = init { + check_expr(cx, o, bindings); + check_pat(cx, pat, &Some(o), span, bindings); + } else { + check_pat(cx, pat, &None, span, bindings); + } } } @@ -72,8 +76,8 @@ fn is_binding(cx: &Context, pat: &Pat) -> bool { } } -fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, - bindings: &mut Vec<Name>) where T: Deref<Target=Expr> { +fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, + bindings: &mut Vec<Name>) { //TODO: match more stuff / destructuring match pat.node { PatIdent(_, ref ident, ref inner) => { @@ -88,9 +92,43 @@ fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span, if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } }, //PatEnum(Path, Option<Vec<P<Pat>>>), - //PatQPath(QSelf, Path), - //PatStruct(Path, Vec<Spanned<FieldPat>>, bool), - //PatTup(Vec<P<Pat>>), + PatStruct(_, ref pfields, _) => + if let Some(ref init_struct) = *init { // TODO follow + if let ExprStruct(_, ref efields, ref _base) = init_struct.node { + // TODO: follow base + for field in pfields { + let ident = field.node.ident; + let efield = efields.iter() + .find(|ref f| f.ident.node == ident) + .map(|f| &*f.expr); + check_pat(cx, &field.node.pat, &efield, span, bindings); + } + } else { + for field in pfields { + check_pat(cx, &field.node.pat, &None, span, bindings); + } + } + } else { + for field in pfields { + check_pat(cx, &field.node.pat, &None, span, bindings); + } + }, + PatTup(ref inner) => + if let Some(ref init_tup) = *init { //TODO: follow + 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); + } + } else { + for p in inner { + check_pat(cx, p, &None, span, bindings); + } + } + } else { + for p in inner { + check_pat(cx, p, &None, span, bindings); + } + }, PatBox(ref inner) => { if let Some(ref initp) = *init { match initp.node { -- cgit 1.4.1-3-g733a5 From 1ab733cfa1b8ccad239aaa1a9e9a0fbf69a5ee18 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 2 Sep 2015 01:36:37 +0200 Subject: extended pattern matching --- src/shadow.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index e7097f9daf6..2276fb1da5d 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -60,7 +60,7 @@ fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; if let &Some(ref t) = ty { check_ty(cx, t, bindings) } - if let &Some(ref o) = init { + if let &Some(ref o) = init { check_expr(cx, o, bindings); check_pat(cx, pat, &Some(o), span, bindings); } else { @@ -92,10 +92,9 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } }, //PatEnum(Path, Option<Vec<P<Pat>>>), - PatStruct(_, ref pfields, _) => - if let Some(ref init_struct) = *init { // TODO follow - if let ExprStruct(_, ref efields, ref _base) = init_struct.node { - // TODO: follow base + PatStruct(_, ref pfields, _) => + if let Some(ref init_struct) = *init { + if let ExprStruct(_, ref efields, _) = init_struct.node { for field in pfields { let ident = field.node.ident; let efield = efields.iter() @@ -105,7 +104,7 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, } } else { for field in pfields { - check_pat(cx, &field.node.pat, &None, span, bindings); + check_pat(cx, &field.node.pat, init, span, bindings); } } } else { @@ -114,14 +113,14 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, } }, PatTup(ref inner) => - if let Some(ref init_tup) = *init { //TODO: follow + if let Some(ref init_tup) = *init { if let ExprTup(ref tup) = init_tup.node { - for (i, p) in inner.iter().enumerate() { + for (i, p) in inner.iter().enumerate() { check_pat(cx, p, &Some(&tup[i]), p.span, bindings); } } else { for p in inner { - check_pat(cx, p, &None, span, bindings); + check_pat(cx, p, init, span, bindings); } } } else { -- cgit 1.4.1-3-g733a5 From bc1eb8481029856d41df3ae2a404cbfe51b80016 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 2 Sep 2015 07:56:13 +0200 Subject: match region patterns --- src/shadow.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index 2276fb1da5d..d64f6840db8 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -130,17 +130,17 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, }, PatBox(ref inner) => { if let Some(ref initp) = *init { - match initp.node { - ExprBox(_, ref inner_init) => - check_pat(cx, inner, &Some(&**inner_init), span, bindings), - //TODO: ExprCall on Box::new - _ => check_pat(cx, inner, init, span, bindings), + if let ExprBox(_, ref inner_init) = initp.node { + 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); } }, - //PatRegion(P<Pat>, Mutability), + PatRegion(ref inner, _) => + check_pat(cx, inner, init, span, bindings), //PatRange(P<Expr>, P<Expr>), //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), _ => (), -- cgit 1.4.1-3-g733a5 From 0fb7d1d2d98016b496c36606ab003fd5d0b7e994 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 2 Sep 2015 08:19:47 +0200 Subject: reporting improvements --- src/shadow.rs | 22 ++++++++++++---------- src/utils.rs | 19 +++++++++++++++++-- tests/compile-fail/matches.rs | 18 ++++++++++-------- tests/compile-fail/shadow.rs | 2 +- 4 files changed, 40 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index d64f6840db8..751077ec1d9 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -6,7 +6,7 @@ use syntax::visit::FnKind; use rustc::lint::{Context, LintArray, LintPass}; use rustc::middle::def::Def::{DefVariant, DefStruct}; -use utils::{in_external_macro, snippet, span_lint}; +use utils::{in_external_macro, snippet, span_lint, span_note_and_lint}; declare_lint!(pub SHADOW_SAME, Allow, "rebinding a name to itself, e.g. `let mut x = &mut x`"); @@ -131,9 +131,9 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, PatBox(ref inner) => { if let Some(ref 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), + check_pat(cx, inner, init, span, bindings); } } else { check_pat(cx, inner, init, span, bindings); @@ -149,7 +149,7 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: &Option<T>) where T: Deref<Target=Expr> { - if let &Some(ref expr) = init { + if let Some(ref expr) = *init { if is_self_shadow(name, expr) { span_lint(cx, SHADOW_SAME, span, &format!( "{} is shadowed by itself in {}", @@ -157,20 +157,22 @@ fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: snippet(cx, expr.span, ".."))); } else { if contains_self(name, expr) { - span_lint(cx, SHADOW_REUSE, span, &format!( + span_note_and_lint(cx, SHADOW_REUSE, lspan, &format!( "{} is shadowed by {} which reuses the original value", snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); + snippet(cx, expr.span, "..")), + expr.span, "initialization happens here"); } else { - span_lint(cx, SHADOW_UNRELATED, span, &format!( - "{} is shadowed by {} in this declaration", + span_note_and_lint(cx, SHADOW_UNRELATED, lspan, &format!( + "{} is shadowed by {}", snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); + snippet(cx, expr.span, "..")), + expr.span, "initialization happens here"); } } } else { span_lint(cx, SHADOW_UNRELATED, span, &format!( - "{} is shadowed in this declaration", snippet(cx, lspan, "_"))); + "{} shadows a previous declaration", snippet(cx, lspan, "_"))); } } diff --git a/src/utils.rs b/src/utils.rs index f16387f606d..2f9b86964c2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -23,7 +23,7 @@ pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { if info.callee.name() == "closure expansion" { return false; } - }, + }, ExpnFormat::MacroAttribute(..) => { // these are all plugins return true; @@ -177,7 +177,7 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, msg: &str, help: &str) { - span_lint(cx, lint, span, msg); + cx.span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { cx.sess().fileline_help(span, &format!("{}\nfor further information \ visit https://github.com/Manishearth/rust-clippy/wiki#{}", @@ -185,6 +185,21 @@ pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, } } +pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, + msg: &str, note_span: Span, note: &str) { + cx.span_lint(lint, span, msg); + if cx.current_level(lint) != Level::Allow { + if note_span == span { + cx.sess().fileline_note(note_span, note) + } else { + cx.sess().span_note(note_span, note) + } + cx.sess().fileline_help(span, &format!("for further information visit \ + https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())) + } +} + /// return the base type for references and raw pointers pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 3cc540992c9..07dc7c9ef83 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -39,14 +39,16 @@ fn single_match(){ } fn ref_pats() { - let ref v = Some(0); - match v { //~ERROR instead of prefixing all patterns with `&` - &Some(v) => println!("{:?}", v), - &None => println!("none"), - } - match v { // this doesn't trigger, we have a different pattern - &Some(v) => println!("some"), - other => println!("other"), + { + let ref v = Some(0); + match v { //~ERROR instead of prefixing all patterns with `&` + &Some(v) => println!("{:?}", v), + &None => println!("none"), + } + match v { // this doesn't trigger, we have a different pattern + &Some(v) => println!("some"), + other => println!("other"), + } } let ref tup = (1, 2); match tup { //~ERROR instead of prefixing all patterns with `&` diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 8ac9a93b140..80d48f84163 100755 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -18,7 +18,7 @@ fn main() { let x = (1, x); //~ERROR: x is shadowed by (1, x) which reuses let x = first(x); //~ERROR: x is shadowed by first(x) which reuses let y = 1; - let x = y; //~ERROR: x is shadowed by y in this declaration + let x = y; //~ERROR: x is shadowed by y let o = Some(1u8); -- cgit 1.4.1-3-g733a5 From 0c7f05dd760b7d1ad329d62268236184e2210c3f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 2 Sep 2015 10:30:11 +0200 Subject: check item name for eq, fixes #268 --- src/misc.rs | 12 ++++++++++++ tests/compile-fail/float_cmp.rs | 25 +++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index b9d74c645b7..5f32a93d3dd 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -4,6 +4,7 @@ use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; +use rustc::ast_map::Node::*; use rustc::middle::ty; use utils::{match_path, snippet, span_lint, walk_ptrs_ty}; @@ -91,6 +92,17 @@ impl LintPass for FloatCmp { false, |c| c.0.as_float().map_or(false, |f| f == 0.0)) { return; } + let parent_id = cx.tcx.map.get_parent(expr.id); + match cx.tcx.map.find(parent_id) { + Some(NodeItem(&Item{ ref ident, .. })) | + Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | + Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { + let name = ident.name.as_str(); + if &*name == "eq" || name.starts_with("eq_") || + name.ends_with("_eq") { return; } + }, + _ => (), + } span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-comparison of f32 or f64 detected. Consider changing this to \ `abs({} - {}) < epsilon` for some suitable value of epsilon", diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index 067ec2818bf..da3dba5e4d4 100755 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -1,6 +1,9 @@ #![feature(plugin)] #![plugin(clippy)] +#![deny(float_cmp)] +#![allow(unused)] + use std::ops::Add; const ZERO : f32 = 0.0; @@ -10,8 +13,26 @@ fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy { x + x } -#[deny(float_cmp)] -#[allow(unused)] +fn eq_fl(x: f32, y: f32) -> bool { + if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn +} + +fn fl_eq(x: f32, y: f32) -> bool { + if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn +} + +struct X { val: f32 } + +impl PartialEq for X { + fn eq(&self, o: &X) -> bool { + if self.val.is_nan() { + o.val.is_nan() + } else { + self.val == o.val // no error, inside "eq" fn + } + } +} + fn main() { ZERO == 0f32; //no error, comparison with zero is ok ZERO == 0.0; //no error, comparison with zero is ok -- cgit 1.4.1-3-g733a5 From 73c34e12b324038e3c501faf63de1a3d618f22b5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 2 Sep 2015 16:11:51 +0530 Subject: Only handle ranges starting with 0 for needless_range_loop (fixes #279) --- src/loops.rs | 46 ++++++++++++++++++++++++------------------ tests/compile-fail/for_loop.rs | 4 ++++ 2 files changed, 30 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 33401dc67e1..3e1e669ea48 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -37,26 +37,32 @@ impl LintPass for LoopsPass { if let Some((pat, arg, body)) = recover_for_loop(expr) { // check for looping over a range and then indexing a sequence with it // -> the iteratee must be a range literal - if let ExprRange(_, _) = arg.node { - // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { cx: cx, var: ident.node.name, - indexed: HashSet::new(), nonindex: false }; - walk_expr(&mut visitor, body); - // linting condition: we only indexed one variable - if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().expect( - "Len was nonzero, but no contents found"); - if visitor.nonindex { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is used to index `{}`. Consider using \ - `for ({}, item) in {}.iter().enumerate()` or similar iterators", - ident.node.name, indexed, ident.node.name, indexed)); - } else { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in &{}` or similar iterators", - ident.node.name, indexed, indexed)); + if let ExprRange(Some(ref l), _) = arg.node { + // Range should start with `0` + if let ExprLit(ref lit) = l.node { + if let LitInt(0, _) = lit.node { + + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { cx: cx, var: ident.node.name, + indexed: HashSet::new(), nonindex: false }; + walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable + if visitor.indexed.len() == 1 { + let indexed = visitor.indexed.into_iter().next().expect( + "Len was nonzero, but no contents found"); + if visitor.nonindex { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is used to index `{}`. Consider using \ + `for ({}, item) in {}.iter().enumerate()` or similar iterators", + ident.node.name, indexed, ident.node.name, indexed)); + } else { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in &{}` or similar iterators", + ident.node.name, indexed, indexed)); + } + } } } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index f2540bfd595..4d0c22fff0b 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -30,6 +30,10 @@ fn main() { println!("{} {}", vec[i], vec2[i]); } + for i in 5..vec.len() { // not an error, not starting with 0 + println!("{}", vec[i]); + } + for _v in vec.iter() { } //~ERROR it is more idiomatic to loop over `&vec` for _v in vec.iter_mut() { } //~ERROR it is more idiomatic to loop over `&mut vec` -- cgit 1.4.1-3-g733a5 From 846c164709dac20fd16e30e8366c2b0dadd55787 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 2 Sep 2015 16:46:12 +0200 Subject: don't say "did you mean to" - use the standard "consider..." "Did you mean to ..." sounds a bit condescending to me, since if I meant to write "if let" I probably wouldn't have written "match" :) --- README.md | 2 +- src/matches.rs | 13 ++++++------- src/types.rs | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 1232f526875..8c00c9f901b 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ fn main(){ Produce this warning: ``` -src/main.rs:8:5: 11:6 warning: You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?, #[warn(single_match)] on by default +src/main.rs:8:5: 11:6 warning: you seem to be trying to use match for destructuring a single type. Consider using `if let`, #[warn(single_match)] on by default src/main.rs:8 match x { src/main.rs:9 Some(y) => println!("{:?}", y), src/main.rs:10 _ => () diff --git a/src/matches.rs b/src/matches.rs index 3d04c9210ce..fdc3ca5e907 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -37,13 +37,12 @@ impl LintPass for MatchPass { { if in_external_macro(cx, expr.span) {return;} span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for \ - destructuring a single pattern. Did you mean to \ - use `if let`?", - &format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, ".."))); + "you seem to be trying to use match for destructuring a \ + single pattern. Consider using `if let`", + &format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, ".."))); } // check preconditions for MATCH_REF_PATS diff --git a/src/types.rs b/src/types.rs index 3c4d1441f17..4a3c183462d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -30,7 +30,7 @@ impl LintPass for TypePass { if match_type(cx, inner, &VEC_PATH) { span_help_and_lint( cx, BOX_VEC, ast_ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?", + "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); } } -- cgit 1.4.1-3-g733a5 From 6b589681c9855a4802308423242976414d414b17 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 2 Sep 2015 17:14:23 +0200 Subject: methods: allow multiple self kinds for "is_" methods These can be static method predicates. (Found one in rust-copperline, called Term::is_unsupported_term().) --- src/methods.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index d55cf49daab..4a144734a94 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -88,12 +88,14 @@ impl LintPass for MethodsPass { } } // check conventions w.r.t. conversion method names and predicates - for &(prefix, self_kind) in &CONVENTIONS { + let is_copy = is_copy(cx, &ty, &item); + for &(prefix, self_kinds) in &CONVENTIONS { if name.as_str().starts_with(prefix) && - !self_kind.matches(&sig.explicit_self.node, is_copy(cx, &ty, &item)) { + !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!( "methods called `{}*` usually take {}; consider choosing a less \ - ambiguous name", prefix, self_kind.description())); + ambiguous name", prefix, + &self_kinds.iter().map(|k| k.description()).collect::<Vec<_>>().join(" or "))); } } } @@ -102,12 +104,12 @@ impl LintPass for MethodsPass { } } -const CONVENTIONS: [(&'static str, SelfKind); 5] = [ - ("into_", ValueSelf), - ("to_", RefSelf), - ("as_", RefSelf), - ("is_", RefSelf), - ("from_", NoSelf), +const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ + ("into_", &[ValueSelf]), + ("to_", &[RefSelf]), + ("as_", &[RefSelf]), + ("is_", &[RefSelf, NoSelf]), + ("from_", &[NoSelf]), ]; const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ -- cgit 1.4.1-3-g733a5 From 7649d1c2a8d53dc5928450d6d7befd602bc966cd Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 2 Sep 2015 18:17:38 +0200 Subject: shadow: complete coverage of "contains_self" checker --- src/shadow.rs | 52 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index 751077ec1d9..7f555d4be85 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -255,29 +255,55 @@ fn path_eq_name(name: Name, path: &Path) -> bool { fn contains_self(name: Name, expr: &Expr) -> bool { match expr.node { + // the "self" name itself (maybe) + ExprPath(_, ref path) => path_eq_name(name, path), + // no subexprs + ExprLit(_) => false, + // one subexpr ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | - ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e) - => contains_self(name, e), - ExprBinary(_, ref l, ref r) => + ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e) | + ExprCast(ref e, _) => + contains_self(name, e), + // two subexprs + ExprBinary(_, ref l, ref r) | ExprIndex(ref l, ref r) | + ExprAssign(ref l, ref r) | ExprAssignOp(_, ref l, ref r) | + ExprRepeat(ref l, ref r) => contains_self(name, l) || contains_self(name, r), - ExprBlock(ref block) | ExprLoop(ref block, _) => + // one optional subexpr + ExprRet(ref oe) => + oe.as_ref().map_or(false, |ref e| contains_self(name, e)), + // two optional subexprs + ExprRange(ref ol, ref or) => + ol.as_ref().map_or(false, |ref e| contains_self(name, e)) || + or.as_ref().map_or(false, |ref e| contains_self(name, e)), + // one subblock + ExprBlock(ref block) | ExprLoop(ref block, _) | + ExprClosure(_, _, ref block) => contains_block_self(name, block), - ExprCall(ref fun, ref args) => contains_self(name, fun) || - args.iter().any(|ref a| contains_self(name, a)), - ExprMethodCall(_, _, ref args) => + // one vec + ExprMethodCall(_, _, ref v) | ExprVec(ref v) | ExprTup(ref v) => + v.iter().any(|ref a| contains_self(name, a)), + // one expr, one vec + ExprCall(ref fun, ref args) => + contains_self(name, fun) || args.iter().any(|ref a| contains_self(name, a)), - ExprVec(ref v) | ExprTup(ref v) => - v.iter().any(|ref e| contains_self(name, e)), + // special ones ExprIf(ref cond, ref then, ref otherwise) => contains_self(name, cond) || contains_block_self(name, then) || otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)), ExprWhile(ref e, ref block, _) => contains_self(name, e) || contains_block_self(name, block), ExprMatch(ref e, ref arms, _) => - arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat| - contains_pat_self(name, pat))) || contains_self(name, e), - ExprPath(_, ref path) => path_eq_name(name, path), - _ => false + contains_self(name, e) || + arms.iter().any( + |ref arm| + arm.pats.iter().any(|ref pat| contains_pat_self(name, pat)) || + arm.guard.as_ref().map_or(false, |ref g| contains_self(name, g)) || + contains_self(name, &arm.body)), + ExprStruct(_, ref fields, ref other) => + fields.iter().any(|ref f| contains_self(name, &f.expr)) || + other.as_ref().map_or(false, |ref e| contains_self(name, e)), + _ => false, } } -- cgit 1.4.1-3-g733a5 From fbdba7f915cae7689b4afb6ef7580d8274f09d22 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 3 Sep 2015 02:14:05 +0530 Subject: Fix ICE --- src/methods.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 4a144734a94..c6f0b1c2e59 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,6 +1,7 @@ use syntax::ast::*; use rustc::lint::*; use rustc::middle::ty; +use rustc::middle::subst::Subst; use std::iter; use std::borrow::Cow; @@ -225,7 +226,7 @@ fn is_copy(cx: &Context, ast_ty: &Ty, item: &Item) -> bool { None => false, Some(ty) => { let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - !ty.moves_by_default(&env, ast_ty.span) + !ty.subst(cx.tcx, &env.free_substs).moves_by_default(&env, ast_ty.span) } } } -- cgit 1.4.1-3-g733a5 From cb571bf2e2b3b4f9696a9ed4d93f599a2b044fd6 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 3 Sep 2015 10:57:11 +0200 Subject: also ignore functions --- src/misc.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 5f32a93d3dd..1376bf41b38 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -98,8 +98,11 @@ impl LintPass for FloatCmp { Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { let name = ident.name.as_str(); - if &*name == "eq" || name.starts_with("eq_") || - name.ends_with("_eq") { return; } + if &*name == "eq" || &*name == "ne" || + name.starts_with("eq_") || + name.ends_with("_eq") { + return; + } }, _ => (), } -- cgit 1.4.1-3-g733a5 From eca185438b52ae4645f5aa78b6076adeec49707d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 3 Sep 2015 20:12:17 +0530 Subject: Update rust to 0efb9dab8c7c07fa28e9df0eccc5c07ea3c17fbb (HIR+lints, Thu Sep 3 18:59:56 2015 +0530) fixes #294 --- src/approx_const.rs | 2 +- src/attrs.rs | 6 +++--- src/bit_mask.rs | 4 ++-- src/collapsible_if.rs | 2 +- src/consts.rs | 2 +- src/eq_op.rs | 4 ++-- src/eta_reduction.rs | 2 +- src/identity_op.rs | 2 +- src/len_zero.rs | 2 +- src/lib.rs | 6 ++++++ src/lifetimes.rs | 7 ++++--- src/loops.rs | 5 +++-- src/matches.rs | 5 ++--- src/methods.rs | 2 +- src/misc.rs | 9 +++++---- src/mut_mut.rs | 2 +- src/needless_bool.rs | 2 +- src/precedence.rs | 2 +- src/ptr_arg.rs | 2 +- src/ranges.rs | 2 +- src/returns.rs | 8 ++++---- src/shadow.rs | 11 +++++------ src/strings.rs | 2 +- src/types.rs | 22 +++++++++++----------- src/unicode.rs | 2 +- src/utils.rs | 5 +++-- tests/consts.rs | 3 ++- 27 files changed, 66 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index d307c7dd056..a132bc90361 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::Span; use std::f64::consts as f64; diff --git a/src/attrs.rs b/src/attrs.rs index ad021f28a4d..05362c706f0 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,7 +1,8 @@ //! checks for attributes use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; +use reexport::*; use syntax::codemap::ExpnInfo; use utils::{in_macro, match_path, span_lint}; @@ -68,7 +69,6 @@ fn is_relevant_block(block: &Block) -> bool { StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { return is_relevant_expr(expr); } - _ => () } } block.expr.as_ref().map_or(false, |e| is_relevant_expr(e)) @@ -79,7 +79,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprBlock(ref block) => is_relevant_block(block), ExprRet(Some(ref e)) | ExprParen(ref e) => is_relevant_expr(e), - ExprRet(None) | ExprBreak(_) | ExprMac(_) => false, + ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { !match_path(path, &["std", "rt", "begin_unwind"]) diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 465b772da5c..b1b8a735455 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,8 +1,8 @@ use rustc::lint::*; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::*; -use syntax::ast::*; -use syntax::ast_util::is_comparison_binop; +use rustc_front::hir::*; +use rustc_front::util::is_comparison_binop; use syntax::codemap::Span; use utils::span_lint; diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index e0b25b7283b..9301aafbace 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -13,7 +13,7 @@ //! This lint is **warn** by default use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::{Spanned, ExpnInfo}; use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; diff --git a/src/consts.rs b/src/consts.rs index 29b96146db2..a8a446a703f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -4,7 +4,7 @@ use rustc::lint::Context; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::ptr::P; use std::cmp::PartialOrd; use std::cmp::Ordering::{self, Greater, Less, Equal}; diff --git a/src/eq_op.rs b/src/eq_op.rs index 3b4f47b5562..c5953201436 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,6 +1,6 @@ use rustc::lint::*; -use syntax::ast::*; -use syntax::ast_util as ast_util; +use rustc_front::hir::*; +use rustc_front::util as ast_util; use syntax::ptr::P; use consts::constant; diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index da2149f0539..f3359ad0c37 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use rustc::middle::ty; use utils::{snippet, span_lint}; diff --git a/src/identity_op.rs b/src/identity_op.rs index bcdd527e407..0225c9b4d69 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::Span; use consts::{constant, is_negative}; diff --git a/src/len_zero.rs b/src/len_zero.rs index 068568cb392..c30a98d8537 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::ptr::P; use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; diff --git a/src/lib.rs b/src/lib.rs index e51732818ba..e0556972a7d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,8 @@ extern crate syntax; #[macro_use] extern crate rustc; +#[macro_use] +extern crate rustc_front; // Only for the compile time checking of paths extern crate core; @@ -42,6 +44,10 @@ pub mod ranges; pub mod matches; pub mod precedence; +mod reexport { + pub use syntax::ast::{Name, Ident, NodeId}; +} + #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); diff --git a/src/lifetimes.rs b/src/lifetimes.rs index de7a39fdb3b..dccad1ffbe7 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -1,7 +1,8 @@ -use syntax::ast::*; +use rustc_front::hir::*; +use reexport::*; use rustc::lint::*; use syntax::codemap::Span; -use syntax::visit::{Visitor, walk_ty, walk_ty_param_bound}; +use rustc_front::visit::{Visitor, walk_ty, walk_ty_param_bound}; use std::collections::HashSet; use utils::{in_external_macro, span_lint}; @@ -152,7 +153,7 @@ fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::<HashSet<_>>().len() } -/// A visitor usable for syntax::visit::walk_ty(). +/// A visitor usable for rustc_front::visit::walk_ty(). struct RefVisitor(Vec<RefLt>); impl RefVisitor { diff --git a/src/loops.rs b/src/loops.rs index 3e1e669ea48..d40eca8c0f3 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,6 +1,7 @@ use rustc::lint::*; -use syntax::ast::*; -use syntax::visit::{Visitor, walk_expr}; +use rustc_front::hir::*; +use reexport::*; +use rustc_front::visit::{Visitor, walk_expr}; use rustc::middle::ty; use std::collections::HashSet; diff --git a/src/matches.rs b/src/matches.rs index fdc3ca5e907..5947469cd90 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,6 +1,5 @@ use rustc::lint::*; -use syntax::ast; -use syntax::ast::*; +use rustc_front::hir::*; use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; @@ -20,7 +19,7 @@ impl LintPass for MatchPass { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node { + if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { // check preconditions for SINGLE_MATCH // only two arms if arms.len() == 2 && diff --git a/src/methods.rs b/src/methods.rs index c6f0b1c2e59..25435274313 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,4 +1,4 @@ -use syntax::ast::*; +use rustc_front::hir::*; use rustc::lint::*; use rustc::middle::ty; use rustc::middle::subst::Subst; diff --git a/src/misc.rs b/src/misc.rs index 1376bf41b38..eb3a93941be 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,10 +1,11 @@ use rustc::lint::*; use syntax::ptr::P; -use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use rustc_front::hir::*; +use reexport::*; +use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; -use syntax::visit::FnKind; -use rustc::ast_map::Node::*; +use rustc_front::visit::FnKind; +use rustc::front::map::Node::*; use rustc::middle::ty; use utils::{match_path, snippet, span_lint, walk_ptrs_ty}; diff --git a/src/mut_mut.rs b/src/mut_mut.rs index fbcb70e17d3..236d9b6a5a2 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::ExpnInfo; use rustc::middle::ty::{TypeAndMut, TyRef}; diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 0fe52c44189..0e8276bfafa 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -3,7 +3,7 @@ //! This lint is **warn** by default use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use utils::{span_lint, snippet}; diff --git a/src/precedence.rs b/src/precedence.rs index 1d89adf9df8..31c28146e1e 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::span_lint; diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index bcbd8dad68a..b0d9757e6c5 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -3,7 +3,7 @@ //! This lint is **warn** by default use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use rustc::middle::ty; use utils::{span_lint, match_type}; diff --git a/src/ranges.rs b/src/ranges.rs index 914b4daa6be..197afaf1163 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,5 +1,5 @@ use rustc::lint::{Context, LintArray, LintPass}; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::match_type; diff --git a/src/returns.rs b/src/returns.rs index 29749b29435..ea75cf562bf 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,7 +1,8 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; +use reexport::*; use syntax::codemap::{Span, Spanned}; -use syntax::visit::FnKind; +use rustc_front::visit::FnKind; use utils::{span_lint, snippet, match_path, in_external_macro}; @@ -42,8 +43,7 @@ impl ReturnPass { // 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 - ExprIf(_, ref ifblock, Some(ref elsexpr)) | - ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { + ExprIf(_, ref ifblock, Some(ref elsexpr)) => { self.check_block_return(cx, ifblock); self.check_final_expr(cx, elsexpr); } diff --git a/src/shadow.rs b/src/shadow.rs index 7f555d4be85..aaa2c91a036 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -1,7 +1,8 @@ use std::ops::Deref; -use syntax::ast::*; +use rustc_front::hir::*; +use reexport::*; use syntax::codemap::Span; -use syntax::visit::FnKind; +use rustc_front::visit::FnKind; use rustc::lint::{Context, LintArray, LintPass}; use rustc::middle::def::Def::{DefVariant, DefStruct}; @@ -47,8 +48,7 @@ fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { match stmt.node { StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), StmtExpr(ref e, _) | StmtSemi(ref e, _) => - check_expr(cx, e, bindings), - _ => () + check_expr(cx, e, bindings) } } if let Some(ref o) = block.expr { check_expr(cx, o, bindings); } @@ -320,8 +320,7 @@ fn contains_block_self(name: Name, block: &Block) -> bool { } }, StmtExpr(ref e, _) | StmtSemi(ref e, _) => - if contains_self(name, e) { return true }, - _ => () + if contains_self(name, e) { return true } } } if let Some(ref e) = block.expr { contains_self(name, e) } else { false } diff --git a/src/strings.rs b/src/strings.rs index fc8a2d238bb..3c9c1086a12 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -4,7 +4,7 @@ //! disable the subsumed lint unless it has a higher level use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::Spanned; use eq_op::is_exp_equal; diff --git a/src/types.rs b/src/types.rs index 4a3c183462d..9fa63f1986c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,9 +1,9 @@ use rustc::lint::*; -use syntax::ast; -use syntax::ast::*; -use syntax::ast_util::{is_comparison_binop, binop_to_string}; +use rustc_front::hir::*; +use reexport::*; +use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; -use syntax::visit::{FnKind, Visitor, walk_ty}; +use rustc_front::visit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; use utils::{match_type, snippet, span_lint, span_help_and_lint, in_external_macro}; @@ -24,7 +24,7 @@ impl LintPass for TypePass { lint_array!(BOX_VEC, LINKEDLIST) } - fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) { + fn check_ty(&mut self, cx: &Context, ast_ty: &Ty) { if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { if match_type(cx, inner, &VEC_PATH) { @@ -126,7 +126,7 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize { fn is_isize_or_usize(typ: &ty::TyS) -> bool { match typ.sty { - ty::TyInt(ast::TyIs) | ty::TyUint(ast::TyUs) => true, + ty::TyInt(TyIs) | ty::TyUint(TyUs) => true, _ => false } } @@ -211,7 +211,7 @@ impl LintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = if let ty::TyFloat(ast::TyF32) = cast_to.sty {32} else {64}; + let to_nbits = if let ty::TyFloat(TyF32) = cast_to.sty {32} else {64}; if is_isize_or_usize(cast_from) || from_nbits >= to_nbits { span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64); } @@ -235,8 +235,8 @@ impl LintPass for CastPass { check_truncation_and_wrapping(cx, expr, cast_from, cast_to); } (false, false) => { - if let (&ty::TyFloat(ast::TyF64), - &ty::TyFloat(ast::TyF32)) = (&cast_from.sty, &cast_to.sty) { + if let (&ty::TyFloat(TyF64), + &ty::TyFloat(TyF32)) = (&cast_from.sty, &cast_to.sty) { span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, "casting f64 to f32 may truncate the value"); @@ -320,7 +320,7 @@ fn check_fndecl(cx: &Context, decl: &FnDecl) { } } -fn check_type(cx: &Context, ty: &ast::Ty) { +fn check_type(cx: &Context, ty: &Ty) { if in_external_macro(cx, ty.span) { return; } let score = { let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; @@ -343,7 +343,7 @@ struct TypeComplexityVisitor { } impl<'v> Visitor<'v> for TypeComplexityVisitor { - fn visit_ty(&mut self, ty: &'v ast::Ty) { + fn visit_ty(&mut self, ty: &'v Ty) { let (add_score, sub_nest) = match ty.node { // _, &x and *x have only small overhead; don't mess with nesting level TyInfer | diff --git a/src/unicode.rs b/src/unicode.rs index 8a64f612666..a993da1782a 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::codemap::{BytePos, Span}; use utils::span_lint; diff --git a/src/utils.rs b/src/utils.rs index 2f9b86964c2..860ad85aab9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,8 @@ use rustc::lint::*; -use syntax::ast::*; +use rustc_front::hir::*; +use reexport::*; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; -use rustc::ast_map::Node::NodeExpr; +use rustc::front::map::Node::NodeExpr; use rustc::middle::def_id::DefId; use rustc::middle::ty; use std::borrow::Cow; diff --git a/tests/consts.rs b/tests/consts.rs index 55270cc6b51..7aa42545074 100755 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -4,8 +4,9 @@ extern crate clippy; extern crate syntax; extern crate rustc; +extern crate rustc_front; -use syntax::ast::*; +use rustc_front::hir::*; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; -- cgit 1.4.1-3-g733a5 From d659d039b6b6e3c5c858baf7e2be82dfee4c35d3 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Fri, 4 Sep 2015 07:56:52 +0200 Subject: methods: allow &mut self for as_ methods --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index c6f0b1c2e59..1d0ac662c50 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -108,7 +108,7 @@ impl LintPass for MethodsPass { const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ("into_", &[ValueSelf]), ("to_", &[RefSelf]), - ("as_", &[RefSelf]), + ("as_", &[RefSelf, RefMutSelf]), ("is_", &[RefSelf, NoSelf]), ("from_", &[NoSelf]), ]; -- cgit 1.4.1-3-g733a5 From e11fd49b1cc333a4fedbe1f948e6203208edd17b Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 4 Sep 2015 09:08:07 +0200 Subject: Unicode lints, second attempt: Lint whole strings, help with replacement --- Cargo.toml | 3 +++ README.md | 3 ++- src/lib.rs | 4 +++ src/unicode.rs | 58 ++++++++++++++++++++++++++++++------------- tests/compile-fail/unicode.rs | 9 +++---- 5 files changed, 54 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 28fd03e5d6f..656efd312b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,9 @@ keywords = ["clippy", "lint", "plugin"] name = "clippy" plugin = true +[dependencies] +unicode-normalization = "*" + [dev-dependencies] compiletest_rs = "*" regex = "*" diff --git a/README.md b/README.md index 8c00c9f901b..0046d891129 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 53 lints included in this crate: +There are 54 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -56,6 +56,7 @@ name [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions +[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop diff --git a/src/lib.rs b/src/lib.rs index e0556972a7d..a4aee0c27fd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,9 @@ extern crate rustc_front; extern crate core; extern crate collections; +// for unicode nfc normalization +extern crate unicode_normalization; + use rustc::plugin::Registry; use rustc::lint::LintPassObject; @@ -96,6 +99,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::CAST_PRECISION_LOSS, types::CAST_SIGN_LOSS, unicode::NON_ASCII_LITERAL, + unicode::UNICODE_NOT_NFC, ]); reg.register_lint_group("clippy", vec![ diff --git a/src/unicode.rs b/src/unicode.rs index a993da1782a..5e1af6f9818 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,21 +1,27 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::codemap::{BytePos, Span}; +use syntax::codemap::Span; -use utils::span_lint; +use unicode_normalization::UnicodeNormalization; + +use utils::span_help_and_lint; declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "using a zero-width space in a string literal, which is confusing" } declare_lint!{ pub NON_ASCII_LITERAL, Allow, "using any literal non-ASCII chars in a string literal; suggests \ using the \\u escape instead" } +declare_lint!{ pub UNICODE_NOT_NFC, Allow, + "using a unicode literal not in NFC normal form (see \ + http://www.unicode.org/reports/tr15/ for further information)" } + #[derive(Copy, Clone)] pub struct Unicode; impl LintPass for Unicode { fn get_lints(&self) -> LintArray { - lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL) + lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -27,23 +33,41 @@ impl LintPass for Unicode { } } -fn check_str(cx: &Context, string: &str, span: Span) { - for (i, c) in string.char_indices() { - if c == '\u{200B}' { - str_pos_lint(cx, ZERO_WIDTH_SPACE, span, i, - "zero-width space detected. Consider using `\\u{200B}`"); - } +fn escape<T: Iterator<Item=char>>(s: T) -> String { + let mut result = String::new(); + for c in s { if c as u32 > 0x7F { - str_pos_lint(cx, NON_ASCII_LITERAL, span, i, &format!( - "literal non-ASCII character detected. Consider using `\\u{{{:X}}}`", c as u32)); + for d in c.escape_unicode() { result.push(d) }; + } else { + result.push(c); } } + result } -#[allow(cast_possible_truncation)] -fn str_pos_lint(cx: &Context, lint: &'static Lint, span: Span, index: usize, msg: &str) { - span_lint(cx, lint, Span { lo: span.lo + BytePos((1 + index) as u32), - hi: span.lo + BytePos((1 + index) as u32), - expn_id: span.expn_id }, msg); - +fn check_str(cx: &Context, string: &str, span: Span) { + if string.contains('\u{200B}') { + span_help_and_lint(cx, ZERO_WIDTH_SPACE, span, + "zero-width space detected", + &format!("Consider replacing the string with:\n\"{}\"", + string.replace("\u{200B}", "\\u{200B}"))); + } + if string.chars().any(|c| c as u32 > 0x7F) { + span_help_and_lint(cx, NON_ASCII_LITERAL, span, + "literal non-ASCII character detected", + &format!("Consider replacing the string with:\n\"{}\"", + if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { + escape(string.chars()) + } else { + escape(string.nfc()) + })); + } + if string.chars().zip(string.nfc()).any(|(a, b)| a != b) { + if cx.current_level(NON_ASCII_LITERAL) == Level::Allow { + span_help_and_lint(cx, UNICODE_NOT_NFC, span, + "non-nfc unicode sequence detected", + &format!("Consider replacing the string with:\n\"{}\"", + string.nfc().collect::<String>())); + } + } } diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs index e4730f60de8..066825fc686 100755 --- a/tests/compile-fail/unicode.rs +++ b/tests/compile-fail/unicode.rs @@ -4,18 +4,17 @@ #[deny(zero_width_space)] fn zero() { print!("Here >​< is a ZWS, and ​another"); - //~^ ERROR zero-width space detected. Consider using `\u{200B}` - //~^^ ERROR zero-width space detected. Consider using `\u{200B}` + //~^ ERROR zero-width space detected } -//#[deny(unicode_canon)] +#[deny(unicode_not_nfc)] fn canon() { - print!("̀ah?"); //not yet ~ERROR non-canonical unicode sequence detected. Consider using à + print!("̀àh?"); //~ERROR non-nfc unicode sequence detected } #[deny(non_ascii_literal)] fn uni() { - print!("Üben!"); //~ERROR literal non-ASCII character detected. Consider using `\u{DC}` + print!("Üben!"); //~ERROR literal non-ASCII character detected } fn main() { -- cgit 1.4.1-3-g733a5 From 28212e4981f9a3f9eb187ed88cfdc4efbd90463f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 4 Sep 2015 14:24:49 +0200 Subject: fixed dogfood by using snippet instead of the (escaped) literal string --- src/unicode.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/unicode.rs b/src/unicode.rs index 5e1af6f9818..e745c0960ea 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -4,7 +4,7 @@ use syntax::codemap::Span; use unicode_normalization::UnicodeNormalization; -use utils::span_help_and_lint; +use utils::{snippet, span_help_and_lint}; declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "using a zero-width space in a string literal, which is confusing" } @@ -26,8 +26,8 @@ impl LintPass for Unicode { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprLit(ref lit) = expr.node { - if let LitStr(ref string, _) = lit.node { - check_str(cx, string, lit.span) + if let LitStr(_, _) = lit.node { + check_str(cx, lit.span) } } } @@ -45,7 +45,8 @@ fn escape<T: Iterator<Item=char>>(s: T) -> String { result } -fn check_str(cx: &Context, string: &str, span: Span) { +fn check_str(cx: &Context, span: Span) { + let string = snippet(cx, span, ""); if string.contains('\u{200B}') { span_help_and_lint(cx, ZERO_WIDTH_SPACE, span, "zero-width space detected", @@ -62,12 +63,11 @@ fn check_str(cx: &Context, string: &str, span: Span) { escape(string.nfc()) })); } - if string.chars().zip(string.nfc()).any(|(a, b)| a != b) { - if cx.current_level(NON_ASCII_LITERAL) == Level::Allow { - span_help_and_lint(cx, UNICODE_NOT_NFC, span, - "non-nfc unicode sequence detected", - &format!("Consider replacing the string with:\n\"{}\"", - string.nfc().collect::<String>())); - } + if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && + string.chars().zip(string.nfc()).any(|(a, b)| a != b) { + span_help_and_lint(cx, UNICODE_NOT_NFC, span, + "non-nfc unicode sequence detected", + &format!("Consider replacing the string with:\n\"{}\"", + string.nfc().collect::<String>())); } } -- cgit 1.4.1-3-g733a5 From cd91110ec0ca4f823145a13033cfd45f74ce72c6 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 5 Sep 2015 12:46:34 +0200 Subject: new lint: min_max --- README.md | 3 +- src/consts.rs | 8 ++-- src/lib.rs | 3 ++ src/minmax.rs | 90 +++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/min_max.rs | 25 ++++++++++++ 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 src/minmax.rs create mode 100644 tests/compile-fail/min_max.rs (limited to 'src') diff --git a/README.md b/README.md index 0046d891129..590ba60d552 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 54 lints included in this crate: +There are 55 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -31,6 +31,7 @@ name [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead +[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | deny | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) [needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` diff --git a/src/consts.rs b/src/consts.rs index a8a446a703f..5e7cd200d0f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -121,10 +121,10 @@ impl PartialOrd for Constant { (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => Some(match (is_negative(lty) && *lv != 0, is_negative(rty) && *rv != 0) { - (true, true) => lv.cmp(rv), - (false, false) => rv.cmp(lv), - (true, false) => Greater, - (false, true) => Less, + (true, true) => rv.cmp(lv), + (false, false) => lv.cmp(rv), + (true, false) => Less, + (false, true) => Greater, }), (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => if match (lw, rw) { diff --git a/src/lib.rs b/src/lib.rs index a4aee0c27fd..7665d06b193 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; pub mod identity_op; +pub mod minmax; pub mod mut_mut; pub mod len_zero; pub mod attrs; @@ -85,6 +86,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); reg.register_lint_pass(box matches::MatchPass as LintPassObject); reg.register_lint_pass(box misc::PatternPass as LintPassObject); + reg.register_lint_pass(box minmax::MinMaxPass as LintPassObject); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -125,6 +127,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::STR_TO_STRING, methods::STRING_TO_STRING, methods::WRONG_SELF_CONVENTION, + minmax::MIN_MAX, misc::CMP_NAN, misc::CMP_OWNED, misc::FLOAT_CMP, diff --git a/src/minmax.rs b/src/minmax.rs new file mode 100644 index 00000000000..2e4c9256657 --- /dev/null +++ b/src/minmax.rs @@ -0,0 +1,90 @@ +use rustc::lint::{Context, LintPass, LintArray}; +use rustc_front::hir::*; +use syntax::codemap::Spanned; +use syntax::ptr::P; +use std::cmp::PartialOrd; +use std::cmp::Ordering::*; + +use consts::{Constant, constant}; +use utils::{match_path, span_lint}; +use self::MinMax::{Min, Max}; + +declare_lint!(pub MIN_MAX, Deny, + "`min(_, max(_, _))` (or vice versa) with bounds clamping the result \ + to a constant"); + +#[allow(missing_copy_implementations)] +pub struct MinMaxPass; + +impl LintPass for MinMaxPass { + fn get_lints(&self) -> LintArray { + lint_array!(MIN_MAX) + } + + fn check_expr(&mut self, cx: &Context, expr: &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 { return; } + match (outer_max, outer_c.partial_cmp(&inner_c)) { + (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), + _ => { + span_lint(cx, MIN_MAX, expr.span, + "this min/max combination leads to constant result") + }, + } + } + } + } +} + +#[derive(PartialEq, Eq, Debug)] +enum MinMax { + Min, + Max, +} + +fn min_max<'e>(cx: &Context, expr: &'e Expr) -> + Option<(MinMax, Constant, &'e Expr)> { + match expr.node { + ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { + let name = ident.name; + if name == "min" { + fetch_const(cx, args, Min) + } else { + if name == "max" { + fetch_const(cx, args, Max) + } else { + None + } + } + }, + ExprCall(ref path, ref args) => { + if let &ExprPath(None, ref path) = &path.node { + if match_path(path, &["min"]) { + fetch_const(cx, args, Min) + } else { + if match_path(path, &["max"]) { + fetch_const(cx, args, Max) + } else { + None + } + } + } else { None } + }, + _ => None, + } + } + +fn fetch_const<'e>(cx: &Context, args: &'e Vec<P<Expr>>, m: MinMax) -> + Option<(MinMax, Constant, &'e Expr)> { + if args.len() != 2 { return None } + if let Some((c, _)) = constant(cx, &args[0]) { + if let None = constant(cx, &args[1]) { // otherwise ignore + Some((m, c, &args[1])) + } else { None } + } else { + if let Some((c, _)) = constant(cx, &args[1]) { + Some((m, c, &args[0])) + } else { None } + } +} diff --git a/tests/compile-fail/min_max.rs b/tests/compile-fail/min_max.rs new file mode 100644 index 00000000000..18f415ddc0b --- /dev/null +++ b/tests/compile-fail/min_max.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] + +#![plugin(clippy)] +#![deny(clippy)] + +use std::cmp::{min, max}; + +fn main() { + let x; + x = 2usize; + min(1, max(3, x)); //~ERROR this min/max combination leads to constant result + min(max(3, x), 1); //~ERROR this min/max combination leads to constant result + max(min(x, 1), 3); //~ERROR this min/max combination leads to constant result + max(3, min(x, 1)); //~ERROR this min/max combination leads to constant result + + min(3, max(1, x)); // ok, could be 1, 2 or 3 depending on x + + let s; + s = "Hello"; + + min("Apple", max("Zoo", s)); //~ERROR this min/max combination leads to constant result + max(min(s, "Apple"), "Zoo"); //~ERROR this min/max combination leads to constant result + + max("Apple", min(s, "Zoo")); // ok +} -- cgit 1.4.1-3-g733a5 From b90e4c7bd51e3193504d7acf8cfc3220933cd5ee Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 5 Sep 2015 13:15:18 +0200 Subject: hir naming, removed lookup, match full path --- src/consts.rs | 2 +- src/minmax.rs | 51 +++++++++++++++++---------------------------------- 2 files changed, 18 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 5e7cd200d0f..0c32dc5efad 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -154,8 +154,8 @@ impl PartialOrd for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { match *lit { LitStr(ref is, style) => ConstantStr(is.to_string(), style), - LitBinary(ref blob) => ConstantBinary(blob.clone()), LitByte(b) => ConstantByte(b), + LitByteStr(ref s) => ConstantBinary(s.clone()), LitChar(c) => ConstantChar(c), LitInt(value, ty) => ConstantInt(value, ty), LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), diff --git a/src/minmax.rs b/src/minmax.rs index 2e4c9256657..d7a74aa8c8b 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,11 +1,10 @@ use rustc::lint::{Context, LintPass, LintArray}; use rustc_front::hir::*; -use syntax::codemap::Spanned; use syntax::ptr::P; use std::cmp::PartialOrd; use std::cmp::Ordering::*; -use consts::{Constant, constant}; +use consts::{Constant, constant_simple}; use utils::{match_path, span_lint}; use self::MinMax::{Min, Max}; @@ -22,8 +21,8 @@ impl LintPass for MinMaxPass { } fn check_expr(&mut self, cx: &Context, expr: &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 let Some((outer_max, outer_c, oe)) = min_max(expr) { + if let Some((inner_max, inner_c, _)) = min_max(oe) { if outer_max == inner_max { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), @@ -43,47 +42,31 @@ enum MinMax { Max, } -fn min_max<'e>(cx: &Context, expr: &'e Expr) -> - Option<(MinMax, Constant, &'e Expr)> { - match expr.node { - ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { - let name = ident.name; - if name == "min" { - fetch_const(cx, args, Min) +fn min_max(expr: &Expr) -> Option<(MinMax, Constant, &Expr)> { + if let ExprCall(ref path, ref args) = expr.node { + if let ExprPath(None, ref path) = path.node { + if match_path(path, &["std", "cmp", "min"]) { + fetch_const(args, Min) } else { - if name == "max" { - fetch_const(cx, args, Max) + if match_path(path, &["std", "cmp", "max"]) { + fetch_const(args, Max) } else { None } } - }, - ExprCall(ref path, ref args) => { - if let &ExprPath(None, ref path) = &path.node { - if match_path(path, &["min"]) { - fetch_const(cx, args, Min) - } else { - if match_path(path, &["max"]) { - fetch_const(cx, args, Max) - } else { - None - } - } - } else { None } - }, - _ => None, - } + } else { None } + } else { None } } -fn fetch_const<'e>(cx: &Context, args: &'e Vec<P<Expr>>, m: MinMax) -> - Option<(MinMax, Constant, &'e Expr)> { +fn fetch_const(args: &[P<Expr>], m: MinMax) -> + Option<(MinMax, Constant, &Expr)> { if args.len() != 2 { return None } - if let Some((c, _)) = constant(cx, &args[0]) { - if let None = constant(cx, &args[1]) { // otherwise ignore + if let Some(c) = constant_simple(&args[0]) { + if let None = constant_simple(&args[1]) { // otherwise ignore Some((m, c, &args[1])) } else { None } } else { - if let Some((c, _)) = constant(cx, &args[1]) { + if let Some(c) = constant_simple(&args[1]) { Some((m, c, &args[0])) } else { None } } -- cgit 1.4.1-3-g733a5 From 3848756be09744d0947f7472a340764e7ecd2249 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 5 Sep 2015 14:20:35 +0200 Subject: Made min_max `Warn` by default --- src/minmax.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/minmax.rs b/src/minmax.rs index d7a74aa8c8b..72190d70e2e 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -8,7 +8,7 @@ use consts::{Constant, constant_simple}; use utils::{match_path, span_lint}; use self::MinMax::{Min, Max}; -declare_lint!(pub MIN_MAX, Deny, +declare_lint!(pub MIN_MAX, Warn, "`min(_, max(_, _))` (or vice versa) with bounds clamping the result \ to a constant"); -- cgit 1.4.1-3-g733a5 From 54393f0ef5ecabf43da2f4749d16eb1145ad0455 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 10:53:55 +0200 Subject: More strict macro check --- src/attrs.rs | 17 ++++++------- src/collapsible_if.rs | 11 ++++---- src/identity_op.rs | 29 ++++++++++------------ src/mut_mut.rs | 10 +++----- src/types.rs | 4 +-- src/utils.rs | 69 +++++++++++++++++++++++++++++---------------------- 6 files changed, 71 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 05362c706f0..e6185d8b400 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; -use syntax::codemap::ExpnInfo; +use syntax::codemap::Span; use utils::{in_macro, match_path, span_lint}; @@ -21,22 +21,19 @@ impl LintPass for AttrPass { fn check_item(&mut self, cx: &Context, item: &Item) { if is_relevant_item(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + check_attrs(cx, item.span, &item.ident, &item.attrs) } } fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { if is_relevant_impl(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + check_attrs(cx, item.span, &item.ident, &item.attrs) } } fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { if is_relevant_trait(item) { - cx.sess().codemap().with_expn_info(item.span.expn_id, - |info| check_attrs(cx, info, &item.ident, &item.attrs)) + check_attrs(cx, item.span, &item.ident, &item.attrs) } } } @@ -89,9 +86,9 @@ fn is_relevant_expr(expr: &Expr) -> bool { } } -fn check_attrs(cx: &Context, info: Option<&ExpnInfo>, ident: &Ident, - attrs: &[Attribute]) { - if in_macro(cx, info) { return; } +fn check_attrs(cx: &Context, span: Span, ident: &Ident, + attrs: &[Attribute]) { + if in_macro(cx, span) { return; } for attr in attrs { if let MetaList(ref inline, ref values) = attr.node.value.node { diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 9301aafbace..7326bd20c7c 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -14,7 +14,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::codemap::{Spanned, ExpnInfo}; +use syntax::codemap::Spanned; use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; @@ -34,14 +34,13 @@ impl LintPass for CollapsibleIf { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - cx.sess().codemap().with_expn_info(expr.span.expn_id, - |info| check_expr_expd(cx, expr, info)) + if !in_macro(cx, expr.span) { + check_if(cx, expr) + } } } -fn check_expr_expd(cx: &Context, e: &Expr, info: Option<&ExpnInfo>) { - if in_macro(cx, info) { return; } - +fn check_if(cx: &Context, e: &Expr) { if let ExprIf(ref check, ref then, None) = e.node { if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = single_stmt_of_block(then) { diff --git a/src/identity_op.rs b/src/identity_op.rs index 0225c9b4d69..9601a685690 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -2,9 +2,9 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use consts::{constant, is_negative}; +use consts::{constant_simple, is_negative}; use consts::Constant::ConstantInt; -use utils::{span_lint, snippet, in_external_macro}; +use utils::{span_lint, snippet, in_macro}; declare_lint! { pub IDENTITY_OP, Warn, "using identity operations, e.g. `x + 0` or `y / 1`" } @@ -18,6 +18,7 @@ impl LintPass for IdentityOp { } fn check_expr(&mut self, cx: &Context, e: &Expr) { + if in_macro(cx, e.span) { return; } if let ExprBinary(ref cmp, ref left, ref right) = e.node { match cmp.node { BiAdd | BiBitOr | BiBitXor => { @@ -44,20 +45,16 @@ impl LintPass for IdentityOp { fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some((c, needed_resolution)) = constant(cx, e) { - if needed_resolution { return; } // skip linting w/ lookup for now - if let ConstantInt(v, ty) = c { - if match m { - 0 => v == 0, - -1 => is_negative(ty) && v == 1, - 1 => !is_negative(ty) && v == 1, - _ => unreachable!(), - } { - if in_external_macro(cx, e.span) {return;} - span_lint(cx, IDENTITY_OP, span, &format!( - "the operation is ineffective. Consider reducing it to `{}`", - snippet(cx, arg, ".."))); - } + if let Some(ConstantInt(v, ty)) = constant_simple(e) { + if match m { + 0 => v == 0, + -1 => is_negative(ty) && v == 1, + 1 => !is_negative(ty) && v == 1, + _ => unreachable!(), + } { + span_lint(cx, IDENTITY_OP, span, &format!( + "the operation is ineffective. Consider reducing it to `{}`", + snippet(cx, arg, ".."))); } } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 236d9b6a5a2..b6260bb8ecc 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,9 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::codemap::ExpnInfo; use rustc::middle::ty::{TypeAndMut, TyRef}; -use utils::{in_macro, span_lint}; +use utils::{in_external_macro, span_lint}; declare_lint!(pub MUT_MUT, Warn, "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ @@ -18,8 +17,7 @@ impl LintPass for MutMut { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - cx.sess().codemap().with_expn_info(expr.span.expn_id, - |info| check_expr_expd(cx, expr, info)) + check_expr_mut(cx, expr) } fn check_ty(&mut self, cx: &Context, ty: &Ty) { @@ -28,8 +26,8 @@ impl LintPass for MutMut { } } -fn check_expr_expd(cx: &Context, expr: &Expr, info: Option<&ExpnInfo>) { - if in_macro(cx, info) { return; } +fn check_expr_mut(cx: &Context, expr: &Expr) { + if in_external_macro(cx, expr.span) { return; } fn unwrap_addr(expr : &Expr) -> Option<&Expr> { match expr.node { diff --git a/src/types.rs b/src/types.rs index 9fa63f1986c..44c0cd78148 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,7 +6,7 @@ use syntax::codemap::Span; use rustc_front::visit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; -use utils::{match_type, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{match_type, snippet, span_lint, span_help_and_lint, in_macro, in_external_macro}; use utils::{LL_PATH, VEC_PATH}; /// Handles all the linting of funky types @@ -321,7 +321,7 @@ fn check_fndecl(cx: &Context, decl: &FnDecl) { } fn check_type(cx: &Context, ty: &Ty) { - if in_external_macro(cx, ty.span) { return; } + if in_macro(cx, ty.span) { return; } let score = { let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; visitor.visit_ty(ty); diff --git a/src/utils.rs b/src/utils.rs index 860ad85aab9..33e53710df3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,40 +14,51 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; -/// returns true if the macro that expanded the crate was outside of -/// the current crate or was a compiler plugin -pub fn in_macro(cx: &Context, opt_info: Option<&ExpnInfo>) -> bool { - // no ExpnInfo = no macro - opt_info.map_or(false, |info| { - match info.callee.format { - ExpnFormat::CompilerExpansion(..) => { - if info.callee.name() == "closure expansion" { - return false; - } - }, - ExpnFormat::MacroAttribute(..) => { - // these are all plugins - return true; - }, - _ => (), +/// returns true this expn_info was expanded by any macro +pub fn in_macro(cx: &Context, span: Span) -> bool { + cx.sess().codemap().with_expn_info(span.expn_id, + |info| info.map_or(false, |i| { + match i.callee.format { + ExpnFormat::CompilerExpansion(..) => false, + _ => true, } - // no span for the callee = external macro - info.callee.span.map_or(true, |span| { - // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| - // macro doesn't start with "macro_rules" - // = compiler plugin - !code.starts_with("macro_rules") - ) - }) - }) + })) } -/// invokes in_macro with the expansion info of the given span -/// slightly heavy, try to use this after other checks have already happened +/// 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: &Context, 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: &Context, opt_info: Option<&ExpnInfo>) -> bool { + // no ExpnInfo = no macro + opt_info.map_or(false, |info| { + match info.callee.format { + ExpnFormat::CompilerExpansion(..) => { + if info.callee.name() == "closure expansion" { + return false; + } + }, + ExpnFormat::MacroAttribute(..) => { + // these are all plugins + return true; + }, + _ => (), + } + // no span for the callee = external macro + info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + // macro doesn't start with "macro_rules" + // = compiler plugin + !code.starts_with("macro_rules") + ) + }) + }) + } + cx.sess().codemap().with_expn_info(span.expn_id, - |info| in_macro(cx, info)) + |info| in_macro_ext(cx, info)) } /// check if a DefId's path matches the given absolute type path -- cgit 1.4.1-3-g733a5 From 55729b7caabca9ceac7a920ff09f0c80dc081d0a Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 10:59:06 +0200 Subject: dogfooding a newly caught problem --- src/loops.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index d40eca8c0f3..099ff7910ac 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -84,12 +84,11 @@ impl LintPass for LoopsPass { } } // check for looping over Iterator::next() which is not what you want - else if method_name == "next" { - if match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { - span_lint(cx, ITER_NEXT_LOOP, expr.span, - "you are iterating over `Iterator::next()` which is an Option; \ - this will compile but is probably not what you want"); - } + else if method_name == "next" && + match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + span_lint(cx, ITER_NEXT_LOOP, expr.span, + "you are iterating over `Iterator::next()` which is an Option; \ + this will compile but is probably not what you want"); } } } @@ -127,12 +126,11 @@ impl LintPass for LoopsPass { fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 && method.node.name == "collect" { - if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { - span_lint(cx, UNUSED_COLLECT, expr.span, &format!( - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator")); - } + if args.len() == 1 && method.node.name == "collect" && + match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + span_lint(cx, UNUSED_COLLECT, expr.span, &format!( + "you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator")); } } } -- cgit 1.4.1-3-g733a5 From efd553c8a98ebe1799218aa05cf773f2ac57852c Mon Sep 17 00:00:00 2001 From: inrustwetrust <inrustwetrust@users.noreply.github.com> Date: Sun, 6 Sep 2015 13:36:21 +0200 Subject: Don't show the explicit_iter_loop lint for arrays with more than 32 elements The IntoIterator trait is currently not implemented for arrays with more than 32 elements, so for longer arrays, the iter() or iter_mut() methods must be used. --- src/loops.rs | 7 ++++--- tests/compile-fail/for_loop.rs | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 099ff7910ac..d1a3e4ac7ab 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -199,7 +199,7 @@ fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); - is_array(ty) || + is_iterable_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) || @@ -210,9 +210,10 @@ fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) } -fn is_array(ty: ty::Ty) -> bool { +fn is_iterable_array(ty: ty::Ty) -> bool { + //IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { - ty::TyArray(..) => true, + ty::TyArray(_, 0...32) => true, _ => false } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 4d0c22fff0b..c8d1d383c78 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -42,6 +42,8 @@ fn main() { for _v in [1, 2, 3].iter() { } //~ERROR it is more idiomatic to loop over `&[ for _v in (&mut [1, 2, 3]).iter() { } // no error + for _v in [0; 32].iter() {} //~ERROR it is more idiomatic to loop over `&[ + for _v in [0; 33].iter() {} // no error let ll: LinkedList<()> = LinkedList::new(); for _v in ll.iter() { } //~ERROR it is more idiomatic to loop over `&ll` let vd: VecDeque<()> = VecDeque::new(); -- cgit 1.4.1-3-g733a5 From b76ad366abbd8085ed1f59ed09e95886de8c1ae1 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 16:09:35 +0200 Subject: fixed bad_bit_mask false positive --- README.md | 2 +- src/bit_mask.rs | 4 ++-- tests/compile-fail/bit_masks.rs | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index c7071688e10..0da19cbd620 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ There are 55 lints included in this crate: name | default | meaning -----------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | deny | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap [cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` [cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` diff --git a/src/bit_mask.rs b/src/bit_mask.rs index b1b8a735455..97d33b5e699 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -9,7 +9,7 @@ use utils::span_lint; declare_lint! { pub BAD_BIT_MASK, - Deny, + Warn, "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \ (because in the example `select` containing bits that `mask` doesn't have)" } @@ -98,7 +98,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { match cmp_op { BiEq | BiNe => match bit_op { - BiBitAnd => if mask_value & cmp_value != mask_value { + BiBitAnd => if mask_value & cmp_value != cmp_value { if cmp_value != 0 { span_lint(cx, BAD_BIT_MASK, *span, &format!( "incompatible bit mask: `_ & {}` can never be equal to `{}`", diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index 47e9c11138a..0b7b31b64a5 100755 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -25,6 +25,9 @@ fn main() { x | 2 > 1; //~ERROR incompatible bit mask x | 2 <= 2; // ok (if a bit silly), equals x <= 2 + x & 192 == 128; // ok, tests for bit 7 and not bit 6 + x & 0xffc0 == 0xfe80; // ok + // this also now works with constants x & THREE_BITS == 8; //~ERROR incompatible bit mask x | EVEN_MORE_REDIRECTION < 7; //~ERROR incompatible bit mask -- cgit 1.4.1-3-g733a5 From 0c74304f7b4351d6fb27b9c206ec25476c0228f3 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 19:41:09 +0200 Subject: macro check for unit_cmp --- src/types.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 44c0cd78148..6586ce2c703 100644 --- a/src/types.rs +++ b/src/types.rs @@ -85,6 +85,7 @@ impl LintPass for UnitCmp { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if in_macro(expr) { return; } if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; let sty = &cx.tcx.expr_ty(left).sty; -- cgit 1.4.1-3-g733a5 From 391a5135e88afe2e6f86319db45b96262f350c4d Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 19:44:54 +0200 Subject: fixed build --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 6586ce2c703..6d096e18b88 100644 --- a/src/types.rs +++ b/src/types.rs @@ -85,7 +85,7 @@ impl LintPass for UnitCmp { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if in_macro(expr) { return; } + if in_macro(cx, expr.span) { return; } if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; let sty = &cx.tcx.expr_ty(left).sty; -- cgit 1.4.1-3-g733a5 From 87e6099ad7eb145c8fb2704d267eeaa3fdba2a2f Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 20:57:06 +0200 Subject: fix false positive len_zero in is_empty() --- src/len_zero.rs | 22 +++++++++++++--------- src/misc.rs | 21 ++++++--------------- src/utils.rs | 15 ++++++++++++++- 3 files changed, 33 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index c30a98d8537..206f18217d1 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,7 +5,7 @@ use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use utils::{span_lint, walk_ptrs_ty, snippet}; +use utils::{snippet, span_lint, walk_ptrs_ty, with_item_name}; declare_lint!(pub LEN_ZERO, Warn, "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ @@ -33,14 +33,14 @@ impl LintPass for LenZero { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if let &ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = - &expr.node { - match cmp { - BiEq => check_cmp(cx, expr.span, left, right, ""), - BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), - _ => () - } + if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = + expr.node { + match cmp { + BiEq => check_cmp(cx, expr.span, left, right, ""), + BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), + _ => () } + } } } @@ -89,7 +89,11 @@ fn is_self_sig(sig: &MethodSig) -> bool { false } else { sig.decl.inputs.len() == 1 } } -fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { +fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { + // check if we are in an is_empty() method + if let Some(true) = with_item_name(cx, left, |n| n == "is_empty") { + return; + } match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => check_len_zero(cx, span, method, args, lit, op), diff --git a/src/misc.rs b/src/misc.rs index eb3a93941be..87cc512f819 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -5,10 +5,9 @@ use reexport::*; use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; use rustc_front::visit::FnKind; -use rustc::front::map::Node::*; use rustc::middle::ty; -use utils::{match_path, snippet, span_lint, walk_ptrs_ty}; +use utils::{match_path, snippet, span_lint, walk_ptrs_ty, with_item_name}; use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, @@ -93,19 +92,11 @@ impl LintPass for FloatCmp { false, |c| c.0.as_float().map_or(false, |f| f == 0.0)) { return; } - let parent_id = cx.tcx.map.get_parent(expr.id); - match cx.tcx.map.find(parent_id) { - Some(NodeItem(&Item{ ref ident, .. })) | - Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | - Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { - let name = ident.name.as_str(); - if &*name == "eq" || &*name == "ne" || - name.starts_with("eq_") || - name.ends_with("_eq") { - return; - } - }, - _ => (), + if let Some(true) = with_item_name(cx, expr, |name| + name == "eq" || name == "ne" || + name.as_str().starts_with("eq_") || + name.as_str().ends_with("_eq")) { + return; } span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-comparison of f32 or f64 detected. Consider changing this to \ diff --git a/src/utils.rs b/src/utils.rs index 33e53710df3..c781b74b359 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; -use rustc::front::map::Node::NodeExpr; +use rustc::front::map::Node::*; use rustc::middle::def_id::DefId; use rustc::middle::ty; use std::borrow::Cow; @@ -100,6 +100,19 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { |(a, b)| &a.identifier.name == b) } +pub fn with_item_name<T, F>(cx: &Context, expr: &Expr, f: F) -> Option<T> +where F: FnOnce(Name) -> T { + let parent_id = cx.tcx.map.get_parent(expr.id); + match cx.tcx.map.find(parent_id) { + Some(NodeItem(&Item{ ref ident, .. })) | + Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | + Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { + Some(f(ident.name)) + }, + _ => None, + } +} + /// convert a span to a code snippet if available, otherwise use default, e.g. /// `snippet(cx, expr.span, "..")` pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { -- cgit 1.4.1-3-g733a5 From 468b410d04a486bf9208be5136feee93d3818c21 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 6 Sep 2015 21:03:09 +0200 Subject: de-closured the item name getter --- src/len_zero.rs | 6 +++--- src/misc.rs | 13 +++++++------ src/utils.rs | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 206f18217d1..45b9c844af3 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,7 +5,7 @@ use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use utils::{snippet, span_lint, walk_ptrs_ty, with_item_name}; +use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; declare_lint!(pub LEN_ZERO, Warn, "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ @@ -91,8 +91,8 @@ fn is_self_sig(sig: &MethodSig) -> bool { fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { // check if we are in an is_empty() method - if let Some(true) = with_item_name(cx, left, |n| n == "is_empty") { - return; + if let Some(name) = get_item_name(cx, left) { + if name == "is_empty" { return; } } match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => diff --git a/src/misc.rs b/src/misc.rs index 87cc512f819..8891b000b59 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,7 +7,7 @@ use syntax::codemap::{Span, Spanned}; use rustc_front::visit::FnKind; use rustc::middle::ty; -use utils::{match_path, snippet, span_lint, walk_ptrs_ty, with_item_name}; +use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty}; use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, @@ -92,11 +92,12 @@ impl LintPass for FloatCmp { false, |c| c.0.as_float().map_or(false, |f| f == 0.0)) { return; } - if let Some(true) = with_item_name(cx, expr, |name| - name == "eq" || name == "ne" || - name.as_str().starts_with("eq_") || - name.as_str().ends_with("_eq")) { - return; + if let Some(name) = get_item_name(cx, expr) { + if name == "eq" || name == "ne" || + name.as_str().starts_with("eq_") || + name.as_str().ends_with("_eq") { + return; + } } span_lint(cx, FLOAT_CMP, expr.span, &format!( "{}-comparison of f32 or f64 detected. Consider changing this to \ diff --git a/src/utils.rs b/src/utils.rs index c781b74b359..d6e529048c9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -100,14 +100,14 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { |(a, b)| &a.identifier.name == b) } -pub fn with_item_name<T, F>(cx: &Context, expr: &Expr, f: F) -> Option<T> -where F: FnOnce(Name) -> T { +/// get the name of the item the expression is in, if available +pub fn get_item_name(cx: &Context, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { Some(NodeItem(&Item{ ref ident, .. })) | Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { - Some(f(ident.name)) + Some(ident.name) }, _ => None, } -- cgit 1.4.1-3-g733a5 From 92b04cd75db905dcb21ffabf10c005560c4e0f80 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 7 Sep 2015 09:17:45 +0200 Subject: split wrong_self_convention in pub/default visibility part --- README.md | 119 +++++++++++++++++++++++++++++---------------------------- src/lib.rs | 1 + src/methods.rs | 10 ++++- 3 files changed, 70 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 0da19cbd620..060eac942ba 100644 --- a/README.md +++ b/README.md @@ -4,65 +4,66 @@ A collection of lints that give helpful tips to newbies and catch oversights. ##Lints -There are 55 lints included in this crate: - -name | default | meaning ------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` -[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` -[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` -[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` -[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) -[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` -[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` -[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases -[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended -[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` -[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function -[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf -[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead -[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant -[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 -[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do -[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice -[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught -[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively -[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 -[redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern -[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled -[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` -[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` -[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | warn | The name is re-bound without even using the original value -[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait -[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` -[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op -[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) -[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions -[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) -[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) -[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop -[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop -[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention -[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing +There are 56 lints included in this crate: + +name | default | meaning +-------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` +[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) +[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended +[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` +[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a function +[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead +[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant +[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 +[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do +[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice +[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught +[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +[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 +[redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern +[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled +[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` +[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` +[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | warn | The name is re-bound without even using the original value +[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` +[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op +[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions +[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) +[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention +[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention +[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/lib.rs b/src/lib.rs index 7665d06b193..fdb0f975109 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, + methods::WRONG_PUB_SELF_CONVENTION, ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, diff --git a/src/methods.rs b/src/methods.rs index 4f64f0f7a94..c3ad4762873 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -27,6 +27,9 @@ declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, declare_lint!(pub WRONG_SELF_CONVENTION, Warn, "defining a method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); +declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, + "defining a public method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { @@ -93,7 +96,12 @@ impl LintPass for MethodsPass { for &(prefix, self_kinds) in &CONVENTIONS { if name.as_str().starts_with(prefix) && !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { - span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!( + let lint = if let Visibility::Public = item.vis { + WRONG_PUB_SELF_CONVENTION + } else { + WRONG_SELF_CONVENTION + }; + span_lint(cx, lint, sig.explicit_self.span, &format!( "methods called `{}*` usually take {}; consider choosing a less \ ambiguous name", prefix, &self_kinds.iter().map(|k| k.description()).collect::<Vec<_>>().join(" or "))); -- cgit 1.4.1-3-g733a5 From c79d8844501e7fe92bcabbf2da2024b35d1682f7 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 7 Sep 2015 11:46:04 +0200 Subject: replace if let by equality check --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index c3ad4762873..b9132399652 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -96,7 +96,7 @@ impl LintPass for MethodsPass { for &(prefix, self_kinds) in &CONVENTIONS { if name.as_str().starts_with(prefix) && !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { - let lint = if let Visibility::Public = item.vis { + let lint = if item.VI's == Visibility::Public { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION -- cgit 1.4.1-3-g733a5 From e43f2d7e5480272e75b7583ffbfab4293715cda1 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 7 Sep 2015 11:49:35 +0200 Subject: damn autocorrect --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index b9132399652..b110d92e7f8 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -96,7 +96,7 @@ impl LintPass for MethodsPass { for &(prefix, self_kinds) in &CONVENTIONS { if name.as_str().starts_with(prefix) && !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { - let lint = if item.VI's == Visibility::Public { + let lint = if item.vis == Visibility::Public { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION -- cgit 1.4.1-3-g733a5 From 0e658afc1bd3447e1f10a5cb67002512ea45ba3c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 8 Sep 2015 02:28:15 +0530 Subject: Fix mut_mut false positive, make Allow (fixes #309) --- README.md | 2 +- src/lib.rs | 2 +- src/mut_mut.rs | 3 +-- tests/compile-fail/mut_mut.rs | 7 +++++++ 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 060eac942ba..ca96e496bfe 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ name [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 -[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | warn | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) [needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` [needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do diff --git a/src/lib.rs b/src/lib.rs index fdb0f975109..7ce2be97358 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,6 +92,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, + mut_mut::MUT_MUT, ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, @@ -135,7 +136,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, - mut_mut::MUT_MUT, needless_bool::NEEDLESS_BOOL, precedence::PRECEDENCE, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/mut_mut.rs b/src/mut_mut.rs index b6260bb8ecc..d3270861870 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -4,7 +4,7 @@ use rustc::middle::ty::{TypeAndMut, TyRef}; use utils::{in_external_macro, span_lint}; -declare_lint!(pub MUT_MUT, Warn, +declare_lint!(pub MUT_MUT, Allow, "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ or shows a fundamental misunderstanding of references)"); @@ -53,7 +53,6 @@ fn check_expr_mut(cx: &Context, expr: &Expr) { fn unwrap_mut(ty : &Ty) -> Option<&Ty> { match ty.node { - TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), _ => Option::None } diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 8aa47769539..2560a54c0ef 100755 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -1,6 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(unused)] + //#![plugin(regex_macros)] //extern crate regex; @@ -9,6 +11,11 @@ fn fun(x : &mut &mut u32) -> bool { //~ERROR generally you want to avoid `&mut & **x > 0 } +#[deny(mut_mut)] +fn less_fun(x : *mut *mut u32) { + let y = x; +} + macro_rules! mut_ptr { ($p:expr) => { &mut $p } } -- cgit 1.4.1-3-g733a5 From 4835372df559ff2e14edcdba409f5a6566a779bc Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 8 Sep 2015 11:50:04 +0200 Subject: made shadow_unrelated allow, added previous binding span note, fixed #319 --- README.md | 2 +- src/lib.rs | 2 +- src/shadow.rs | 55 ++++++++++++++++++++++++++++---------------- tests/compile-fail/shadow.rs | 5 ++++ 4 files changed, 42 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index ca96e496bfe..fdd341efa45 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ name [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled [shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` -[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | warn | The name is re-bound without even using the original value +[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value [should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait [single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead [str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` diff --git a/src/lib.rs b/src/lib.rs index 7ce2be97358..ddaa3bf490c 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::CAST_POSSIBLE_TRUNCATION, @@ -141,7 +142,6 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, - shadow::SHADOW_UNRELATED, types::BOX_VEC, types::LET_UNIT_VALUE, types::LINKEDLIST, diff --git a/src/shadow.rs b/src/shadow.rs index aaa2c91a036..ae1eeee2401 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -4,7 +4,7 @@ use reexport::*; use syntax::codemap::Span; use rustc_front::visit::FnKind; -use rustc::lint::{Context, LintArray, LintPass}; +use rustc::lint::{Context, Level, Lint, LintArray, LintPass}; use rustc::middle::def::Def::{DefVariant, DefStruct}; use utils::{in_external_macro, snippet, span_lint, span_note_and_lint}; @@ -14,7 +14,7 @@ declare_lint!(pub SHADOW_SAME, Allow, declare_lint!(pub SHADOW_REUSE, Allow, "rebinding a name to an expression that re-uses the original value, e.g. \ `let x = x + 1`"); -declare_lint!(pub SHADOW_UNRELATED, Warn, +declare_lint!(pub SHADOW_UNRELATED, Allow, "The name is re-bound without even using the original value"); #[derive(Copy, Clone)] @@ -36,13 +36,13 @@ fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) { let mut bindings = Vec::new(); for arg in &decl.inputs { if let PatIdent(_, ident, _) = arg.pat.node { - bindings.push(ident.node.name) + bindings.push((ident.node.name, ident.span)) } } check_block(cx, block, &mut bindings); } -fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { +fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<(Name, Span)>) { let len = bindings.len(); for stmt in &block.stmts { match stmt.node { @@ -55,7 +55,7 @@ fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) { bindings.truncate(len); } -fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) { +fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; @@ -77,16 +77,23 @@ fn is_binding(cx: &Context, pat: &Pat) -> bool { } fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, - bindings: &mut Vec<Name>) { + bindings: &mut Vec<(Name, Span)>) { //TODO: match more stuff / destructuring match pat.node { PatIdent(_, ref ident, ref inner) => { let name = ident.node.name; if is_binding(cx, pat) { - if bindings.contains(&name) { - lint_shadow(cx, name, span, pat.span, init); - } else { - bindings.push(name); + let mut new_binding = true; + for tup in bindings.iter_mut() { + if tup.0 == name { + lint_shadow(cx, name, span, pat.span, init, tup.1); + tup.1 = ident.span; + new_binding = false; + break; + } + } + if new_binding { + bindings.push((name, ident.span)); } } if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } @@ -141,20 +148,25 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, }, PatRegion(ref inner, _) => check_pat(cx, inner, init, span, bindings), - //PatRange(P<Expr>, P<Expr>), //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), _ => (), } } fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: - &Option<T>) where T: Deref<Target=Expr> { + &Option<T>, prev_span: Span) where T: Deref<Target=Expr> { + fn note_orig(cx: &Context, lint: &'static Lint, span: Span) { + if cx.current_level(lint) != Level::Allow { + cx.sess().span_note(span, "previous binding is here"); + } + } if let Some(ref expr) = *init { if is_self_shadow(name, expr) { span_lint(cx, SHADOW_SAME, span, &format!( "{} is shadowed by itself in {}", snippet(cx, lspan, "_"), snippet(cx, expr.span, ".."))); + note_orig(cx, SHADOW_SAME, prev_span); } else { if contains_self(name, expr) { span_note_and_lint(cx, SHADOW_REUSE, lspan, &format!( @@ -162,21 +174,24 @@ fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); + note_orig(cx, SHADOW_REUSE, prev_span); } else { span_note_and_lint(cx, SHADOW_UNRELATED, lspan, &format!( "{} is shadowed by {}", snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); + note_orig(cx, SHADOW_UNRELATED, prev_span); } } } else { span_lint(cx, SHADOW_UNRELATED, span, &format!( "{} shadows a previous declaration", snippet(cx, lspan, "_"))); + note_orig(cx, SHADOW_UNRELATED, prev_span); } } -fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { +fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, expr.span) { return; } match expr.node { ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | @@ -205,20 +220,20 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) { for ref arm in arms { for ref pat in &arm.pats { check_pat(cx, &pat, &Some(&**init), pat.span, bindings); - //TODO: This is ugly, but needed to get the right type - } - if let Some(ref guard) = arm.guard { - check_expr(cx, guard, bindings); + //This is ugly, but needed to get the right type + if let Some(ref guard) = arm.guard { + check_expr(cx, guard, bindings); + } + check_expr(cx, &arm.body, bindings); + bindings.truncate(len); } - check_expr(cx, &arm.body, bindings); - bindings.truncate(len); } }, _ => () } } -fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) { +fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { match ty.node { TyParen(ref sty) | TyObjectSum(ref sty, _) | TyVec(ref sty) => check_ty(cx, sty, bindings), diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 80d48f84163..293d97a42fa 100755 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -27,4 +27,9 @@ fn main() { Some(p) => p, // no error, because the p above is in its own scope None => 0, }; + + match (x, o) { + (1, Some(a)) | (a, Some(1)) => (), // no error though `a` appears twice + _ => (), + } } -- cgit 1.4.1-3-g733a5 From 0e1bc74683c7901f8432499eccb890f9f6b29ad9 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 10 Sep 2015 08:51:14 +0200 Subject: additional macro check + more tests --- src/types.rs | 4 ++-- tests/compile-fail/let_unit.rs | 12 ++++++++++++ tests/compile-fail/unit_cmp.rs | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 6d096e18b88..08a8560fcd6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -50,12 +50,12 @@ pub struct LetPass; declare_lint!(pub LET_UNIT_VALUE, Warn, "creating a let binding to a value of unit type, which usually can't be used afterwards"); - fn check_let_unit(cx: &Context, decl: &Decl) { if let DeclLocal(ref local) = decl.node { let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { - if in_external_macro(cx, decl.span) { return; } + if in_external_macro(cx, decl.span) || + in_macro(cx, local.pat.span) { return; } span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( "this let-binding has unit value. Consider omitting `let {} =`", snippet(cx, local.pat.span, ".."))); diff --git a/tests/compile-fail/let_unit.rs b/tests/compile-fail/let_unit.rs index f06a10bfe13..a0143406e52 100755 --- a/tests/compile-fail/let_unit.rs +++ b/tests/compile-fail/let_unit.rs @@ -2,6 +2,13 @@ #![plugin(clippy)] #![deny(let_unit_value)] +#![allow(unused_variables)] + +macro_rules! let_and_return { + ($n:expr) => {{ + let ret = $n; + }} +} fn main() { let _x = println!("x"); //~ERROR this let-binding has unit value @@ -10,4 +17,9 @@ fn main() { if true { let _a = (); //~ERROR this let-binding has unit value } + + let_and_return!(()) // should be fine } + +#[derive(Copy, Clone)] +pub struct ContainsUnit(()); // should be fine diff --git a/tests/compile-fail/unit_cmp.rs b/tests/compile-fail/unit_cmp.rs index e246d9f3909..af28f849e8c 100755 --- a/tests/compile-fail/unit_cmp.rs +++ b/tests/compile-fail/unit_cmp.rs @@ -3,6 +3,9 @@ #![deny(unit_cmp)] +#[derive(PartialEq)] +pub struct ContainsUnit(()); // should be fine + fn main() { // this is fine if true == false { -- cgit 1.4.1-3-g733a5 From 681bce925f92eaebc5ae3fc40a6a4a8720e46790 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 11 Sep 2015 15:30:08 +0200 Subject: less false positives for approx_const and float_cmp --- src/approx_const.rs | 10 +++++++++- src/misc.rs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index a132bc90361..9a3d46c14bb 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,8 +1,9 @@ use rustc::lint::*; +use rustc::metadata::cstore::crate_metadata; use rustc_front::hir::*; use syntax::codemap::Span; +use std::borrow::Borrow; use std::f64::consts as f64; - use utils::span_lint; declare_lint! { @@ -31,6 +32,13 @@ impl LintPass for ApproxConstant { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let &ExprLit(ref lit) = &e.node { + if let Some(res) = cx.tcx.def_map.borrow().get(&e.id) { + let krate = res.def_id().krate; + let cdata = &cx.sess().cstore.get_crate_data(krate); + let crate_data : &crate_metadata = cdata.borrow(); + let name = &crate_data.name; + if name == "f32" || name == "f64" { return; } + } check_lit(cx, lit, e.span); } } diff --git a/src/misc.rs b/src/misc.rs index 8891b000b59..2cd6babb9c5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -93,7 +93,7 @@ impl LintPass for FloatCmp { return; } if let Some(name) = get_item_name(cx, expr) { - if name == "eq" || name == "ne" || + if name == "eq" || name == "ne" || name == "is_nan" || name.as_str().starts_with("eq_") || name.as_str().ends_with("_eq") { return; -- cgit 1.4.1-3-g733a5 From 03af82afd162a7516796097710ab5dc4dd48acf3 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 11 Sep 2015 15:59:19 +0200 Subject: removed expensive crate check from approx_const --- src/approx_const.rs | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 9a3d46c14bb..29631b6852f 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,8 +1,5 @@ use rustc::lint::*; -use rustc::metadata::cstore::crate_metadata; use rustc_front::hir::*; -use syntax::codemap::Span; -use std::borrow::Borrow; use std::f64::consts as f64; use utils::span_lint; @@ -32,36 +29,28 @@ impl LintPass for ApproxConstant { fn check_expr(&mut self, cx: &Context, e: &Expr) { if let &ExprLit(ref lit) = &e.node { - if let Some(res) = cx.tcx.def_map.borrow().get(&e.id) { - let krate = res.def_id().krate; - let cdata = &cx.sess().cstore.get_crate_data(krate); - let crate_data : &crate_metadata = cdata.borrow(); - let name = &crate_data.name; - if name == "f32" || name == "f64" { return; } - } - check_lit(cx, lit, e.span); + check_lit(cx, lit, e); } } } -fn check_lit(cx: &Context, lit: &Lit, span: Span) { +fn check_lit(cx: &Context, lit: &Lit, e: &Expr) { match lit.node { - LitFloat(ref str, TyF32) => check_known_consts(cx, span, str, "f32"), - LitFloat(ref str, TyF64) => check_known_consts(cx, span, str, "f64"), + LitFloat(ref str, TyF32) => check_known_consts(cx, e, str, "f32"), + LitFloat(ref str, TyF64) => check_known_consts(cx, e, str, "f64"), LitFloatUnsuffixed(ref str) => - check_known_consts(cx, span, str, "f{32, 64}"), + check_known_consts(cx, e, str, "f{32, 64}"), _ => () } } -fn check_known_consts(cx: &Context, span: Span, str: &str, module: &str) { +fn check_known_consts(cx: &Context, e: &Expr, str: &str, module: &str) { if let Ok(value) = str.parse::<f64>() { for &(constant, name) in KNOWN_CONSTS { - if within_epsilon(constant, value) { - span_lint(cx, APPROX_CONSTANT, span, &format!( - "approximate value of `{}::{}` found. \ - Consider using it directly", module, &name)); - } + if !within_epsilon(constant, value) { continue; } + span_lint(cx, APPROX_CONSTANT, e.span, &format!( + "approximate value of `{}::{}` found. \ + Consider using it directly", module, &name)); } } } -- cgit 1.4.1-3-g733a5 From 82c524b7747d0df2e92a088708795771872ca8ff Mon Sep 17 00:00:00 2001 From: swgillespie <sean.william.g@gmail.com> Date: Mon, 14 Sep 2015 17:19:05 -0700 Subject: implement empty range lint as described in #330 --- README.md | 3 ++- src/lib.rs | 1 + src/loops.rs | 38 ++++++++++++++++++++++++++++++++++++-- tests/compile-fail/for_loop.rs | 14 +++++++++++++- 4 files changed, 52 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 813d18683d5..ae711357901 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. [Jump to usage instructions](#usage) ##Lints -There are 56 lints included in this crate: +There are 57 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -48,6 +48,7 @@ name [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled +[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` [shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` [shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value diff --git a/src/lib.rs b/src/lib.rs index ddaa3bf490c..9cb9eb30561 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,6 +122,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, + loops::REVERSE_RANGE_LOOP, loops::UNUSED_COLLECT, loops::WHILE_LET_LOOP, matches::MATCH_REF_PATS, diff --git a/src/loops.rs b/src/loops.rs index d1a3e4ac7ab..3b719481217 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -25,13 +25,16 @@ declare_lint!{ pub UNUSED_COLLECT, Warn, "`collect()`ing an iterator without using the result; this is usually better \ written as a for loop" } +declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, + "Iterating over an empty range, such as `10..0` or `5..5`" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT) + WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -69,6 +72,37 @@ impl LintPass for LoopsPass { } } + // if this for-loop is iterating over a two-sided range... + if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { + // and both sides are literals... + if let ExprLit(ref start_lit) = start_expr.node { + if let ExprLit(ref stop_lit) = stop_expr.node { + // and they are both integers... + if let LitInt(start_idx, _) = start_lit.node { + if let LitInt(stop_idx, _) = stop_lit.node { + // and the start index is greater than the stop index, + // this loop will never run. This is often confusing for developers + // who think that this will iterate from the larger value to the + // smaller value. + if start_idx > stop_idx { + span_lint(cx, REVERSE_RANGE_LOOP, expr.span, &format!( + "this range is empty and this for loop will never run. \ + Consider using `({}..{}).rev()` if you are attempting to \ + iterate over this range in reverse", stop_idx, start_idx)); + } + + // if they are equal, it's also problematic - this loop + // will never run. + if start_idx == stop_idx { + span_lint(cx, REVERSE_RANGE_LOOP, expr.span, + "this range is empty and this for loop will never run"); + } + } + } + } + } + } + if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments if args.len() == 1 { @@ -126,7 +160,7 @@ impl LintPass for LoopsPass { fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 && method.node.name == "collect" && + if args.len() == 1 && method.node.name == "collect" && match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { span_lint(cx, UNUSED_COLLECT, expr.span, &format!( "you are collect()ing an iterator and throwing away the result. \ diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index c8d1d383c78..d84b70025b8 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -14,7 +14,7 @@ impl Unrelated { } } -#[deny(needless_range_loop, explicit_iter_loop, iter_next_loop)] +#[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop)] #[deny(unused_collect)] #[allow(linkedlist)] fn main() { @@ -34,6 +34,18 @@ fn main() { println!("{}", vec[i]); } + for i in 10..0 { //~ERROR this range is empty and this for loop will never run. Consider using `(0..10).rev()` + println!("{}", i); + } + + for i in 5..5 { //~ERROR this range is empty and this for loop will never run + println!("{}", i); + } + + for i in 0..10 { // not an error, the start index is less than the end index + println!("{}", i); + } + for _v in vec.iter() { } //~ERROR it is more idiomatic to loop over `&vec` for _v in vec.iter_mut() { } //~ERROR it is more idiomatic to loop over `&mut vec` -- cgit 1.4.1-3-g733a5 From bc7d25285600f497206d0b1f911534eb038ca81d Mon Sep 17 00:00:00 2001 From: swgillespie <sean.william.g@gmail.com> Date: Mon, 14 Sep 2015 22:20:56 -0700 Subject: use the constant folder to generalize the lint a little bit and clean up the code. Add additional tests for things that should not be linted --- src/loops.rs | 44 ++++++++++++++++++------------------------ tests/compile-fail/for_loop.rs | 39 +++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 3b719481217..286b51ab04e 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -3,6 +3,7 @@ use rustc_front::hir::*; use reexport::*; use rustc_front::visit::{Visitor, walk_expr}; use rustc::middle::ty; +use consts::{constant_simple, Constant}; use std::collections::HashSet; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, @@ -72,32 +73,25 @@ impl LintPass for LoopsPass { } } - // if this for-loop is iterating over a two-sided range... + // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { - // and both sides are literals... - if let ExprLit(ref start_lit) = start_expr.node { - if let ExprLit(ref stop_lit) = stop_expr.node { - // and they are both integers... - if let LitInt(start_idx, _) = start_lit.node { - if let LitInt(stop_idx, _) = stop_lit.node { - // and the start index is greater than the stop index, - // this loop will never run. This is often confusing for developers - // who think that this will iterate from the larger value to the - // smaller value. - if start_idx > stop_idx { - span_lint(cx, REVERSE_RANGE_LOOP, expr.span, &format!( - "this range is empty and this for loop will never run. \ - Consider using `({}..{}).rev()` if you are attempting to \ - iterate over this range in reverse", stop_idx, start_idx)); - } - - // if they are equal, it's also problematic - this loop - // will never run. - if start_idx == stop_idx { - span_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty and this for loop will never run"); - } - } + // ...and both sides are compile-time constant integers... + if let Some(Constant::ConstantInt(start_idx, _)) = constant_simple(start_expr) { + if let Some(Constant::ConstantInt(stop_idx, _)) = constant_simple(stop_expr) { + // ...and the start index is greater than the stop index, + // this loop will never run. This is often confusing for developers + // who think that this will iterate from the larger value to the + // smaller value. + if start_idx > stop_idx { + span_help_and_lint(cx, REVERSE_RANGE_LOOP, expr.span, + "this range is empty so this for loop will never run", + &format!("Consider using `({}..{}).rev()` if you are attempting to \ + iterate over this range in reverse", stop_idx, start_idx)); + } else if start_idx == stop_idx { + // if they are equal, it's also problematic - this loop + // will never run. + span_lint(cx, REVERSE_RANGE_LOOP, expr.span, + "this range is empty so this for loop will never run"); } } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index d84b70025b8..882373e0216 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -34,11 +34,11 @@ fn main() { println!("{}", vec[i]); } - for i in 10..0 { //~ERROR this range is empty and this for loop will never run. Consider using `(0..10).rev()` + for i in 10..0 { //~ERROR this range is empty so this for loop will never run println!("{}", i); } - for i in 5..5 { //~ERROR this range is empty and this for loop will never run + for i in 5..5 { //~ERROR this range is empty so this for loop will never run println!("{}", i); } @@ -46,6 +46,41 @@ fn main() { println!("{}", i); } + for i in (10..0).rev() { // not an error, this is an established idiom for looping backwards on a range + println!("{}", i); + } + + for i in (10..0).map(|x| x * 2) { // not an error, it can't be known what arbitrary methods do to a range + println!("{}", i); + } + + // testing that the empty range lint folds constants + for i in 10..5+4 { //~ERROR this range is empty so this for loop will never run + println!("{}", i); + } + + for i in (5+2)..(3-1) { //~ERROR this range is empty so this for loop will never run + println!("{}", i); + } + + for i in (5+2)..(8-1) { //~ERROR this range is empty so this for loop will never run + println!("{}", i); + } + + for i in (2*2)..(2*3) { // no error, 4..6 is fine + println!("{}", i); + } + + let x = 42; + for i in x..10 { // no error, not constant-foldable + println!("{}", i); + } + + /* + for i in (10..0).map(|x| x * 2) { + println!("{}", i); + }*/ + for _v in vec.iter() { } //~ERROR it is more idiomatic to loop over `&vec` for _v in vec.iter_mut() { } //~ERROR it is more idiomatic to loop over `&mut vec` -- cgit 1.4.1-3-g733a5 From f87dd31f30c2e5f731a2408b0da18f43fbc34c6f Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Sun, 23 Aug 2015 13:25:45 -0400 Subject: New lint: loop with explicit counter variable (fixes #159) Avoiding false positives here turns out to be fairly complicated. --- README.md | 3 +- src/lib.rs | 1 + src/loops.rs | 229 ++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/for_loop.rs | 64 +++++++++++- 4 files changed, 291 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index ae711357901..011078c5407 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. [Jump to usage instructions](#usage) ##Lints -There are 57 lints included in this crate: +There are 58 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -21,6 +21,7 @@ name [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` diff --git a/src/lib.rs b/src/lib.rs index 9cb9eb30561..b88d2c844b0 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,6 +119,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, + loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, diff --git a/src/loops.rs b/src/loops.rs index 286b51ab04e..a381737fe3b 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,10 +1,12 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; -use rustc_front::visit::{Visitor, walk_expr}; +use rustc_front::visit::{Visitor, walk_expr, walk_block, walk_decl}; use rustc::middle::ty; +use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; -use std::collections::HashSet; +use rustc::front::map::Node::{NodeBlock}; +use std::collections::{HashSet,HashMap}; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint}; @@ -29,13 +31,16 @@ declare_lint!{ pub UNUSED_COLLECT, Warn, declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, "Iterating over an empty range, such as `10..0` or `5..5`" } +declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, + "for-looping with an explicit counter when `_.enumerate()` would do" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP) + WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP) } fn check_expr(&mut self, cx: &Context, expr: &Expr) { @@ -120,6 +125,35 @@ impl LintPass for LoopsPass { } } } + + // Look for variables that are incremented once per loop iteration. + let mut visitor = IncrementVisitor { cx: cx, states: HashMap::new(), depth: 0, done: false }; + walk_expr(&mut visitor, body); + + // For each candidate, check the parent block to see if + // it's initialized to zero at the start of the loop. + let map = &cx.tcx.map; + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id) ); + if let Some(parent_id) = parent_scope { + if let NodeBlock(block) = map.get(parent_id) { + for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { + let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), + state: VarState::IncrOnce, name: None, + depth: 0, done: false }; + walk_block(&mut visitor2, block); + + if visitor2.state == VarState::Warn { + if let Some(name) = visitor2.name { + span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, + &format!("the variable `{0}` is used as a loop counter. Consider \ + using `for ({0}, item) in _.iter().enumerate()` \ + or similar iterators.", + name)); + } + } + } + } + } } // check for `loop { if let {} else break }` that could be `while let` // (also matches explicit "match" instead of "if let") @@ -270,3 +304,192 @@ fn is_break_expr(expr: &Expr) -> bool { _ => false, } } + +// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be +// incremented exactly once in the loop body, and initialized to zero +// at the start of the loop. +#[derive(PartialEq)] +enum VarState { + Initial, // Not examined yet + IncrOnce, // Incremented exactly once, may be a loop counter + Declared, // Declared but not (yet) initialized to zero + Warn, + DontWarn +} + +// Scan a for loop for variables that are incremented exactly once. +struct IncrementVisitor<'v, 't: 'v> { + cx: &'v Context<'v, 't>, // context reference + states: HashMap<NodeId, VarState>, // incremented variables + depth: u32, // depth of conditional expressions + done: bool +} + +impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { + fn visit_expr(&mut self, expr: &'v Expr) { + if self.done { + return; + } + + // If node is a variable + if let Some(def_id) = var_def_id(self.cx, expr) { + if let Some(parent) = get_parent_expr(self.cx, expr) { + let state = self.states.entry(def_id).or_insert(VarState::Initial); + + match parent.node { + ExprAssignOp(op, ref lhs, ref rhs) => + if lhs.id == expr.id { + if op.node == BiAdd && is_lit_one(rhs) { + *state = match *state { + VarState::Initial if self.depth == 0 => VarState::IncrOnce, + _ => VarState::DontWarn + }; + } + else { + // Assigned some other value + *state = VarState::DontWarn; + } + }, + ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, + _ => () + } + } + } + // Give up if there are nested loops + else if is_loop(expr) { + self.states.clear(); + self.done = true; + return; + } + // Keep track of whether we're inside a conditional expression + else if is_conditional(expr) { + self.depth += 1; + walk_expr(self, expr); + self.depth -= 1; + return; + } + walk_expr(self, expr); + } +} + +// Check whether a variable is initialized to zero at the start of a loop. +struct InitializeVisitor<'v, 't: 'v> { + cx: &'v Context<'v, 't>, // context reference + end_expr: &'v Expr, // the for loop. Stop scanning here. + var_id: NodeId, + state: VarState, + name: Option<Name>, + depth: u32, // depth of conditional expressions + done: bool +} + +impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { + fn visit_decl(&mut self, decl: &'v Decl) { + // Look for declarations of the variable + if let DeclLocal(ref local) = decl.node { + if local.pat.id == self.var_id { + if let PatIdent(_, ref ident, _) = local.pat.node { + self.name = Some(ident.node.name); + + self.state = if let Some(ref init) = local.init { + if is_lit_zero(init) { + VarState::Warn + } else { + VarState::Declared + } + } + else { + VarState::Declared + } + } + } + } + walk_decl(self, decl); + } + + fn visit_expr(&mut self, expr: &'v Expr) { + if self.state == VarState::DontWarn || expr == self.end_expr { + self.done = true; + } + // No need to visit expressions before the variable is + // declared or after we've rejected it. + if self.state == VarState::IncrOnce || self.done { + return; + } + + // If node is the desired variable, see how it's used + if var_def_id(self.cx, expr) == Some(self.var_id) { + if let Some(parent) = get_parent_expr(self.cx, expr) { + 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_lit_zero(rhs) && self.depth == 0 { + VarState::Warn + } else { + VarState::DontWarn + }}, + _ => () + } + } + } + // If there are other loops between the declaration and the target loop, give up + else if is_loop(expr) { + self.state = VarState::DontWarn; + self.done = true; + return; + } + // Keep track of whether we're inside a conditional expression + else if is_conditional(expr) { + self.depth += 1; + walk_expr(self, expr); + self.depth -= 1; + return; + } + walk_expr(self, expr); + } +} + +fn var_def_id(cx: &Context, expr: &Expr) -> Option<NodeId> { + if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { + if let DefLocal(node_id) = path_res.base_def { + return Some(node_id) + } + } + None +} + +fn is_loop(expr: &Expr) -> bool { + match expr.node { + ExprLoop(..) | ExprWhile(..) => true, + _ => false + } +} + +fn is_conditional(expr: &Expr) -> bool { + match expr.node { + ExprIf(..) | ExprMatch(..) => true, + _ => false + } +} + +// FIXME: copy/paste from misc.rs +fn is_lit_one(expr: &Expr) -> bool { + if let ExprLit(ref spanned) = expr.node { + if let LitInt(1, _) = spanned.node { + return true; + } + } + false +} + +// FIXME: copy/paste from ranges.rs +fn is_lit_zero(expr: &Expr) -> bool { + if let ExprLit(ref spanned) = expr.node { + if let LitInt(0, _) = spanned.node { + return true; + } + } + false +} diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index a43ed7faa23..3320e9acc1d 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -14,9 +14,9 @@ impl Unrelated { } } -#[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop)] +#[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] -#[allow(linkedlist)] +#[allow(linkedlist,shadow_unrelated)] fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; @@ -119,4 +119,64 @@ fn main() { let mut out = vec![]; vec.iter().map(|x| out.push(x)).collect::<Vec<_>>(); //~ERROR you are collect()ing an iterator let _y = vec.iter().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine + + // Loop with explicit counter variable + let mut _index = 0; + for _v in &vec { _index += 1 } //~ERROR the variable `_index` is used as a loop counter + + let mut _index = 1; + _index = 0; + for _v in &vec { _index += 1 } //~ERROR the variable `_index` is used as a loop counter + + let mut _index; + _index = 0; + for _v in &vec { _index += 1 } //~ERROR the variable `_index` is used as a loop counter + for _v in &vec { _index += 1 } // But this does not warn + + // Potential false positives + let mut _index = 0; + _index = 1; + for _v in &vec { _index += 1 } + + let mut _index = 0; + _index += 1; + for _v in &vec { _index += 1 } + + let mut _index = 0; + if true { _index = 1 } + for _v in &vec { _index += 1 } + + let mut _index = 0; + let mut _index = 1; + for _v in &vec { _index += 1 } + + let mut _index = 0; + for _v in &vec { _index += 1; _index += 1 } + + let mut _index = 0; + for _v in &vec { _index *= 2; _index += 1 } + + let mut _index = 0; + for _v in &vec { _index = 1; _index += 1 } + + let mut _index = 0; + + for _v in &vec { let mut _index = 0; _index += 1 } + + let mut _index = 0; + for _v in &vec { _index += 1; _index = 0; } + + let mut _index = 0; + for _v in &vec { for _x in 0..1 { _index += 1; }; _index += 1 } + + let mut _index = 0; + for x in &vec { if *x == 1 { _index += 1 } } + + let mut _index = 0; + if true { _index = 1 }; + for _v in &vec { _index += 1 } + + let mut _index = 1; + if false { _index = 0 }; + for _v in &vec { _index += 1 } } -- cgit 1.4.1-3-g733a5 From 1e320b38c18165964916829a990bff1b663bf718 Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Fri, 4 Sep 2015 09:26:58 -0400 Subject: Add is_integer_literal utility function Replaces is_lit_zero and is_lit_one which were used in a couple of places. --- src/loops.rs | 28 ++++------------------------ src/misc.rs | 13 ++----------- src/ranges.rs | 14 ++------------ src/utils.rs | 11 +++++++++++ 4 files changed, 19 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index a381737fe3b..ade4f46b4a0 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -9,7 +9,7 @@ use rustc::front::map::Node::{NodeBlock}; use std::collections::{HashSet,HashMap}; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, - in_external_macro, expr_block, span_help_and_lint}; + in_external_macro, expr_block, span_help_and_lint, is_integer_literal}; use utils::{VEC_PATH, LL_PATH}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, @@ -339,7 +339,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { match parent.node { ExprAssignOp(op, ref lhs, ref rhs) => if lhs.id == expr.id { - if op.node == BiAdd && is_lit_one(rhs) { + if op.node == BiAdd && is_integer_literal(rhs, 1) { *state = match *state { VarState::Initial if self.depth == 0 => VarState::IncrOnce, _ => VarState::DontWarn @@ -392,7 +392,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { self.name = Some(ident.node.name); self.state = if let Some(ref init) = local.init { - if is_lit_zero(init) { + if is_integer_literal(init, 0) { VarState::Warn } else { VarState::Declared @@ -425,7 +425,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { self.state = VarState::DontWarn; }, ExprAssign(ref lhs, ref rhs) if lhs.id == expr.id => { - self.state = if is_lit_zero(rhs) && self.depth == 0 { + self.state = if is_integer_literal(rhs, 0) && self.depth == 0 { VarState::Warn } else { VarState::DontWarn @@ -473,23 +473,3 @@ fn is_conditional(expr: &Expr) -> bool { _ => false } } - -// FIXME: copy/paste from misc.rs -fn is_lit_one(expr: &Expr) -> bool { - if let ExprLit(ref spanned) = expr.node { - if let LitInt(1, _) = spanned.node { - return true; - } - } - false -} - -// FIXME: copy/paste from ranges.rs -fn is_lit_zero(expr: &Expr) -> bool { - if let ExprLit(ref spanned) = expr.node { - if let LitInt(0, _) = spanned.node { - return true; - } - } - false -} diff --git a/src/misc.rs b/src/misc.rs index 2cd6babb9c5..63c2082abde 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -7,7 +7,7 @@ use syntax::codemap::{Span, Spanned}; use rustc_front::visit::FnKind; use rustc::middle::ty; -use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty}; +use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, @@ -183,7 +183,7 @@ impl LintPass for ModuloOne { fn check_expr(&mut self, cx: &Context, expr: &Expr) { if let ExprBinary(ref cmp, _, ref right) = expr.node { if let &Spanned {node: BinOp_::BiRem, ..} = cmp { - if is_lit_one(right) { + if is_integer_literal(right, 1) { cx.span_lint(MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } } @@ -191,15 +191,6 @@ impl LintPass for ModuloOne { } } -fn is_lit_one(expr: &Expr) -> bool { - if let ExprLit(ref spanned) = expr.node { - if let LitInt(1, _) = spanned.node { - return true; - } - } - false -} - declare_lint!(pub REDUNDANT_PATTERN, Warn, "using `name @ _` in a pattern"); #[derive(Copy,Clone)] diff --git a/src/ranges.rs b/src/ranges.rs index 197afaf1163..97f59a3aadd 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,7 +1,7 @@ use rustc::lint::{Context, LintArray, LintPass}; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::match_type; +use utils::{match_type, is_integer_literal}; declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, @@ -21,7 +21,7 @@ impl LintPass for StepByZero { ref args) = expr.node { // Only warn on literal ranges. if ident.name == "step_by" && args.len() == 2 && - is_range(cx, &args[0]) && is_lit_zero(&args[1]) { + is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, "Range::step_by(0) produces an infinite iterator. \ Consider using `std::iter::repeat()` instead") @@ -37,13 +37,3 @@ fn is_range(cx: &Context, expr: &Expr) -> bool { // Note: RangeTo and RangeFull don't have step_by match_type(cx, ty, &["core", "ops", "Range"]) || match_type(cx, ty, &["core", "ops", "RangeFrom"]) } - -fn is_lit_zero(expr: &Expr) -> bool { - // FIXME: use constant folding - if let ExprLit(ref spanned) = expr.node { - if let LitInt(0, _) = spanned.node { - return true; - } - } - false -} diff --git a/src/utils.rs b/src/utils.rs index d6e529048c9..01c9adf866c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -244,6 +244,17 @@ pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { inner(ty, 0) } +pub fn is_integer_literal(expr: &Expr, value: u64) -> bool +{ + // FIXME: use constant folding + if let ExprLit(ref spanned) = expr.node { + if let LitInt(v, _) = spanned.node { + return v == value; + } + } + false +} + /// Produce a nested chain of if-lets and ifs from the patterns: /// /// if_let_chain! { -- cgit 1.4.1-3-g733a5 From 6b57924e816af4543fc6b3214ccc4d472f5c9434 Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Thu, 10 Sep 2015 08:26:31 -0400 Subject: Improve lint message Remove trailing period and include snippet of loop argument. --- src/loops.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index ade4f46b4a0..06892f6a74e 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -146,9 +146,9 @@ impl LintPass for LoopsPass { if let Some(name) = visitor2.name { span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, &format!("the variable `{0}` is used as a loop counter. Consider \ - using `for ({0}, item) in _.iter().enumerate()` \ - or similar iterators.", - name)); + using `for ({0}, item) in {1}.enumerate()` \ + or similar iterators", + name, snippet(cx, arg.span, "_"))); } } } -- cgit 1.4.1-3-g733a5 From 8a5b4f19fd6cec7b3ef583afa592fde99dabe58e Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Thu, 10 Sep 2015 08:33:29 -0400 Subject: Check for mutable borrow of counter variable --- src/loops.rs | 2 ++ tests/compile-fail/for_loop.rs | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 06892f6a74e..406fbee0b7c 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -351,6 +351,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { } }, ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, + ExprAddrOf(mutability,_) if mutability == MutMutable => *state = VarState::DontWarn, _ => () } } @@ -430,6 +431,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { } else { VarState::DontWarn }}, + ExprAddrOf(mutability,_) if mutability == MutMutable => self.state = VarState::DontWarn, _ => () } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 3320e9acc1d..d6d73db3c18 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -179,4 +179,8 @@ fn main() { let mut _index = 1; if false { _index = 0 }; for _v in &vec { _index += 1 } + + let mut _index = 0; + { let mut _x = &mut _index; } + for _v in &vec { _index += 1 } } -- cgit 1.4.1-3-g733a5 From 3124d2b8df3f9a2f265778555f67a6eb54f81834 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 17 Sep 2015 05:31:41 +0530 Subject: Rustup to rustc 1.5.0-nightly (fc4d566b4 2015-09-16) fixes #334 --- Cargo.toml | 2 +- src/approx_const.rs | 3 +++ src/attrs.rs | 3 ++- src/bit_mask.rs | 1 + src/consts.rs | 10 ++++++++++ src/len_zero.rs | 3 +++ src/lib.rs | 2 +- src/loops.rs | 1 + src/needless_bool.rs | 2 ++ src/precedence.rs | 2 +- src/types.rs | 3 +++ src/unicode.rs | 2 ++ src/utils.rs | 1 + tests/consts.rs | 6 ++++++ 14 files changed, 37 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 9dea1c0d453..0ac40f29cb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.13" +version = "0.0.14" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/approx_const.rs b/src/approx_const.rs index 29631b6852f..b357c2dc40a 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -2,6 +2,9 @@ use rustc::lint::*; use rustc_front::hir::*; use std::f64::consts as f64; use utils::span_lint; +use syntax::ast::Lit_::*; +use syntax::ast::Lit; +use syntax::ast::FloatTy::*; declare_lint! { pub APPROX_CONSTANT, diff --git a/src/attrs.rs b/src/attrs.rs index e6185d8b400..a80d19d32a1 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -4,7 +4,8 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; use syntax::codemap::Span; - +use syntax::attr::*; +use syntax::ast::{Attribute, MetaList, MetaWord}; use utils::{in_macro, match_path, span_lint}; declare_lint! { pub INLINE_ALWAYS, Warn, diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 97d33b5e699..58d0f3f6085 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -4,6 +4,7 @@ use rustc::middle::def::*; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; use syntax::codemap::Span; +use syntax::ast::Lit_::*; use utils::span_lint; diff --git a/src/consts.rs b/src/consts.rs index 0c32dc5efad..5a97a5d3f7a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -13,6 +13,16 @@ use std::ops::Deref; use self::Constant::*; use self::FloatWidth::*; +use syntax::ast::Lit_::*; +use syntax::ast::Lit_; +use syntax::ast::LitIntType::*; +use syntax::ast::LitIntType; +use syntax::ast::{UintTy, FloatTy, StrStyle}; +use syntax::ast::UintTy::*; +use syntax::ast::FloatTy::*; +use syntax::ast::Sign::{self, Plus, Minus}; + + #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum FloatWidth { Fw32, diff --git a/src/len_zero.rs b/src/len_zero.rs index 45b9c844af3..22aa75f8c9d 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -5,6 +5,9 @@ use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; +use syntax::ast::Lit_::*; +use syntax::ast::Lit; + use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; declare_lint!(pub LEN_ZERO, Warn, diff --git a/src/lib.rs b/src/lib.rs index b88d2c844b0..5995b4be8af 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, core, collections)] -#![feature(str_split_at, num_bits_bytes)] +#![feature(num_bits_bytes)] #![allow(unknown_lints)] #[macro_use] diff --git a/src/loops.rs b/src/loops.rs index 406fbee0b7c..bcb9744b3f2 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -7,6 +7,7 @@ use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; use rustc::front::map::Node::{NodeBlock}; use std::collections::{HashSet,HashMap}; +use syntax::ast::Lit_::*; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal}; diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 0e8276bfafa..7947839426d 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -5,6 +5,8 @@ use rustc::lint::*; use rustc_front::hir::*; +use syntax::ast::Lit_::*; + use utils::{span_lint, snippet}; declare_lint! { diff --git a/src/precedence.rs b/src/precedence.rs index 31c28146e1e..c55e65b3a6b 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; - +use syntax::ast::Lit_::*; use utils::span_lint; declare_lint!(pub PRECEDENCE, Warn, diff --git a/src/types.rs b/src/types.rs index 08a8560fcd6..d8d2c7a9438 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,6 +5,9 @@ use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; use rustc_front::visit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; +use syntax::ast::IntTy::*; +use syntax::ast::UintTy::*; +use syntax::ast::FloatTy::*; use utils::{match_type, snippet, span_lint, span_help_and_lint, in_macro, in_external_macro}; use utils::{LL_PATH, VEC_PATH}; diff --git a/src/unicode.rs b/src/unicode.rs index e745c0960ea..16f2653429f 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -2,6 +2,8 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; +use syntax::ast::Lit_::*; + use unicode_normalization::UnicodeNormalization; use utils::{snippet, span_help_and_lint}; diff --git a/src/utils.rs b/src/utils.rs index 01c9adf866c..da288db60ca 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,6 +6,7 @@ use rustc::front::map::Node::*; use rustc::middle::def_id::DefId; use rustc::middle::ty; use std::borrow::Cow; +use syntax::ast::Lit_::*; // module DefPaths for certain structs/enums we check for pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; diff --git a/tests/consts.rs b/tests/consts.rs index 7aa42545074..66a7953994b 100755 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -11,6 +11,12 @@ use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; +use syntax::ast::Lit_::*; +use syntax::ast::Lit_; +use syntax::ast::LitIntType::*; +use syntax::ast::StrStyle::*; +use syntax::ast::Sign::*; + use clippy::consts::{constant_simple, Constant}; use clippy::consts::Constant::*; -- cgit 1.4.1-3-g733a5 From e3ee87965e577a6520c2596c3a1b9dc16794427e Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 17 Sep 2015 07:24:11 +0200 Subject: ref matches: false positive with only wildcard pattern match (fixes #335) --- src/matches.rs | 13 ++++++++----- tests/compile-fail/matches.rs | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 5947469cd90..8e5a7f51577 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -46,6 +46,7 @@ impl LintPass for MatchPass { // check preconditions for MATCH_REF_PATS if has_only_ref_pats(arms) { + if in_external_macro(cx, expr.span) { return; } if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { span_lint(cx, MATCH_REF_PATS, expr.span, &format!( "you don't need to add `&` to both the expression to match \ @@ -69,9 +70,11 @@ fn is_unit_expr(expr: &Expr) -> bool { } fn has_only_ref_pats(arms: &[Arm]) -> bool { - arms.iter().flat_map(|a| &a.pats).all(|p| match p.node { - PatRegion(..) => true, // &-patterns - PatWild(..) => true, // an "anything" wildcard is also fine - _ => false, - }) + let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node { + PatRegion(..) => Some(true), // &-patterns + PatWild(..) => Some(false), // an "anything" wildcard is also fine + _ => None, // any other pattern is not fine + }).collect::<Option<Vec<bool>>>(); + // look for Some(v) where there's at least one true element + mapped.map_or(false, |v| v.iter().any(|el| *el)) } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 07dc7c9ef83..2fd9df33ef5 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -61,6 +61,11 @@ fn ref_pats() { &Some(v) => println!("{:?}", v), &None => println!("none"), } + // false positive: only wildcard pattern + let w = Some(0); + match w { + _ => println!("none"), + } } fn main() { -- cgit 1.4.1-3-g733a5 From 58fee220a9ec3bd904aa7c8e84b6643b51e88f76 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Thu, 17 Sep 2015 07:27:18 +0200 Subject: fix indentation --- src/collapsible_if.rs | 6 +++--- src/utils.rs | 56 +++++++++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 7326bd20c7c..d22fc4817f3 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -34,9 +34,9 @@ impl LintPass for CollapsibleIf { } fn check_expr(&mut self, cx: &Context, expr: &Expr) { - if !in_macro(cx, expr.span) { - check_if(cx, expr) - } + if !in_macro(cx, expr.span) { + check_if(cx, expr) + } } } diff --git a/src/utils.rs b/src/utils.rs index 01c9adf866c..a49a7b2b7a3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -28,34 +28,34 @@ pub fn in_macro(cx: &Context, span: Span) -> bool { /// 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: &Context, 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: &Context, opt_info: Option<&ExpnInfo>) -> bool { - // no ExpnInfo = no macro - opt_info.map_or(false, |info| { - match info.callee.format { - ExpnFormat::CompilerExpansion(..) => { - if info.callee.name() == "closure expansion" { - return false; - } - }, - ExpnFormat::MacroAttribute(..) => { - // these are all plugins - return true; - }, - _ => (), - } - // no span for the callee = external macro - info.callee.span.map_or(true, |span| { - // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| - // macro doesn't start with "macro_rules" - // = compiler plugin - !code.starts_with("macro_rules") - ) - }) - }) - } + /// 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: &Context, opt_info: Option<&ExpnInfo>) -> bool { + // no ExpnInfo = no macro + opt_info.map_or(false, |info| { + match info.callee.format { + ExpnFormat::CompilerExpansion(..) => { + if info.callee.name() == "closure expansion" { + return false; + } + }, + ExpnFormat::MacroAttribute(..) => { + // these are all plugins + return true; + }, + _ => (), + } + // no span for the callee = external macro + info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| + // macro doesn't start with "macro_rules" + // = compiler plugin + !code.starts_with("macro_rules") + ) + }) + }) + } cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) -- cgit 1.4.1-3-g733a5 From f4da7d09d278b39d66590d85f48938243372782d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 19 Sep 2015 08:23:04 +0530 Subject: Upgrade Rust to rustc 1.5.0-nightly (cff041170 2015-09-17) LintPass was split and ExprParen was removed from the HIR Fixes #338 --- Cargo.toml | 2 +- src/approx_const.rs | 8 ++++-- src/attrs.rs | 13 +++++---- src/bit_mask.rs | 15 +++++----- src/collapsible_if.rs | 8 ++++-- src/consts.rs | 15 +++++----- src/eq_op.rs | 10 +++---- src/eta_reduction.rs | 8 ++++-- src/identity_op.rs | 6 ++-- src/len_zero.rs | 20 +++++++------ src/lib.rs | 67 ++++++++++++++++++++++---------------------- src/lifetimes.rs | 10 ++++--- src/loops.rs | 16 ++++++----- src/matches.rs | 4 ++- src/methods.rs | 8 ++++-- src/minmax.rs | 6 ++-- src/misc.rs | 32 ++++++++++++++------- src/mut_mut.rs | 8 ++++-- src/needless_bool.rs | 4 ++- src/precedence.rs | 7 +++-- src/ptr_arg.rs | 10 ++++--- src/ranges.rs | 8 ++++-- src/returns.rs | 14 +++++---- src/shadow.rs | 30 +++++++++++--------- src/strings.rs | 9 +++--- src/types.rs | 42 ++++++++++++++++----------- src/unicode.rs | 6 ++-- src/utils.rs | 30 ++++++++++---------- tests/compile-fail/shadow.rs | 2 +- 29 files changed, 238 insertions(+), 180 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 0ac40f29cb6..4ff702de4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.14" +version = "0.0.15" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/approx_const.rs b/src/approx_const.rs index b357c2dc40a..9a186a4f8cd 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -29,15 +29,17 @@ impl LintPass for ApproxConstant { fn get_lints(&self) -> LintArray { lint_array!(APPROX_CONSTANT) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for ApproxConstant { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let &ExprLit(ref lit) = &e.node { check_lit(cx, lit, e); } } } -fn check_lit(cx: &Context, lit: &Lit, e: &Expr) { +fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { match lit.node { LitFloat(ref str, TyF32) => check_known_consts(cx, e, str, "f32"), LitFloat(ref str, TyF64) => check_known_consts(cx, e, str, "f64"), @@ -47,7 +49,7 @@ fn check_lit(cx: &Context, lit: &Lit, e: &Expr) { } } -fn check_known_consts(cx: &Context, e: &Expr, str: &str, module: &str) { +fn check_known_consts(cx: &LateContext, e: &Expr, str: &str, module: &str) { if let Ok(value) = str.parse::<f64>() { for &(constant, name) in KNOWN_CONSTS { if !within_epsilon(constant, value) { continue; } diff --git a/src/attrs.rs b/src/attrs.rs index a80d19d32a1..6450cc16195 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -19,20 +19,22 @@ impl LintPass for AttrPass { fn get_lints(&self) -> LintArray { lint_array!(INLINE_ALWAYS) } +} - fn check_item(&mut self, cx: &Context, item: &Item) { +impl LateLintPass for AttrPass { + fn check_item(&mut self, cx: &LateContext, item: &Item) { if is_relevant_item(item) { check_attrs(cx, item.span, &item.ident, &item.attrs) } } - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if is_relevant_impl(item) { check_attrs(cx, item.span, &item.ident, &item.attrs) } } - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if is_relevant_trait(item) { check_attrs(cx, item.span, &item.ident, &item.attrs) } @@ -75,8 +77,7 @@ fn is_relevant_block(block: &Block) -> bool { fn is_relevant_expr(expr: &Expr) -> bool { match expr.node { ExprBlock(ref block) => is_relevant_block(block), - ExprRet(Some(ref e)) | ExprParen(ref e) => - is_relevant_expr(e), + ExprRet(Some(ref e)) => is_relevant_expr(e), ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { @@ -87,7 +88,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { } } -fn check_attrs(cx: &Context, span: Span, ident: &Ident, +fn check_attrs(cx: &LateContext, span: Span, ident: &Ident, attrs: &[Attribute]) { if in_macro(cx, span) { return; } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 58d0f3f6085..d99497aafe9 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -54,8 +54,10 @@ impl LintPass for BitMask { fn get_lints(&self) -> LintArray { lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for BitMask { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { fetch_int_literal(cx, right).map_or_else(|| @@ -82,9 +84,8 @@ fn invert_cmp(cmp : BinOp_) -> BinOp_ { } -fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { +fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { match bit_op.node { - ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span), ExprBinary(ref op, ref left, ref right) => { if op.node != BiBitAnd && op.node != BiBitOr { return; } fetch_int_literal(cx, right).or_else(|| fetch_int_literal( @@ -95,7 +96,7 @@ fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, sp } } -fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, +fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { match cmp_op { BiEq | BiNe => match bit_op { @@ -163,7 +164,7 @@ fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, } } -fn check_ineffective_lt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { +fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { if c.is_power_of_two() && m < c { span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", @@ -171,7 +172,7 @@ fn check_ineffective_lt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { } } -fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { +fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { if (c + 1).is_power_of_two() && m <= c { span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", @@ -179,7 +180,7 @@ fn check_ineffective_gt(cx: &Context, span: Span, m: u64, c: u64, op: &str) { } } -fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> { +fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { if let &LitInt(value, _) = &lit_ptr.node { diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index d22fc4817f3..78e3ec5e35f 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -32,15 +32,17 @@ impl LintPass for CollapsibleIf { fn get_lints(&self) -> LintArray { lint_array!(COLLAPSIBLE_IF) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for CollapsibleIf { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if !in_macro(cx, expr.span) { check_if(cx, expr) } } } -fn check_if(cx: &Context, e: &Expr) { +fn check_if(cx: &LateContext, e: &Expr) { if let ExprIf(ref check, ref then, None) = e.node { if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = single_stmt_of_block(then) { @@ -63,7 +65,7 @@ fn requires_brackets(e: &Expr) -> bool { } } -fn check_to_string(cx: &Context, e: &Expr) -> String { +fn check_to_string(cx: &LateContext, e: &Expr) -> String { if requires_brackets(e) { format!("({})", snippet(cx, e.span, "..")) } else { diff --git a/src/consts.rs b/src/consts.rs index 5a97a5d3f7a..d66bfb5b4fc 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,6 +1,6 @@ #![allow(cast_possible_truncation)] -use rustc::lint::Context; +use rustc::lint::LateContext; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; @@ -287,27 +287,26 @@ fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> } -pub fn constant(lcx: &Context, e: &Expr) -> Option<(Constant, bool)> { - let mut cx = ConstEvalContext { lcx: Some(lcx), needed_resolution: false }; +pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { + let mut cx = ConstEvalLateContext { lcx: Some(lcx), needed_resolution: false }; cx.expr(e).map(|cst| (cst, cx.needed_resolution)) } pub fn constant_simple(e: &Expr) -> Option<Constant> { - let mut cx = ConstEvalContext { lcx: None, needed_resolution: false }; + let mut cx = ConstEvalLateContext { lcx: None, needed_resolution: false }; cx.expr(e) } -struct ConstEvalContext<'c, 'cc: 'c> { - lcx: Option<&'c Context<'c, 'cc>>, +struct ConstEvalLateContext<'c, 'cc: 'c> { + lcx: Option<&'c LateContext<'c, 'cc>>, needed_resolution: bool } -impl<'c, 'cc> ConstEvalContext<'c, 'cc> { +impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { /// simple constant folding: Insert an expression, get a constant or none. fn expr(&mut self, e: &Expr) -> Option<Constant> { match e.node { - ExprParen(ref inner) => self.expr(inner), ExprPath(_, _) => self.fetch_path(e), ExprBlock(ref block) => self.block(block), ExprIf(ref cond, ref then, ref otherwise) => diff --git a/src/eq_op.rs b/src/eq_op.rs index c5953201436..6f305b6adf8 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -19,8 +19,10 @@ impl LintPass for EqOp { fn get_lints(&self) -> LintArray { lint_array!(EQ_OP) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for EqOp { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(cx, left, right) { span_lint(cx, EQ_OP, e.span, &format!( @@ -31,7 +33,7 @@ impl LintPass for EqOp { } } -pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { +pub fn is_exp_equal(cx: &LateContext, left : &Expr, right : &Expr) -> bool { if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { if l == r { return true; @@ -42,8 +44,6 @@ pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { &ExprField(ref rfexp, ref rfident)) => lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprParen(ref lparen), _) => is_exp_equal(cx, lparen, right), - (_, &ExprParen(ref rparen)) => is_exp_equal(cx, left, rparen), (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => both(lqself, rqself, is_qself_equal) && @@ -57,7 +57,7 @@ pub fn is_exp_equal(cx: &Context, left : &Expr, right : &Expr) -> bool { } } -fn is_exps_equal(cx: &Context, left : &[P<Expr>], right : &[P<Expr>]) -> bool { +fn is_exps_equal(cx: &LateContext, left : &[P<Expr>], right : &[P<Expr>]) -> bool { over(left, right, |l, r| is_exp_equal(cx, l, r)) } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index f3359ad0c37..7226a4bad05 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -16,8 +16,10 @@ impl LintPass for EtaPass { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_CLOSURE) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for EtaPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { match expr.node { ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => { @@ -30,11 +32,11 @@ impl LintPass for EtaPass { } } -fn is_adjusted(cx: &Context, e: &Expr) -> bool { +fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() } -fn check_closure(cx: &Context, expr: &Expr) { +fn check_closure(cx: &LateContext, expr: &Expr) { if let ExprClosure(_, ref decl, ref blk) = expr.node { if !blk.stmts.is_empty() { // || {foo(); bar()}; can't be reduced here diff --git a/src/identity_op.rs b/src/identity_op.rs index 9601a685690..aee208d624e 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -16,8 +16,10 @@ impl LintPass for IdentityOp { fn get_lints(&self) -> LintArray { lint_array!(IDENTITY_OP) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for IdentityOp { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if in_macro(cx, e.span) { return; } if let ExprBinary(ref cmp, ref left, ref right) = e.node { match cmp.node { @@ -44,7 +46,7 @@ impl LintPass for IdentityOp { } -fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) { +fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { if let Some(ConstantInt(v, ty)) = constant_simple(e) { if match m { 0 => v == 0, diff --git a/src/len_zero.rs b/src/len_zero.rs index 22aa75f8c9d..dfd340ef5ea 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -24,8 +24,10 @@ impl LintPass for LenZero { fn get_lints(&self) -> LintArray { lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) } +} - fn check_item(&mut self, cx: &Context, item: &Item) { +impl LateLintPass for LenZero { + fn check_item(&mut self, cx: &LateContext, item: &Item) { match item.node { ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), @@ -35,7 +37,7 @@ impl LintPass for LenZero { } } - fn check_expr(&mut self, cx: &Context, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = expr.node { match cmp { @@ -47,7 +49,7 @@ impl LintPass for LenZero { } } -fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { +fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { item.ident.name == name && if let MethodTraitItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } @@ -66,7 +68,7 @@ fn check_trait_items(cx: &Context, item: &Item, trait_items: &[P<TraitItem>]) { } } -fn check_impl_items(cx: &Context, item: &Item, impl_items: &[P<ImplItem>]) { +fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { item.ident.name == name && if let MethodImplItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } @@ -92,7 +94,7 @@ fn is_self_sig(sig: &MethodSig) -> bool { false } else { sig.decl.inputs.len() == 1 } } -fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { +fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, left) { if name == "is_empty" { return; } @@ -106,7 +108,7 @@ fn check_cmp(cx: &Context, span: Span, left: &Expr, right: &Expr, op: &str) { } } -fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, +fn check_len_zero(cx: &LateContext, span: Span, method: &SpannedIdent, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { if method.node.name == "len" && args.len() == 1 && @@ -119,9 +121,9 @@ fn check_len_zero(cx: &Context, span: Span, method: &SpannedIdent, } /// check if this type has an is_empty method -fn has_is_empty(cx: &Context, expr: &Expr) -> bool { +fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { /// get a ImplOrTraitItem and return true if it matches is_empty(self) - fn is_is_empty(cx: &Context, id: &ImplOrTraitItemId) -> bool { + fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { if let &MethodTraitItemId(def_id) = id { if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { @@ -132,7 +134,7 @@ fn has_is_empty(cx: &Context, expr: &Expr) -> bool { } /// check the inherent impl's items for an is_empty(self) method - fn has_is_empty_impl(cx: &Context, id: &DefId) -> bool { + fn has_is_empty_impl(cx: &LateContext, id: &DefId) -> bool { let impl_items = cx.tcx.impl_items.borrow(); cx.tcx.inherent_impls.borrow().get(id).map_or(false, |ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false, diff --git a/src/lib.rs b/src/lib.rs index 5995b4be8af..3c2d870aee2 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ extern crate collections; extern crate unicode_normalization; use rustc::plugin::Registry; -use rustc::lint::LintPassObject; #[macro_use] pub mod utils; @@ -54,39 +53,39 @@ mod reexport { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_lint_pass(box types::TypePass as LintPassObject); - reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); - reg.register_lint_pass(box misc::CmpNan as LintPassObject); - reg.register_lint_pass(box eq_op::EqOp as LintPassObject); - reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); - reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); - reg.register_lint_pass(box needless_bool::NeedlessBool as LintPassObject); - reg.register_lint_pass(box approx_const::ApproxConstant as LintPassObject); - reg.register_lint_pass(box misc::FloatCmp as LintPassObject); - reg.register_lint_pass(box precedence::Precedence as LintPassObject); - reg.register_lint_pass(box eta_reduction::EtaPass as LintPassObject); - reg.register_lint_pass(box identity_op::IdentityOp as LintPassObject); - reg.register_lint_pass(box mut_mut::MutMut as LintPassObject); - reg.register_lint_pass(box len_zero::LenZero as LintPassObject); - reg.register_lint_pass(box misc::CmpOwned as LintPassObject); - reg.register_lint_pass(box attrs::AttrPass as LintPassObject); - reg.register_lint_pass(box collapsible_if::CollapsibleIf as LintPassObject); - reg.register_lint_pass(box misc::ModuloOne as LintPassObject); - reg.register_lint_pass(box unicode::Unicode as LintPassObject); - reg.register_lint_pass(box strings::StringAdd as LintPassObject); - reg.register_lint_pass(box returns::ReturnPass as LintPassObject); - reg.register_lint_pass(box methods::MethodsPass as LintPassObject); - reg.register_lint_pass(box shadow::ShadowPass as LintPassObject); - reg.register_lint_pass(box types::LetPass as LintPassObject); - reg.register_lint_pass(box types::UnitCmp as LintPassObject); - reg.register_lint_pass(box loops::LoopsPass as LintPassObject); - reg.register_lint_pass(box lifetimes::LifetimePass as LintPassObject); - reg.register_lint_pass(box ranges::StepByZero as LintPassObject); - reg.register_lint_pass(box types::CastPass as LintPassObject); - reg.register_lint_pass(box types::TypeComplexityPass as LintPassObject); - reg.register_lint_pass(box matches::MatchPass as LintPassObject); - reg.register_lint_pass(box misc::PatternPass as LintPassObject); - reg.register_lint_pass(box minmax::MinMaxPass as LintPassObject); + reg.register_late_lint_pass(box types::TypePass); + reg.register_late_lint_pass(box misc::TopLevelRefPass); + reg.register_late_lint_pass(box misc::CmpNan); + reg.register_late_lint_pass(box eq_op::EqOp); + reg.register_late_lint_pass(box bit_mask::BitMask); + reg.register_late_lint_pass(box ptr_arg::PtrArg); + reg.register_late_lint_pass(box needless_bool::NeedlessBool); + reg.register_late_lint_pass(box approx_const::ApproxConstant); + reg.register_late_lint_pass(box misc::FloatCmp); + reg.register_early_lint_pass(box precedence::Precedence); + reg.register_late_lint_pass(box eta_reduction::EtaPass); + reg.register_late_lint_pass(box identity_op::IdentityOp); + reg.register_late_lint_pass(box mut_mut::MutMut); + reg.register_late_lint_pass(box len_zero::LenZero); + reg.register_late_lint_pass(box misc::CmpOwned); + reg.register_late_lint_pass(box attrs::AttrPass); + reg.register_late_lint_pass(box collapsible_if::CollapsibleIf); + reg.register_late_lint_pass(box misc::ModuloOne); + reg.register_late_lint_pass(box unicode::Unicode); + reg.register_late_lint_pass(box strings::StringAdd); + reg.register_late_lint_pass(box returns::ReturnPass); + reg.register_late_lint_pass(box methods::MethodsPass); + reg.register_late_lint_pass(box shadow::ShadowPass); + reg.register_late_lint_pass(box types::LetPass); + reg.register_late_lint_pass(box types::UnitCmp); + reg.register_late_lint_pass(box loops::LoopsPass); + reg.register_late_lint_pass(box lifetimes::LifetimePass); + reg.register_late_lint_pass(box ranges::StepByZero); + reg.register_late_lint_pass(box types::CastPass); + reg.register_late_lint_pass(box types::TypeComplexityPass); + reg.register_late_lint_pass(box matches::MatchPass); + reg.register_late_lint_pass(box misc::PatternPass); + reg.register_late_lint_pass(box minmax::MinMaxPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index dccad1ffbe7..bfd7125aa4e 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -18,21 +18,23 @@ impl LintPass for LifetimePass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_LIFETIMES) } +} - fn check_item(&mut self, cx: &Context, item: &Item) { +impl LateLintPass for LifetimePass { + fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { check_fn_inner(cx, decl, None, &generics, item.span); } } - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let MethodImplItem(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); } } - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); @@ -49,7 +51,7 @@ enum RefLt { } use self::RefLt::*; -fn check_fn_inner(cx: &Context, decl: &FnDecl, slf: Option<&ExplicitSelf>, +fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, generics: &Generics, span: Span) { if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) { return; diff --git a/src/loops.rs b/src/loops.rs index bcb9744b3f2..497ea8d46c4 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -43,8 +43,10 @@ impl LintPass for LoopsPass { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for LoopsPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let Some((pat, arg, body)) = recover_for_loop(expr) { // check for looping over a range and then indexing a sequence with it // -> the iteratee must be a range literal @@ -186,7 +188,7 @@ impl LintPass for LoopsPass { } } - fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) { + fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { if args.len() == 1 && method.node.name == "collect" && @@ -225,7 +227,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { } struct VarVisitor<'v, 't: 'v> { - cx: &'v Context<'v, 't>, // context reference + cx: &'v LateContext<'v, 't>, // context reference var: Name, // var name to look for as index indexed: HashSet<Name>, // indexed variables nonindex: bool, // has the var been used otherwise? @@ -258,7 +260,7 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { /// Return true if the type of expr is one that provides IntoIterator impls /// for &T and &mut T, such as Vec. -fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool { +fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); @@ -320,7 +322,7 @@ enum VarState { // Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'v, 't: 'v> { - cx: &'v Context<'v, 't>, // context reference + cx: &'v LateContext<'v, 't>, // context reference states: HashMap<NodeId, VarState>, // incremented variables depth: u32, // depth of conditional expressions done: bool @@ -376,7 +378,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { // Check whether a variable is initialized to zero at the start of a loop. struct InitializeVisitor<'v, 't: 'v> { - cx: &'v Context<'v, 't>, // context reference + cx: &'v LateContext<'v, 't>, // context reference end_expr: &'v Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, @@ -454,7 +456,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { } } -fn var_def_id(cx: &Context, expr: &Expr) -> Option<NodeId> { +fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { if let DefLocal(node_id) = path_res.base_def { return Some(node_id) diff --git a/src/matches.rs b/src/matches.rs index 8e5a7f51577..4e49cd3ff73 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -17,8 +17,10 @@ impl LintPass for MatchPass { fn get_lints(&self) -> LintArray { lint_array!(SINGLE_MATCH, MATCH_REF_PATS) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for MatchPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { // check preconditions for SINGLE_MATCH // only two arms diff --git a/src/methods.rs b/src/methods.rs index b110d92e7f8..facedaa3867 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -36,8 +36,10 @@ impl LintPass for MethodsPass { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for MethodsPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(ref ident, _, ref args) = expr.node { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); if ident.node.name == "unwrap" { @@ -71,7 +73,7 @@ impl LintPass for MethodsPass { } } - fn check_item(&mut self, cx: &Context, item: &Item) { + fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { for implitem in items { let name = implitem.ident.name; @@ -229,7 +231,7 @@ fn is_bool(ty: &Ty) -> bool { false } -fn is_copy(cx: &Context, ast_ty: &Ty, item: &Item) -> bool { +fn is_copy(cx: &LateContext, ast_ty: &Ty, item: &Item) -> bool { match cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { None => false, Some(ty) => { diff --git a/src/minmax.rs b/src/minmax.rs index 72190d70e2e..a94b0b42ec1 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,4 +1,4 @@ -use rustc::lint::{Context, LintPass, LintArray}; +use rustc::lint::*; use rustc_front::hir::*; use syntax::ptr::P; use std::cmp::PartialOrd; @@ -19,8 +19,10 @@ impl LintPass for MinMaxPass { fn get_lints(&self) -> LintArray { lint_array!(MIN_MAX) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for MinMaxPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let Some((outer_max, outer_c, oe)) = min_max(expr) { if let Some((inner_max, inner_c, _)) = min_max(oe) { if outer_max == inner_max { return; } diff --git a/src/misc.rs b/src/misc.rs index 63c2082abde..20f5d16bbc1 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -21,8 +21,10 @@ impl LintPass for TopLevelRefPass { fn get_lints(&self) -> LintArray { lint_array!(TOPLEVEL_REF_ARG) } +} - fn check_fn(&mut self, cx: &Context, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { +impl LateLintPass for TopLevelRefPass { + fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { if let FnKind::Closure = k { // Does not apply to closures return @@ -49,8 +51,10 @@ impl LintPass for CmpNan { fn get_lints(&self) -> LintArray { lint_array!(CMP_NAN) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for CmpNan { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { if let &ExprPath(_, ref path) = &left.node { @@ -64,7 +68,7 @@ impl LintPass for CmpNan { } } -fn check_nan(cx: &Context, path: &Path, span: Span) { +fn check_nan(cx: &LateContext, path: &Path, span: Span) { path.segments.last().map(|seg| if seg.identifier.name == "NAN" { span_lint(cx, CMP_NAN, span, "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); @@ -83,8 +87,10 @@ impl LintPass for FloatCmp { fn get_lints(&self) -> LintArray { lint_array!(FLOAT_CMP) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for FloatCmp { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { @@ -109,7 +115,7 @@ impl LintPass for FloatCmp { } } -fn is_float(cx: &Context, expr: &Expr) -> bool { +fn is_float(cx: &LateContext, expr: &Expr) -> bool { if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { true } else { @@ -127,8 +133,10 @@ impl LintPass for CmpOwned { fn get_lints(&self) -> LintArray { lint_array!(CMP_OWNED) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for CmpOwned { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { check_to_owned(cx, left, right.span); @@ -138,7 +146,7 @@ impl LintPass for CmpOwned { } } -fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { +fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span) { match expr.node { ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { let name = ident.name; @@ -165,7 +173,7 @@ fn check_to_owned(cx: &Context, expr: &Expr, other_span: Span) { } } -fn is_str_arg(cx: &Context, args: &[P<Expr>]) -> bool { +fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { args.len() == 1 && if let ty::TyStr = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { true } else { false } } @@ -179,8 +187,10 @@ impl LintPass for ModuloOne { fn get_lints(&self) -> LintArray { lint_array!(MODULO_ONE) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for ModuloOne { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, _, ref right) = expr.node { if let &Spanned {node: BinOp_::BiRem, ..} = cmp { if is_integer_literal(right, 1) { @@ -200,8 +210,10 @@ impl LintPass for PatternPass { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_PATTERN) } +} - fn check_pat(&mut self, cx: &Context, pat: &Pat) { +impl LateLintPass for PatternPass { + fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatIdent(_, ref ident, Some(ref right)) = pat.node { if right.node == PatWild(PatWildSingle) { cx.span_lint(REDUNDANT_PATTERN, pat.span, &format!( diff --git a/src/mut_mut.rs b/src/mut_mut.rs index d3270861870..9b6a5d9ddcc 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -15,18 +15,20 @@ impl LintPass for MutMut { fn get_lints(&self) -> LintArray { lint_array!(MUT_MUT) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for MutMut { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { check_expr_mut(cx, expr) } - fn check_ty(&mut self, cx: &Context, ty: &Ty) { + fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible")) } } -fn check_expr_mut(cx: &Context, expr: &Expr) { +fn check_expr_mut(cx: &LateContext, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } fn unwrap_addr(expr : &Expr) -> Option<&Expr> { diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 7947839426d..c0a99acb71d 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -23,8 +23,10 @@ impl LintPass for NeedlessBool { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_BOOL) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for NeedlessBool { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (Some(true), Some(true)) => { diff --git a/src/precedence.rs b/src/precedence.rs index c55e65b3a6b..ce06278b782 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,7 +1,6 @@ use rustc::lint::*; -use rustc_front::hir::*; use syntax::codemap::Spanned; -use syntax::ast::Lit_::*; +use syntax::ast::*; use utils::span_lint; declare_lint!(pub PRECEDENCE, Warn, @@ -15,8 +14,10 @@ impl LintPass for Precedence { fn get_lints(&self) -> LintArray { lint_array!(PRECEDENCE) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl EarlyLintPass for Precedence { + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { span_lint(cx, PRECEDENCE, expr.span, diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index b0d9757e6c5..7c369469ea2 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -23,27 +23,29 @@ impl LintPass for PtrArg { fn get_lints(&self) -> LintArray { lint_array!(PTR_ARG) } +} - fn check_item(&mut self, cx: &Context, item: &Item) { +impl LateLintPass for PtrArg { + fn check_item(&mut self, cx: &LateContext, item: &Item) { if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { check_fn(cx, decl); } } - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let &MethodImplItem(ref sig, _) = &item.node { check_fn(cx, &sig.decl); } } - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if let &MethodTraitItem(ref sig, _) = &item.node { check_fn(cx, &sig.decl); } } } -fn check_fn(cx: &Context, decl: &FnDecl) { +fn check_fn(cx: &LateContext, decl: &FnDecl) { for arg in &decl.inputs { if let Some(pat_ty) = cx.tcx.pat_ty_opt(&arg.pat) { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = pat_ty.sty { diff --git a/src/ranges.rs b/src/ranges.rs index 97f59a3aadd..8ba2440d361 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,4 +1,4 @@ -use rustc::lint::{Context, LintArray, LintPass}; +use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::{match_type, is_integer_literal}; @@ -15,8 +15,10 @@ impl LintPass for StepByZero { fn get_lints(&self) -> LintArray { lint_array!(RANGE_STEP_BY_ZERO) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for StepByZero { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(Spanned { node: ref ident, .. }, _, ref args) = expr.node { // Only warn on literal ranges. @@ -30,7 +32,7 @@ impl LintPass for StepByZero { } } -fn is_range(cx: &Context, expr: &Expr) -> bool { +fn is_range(cx: &LateContext, expr: &Expr) -> bool { // No need for walk_ptrs_ty here because step_by moves self, so it // can't be called on a borrowed range. let ty = cx.tcx.expr_ty(expr); diff --git a/src/returns.rs b/src/returns.rs index ea75cf562bf..7ab5f3364ac 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -17,7 +17,7 @@ pub struct ReturnPass; impl ReturnPass { // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &Context, block: &Block) { + fn check_block_return(&mut self, cx: &LateContext, block: &Block) { if let Some(ref expr) = block.expr { self.check_final_expr(cx, expr); } else if let Some(stmt) = block.stmts.last() { @@ -30,7 +30,7 @@ impl ReturnPass { } // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { + fn check_final_expr(&mut self, cx: &LateContext, expr: &Expr) { match expr.node { // simple return is always "bad" ExprRet(Some(ref inner)) => { @@ -57,7 +57,7 @@ impl ReturnPass { } } - fn emit_return_lint(&mut self, cx: &Context, spans: (Span, Span)) { + fn emit_return_lint(&mut self, cx: &LateContext, spans: (Span, Span)) { if in_external_macro(cx, spans.1) {return;} span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using `{}` \ @@ -66,7 +66,7 @@ impl ReturnPass { } // Check for "let x = EXPR; x" - fn check_let_return(&mut self, cx: &Context, block: &Block) { + fn check_let_return(&mut self, cx: &LateContext, block: &Block) { // we need both a let-binding stmt and an expr if_let_chain! { [ @@ -84,7 +84,7 @@ impl ReturnPass { } } - fn emit_let_lint(&mut self, cx: &Context, lint_span: Span, note_span: Span) { + fn emit_let_lint(&mut self, cx: &LateContext, lint_span: Span, note_span: Span) { if in_external_macro(cx, note_span) {return;} span_lint(cx, LET_AND_RETURN, lint_span, "returning the result of a let binding. \ @@ -100,8 +100,10 @@ impl LintPass for ReturnPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RETURN, LET_AND_RETURN) } +} - fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, +impl LateLintPass for ReturnPass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { self.check_block_return(cx, block); self.check_let_return(cx, block); diff --git a/src/shadow.rs b/src/shadow.rs index ae1eeee2401..f1c09b802c3 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -4,7 +4,7 @@ use reexport::*; use syntax::codemap::Span; use rustc_front::visit::FnKind; -use rustc::lint::{Context, Level, Lint, LintArray, LintPass}; +use rustc::lint::*; use rustc::middle::def::Def::{DefVariant, DefStruct}; use utils::{in_external_macro, snippet, span_lint, span_note_and_lint}; @@ -25,14 +25,17 @@ impl LintPass for ShadowPass { lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) } - fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, +} + +impl LateLintPass for ShadowPass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, block: &Block, _: Span, _: NodeId) { if in_external_macro(cx, block.span) { return; } check_fn(cx, decl, block); } } -fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) { +fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { let mut bindings = Vec::new(); for arg in &decl.inputs { if let PatIdent(_, ident, _) = arg.pat.node { @@ -42,7 +45,7 @@ fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) { check_block(cx, block, &mut bindings); } -fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<(Name, Span)>) { +fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>) { let len = bindings.len(); for stmt in &block.stmts { match stmt.node { @@ -55,7 +58,7 @@ fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<(Name, Span)>) { bindings.truncate(len); } -fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { +fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; @@ -69,14 +72,14 @@ fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { } } -fn is_binding(cx: &Context, pat: &Pat) -> bool { +fn is_binding(cx: &LateContext, pat: &Pat) -> bool { match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { Some(DefVariant(..)) | Some(DefStruct(..)) => false, _ => true } } -fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, +fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { //TODO: match more stuff / destructuring match pat.node { @@ -153,9 +156,9 @@ fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span, } } -fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: +fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: &Option<T>, prev_span: Span) where T: Deref<Target=Expr> { - fn note_orig(cx: &Context, lint: &'static Lint, span: Span) { + fn note_orig(cx: &LateContext, lint: &'static Lint, span: Span) { if cx.current_level(lint) != Level::Allow { cx.sess().span_note(span, "previous binding is here"); } @@ -191,10 +194,10 @@ fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init: } } -fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { +fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, expr.span) { return; } match expr.node { - ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | + ExprUnary(_, ref e) | ExprField(ref e, _) | ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e) => { check_expr(cx, e, bindings) }, ExprBox(Some(ref place), ref e) => { @@ -233,7 +236,7 @@ fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { } } -fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { +fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { match ty.node { TyParen(ref sty) | TyObjectSum(ref sty, _) | TyVec(ref sty) => check_ty(cx, sty, bindings), @@ -252,7 +255,6 @@ fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { fn is_self_shadow(name: Name, expr: &Expr) -> bool { match expr.node { ExprBox(_, ref inner) | - ExprParen(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref(). map_or(false, |ref e| is_self_shadow(name, e)), @@ -275,7 +277,7 @@ fn contains_self(name: Name, expr: &Expr) -> bool { // no subexprs ExprLit(_) => false, // one subexpr - ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) | + ExprUnary(_, ref e) | ExprField(ref e, _) | ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e) | ExprCast(ref e, _) => contains_self(name, e), diff --git a/src/strings.rs b/src/strings.rs index 3c9c1086a12..6bbf94004b0 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -30,8 +30,10 @@ impl LintPass for StringAdd { fn get_lints(&self) -> LintArray { lint_array!(STRING_ADD, STRING_ADD_ASSIGN) } +} - fn check_expr(&mut self, cx: &Context, e: &Expr) { +impl LateLintPass for StringAdd { + fn check_expr(&mut self, cx: &LateContext, e: &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) { @@ -59,18 +61,17 @@ impl LintPass for StringAdd { } } -fn is_string(cx: &Context, e: &Expr) -> bool { +fn is_string(cx: &LateContext, e: &Expr) -> bool { match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH) } -fn is_add(cx: &Context, src: &Expr, target: &Expr) -> bool { +fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left), ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)), - ExprParen(ref expr) => is_add(cx, expr, target), _ => false } } diff --git a/src/types.rs b/src/types.rs index d8d2c7a9438..dd41b4f2239 100644 --- a/src/types.rs +++ b/src/types.rs @@ -26,8 +26,10 @@ impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) } +} - fn check_ty(&mut self, cx: &Context, ast_ty: &Ty) { +impl LateLintPass for TypePass { + fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) { if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { if match_type(cx, inner, &VEC_PATH) { @@ -53,7 +55,7 @@ pub struct LetPass; declare_lint!(pub LET_UNIT_VALUE, Warn, "creating a let binding to a value of unit type, which usually can't be used afterwards"); -fn check_let_unit(cx: &Context, decl: &Decl) { +fn check_let_unit(cx: &LateContext, decl: &Decl) { if let DeclLocal(ref local) = decl.node { let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { @@ -70,8 +72,10 @@ impl LintPass for LetPass { fn get_lints(&self) -> LintArray { lint_array!(LET_UNIT_VALUE) } +} - fn check_decl(&mut self, cx: &Context, decl: &Decl) { +impl LateLintPass for LetPass { + fn check_decl(&mut self, cx: &LateContext, decl: &Decl) { check_let_unit(cx, decl) } } @@ -86,8 +90,10 @@ impl LintPass for UnitCmp { fn get_lints(&self) -> LintArray { lint_array!(UNIT_CMP) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for UnitCmp { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_macro(cx, expr.span) { return; } if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; @@ -135,7 +141,7 @@ fn is_isize_or_usize(typ: &ty::TyS) -> bool { } } -fn span_precision_loss_lint(cx: &Context, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: 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 arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; let arch_dependent_str = "on targets with 64-bit wide pointers "; @@ -154,7 +160,7 @@ enum ArchSuffix { _32, _64, None } -fn check_truncation_and_wrapping(cx: &Context, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { +fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { let arch_64_suffix = " on targets with 64-bit wide pointers"; let arch_32_suffix = " on targets with 32-bit wide pointers"; let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); @@ -207,8 +213,10 @@ impl LintPass for CastPass { CAST_POSSIBLE_TRUNCATION, CAST_POSSIBLE_WRAP) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for CastPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprCast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr)); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { @@ -262,16 +270,18 @@ impl LintPass for TypeComplexityPass { fn get_lints(&self) -> LintArray { lint_array!(TYPE_COMPLEXITY) } +} - fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { +impl LateLintPass for TypeComplexityPass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { check_fndecl(cx, decl); } - fn check_struct_field(&mut self, cx: &Context, field: &StructField) { + fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { check_type(cx, &field.node.ty); } - fn check_variant(&mut self, cx: &Context, var: &Variant, _: &Generics) { + fn check_variant(&mut self, cx: &LateContext, var: &Variant, _: &Generics) { // StructVariant is covered by check_struct_field if let TupleVariantKind(ref args) = var.node.kind { for arg in args { @@ -280,7 +290,7 @@ impl LintPass for TypeComplexityPass { } } - fn check_item(&mut self, cx: &Context, item: &Item) { + fn check_item(&mut self, cx: &LateContext, item: &Item) { match item.node { ItemStatic(ref ty, _, _) | ItemConst(ref ty, _) => check_type(cx, ty), @@ -289,7 +299,7 @@ impl LintPass for TypeComplexityPass { } } - fn check_trait_item(&mut self, cx: &Context, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { match item.node { ConstTraitItem(ref ty, _) | TypeTraitItem(_, Some(ref ty)) => check_type(cx, ty), @@ -299,7 +309,7 @@ impl LintPass for TypeComplexityPass { } } - fn check_impl_item(&mut self, cx: &Context, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { match item.node { ConstImplItem(ref ty, _) | TypeImplItem(ref ty) => check_type(cx, ty), @@ -308,14 +318,14 @@ impl LintPass for TypeComplexityPass { } } - fn check_local(&mut self, cx: &Context, local: &Local) { + fn check_local(&mut self, cx: &LateContext, local: &Local) { if let Some(ref ty) = local.ty { check_type(cx, ty); } } } -fn check_fndecl(cx: &Context, decl: &FnDecl) { +fn check_fndecl(cx: &LateContext, decl: &FnDecl) { for arg in &decl.inputs { check_type(cx, &arg.ty); } @@ -324,7 +334,7 @@ fn check_fndecl(cx: &Context, decl: &FnDecl) { } } -fn check_type(cx: &Context, ty: &Ty) { +fn check_type(cx: &LateContext, ty: &Ty) { if in_macro(cx, ty.span) { return; } let score = { let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; diff --git a/src/unicode.rs b/src/unicode.rs index 16f2653429f..3855fafe7be 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -25,8 +25,10 @@ impl LintPass for Unicode { fn get_lints(&self) -> LintArray { lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC) } +} - fn check_expr(&mut self, cx: &Context, expr: &Expr) { +impl LateLintPass for Unicode { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprLit(ref lit) = expr.node { if let LitStr(_, _) = lit.node { check_str(cx, lit.span) @@ -47,7 +49,7 @@ fn escape<T: Iterator<Item=char>>(s: T) -> String { result } -fn check_str(cx: &Context, span: Span) { +fn check_str(cx: &LateContext, span: Span) { let string = snippet(cx, span, ""); if string.contains('\u{200B}') { span_help_and_lint(cx, ZERO_WIDTH_SPACE, span, diff --git a/src/utils.rs b/src/utils.rs index 6c0fe97c983..d5566c3a691 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -16,7 +16,7 @@ pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; /// returns true this expn_info was expanded by any macro -pub fn in_macro(cx: &Context, span: Span) -> bool { +pub fn in_macro(cx: &LateContext, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, |info| info.map_or(false, |i| { match i.callee.format { @@ -28,10 +28,10 @@ pub fn in_macro(cx: &Context, span: Span) -> bool { /// 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: &Context, span: Span) -> bool { +pub fn in_external_macro<T: LintContext>(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: &Context, opt_info: Option<&ExpnInfo>) -> bool { + fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { match info.callee.format { @@ -65,12 +65,12 @@ pub fn in_external_macro(cx: &Context, span: Span) -> bool { /// check if a DefId's path matches the given absolute type path /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` -pub fn match_def_path(cx: &Context, def_id: DefId, path: &[&str]) -> bool { +pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { cx.tcx.with_path(def_id, |iter| iter.zip(path).all(|(nm, p)| nm.name() == p)) } /// check if type is struct or enum type with given def path -pub fn match_type(cx: &Context, ty: ty::Ty, path: &[&str]) -> bool { +pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { match ty.sty { ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => { match_def_path(cx, adt.did, path) @@ -82,7 +82,7 @@ pub fn match_type(cx: &Context, ty: ty::Ty, path: &[&str]) -> bool { } /// check if method call given in "expr" belongs to given trait -pub fn match_trait_method(cx: &Context, expr: &Expr, path: &[&str]) -> bool { +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) @@ -102,7 +102,7 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { } /// get the name of the item the expression is in, if available -pub fn get_item_name(cx: &Context, expr: &Expr) -> Option<Name> { +pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { Some(NodeItem(&Item{ ref ident, .. })) | @@ -116,7 +116,7 @@ pub fn get_item_name(cx: &Context, expr: &Expr) -> Option<Name> { /// convert a span to a code snippet if available, otherwise use default, e.g. /// `snippet(cx, expr.span, "..")` -pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) } @@ -124,13 +124,13 @@ pub fn snippet<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { /// `snippet(cx, expr.span, "..")` /// This trims the code of indentation, except for the first line /// Use it for blocks or block-like things which need to be printed as such -pub fn snippet_block<'a>(cx: &Context, span: Span, default: &'a str) -> Cow<'a, str> { +pub fn snippet_block<'a, T: LintContext>(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 -pub fn expr_block<'a>(cx: &Context, expr: &Expr, default: &'a str) -> Cow<'a, str> { +pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, default: &'a str) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); if let ExprBlock(_) = expr.node { code @@ -169,7 +169,7 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { } /// get a parent expr if any – this is useful to constrain a lint -pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { +pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.map; let node_id : NodeId = e.id; let parent_id : NodeId = map.get_parent_node(node_id); @@ -179,7 +179,7 @@ pub fn get_parent_expr<'c>(cx: &'c Context, e: &Expr) -> Option<&'c Expr> { } #[cfg(not(feature="structured_logging"))] -pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { +pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { cx.sess().fileline_help(sp, &format!("for further information visit \ @@ -189,7 +189,7 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { } #[cfg(feature="structured_logging")] -pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { +pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { // lint.name / lint.desc is can give details of the lint // cx.sess().codemap() has all these nice functions for line/column/snippet details // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string @@ -201,7 +201,7 @@ pub fn span_lint(cx: &Context, lint: &'static Lint, sp: Span, msg: &str) { } } -pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, +pub fn span_help_and_lint<T: LintContext>(cx: &T, lint: &'static Lint, span: Span, msg: &str, help: &str) { cx.span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { @@ -211,7 +211,7 @@ pub fn span_help_and_lint(cx: &Context, lint: &'static Lint, span: Span, } } -pub fn span_note_and_lint(cx: &Context, lint: &'static Lint, span: Span, +pub fn span_note_and_lint<T: LintContext>(cx: &T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, note: &str) { cx.span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 293d97a42fa..d70f26ed090 100755 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -12,7 +12,7 @@ fn main() { let mut x = 1; let x = &mut x; //~ERROR: x is shadowed by itself in &mut x let x = { x }; //~ERROR: x is shadowed by itself in { x } - let x = (&*x); //~ERROR: x is shadowed by itself in (&*x) + let x = (&*x); //~ERROR: x is shadowed by itself in &*x let x = { *x + 1 }; //~ERROR: x is shadowed by { *x + 1 } which reuses let x = id(x); //~ERROR: x is shadowed by id(x) which reuses let x = (1, x); //~ERROR: x is shadowed by (1, x) which reuses -- cgit 1.4.1-3-g733a5 From b56ff4319eb341ce3393eadba4ff200efe32a4e9 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 19 Sep 2015 08:32:56 +0530 Subject: fix dogfood --- src/bit_mask.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index d99497aafe9..e6665bbbb4d 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -85,14 +85,13 @@ fn invert_cmp(cmp : BinOp_) -> BinOp_ { fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { - match bit_op.node { - ExprBinary(ref op, ref left, ref right) => { - if op.node != BiBitAnd && op.node != BiBitOr { return; } - fetch_int_literal(cx, right).or_else(|| fetch_int_literal( - cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, - cmp_op, mask, cmp_value, span)) - }, - _ => () + if let ExprBinary(ref op, ref left, ref right) = bit_op.node { + if op.node != BiBitAnd && op.node != BiBitOr { + return; + } + fetch_int_literal(cx, right).or_else(|| fetch_int_literal( + cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, + cmp_op, mask, cmp_value, span)) } } -- cgit 1.4.1-3-g733a5 From 7fdf52270b504f4e8e680cc7ae2dc2f8b1eaae3b Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sat, 19 Sep 2015 08:49:01 +0200 Subject: Fix stray backquote. --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index facedaa3867..f5361f255c7 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -124,7 +124,7 @@ const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ]; const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ - ("add", 2, ValueSelf, AnyType, "std::ops::Add`"), + ("add", 2, ValueSelf, AnyType, "std::ops::Add"), ("sub", 2, ValueSelf, AnyType, "std::ops::Sub"), ("mul", 2, ValueSelf, AnyType, "std::ops::Mul"), ("div", 2, ValueSelf, AnyType, "std::ops::Div"), -- cgit 1.4.1-3-g733a5 From 7cc291d02eba4b513461d697ee89971d0a0fb2cd Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 20 Sep 2015 13:57:27 +0200 Subject: generalize let_and_return for any block (closes #340) --- src/returns.rs | 9 ++++++--- tests/compile-fail/let_return.rs | 14 ++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/returns.rs b/src/returns.rs index 7ab5f3364ac..d04307ffd5d 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -10,7 +10,7 @@ declare_lint!(pub NEEDLESS_RETURN, Warn, "using a return statement like `return expr;` where an expression would suffice"); declare_lint!(pub LET_AND_RETURN, Warn, "creating a let-binding and then immediately returning it like `let x = expr; x` at \ - the end of a function"); + the end of a block"); #[derive(Copy, Clone)] pub struct ReturnPass; @@ -71,11 +71,11 @@ impl ReturnPass { if_let_chain! { [ let Some(stmt) = block.stmts.last(), + let Some(ref retexpr) = block.expr, let StmtDecl(ref decl, _) = stmt.node, let DeclLocal(ref local) = decl.node, let Some(ref initexpr) = local.init, let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, - let Some(ref retexpr) = block.expr, let ExprPath(_, ref path) = retexpr.node, match_path(path, &[&id.name.as_str()]) ], { @@ -87,7 +87,7 @@ impl ReturnPass { fn emit_let_lint(&mut self, cx: &LateContext, lint_span: Span, note_span: Span) { if in_external_macro(cx, note_span) {return;} span_lint(cx, LET_AND_RETURN, lint_span, - "returning the result of a let binding. \ + "returning the result of a let binding from a block. \ Consider returning the expression directly."); if cx.current_level(LET_AND_RETURN) != Level::Allow { cx.sess().span_note(note_span, @@ -106,6 +106,9 @@ impl LateLintPass for ReturnPass { fn check_fn(&mut self, cx: &LateContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { self.check_block_return(cx, block); + } + + fn check_block(&mut self, cx: &LateContext, block: &Block) { self.check_let_return(cx, block); } } diff --git a/tests/compile-fail/let_return.rs b/tests/compile-fail/let_return.rs index 082378d21e2..33d2d6a823a 100755 --- a/tests/compile-fail/let_return.rs +++ b/tests/compile-fail/let_return.rs @@ -1,5 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(unused)] #![deny(let_and_return)] @@ -9,6 +10,15 @@ fn test() -> i32 { x //~ERROR returning the result of a let binding } +fn test_inner() -> i32 { + if true { + let x = 5; + x //~ERROR returning the result of a let binding + } else { + 0 + } +} + fn test_nowarn_1() -> i32 { let mut x = 5; x += 1; @@ -27,8 +37,4 @@ fn test_nowarn_3() -> (i32, i32) { } fn main() { - test(); - test_nowarn_1(); - test_nowarn_2(); - test_nowarn_3(); } -- cgit 1.4.1-3-g733a5 From 3609a2211a1cdb27c77f139108b25f9c9d3613f9 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 22 Sep 2015 12:38:42 +0530 Subject: Handle let ref in toplevel_ref_arg as well --- README.md | 4 ++-- src/misc.rs | 29 +++++++++++++++++++++++++++-- tests/compile-fail/matches.rs | 4 ++-- tests/compile-fail/toplevel_ref_arg.rs | 8 ++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 011078c5407..902667f31c5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A collection of lints that give helpful tips to newbies and catch oversights. There are 58 lints included in this crate: name | default | meaning --------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap @@ -59,7 +59,7 @@ name [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op -[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`) +[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) diff --git a/src/misc.rs b/src/misc.rs index 20f5d16bbc1..c18c483bcba 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -8,11 +8,13 @@ use rustc_front::visit::FnKind; use rustc::middle::ty; use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; +use utils::span_help_and_lint; use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, - "a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not \ - `fn foo((ref x, ref y): (u8, u8))`)"); + "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ + or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ + references with `&`."); #[allow(missing_copy_implementations)] pub struct TopLevelRefPass; @@ -39,6 +41,29 @@ impl LateLintPass for TopLevelRefPass { } } } + fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) { + if_let_chain! { + [ + let StmtDecl(ref d, _) = s.node, + let DeclLocal(ref l) = d.node, + let PatIdent(BindByRef(_), i, None) = l.pat.node, + let Some(ref init) = l.init + ], { + let tyopt = if let Some(ref ty) = l.ty { + format!(": {:?} ", ty) + } else { + "".to_owned() + }; + span_help_and_lint(cx, + TOPLEVEL_REF_ARG, + l.pat.span, + "`ref` on an entire `let` pattern is discouraged, take a reference with & instead", + &format!("try `let {} {}= &{};`", snippet(cx, i.span, "_"), + tyopt, snippet(cx, init.span, "_")) + ); + } + }; + } } declare_lint!(pub CMP_NAN, Deny, diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 2fd9df33ef5..f25a5fa3fa4 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -40,7 +40,7 @@ fn single_match(){ fn ref_pats() { { - let ref v = Some(0); + let v = &Some(0); match v { //~ERROR instead of prefixing all patterns with `&` &Some(v) => println!("{:?}", v), &None => println!("none"), @@ -50,7 +50,7 @@ fn ref_pats() { other => println!("other"), } } - let ref tup = (1, 2); + let tup =& (1, 2); match tup { //~ERROR instead of prefixing all patterns with `&` &(v, 1) => println!("{}", v), _ => println!("none"), diff --git a/tests/compile-fail/toplevel_ref_arg.rs b/tests/compile-fail/toplevel_ref_arg.rs index ea69a8cfa15..05ad1af0034 100644 --- a/tests/compile-fail/toplevel_ref_arg.rs +++ b/tests/compile-fail/toplevel_ref_arg.rs @@ -14,5 +14,13 @@ fn main() { // Closures should not warn let y = |ref x| { println!("{:?}", x) }; y(1u8); + + let ref x = 1; //~ ERROR `ref` on an entire `let` pattern is discouraged + //~^ HELP try `let x = &1;` + + let ref y = (&1, 2); //~ ERROR `ref` on an entire `let` pattern is discouraged + //~^ HELP try `let y = &(&1, 2);` + + let (ref x, _) = (1,2); // okay, not top level println!("The answer is {}.", x); } -- cgit 1.4.1-3-g733a5 From b2c66d1a0eb77338dc6b421fd18903fca4d8975e Mon Sep 17 00:00:00 2001 From: Pietro Monteiro <pietro@riseup.net> Date: Wed, 23 Sep 2015 17:30:39 -0700 Subject: Upgrade Rust to rustc 1.5.0-nightly (b2f379cdc 2015-09-23) Ident was removed in many HIR structures in favor of Name. --- Cargo.toml | 2 +- src/attrs.rs | 10 +++++----- src/len_zero.rs | 17 +++++++++-------- src/loops.rs | 4 ++-- src/methods.rs | 8 ++++---- src/misc.rs | 7 +++---- src/ranges.rs | 4 ++-- src/shadow.rs | 4 ++-- src/utils.rs | 8 ++++---- 9 files changed, 32 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 4ff702de4a5..8a905ffac42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.15" +version = "0.0.16" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/attrs.rs b/src/attrs.rs index 6450cc16195..936548c04f8 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -24,19 +24,19 @@ impl LintPass for AttrPass { impl LateLintPass for AttrPass { fn check_item(&mut self, cx: &LateContext, item: &Item) { if is_relevant_item(item) { - check_attrs(cx, item.span, &item.ident, &item.attrs) + check_attrs(cx, item.span, &item.name, &item.attrs) } } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if is_relevant_impl(item) { - check_attrs(cx, item.span, &item.ident, &item.attrs) + check_attrs(cx, item.span, &item.name, &item.attrs) } } fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if is_relevant_trait(item) { - check_attrs(cx, item.span, &item.ident, &item.attrs) + check_attrs(cx, item.span, &item.name, &item.attrs) } } } @@ -88,7 +88,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { } } -fn check_attrs(cx: &LateContext, span: Span, ident: &Ident, +fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { if in_macro(cx, span) { return; } @@ -100,7 +100,7 @@ fn check_attrs(cx: &LateContext, span: Span, ident: &Ident, span_lint(cx, INLINE_ALWAYS, attr.span, &format!( "you have declared `#[inline(always)]` on `{}`. This \ is usually a bad idea. Are you sure?", - ident.name)); + name)); } } } diff --git a/src/len_zero.rs b/src/len_zero.rs index dfd340ef5ea..d8886e43dca 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,5 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; +use syntax::ast::Name; use syntax::ptr::P; use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; @@ -51,7 +52,7 @@ impl LateLintPass for LenZero { fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.ident.name == name && if let MethodTraitItem(ref sig, _) = + item.name == name && if let MethodTraitItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -62,7 +63,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>] span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, &format!("trait `{}` has a `.len(_: &Self)` method, but no \ `.is_empty(_: &Self)` method. Consider adding one", - item.ident.name)); + item.name)); } }; } @@ -70,7 +71,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>] fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.ident.name == name && if let MethodImplItem(ref sig, _) = + item.name == name && if let MethodImplItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -82,7 +83,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, &format!("item `{}` has a `.len(_: &Self)` method, but no \ `.is_empty(_: &Self)` method. Consider adding one", - item.ident.name)); + item.name)); return; } } @@ -101,17 +102,17 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => - check_len_zero(cx, span, method, args, lit, op), + check_len_zero(cx, span, &method.node, args, lit, op), (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => - check_len_zero(cx, span, method, args, lit, op), + check_len_zero(cx, span, &method.node, args, lit, op), _ => () } } -fn check_len_zero(cx: &LateContext, span: Span, method: &SpannedIdent, +fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { - if method.node.name == "len" && args.len() == 1 && + if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "consider replacing the len comparison with `{}{}.is_empty()`", diff --git a/src/loops.rs b/src/loops.rs index 497ea8d46c4..4afa31ff515 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -108,7 +108,7 @@ impl LateLintPass for LoopsPass { if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments if args.len() == 1 { - let method_name = method.node.name; + let method_name = method.node; // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x if method_name == "iter" || method_name == "iter_mut" { if is_ref_iterable_type(cx, &args[0]) { @@ -191,7 +191,7 @@ impl LateLintPass for LoopsPass { fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 && method.node.name == "collect" && + if args.len() == 1 && method.node == "collect" && match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { span_lint(cx, UNUSED_COLLECT, expr.span, &format!( "you are collect()ing an iterator and throwing away the result. \ diff --git a/src/methods.rs b/src/methods.rs index f5361f255c7..1adf9c30e81 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -40,9 +40,9 @@ impl LintPass for MethodsPass { impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(ref ident, _, ref args) = expr.node { + if let ExprMethodCall(ref name, _, ref args) = expr.node { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - if ident.node.name == "unwrap" { + if name.node.as_str() == "unwrap" { if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ @@ -54,7 +54,7 @@ impl LateLintPass for MethodsPass { of Err values is preferred"); } } - else if ident.node.name == "to_string" { + else if name.node.as_str() == "to_string" { if obj_ty.sty == ty::TyStr { let mut arg_str = snippet(cx, args[0].span, "_"); if ptr_depth > 1 { @@ -76,7 +76,7 @@ impl LateLintPass for MethodsPass { fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { for implitem in items { - let name = implitem.ident.name; + let name = implitem.name; if let MethodImplItem(ref sig, _) = implitem.node { // check missing trait implementations for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { diff --git a/src/misc.rs b/src/misc.rs index c18c483bcba..c40fd0fa364 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -173,10 +173,9 @@ impl LateLintPass for CmpOwned { fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span) { match expr.node { - ExprMethodCall(Spanned{node: ref ident, ..}, _, ref args) => { - let name = ident.name; - if name == "to_string" || - name == "to_owned" && is_str_arg(cx, args) { + ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) => { + if name.as_str() == "to_string" || + name.as_str() == "to_owned" && is_str_arg(cx, args) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using `{}.as_slice()` to compare without allocation", diff --git a/src/ranges.rs b/src/ranges.rs index 8ba2440d361..2ef272237d1 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -19,10 +19,10 @@ impl LintPass for StepByZero { impl LateLintPass for StepByZero { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(Spanned { node: ref ident, .. }, _, + if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { // Only warn on literal ranges. - if ident.name == "step_by" && args.len() == 2 && + if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, "Range::step_by(0) produces an infinite iterator. \ diff --git a/src/shadow.rs b/src/shadow.rs index f1c09b802c3..25970df399d 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -106,9 +106,9 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, if let Some(ref init_struct) = *init { if let ExprStruct(_, ref efields, _) = init_struct.node { for field in pfields { - let ident = field.node.ident; + let name = field.node.name; let efield = efields.iter() - .find(|ref f| f.ident.node == ident) + .find(|ref f| f.name.node == name) .map(|f| &*f.expr); check_pat(cx, &field.node.pat, &efield, span, bindings); } diff --git a/src/utils.rs b/src/utils.rs index d5566c3a691..250e24ac646 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -105,10 +105,10 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { - Some(NodeItem(&Item{ ref ident, .. })) | - Some(NodeTraitItem(&TraitItem{ id: _, ref ident, .. })) | - Some(NodeImplItem(&ImplItem{ id: _, ref ident, .. })) => { - Some(ident.name) + Some(NodeItem(&Item{ ref name, .. })) | + Some(NodeTraitItem(&TraitItem{ id: _, ref name, .. })) | + Some(NodeImplItem(&ImplItem{ id: _, ref name, .. })) => { + Some(*name) }, _ => None, } -- cgit 1.4.1-3-g733a5 From cd114880800069d5a79c5bfb5c146110b078160c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 25 Sep 2015 18:52:36 +0530 Subject: rustup 2015-09-24 --- Cargo.toml | 2 +- src/consts.rs | 2 +- src/shadow.rs | 12 +++++------- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 8a905ffac42..5ff911c8ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.16" +version = "0.0.17" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/consts.rs b/src/consts.rs index d66bfb5b4fc..be681efb257 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -321,7 +321,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { |o| match op { UnNot => constant_not(o), UnNeg => constant_negate(o), - UnUniq | UnDeref => Some(o), + UnDeref => Some(o), }), ExprBinary(op, ref left, ref right) => self.binop(op, left, right), diff --git a/src/shadow.rs b/src/shadow.rs index 25970df399d..8fd8d0d15ac 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -140,7 +140,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, }, PatBox(ref inner) => { if let Some(ref initp) = *init { - if let ExprBox(_, ref inner_init) = initp.node { + if let ExprBox(ref inner_init) = initp.node { check_pat(cx, inner, &Some(&**inner_init), span, bindings); } else { check_pat(cx, inner, init, span, bindings); @@ -198,10 +198,8 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, expr.span) { return; } match expr.node { ExprUnary(_, ref e) | ExprField(ref e, _) | - ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e) + ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) => { check_expr(cx, e, bindings) }, - ExprBox(Some(ref place), ref e) => { - check_expr(cx, place, bindings); check_expr(cx, e, bindings) } ExprBlock(ref block) | ExprLoop(ref block, _) => { check_block(cx, block, bindings) }, //ExprCall @@ -254,11 +252,11 @@ fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { fn is_self_shadow(name: Name, expr: &Expr) -> bool { match expr.node { - ExprBox(_, ref inner) | + ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref(). map_or(false, |ref e| is_self_shadow(name, e)), - ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) && + ExprUnary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner), ExprPath(_, ref path) => path_eq_name(name, path), _ => false, @@ -278,7 +276,7 @@ fn contains_self(name: Name, expr: &Expr) -> bool { ExprLit(_) => false, // one subexpr ExprUnary(_, ref e) | ExprField(ref e, _) | - ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e) | + ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) | ExprCast(ref e, _) => contains_self(name, e), // two subexprs -- cgit 1.4.1-3-g733a5 From 15e3774cb4a6536cdb6c01edaa93315743b9f49a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 28 Sep 2015 10:34:06 +0530 Subject: rustup to 1.5.0-nightly (7bf4c885f 2015-09-26) fixes #348 --- src/len_zero.rs | 10 +++++----- src/lifetimes.rs | 2 +- src/loops.rs | 8 ++++---- src/methods.rs | 6 +++--- src/misc.rs | 11 ++++++----- src/ranges.rs | 2 +- src/utils.rs | 7 ++++--- 7 files changed, 24 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 620c6bfd7b8..2c85298201f 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -52,7 +52,7 @@ impl LateLintPass for LenZero { fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.name == name && if let MethodTraitItem(ref sig, _) = + item.name.as_str() == name && if let MethodTraitItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -71,7 +71,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>] fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.name == name && if let MethodImplItem(ref sig, _) = + item.name.as_str() == name && if let MethodImplItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } } @@ -98,7 +98,7 @@ fn is_self_sig(sig: &MethodSig) -> bool { fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, left) { - if name == "is_empty" { return; } + if name.as_str() == "is_empty" { return; } } match (&left.node, &right.node) { (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => @@ -112,7 +112,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { - if name == &"len" && args.len() == 1 && + if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "consider replacing the len comparison with `{}{}.is_empty()`", @@ -128,7 +128,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { if let &MethodTraitItemId(def_id) = id { if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { - method.name == "is_empty" + method.name.as_str() == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 } else { false } } else { false } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index bfd7125aa4e..b64fa148ef3 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -161,7 +161,7 @@ struct RefVisitor(Vec<RefLt>); impl RefVisitor { fn record(&mut self, lifetime: &Option<Lifetime>) { if let &Some(ref lt) = lifetime { - if lt.name == "'static" { + if lt.name.as_str() == "'static" { self.0.push(Static); } else { self.0.push(Named(lt.name)); diff --git a/src/loops.rs b/src/loops.rs index 4afa31ff515..9e7b0ee38d4 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -110,17 +110,17 @@ impl LateLintPass for LoopsPass { if args.len() == 1 { let method_name = method.node; // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - if method_name == "iter" || method_name == "iter_mut" { + if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { if is_ref_iterable_type(cx, &args[0]) { let object = snippet(cx, args[0].span, "_"); span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", - if method_name == "iter_mut" { "mut " } else { "" }, + if method_name.as_str() == "iter_mut" { "mut " } else { "" }, object, object, method_name)); } } // check for looping over Iterator::next() which is not what you want - else if method_name == "next" && + else if method_name.as_str() == "next" && match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { span_lint(cx, ITER_NEXT_LOOP, expr.span, "you are iterating over `Iterator::next()` which is an Option; \ @@ -191,7 +191,7 @@ impl LateLintPass for LoopsPass { fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 && method.node == "collect" && + if args.len() == 1 && method.node.as_str() == "collect" && match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { span_lint(cx, UNUSED_COLLECT, expr.span, &format!( "you are collect()ing an iterator and throwing away the result. \ diff --git a/src/methods.rs b/src/methods.rs index 946e0985823..18da7e977d6 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -42,7 +42,7 @@ impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(ref name, _, ref args) = expr.node { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - if name.node == "unwrap" { + if name.node.as_str() == "unwrap" { if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ @@ -54,7 +54,7 @@ impl LateLintPass for MethodsPass { of Err values is preferred"); } } - else if name.node == "to_string" { + else if name.node.as_str() == "to_string" { if obj_ty.sty == ty::TyStr { let mut arg_str = snippet(cx, args[0].span, "_"); if ptr_depth > 1 { @@ -82,7 +82,7 @@ impl LateLintPass for MethodsPass { for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { if_let_chain! { [ - name == method_name, + name.as_str() == method_name, sig.decl.inputs.len() == n_args, out_type.matches(&sig.decl.output), self_kind.matches(&sig.explicit_self.node, false) diff --git a/src/misc.rs b/src/misc.rs index 2dd396cb1c5..cf4504d2f67 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -94,7 +94,7 @@ impl LateLintPass for CmpNan { } fn check_nan(cx: &LateContext, path: &Path, span: Span) { - path.segments.last().map(|seg| if seg.identifier.name == "NAN" { + path.segments.last().map(|seg| if seg.identifier.name.as_str() == "NAN" { span_lint(cx, CMP_NAN, span, "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); }); @@ -124,9 +124,10 @@ impl LateLintPass for FloatCmp { return; } if let Some(name) = get_item_name(cx, expr) { + let name = name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || - name.as_str().starts_with("eq_") || - name.as_str().ends_with("_eq") { + name.starts_with("eq_") || + name.ends_with("_eq") { return; } } @@ -174,8 +175,8 @@ impl LateLintPass for CmpOwned { fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span) { match expr.node { ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) => { - if name == &"to_string" || - name == &"to_owned" && is_str_arg(cx, args) { + if name.as_str() == "to_string" || + name.as_str() == "to_owned" && is_str_arg(cx, args) { span_lint(cx, CMP_OWNED, expr.span, &format!( "this creates an owned instance just for comparison. \ Consider using `{}.as_slice()` to compare without allocation", diff --git a/src/ranges.rs b/src/ranges.rs index 94bbb34a421..2ef272237d1 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -22,7 +22,7 @@ impl LateLintPass for StepByZero { if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { // Only warn on literal ranges. - if name == &"step_by" && args.len() == 2 && + if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, "Range::step_by(0) produces an infinite iterator. \ diff --git a/src/utils.rs b/src/utils.rs index 250e24ac646..0dfc10b390a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -36,7 +36,7 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { opt_info.map_or(false, |info| { match info.callee.format { ExpnFormat::CompilerExpansion(..) => { - if info.callee.name() == "closure expansion" { + if info.callee.name().as_str() == "closure expansion" { return false; } }, @@ -66,7 +66,8 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| iter.zip(path).all(|(nm, p)| nm.name() == p)) + cx.tcx.with_path(def_id, |iter| iter.zip(path) + .all(|(nm, p)| nm.name().as_str() == *p)) } /// check if type is struct or enum type with given def path @@ -98,7 +99,7 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a, b)| &a.identifier.name == b) + |(a, b)| a.identifier.name.as_str() == *b) } /// get the name of the item the expression is in, if available -- cgit 1.4.1-3-g733a5 From e8f875813d75f5547c2e1e8b139c89a6275c0ccb Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 28 Sep 2015 07:11:03 +0200 Subject: all: remove trailing spaces --- src/len_zero.rs | 4 ++-- tests/compile-fail/bit_masks.rs | 2 +- tests/compile-fail/cast.rs | 4 ++-- tests/compile-fail/unicode.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) mode change 100644 => 100755 tests/compile-fail/cast.rs (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 2c85298201f..f5ad37a71be 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -95,8 +95,8 @@ fn is_self_sig(sig: &MethodSig) -> bool { false } else { sig.decl.inputs.len() == 1 } } -fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { - // check if we are in an is_empty() method +fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { + // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, left) { if name.as_str() == "is_empty" { return; } } diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index 0b7b31b64a5..f78012864a0 100755 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -27,7 +27,7 @@ fn main() { x & 192 == 128; // ok, tests for bit 7 and not bit 6 x & 0xffc0 == 0xfe80; // ok - + // this also now works with constants x & THREE_BITS == 8; //~ERROR incompatible bit mask x | EVEN_MORE_REDIRECTION < 7; //~ERROR incompatible bit mask diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs old mode 100644 new mode 100755 index b17f5de841b..70cc1919be4 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -45,7 +45,7 @@ fn main() { 1usize as f32; //~ERROR casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) 1isize as i32; //~ERROR casting isize to i32 may truncate the value on targets with 64-bit wide pointers 1isize as u32; //~ERROR casting isize to u32 may lose the sign of the value - //~^ERROR casting isize to u32 may truncate the value on targets with 64-bit wide pointers + //~^ERROR casting isize to u32 may truncate the value on targets with 64-bit wide pointers 1usize as u32; //~ERROR casting usize to u32 may truncate the value on targets with 64-bit wide pointers 1usize as i32; //~ERROR casting usize to i32 may truncate the value on targets with 64-bit wide pointers //~^ERROR casting usize to i32 may wrap around the value on targets with 32-bit wide pointers @@ -60,4 +60,4 @@ fn main() { 1u32 as usize; // Should not trigger any lint 1i32 as isize; // Neither should this 1i32 as usize; //~ERROR casting i32 to usize may lose the sign of the value -} \ No newline at end of file +} diff --git a/tests/compile-fail/unicode.rs b/tests/compile-fail/unicode.rs index 44bc9f1b199..e55a0390ff3 100755 --- a/tests/compile-fail/unicode.rs +++ b/tests/compile-fail/unicode.rs @@ -17,7 +17,7 @@ fn canon() { #[deny(non_ascii_literal)] fn uni() { print!("Üben!"); //~ERROR literal non-ASCII character detected - print!("\u{DC}ben!"); // this is okay + print!("\u{DC}ben!"); // this is okay } fn main() { -- cgit 1.4.1-3-g733a5 From b8cdefb6cfab11087943bb41824bb955c655daf1 Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Tue, 29 Sep 2015 13:11:19 +0200 Subject: Add unnecessary mut passed lint --- README.md | 3 ++- src/lib.rs | 3 +++ src/mut_reference.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/mut_reference.rs (limited to 'src') diff --git a/README.md b/README.md index e15ed7e8fce..427f4181dea 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 58 lints included in this crate: +There are 59 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -63,6 +63,7 @@ name [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function only demands an immutable reference [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention diff --git a/src/lib.rs b/src/lib.rs index 3c2d870aee2..2f71d8cc9df 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub mod eta_reduction; pub mod identity_op; pub mod minmax; pub mod mut_mut; +pub mod mut_reference; pub mod len_zero; pub mod attrs; pub mod collapsible_if; @@ -66,6 +67,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box identity_op::IdentityOp); reg.register_late_lint_pass(box mut_mut::MutMut); + reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); reg.register_late_lint_pass(box len_zero::LenZero); reg.register_late_lint_pass(box misc::CmpOwned); reg.register_late_lint_pass(box attrs::AttrPass); @@ -138,6 +140,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, + mut_reference::UNNECESSARY_MUT_PASSED, needless_bool::NEEDLESS_BOOL, precedence::PRECEDENCE, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/mut_reference.rs b/src/mut_reference.rs new file mode 100644 index 00000000000..13cf1e1301e --- /dev/null +++ b/src/mut_reference.rs @@ -0,0 +1,53 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::span_lint; +use rustc::middle::ty::{TypeAndMut, TypeVariants}; + +declare_lint! { + pub UNNECESSARY_MUT_PASSED, + Warn, + "an argument is passed as a mutable reference although the function only demands an \ + immutable reference" +} + + +#[derive(Copy,Clone)] +pub struct UnnecessaryMutPassed; + +impl LintPass for UnnecessaryMutPassed { + fn get_lints(&self) -> LintArray { + lint_array!(UNNECESSARY_MUT_PASSED) + } +} + +impl LateLintPass for UnnecessaryMutPassed { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let &ExprCall(ref fn_expr, ref arguments) = &e.node { + let borrowed_table = cx.tcx.tables.borrow(); + let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { + Some(funtion_type) => funtion_type, + None => unreachable!(), // A function with unknown type is called. + // If this happened the compiler would have aborted the + // compilation long ago. + }; + if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { + let parameters = b.sig.skip_binder().inputs.clone(); + for (argument, parameter) in arguments.iter().zip(parameters.iter()) { + match parameter.sty { + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + if let ExprPath(_, path) = fn_expr.node.clone() { + span_lint(cx, UNNECESSARY_MUT_PASSED, + argument.span, &format!("This argument of the \ + function \"{}\" doesn't need to be mutable", path)); + } + } + }, + _ => {} + } + } + } + } + } +} -- cgit 1.4.1-3-g733a5 From 40e180d8c777a7689b20033b9c9eba982a9cebda Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Tue, 29 Sep 2015 13:16:53 +0200 Subject: Replace tabs by spaces --- src/mut_reference.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 13cf1e1301e..96e78256f4e 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -23,28 +23,28 @@ impl LintPass for UnnecessaryMutPassed { impl LateLintPass for UnnecessaryMutPassed { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let &ExprCall(ref fn_expr, ref arguments) = &e.node { - let borrowed_table = cx.tcx.tables.borrow(); - let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { - Some(funtion_type) => funtion_type, - None => unreachable!(), // A function with unknown type is called. - // If this happened the compiler would have aborted the - // compilation long ago. - }; + let borrowed_table = cx.tcx.tables.borrow(); + let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { + Some(funtion_type) => funtion_type, + None => unreachable!(), // A function with unknown type is called. + // If this happened the compiler would have aborted the + // compilation long ago. + }; if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { let parameters = b.sig.skip_binder().inputs.clone(); for (argument, parameter) in arguments.iter().zip(parameters.iter()) { match parameter.sty { - TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | - TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { - if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { - if let ExprPath(_, path) = fn_expr.node.clone() { - span_lint(cx, UNNECESSARY_MUT_PASSED, + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + if let ExprPath(_, path) = fn_expr.node.clone() { + span_lint(cx, UNNECESSARY_MUT_PASSED, argument.span, &format!("This argument of the \ function \"{}\" doesn't need to be mutable", path)); - } - } - }, - _ => {} + } + } + }, + _ => {} } } } -- cgit 1.4.1-3-g733a5 From 185da552635321d51be06e66115199f11a586289 Mon Sep 17 00:00:00 2001 From: Ravi Shankar <wafflespeanut@gmail.com> Date: Sun, 27 Sep 2015 13:09:42 +0530 Subject: extending while_let to warn for more statements --- src/loops.rs | 67 ++++++++++++++++++++++++++++++++-------- src/matches.rs | 2 +- src/utils.rs | 12 +++++-- tests/compile-fail/while_loop.rs | 16 +++------- 4 files changed, 69 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 4afa31ff515..b48ae13e73a 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -6,6 +6,7 @@ use rustc::middle::ty; use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; use rustc::front::map::Node::{NodeBlock}; +use std::borrow::Cow; use std::collections::{HashSet,HashMap}; use syntax::ast::Lit_::*; @@ -159,10 +160,27 @@ impl LateLintPass for LoopsPass { } } // check for `loop { if let {} else break }` that could be `while let` - // (also matches explicit "match" instead of "if let") + // (also matches an explicit "match" instead of "if let") + // (even if the "match" or "if let" is used for declaration) if let ExprLoop(ref block, _) = expr.node { + // extract the first statement (if any) in a block + let inner_stmt = extract_expr_from_first_stmt(block); // extract a single expression - if let Some(inner) = extract_single_expr(block) { + let inner_expr = extract_first_expr(block); + let extracted = match inner_stmt { + Some(_) => inner_stmt, + None => inner_expr, + }; + + if let Some(inner) = extracted { + // collect remaining expressions below the match + let other_stuff = block.stmts + .iter() + .skip(1) + .map(|stmt| { + format!("{}", snippet(cx, stmt.span, "..")) + }).collect::<Vec<String>>(); + if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // ensure "if let" compatible match structure match *source { @@ -174,12 +192,19 @@ impl LateLintPass for LoopsPass { is_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { return; } + let loop_body = match inner_stmt { + // FIXME: should probably be an ellipsis + // tabbing and newline is probably a bad idea, especially for large blocks + Some(_) => Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))), + None => expr_block(cx, &arms[0].body, + Some(other_stuff.join("\n ")), ".."), + }; span_help_and_lint(cx, WHILE_LET_LOOP, expr.span, "this loop could be written as a `while let` loop", &format!("try\nwhile let {} = {} {}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, matchexpr.span, ".."), - expr_block(cx, &arms[0].body, ".."))); + loop_body)); }, _ => () } @@ -276,23 +301,38 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { } fn is_iterable_array(ty: ty::Ty) -> bool { - //IntoIterator is currently only implemented for array sizes <= 32 in rustc + // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { ty::TyArray(_, 0...32) => true, _ => false } } -/// If block consists of a single expression (with or without semicolon), return it. -fn extract_single_expr(block: &Block) -> Option<&Expr> { - match (&block.stmts.len(), &block.expr) { - (&1, &None) => match block.stmts[0].node { - StmtExpr(ref expr, _) | - StmtSemi(ref expr, _) => Some(expr), +/// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. +fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { + match block.expr { + Some(_) => None, + None => match block.stmts[0].node { + StmtDecl(ref decl, _) => match decl.node { + DeclLocal(ref local) => match local.init { + Some(ref expr) => Some(expr), + None => None, + }, + _ => None, + }, + _ => None, + }, + } +} + +/// If a block begins with an expression (with or without semicolon), return it. +fn extract_first_expr(block: &Block) -> Option<&Expr> { + match block.expr { + Some(ref expr) => Some(expr), + None => match block.stmts[0].node { + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), _ => None, }, - (&0, &Some(ref expr)) => Some(expr), - _ => None } } @@ -300,7 +340,8 @@ fn extract_single_expr(block: &Block) -> Option<&Expr> { fn is_break_expr(expr: &Expr) -> bool { match expr.node { ExprBreak(None) => true, - ExprBlock(ref b) => match extract_single_expr(b) { + // there won't be a `let <pat> = break` and so we can safely ignore the StmtDecl case + ExprBlock(ref b) => match extract_first_expr(b) { Some(ref subexpr) => is_break_expr(subexpr), None => false, }, diff --git a/src/matches.rs b/src/matches.rs index 4e49cd3ff73..e935a6aa6e1 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -43,7 +43,7 @@ impl LateLintPass for MatchPass { &format!("try\nif let {} = {} {}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, ".."))); + expr_block(cx, &arms[0].body, None, ".."))); } // check preconditions for MATCH_REF_PATS diff --git a/src/utils.rs b/src/utils.rs index 250e24ac646..09924d902d3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -130,12 +130,18 @@ pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) - } /// Like snippet_block, but add braces if the expr is not an ExprBlock -pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, default: &'a str) -> Cow<'a, str> { +/// Also takes an Option<String> which can be put inside the braces +pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, + option: Option<String>, + default: &'a str) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); + let string = option.map_or("".to_owned(), |s| s); if let ExprBlock(_) = expr.node { - code - } else { + Cow::Owned(format!("{}{}", code, string)) + } else if string.is_empty() { Cow::Owned(format!("{{ {} }}", code)) + } else { + Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) } } diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index bc09168fad0..ef798b2a79e 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -4,13 +4,6 @@ #[deny(while_let_loop)] fn main() { let y = Some(true); - loop { //~ERROR - if let Some(_x) = y { - let _v = 1; - } else { - break; - } - } loop { //~ERROR if let Some(_x) = y { let _v = 1; @@ -30,12 +23,13 @@ fn main() { None => break }; } - loop { // no error, match is not the only statement - match y { - Some(_x) => true, + loop { //~ERROR + let x = match y { + Some(x) => x, None => break }; - let _x = 1; + let _x = x; + let _str = "foo"; } loop { // no error, else branch does something other than break match y { -- cgit 1.4.1-3-g733a5 From e2a6c9e375c1d160133aadb202a948245e73e750 Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Tue, 29 Sep 2015 18:43:38 +0200 Subject: Add unnecessary mut passed lint for methods --- src/mut_reference.rs | 76 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 96e78256f4e..16973ea987a 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -1,12 +1,12 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::span_lint; -use rustc::middle::ty::{TypeAndMut, TypeVariants}; +use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall}; declare_lint! { pub UNNECESSARY_MUT_PASSED, Warn, - "an argument is passed as a mutable reference although the function only demands an \ + "an argument is passed as a mutable reference although the function/method only demands an \ immutable reference" } @@ -22,32 +22,62 @@ impl LintPass for UnnecessaryMutPassed { impl LateLintPass for UnnecessaryMutPassed { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let &ExprCall(ref fn_expr, ref arguments) = &e.node { - let borrowed_table = cx.tcx.tables.borrow(); - let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { - Some(funtion_type) => funtion_type, - None => unreachable!(), // A function with unknown type is called. - // If this happened the compiler would have aborted the - // compilation long ago. - }; - if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { - let parameters = b.sig.skip_binder().inputs.clone(); - for (argument, parameter) in arguments.iter().zip(parameters.iter()) { - match parameter.sty { - TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | - TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { - if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { - if let ExprPath(_, path) = fn_expr.node.clone() { + match e.node { + ExprCall(ref fn_expr, ref arguments) => { + let borrowed_table = cx.tcx.tables.borrow(); + let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { + Some(funtion_type) => funtion_type, + None => unreachable!(), // A function with unknown type is called. + // If this happened the compiler would have aborted the + // compilation long ago. + }; + if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { + let parameters = b.sig.skip_binder().inputs.clone(); + for (argument, parameter) in arguments.iter().zip(parameters.iter()) { + match parameter.sty { + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + if let ExprPath(_, path) = fn_expr.node.clone() { + span_lint(cx, UNNECESSARY_MUT_PASSED, + argument.span, &format!("This argument of the \ + function \"{}\" doesn't need to be mutable", path)); + } + } + }, + _ => {} + } + } + } + }, + ExprMethodCall(ref name, _, ref arguments) => { + let method_call = MethodCall::expr(e.id); + let borrowed_table = cx.tcx.tables.borrow(); + let method_type = match borrowed_table.method_map.get(&method_call) { + Some(method_type) => method_type, + None => unreachable!(), // Just like above, this should never happen. + }; + if let TypeVariants::TyBareFn(_, ref b) = method_type.ty.sty { + let parameters = b.sig.skip_binder().inputs.iter().clone(); + for (argument, parameter) in arguments.iter().zip(parameters).skip(1) { + // Skip the first argument and the first parameter because it is the + // struct the function is called on. + match parameter.sty { + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { span_lint(cx, UNNECESSARY_MUT_PASSED, argument.span, &format!("This argument of the \ - function \"{}\" doesn't need to be mutable", path)); + method \"{}\" doesn't need to be mutable", + name.node.as_str())); } - } - }, - _ => {} + }, + _ => {} + } } } - } + }, + _ => {} } } } -- cgit 1.4.1-3-g733a5 From 33a0799fa9777a4e2735faa8c4d6595db5cb6179 Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Wed, 30 Sep 2015 13:08:29 +0200 Subject: Remove unnecessary clones and add helper function --- src/mut_reference.rs | 79 +++++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 16973ea987a..1cc04e096ba 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -1,7 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::span_lint; -use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall}; +use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; +use syntax::ptr::P; declare_lint! { pub UNNECESSARY_MUT_PASSED, @@ -22,62 +23,52 @@ impl LintPass for UnnecessaryMutPassed { impl LateLintPass for UnnecessaryMutPassed { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + let borrowed_table = cx.tcx.tables.borrow(); match e.node { ExprCall(ref fn_expr, ref arguments) => { - let borrowed_table = cx.tcx.tables.borrow(); - let funtion_type = match borrowed_table.node_types.get(&fn_expr.id) { - Some(funtion_type) => funtion_type, + match borrowed_table.node_types.get(&fn_expr.id) { + Some(function_type) => { + if let ExprPath(_, ref path) = fn_expr.node { + check_arguments(cx, &arguments, function_type, + &format!("{}", path)); + } + }, None => unreachable!(), // A function with unknown type is called. // If this happened the compiler would have aborted the // compilation long ago. }; - if let TypeVariants::TyBareFn(_, ref b) = funtion_type.sty { - let parameters = b.sig.skip_binder().inputs.clone(); - for (argument, parameter) in arguments.iter().zip(parameters.iter()) { - match parameter.sty { - TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | - TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { - if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { - if let ExprPath(_, path) = fn_expr.node.clone() { - span_lint(cx, UNNECESSARY_MUT_PASSED, - argument.span, &format!("This argument of the \ - function \"{}\" doesn't need to be mutable", path)); - } - } - }, - _ => {} - } - } - } + + }, ExprMethodCall(ref name, _, ref arguments) => { let method_call = MethodCall::expr(e.id); - let borrowed_table = cx.tcx.tables.borrow(); - let method_type = match borrowed_table.method_map.get(&method_call) { - Some(method_type) => method_type, + match borrowed_table.method_map.get(&method_call) { + Some(method_type) => check_arguments(cx, &arguments, method_type.ty, + &format!("{}", name.node.as_str())), None => unreachable!(), // Just like above, this should never happen. }; - if let TypeVariants::TyBareFn(_, ref b) = method_type.ty.sty { - let parameters = b.sig.skip_binder().inputs.iter().clone(); - for (argument, parameter) in arguments.iter().zip(parameters).skip(1) { - // Skip the first argument and the first parameter because it is the - // struct the function is called on. - match parameter.sty { - TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | - TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { - if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, UNNECESSARY_MUT_PASSED, - argument.span, &format!("This argument of the \ - method \"{}\" doesn't need to be mutable", - name.node.as_str())); - } - }, - _ => {} - } - } - } }, _ => {} } } } + +fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) { + if let TypeVariants::TyBareFn(_, ref fn_type) = type_definition.sty { + let parameters = &fn_type.sig.skip_binder().inputs; + for (argument, parameter) in arguments.iter().zip(parameters.iter()) { + match parameter.sty { + TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | + TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + span_lint(cx, UNNECESSARY_MUT_PASSED, + argument.span, &format!("The function/method \"{}\" \ + doesn't need a mutable reference", + name)); + } + }, + _ => {} + } + } + } +} -- cgit 1.4.1-3-g733a5 From 4fc17e7fafcc59223fd9047b18829e052e074226 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 30 Sep 2015 19:54:41 +0530 Subject: rustup to rustc 1.5.0-nightly (65d5c0833 2015-09-29) --- src/lifetimes.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index b64fa148ef3..e39a41316a0 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -177,18 +177,10 @@ impl RefVisitor { } impl<'v> Visitor<'v> for RefVisitor { - // for lifetimes of references - fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) { - self.record(lifetime); - } - // for lifetimes as parameters of generics - fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.record(&Some(*lifetime)); } - - // for lifetime bounds; the default impl calls visit_lifetime_ref - fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { } } /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to -- cgit 1.4.1-3-g733a5 From f76f4d52c261eaaa94028b2c864a405affeb2f6a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 30 Sep 2015 20:10:54 +0530 Subject: Fix rustup fallout: lifetimes false positives --- src/lifetimes.rs | 10 ++++++++++ tests/compile-fail/lifetimes.rs | 4 ++++ 2 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index e39a41316a0..206424de9b5 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -89,6 +89,9 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, // extract lifetimes in input argument types for arg in &func.inputs { walk_ty(&mut input_visitor, &arg.ty); + if let TyRptr(None, _) = arg.ty.node { + input_visitor.record(&None); + } } // extract lifetimes in output type if let Return(ref ty) = func.output { @@ -181,6 +184,13 @@ impl<'v> Visitor<'v> for RefVisitor { fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.record(&Some(*lifetime)); } + + fn visit_ty(&mut self, ty: &'v Ty) { + if let TyRptr(None, _) = ty.node { + self.record(&None); + } + walk_ty(self, ty); + } } /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 0b24ca65241..a654c452379 100755 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -81,5 +81,9 @@ impl<'a> Foo<'a> { fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist } +fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 { + unimplemented!() +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 431c3918189f845d3a57f0290857971ee03a7d33 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 2 Oct 2015 13:25:34 +0530 Subject: Fix a panic caused by while let --- src/loops.rs | 6 ++++-- tests/compile-fail/while_loop.rs | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 23be0ce728f..2069a56f78f 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -312,7 +312,7 @@ fn is_iterable_array(ty: ty::Ty) -> bool { fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { match block.expr { Some(_) => None, - None => match block.stmts[0].node { + None if !block.stmts.is_empty() => match block.stmts[0].node { StmtDecl(ref decl, _) => match decl.node { DeclLocal(ref local) => match local.init { Some(ref expr) => Some(expr), @@ -322,6 +322,7 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { }, _ => None, }, + _ => None, } } @@ -329,10 +330,11 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { fn extract_first_expr(block: &Block) -> Option<&Expr> { match block.expr { Some(ref expr) => Some(expr), - None => match block.stmts[0].node { + None if !block.stmts.is_empty() => match block.stmts[0].node { StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), _ => None, }, + _ => None, } } diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index ef798b2a79e..eca2c7e12ae 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -1,7 +1,9 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(while_let_loop)] +#![deny(while_let_loop)] +#![allow(dead_code, unused)] + fn main() { let y = Some(true); loop { //~ERROR @@ -44,3 +46,18 @@ fn main() { println!("{}", x); } } + +// regression test (#360) +// this should not panic +// it's okay if further iterations of the lint +// cause this function to trigger it +fn no_panic<T>(slice: &[T]) { + let mut iter = slice.iter(); + loop { + let _ = match iter.next() { + Some(ele) => ele, + None => break + }; + loop {} + } +} -- cgit 1.4.1-3-g733a5 From 846602a87680089c0cda6e4c21d1181205b9d4aa Mon Sep 17 00:00:00 2001 From: Josh Stone <cuviper@gmail.com> Date: Fri, 2 Oct 2015 11:07:56 -0700 Subject: Update the DefLocal pattern DefLocal now contains a DefId too, since rust-lang/rust@a0dc2d9a29218. --- src/loops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 2069a56f78f..ee978932d09 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -501,7 +501,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { - if let DefLocal(node_id) = path_res.base_def { + if let DefLocal(_, node_id) = path_res.base_def { return Some(node_id) } } -- cgit 1.4.1-3-g733a5 From 85ac8343431ef693ca07dcbce1e73f17f4c5ec7d Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 5 Oct 2015 22:02:05 +0200 Subject: RingBuf was renamed to VecDeque (fixes #363) --- README.md | 2 +- src/types.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index e15ed7e8fce..2147530ff57 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ name [len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead [let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a RingBuf +[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 diff --git a/src/types.rs b/src/types.rs index dd41b4f2239..e9125085bb5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -20,7 +20,7 @@ declare_lint!(pub BOX_VEC, Warn, "usage of `Box<Vec<T>>`, vector elements are already on the heap"); declare_lint!(pub LINKEDLIST, Warn, "usage of LinkedList, usually a vector is faster, or a more specialized data \ - structure like a RingBuf"); + structure like a VecDeque"); impl LintPass for TypePass { fn get_lints(&self) -> LintArray { @@ -43,7 +43,7 @@ impl LateLintPass for TypePass { span_help_and_lint( cx, LINKEDLIST, ast_ty.span, "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "a RingBuf might work"); + "a VecDeque might work"); } } } -- cgit 1.4.1-3-g733a5 From f8aa0431bdea0b5adb8a53a7a8eb32b091759561 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 7 Oct 2015 01:17:57 +0200 Subject: Suggest using an atomic value instead of a Mutex where possible --- README.md | 3 ++- src/lib.rs | 3 +++ src/mutex_atomic.rs | 51 ++++++++++++++++++++++++++++++++++++++ src/utils.rs | 1 + tests/compile-fail/mutex_atomic.rs | 15 +++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/mutex_atomic.rs create mode 100644 tests/compile-fail/mutex_atomic.rs (limited to 'src') diff --git a/README.md b/README.md index a5ab856fc21..a09a9fefc35 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 59 lints included in this crate: +There are 60 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -37,6 +37,7 @@ name [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead [needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` [needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do diff --git a/src/lib.rs b/src/lib.rs index 2f71d8cc9df..0e560978979 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub mod loops; pub mod ranges; pub mod matches; pub mod precedence; +pub mod mutex_atomic; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -88,6 +89,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box matches::MatchPass); reg.register_late_lint_pass(box misc::PatternPass); reg.register_late_lint_pass(box minmax::MinMaxPass); + reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -141,6 +143,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, mut_reference::UNNECESSARY_MUT_PASSED, + mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, precedence::PRECEDENCE, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs new file mode 100644 index 00000000000..6cf71fe23bc --- /dev/null +++ b/src/mutex_atomic.rs @@ -0,0 +1,51 @@ +//! Checks for uses of Mutex where an atomic value could be used +//! +//! This lint is **warn** by default + +use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; +use rustc_front::hir::Expr; + +use syntax::ast; +use rustc::middle::ty; +use rustc::middle::subst::ParamSpace; + +use utils::{span_lint, MUTEX_PATH, match_type}; + +declare_lint! { + pub MUTEX_ATOMIC, + Warn, + "using a Mutex where an atomic value could be used instead" +} + +impl LintPass for MutexAtomic { + fn get_lints(&self) -> LintArray { + lint_array!(MUTEX_ATOMIC) + } +} +pub struct MutexAtomic; + +impl LateLintPass for MutexAtomic { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + let ty = cx.tcx.expr_ty(expr); + if let &ty::TyStruct(_, subst) = &ty.sty { + if match_type(cx, ty, &MUTEX_PATH) { + let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; + if let Some(atomic_name) = get_atomic_name(mutex_param) { + let msg = format!("Consider using an {} instead of a \ + Mutex here.", atomic_name); + span_lint(cx, MUTEX_ATOMIC, expr.span, &msg); + } + } + } + } +} + +fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> { + match *ty { + ty::TyBool => Some("AtomicBool"), + ty::TyUint(ast::TyUs) => Some("AtomicUsize"), + ty::TyInt(ast::TyIs) => Some("AtomicIsize"), + ty::TyRawPtr(_) => Some("AtomicPtr"), + _ => None + } +} diff --git a/src/utils.rs b/src/utils.rs index ac155617011..4c9f1fb4b3e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -14,6 +14,7 @@ pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; /// returns true this expn_info was expanded by any macro pub fn in_macro(cx: &LateContext, span: Span) -> bool { diff --git a/tests/compile-fail/mutex_atomic.rs b/tests/compile-fail/mutex_atomic.rs new file mode 100644 index 00000000000..97e08d7ba36 --- /dev/null +++ b/tests/compile-fail/mutex_atomic.rs @@ -0,0 +1,15 @@ +#![feature(plugin)] + +#![plugin(clippy)] +#![deny(clippy)] + +fn main() { + use std::sync::Mutex; + Mutex::new(true); //~ERROR Consider using an AtomicBool instead of a Mutex here. + Mutex::new(5usize); //~ERROR Consider using an AtomicUsize instead of a Mutex here. + Mutex::new(9isize); //~ERROR Consider using an AtomicIsize instead of a Mutex here. + let mut x = 4u32; + Mutex::new(&x as *const u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here. + Mutex::new(&mut x as *mut u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here. + Mutex::new(0f32); // there are no float atomics, so this should not lint +} -- cgit 1.4.1-3-g733a5 From 7644f8e2a1774c426f520efc50fe3626b31e028c Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Wed, 7 Oct 2015 13:15:14 +0200 Subject: Add "nonsensical OpenOptions" lint --- README.md | 3 +- src/lib.rs | 3 + src/open_options.rs | 139 +++++++++++++++++++++++++++++++++++++ src/utils.rs | 11 +-- tests/compile-fail/open_options.rs | 16 +++++ 5 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 src/open_options.rs create mode 100644 tests/compile-fail/open_options.rs (limited to 'src') diff --git a/README.md b/README.md index a5ab856fc21..96465d9fd35 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 59 lints included in this crate: +There are 60 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -42,6 +42,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | The options used for opening a file are nonsensical [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively diff --git a/src/lib.rs b/src/lib.rs index 2f71d8cc9df..44f8e9e5b98 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub mod loops; pub mod ranges; pub mod matches; pub mod precedence; +pub mod open_options; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -88,6 +89,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box matches::MatchPass); reg.register_late_lint_pass(box misc::PatternPass); reg.register_late_lint_pass(box minmax::MinMaxPass); + reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -142,6 +144,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::TOPLEVEL_REF_ARG, mut_reference::UNNECESSARY_MUT_PASSED, needless_bool::NEEDLESS_BOOL, + open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, diff --git a/src/open_options.rs b/src/open_options.rs new file mode 100644 index 00000000000..d91305c36c2 --- /dev/null +++ b/src/open_options.rs @@ -0,0 +1,139 @@ +use rustc::lint::*; +use rustc_front::hir::{Expr, ExprMethodCall, ExprLit}; +use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; +use syntax::codemap::{Span, Spanned}; +use syntax::ast::Lit_::LitBool; + +declare_lint! { + pub NONSENSICAL_OPEN_OPTIONS, + Warn, + "The options used for opening a file are nonsensical" +} + + +#[derive(Copy,Clone)] +pub struct NonSensicalOpenOptions; + +impl LintPass for NonSensicalOpenOptions { + fn get_lints(&self) -> LintArray { + lint_array!(NONSENSICAL_OPEN_OPTIONS) + } +} + +impl LateLintPass for NonSensicalOpenOptions { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprMethodCall(ref name, _, ref arguments) = e.node { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); + if name.node.as_str() == "open" && match_type(cx, obj_ty, &OPEN_OPTIONS_PATH){ + let mut options = Vec::new(); + get_open_options(cx, &arguments[0], &mut options); + check_open_options(cx, &options, e.span); + } + } + } +} + +#[derive(Debug)] +enum Argument { + True, + False, + Unknown +} + +#[derive(Debug)] +enum OpenOption { + Write(Argument), + Read(Argument), + Truncate(Argument), + Create(Argument), + Append(Argument) +} + +fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<OpenOption>) { + if let ExprMethodCall(ref name, _, ref arguments) = argument.node { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); + + // Only proceed if this is a call on some object of type std::fs::OpenOptions + if match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) && arguments.len() >= 2 { + + let argument_option = match arguments[1].node { + ExprLit(ref span) => { + if let Spanned {node: LitBool(lit), span: _} = **span { + 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)); + }, + _ => {} + } + + get_open_options(cx, &arguments[0], options); + } + } +} + +fn check_for_duplicates(cx: &LateContext, options: &[OpenOption], span: Span) { + // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. + if options.iter().filter(|o| if let OpenOption::Create(_) = **o {true} else {false}).count() > 1 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"create\" \ + is called more than once"); + } + if options.iter().filter(|o| if let OpenOption::Append(_) = **o {true} else {false}).count() > 1 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"append\" \ + is called more than once"); + } + if options.iter().filter(|o| if let OpenOption::Truncate(_) = **o {true} else {false}).count() > 1 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"truncate\" \ + is called more than once"); + } + if options.iter().filter(|o| if let OpenOption::Read(_) = **o {true} else {false}).count() > 1 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"read\" \ + is called more than once"); + } + if options.iter().filter(|o| if let OpenOption::Write(_) = **o {true} else {false}).count() > 1 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"write\" \ + is called more than once"); + } +} + +fn check_for_inconsistencies(cx: &LateContext, options: &[OpenOption], span: Span) { + // Truncate + read makes no sense. + if options.iter().filter(|o| if let OpenOption::Read(Argument::True) = **o {true} else {false}).count() > 0 && + options.iter().filter(|o| if let OpenOption::Truncate(Argument::True) = **o {true} else {false}).count() > 0 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"truncate\" and \"read\""); + } + + // Append + truncate makes no sense. + if options.iter().filter(|o| if let OpenOption::Append(Argument::True) = **o {true} else {false}).count() > 0 && + options.iter().filter(|o| if let OpenOption::Truncate(Argument::True) = **o {true} else {false}).count() > 0 { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"append\" and \"truncate\""); + } +} + +fn check_open_options(cx: &LateContext, options: &[OpenOption], span: Span) { + check_for_duplicates(cx, options, span); + check_for_inconsistencies(cx, options, span); +} diff --git a/src/utils.rs b/src/utils.rs index ac155617011..1f4fb2b251d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,11 +9,12 @@ use std::borrow::Cow; use syntax::ast::Lit_::*; // module DefPaths for certain structs/enums we check for -pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; -pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; -pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; /// returns true this expn_info was expanded by any macro pub fn in_macro(cx: &LateContext, span: Span) -> bool { diff --git a/tests/compile-fail/open_options.rs b/tests/compile-fail/open_options.rs new file mode 100644 index 00000000000..35cc91c9d0f --- /dev/null +++ b/tests/compile-fail/open_options.rs @@ -0,0 +1,16 @@ +#![feature(plugin)] +#![plugin(clippy)] +use std::fs::OpenOptions; + +#[allow(unused_must_use)] +#[deny(nonsensical_open_options)] +fn main() { + OpenOptions::new().read(true).truncate(true).open("foo.txt"); //~ERROR File opened with "truncate" and "read" + OpenOptions::new().append(true).truncate(true).open("foo.txt"); //~ERROR File opened with "append" and "truncate" + + OpenOptions::new().read(true).read(false).open("foo.txt"); //~ERROR The method "read" is called more than once + OpenOptions::new().create(true).create(false).open("foo.txt"); //~ERROR The method "create" is called more than once + OpenOptions::new().write(true).write(false).open("foo.txt"); //~ERROR The method "write" is called more than once + OpenOptions::new().append(true).append(false).open("foo.txt"); //~ERROR The method "append" is called more than once + OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); //~ERROR The method "truncate" is called more than once +} -- cgit 1.4.1-3-g733a5 From b7c6c30c8835254e2cb7c5fada886ffa7685bbd4 Mon Sep 17 00:00:00 2001 From: Pyriphlegethon <pyriphlegethon.github@gmail.com> Date: Wed, 7 Oct 2015 17:15:44 +0200 Subject: Change lint description --- README.md | 2 +- src/open_options.rs | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 96465d9fd35..6c6849ba105 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | The options used for opening a file are nonsensical +[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively diff --git a/src/open_options.rs b/src/open_options.rs index d91305c36c2..76a2eeef1ba 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -7,7 +7,7 @@ use syntax::ast::Lit_::LitBool; declare_lint! { pub NONSENSICAL_OPEN_OPTIONS, Warn, - "The options used for opening a file are nonsensical" + "nonsensical combination of options for opening a file" } @@ -42,14 +42,14 @@ enum Argument { #[derive(Debug)] enum OpenOption { - Write(Argument), - Read(Argument), - Truncate(Argument), - Create(Argument), - Append(Argument) + Write, + Read, + Truncate, + Create, + Append } -fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<OpenOption>) { +fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { if let ExprMethodCall(ref name, _, ref arguments) = argument.node { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); @@ -73,19 +73,19 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<OpenOpt match &*name.node.as_str() { "create" => { - options.push(OpenOption::Create(argument_option)); + options.push((OpenOption::Create, argument_option)); }, "append" => { - options.push(OpenOption::Append(argument_option)); + options.push((OpenOption::Append, argument_option)); }, "truncate" => { - options.push(OpenOption::Truncate(argument_option)); + options.push((OpenOption::Truncate, argument_option)); }, "read" => { - options.push(OpenOption::Read(argument_option)); + options.push((OpenOption::Read, argument_option)); }, "write" => { - options.push(OpenOption::Write(argument_option)); + options.push((OpenOption::Write, argument_option)); }, _ => {} } @@ -95,45 +95,45 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<OpenOpt } } -fn check_for_duplicates(cx: &LateContext, options: &[OpenOption], span: Span) { +fn check_for_duplicates(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. - if options.iter().filter(|o| if let OpenOption::Create(_) = **o {true} else {false}).count() > 1 { + if options.iter().filter(|o| if let (OpenOption::Create, _) = **o {true} else {false}).count() > 1 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"create\" \ is called more than once"); } - if options.iter().filter(|o| if let OpenOption::Append(_) = **o {true} else {false}).count() > 1 { + if options.iter().filter(|o| if let (OpenOption::Append, _) = **o {true} else {false}).count() > 1 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"append\" \ is called more than once"); } - if options.iter().filter(|o| if let OpenOption::Truncate(_) = **o {true} else {false}).count() > 1 { + if options.iter().filter(|o| if let (OpenOption::Truncate, _) = **o {true} else {false}).count() > 1 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"truncate\" \ is called more than once"); } - if options.iter().filter(|o| if let OpenOption::Read(_) = **o {true} else {false}).count() > 1 { + if options.iter().filter(|o| if let (OpenOption::Read, _) = **o {true} else {false}).count() > 1 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"read\" \ is called more than once"); } - if options.iter().filter(|o| if let OpenOption::Write(_) = **o {true} else {false}).count() > 1 { + if options.iter().filter(|o| if let (OpenOption::Write, _) = **o {true} else {false}).count() > 1 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"write\" \ is called more than once"); } } -fn check_for_inconsistencies(cx: &LateContext, options: &[OpenOption], span: Span) { +fn check_for_inconsistencies(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { // Truncate + read makes no sense. - if options.iter().filter(|o| if let OpenOption::Read(Argument::True) = **o {true} else {false}).count() > 0 && - options.iter().filter(|o| if let OpenOption::Truncate(Argument::True) = **o {true} else {false}).count() > 0 { + if options.iter().filter(|o| if let (OpenOption::Read, Argument::True) = **o {true} else {false}).count() > 0 && + options.iter().filter(|o| if let (OpenOption::Truncate, Argument::True) = **o {true} else {false}).count() > 0 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"truncate\" and \"read\""); } // Append + truncate makes no sense. - if options.iter().filter(|o| if let OpenOption::Append(Argument::True) = **o {true} else {false}).count() > 0 && - options.iter().filter(|o| if let OpenOption::Truncate(Argument::True) = **o {true} else {false}).count() > 0 { + if options.iter().filter(|o| if let (OpenOption::Append, Argument::True) = **o {true} else {false}).count() > 0 && + options.iter().filter(|o| if let (OpenOption::Truncate, Argument::True) = **o {true} else {false}).count() > 0 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"append\" and \"truncate\""); } } -fn check_open_options(cx: &LateContext, options: &[OpenOption], span: Span) { +fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { check_for_duplicates(cx, options, span); check_for_inconsistencies(cx, options, span); } -- cgit 1.4.1-3-g733a5 From 26b2733b15a0011ff1569e059ae7520d1a3a519d Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 7 Oct 2015 22:58:34 +0200 Subject: Add a lint for sized integer types in a mutex --- README.md | 3 ++- src/lib.rs | 1 + src/mutex_atomic.rs | 21 +++++++++++++++++---- tests/compile-fail/mutex_atomic.rs | 3 +++ 4 files changed, 23 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index a09a9fefc35..50789cc3db2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 60 lints included in this crate: +There are 61 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -38,6 +38,7 @@ name [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) [mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead +[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type [needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` [needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do diff --git a/src/lib.rs b/src/lib.rs index 0e560978979..3483efea868 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, mut_mut::MUT_MUT, + mutex_atomic::MUTEX_INTEGER, ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 6cf71fe23bc..994e7937984 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -17,11 +17,18 @@ declare_lint! { "using a Mutex where an atomic value could be used instead" } +declare_lint! { + pub MUTEX_INTEGER, + Allow, + "using a Mutex for an integer type" +} + impl LintPass for MutexAtomic { fn get_lints(&self) -> LintArray { - lint_array!(MUTEX_ATOMIC) + lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER) } } + pub struct MutexAtomic; impl LateLintPass for MutexAtomic { @@ -33,7 +40,13 @@ impl LateLintPass for MutexAtomic { if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!("Consider using an {} instead of a \ Mutex here.", atomic_name); - span_lint(cx, MUTEX_ATOMIC, expr.span, &msg); + match *mutex_param { + ty::TyUint(t) if t != ast::TyUs => + span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + ty::TyInt(t) if t != ast::TyIs => + span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg) + } } } } @@ -43,8 +56,8 @@ impl LateLintPass for MutexAtomic { fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> { match *ty { ty::TyBool => Some("AtomicBool"), - ty::TyUint(ast::TyUs) => Some("AtomicUsize"), - ty::TyInt(ast::TyIs) => Some("AtomicIsize"), + ty::TyUint(_) => Some("AtomicUsize"), + ty::TyInt(_) => Some("AtomicIsize"), ty::TyRawPtr(_) => Some("AtomicPtr"), _ => None } diff --git a/tests/compile-fail/mutex_atomic.rs b/tests/compile-fail/mutex_atomic.rs index 97e08d7ba36..20a34ba5547 100644 --- a/tests/compile-fail/mutex_atomic.rs +++ b/tests/compile-fail/mutex_atomic.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(clippy)] +#![deny(mutex_integer)] fn main() { use std::sync::Mutex; @@ -11,5 +12,7 @@ fn main() { let mut x = 4u32; Mutex::new(&x as *const u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here. Mutex::new(&mut x as *mut u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here. + Mutex::new(0u32); //~ERROR Consider using an AtomicUsize instead of a Mutex here. + Mutex::new(0i32); //~ERROR Consider using an AtomicIsize instead of a Mutex here. Mutex::new(0f32); // there are no float atomics, so this should not lint } -- cgit 1.4.1-3-g733a5 From 6b7fff93bc343027b601d3abfe6e1435447ade23 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 8 Oct 2015 00:35:32 +0200 Subject: Fix documentation that disagrees with code --- src/ptr_arg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 7c369469ea2..be11ebce26a 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -1,6 +1,6 @@ //! Checks for usage of &Vec[_] and &String //! -//! This lint is **warn** by default +//! This lint is **allow** by default use rustc::lint::*; use rustc_front::hir::*; -- cgit 1.4.1-3-g733a5 From b48db27152caf31c892312bc8a8ea8db7418e157 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Sun, 11 Oct 2015 16:07:00 +0200 Subject: Recommend using Mutex<()> for locking --- src/mutex_atomic.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 994e7937984..9c10a062419 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -39,7 +39,10 @@ impl LateLintPass for MutexAtomic { let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!("Consider using an {} instead of a \ - Mutex here.", atomic_name); + Mutex here. If you just want the \ + locking behaviour and not the internal \ + type, consider using Mutex<()>.", + atomic_name); match *mutex_param { ty::TyUint(t) if t != ast::TyUs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), -- cgit 1.4.1-3-g733a5 From 4e2b09831bd67ad52954d5cfb48eae066b3d4c00 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 12 Oct 2015 02:42:21 +0530 Subject: Rust upgrade to rustc 1.5.0-nightly (9d3e79ad3 2015-10-10) --- src/lib.rs | 2 +- src/returns.rs | 28 ++++----- src/shadow.rs | 3 +- src/types.rs | 10 +-- src/utils.rs | 139 +++++++++++++++++++++++------------------- tests/compile-fail/strings.rs | 6 +- 6 files changed, 102 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 2f71d8cc9df..6503c5e1006 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box misc::ModuloOne); reg.register_late_lint_pass(box unicode::Unicode); reg.register_late_lint_pass(box strings::StringAdd); - reg.register_late_lint_pass(box returns::ReturnPass); + reg.register_early_lint_pass(box returns::ReturnPass); reg.register_late_lint_pass(box methods::MethodsPass); reg.register_late_lint_pass(box shadow::ShadowPass); reg.register_late_lint_pass(box types::LetPass); diff --git a/src/returns.rs b/src/returns.rs index d04307ffd5d..3df4efd0889 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,10 +1,10 @@ use rustc::lint::*; -use rustc_front::hir::*; -use reexport::*; +use syntax::ast::*; +//use reexport::*; use syntax::codemap::{Span, Spanned}; -use rustc_front::visit::FnKind; +use syntax::visit::FnKind; -use utils::{span_lint, snippet, match_path, in_external_macro}; +use utils::{span_lint, snippet, match_path_ast, in_external_macro}; declare_lint!(pub NEEDLESS_RETURN, Warn, "using a return statement like `return expr;` where an expression would suffice"); @@ -17,7 +17,7 @@ pub struct ReturnPass; impl ReturnPass { // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &LateContext, block: &Block) { + fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) { if let Some(ref expr) = block.expr { self.check_final_expr(cx, expr); } else if let Some(stmt) = block.stmts.last() { @@ -30,7 +30,7 @@ impl ReturnPass { } // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) { match expr.node { // simple return is always "bad" ExprRet(Some(ref inner)) => { @@ -48,7 +48,7 @@ impl ReturnPass { self.check_final_expr(cx, elsexpr); } // a match expr, check all arms - ExprMatch(_, ref arms, _) => { + ExprMatch(_, ref arms) => { for arm in arms { self.check_final_expr(cx, &arm.body); } @@ -57,7 +57,7 @@ impl ReturnPass { } } - fn emit_return_lint(&mut self, cx: &LateContext, spans: (Span, Span)) { + fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) { if in_external_macro(cx, spans.1) {return;} span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( "unneeded return statement. Consider using `{}` \ @@ -66,7 +66,7 @@ impl ReturnPass { } // Check for "let x = EXPR; x" - fn check_let_return(&mut self, cx: &LateContext, block: &Block) { + fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) { // we need both a let-binding stmt and an expr if_let_chain! { [ @@ -77,14 +77,14 @@ impl ReturnPass { let Some(ref initexpr) = local.init, let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, let ExprPath(_, ref path) = retexpr.node, - match_path(path, &[&id.name.as_str()]) + match_path_ast(path, &[&id.name.as_str()]) ], { self.emit_let_lint(cx, retexpr.span, initexpr.span); } } } - fn emit_let_lint(&mut self, cx: &LateContext, lint_span: Span, note_span: Span) { + fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) { if in_external_macro(cx, note_span) {return;} span_lint(cx, LET_AND_RETURN, lint_span, "returning the result of a let binding from a block. \ @@ -102,13 +102,13 @@ impl LintPass for ReturnPass { } } -impl LateLintPass for ReturnPass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, _: &FnDecl, +impl EarlyLintPass for ReturnPass { + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { self.check_block_return(cx, block); } - fn check_block(&mut self, cx: &LateContext, block: &Block) { + fn check_block(&mut self, cx: &EarlyContext, block: &Block) { self.check_let_return(cx, block); } } diff --git a/src/shadow.rs b/src/shadow.rs index 8fd8d0d15ac..13df95bf8dd 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -7,7 +7,7 @@ use rustc_front::visit::FnKind; use rustc::lint::*; use rustc::middle::def::Def::{DefVariant, DefStruct}; -use utils::{in_external_macro, snippet, span_lint, span_note_and_lint}; +use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint}; declare_lint!(pub SHADOW_SAME, Allow, "rebinding a name to itself, e.g. `let mut x = &mut x`"); @@ -60,6 +60,7 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)> fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } + if is_from_for_desugar(decl) { return; } if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; if let &Some(ref t) = ty { check_ty(cx, t, bindings) } diff --git a/src/types.rs b/src/types.rs index e9125085bb5..584f9b34988 100644 --- a/src/types.rs +++ b/src/types.rs @@ -9,7 +9,8 @@ use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; use syntax::ast::FloatTy::*; -use utils::{match_type, snippet, span_lint, span_help_and_lint, in_macro, in_external_macro}; +use utils::{match_type, snippet, span_lint, span_help_and_lint}; +use utils::{is_from_for_desugar, in_macro, in_external_macro}; use utils::{LL_PATH, VEC_PATH}; /// Handles all the linting of funky types @@ -61,9 +62,10 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) { if *bindtype == ty::TyTuple(vec![]) { if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) { return; } - span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( - "this let-binding has unit value. Consider omitting `let {} =`", - snippet(cx, local.pat.span, ".."))); + if is_from_for_desugar(decl) { return; } + span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( + "this let-binding has unit value. Consider omitting `let {} =`", + snippet(cx, local.pat.span, ".."))); } } } diff --git a/src/utils.rs b/src/utils.rs index ac155617011..34a6d25af25 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,6 +7,7 @@ use rustc::middle::def_id::DefId; use rustc::middle::ty; use std::borrow::Cow; use syntax::ast::Lit_::*; +use syntax::ast; // module DefPaths for certain structs/enums we check for pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; @@ -15,15 +16,56 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +/// Produce a nested chain of if-lets and ifs from the patterns: +/// +/// if_let_chain! { +/// [ +/// Some(y) = x, +/// y.len() == 2, +/// Some(z) = y, +/// ], +/// { +/// block +/// } +/// } +/// +/// becomes +/// +/// 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) => { + if let $pat = $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([let $pat:pat = $expr:expr], $block:block) => { + if let $pat = $expr { + $block + } + }; + ([$expr:expr, $($tt:tt)+], $block:block) => { + if $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([$expr:expr], $block:block) => { + if $expr { + $block + } + }; +} + /// returns true this expn_info was expanded by any macro pub fn in_macro(cx: &LateContext, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, - |info| info.map_or(false, |i| { - match i.callee.format { - ExpnFormat::CompilerExpansion(..) => false, - _ => true, - } - })) + |info| info.is_some()) } /// returns true if the macro that expanded the crate was outside of @@ -34,17 +76,9 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { - match info.callee.format { - ExpnFormat::CompilerExpansion(..) => { - if info.callee.name().as_str() == "closure expansion" { - return false; - } - }, - ExpnFormat::MacroAttribute(..) => { - // these are all plugins - return true; - }, - _ => (), + if let ExpnFormat::MacroAttribute(..) = info.callee.format { + // these are all plugins + return true; } // no span for the callee = external macro info.callee.span.map_or(true, |span| { @@ -102,6 +136,13 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { |(a, b)| a.identifier.name.as_str() == *b) } +/// match a Path against a slice of segment string literals, e.g. +/// `match_path(path, &["std", "rt", "begin_unwind"])` +pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all( + |(a, b)| a.identifier.name.as_str() == *b) +} + /// get the name of the item the expression is in, if available pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); @@ -115,6 +156,24 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { } } +/// checks if a `let` decl is from a for loop desugaring +pub fn is_from_for_desugar(decl: &Decl) -> bool { + if_let_chain! { + [ + let DeclLocal(ref loc) = decl.node, + let Some(ref expr) = loc.init, + // FIXME: This should check for MatchSource::ForLoop + // but right now there's a bug where the match source isn't + // set during lowering + // https://github.com/rust-lang/rust/pull/28973 + let ExprMatch(_, _, _) = expr.node + ], + { return true; } + }; + false +} + + /// convert a span to a code snippet if available, otherwise use default, e.g. /// `snippet(cx, expr.span, "..")` pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { @@ -262,49 +321,3 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool } false } - -/// Produce a nested chain of if-lets and ifs from the patterns: -/// -/// if_let_chain! { -/// [ -/// Some(y) = x, -/// y.len() == 2, -/// Some(z) = y, -/// ], -/// { -/// block -/// } -/// } -/// -/// becomes -/// -/// 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) => { - if let $pat = $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([let $pat:pat = $expr:expr], $block:block) => { - if let $pat = $expr { - $block - } - }; - ([$expr:expr, $($tt:tt)+], $block:block) => { - if $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([$expr:expr], $block:block) => { - if $expr { - $block - } - }; -} diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 7e21294a3d1..1ba8616ed29 100755 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -6,7 +6,7 @@ fn add_only() { // ignores assignment distinction let mut x = "".to_owned(); - for _ in (1..3) { + for _ in 1..3 { x = x + "."; //~ERROR you added something to a string. } @@ -20,7 +20,7 @@ fn add_only() { // ignores assignment distinction fn add_assign_only() { let mut x = "".to_owned(); - for _ in (1..3) { + for _ in 1..3 { x = x + "."; //~ERROR you assigned the result of adding something to this string. } @@ -34,7 +34,7 @@ fn add_assign_only() { fn both() { let mut x = "".to_owned(); - for _ in (1..3) { + for _ in 1..3 { x = x + "."; //~ERROR you assigned the result of adding something to this string. } -- cgit 1.4.1-3-g733a5 From b02e80c0124ad356f5b5be4f8ae4e23c0bf33efc Mon Sep 17 00:00:00 2001 From: swgillespie <sean.william.g@gmail.com> Date: Sun, 11 Oct 2015 19:22:13 -0700 Subject: implement 0.0/0.0 -> NaN lint as described in #370 casing of NaN --- README.md | 3 ++- src/lib.rs | 3 +++ src/zero_div_zero.rs | 50 +++++++++++++++++++++++++++++++++++++ tests/compile-fail/zero_div_zero.rs | 16 ++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/zero_div_zero.rs create mode 100644 tests/compile-fail/zero_div_zero.rs (limited to 'src') diff --git a/README.md b/README.md index a5ab856fc21..44262eba8a1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 59 lints included in this crate: +There are 60 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -68,6 +68,7 @@ name [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention [wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention +[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN [zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/lib.rs b/src/lib.rs index 6503c5e1006..8675eb01527 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub mod loops; pub mod ranges; pub mod matches; pub mod precedence; +pub mod zero_div_zero; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -88,6 +89,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box matches::MatchPass); reg.register_late_lint_pass(box misc::PatternPass); reg.register_late_lint_pass(box minmax::MinMaxPass); + reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -152,5 +154,6 @@ pub fn plugin_registrar(reg: &mut Registry) { types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, + zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); } diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs new file mode 100644 index 00000000000..37d5d8904e1 --- /dev/null +++ b/src/zero_div_zero.rs @@ -0,0 +1,50 @@ +use rustc::lint::*; +use rustc_front::hir::*; + +use utils::{span_help_and_lint}; +use consts::{Constant, constant_simple, FloatWidth}; + +/// ZeroDivZeroPass is a pass that checks for a binary expression that consists +/// of 0.0/0.0, which is always NaN. It is more clear to replace instances of +/// 0.0/0.0 with std::f32::NaN or std::f64::NaN, depending on the precision. +pub struct ZeroDivZeroPass; + +declare_lint!(pub ZERO_DIVIDED_BY_ZERO, Warn, + "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN"); + +impl LintPass for ZeroDivZeroPass { + fn get_lints(&self) -> LintArray { + lint_array!(ZERO_DIVIDED_BY_ZERO) + } +} + +impl LateLintPass for ZeroDivZeroPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + // check for instances of 0.0/0.0 + if_let_chain! { + [ + let ExprBinary(ref op, ref left, ref right) = expr.node, + let BinOp_::BiDiv = op.node, + // TODO - constant_simple does not fold many operations involving floats. + // That's probably fine for this lint - it's pretty unlikely that someone would + // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. + let Some(Constant::ConstantFloat(ref lhs_value, lhs_width)) = constant_simple(left), + let Some(Constant::ConstantFloat(ref rhs_value, rhs_width)) = constant_simple(right), + let Some(0.0) = lhs_value.parse().ok(), + let Some(0.0) = rhs_value.parse().ok() + ], + { + // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, + // match the precision of the literals that are given. + let float_type = match (lhs_width, rhs_width) { + (FloatWidth::Fw64, _) + | (_, FloatWidth::Fw64) => "f64", + _ => "f32" + }; + span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span, + "constant division of 0.0 with 0.0 will always result in NaN", + &format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type)); + } + } + } +} diff --git a/tests/compile-fail/zero_div_zero.rs b/tests/compile-fail/zero_div_zero.rs new file mode 100644 index 00000000000..8c40923d3ed --- /dev/null +++ b/tests/compile-fail/zero_div_zero.rs @@ -0,0 +1,16 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[allow(unused_variables)] +#[deny(zero_divided_by_zero)] +fn main() { + let nan = 0.0 / 0.0; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + let f64_nan = 0.0 / 0.0f64; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + let other_f64_nan = 0.0f64 / 0.0; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + let one_more_f64_nan = 0.0f64/0.0f64; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + let zero = 0.0; + let other_zero = 0.0; + let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants. + let not_nan = 2.0/0.0; // not an error: 2/0 = inf + let also_not_nan = 0.0/2.0; // not an error: 0/2 = 0 +} -- cgit 1.4.1-3-g733a5 From 3632b93d7afe5af15c9daa7e86b775c54ccfbd29 Mon Sep 17 00:00:00 2001 From: Alex Burka <durka42+github@gmail.com> Date: Mon, 12 Oct 2015 01:54:44 -0400 Subject: fix doc comment for if_let_chain! --- src/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 34a6d25af25..df730a4c021 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,9 +20,9 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke /// /// if_let_chain! { /// [ -/// Some(y) = x, +/// let Some(y) = x, /// y.len() == 2, -/// Some(z) = y, +/// let Some(z) = y, /// ], /// { /// block -- cgit 1.4.1-3-g733a5 From be2fb9ba113125c0ad3c156b3bcedb036eac60c2 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 12 Oct 2015 07:59:08 +0200 Subject: Remove "are you sure?" from lint msg. No added value, and leads to punctuation clash. --- src/attrs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 936548c04f8..79cec664adc 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -99,7 +99,7 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, if always != &"always" { continue; } span_lint(cx, INLINE_ALWAYS, attr.span, &format!( "you have declared `#[inline(always)]` on `{}`. This \ - is usually a bad idea. Are you sure?", + is usually a bad idea", name)); } } -- cgit 1.4.1-3-g733a5 From fb5fdb61fab3b08a39aeb6713aeadd14f309f376 Mon Sep 17 00:00:00 2001 From: Ravi Shankar <wafflespeanut@gmail.com> Date: Sun, 11 Oct 2015 22:19:01 +0530 Subject: whup the while_let_loop for ignoring expressions! --- src/loops.rs | 43 ++++++++++++++++++++++------------------ tests/compile-fail/while_loop.rs | 10 +++++++++- 2 files changed, 33 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index ee978932d09..5657f08fdef 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -163,25 +163,31 @@ impl LateLintPass for LoopsPass { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprLoop(ref block, _) = expr.node { - // extract the first statement (if any) in a block - let inner_stmt = extract_expr_from_first_stmt(block); - // extract a single expression + // extract the expression from the first statement (if any) in a block + let inner_stmt_expr = extract_expr_from_first_stmt(block); + // extract the first expression (if any) from the block let inner_expr = extract_first_expr(block); - let extracted = match inner_stmt { - Some(_) => inner_stmt, - None => inner_expr, + let (extracted, collect_expr) = match inner_stmt_expr { + Some(_) => (inner_stmt_expr, true), // check if an expression exists in the first statement + None => (inner_expr, false), // if not, let's go for the first expression in the block }; if let Some(inner) = extracted { - // collect remaining expressions below the match - let other_stuff = block.stmts - .iter() - .skip(1) - .map(|stmt| { - format!("{}", snippet(cx, stmt.span, "..")) - }).collect::<Vec<String>>(); - if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { + // collect the remaining statements below the match + let mut other_stuff = block.stmts + .iter() + .skip(1) + .map(|stmt| { + format!("{}", snippet(cx, stmt.span, "..")) + }).collect::<Vec<String>>(); + if collect_expr { // if we have a statement which has a match, + match block.expr { // then collect the expression (without semicolon) below it + Some(ref expr) => other_stuff.push(format!("{}", snippet(cx, expr.span, ".."))), + None => (), + } + } + // ensure "if let" compatible match structure match *source { MatchSource::Normal | MatchSource::IfLetDesugar{..} => if @@ -192,7 +198,7 @@ impl LateLintPass for LoopsPass { is_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { return; } - let loop_body = match inner_stmt { + let loop_body = match inner_stmt_expr { // FIXME: should probably be an ellipsis // tabbing and newline is probably a bad idea, especially for large blocks Some(_) => Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))), @@ -310,9 +316,9 @@ fn is_iterable_array(ty: ty::Ty) -> bool { /// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { - match block.expr { - Some(_) => None, - None if !block.stmts.is_empty() => match block.stmts[0].node { + match block.stmts.is_empty() { + true => None, + false => match block.stmts[0].node { StmtDecl(ref decl, _) => match decl.node { DeclLocal(ref local) => match local.init { Some(ref expr) => Some(expr), @@ -322,7 +328,6 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { }, _ => None, }, - _ => None, } } diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index eca2c7e12ae..c8444ee0a57 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -33,6 +33,14 @@ fn main() { let _x = x; let _str = "foo"; } + loop { //~ERROR + let x = match y { + Some(x) => x, + None => break, + }; + { let _a = "bar"; }; + { let _b = "foobar"; } + } loop { // no error, else branch does something other than break match y { Some(_x) => true, @@ -53,7 +61,7 @@ fn main() { // cause this function to trigger it fn no_panic<T>(slice: &[T]) { let mut iter = slice.iter(); - loop { + loop { //~ERROR let _ = match iter.next() { Some(ele) => ele, None => break -- cgit 1.4.1-3-g733a5 From 567d5a7293f2a3ab6672919fb0ce8f94c28a6136 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 13 Oct 2015 04:16:05 +0530 Subject: Improve cmp_owned suggestions (fixes #386) --- src/misc.rs | 42 ++++++++++++++++++++++++++--------------- tests/compile-fail/cmp_owned.rs | 6 +++++- 2 files changed, 32 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index cf4504d2f67..497bb6692c7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -165,37 +165,49 @@ impl LateLintPass for CmpOwned { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { - check_to_owned(cx, left, right.span); - check_to_owned(cx, right, left.span) + check_to_owned(cx, left, right.span, true, cmp.span); + check_to_owned(cx, right, left.span, false, cmp.span) } } } } -fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span) { - match expr.node { - ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) => { +fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, op: Span) { + let snip = match expr.node { + ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => { if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. \ - Consider using `{}.as_slice()` to compare without allocation", - snippet(cx, other_span, ".."))) + snippet(cx, args[0].span, "..") + } else { + return } }, - ExprCall(ref path, _) => { + ExprCall(ref path, ref v) if v.len() == 1 => { if let &ExprPath(None, ref path) = &path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. \ - Consider using `{}.as_slice()` to compare without allocation", - snippet(cx, other_span, ".."))) + snippet(cx, v[0].span, "..") + } else { + return } + } else { + return } }, - _ => () + _ => return + }; + if left { + span_lint(cx, CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. Consider using \ + `{} {} {}` to compare without allocation", snip, + snippet(cx, op, "=="), snippet(cx, other_span, ".."))); + } else { + span_lint(cx, CMP_OWNED, expr.span, &format!( + "this creates an owned instance just for comparison. Consider using \ + `{} {} {}` to compare without allocation", + snippet(cx, other_span, ".."), snippet(cx, op, "=="), snip)); } + } fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index 2765da5cf23..afca83e1d32 100755 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -7,7 +7,11 @@ fn main() { #[allow(str_to_string)] fn with_to_string(x : &str) { - x != "foo".to_string(); //~ERROR this creates an owned instance + x != "foo".to_string(); + //~^ ERROR this creates an owned instance just for comparison. Consider using `x != "foo"` to compare without allocation + + "foo".to_string() != x; + //~^ ERROR this creates an owned instance just for comparison. Consider using `"foo" != x` to compare without allocation } with_to_string(x); -- cgit 1.4.1-3-g733a5 From b2f1940f6f76c78771a2793b97e0cf2c5b459d1f Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Tue, 13 Oct 2015 13:48:48 +0200 Subject: improved precedence messages (fixes #389) --- src/precedence.rs | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/precedence.rs b/src/precedence.rs index ce06278b782..b7dbe268557 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,7 +1,9 @@ use rustc::lint::*; use syntax::codemap::Spanned; use syntax::ast::*; -use utils::span_lint; +use syntax::ast_util::binop_to_string; + +use utils::{span_lint, snippet}; declare_lint!(pub PRECEDENCE, Warn, "catches operations where precedence may be unclear. See the wiki for a \ @@ -19,10 +21,24 @@ impl LintPass for Precedence { impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { - if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) { - span_lint(cx, PRECEDENCE, expr.span, - "operator precedence can trip the unwary. Consider adding parentheses \ - to the subexpression"); + if !is_bit_op(op) { return; } + match (is_arith_expr(left), is_arith_expr(right)) { + (true, true) => span_lint(cx, PRECEDENCE, expr.span, + &format!("operator precedence can trip the unwary. \ + Consider parenthesizing your expression:\ + `({}) {} ({})`", snippet(cx, left.span, ".."), + binop_to_string(op), snippet(cx, right.span, ".."))), + (true, false) => span_lint(cx, PRECEDENCE, expr.span, + &format!("operator precedence can trip the unwary. \ + Consider parenthesizing your expression:\ + `({}) {} {}`", snippet(cx, left.span, ".."), + binop_to_string(op), snippet(cx, right.span, ".."))), + (false, true) => span_lint(cx, PRECEDENCE, expr.span, + &format!("operator precedence can trip the unwary. \ + Consider parenthesizing your expression:\ + `{} {} ({})`", snippet(cx, left.span, ".."), + binop_to_string(op), snippet(cx, right.span, ".."))), + _ => (), } } @@ -32,9 +48,11 @@ impl EarlyLintPass for Precedence { if let ExprLit(ref lit) = slf.node { match lit.node { LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => - span_lint(cx, PRECEDENCE, expr.span, - "unary minus has lower precedence than method call. Consider \ - adding parentheses to clarify your intent"), + span_lint(cx, PRECEDENCE, expr.span, &format!( + "unary minus has lower precedence than \ + method call. Consider adding parentheses \ + to clarify your intent: -({})", + snippet(cx, rhs.span, ".."))), _ => () } } -- cgit 1.4.1-3-g733a5 From bed29a017b6c998b671cfd7821111ed550d5ad98 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Mon, 12 Oct 2015 13:38:18 +0200 Subject: new lint to detect --- README.md | 1 + src/lib.rs | 1 + src/loops.rs | 13 ++++++++++++- tests/compile-fail/while_loop.rs | 4 ++-- 4 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 44262eba8a1..138900937f7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ name [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do diff --git a/src/lib.rs b/src/lib.rs index 8675eb01527..fd7adbed16d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,6 +122,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, + loops::EMPTY_LOOP, loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, loops::ITER_NEXT_LOOP, diff --git a/src/loops.rs b/src/loops.rs index ee978932d09..10f58716dc7 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -36,13 +36,16 @@ declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, "for-looping with an explicit counter when `_.enumerate()` would do" } +declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } + #[derive(Copy, Clone)] pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP) + WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, EMPTY_LOOP) } } @@ -163,6 +166,14 @@ impl LateLintPass for LoopsPass { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprLoop(ref block, _) = expr.node { + // also check for empty `loop {}` statements + if block.stmts.is_empty() && block.expr.is_none() { + span_lint(cx, EMPTY_LOOP, expr.span, + "empty `loop {}` detected. You may want to either \ + use `panic!()` or add `std::thread::sleep(..);` to \ + the loop body."); + } + // extract the first statement (if any) in a block let inner_stmt = extract_expr_from_first_stmt(block); // extract a single expression diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index eca2c7e12ae..8e51bf84887 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(while_let_loop)] +#![deny(while_let_loop, empty_loop)] #![allow(dead_code, unused)] fn main() { @@ -58,6 +58,6 @@ fn no_panic<T>(slice: &[T]) { Some(ele) => ele, None => break }; - loop {} + loop {} //~ERROR empty `loop {}` detected. } } -- cgit 1.4.1-3-g733a5 From 871d9fc27c54159bf7ad9dbff5a0fe52a6d84645 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 14 Oct 2015 19:51:54 +0200 Subject: Make ptr_arg lint warn by default --- README.md | 2 +- src/lib.rs | 2 +- src/ptr_arg.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index e57ca8d1e02..a0131583597 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ name [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught -[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | allow | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively +[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 [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 [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern diff --git a/src/lib.rs b/src/lib.rs index 5276ad711c0..8bf199bff47 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,6 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::WRONG_PUB_SELF_CONVENTION, mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, - ptr_arg::PTR_ARG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, @@ -153,6 +152,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_bool::NEEDLESS_BOOL, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, + ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index be11ebce26a..4baba711886 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -1,6 +1,6 @@ //! Checks for usage of &Vec[_] and &String //! -//! This lint is **allow** by default +//! This lint is **warn** by default use rustc::lint::*; use rustc_front::hir::*; @@ -11,7 +11,7 @@ use utils::{STRING_PATH, VEC_PATH}; declare_lint! { pub PTR_ARG, - Allow, + Warn, "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \ instead, respectively" } -- cgit 1.4.1-3-g733a5 From 657afc1157fa316a1f1b311e8d54d733e6f50be2 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Thu, 15 Oct 2015 16:02:19 +0200 Subject: rustup --- src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 584f9b34988..af2deb9aa97 100644 --- a/src/types.rs +++ b/src/types.rs @@ -285,9 +285,9 @@ impl LateLintPass for TypeComplexityPass { fn check_variant(&mut self, cx: &LateContext, var: &Variant, _: &Generics) { // StructVariant is covered by check_struct_field - if let TupleVariantKind(ref args) = var.node.kind { + if let VariantData::Tuple(ref args, _) = *var.node.data { for arg in args { - check_type(cx, &arg.ty); + check_type(cx, &arg.node.ty); } } } -- cgit 1.4.1-3-g733a5 From b2f455065401eeb65250815e8ce566239ca69217 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 15 Oct 2015 19:55:14 +0530 Subject: Fix type complexity lint --- src/types.rs | 10 +--------- tests/compile-fail/complex_types.rs | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index af2deb9aa97..93962586bc6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -280,18 +280,10 @@ impl LateLintPass for TypeComplexityPass { } fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { + // enum variants are also struct fields now check_type(cx, &field.node.ty); } - fn check_variant(&mut self, cx: &LateContext, var: &Variant, _: &Generics) { - // StructVariant is covered by check_struct_field - if let VariantData::Tuple(ref args, _) = *var.node.data { - for arg in args { - check_type(cx, &arg.node.ty); - } - } - } - fn check_item(&mut self, cx: &LateContext, item: &Item) { match item.node { ItemStatic(ref ty, _, _) | diff --git a/tests/compile-fail/complex_types.rs b/tests/compile-fail/complex_types.rs index f5b21c6df4b..995132ba88c 100755 --- a/tests/compile-fail/complex_types.rs +++ b/tests/compile-fail/complex_types.rs @@ -17,7 +17,6 @@ struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type enum E { V1(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type - //~^ERROR very complex type V2 { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type } -- cgit 1.4.1-3-g733a5 From 1bd023d3e01857b6fff86efb8da7159c84d0be5d Mon Sep 17 00:00:00 2001 From: Florian Gilcher <florian.gilcher@asquera.de> Date: Thu, 15 Oct 2015 11:13:01 +0200 Subject: New lint for needless use of nightly features --- src/lib.rs | 4 +++ src/needless_features.rs | 49 +++++++++++++++++++++++++++++++++ tests/compile-fail/needless_features.rs | 17 ++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/needless_features.rs create mode 100644 tests/compile-fail/needless_features.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8bf199bff47..31ce6738fd1 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ pub mod precedence; pub mod mutex_atomic; pub mod zero_div_zero; pub mod open_options; +pub mod needless_features; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -94,6 +95,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions); reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); + reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -150,6 +152,8 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, + needless_features::AS_SLICE, + needless_features::AS_MUT_SLICE, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/needless_features.rs b/src/needless_features.rs new file mode 100644 index 00000000000..950057da26c --- /dev/null +++ b/src/needless_features.rs @@ -0,0 +1,49 @@ +//! Checks for usage of nightly features that have simple stable equivalents +//! +//! This lint is **warn** by default + +use rustc::lint::*; +use rustc_front::hir::*; + +use utils::{span_lint}; + +declare_lint! { + pub AS_SLICE, + Warn, + "as_slice is not stable and can be replaced by & v[..]\ +see https://github.com/rust-lang/rust/issues/27729" +} + +declare_lint! { + pub AS_MUT_SLICE, + Warn, + "as_mut_slice is not stable and can be replaced by &mut v[..]\ +see https://github.com/rust-lang/rust/issues/27729" +} + + +#[derive(Copy,Clone)] +pub struct NeedlessFeaturesPass; + +impl LintPass for NeedlessFeaturesPass { + fn get_lints(&self) -> LintArray { + lint_array!(AS_SLICE,AS_MUT_SLICE) + } +} + +impl LateLintPass for NeedlessFeaturesPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprMethodCall(ref name, _, _) = expr.node { + if name.node.as_str() == "as_slice" { + span_lint(cx, AS_SLICE, expr.span, + "used as_slice() from the 'convert' nightly feature. Use &[..] \ + instead"); + } + if name.node.as_str() == "as_mut_slice" { + span_lint(cx, AS_MUT_SLICE, expr.span, + "used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] \ + instead"); + } + } + } +} \ No newline at end of file diff --git a/tests/compile-fail/needless_features.rs b/tests/compile-fail/needless_features.rs new file mode 100644 index 00000000000..02639aea66f --- /dev/null +++ b/tests/compile-fail/needless_features.rs @@ -0,0 +1,17 @@ +#![feature(plugin)] +#![feature(convert)] +#![plugin(clippy)] + +#![deny(clippy)] + +fn test_as_slice() { + let v = vec![1]; + v.as_slice(); //~ERROR used as_slice() from the 'convert' nightly feature. Use &[..] + + let mut v2 = vec![1]; + v2.as_mut_slice(); //~ERROR used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] +} + +fn main() { + test_as_slice(); +} -- cgit 1.4.1-3-g733a5 From 39e93d572b4fa85a71bbe04a2a1c15bcb445e26c Mon Sep 17 00:00:00 2001 From: Florian Gilcher <florian.gilcher@asquera.de> Date: Thu, 15 Oct 2015 12:53:21 +0200 Subject: Regnerate README.md --- README.md | 4 +++- src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index a0131583597..5125f6d4e00 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,13 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 64 lints included in this crate: +There are 66 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 +[as_slice](https://github.com/Manishearth/rust-clippy/wiki#as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap [cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` diff --git a/src/lib.rs b/src/lib.rs index 31ce6738fd1..3175b92be4e 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,8 +152,8 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, - needless_features::AS_SLICE, needless_features::AS_MUT_SLICE, + needless_features::AS_SLICE, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, -- cgit 1.4.1-3-g733a5 From 853368c1d3c92fa699ba5d1bd1cca2cd2703d4d1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 17 Oct 2015 04:33:05 +0530 Subject: Make is_from_for_desugar sound (rust/28973 got fixed) --- src/utils.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 1ba6029ebe6..caf77332b62 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -164,11 +164,7 @@ pub fn is_from_for_desugar(decl: &Decl) -> bool { [ let DeclLocal(ref loc) = decl.node, let Some(ref expr) = loc.init, - // FIXME: This should check for MatchSource::ForLoop - // but right now there's a bug where the match source isn't - // set during lowering - // https://github.com/rust-lang/rust/pull/28973 - let ExprMatch(_, _, _) = expr.node + let ExprMatch(_, _, MatchSource::ForLoopDesugar) = expr.node ], { return true; } }; -- cgit 1.4.1-3-g733a5 From 80639164770bd5755443b52073d358c7496a030a Mon Sep 17 00:00:00 2001 From: Florian Gilcher <florian.gilcher@asquera.de> Date: Sat, 17 Oct 2015 20:16:54 +0200 Subject: Cleanup as discussed in PR --- src/lib.rs | 4 ++-- src/needless_features.rs | 22 +++++++++++++--------- src/utils.rs | 13 +++++++++++++ tests/compile-fail/needless_features.rs | 12 ++++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 3175b92be4e..a3657460fe9 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,8 +152,8 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, - needless_features::AS_MUT_SLICE, - needless_features::AS_SLICE, + needless_features::UNSTABLE_AS_MUT_SLICE, + needless_features::UNSTABLE_AS_SLICE, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/needless_features.rs b/src/needless_features.rs index 950057da26c..b1d38df7311 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -6,44 +6,48 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::{span_lint}; +use utils; declare_lint! { - pub AS_SLICE, + pub UNSTABLE_AS_SLICE, Warn, "as_slice is not stable and can be replaced by & v[..]\ see https://github.com/rust-lang/rust/issues/27729" } declare_lint! { - pub AS_MUT_SLICE, + pub UNSTABLE_AS_MUT_SLICE, Warn, "as_mut_slice is not stable and can be replaced by &mut v[..]\ see https://github.com/rust-lang/rust/issues/27729" } - #[derive(Copy,Clone)] pub struct NeedlessFeaturesPass; impl LintPass for NeedlessFeaturesPass { fn get_lints(&self) -> LintArray { - lint_array!(AS_SLICE,AS_MUT_SLICE) + lint_array!(UNSTABLE_AS_SLICE,UNSTABLE_AS_MUT_SLICE) } } impl LateLintPass for NeedlessFeaturesPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(ref name, _, _) = expr.node { - if name.node.as_str() == "as_slice" { - span_lint(cx, AS_SLICE, expr.span, + if name.node.as_str() == "as_slice" && check_paths(cx, expr) { + span_lint(cx, UNSTABLE_AS_SLICE, expr.span, "used as_slice() from the 'convert' nightly feature. Use &[..] \ instead"); } - if name.node.as_str() == "as_mut_slice" { - span_lint(cx, AS_MUT_SLICE, expr.span, + if name.node.as_str() == "as_mut_slice" && check_paths(cx, expr) { + span_lint(cx, UNSTABLE_AS_MUT_SLICE, expr.span, "used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] \ instead"); } } } -} \ No newline at end of file +} + +fn check_paths(cx: &LateContext, expr: &Expr) -> bool { + utils::match_impl_method(cx, expr, &["collections", "vec", "Vec<T>"]) +} diff --git a/src/utils.rs b/src/utils.rs index 1ba6029ebe6..c3ebfd8147d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -118,6 +118,19 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { } } +/// check if method call given in "expr" belongs to given trait +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)); + if let Some(trt_id) = trt_id { + match_def_path(cx, trt_id, path) + } else { + false + } +} /// check if method call given in "expr" belongs to given trait pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); diff --git a/tests/compile-fail/needless_features.rs b/tests/compile-fail/needless_features.rs index 02639aea66f..dee2a19d5d0 100644 --- a/tests/compile-fail/needless_features.rs +++ b/tests/compile-fail/needless_features.rs @@ -12,6 +12,18 @@ fn test_as_slice() { v2.as_mut_slice(); //~ERROR used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] } +struct ShouldWork; + +impl ShouldWork { + fn as_slice(&self) -> &ShouldWork { self } +} + +fn test_should_work() { + let sw = ShouldWork; + sw.as_slice(); +} + fn main() { test_as_slice(); + test_should_work(); } -- cgit 1.4.1-3-g733a5 From 2951b70d1575f62771ac2da007ef426f9ac600c6 Mon Sep 17 00:00:00 2001 From: Vikas Kumar <kr.vikas@gmail.com> Date: Tue, 20 Oct 2015 10:18:48 -0700 Subject: Match on bool should be replaced with if..else block 1. Added another conditional in `check_expr` impl to lint if match expr is a bool. 2. Test cases. --- src/lib.rs | 1 + src/matches.rs | 19 ++++++++++++++++++- tests/compile-fail/matches.rs | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a3657460fe9..6d6c6dfeeb0 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::WHILE_LET_LOOP, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, + matches::MATCH_BOOL, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, diff --git a/src/matches.rs b/src/matches.rs index e935a6aa6e1..0606c244747 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,5 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; +use rustc::middle::ty; use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; @@ -9,13 +10,15 @@ declare_lint!(pub SINGLE_MATCH, Warn, declare_lint!(pub MATCH_REF_PATS, Warn, "a match has all arms prefixed with `&`; the match expression can be \ dereferenced instead"); +declare_lint!(pub MATCH_BOOL, Warn, + "a match on boolean expression; recommends `if..else` block instead"); #[allow(missing_copy_implementations)] pub struct MatchPass; impl LintPass for MatchPass { fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH, MATCH_REF_PATS) + lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL) } } @@ -59,6 +62,16 @@ impl LateLintPass for MatchPass { expression to match: `match *{} {{ ...`", snippet(cx, ex.span, ".."))); } } + + // check preconditions for MATCH_BOOL + // type of expression == bool + if is_bool_expr(cx, ex) { + if in_external_macro(cx, expr.span) { return; } + + span_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using if..else block"); + } } } } @@ -71,6 +84,10 @@ fn is_unit_expr(expr: &Expr) -> bool { } } +fn is_bool_expr(cx: &LateContext, ex: &Expr ) -> bool { + cx.tcx.expr_ty(ex).sty == ty::TyBool +} + fn has_only_ref_pats(arms: &[Arm]) -> bool { let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node { PatRegion(..) => Some(true), // &-patterns diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index f25a5fa3fa4..1cdf813bc00 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -38,6 +38,28 @@ fn single_match(){ } } +fn match_bool() { + let test: bool = true; + + match test { //~ ERROR you seem to be trying to match on a boolean expression + true => (), + false => (), + }; + + let option = 1; + match option == 1 { //~ ERROR you seem to be trying to match on a boolean expression + true => (), + false => (), + }; + + // Not linted + match option { + 1 ... 10 => (), + 10 ... 20 => (), + _ => (), + }; +} + fn ref_pats() { { let v = &Some(0); -- cgit 1.4.1-3-g733a5 From 675c532eabadeb5e203e71336a50fbf70f7decde Mon Sep 17 00:00:00 2001 From: Vikas Kumar <kr.vikas@gmail.com> Date: Tue, 20 Oct 2015 10:25:37 -0700 Subject: Ran util/update_lints.py to auto gen doc and lib.rs --- README.md | 3 ++- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index e50407eaaaa..990db2e5460 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 66 lints included in this crate: +There are 67 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -34,6 +34,7 @@ name [let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 diff --git a/src/lib.rs b/src/lib.rs index 6d6c6dfeeb0..6f06641ef45 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,9 +136,9 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::REVERSE_RANGE_LOOP, loops::UNUSED_COLLECT, loops::WHILE_LET_LOOP, + matches::MATCH_BOOL, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, - matches::MATCH_BOOL, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, -- cgit 1.4.1-3-g733a5 From 5e78fbbf57e5bf5891c116a3c1bf287212744efa Mon Sep 17 00:00:00 2001 From: Vikas Kumar <kr.vikas@gmail.com> Date: Tue, 20 Oct 2015 11:26:54 -0700 Subject: Fixups from review comments 1. Moved common check `in_external_macro` to the top of function from inside each conditionals. 2. Inlined `is_bool_expr` call --- src/matches.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 0606c244747..da770c6f484 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -25,6 +25,8 @@ impl LintPass for MatchPass { impl LateLintPass for MatchPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { + if in_external_macro(cx, expr.span) { return; } + // check preconditions for SINGLE_MATCH // only two arms if arms.len() == 2 && @@ -39,7 +41,6 @@ impl LateLintPass for MatchPass { // finally, we don't want any content in the second arm (unit or empty block) is_unit_expr(&arms[1].body) { - if in_external_macro(cx, expr.span) {return;} span_help_and_lint(cx, SINGLE_MATCH, expr.span, "you seem to be trying to use match for destructuring a \ single pattern. Consider using `if let`", @@ -51,7 +52,6 @@ impl LateLintPass for MatchPass { // check preconditions for MATCH_REF_PATS if has_only_ref_pats(arms) { - if in_external_macro(cx, expr.span) { return; } if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { span_lint(cx, MATCH_REF_PATS, expr.span, &format!( "you don't need to add `&` to both the expression to match \ @@ -65,12 +65,11 @@ impl LateLintPass for MatchPass { // check preconditions for MATCH_BOOL // type of expression == bool - if is_bool_expr(cx, ex) { - if in_external_macro(cx, expr.span) { return; } + if cx.tcx.expr_ty(ex).sty == ty::TyBool { span_lint(cx, MATCH_BOOL, expr.span, "you seem to be trying to match on a boolean expression. \ - Consider using if..else block"); + Consider using an if..else block"); } } } @@ -84,10 +83,6 @@ fn is_unit_expr(expr: &Expr) -> bool { } } -fn is_bool_expr(cx: &LateContext, ex: &Expr ) -> bool { - cx.tcx.expr_ty(ex).sty == ty::TyBool -} - fn has_only_ref_pats(arms: &[Arm]) -> bool { let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node { PatRegion(..) => Some(true), // &-patterns -- cgit 1.4.1-3-g733a5 From da82e2d3baee6061ca28894ac053cd5e3f332927 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Wed, 21 Oct 2015 08:24:56 +0200 Subject: added code snippet help to match_bool --- src/matches.rs | 53 +++++++++++++++++++++++++++++++++++++++++-- tests/compile-fail/matches.rs | 19 +++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index da770c6f484..a7cfefd7af5 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,6 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; +use syntax::ast::Lit_::LitBool; use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; @@ -66,10 +67,58 @@ impl LateLintPass for MatchPass { // check preconditions for MATCH_BOOL // type of expression == bool if cx.tcx.expr_ty(ex).sty == ty::TyBool { - - span_lint(cx, MATCH_BOOL, expr.span, + if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards + let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { + if let ExprLit(ref lit) = arm_bool.node { + if let LitBool(val) = lit.node { + if val { + Some((&*arms[0].body, &*arms[1].body)) + } else { + Some((&*arms[1].body, &*arms[0].body)) + } + } else { None } + } else { None } + } else { None }; + if let Some((ref true_expr, ref false_expr)) = exprs { + if !is_unit_expr(true_expr) { + if !is_unit_expr(false_expr) { + span_help_and_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block:", + &format!("try\nif {} {} else {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."), + expr_block(cx, false_expr, None, ".."))); + } else { + span_help_and_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block:", + &format!("try\nif {} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."))); + } + } else if !is_unit_expr(false_expr) { + span_help_and_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block:", + &format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))); + } else { + span_lint(cx, MATCH_BOOL, expr.span, "you seem to be trying to match on a boolean expression. \ Consider using an if..else block"); + } + } else { + span_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block"); + } + } else { + span_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block"); + } } } } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 1cdf813bc00..f0cc650f753 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -48,8 +48,25 @@ fn match_bool() { let option = 1; match option == 1 { //~ ERROR you seem to be trying to match on a boolean expression + true => 1, + false => 0, + }; + + match test { //~ ERROR you seem to be trying to match on a boolean expression true => (), - false => (), + false => { println!("Noooo!"); }, + }; + + match test { //~ ERROR you seem to be trying to match on a boolean expression + //~^ERROR you seem to be trying to use match + //TODO: Remove duplicate warning + false => { println!("Noooo!"); }, + _ => (), + }; + + match test { //~ ERROR you seem to be trying to match on a boolean expression + false => { println!("Noooo!"); }, + true => { println!("Yes!"); }, }; // Not linted -- cgit 1.4.1-3-g733a5 From d843257643637facfa7308c2c85e677442298738 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Thu, 22 Oct 2015 00:25:16 +0900 Subject: New lint for struct update that has no effect --- README.md | 3 ++- src/lib.rs | 3 +++ src/needless_update.rs | 35 +++++++++++++++++++++++++++++++++++ tests/compile-fail/needless_update.rs | 16 ++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/needless_update.rs create mode 100644 tests/compile-fail/needless_update.rs (limited to 'src') diff --git a/README.md b/README.md index 990db2e5460..3e56e863287 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 67 lints included in this crate: +There are 68 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -45,6 +45,7 @@ name [needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice +[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` diff --git a/src/lib.rs b/src/lib.rs index 6f06641ef45..d5d27e5e2af 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ pub mod mutex_atomic; pub mod zero_div_zero; pub mod open_options; pub mod needless_features; +pub mod needless_update; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -96,6 +97,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); + reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -155,6 +157,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_bool::NEEDLESS_BOOL, needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, + needless_update::NEEDLESS_UPDATE, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/needless_update.rs b/src/needless_update.rs new file mode 100644 index 00000000000..c65d0c9e7d3 --- /dev/null +++ b/src/needless_update.rs @@ -0,0 +1,35 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::middle::ty::TyStruct; +use rustc_front::hir::{Expr, ExprStruct}; + +use utils::span_lint; + +declare_lint! { + pub NEEDLESS_UPDATE, + Warn, + "using `{ ..base }` when there are no missing fields" +} + +#[derive(Copy, Clone)] +pub struct NeedlessUpdatePass; + +impl LintPass for NeedlessUpdatePass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_UPDATE) + } +} + +impl LateLintPass for NeedlessUpdatePass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprStruct(_, ref fields, Some(ref base)) = expr.node { + let ty = cx.tcx.expr_ty(expr); + if let TyStruct(def, _) = ty.sty { + if fields.len() == def.struct_variant().fields.len() { + span_lint(cx, NEEDLESS_UPDATE, base.span, + "struct update has no effect, all the fields \ + in the struct have already been specified"); + } + } + } + } +} diff --git a/tests/compile-fail/needless_update.rs b/tests/compile-fail/needless_update.rs new file mode 100644 index 00000000000..55438d9d90a --- /dev/null +++ b/tests/compile-fail/needless_update.rs @@ -0,0 +1,16 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(needless_update)] + +struct S { + pub a: i32, + pub b: i32, +} + +fn main() { + let base = S { a: 0, b: 0 }; + S { ..base }; // no error + S { a: 1, ..base }; // no error + S { a: 1, b: 1, ..base }; //~ERROR struct update has no effect +} -- cgit 1.4.1-3-g733a5 From 546eb14b7ef847545d91c10e48b564a30b51fc60 Mon Sep 17 00:00:00 2001 From: Kevin Yap <me@kevinyap.ca> Date: Thu, 22 Oct 2015 15:19:03 -0700 Subject: Change implementation of approx_const lint - Replace epsilon with lower and upper bounds for each constant. - Warn on use of "3.14", and update tests accordingly. --- src/approx_const.rs | 50 +++++++++++++++++++++----------------- tests/compile-fail/approx_const.rs | 3 ++- 2 files changed, 30 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 9a186a4f8cd..19753aaf844 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,6 +1,5 @@ use rustc::lint::*; use rustc_front::hir::*; -use std::f64::consts as f64; use utils::span_lint; use syntax::ast::Lit_::*; use syntax::ast::Lit; @@ -13,14 +12,26 @@ declare_lint! { is found; suggests to use the constant" } -const KNOWN_CONSTS : &'static [(f64, &'static str)] = &[(f64::E, "E"), (f64::FRAC_1_PI, "FRAC_1_PI"), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2"), (f64::FRAC_2_PI, "FRAC_2_PI"), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI"), (f64::FRAC_PI_2, "FRAC_PI_2"), (f64::FRAC_PI_3, "FRAC_PI_3"), - (f64::FRAC_PI_4, "FRAC_PI_4"), (f64::FRAC_PI_6, "FRAC_PI_6"), (f64::FRAC_PI_8, "FRAC_PI_8"), - (f64::LN_10, "LN_10"), (f64::LN_2, "LN_2"), (f64::LOG10_E, "LOG10_E"), (f64::LOG2_E, "LOG2_E"), - (f64::PI, "PI"), (f64::SQRT_2, "SQRT_2")]; - -const EPSILON_DIVISOR : f64 = 8192f64; //TODO: test to find a good value +// Tuples are of the form (name, lower_bound, upper_bound) +#[allow(approx_constant)] +const KNOWN_CONSTS : &'static [(&'static str, f64, f64)] = &[ + ("E", 2.7101, 2.7200), + ("FRAC_1_PI", 0.31829, 0.31840), + ("FRAC_1_SQRT_2", 0.7071, 0.7072), + ("FRAC_2_PI", 0.6366, 0.6370), + ("FRAC_2_SQRT_PI", 1.1283, 1.1284), + ("FRAC_PI_2", 1.5707, 1.5708), + ("FRAC_PI_3", 1.0471, 1.0472), + ("FRAC_PI_4", 0.7853, 0.7854), + ("FRAC_PI_6", 0.5235, 0.5236), + ("FRAC_PI_8", 0.3926, 0.3927), + ("LN_10", 2.302, 2.303), + ("LN_2", 0.6931, 0.6932), + ("LOG10_E", 0.4342, 0.4343), + ("LOG2_E", 1.4426, 1.4427), + ("PI", 3.140, 3.142), + ("SQRT_2", 1.4142, 1.4143), +]; #[derive(Copy,Clone)] pub struct ApproxConstant; @@ -49,19 +60,14 @@ fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { } } -fn check_known_consts(cx: &LateContext, e: &Expr, str: &str, module: &str) { - if let Ok(value) = str.parse::<f64>() { - for &(constant, name) in KNOWN_CONSTS { - if !within_epsilon(constant, value) { continue; } - span_lint(cx, APPROX_CONSTANT, e.span, &format!( - "approximate value of `{}::{}` found. \ - Consider using it directly", module, &name)); +fn check_known_consts(cx: &LateContext, e: &Expr, s: &str, module: &str) { + if let Ok(value) = s.parse::<f64>() { + for &(name, lower_bound, upper_bound) in KNOWN_CONSTS { + if (value >= lower_bound) && (value < upper_bound) { + span_lint(cx, APPROX_CONSTANT, e.span, &format!( + "approximate value of `{}::{}` found. \ + Consider using it directly", module, &name)); + } } } } - -fn within_epsilon(target: f64, value: f64) -> bool { - f64::abs(value - target) < f64::abs(if target > value { - target - } else { value }) / EPSILON_DIVISOR -} diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index a75cd0bf3f2..ebd5d3ea139 100755 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -49,7 +49,8 @@ fn main() { let no_log2_e = 1.442; let my_pi = 3.1415; //~ERROR approximate value of `f{32, 64}::PI` found - let almost_pi = 3.141; + let almost_pi = 3.14; //~ERROR approximate value of `f{32, 64}::PI` found + let no_pi = 3.15; let my_sq2 = 1.4142; //~ERROR approximate value of `f{32, 64}::SQRT_2` found let no_sq2 = 1.414; -- cgit 1.4.1-3-g733a5 From 70e3277bf960be55c529fcfaf4beb713620dd19d Mon Sep 17 00:00:00 2001 From: Kevin Yap <me@kevinyap.ca> Date: Fri, 23 Oct 2015 21:30:57 -0700 Subject: Compare float literals to stringified constants - Convert constants to strings and compare directly with float literal. - Return immediately after positive match for constant. - Fix value of `my_log10_e` in `approx_const` tests. --- src/approx_const.rs | 71 ++++++++++++++++++++++++-------------- tests/compile-fail/approx_const.rs | 2 +- 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 19753aaf844..89cb5204a8c 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,5 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; +use std::f64::consts as f64; use utils::span_lint; use syntax::ast::Lit_::*; use syntax::ast::Lit; @@ -12,25 +13,24 @@ declare_lint! { is found; suggests to use the constant" } -// Tuples are of the form (name, lower_bound, upper_bound) -#[allow(approx_constant)] -const KNOWN_CONSTS : &'static [(&'static str, f64, f64)] = &[ - ("E", 2.7101, 2.7200), - ("FRAC_1_PI", 0.31829, 0.31840), - ("FRAC_1_SQRT_2", 0.7071, 0.7072), - ("FRAC_2_PI", 0.6366, 0.6370), - ("FRAC_2_SQRT_PI", 1.1283, 1.1284), - ("FRAC_PI_2", 1.5707, 1.5708), - ("FRAC_PI_3", 1.0471, 1.0472), - ("FRAC_PI_4", 0.7853, 0.7854), - ("FRAC_PI_6", 0.5235, 0.5236), - ("FRAC_PI_8", 0.3926, 0.3927), - ("LN_10", 2.302, 2.303), - ("LN_2", 0.6931, 0.6932), - ("LOG10_E", 0.4342, 0.4343), - ("LOG2_E", 1.4426, 1.4427), - ("PI", 3.140, 3.142), - ("SQRT_2", 1.4142, 1.4143), +// Tuples are of the form (constant, name, min_digits) +const KNOWN_CONSTS : &'static [(f64, &'static str, usize)] = &[ + (f64::E, "E", 4), + (f64::FRAC_1_PI, "FRAC_1_PI", 4), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), + (f64::FRAC_2_PI, "FRAC_2_PI", 5), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), + (f64::FRAC_PI_2, "FRAC_PI_2", 5), + (f64::FRAC_PI_3, "FRAC_PI_3", 5), + (f64::FRAC_PI_4, "FRAC_PI_4", 5), + (f64::FRAC_PI_6, "FRAC_PI_6", 5), + (f64::FRAC_PI_8, "FRAC_PI_8", 5), + (f64::LN_10, "LN_10", 5), + (f64::LN_2, "LN_2", 5), + (f64::LOG10_E, "LOG10_E", 5), + (f64::LOG2_E, "LOG2_E", 5), + (f64::PI, "PI", 3), + (f64::SQRT_2, "SQRT_2", 5), ]; #[derive(Copy,Clone)] @@ -52,22 +52,41 @@ impl LateLintPass for ApproxConstant { fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { match lit.node { - LitFloat(ref str, TyF32) => check_known_consts(cx, e, str, "f32"), - LitFloat(ref str, TyF64) => check_known_consts(cx, e, str, "f64"), - LitFloatUnsuffixed(ref str) => - check_known_consts(cx, e, str, "f{32, 64}"), + LitFloat(ref s, TyF32) => check_known_consts(cx, e, s, "f32"), + LitFloat(ref s, TyF64) => check_known_consts(cx, e, s, "f64"), + LitFloatUnsuffixed(ref s) => + check_known_consts(cx, e, s, "f{32, 64}"), _ => () } } fn check_known_consts(cx: &LateContext, e: &Expr, s: &str, module: &str) { - if let Ok(value) = s.parse::<f64>() { - for &(name, lower_bound, upper_bound) in KNOWN_CONSTS { - if (value >= lower_bound) && (value < upper_bound) { + if let Ok(_) = s.parse::<f64>() { + for &(constant, name, min_digits) in KNOWN_CONSTS { + if is_approx_const(constant, s, min_digits) { span_lint(cx, APPROX_CONSTANT, e.span, &format!( "approximate value of `{}::{}` found. \ Consider using it directly", module, &name)); + return; } } } } + +/// Returns false if the number of significant figures in `value` are +/// less than `min_digits`; otherwise, returns true if `value` is equal +/// to `constant`, rounded to the number of digits present in `value`. +fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { + if value.len() <= min_digits { + false + } else { + let round_const = format!("{:.*}", value.len() - 2, constant); + + let mut trunc_const = constant.to_string(); + if trunc_const.len() > value.len() { + trunc_const.truncate(value.len()); + } + + (value == round_const) || (value == trunc_const) + } +} diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index ebd5d3ea139..148746bfa94 100755 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -42,7 +42,7 @@ fn main() { let my_ln_2 = 0.6931471805599453; //~ERROR approximate value of `f{32, 64}::LN_2` found let no_ln_2 = 0.693; - let my_log10_e = 0.43429448190325176; //~ERROR approximate value of `f{32, 64}::LOG10_E` found + let my_log10_e = 0.43429448190325182; //~ERROR approximate value of `f{32, 64}::LOG10_E` found let no_log10_e = 0.434; let my_log2_e = 1.4426950408889634; //~ERROR approximate value of `f{32, 64}::LOG2_E` found -- cgit 1.4.1-3-g733a5 From a91c618fed0ffdc0651768d148985c1594dc9de5 Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Mon, 26 Oct 2015 07:43:38 +0100 Subject: Fix reverse_range_loop not taking sign into account (fixes #409) Adds a Display impl for Constant, because that might come in handy elsewhere as well. --- src/consts.rs | 64 ++++++++++++++++++++++++++++++++++++++++++ src/loops.rs | 6 ++-- tests/compile-fail/for_loop.rs | 4 +++ 3 files changed, 71 insertions(+), 3 deletions(-) mode change 100644 => 100755 src/consts.rs (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs old mode 100644 new mode 100755 index be681efb257..766d998c256 --- a/src/consts.rs +++ b/src/consts.rs @@ -6,10 +6,12 @@ use rustc::middle::def::PathResolution; use rustc::middle::def::Def::*; use rustc_front::hir::*; use syntax::ptr::P; +use std::char; use std::cmp::PartialOrd; use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; +use std::fmt; use self::Constant::*; use self::FloatWidth::*; @@ -21,6 +23,7 @@ use syntax::ast::{UintTy, FloatTy, StrStyle}; use syntax::ast::UintTy::*; use syntax::ast::FloatTy::*; use syntax::ast::Sign::{self, Plus, Minus}; +use syntax::ast_util; #[derive(PartialEq, Eq, Debug, Copy, Clone)] @@ -159,6 +162,67 @@ impl PartialOrd for Constant { } } +fn format_byte(fmt: &mut fmt::Formatter, b: u8) -> fmt::Result { + if b == b'\\' { + write!(fmt, "\\\\") + } else if 0x20 <= b && b <= 0x7e { + write!(fmt, "{}", char::from_u32(b as u32).expect("all u8 are valid char")) + } else if b == 0x0a { + write!(fmt, "\\n") + } else if b == 0x0d { + write!(fmt, "\\r") + } else { + write!(fmt, "\\x{:02x}", b) + } +} + +impl fmt::Display for Constant { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + ConstantStr(ref s, _) => write!(fmt, "{:?}", s), + ConstantByte(ref b) => + write!(fmt, "b'").and_then(|_| format_byte(fmt, *b)) + .and_then(|_| write!(fmt, "'")), + ConstantBinary(ref bs) => { + try!(write!(fmt, "b\"")); + for b in bs.iter() { + try!(format_byte(fmt, *b)); + } + write!(fmt, "\"") + } + ConstantChar(ref c) => write!(fmt, "'{}'", c), + ConstantInt(ref i, ref ity) => { + let (sign, suffix) = match *ity { + LitIntType::SignedIntLit(ref sity, ref sign) => + (if let Sign::Minus = *sign { "-" } else { "" }, + ast_util::int_ty_to_string(*sity, None)), + LitIntType::UnsignedIntLit(ref uity) => + ("", ast_util::uint_ty_to_string(*uity, None)), + LitIntType::UnsuffixedIntLit(ref sign) => + (if let Sign::Minus = *sign { "-" } else { "" }, + "".into()), + }; + write!(fmt, "{}{}{}", sign, i, suffix) + } + ConstantFloat(ref s, ref fw) => { + let suffix = match *fw { + FloatWidth::Fw32 => "f32", + FloatWidth::Fw64 => "f64", + FloatWidth::FwAny => "", + }; + write!(fmt, "{}{}", s, suffix) + } + ConstantBool(ref b) => write!(fmt, "{}", b), + ConstantRepeat(ref c, ref n) => write!(fmt, "[{}; {}]", c, n), + ConstantVec(ref v) => write!(fmt, "[{}]", + v.iter().map(|i| format!("{}", i)) + .collect::<Vec<_>>().join(", ")), + ConstantTuple(ref t) => write!(fmt, "({})", + t.iter().map(|i| format!("{}", i)) + .collect::<Vec<_>>().join(", ")), + } + } +} fn lit_to_constant(lit: &Lit_) -> Constant { diff --git a/src/loops.rs b/src/loops.rs index 7d7c97f1bb1..95289cf347c 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -44,7 +44,7 @@ pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, + WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP, EMPTY_LOOP) } } @@ -88,8 +88,8 @@ impl LateLintPass for LoopsPass { // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { // ...and both sides are compile-time constant integers... - if let Some(Constant::ConstantInt(start_idx, _)) = constant_simple(start_expr) { - if let Some(Constant::ConstantInt(stop_idx, _)) = constant_simple(stop_expr) { + if let Some(start_idx @ Constant::ConstantInt(..)) = constant_simple(start_expr) { + if let Some(stop_idx @ Constant::ConstantInt(..)) = constant_simple(stop_expr) { // ...and the start index is greater than the stop index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 11810242a88..02c8cc56083 100755 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -46,6 +46,10 @@ fn main() { println!("{}", i); } + for i in -10..0 { // not an error + println!("{}", i); + } + for i in (10..0).rev() { // not an error, this is an established idiom for looping backwards on a range println!("{}", i); } -- cgit 1.4.1-3-g733a5 From f6163fce6120b6bde902d1fd8f862d80e67c0721 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Fri, 16 Oct 2015 20:27:13 +0200 Subject: Suggest for loop instead of while-let when looping over iterators --- README.md | 4 +++- src/lib.rs | 1 + src/loops.rs | 16 +++++++++++++++- tests/compile-fail/while_loop.rs | 19 ++++++++++++++++++- 4 files changed, 37 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index b37695f2f69..664fc0359bf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 68 lints included in this crate: +There are 69 lints included in this crate: +There are 65 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -74,6 +75,7 @@ name [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention [wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention [zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN diff --git a/src/lib.rs b/src/lib.rs index d5d27e5e2af..b84c1e2aab6 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::REVERSE_RANGE_LOOP, loops::UNUSED_COLLECT, loops::WHILE_LET_LOOP, + loops::WHILE_LET_ON_ITERATOR, matches::MATCH_BOOL, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, diff --git a/src/loops.rs b/src/loops.rs index 95289cf347c..6b6fbf60c4c 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -38,6 +38,8 @@ declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } +declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" } + #[derive(Copy, Clone)] pub struct LoopsPass; @@ -45,7 +47,8 @@ impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, - EXPLICIT_COUNTER_LOOP, EMPTY_LOOP) + EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, + WHILE_LET_ON_ITERATOR) } } @@ -228,6 +231,17 @@ impl LateLintPass for LoopsPass { } } } + if let ExprMatch(ref expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { + let pat = &arms[0].pats[0].node; + if let (&PatEnum(ref path, _), &ExprMethodCall(method_name, _, _)) = (pat, &expr.node) { + if method_name.node.as_str() == "next" && + match_trait_method(cx, expr, &["core", "iter", "Iterator"]) && + path.segments.last().unwrap().identifier.name.as_str() == "Some" { + span_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, + "this loop could be written as a `for` loop"); + } + } + } } fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index a056fe249b5..efd77a6d9c3 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(while_let_loop, empty_loop)] +#![deny(while_let_loop, empty_loop, while_let_on_iterator)] #![allow(dead_code, unused)] fn main() { @@ -53,6 +53,23 @@ fn main() { while let Some(x) = y { // no error, obviously println!("{}", x); } + + + while let Option::Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop + println!("{}", x); + } + + while let Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop + println!("{}", x); + } + + while let Some(_) = (1..20).next() {} //~ERROR this loop could be written as a `for` loop + + while let None = (1..20).next() {} // this is fine (if nonsensical) + + if let Some(x) = (1..20).next() { // also fine + println!("{}", x) + } } // regression test (#360) -- cgit 1.4.1-3-g733a5 From 659e7c1d5efa79394695c62375ef6860ab37aa67 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Tue, 20 Oct 2015 01:04:21 +0200 Subject: Don't suggest using a for loop if the iterator is used in the loop body Due to https://github.com/rust-lang/rust/issues/8372, we have to use while-let in these cases. --- src/loops.rs | 33 +++++++++++++++++++++++++++++++-- tests/compile-fail/while_loop.rs | 10 ++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 6b6fbf60c4c..04a2350db6b 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -232,11 +232,14 @@ impl LateLintPass for LoopsPass { } } if let ExprMatch(ref expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { + let body = &arms[0].body; let pat = &arms[0].pats[0].node; - if let (&PatEnum(ref path, _), &ExprMethodCall(method_name, _, _)) = (pat, &expr.node) { + if let (&PatEnum(ref path, _), &ExprMethodCall(method_name, _, ref args)) = (pat, &expr.node) { + let iterator_def_id = var_def_id(cx, &args[0]); if method_name.node.as_str() == "next" && match_trait_method(cx, expr, &["core", "iter", "Iterator"]) && - path.segments.last().unwrap().identifier.name.as_str() == "Some" { + path.segments.last().unwrap().identifier.name.as_str() == "Some" && + !var_used(body, iterator_def_id, cx) { span_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, "this loop could be written as a `for` loop"); } @@ -314,6 +317,32 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { } } +fn var_used(expr: &Expr, def_id: Option<NodeId>, cx: &LateContext) -> bool { + match def_id { + None => false, + Some(def_id) => { + let mut visitor = VarUsedVisitor{ def_id: def_id, found: false, cx: cx }; + walk_expr(&mut visitor, expr); + visitor.found + } + } +} + +struct VarUsedVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, + def_id: NodeId, + found: bool +} + +impl<'v, 't> Visitor<'v> for VarUsedVisitor<'v, 't> { + fn visit_expr(&mut self, expr: &'v Expr) { + if Some(self.def_id) == var_def_id(self.cx, expr) { + self.found = true; + } + walk_expr(self, expr); + } +} + /// Return true if the type of expr is one that provides IntoIterator impls /// for &T and &mut T, such as Vec. fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index efd77a6d9c3..ae2f6995061 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -70,6 +70,16 @@ fn main() { if let Some(x) = (1..20).next() { // also fine println!("{}", x) } + + // the following shouldn't warn because it can't be written with a for loop + let mut iter = 1u32..20; + while let Some(x) = iter.next() { + println!("next: {:?}", iter.next()) + } + + // but this should: + let mut iter2 = 1u32..20; + while let Some(x) = iter2.next() { } //~ERROR this loop could be written as a `for` loop } // regression test (#360) -- cgit 1.4.1-3-g733a5 From 8626ac1fd40f70e18857b4b8c143c522def544f1 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 22 Oct 2015 23:16:58 +0200 Subject: Fixes for code review comments * remove weird infinite loops from compile-tests * remove call to Option::unwrap * in the lint message, show while-let loop rewritten as for loop --- src/loops.rs | 27 ++++++++++++++++++--------- tests/compile-fail/while_loop.rs | 20 ++++++++++---------- 2 files changed, 28 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 04a2350db6b..bf64ec5b132 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -231,17 +231,26 @@ impl LateLintPass for LoopsPass { } } } - if let ExprMatch(ref expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { + if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { let body = &arms[0].body; let pat = &arms[0].pats[0].node; - if let (&PatEnum(ref path, _), &ExprMethodCall(method_name, _, ref args)) = (pat, &expr.node) { - let iterator_def_id = var_def_id(cx, &args[0]); - if method_name.node.as_str() == "next" && - match_trait_method(cx, expr, &["core", "iter", "Iterator"]) && - path.segments.last().unwrap().identifier.name.as_str() == "Some" && - !var_used(body, iterator_def_id, cx) { - span_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, - "this loop could be written as a `for` loop"); + if let (&PatEnum(ref path, Some(ref pat_args)), + &ExprMethodCall(method_name, _, ref method_args)) = + (pat, &match_expr.node) { + let iterator_def_id = var_def_id(cx, &method_args[0]); + if let Some(lhs_constructor) = path.segments.last() { + if method_name.node.as_str() == "next" && + match_trait_method(cx, match_expr, &["core", "iter", "Iterator"]) && + lhs_constructor.identifier.name.as_str() == "Some" && + !var_used(body, iterator_def_id, cx) { + let iterator = snippet(cx, method_args[0].span, "_"); + let loop_var = snippet(cx, pat_args[0].span, "_"); + span_help_and_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, + "this loop could be written as a `for` loop", + &format!("try\nfor {} in {} {{...}}", + loop_var, + iterator)); + } } } } diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index ae2f6995061..334ddd346a2 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -54,20 +54,24 @@ fn main() { println!("{}", x); } - - while let Option::Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop + let mut iter = 1..20; + while let Option::Some(x) = iter.next() { //~ERROR this loop could be written as a `for` loop println!("{}", x); } - while let Some(x) = (1..20).next() { //~ERROR this loop could be written as a `for` loop + let mut iter = 1..20; + while let Some(x) = iter.next() { //~ERROR this loop could be written as a `for` loop println!("{}", x); } - while let Some(_) = (1..20).next() {} //~ERROR this loop could be written as a `for` loop + let mut iter = 1..20; + while let Some(_) = iter.next() {} //~ERROR this loop could be written as a `for` loop - while let None = (1..20).next() {} // this is fine (if nonsensical) + let mut iter = 1..20; + while let None = iter.next() {} // this is fine (if nonsensical) - if let Some(x) = (1..20).next() { // also fine + let mut iter = 1..20; + if let Some(x) = iter.next() { // also fine println!("{}", x) } @@ -76,10 +80,6 @@ fn main() { while let Some(x) = iter.next() { println!("next: {:?}", iter.next()) } - - // but this should: - let mut iter2 = 1u32..20; - while let Some(x) = iter2.next() { } //~ERROR this loop could be written as a `for` loop } // regression test (#360) -- cgit 1.4.1-3-g733a5 From 5ca7ebb6d271c593605e03046abbd3a3849036b3 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Mon, 26 Oct 2015 23:49:37 +0100 Subject: Fix false positives when iterator variable is used after the loop --- src/loops.rs | 48 ++++++++++++++++++++++++++-------------- src/utils.rs | 13 +++++++++++ tests/compile-fail/while_loop.rs | 17 ++++++++++++++ 3 files changed, 61 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index bf64ec5b132..d056c67c541 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -11,7 +11,8 @@ use std::collections::{HashSet,HashMap}; use syntax::ast::Lit_::*; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, - in_external_macro, expr_block, span_help_and_lint, is_integer_literal}; + in_external_macro, expr_block, span_help_and_lint, is_integer_literal, + get_enclosing_block}; use utils::{VEC_PATH, LL_PATH}; declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, @@ -232,17 +233,16 @@ impl LateLintPass for LoopsPass { } } if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { - let body = &arms[0].body; let pat = &arms[0].pats[0].node; if let (&PatEnum(ref path, Some(ref pat_args)), &ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) { - let iterator_def_id = var_def_id(cx, &method_args[0]); + 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, &["core", "iter", "Iterator"]) && lhs_constructor.identifier.name.as_str() == "Some" && - !var_used(body, iterator_def_id, cx) { + !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_help_and_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, @@ -326,32 +326,46 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { } } -fn var_used(expr: &Expr, def_id: Option<NodeId>, cx: &LateContext) -> bool { - match def_id { - None => false, - Some(def_id) => { - let mut visitor = VarUsedVisitor{ def_id: def_id, found: false, cx: cx }; - walk_expr(&mut visitor, expr); - visitor.found - } +fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { + let def_id = match var_def_id(cx, iter_expr) { + Some(id) => id, + None => return false + }; + let mut visitor = VarUsedAfterLoopVisitor { + cx: cx, + def_id: def_id, + iter_expr_id: iter_expr.id, + past_while_let: false, + var_used_after_while_let: false + }; + if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { + walk_block(&mut visitor, enclosing_block); } + visitor.var_used_after_while_let } -struct VarUsedVisitor<'v, 't: 'v> { +struct VarUsedAfterLoopVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, def_id: NodeId, - found: bool + iter_expr_id: NodeId, + past_while_let: bool, + var_used_after_while_let: bool } -impl<'v, 't> Visitor<'v> for VarUsedVisitor<'v, 't> { +impl <'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { fn visit_expr(&mut self, expr: &'v Expr) { - if Some(self.def_id) == var_def_id(self.cx, expr) { - self.found = true; + if self.past_while_let { + if Some(self.def_id) == var_def_id(self.cx, expr) { + self.var_used_after_while_let = true; + } + } else if self.iter_expr_id == expr.id { + self.past_while_let = true; } walk_expr(self, expr); } } + /// Return true if the type of expr is one that provides IntoIterator impls /// for &T and &mut T, such as Vec. fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { diff --git a/src/utils.rs b/src/utils.rs index 80b8c88361a..73b641b644e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -255,6 +255,19 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if let NodeExpr(parent) = node { Some(parent) } else { None } ) } +pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { + let map = &cx.tcx.map; + let enclosing_node = map.get_enclosing_scope(node) + .and_then(|enclosing_id| map.find(enclosing_id)); + if let Some(node) = enclosing_node { + match node { + NodeBlock(ref block) => Some(block), + NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), + _ => None + } + } else { None } +} + #[cfg(not(feature="structured_logging"))] pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { cx.span_lint(lint, sp, msg); diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index 334ddd346a2..7d1904ad446 100755 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -80,6 +80,23 @@ fn main() { while let Some(x) = iter.next() { println!("next: {:?}", iter.next()) } + + // neither can this + let mut iter = 1u32..20; + while let Some(x) = iter.next() { + println!("next: {:?}", iter.next()); + } + + // or this + let mut iter = 1u32..20; + while let Some(x) = iter.next() {break;} + println!("Remaining iter {:?}", iter); + + // or this + let mut iter = 1u32..20; + while let Some(x) = iter.next() { + iter = 1..20; + } } // regression test (#360) -- cgit 1.4.1-3-g733a5 From c5b6fda399644147c9a002109a4be1ac9508e9ec Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Tue, 27 Oct 2015 18:28:36 +0100 Subject: Allow needless_lifetime to pass dogfood.sh --- src/utils.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 73b641b644e..7cbb532cf22 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -255,6 +255,7 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if let NodeExpr(parent) = node { Some(parent) } else { None } ) } +#[allow(needless_lifetimes)] // workaround for https://github.com/Manishearth/rust-clippy/issues/417 pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { let map = &cx.tcx.map; let enclosing_node = map.get_enclosing_scope(node) -- cgit 1.4.1-3-g733a5 From 8e4c2171d24a3f43a5f6d7af3c15efb6d1d56803 Mon Sep 17 00:00:00 2001 From: wartman4404 <wartman4404@my.mstc.edu> Date: Wed, 28 Oct 2015 22:26:48 -0500 Subject: Don't show single_match if match_bool also applies --- src/matches.rs | 6 ++++-- tests/compile-fail/matches.rs | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index a7cfefd7af5..fb000c24364 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -39,8 +39,10 @@ impl LateLintPass for MatchPass { // but in some cases, an explicit match is preferred to catch situations // when an enum is extended, so we don't consider these cases arms[1].pats[0].node == PatWild(PatWildSingle) && - // finally, we don't want any content in the second arm (unit or empty block) - is_unit_expr(&arms[1].body) + // we don't want any content in the second arm (unit or empty block) + is_unit_expr(&arms[1].body) && + // finally, MATCH_BOOL doesn't apply here + (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) { span_help_and_lint(cx, SINGLE_MATCH, expr.span, "you seem to be trying to use match for destructuring a \ diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index f0cc650f753..ff92a67271b 100755 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -58,8 +58,6 @@ fn match_bool() { }; match test { //~ ERROR you seem to be trying to match on a boolean expression - //~^ERROR you seem to be trying to use match - //TODO: Remove duplicate warning false => { println!("Noooo!"); }, _ => (), }; -- cgit 1.4.1-3-g733a5 From 0fe5981870b4588d3412a31acec18cd5a12269fe Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Thu, 29 Oct 2015 01:50:00 +0900 Subject: New lint for statement with no effect --- README.md | 3 +- src/lib.rs | 3 ++ src/no_effect.rs | 61 +++++++++++++++++++++++++++++++++++ tests/compile-fail/needless_update.rs | 1 + tests/compile-fail/no_effect.rs | 39 ++++++++++++++++++++++ tests/compile-fail/unit_cmp.rs | 1 + 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/no_effect.rs create mode 100644 tests/compile-fail/no_effect.rs (limited to 'src') diff --git a/README.md b/README.md index c602edca7df..29eb6750d16 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 69 lints included in this crate: +There are 70 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -46,6 +46,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` diff --git a/src/lib.rs b/src/lib.rs index b84c1e2aab6..60ab18566b8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,7 @@ pub mod zero_div_zero; pub mod open_options; pub mod needless_features; pub mod needless_update; +pub mod no_effect; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -98,6 +99,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); + reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -159,6 +161,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, + no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/no_effect.rs b/src/no_effect.rs new file mode 100644 index 00000000000..82fcf92fd4c --- /dev/null +++ b/src/no_effect.rs @@ -0,0 +1,61 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::middle::def::{DefStruct, DefVariant}; +use rustc_front::hir::{Expr, ExprCall, ExprLit, ExprPath, ExprStruct}; +use rustc_front::hir::{Stmt, StmtSemi}; + +use utils::in_macro; +use utils::span_lint; + +declare_lint! { + pub NO_EFFECT, + Warn, + "statements with no effect" +} + +fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { + if in_macro(cx, expr.span) { + return false; + } + match expr.node { + ExprLit(..) | + ExprPath(..) => true, + ExprStruct(_, ref fields, ref base) => { + fields.iter().all(|field| has_no_effect(cx, &field.expr)) && + match *base { + Some(ref base) => has_no_effect(cx, base), + None => true, + } + } + ExprCall(ref callee, ref args) => { + let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); + match def { + Some(DefStruct(..)) | + Some(DefVariant(..)) => { + args.iter().all(|arg| has_no_effect(cx, arg)) + } + _ => false, + } + } + _ => false, + } +} + +#[derive(Copy, Clone)] +pub struct NoEffectPass; + +impl LintPass for NoEffectPass { + fn get_lints(&self) -> LintArray { + lint_array!(NO_EFFECT) + } +} + +impl LateLintPass for NoEffectPass { + fn check_stmt(&mut self, cx: &LateContext, stmt: &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"); + } + } + } +} diff --git a/tests/compile-fail/needless_update.rs b/tests/compile-fail/needless_update.rs index 55438d9d90a..55cfed76d5d 100644 --- a/tests/compile-fail/needless_update.rs +++ b/tests/compile-fail/needless_update.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(needless_update)] +#![allow(no_effect)] struct S { pub a: i32, diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs new file mode 100644 index 00000000000..8da119eb16d --- /dev/null +++ b/tests/compile-fail/no_effect.rs @@ -0,0 +1,39 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(no_effect)] +#![allow(dead_code)] +#![allow(path_statements)] + +struct Unit; +struct Tuple(i32); +struct Struct { + field: i32 +} +enum Enum { + TupleVariant(i32), + StructVariant { field: i32 }, +} + +fn get_number() -> i32 { 0 } +fn get_struct() -> Struct { Struct { field: 0 } } + +fn main() { + let s = get_struct(); + + 0; //~ERROR statement with no effect + Unit; //~ERROR statement with no effect + Tuple(0); //~ERROR statement with no effect + Struct { field: 0 }; //~ERROR statement with no effect + Struct { ..s }; //~ERROR statement with no effect + Enum::TupleVariant(0); //~ERROR statement with no effect + Enum::StructVariant { field: 0 }; //~ERROR statement with no effect + + // Do not warn + get_number(); + Tuple(get_number()); + Struct { field: get_number() }; + Struct { ..get_struct() }; + Enum::TupleVariant(get_number()); + Enum::StructVariant { field: get_number() }; +} diff --git a/tests/compile-fail/unit_cmp.rs b/tests/compile-fail/unit_cmp.rs index af28f849e8c..1a28953ace1 100755 --- a/tests/compile-fail/unit_cmp.rs +++ b/tests/compile-fail/unit_cmp.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(unit_cmp)] +#![allow(no_effect)] #[derive(PartialEq)] pub struct ContainsUnit(()); // should be fine -- cgit 1.4.1-3-g733a5 From dbb8a872a3aea4bb9510d109f5f7dbe5273446da Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 31 Oct 2015 05:18:05 +0530 Subject: Fix ptr-arg false positive for trait impls Fixes #425 --- src/ptr_arg.rs | 10 ++++++++-- tests/compile-fail/ptr_arg.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 4baba711886..78a3c146c0f 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -5,6 +5,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; +use rustc::front::map::Node; use utils::{span_lint, match_type}; use utils::{STRING_PATH, VEC_PATH}; @@ -34,6 +35,11 @@ impl LateLintPass for PtrArg { fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let &MethodImplItem(ref sig, _) = &item.node { + if let Some(Node::NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { + if let ItemImpl(_, _, _, Some(_), _, _) = it.node { + return; // ignore trait impls + } + } check_fn(cx, &sig.decl); } } @@ -47,8 +53,8 @@ impl LateLintPass for PtrArg { fn check_fn(cx: &LateContext, decl: &FnDecl) { for arg in &decl.inputs { - if let Some(pat_ty) = cx.tcx.pat_ty_opt(&arg.pat) { - if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = pat_ty.sty { + if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&arg.ty.id) { + if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { if match_type(cx, ty, &VEC_PATH) { span_lint(cx, PTR_ARG, arg.ty.span, "writing `&Vec<_>` instead of `&[_]` involves one more reference \ diff --git a/tests/compile-fail/ptr_arg.rs b/tests/compile-fail/ptr_arg.rs index d0615be492b..e4971208747 100755 --- a/tests/compile-fail/ptr_arg.rs +++ b/tests/compile-fail/ptr_arg.rs @@ -21,3 +21,18 @@ fn do_str_mut(x: &mut String) { // no error here fn main() { } + +trait Foo { + type Item; + fn do_vec(x: &Vec<i64>); //~ERROR writing `&Vec<_>` + fn do_item(x: &Self::Item); +} + +struct Bar; + +// no error, in trait impl (#425) +impl Foo for Bar { + type Item = Vec<u8>; + fn do_vec(x: &Vec<i64>) {} + fn do_item(x: &Vec<u8>) {} +} -- cgit 1.4.1-3-g733a5 From d28b8e169fc9f722aa32dc16a21be137587316ef Mon Sep 17 00:00:00 2001 From: Nathan Weston <nweston@fastmail.com> Date: Tue, 3 Nov 2015 09:42:52 -0500 Subject: New lint for zip with array length instead of enumerate() Fixes #11. --- README.md | 3 ++- src/lib.rs | 1 + src/ranges.rs | 37 ++++++++++++++++++++++++++++++++++--- tests/compile-fail/range.rs | 7 ++++++- 4 files changed, 43 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 29eb6750d16..0da037e7b16 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 70 lints included in this crate: +There are 71 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -53,6 +53,7 @@ name [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [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 [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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled diff --git a/src/lib.rs b/src/lib.rs index 60ab18566b8..525603dc2b8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,6 +166,7 @@ pub fn plugin_registrar(reg: &mut Registry) { precedence::PRECEDENCE, ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, + ranges::RANGE_ZIP_WITH_LEN, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, types::BOX_VEC, diff --git a/src/ranges.rs b/src/ranges.rs index 2ef272237d1..39ff7d3cd31 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,19 +1,23 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::{match_type, is_integer_literal}; +use utils::{is_integer_literal, match_type, snippet}; declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, "using Range::step_by(0), which produces an infinite iterator" } +declare_lint! { + pub RANGE_ZIP_WITH_LEN, Warn, + "zipping iterator with a range when enumerate() would do" +} #[derive(Copy,Clone)] pub struct StepByZero; impl LintPass for StepByZero { fn get_lints(&self) -> LintArray { - lint_array!(RANGE_STEP_BY_ZERO) + lint_array!(RANGE_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN) } } @@ -21,13 +25,40 @@ impl LateLintPass for StepByZero { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { - // Only warn on literal ranges. + // Range with step_by(0). if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, "Range::step_by(0) produces an infinite iterator. \ Consider using `std::iter::repeat()` instead") } + + // x.iter().zip(0..x.len()) + else if name.as_str() == "zip" && args.len() == 2 { + let iter = &args[0].node; + let zip_arg = &args[1].node; + if_let_chain! { + [ + // .iter() call + let &ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = iter, + iter_name.as_str() == "iter", + // range expression in .zip() call: 0..x.len() + let &ExprRange(Some(ref from), Some(ref to)) = zip_arg, + is_integer_literal(from, 0), + // .len() call + let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = to.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 + ], { + cx.span_lint(RANGE_ZIP_WITH_LEN, expr.span, + &format!("It is more idiomatic to use {}.iter().enumerate()", + snippet(cx, iter_args[0].span, "_"))); + } + } + } } } } diff --git a/tests/compile-fail/range.rs b/tests/compile-fail/range.rs index 324f129fafa..2d731670cbe 100644 --- a/tests/compile-fail/range.rs +++ b/tests/compile-fail/range.rs @@ -7,7 +7,7 @@ impl NotARange { fn step_by(&self, _: u32) {} } -#[deny(range_step_by_zero)] +#[deny(range_step_by_zero, range_zip_with_len)] fn main() { (0..1).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator // No warning for non-zero step @@ -21,4 +21,9 @@ fn main() { // No error, not a range. let y = NotARange; y.step_by(0); + + let _v1 = vec![1,2,3]; + let _v2 = vec![4,5]; + let _x = _v1.iter().zip(0.._v1.len()); //~ERROR It is more idiomatic to use _v1.iter().enumerate() + let _y = _v1.iter().zip(0.._v2.len()); // No error } -- cgit 1.4.1-3-g733a5 From 414c0d20f746c2e3852c8a5356b8831176c915f6 Mon Sep 17 00:00:00 2001 From: wartman4404 <wartman4404@my.mstc.edu> Date: Fri, 30 Oct 2015 23:58:37 -0500 Subject: New lint for using `.cloned()` --- README.md | 1 + src/lib.rs | 3 ++ src/map_clone.rs | 102 ++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/map_clone.rs | 69 +++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 src/map_clone.rs create mode 100644 tests/compile-fail/map_clone.rs (limited to 'src') diff --git a/README.md b/README.md index 0da037e7b16..fcfeca1509e 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ name [let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant diff --git a/src/lib.rs b/src/lib.rs index 525603dc2b8..37e1ace61de 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ pub mod returns; pub mod lifetimes; pub mod loops; pub mod ranges; +pub mod map_clone; pub mod matches; pub mod precedence; pub mod mutex_atomic; @@ -100,6 +101,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); reg.register_late_lint_pass(box no_effect::NoEffectPass); + reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -141,6 +143,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::UNUSED_COLLECT, loops::WHILE_LET_LOOP, loops::WHILE_LET_ON_ITERATOR, + map_clone::MAP_CLONE, matches::MATCH_BOOL, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, diff --git a/src/map_clone.rs b/src/map_clone.rs new file mode 100644 index 00000000000..570ee91dd7b --- /dev/null +++ b/src/map_clone.rs @@ -0,0 +1,102 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::ast::Ident; +use utils::OPTION_PATH; +use utils::{match_trait_method, match_type, snippet, span_help_and_lint}; +use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; + +declare_lint!(pub MAP_CLONE, Warn, + "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ + `.cloned()` instead)"); + +#[derive(Copy, Clone)] +pub struct MapClonePass; + +impl LateLintPass for MapClonePass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! { + [ + // call to .map() + let ExprMethodCall(name, _, ref args) = expr.node, + name.node.as_str() == "map" && args.len() == 2, + let ExprClosure(_, ref decl, ref blk) = args[1].node, + // just one expression in the closure + blk.stmts.is_empty(), + let Some(ref closure_expr) = blk.expr, + // nothing special in the argument, besides reference bindings + // (e.g. .map(|&x| x) ) + let Some(arg_ident) = get_arg_name(&*decl.inputs[0].pat), + // the method is being called on a known type (option or iterator) + let Some(type_name) = get_type_name(cx, expr, &args[0]) + ], { + // look for derefs, for .map(|x| *x) + if only_derefs(&*closure_expr, arg_ident) && + // .cloned() only removes one level of indirection, don't lint on more + walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + // explicit clone() calls ( .map(|x| x.clone()) ) + else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { + if clone_call.node.as_str() == "clone" && + clone_args.len() == 1 && + match_trait_method(cx, closure_expr, &["core", "clone", "Clone"]) && + expr_eq_ident(&clone_args[0], arg_ident) + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + } + } + } + } +} + +fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { + match expr.node { + ExprPath(None, ref path) => { + let arg_segment = [PathSegment { identifier: id, parameters: PathParameters::none() }]; + !path.global && path.segments == arg_segment + }, + _ => false, + } +} + +fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { + if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + Some("iterator") + } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &OPTION_PATH) { + Some("Option") + } else { + None + } +} + +fn get_arg_name(pat: &Pat) -> Option<Ident> { + match pat.node { + PatIdent(_, ident, None) => Some(ident.node), + PatRegion(ref subpat, _) => get_arg_name(subpat), + _ => None, + } +} + +fn only_derefs(expr: &Expr, id: Ident) -> bool { + if expr_eq_ident(expr, id) { + true + } else if let ExprUnary(UnDeref, ref subexpr) = expr.node { + only_derefs(subexpr, id) + } else { + false + } +} + +impl LintPass for MapClonePass { + fn get_lints(&self) -> LintArray { + lint_array!(MAP_CLONE) + } +} diff --git a/tests/compile-fail/map_clone.rs b/tests/compile-fail/map_clone.rs new file mode 100644 index 00000000000..9d9f253defe --- /dev/null +++ b/tests/compile-fail/map_clone.rs @@ -0,0 +1,69 @@ +#![feature(plugin)] + +#![plugin(clippy)] +#![deny(map_clone)] + +#![allow(unused)] + +fn map_clone_iter() { + let x = [1,2,3]; + x.iter().map(|y| y.clone()); //~ ERROR you seem to be using .map() + //~^ HELP try + x.iter().map(|&y| y); //~ ERROR you seem to be using .map() + //~^ HELP try + x.iter().map(|y| *y); //~ ERROR you seem to be using .map() + //~^ HELP try +} + +fn map_clone_option() { + let x = Some(4); + x.as_ref().map(|y| y.clone()); //~ ERROR you seem to be using .map() + //~^ HELP try + x.as_ref().map(|&y| y); //~ ERROR you seem to be using .map() + //~^ HELP try + x.as_ref().map(|y| *y); //~ ERROR you seem to be using .map() + //~^ HELP try +} + +fn not_linted_option() { + let x = Some(5); + + // Not linted: other statements + x.as_ref().map(|y| { + println!("y: {}", y); + y.clone() + }); + + // Not linted: argument bindings + let x = Some((6, 7)); + x.map(|(y, _)| y.clone()); + + // Not linted: cloning something else + x.map(|y| y.0.clone()); + + // Not linted: no dereferences + x.map(|y| y); + + // Not linted: multiple dereferences + let _: Option<(i32, i32)> = x.as_ref().as_ref().map(|&&x| x); +} + +#[derive(Copy, Clone)] +struct Wrapper<T>(T); +impl<T> Wrapper<T> { + fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Wrapper<U> { + Wrapper(f(self.0)) + } +} + +fn map_clone_other() { + let eight = 8; + let x = Wrapper(&eight); + + // Not linted: not a linted type + x.map(|y| y.clone()); + x.map(|&y| y); + x.map(|y| *y); +} + +fn main() { } -- cgit 1.4.1-3-g733a5 From 764eedd0508a53b5184741bd05b8d20ea1034c42 Mon Sep 17 00:00:00 2001 From: wartman4404 <wartman4404@my.mstc.edu> Date: Tue, 3 Nov 2015 21:11:40 -0600 Subject: check for Deref conversions --- README.md | 2 +- src/eta_reduction.rs | 6 +----- src/map_clone.rs | 17 ++++++++--------- src/utils.rs | 4 ++++ tests/compile-fail/map_clone.rs | 23 +++++++++++++++++++++++ 5 files changed, 37 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index fcfeca1509e..4c23d6994d2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 71 lints included in this crate: +There are 72 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 7226a4bad05..855ea51ee8e 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; -use utils::{snippet, span_lint}; +use utils::{snippet, span_lint, is_adjusted}; #[allow(missing_copy_implementations)] @@ -32,10 +32,6 @@ impl LateLintPass for EtaPass { } } -fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { - cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() -} - fn check_closure(cx: &LateContext, expr: &Expr) { if let ExprClosure(_, ref decl, ref blk) = expr.node { if !blk.stmts.is_empty() { diff --git a/src/map_clone.rs b/src/map_clone.rs index 570ee91dd7b..e93a8221145 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::Ident; use utils::OPTION_PATH; -use utils::{match_trait_method, match_type, snippet, span_help_and_lint}; +use utils::{is_adjusted, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; declare_lint!(pub MAP_CLONE, Warn, @@ -30,7 +30,7 @@ impl LateLintPass for MapClonePass { let Some(type_name) = get_type_name(cx, expr, &args[0]) ], { // look for derefs, for .map(|x| *x) - if only_derefs(&*closure_expr, arg_ident) && + if only_derefs(cx, &*closure_expr, arg_ident) && // .cloned() only removes one level of indirection, don't lint on more walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 { @@ -85,13 +85,12 @@ fn get_arg_name(pat: &Pat) -> Option<Ident> { } } -fn only_derefs(expr: &Expr, id: Ident) -> bool { - if expr_eq_ident(expr, id) { - true - } else if let ExprUnary(UnDeref, ref subexpr) = expr.node { - only_derefs(subexpr, id) - } else { - false +fn only_derefs(cx: &LateContext, expr: &Expr, id: Ident) -> bool { + match expr.node { + ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => { + only_derefs(cx, subexpr, id) + }, + _ => expr_eq_ident(expr, id), } } diff --git a/src/utils.rs b/src/utils.rs index 7cbb532cf22..757d7bc379d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -347,6 +347,10 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool false } +pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { + cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() +} + /// Produce a nested chain of if-lets and ifs from the patterns: /// /// if_let_chain! { diff --git a/tests/compile-fail/map_clone.rs b/tests/compile-fail/map_clone.rs index 9d9f253defe..f6241114a83 100644 --- a/tests/compile-fail/map_clone.rs +++ b/tests/compile-fail/map_clone.rs @@ -5,6 +5,8 @@ #![allow(unused)] +use std::ops::Deref; + fn map_clone_iter() { let x = [1,2,3]; x.iter().map(|y| y.clone()); //~ ERROR you seem to be using .map() @@ -66,4 +68,25 @@ fn map_clone_other() { x.map(|y| *y); } +#[derive(Copy, Clone)] +struct UnusualDeref; +static NINE: i32 = 9; + +impl Deref for UnusualDeref { + type Target = i32; + fn deref(&self) -> &i32 { &NINE } +} + +fn map_clone_deref() { + let x = Some(UnusualDeref); + let _: Option<UnusualDeref> = x.as_ref().map(|y| *y); //~ ERROR you seem to be using .map() + //~^ HELP try + + // Not linted: using deref conversion + let _: Option<i32> = x.map(|y| *y); + + // Not linted: using regular deref but also deref conversion + let _: Option<i32> = x.as_ref().map(|y| **y); +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 3322ffa8a048ef5369d3cdd914869fdf383473a4 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Wed, 4 Nov 2015 18:55:14 +0900 Subject: New lint for assignment to temporary --- README.md | 3 +- src/lib.rs | 3 ++ src/temporary_assignment.rs | 44 ++++++++++++++++++++++++++++++ tests/compile-fail/temporary_assignment.rs | 36 ++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/temporary_assignment.rs create mode 100644 tests/compile-fail/temporary_assignment.rs (limited to 'src') diff --git a/README.md b/README.md index 4c23d6994d2..5a2ea945349 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 72 lints included in this crate: +There are 73 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -68,6 +68,7 @@ name [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op +[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) diff --git a/src/lib.rs b/src/lib.rs index 37e1ace61de..970a244e2cd 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,7 @@ pub mod open_options; pub mod needless_features; pub mod needless_update; pub mod no_effect; +pub mod temporary_assignment; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -102,6 +103,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); + reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -172,6 +174,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_ZIP_WITH_LEN, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, + temporary_assignment::TEMPORARY_ASSIGNMENT, types::BOX_VEC, types::LET_UNIT_VALUE, types::LINKEDLIST, diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs new file mode 100644 index 00000000000..6cfcb711ff7 --- /dev/null +++ b/src/temporary_assignment.rs @@ -0,0 +1,44 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; + +use utils::is_adjusted; +use utils::span_lint; + +declare_lint! { + pub TEMPORARY_ASSIGNMENT, + Warn, + "assignments to temporaries" +} + +fn is_temporary(expr: &Expr) -> bool { + match expr.node { + ExprStruct(..) | + ExprTup(..) => true, + _ => false, + } +} + +#[derive(Copy, Clone)] +pub struct TemporaryAssignmentPass; + +impl LintPass for TemporaryAssignmentPass { + fn get_lints(&self) -> LintArray { + lint_array!(TEMPORARY_ASSIGNMENT) + } +} + +impl LateLintPass for TemporaryAssignmentPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprAssign(ref target, _) = expr.node { + match target.node { + ExprField(ref base, _) | ExprTupField(ref base, _) => { + if is_temporary(base) && !is_adjusted(cx, base) { + span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, + "assignment to temporary"); + } + } + _ => () + } + } + } +} diff --git a/tests/compile-fail/temporary_assignment.rs b/tests/compile-fail/temporary_assignment.rs new file mode 100644 index 00000000000..b1c2b990024 --- /dev/null +++ b/tests/compile-fail/temporary_assignment.rs @@ -0,0 +1,36 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(temporary_assignment)] + +use std::ops::{Deref, DerefMut}; + +struct Struct { + field: i32 +} + +struct Wrapper<'a> { + inner: &'a mut Struct +} + +impl<'a> Deref for Wrapper<'a> { + type Target = Struct; + fn deref(&self) -> &Struct { self.inner } +} + +impl<'a> DerefMut for Wrapper<'a> { + fn deref_mut(&mut self) -> &mut Struct { self.inner } +} + +fn main() { + let mut s = Struct { field: 0 }; + let mut t = (0, 0); + + Struct { field: 0 }.field = 1; //~ERROR assignment to temporary + (0, 0).0 = 1; //~ERROR assignment to temporary + + // no error + s.field = 1; + t.0 = 1; + Wrapper { inner: &mut s }.field = 1; +} -- cgit 1.4.1-3-g733a5 From c7df4bd0008bb8aad4373457995f56dde861fb8a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 5 Nov 2015 08:20:28 +0530 Subject: Rustup to rustc 1.6.0-nightly (effcd2965 2015-11-04) fixes #437 --- Cargo.toml | 2 +- src/matches.rs | 2 +- src/misc.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 4091a6b1caf..f9eceabfc85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.22" +version = "0.0.23" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/matches.rs b/src/matches.rs index fb000c24364..eaa3e0026a3 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -38,7 +38,7 @@ impl LateLintPass for MatchPass { // since the exhaustiveness check will ensure the last one is a catch-all, // but in some cases, an explicit match is preferred to catch situations // when an enum is extended, so we don't consider these cases - arms[1].pats[0].node == PatWild(PatWildSingle) && + arms[1].pats[0].node == PatWild && // we don't want any content in the second arm (unit or empty block) is_unit_expr(&arms[1].body) && // finally, MATCH_BOOL doesn't apply here diff --git a/src/misc.rs b/src/misc.rs index 497bb6692c7..01ecb2c2cf8 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -252,7 +252,7 @@ impl LintPass for PatternPass { impl LateLintPass for PatternPass { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatIdent(_, ref ident, Some(ref right)) = pat.node { - if right.node == PatWild(PatWildSingle) { + if right.node == PatWild { cx.span_lint(REDUNDANT_PATTERN, pat.span, &format!( "the `{} @ _` pattern can be written as just `{}`", ident.node.name, ident.node.name)); -- cgit 1.4.1-3-g733a5 From a0cd8fc9437a9cc1ccb2a8d27f7c00c9fc9575c7 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 5 Nov 2015 17:11:41 +0100 Subject: match .map(Clone::clone) --- src/map_clone.rs | 91 ++++++++++++++++++++++++----------------- src/utils.rs | 1 + tests/compile-fail/map_clone.rs | 2 + 3 files changed, 56 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/map_clone.rs b/src/map_clone.rs index e93a8221145..b9f677dd03d 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,8 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::Ident; -use utils::OPTION_PATH; -use utils::{is_adjusted, match_trait_method, match_type, snippet, span_help_and_lint}; +use utils::{CLONE_PATH, OPTION_PATH}; +use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; declare_lint!(pub MAP_CLONE, Warn, @@ -14,43 +14,58 @@ pub struct MapClonePass; impl LateLintPass for MapClonePass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if_let_chain! { - [ - // call to .map() - let ExprMethodCall(name, _, ref args) = expr.node, - name.node.as_str() == "map" && args.len() == 2, - let ExprClosure(_, ref decl, ref blk) = args[1].node, - // just one expression in the closure - blk.stmts.is_empty(), - let Some(ref closure_expr) = blk.expr, - // nothing special in the argument, besides reference bindings - // (e.g. .map(|&x| x) ) - let Some(arg_ident) = get_arg_name(&*decl.inputs[0].pat), - // the method is being called on a known type (option or iterator) - let Some(type_name) = get_type_name(cx, expr, &args[0]) - ], { - // look for derefs, for .map(|x| *x) - if only_derefs(cx, &*closure_expr, arg_ident) && - // .cloned() only removes one level of indirection, don't lint on more - walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 - { - span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( - "you seem to be using .map() to clone the contents of an {}, consider \ - using `.cloned()`", type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); - } - // explicit clone() calls ( .map(|x| x.clone()) ) - else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { - if clone_call.node.as_str() == "clone" && - clone_args.len() == 1 && - match_trait_method(cx, closure_expr, &["core", "clone", "Clone"]) && - expr_eq_ident(&clone_args[0], arg_ident) - { - span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( - "you seem to be using .map() to clone the contents of an {}, consider \ - using `.cloned()`", type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + // 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 blk) => { + if_let_chain! { + [ + // just one expression in the closure + blk.stmts.is_empty(), + let Some(ref closure_expr) = blk.expr, + // nothing special in the argument, besides reference bindings + // (e.g. .map(|&x| x) ) + let Some(arg_ident) = get_arg_name(&*decl.inputs[0].pat), + // the method is being called on a known type (option or iterator) + let Some(type_name) = get_type_name(cx, expr, &args[0]) + ], { + // look for derefs, for .map(|x| *x) + if only_derefs(cx, &*closure_expr, arg_ident) && + // .cloned() only removes one level of indirection, don't lint on more + walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + // explicit clone() calls ( .map(|x| x.clone()) ) + else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { + if clone_call.node.as_str() == "clone" && + clone_args.len() == 1 && + match_trait_method(cx, closure_expr, &["core", "clone", "Clone"]) && + expr_eq_ident(&clone_args[0], arg_ident) + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + } + } + } + }, + ExprPath(_, ref path) => { + if match_path(path, &CLONE_PATH) { + let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } } + _ => (), } } } diff --git a/src/utils.rs b/src/utils.rs index 757d7bc379d..e56eab5ad28 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -17,6 +17,7 @@ pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/map_clone.rs b/tests/compile-fail/map_clone.rs index f6241114a83..2e60300afda 100644 --- a/tests/compile-fail/map_clone.rs +++ b/tests/compile-fail/map_clone.rs @@ -15,6 +15,8 @@ fn map_clone_iter() { //~^ HELP try x.iter().map(|y| *y); //~ ERROR you seem to be using .map() //~^ HELP try + x.iter().map(Clone::clone); //~ ERROR you seem to be using .map() + //~^ HELP try } fn map_clone_option() { -- cgit 1.4.1-3-g733a5 From 2801c1031d41d9d2399c4aff9653e078d54e98c4 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <apaseltiner@gmail.com> Date: Mon, 9 Nov 2015 08:04:41 -0500 Subject: Remove executable permission from remaining source files --- src/consts.rs | 0 src/lib.rs | 0 tests/consts.rs | 0 tests/mut_mut_macro.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/consts.rs mode change 100755 => 100644 src/lib.rs mode change 100755 => 100644 tests/consts.rs mode change 100755 => 100644 tests/mut_mut_macro.rs (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs old mode 100755 new mode 100644 diff --git a/src/lib.rs b/src/lib.rs old mode 100755 new mode 100644 diff --git a/tests/consts.rs b/tests/consts.rs old mode 100755 new mode 100644 diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs old mode 100755 new mode 100644 -- cgit 1.4.1-3-g733a5 From aea2eb7da7ef9db34ee225abd3b625f428c00202 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Tue, 10 Nov 2015 10:25:21 +0100 Subject: use visitor for contains_self --- src/shadow.rs | 100 +++++++--------------------------------------------------- 1 file changed, 12 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index 13df95bf8dd..ca45ed11ab8 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use rustc_front::hir::*; use reexport::*; use syntax::codemap::Span; -use rustc_front::visit::FnKind; +use rustc_front::visit::{Visitor, FnKind}; use rustc::lint::*; use rustc::middle::def::Def::{DefVariant, DefStruct}; @@ -269,97 +269,21 @@ fn path_eq_name(name: Name, path: &Path) -> bool { path.segments[0].identifier.name == name } -fn contains_self(name: Name, expr: &Expr) -> bool { - match expr.node { - // the "self" name itself (maybe) - ExprPath(_, ref path) => path_eq_name(name, path), - // no subexprs - ExprLit(_) => false, - // one subexpr - ExprUnary(_, ref e) | ExprField(ref e, _) | - ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) | - ExprCast(ref e, _) => - contains_self(name, e), - // two subexprs - ExprBinary(_, ref l, ref r) | ExprIndex(ref l, ref r) | - ExprAssign(ref l, ref r) | ExprAssignOp(_, ref l, ref r) | - ExprRepeat(ref l, ref r) => - contains_self(name, l) || contains_self(name, r), - // one optional subexpr - ExprRet(ref oe) => - oe.as_ref().map_or(false, |ref e| contains_self(name, e)), - // two optional subexprs - ExprRange(ref ol, ref or) => - ol.as_ref().map_or(false, |ref e| contains_self(name, e)) || - or.as_ref().map_or(false, |ref e| contains_self(name, e)), - // one subblock - ExprBlock(ref block) | ExprLoop(ref block, _) | - ExprClosure(_, _, ref block) => - contains_block_self(name, block), - // one vec - ExprMethodCall(_, _, ref v) | ExprVec(ref v) | ExprTup(ref v) => - v.iter().any(|ref a| contains_self(name, a)), - // one expr, one vec - ExprCall(ref fun, ref args) => - contains_self(name, fun) || - args.iter().any(|ref a| contains_self(name, a)), - // special ones - ExprIf(ref cond, ref then, ref otherwise) => - contains_self(name, cond) || contains_block_self(name, then) || - otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)), - ExprWhile(ref e, ref block, _) => - contains_self(name, e) || contains_block_self(name, block), - ExprMatch(ref e, ref arms, _) => - contains_self(name, e) || - arms.iter().any( - |ref arm| - arm.pats.iter().any(|ref pat| contains_pat_self(name, pat)) || - arm.guard.as_ref().map_or(false, |ref g| contains_self(name, g)) || - contains_self(name, &arm.body)), - ExprStruct(_, ref fields, ref other) => - fields.iter().any(|ref f| contains_self(name, &f.expr)) || - other.as_ref().map_or(false, |ref e| contains_self(name, e)), - _ => false, - } +struct ContainsSelf { + name: Name, + result: bool } -fn contains_block_self(name: Name, block: &Block) -> bool { - for stmt in &block.stmts { - match stmt.node { - StmtDecl(ref decl, _) => - if let DeclLocal(ref local) = decl.node { - //TODO: We don't currently handle the case where the name - //is shadowed wiithin the block; this means code including this - //degenerate pattern will get the wrong warning. - if let Some(ref init) = local.init { - if contains_self(name, init) { return true; } - } - }, - StmtExpr(ref e, _) | StmtSemi(ref e, _) => - if contains_self(name, e) { return true } +impl<'v> Visitor<'v> for ContainsSelf { + fn visit_name(&mut self, _: Span, name: Name) { + if self.name == name { + self.result = true; } } - if let Some(ref e) = block.expr { contains_self(name, e) } else { false } } -fn contains_pat_self(name: Name, pat: &Pat) -> bool { - match pat.node { - PatIdent(_, ref ident, ref inner) => name == ident.node.name || - inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)), - PatEnum(_, ref opats) => opats.as_ref().map_or(false, - |pats| pats.iter().any(|p| contains_pat_self(name, p))), - PatQPath(_, ref path) => path_eq_name(name, path), - PatStruct(_, ref fieldpats, _) => fieldpats.iter().any( - |ref fp| contains_pat_self(name, &fp.node.pat)), - PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)), - PatBox(ref p) | - PatRegion(ref p, _) => contains_pat_self(name, p), - PatRange(ref from, ref until) => - contains_self(name, from) || contains_self(name, until), - PatVec(ref pre, ref opt, ref post) => - pre.iter().any(|ref p| contains_pat_self(name, p)) || - opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) || - post.iter().any(|ref p| contains_pat_self(name, p)), - _ => false, - } +fn contains_self(name: Name, expr: &Expr) -> bool { + let mut cs = ContainsSelf { name: name, result: false }; + cs.visit_expr(expr); + cs.result } -- cgit 1.4.1-3-g733a5 From 42ae1e69182577aa33a378e82362ca78be458bd2 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Tue, 10 Nov 2015 11:19:33 +0100 Subject: use rustc's eval_const, bail on (negative) infinity --- src/misc.rs | 16 +++++++++++----- tests/compile-fail/float_cmp.rs | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 01ecb2c2cf8..85fd03079fe 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -6,10 +6,12 @@ use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; use rustc_front::visit::FnKind; use rustc::middle::ty; +use rustc::middle::const_eval::ConstVal::Float; +use rustc::middle::const_eval::eval_const_expr_partial; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; use utils::span_help_and_lint; -use consts::constant; declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ @@ -119,10 +121,7 @@ impl LateLintPass for FloatCmp { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - if constant(cx, left).or_else(|| constant(cx, right)).map_or( - false, |c| c.0.as_float().map_or(false, |f| f == 0.0)) { - return; - } + if is_allowed(cx, left) || is_allowed(cx, right) { return; } if let Some(name) = get_item_name(cx, expr) { let name = name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || @@ -141,6 +140,13 @@ impl LateLintPass for FloatCmp { } } +fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { + let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None); + if let Ok(Float(val)) = res { + val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY + } else { false } +} + fn is_float(cx: &LateContext, expr: &Expr) -> bool { if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { true diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index da3dba5e4d4..27cde245f68 100644 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -35,8 +35,10 @@ impl PartialEq for X { fn main() { ZERO == 0f32; //no error, comparison with zero is ok + 1.0f32 != ::std::f32::INFINITY; // also comparison with infinity + 1.0f32 != ::std::f32::NEG_INFINITY; // and negative infinity ZERO == 0.0; //no error, comparison with zero is ok - ZERO + ZERO != 1.0; //~ERROR !=-comparison of f32 or f64 + ZERO + ZERO != 1.0; //no error, comparison with zero is ok ONE == 1f32; //~ERROR ==-comparison of f32 or f64 ONE == (1.0 + 0.0); //~ERROR ==-comparison of f32 or f64 -- cgit 1.4.1-3-g733a5 From e48973eb9faa1043de3c1dc5a5a86d709180c992 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 11 Nov 2015 00:12:45 +0100 Subject: Track elided lifetimes in types and trait objects --- src/lifetimes.rs | 86 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 206424de9b5..229d13401c6 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -3,6 +3,7 @@ use reexport::*; use rustc::lint::*; use syntax::codemap::Span; use rustc_front::visit::{Visitor, walk_ty, walk_ty_param_bound}; +use rustc::middle::def::Def::{DefTy, DefTrait}; use std::collections::HashSet; use utils::{in_external_macro, span_lint}; @@ -53,16 +54,16 @@ use self::RefLt::*; fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, generics: &Generics, span: Span) { - if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) { + if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } - if could_use_elision(decl, slf, &generics.lifetimes) { + if could_use_elision(cx, decl, slf, &generics.lifetimes) { span_lint(cx, NEEDLESS_LIFETIMES, span, "explicit lifetimes given in parameter types where they could be elided"); } } -fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, +fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, named_lts: &[LifetimeDef]) -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -74,8 +75,8 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, let allowed_lts = allowed_lts_from(named_lts); // these will collect all the lifetimes for references in arg/return types - let mut input_visitor = RefVisitor(Vec::new()); - let mut output_visitor = RefVisitor(Vec::new()); + let mut input_visitor = RefVisitor::new(cx); + let mut output_visitor = RefVisitor::new(cx); // extract lifetime in "self" argument for methods (there is a "self" argument // in func.inputs, but its type is TyInfer) @@ -88,14 +89,11 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>, } // extract lifetimes in input argument types for arg in &func.inputs { - walk_ty(&mut input_visitor, &arg.ty); - if let TyRptr(None, _) = arg.ty.node { - input_visitor.record(&None); - } + input_visitor.visit_ty(&arg.ty); } // extract lifetimes in output type if let Return(ref ty) = func.output { - walk_ty(&mut output_visitor, ty); + output_visitor.visit_ty(ty); } let input_lts = input_visitor.into_vec(); @@ -159,35 +157,75 @@ fn unique_lifetimes(lts: &[RefLt]) -> usize { } /// A visitor usable for rustc_front::visit::walk_ty(). -struct RefVisitor(Vec<RefLt>); +struct RefVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, // context reference + lts: Vec<RefLt> +} + +impl <'v, 't> RefVisitor<'v, 't> { + fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> { + RefVisitor { cx: cx, lts: Vec::new() } + } -impl RefVisitor { fn record(&mut self, lifetime: &Option<Lifetime>) { if let &Some(ref lt) = lifetime { if lt.name.as_str() == "'static" { - self.0.push(Static); + self.lts.push(Static); } else { - self.0.push(Named(lt.name)); + self.lts.push(Named(lt.name)); } } else { - self.0.push(Unnamed); + self.lts.push(Unnamed); } } fn into_vec(self) -> Vec<RefLt> { - self.0 + 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 { + if params.lifetimes.is_empty() { + let def = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()); + match def { + Some(DefTy(def_id, _)) => { + if let Some(ty_def) = self.cx.tcx.adt_defs.borrow().get(&def_id) { + let scheme = ty_def.type_scheme(self.cx.tcx); + for _ in scheme.generics.regions.as_slice() { + self.record(&None); + } + } + }, + Some(DefTrait(def_id)) => { + let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; + for _ in &trait_def.generics.regions { + self.record(&None); + } + }, + _ => {} + } + } + } } } -impl<'v> Visitor<'v> for RefVisitor { +impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { + // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.record(&Some(*lifetime)); } fn visit_ty(&mut self, ty: &'v Ty) { - if let TyRptr(None, _) = ty.node { - self.record(&None); + match ty.node { + TyRptr(None, _) => { + self.record(&None); + }, + TyPath(_, ref path) => { + self.collect_anonymous_lifetimes(path, ty); + }, + _ => {} } walk_ty(self, ty); } @@ -195,16 +233,16 @@ impl<'v> Visitor<'v> for RefVisitor { /// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to /// reason about elision. -fn has_where_lifetimes(where_clause: &WhereClause) -> bool { +fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { for predicate in &where_clause.predicates { match *predicate { WherePredicate::RegionPredicate(..) => return true, WherePredicate::BoundPredicate(ref pred) => { // a predicate like F: Trait or F: for<'a> Trait<'a> - let mut visitor = RefVisitor(Vec::new()); + let mut visitor = RefVisitor::new(cx); // walk the type F, it may not contain LT refs walk_ty(&mut visitor, &pred.bounded_ty); - if !visitor.0.is_empty() { return true; } + if !visitor.lts.is_empty() { return true; } // if the bounds define new lifetimes, they are fine to occur let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); // now walk the bounds @@ -219,9 +257,9 @@ fn has_where_lifetimes(where_clause: &WhereClause) -> bool { } } WherePredicate::EqPredicate(ref pred) => { - let mut visitor = RefVisitor(Vec::new()); + let mut visitor = RefVisitor::new(cx); walk_ty(&mut visitor, &pred.ty); - if !visitor.0.is_empty() { return true; } + if !visitor.lts.is_empty() { return true; } } } } -- cgit 1.4.1-3-g733a5 From e8a239a1a2ec9e0da86a8553f9dff62431f8bd0e Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <apaseltiner@gmail.com> Date: Wed, 11 Nov 2015 09:28:31 -0500 Subject: Add lint for useless transmutes Closes #441. --- README.md | 3 ++- src/lib.rs | 3 +++ src/transmute.rs | 37 +++++++++++++++++++++++++++++++++ tests/compile-fail/transmute.rs | 46 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/transmute.rs create mode 100644 tests/compile-fail/transmute.rs (limited to 'src') diff --git a/README.md b/README.md index 6727707717f..b893c4e7a17 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 73 lints included in this crate: +There are 74 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -77,6 +77,7 @@ name [unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention diff --git a/src/lib.rs b/src/lib.rs index 970a244e2cd..afbf3d2a92c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ pub mod needless_features; pub mod needless_update; pub mod no_effect; pub mod temporary_assignment; +pub mod transmute; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -104,6 +105,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); + reg.register_late_lint_pass(box transmute::UselessTransmute); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -175,6 +177,7 @@ pub fn plugin_registrar(reg: &mut Registry) { returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, temporary_assignment::TEMPORARY_ASSIGNMENT, + transmute::USELESS_TRANSMUTE, types::BOX_VEC, types::LET_UNIT_VALUE, types::LINKEDLIST, diff --git a/src/transmute.rs b/src/transmute.rs new file mode 100644 index 00000000000..ab1397ea7fe --- /dev/null +++ b/src/transmute.rs @@ -0,0 +1,37 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils; + +declare_lint! { + pub USELESS_TRANSMUTE, + Warn, + "transmutes that have the same to and from types" +} + +pub struct UselessTransmute; + +impl LintPass for UselessTransmute { + fn get_lints(&self) -> LintArray { + lint_array!(USELESS_TRANSMUTE) + } +} + +impl LateLintPass for UselessTransmute { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, ref args) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + + if utils::match_def_path(cx, def_id, &["core", "intrinsics", "transmute"]) { + let from_ty = cx.tcx.expr_ty(&args[0]); + let to_ty = cx.tcx.expr_ty(e); + + if from_ty == to_ty { + cx.span_lint(USELESS_TRANSMUTE, e.span, + &format!("transmute from a type (`{}`) to itself", from_ty)); + } + } + } + } + } +} diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs new file mode 100644 index 00000000000..0a2d09d9431 --- /dev/null +++ b/tests/compile-fail/transmute.rs @@ -0,0 +1,46 @@ +#![feature(core)] +#![feature(plugin)] +#![plugin(clippy)] +#![deny(useless_transmute)] + +extern crate core; + +use std::mem::transmute as my_transmute; +use std::vec::Vec as MyVec; + +fn my_vec() -> MyVec<i32> { + vec![] +} + +#[allow(needless_lifetimes)] +unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { + let _: &'a T = core::intrinsics::transmute(t); + //~^ ERROR transmute from a type (`&'a T`) to itself + + let _: &'a U = core::intrinsics::transmute(t); +} + +fn main() { + unsafe { + let _: Vec<i32> = core::intrinsics::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself + + let _: Vec<i32> = core::mem::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself + + let _: Vec<i32> = std::intrinsics::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself + + let _: Vec<i32> = std::mem::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself + + let _: Vec<i32> = my_transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself + + let _: Vec<u32> = core::intrinsics::transmute(my_vec()); + let _: Vec<u32> = core::mem::transmute(my_vec()); + let _: Vec<u32> = std::intrinsics::transmute(my_vec()); + let _: Vec<u32> = std::mem::transmute(my_vec()); + let _: Vec<u32> = my_transmute(my_vec()); + } +} -- cgit 1.4.1-3-g733a5 From 91763d77251f7f84529b6802fe6172854641a520 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <apaseltiner@gmail.com> Date: Wed, 11 Nov 2015 11:08:33 -0500 Subject: Match `min` and `max` functions using `DefId` Closes #446. --- src/minmax.rs | 16 +++++++++------- tests/compile-fail/min_max.rs | 4 ++++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/minmax.rs b/src/minmax.rs index a94b0b42ec1..3171a951422 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -5,7 +5,7 @@ use std::cmp::PartialOrd; use std::cmp::Ordering::*; use consts::{Constant, constant_simple}; -use utils::{match_path, span_lint}; +use utils::{match_def_path, span_lint}; use self::MinMax::{Min, Max}; declare_lint!(pub MIN_MAX, Warn, @@ -23,8 +23,8 @@ impl LintPass for MinMaxPass { impl LateLintPass for MinMaxPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let Some((outer_max, outer_c, oe)) = min_max(expr) { - if let Some((inner_max, inner_c, _)) = min_max(oe) { + 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 { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), @@ -44,13 +44,15 @@ enum MinMax { Max, } -fn min_max(expr: &Expr) -> Option<(MinMax, Constant, &Expr)> { +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, ref path) = path.node { - if match_path(path, &["std", "cmp", "min"]) { + if let ExprPath(None, _) = path.node { + let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); + + if match_def_path(cx, def_id, &["core", "cmp", "min"]) { fetch_const(args, Min) } else { - if match_path(path, &["std", "cmp", "max"]) { + if match_def_path(cx, def_id, &["core", "cmp", "max"]) { fetch_const(args, Max) } else { None diff --git a/tests/compile-fail/min_max.rs b/tests/compile-fail/min_max.rs index 5a5fae4930d..9a6794afebf 100644 --- a/tests/compile-fail/min_max.rs +++ b/tests/compile-fail/min_max.rs @@ -4,6 +4,8 @@ #![deny(clippy)] use std::cmp::{min, max}; +use std::cmp::min as my_min; +use std::cmp::max as my_max; const LARGE : usize = 3; @@ -15,6 +17,8 @@ fn main() { max(min(x, 1), 3); //~ERROR this min/max combination leads to constant result max(3, min(x, 1)); //~ERROR this min/max combination leads to constant result + my_max(3, my_min(x, 1)); //~ERROR this min/max combination leads to constant result + min(3, max(1, x)); // ok, could be 1, 2 or 3 depending on x min(1, max(LARGE, x)); // no error, we don't lookup consts here -- cgit 1.4.1-3-g733a5 From b17e38782e4cf4313c7ce21c27f00a98dcf823c1 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Tue, 17 Nov 2015 13:39:42 +0900 Subject: Remove trailing commas in match arms with blocks --- src/bit_mask.rs | 2 +- src/consts.rs | 12 ++++++------ src/eta_reduction.rs | 2 +- src/identity_op.rs | 6 +++--- src/lifetimes.rs | 8 ++++---- src/loops.rs | 4 ++-- src/map_clone.rs | 6 +++--- src/minmax.rs | 2 +- src/misc.rs | 4 ++-- src/mut_reference.rs | 8 ++++---- src/needless_bool.rs | 8 ++++---- src/open_options.rs | 12 ++++++------ src/shadow.rs | 18 +++++++++--------- src/types.rs | 4 ++-- src/utils.rs | 2 +- tests/compile-fail/matches.rs | 8 ++++---- 16 files changed, 53 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index e6665bbbb4d..c8530b92d48 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -185,7 +185,7 @@ fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { if let &LitInt(value, _) = &lit_ptr.node { Option::Some(value) //TODO: Handle sign } else { Option::None } - }, + } ExprPath(_, _) => { // Important to let the borrow expire before the const lookup to avoid double // borrowing. diff --git a/src/consts.rs b/src/consts.rs index 766d998c256..1750495d1f3 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -246,7 +246,7 @@ fn constant_not(o: Constant) -> Option<Constant> { SignedIntLit(ity, Plus) => { if value == ::std::u64::MAX { return None; } (value + 1, SignedIntLit(ity, Minus)) - }, + } SignedIntLit(ity, Minus) => { if value == 0 { (1, SignedIntLit(ity, Minus)) @@ -267,7 +267,7 @@ fn constant_not(o: Constant) -> Option<Constant> { UnsuffixedIntLit(_) => { return None; } // refuse to guess }; ConstantInt(nvalue, nty) - }, + } _ => { return None; } }) } @@ -279,11 +279,11 @@ fn constant_negate(o: Constant) -> Option<Constant> { SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; }, + _ => { return None; } }), ConstantFloat(is, ty) => ConstantFloat(neg_float_str(is), ty), - _ => { return None; }, + _ => { return None; } }) } @@ -461,7 +461,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { add_neg_int(l64, lty, r64, rty) } } - }, + } // TODO: float (would need bignum library?) _ => None }), @@ -513,7 +513,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { unify_int_type(lty, rty, if is_negative(lty) == is_negative(rty) { Plus } else { Minus }) .map(|ty| ConstantInt(value, ty))) - }, + } _ => None, }) } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 855ea51ee8e..c4c0912464c 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -26,7 +26,7 @@ impl LateLintPass for EtaPass { for arg in args { check_closure(cx, arg) } - }, + } _ => (), } } diff --git a/src/identity_op.rs b/src/identity_op.rs index aee208d624e..7ed784f00fc 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -26,19 +26,19 @@ 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/src/lifetimes.rs b/src/lifetimes.rs index 229d13401c6..09c5821dd49 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -196,13 +196,13 @@ impl <'v, 't> RefVisitor<'v, 't> { self.record(&None); } } - }, + } Some(DefTrait(def_id)) => { let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; for _ in &trait_def.generics.regions { self.record(&None); } - }, + } _ => {} } } @@ -221,10 +221,10 @@ impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { match ty.node { TyRptr(None, _) => { self.record(&None); - }, + } TyPath(_, ref path) => { self.collect_anonymous_lifetimes(path, ty); - }, + } _ => {} } walk_ty(self, ty); diff --git a/src/loops.rs b/src/loops.rs index d056c67c541..60ae2c23f0a 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -545,13 +545,13 @@ 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, _ => () } diff --git a/src/map_clone.rs b/src/map_clone.rs index b9f677dd03d..ba561fbb167 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -55,7 +55,7 @@ impl LateLintPass for MapClonePass { } } } - }, + } ExprPath(_, ref path) => { if match_path(path, &CLONE_PATH) { let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); @@ -77,7 +77,7 @@ fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { ExprPath(None, ref path) => { let arg_segment = [PathSegment { identifier: id, parameters: PathParameters::none() }]; !path.global && path.segments == arg_segment - }, + } _ => false, } } @@ -104,7 +104,7 @@ fn only_derefs(cx: &LateContext, expr: &Expr, id: Ident) -> bool { match expr.node { ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => { only_derefs(cx, subexpr, id) - }, + } _ => expr_eq_ident(expr, id), } } diff --git a/src/minmax.rs b/src/minmax.rs index 3171a951422..7ed65184727 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -31,7 +31,7 @@ impl LateLintPass for MinMaxPass { _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result") - }, + } } } } diff --git a/src/misc.rs b/src/misc.rs index 85fd03079fe..857ae1cc0c3 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -187,7 +187,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o } else { return } - }, + } ExprCall(ref path, ref v) if v.len() == 1 => { if let &ExprPath(None, ref path) = &path.node { if match_path(path, &["String", "from_str"]) || @@ -199,7 +199,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o } else { return } - }, + } _ => return }; if left { diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 1cc04e096ba..86c272affb7 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -32,14 +32,14 @@ impl LateLintPass for UnnecessaryMutPassed { check_arguments(cx, &arguments, function_type, &format!("{}", path)); } - }, + } None => unreachable!(), // A function with unknown type is called. // If this happened the compiler would have aborted the // compilation long ago. }; - }, + } ExprMethodCall(ref name, _, ref arguments) => { let method_call = MethodCall::expr(e.id); match borrowed_table.method_map.get(&method_call) { @@ -47,7 +47,7 @@ impl LateLintPass for UnnecessaryMutPassed { &format!("{}", name.node.as_str())), None => unreachable!(), // Just like above, this should never happen. }; - }, + } _ => {} } } @@ -66,7 +66,7 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty doesn't need a mutable reference", name)); } - }, + } _ => {} } } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index c0a99acb71d..52f23c7518a 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -31,10 +31,10 @@ impl LateLintPass for NeedlessBool { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (Some(true), Some(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "this if-then-else expression will always return true"); }, + "this if-then-else expression will always return true"); } (Some(false), Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "this if-then-else expression will always return false"); }, + "this if-then-else expression will always return false"); } (Some(true), Some(false)) => { let pred_snip = snippet(cx, pred.span, ".."); let hint = if pred_snip == ".." { "its predicate".into() } else { @@ -42,7 +42,7 @@ impl LateLintPass for NeedlessBool { }; span_lint(cx, NEEDLESS_BOOL, e.span, &format!( "you can reduce this if-then-else expression to just {}", hint)); - }, + } (Some(false), Some(true)) => { let pred_snip = snippet(cx, pred.span, ".."); let hint = if pred_snip == ".." { "`!` and its predicate".into() } else { @@ -50,7 +50,7 @@ impl LateLintPass for NeedlessBool { }; span_lint(cx, NEEDLESS_BOOL, e.span, &format!( "you can reduce this if-then-else expression to just {}", hint)); - }, + } _ => () } } diff --git a/src/open_options.rs b/src/open_options.rs index 76a2eeef1ba..732852e1686 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -65,7 +65,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp // which is not a boolean literal. This is theoretically // possible, but not very likely. } - }, + } _ => { Argument::Unknown } @@ -74,19 +74,19 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp 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)); - }, + } _ => {} } diff --git a/src/shadow.rs b/src/shadow.rs index ca45ed11ab8..a1e86028752 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -101,7 +101,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, } } if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } - }, + } //PatEnum(Path, Option<Vec<P<Pat>>>), PatStruct(_, ref pfields, _) => if let Some(ref init_struct) = *init { @@ -149,7 +149,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, } else { check_pat(cx, inner, init, span, bindings); } - }, + } PatRegion(ref inner, _) => check_pat(cx, inner, init, span, bindings), //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), @@ -200,9 +200,9 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { match expr.node { ExprUnary(_, ref e) | ExprField(ref e, _) | ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) - => { check_expr(cx, e, bindings) }, + => { check_expr(cx, e, bindings) } ExprBlock(ref block) | ExprLoop(ref block, _) => - { check_block(cx, block, bindings) }, + { check_block(cx, block, bindings) } //ExprCall //ExprMethodCall ExprVec(ref v) | ExprTup(ref v) => @@ -211,11 +211,11 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { 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(); @@ -230,7 +230,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { bindings.truncate(len); } } - }, + } _ => () } } @@ -242,10 +242,10 @@ fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { TyFixedLengthVec(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 ref t in tup { check_ty(cx, t, bindings) } }, + TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } } TyTypeof(ref expr) => check_expr(cx, expr, bindings), _ => (), } diff --git a/src/types.rs b/src/types.rs index 93962586bc6..68120f65e1f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -229,7 +229,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, expr.span, &format!("casting {} to {} may truncate the value", @@ -239,7 +239,7 @@ impl LateLintPass for CastPass { &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, CAST_SIGN_LOSS, expr.span, diff --git a/src/utils.rs b/src/utils.rs index e56eab5ad28..3fcfa66259c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -167,7 +167,7 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { Some(NodeTraitItem(&TraitItem{ id: _, ref name, .. })) | Some(NodeImplItem(&ImplItem{ id: _, ref name, .. })) => { Some(*name) - }, + } _ => None, } } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index ff92a67271b..20d7552d77a 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -54,17 +54,17 @@ fn match_bool() { match test { //~ ERROR you seem to be trying to match on a boolean expression true => (), - false => { println!("Noooo!"); }, + false => { println!("Noooo!"); } }; match test { //~ ERROR you seem to be trying to match on a boolean expression - false => { println!("Noooo!"); }, + false => { println!("Noooo!"); } _ => (), }; match test { //~ ERROR you seem to be trying to match on a boolean expression - false => { println!("Noooo!"); }, - true => { println!("Yes!"); }, + false => { println!("Noooo!"); } + true => { println!("Yes!"); } }; // Not linted -- cgit 1.4.1-3-g733a5 From 1d602d0f124904f91d6d934e83a8a687f314e110 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Tue, 17 Nov 2015 14:22:57 +0900 Subject: rustfmt a little --- src/minmax.rs | 2 +- src/mut_mut.rs | 6 +++--- src/needless_bool.rs | 6 ++++-- src/needless_features.rs | 4 ++-- src/precedence.rs | 8 ++++---- src/strings.rs | 2 +- src/zero_div_zero.rs | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/minmax.rs b/src/minmax.rs index 7ed65184727..9eb8a030e15 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -17,7 +17,7 @@ pub struct MinMaxPass; impl LintPass for MinMaxPass { fn get_lints(&self) -> LintArray { - lint_array!(MIN_MAX) + lint_array!(MIN_MAX) } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 9b6a5d9ddcc..a92338165dd 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -19,7 +19,7 @@ impl LintPass for MutMut { impl LateLintPass for MutMut { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - check_expr_mut(cx, expr) + check_expr_mut(cx, expr) } fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { @@ -31,7 +31,7 @@ impl LateLintPass for MutMut { fn check_expr_mut(cx: &LateContext, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } - fn unwrap_addr(expr : &Expr) -> Option<&Expr> { + fn unwrap_addr(expr: &Expr) -> Option<&Expr> { match expr.node { ExprAddrOf(MutMutable, ref e) => Option::Some(e), _ => Option::None @@ -53,7 +53,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { }) } -fn unwrap_mut(ty : &Ty) -> Option<&Ty> { +fn unwrap_mut(ty: &Ty) -> Option<&Ty> { match ty.node { TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), _ => Option::None diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 52f23c7518a..e4d3b00218e 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -31,10 +31,12 @@ impl LateLintPass for NeedlessBool { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (Some(true), Some(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "this if-then-else expression will always return true"); } + "this if-then-else expression will always return true"); + } (Some(false), Some(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, - "this if-then-else expression will always return false"); } + "this if-then-else expression will always return false"); + } (Some(true), Some(false)) => { let pred_snip = snippet(cx, pred.span, ".."); let hint = if pred_snip == ".." { "its predicate".into() } else { diff --git a/src/needless_features.rs b/src/needless_features.rs index b1d38df7311..44db5e92221 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -5,7 +5,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{span_lint}; +use utils::span_lint; use utils; declare_lint! { @@ -27,7 +27,7 @@ pub struct NeedlessFeaturesPass; impl LintPass for NeedlessFeaturesPass { fn get_lints(&self) -> LintArray { - lint_array!(UNSTABLE_AS_SLICE,UNSTABLE_AS_MUT_SLICE) + lint_array!(UNSTABLE_AS_SLICE, UNSTABLE_AS_MUT_SLICE) } } diff --git a/src/precedence.rs b/src/precedence.rs index b7dbe268557..b659bd647a7 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -53,7 +53,7 @@ impl EarlyLintPass for Precedence { method call. Consider adding parentheses \ to clarify your intent: -({})", snippet(cx, rhs.span, ".."))), - _ => () + _ => () } } } @@ -62,21 +62,21 @@ impl EarlyLintPass for Precedence { } } -fn is_arith_expr(expr : &Expr) -> bool { +fn is_arith_expr(expr: &Expr) -> bool { match expr.node { ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), _ => false } } -fn is_bit_op(op : BinOp_) -> bool { +fn is_bit_op(op: BinOp_) -> bool { match op { BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, _ => false } } -fn is_arith_op(op : BinOp_) -> bool { +fn is_arith_op(op: BinOp_) -> bool { match op { BiAdd | BiSub | BiMul | BiDiv | BiRem => true, _ => false diff --git a/src/strings.rs b/src/strings.rs index 6bbf94004b0..08274657538 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -51,7 +51,7 @@ impl LateLintPass for StringAdd { "you added something to a string. \ Consider using `String::push_str()` instead") } - } else if let &ExprAssign(ref target, ref src) = &e.node { + } else if let &ExprAssign(ref target, ref src) = &e.node { if is_string(cx, target) && is_add(cx, src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 37d5d8904e1..484348c5a37 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{span_help_and_lint}; +use utils::span_help_and_lint; use consts::{Constant, constant_simple, FloatWidth}; /// ZeroDivZeroPass is a pass that checks for a binary expression that consists -- cgit 1.4.1-3-g733a5 From 9511e6739dad2874aa39350cb74fcbcc28fe087d Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 19 Nov 2015 15:51:30 +0100 Subject: Update to latest rust nightly --- src/attrs.rs | 2 +- src/eq_op.rs | 1 - src/len_zero.rs | 2 +- src/lifetimes.rs | 4 ++-- src/loops.rs | 2 +- src/methods.rs | 2 +- src/misc.rs | 2 +- src/ptr_arg.rs | 2 +- src/shadow.rs | 4 ++-- src/types.rs | 6 +++--- 10 files changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 79cec664adc..a0101688668 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -49,7 +49,7 @@ fn is_relevant_item(item: &Item) -> bool { fn is_relevant_impl(item: &ImplItem) -> bool { match item.node { - MethodImplItem(_, ref block) => is_relevant_block(block), + ImplItemKind::Method(_, ref block) => is_relevant_block(block), _ => false } } diff --git a/src/eq_op.rs b/src/eq_op.rs index 6f305b6adf8..1d2146537c9 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -105,7 +105,6 @@ fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty), (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), - (&TyParen(ref lty), &TyParen(ref rty)) => is_cast_ty_equal(lty, rty), (&TyInfer, &TyInfer) => true, _ => false } diff --git a/src/len_zero.rs b/src/len_zero.rs index f5ad37a71be..25645ea8742 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -71,7 +71,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>] fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.name.as_str() == name && if let MethodImplItem(ref sig, _) = + item.name.as_str() == name && if let ImplItemKind::Method(ref sig, _) = item.node { is_self_sig(sig) } else { false } } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 09c5821dd49..9b47a4d830f 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -2,7 +2,7 @@ use rustc_front::hir::*; use reexport::*; use rustc::lint::*; use syntax::codemap::Span; -use rustc_front::visit::{Visitor, walk_ty, walk_ty_param_bound}; +use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound}; use rustc::middle::def::Def::{DefTy, DefTrait}; use std::collections::HashSet; @@ -29,7 +29,7 @@ impl LateLintPass for LifetimePass { } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if let MethodImplItem(ref sig, _) = item.node { + if let ImplItemKind::Method(ref sig, _) = item.node { check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); } diff --git a/src/loops.rs b/src/loops.rs index 60ae2c23f0a..92dff3a7d93 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; -use rustc_front::visit::{Visitor, walk_expr, walk_block, walk_decl}; +use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use rustc::middle::ty; use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; diff --git a/src/methods.rs b/src/methods.rs index 18da7e977d6..275de8d8ebd 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -77,7 +77,7 @@ impl LateLintPass for MethodsPass { if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { for implitem in items { let name = implitem.name; - if let MethodImplItem(ref sig, _) = implitem.node { + if let ImplItemKind::Method(ref sig, _) = implitem.node { // check missing trait implementations for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { if_let_chain! { diff --git a/src/misc.rs b/src/misc.rs index 857ae1cc0c3..9a8ce74e997 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -4,7 +4,7 @@ use rustc_front::hir::*; use reexport::*; use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned}; -use rustc_front::visit::FnKind; +use rustc_front::intravisit::FnKind; use rustc::middle::ty; use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::eval_const_expr_partial; diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 78a3c146c0f..78be2af1217 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -34,7 +34,7 @@ impl LateLintPass for PtrArg { } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if let &MethodImplItem(ref sig, _) = &item.node { + if let &ImplItemKind::Method(ref sig, _) = &item.node { if let Some(Node::NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { if let ItemImpl(_, _, _, Some(_), _, _) = it.node { return; // ignore trait impls diff --git a/src/shadow.rs b/src/shadow.rs index a1e86028752..3f72722333b 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use rustc_front::hir::*; use reexport::*; use syntax::codemap::Span; -use rustc_front::visit::{Visitor, FnKind}; +use rustc_front::intravisit::{Visitor, FnKind}; use rustc::lint::*; use rustc::middle::def::Def::{DefVariant, DefStruct}; @@ -237,7 +237,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { match ty.node { - TyParen(ref sty) | TyObjectSum(ref sty, _) | + TyObjectSum(ref sty, _) | TyVec(ref sty) => check_ty(cx, sty, bindings), TyFixedLengthVec(ref fty, ref expr) => { check_ty(cx, fty, bindings); diff --git a/src/types.rs b/src/types.rs index 68120f65e1f..506509cdfed 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,7 +3,7 @@ use rustc_front::hir::*; use reexport::*; use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; -use rustc_front::visit::{FnKind, Visitor, walk_ty}; +use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; @@ -305,8 +305,8 @@ impl LateLintPass for TypeComplexityPass { fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { match item.node { - ConstImplItem(ref ty, _) | - TypeImplItem(ref ty) => check_type(cx, ty), + ImplItemKind::Const(ref ty, _) | + ImplItemKind::Type(ref ty) => check_type(cx, ty), // methods are covered by check_fn _ => () } -- cgit 1.4.1-3-g733a5 From cad88a91371a988a0078016c44b1d6f3c24dec57 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 19 Nov 2015 14:39:27 +0100 Subject: warn on use of ok().expect() --- src/lib.rs | 3 +- src/methods.rs | 108 ++++++++++++++++++++++++++++++++++++++++-- tests/compile-fail/methods.rs | 23 +++++++++ 3 files changed, 128 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index afbf3d2a92c..35e303b749b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box unicode::Unicode); reg.register_late_lint_pass(box strings::StringAdd); reg.register_early_lint_pass(box returns::ReturnPass); - reg.register_late_lint_pass(box methods::MethodsPass); + reg.register_late_lint_pass(box methods::MethodsPass::new()); reg.register_late_lint_pass(box shadow::ShadowPass); reg.register_late_lint_pass(box types::LetPass); reg.register_late_lint_pass(box types::UnitCmp); @@ -151,6 +151,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_BOOL, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, + methods::OK_EXPECT, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, diff --git a/src/methods.rs b/src/methods.rs index 275de8d8ebd..dbc18fdfe33 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,18 +1,81 @@ use rustc_front::hir::*; use rustc::lint::*; use rustc::middle::ty; -use rustc::middle::subst::Subst; +use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; +use std::collections::HashSet; -use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth}; +use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth, + walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; use self::SelfKind::*; use self::OutType::*; -#[derive(Copy,Clone)] -pub struct MethodsPass; +use rustc::middle::def_id::DefId; + +use rustc::middle::ty::TypeFlags; + +#[derive(Clone)] +pub struct MethodsPass { types_implementing_debug: Option<HashSet<DefId>> } + +impl MethodsPass { + pub fn new() -> MethodsPass { + MethodsPass { types_implementing_debug: None } + } + + fn get_debug_impls(&mut self, cx: &LateContext) -> Option<&HashSet<DefId>> { + if self.types_implementing_debug.is_none() { + let debug = match cx.tcx.lang_items.debug_trait() { + Some(debug) => debug, + None => return None + }; + let debug_def = cx.tcx.lookup_trait_def(debug); + let mut impls = HashSet::new(); + debug_def.for_each_impl(cx.tcx, |d| { + let o_self_ty = &cx.tcx.impl_trait_ref(d) + .map(|x| x.substs) + .and_then(|x| x.self_ty()); + let self_ty = match *o_self_ty { + Some(self_type) => self_type, + None => return + }; + let self_ty_def_id = self_ty.ty_to_def_id(); + if let Some(self_ty_def_id) = self_ty_def_id { + let has_params = self_ty.flags.get().contains(TypeFlags::HAS_PARAMS); + if !has_params { + impls.insert(self_ty_def_id); + } + } + }); + self.types_implementing_debug = Some(impls); + } + self.types_implementing_debug.as_ref() + } + + // This checks whether a given type is known to implement Debug. It's + // conservative, i.e. it should not return false positives, but will return + // false negatives. + fn has_debug_impl(&mut self, ty: ty::Ty, cx: &LateContext) -> bool { + let debug_impls = match self.get_debug_impls(cx) { + Some(debug_impls) => debug_impls, + None => return false + }; + match walk_ptrs_ty(ty).sty { + ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) + | ty::TyFloat(..) | ty::TyStr => true, + ty::TyTuple(ref v) if v.is_empty() => true, + ty::TyStruct(..) | ty::TyEnum(..) => { + match ty.ty_to_def_id() { + Some(ref ty_def_id) => debug_impls.contains(ty_def_id), + None => false + } + }, + _ => false + } + } +} declare_lint!(pub OPTION_UNWRAP_USED, Allow, "using `Option.unwrap()`, which should at least get a better message using `expect()`"); @@ -30,16 +93,21 @@ declare_lint!(pub WRONG_SELF_CONVENTION, Warn, declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, "defining a public method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); +declare_lint!(pub OK_EXPECT, Warn, + "using `ok().expect()`, which gives worse error messages than \ + calling `expect` directly on the Result"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, - SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION) + SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT) } } impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprMethodCall(ref name, _, ref args) = expr.node { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); if name.node.as_str() == "unwrap" { @@ -70,6 +138,22 @@ impl LateLintPass for MethodsPass { `clone()` to make a copy"); } } + else if name.node.as_str() == "expect" { + if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + if inner_name.node.as_str() == "ok" + && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &RESULT_PATH) { + let result_type = cx.tcx.expr_ty(&inner_args[0]); + if let Some(error_type) = get_error_type(cx, result_type) { + if self.has_debug_impl(error_type, cx) { + span_lint(cx, OK_EXPECT, expr.span, + "called `ok().expect()` on a Result \ + value. You can call `expect` directly + on the `Result`"); + } + } + } + } + } } } @@ -115,6 +199,20 @@ impl LateLintPass for MethodsPass { } } +// Given a `Result<T, E>` type, return its error type (`E`) +fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { + if !match_type(cx, ty, &RESULT_PATH) { + return None; + } + if let ty::TyEnum(_, substs) = ty.sty { + if let Some(err_ty) = substs.types.opt_get(TypeSpace, 1) { + return Some(err_ty); + } + } + None +} + + const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ("into_", &[ValueSelf]), ("to_", &[RefSelf]), diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 314601f6dbd..aeb79503504 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -35,6 +35,8 @@ impl Mul<T> for T { } fn main() { + use std::io; + let opt = Some(0); let _ = opt.unwrap(); //~ERROR used unwrap() on an Option @@ -46,4 +48,25 @@ fn main() { let v = &"str"; let string = v.to_string(); //~ERROR `(*v).to_owned()` is faster let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op + + res.ok().expect("disaster!"); //~ERROR called `ok().expect()` + // the following should not warn, since `expect` isn't implemented unless + // the error type implements `Debug` + let res2: Result<i32, MyError> = Ok(0); + res2.ok().expect("oh noes!"); + // we're currently don't warn if the error type has a type parameter + // (but it would be nice if we did) + let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0); + res3.ok().expect("whoof"); + let res4: Result<u32, io::Error> = Ok(0); + res4.ok().expect("argh"); //~ERROR called `ok().expect()` + let res5: io::Result<u32> = Ok(0); + res5.ok().expect("oops"); //~ERROR called `ok().expect()` +} + +struct MyError(()); // doesn't implement Debug + +#[derive(Debug)] +struct MyErrorWithParam<T> { + x: T } -- cgit 1.4.1-3-g733a5 From 096c064d4374daf6292cb54f7cf4fac4a8eda718 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 19 Nov 2015 20:13:36 +0100 Subject: Simplify has_debug_impl --- src/lib.rs | 2 +- src/methods.rs | 87 ++++++++++++------------------------------- tests/compile-fail/methods.rs | 4 +- 3 files changed, 27 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 35e303b749b..d977ed07bfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box unicode::Unicode); reg.register_late_lint_pass(box strings::StringAdd); reg.register_early_lint_pass(box returns::ReturnPass); - reg.register_late_lint_pass(box methods::MethodsPass::new()); + reg.register_late_lint_pass(box methods::MethodsPass); reg.register_late_lint_pass(box shadow::ShadowPass); reg.register_late_lint_pass(box types::LetPass); reg.register_late_lint_pass(box types::UnitCmp); diff --git a/src/methods.rs b/src/methods.rs index dbc18fdfe33..858a5a3dca0 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -4,7 +4,6 @@ use rustc::middle::ty; use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; -use std::collections::HashSet; use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth, walk_ptrs_ty}; @@ -13,69 +12,8 @@ use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; use self::SelfKind::*; use self::OutType::*; -use rustc::middle::def_id::DefId; - -use rustc::middle::ty::TypeFlags; - #[derive(Clone)] -pub struct MethodsPass { types_implementing_debug: Option<HashSet<DefId>> } - -impl MethodsPass { - pub fn new() -> MethodsPass { - MethodsPass { types_implementing_debug: None } - } - - fn get_debug_impls(&mut self, cx: &LateContext) -> Option<&HashSet<DefId>> { - if self.types_implementing_debug.is_none() { - let debug = match cx.tcx.lang_items.debug_trait() { - Some(debug) => debug, - None => return None - }; - let debug_def = cx.tcx.lookup_trait_def(debug); - let mut impls = HashSet::new(); - debug_def.for_each_impl(cx.tcx, |d| { - let o_self_ty = &cx.tcx.impl_trait_ref(d) - .map(|x| x.substs) - .and_then(|x| x.self_ty()); - let self_ty = match *o_self_ty { - Some(self_type) => self_type, - None => return - }; - let self_ty_def_id = self_ty.ty_to_def_id(); - if let Some(self_ty_def_id) = self_ty_def_id { - let has_params = self_ty.flags.get().contains(TypeFlags::HAS_PARAMS); - if !has_params { - impls.insert(self_ty_def_id); - } - } - }); - self.types_implementing_debug = Some(impls); - } - self.types_implementing_debug.as_ref() - } - - // This checks whether a given type is known to implement Debug. It's - // conservative, i.e. it should not return false positives, but will return - // false negatives. - fn has_debug_impl(&mut self, ty: ty::Ty, cx: &LateContext) -> bool { - let debug_impls = match self.get_debug_impls(cx) { - Some(debug_impls) => debug_impls, - None => return false - }; - match walk_ptrs_ty(ty).sty { - ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) - | ty::TyFloat(..) | ty::TyStr => true, - ty::TyTuple(ref v) if v.is_empty() => true, - ty::TyStruct(..) | ty::TyEnum(..) => { - match ty.ty_to_def_id() { - Some(ref ty_def_id) => debug_impls.contains(ty_def_id), - None => false - } - }, - _ => false - } - } -} +pub struct MethodsPass; declare_lint!(pub OPTION_UNWRAP_USED, Allow, "using `Option.unwrap()`, which should at least get a better message using `expect()`"); @@ -144,7 +82,7 @@ impl LateLintPass for MethodsPass { && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &RESULT_PATH) { let result_type = cx.tcx.expr_ty(&inner_args[0]); if let Some(error_type) = get_error_type(cx, result_type) { - if self.has_debug_impl(error_type, cx) { + if has_debug_impl(error_type, cx) { span_lint(cx, OK_EXPECT, expr.span, "called `ok().expect()` on a Result \ value. You can call `expect` directly @@ -212,6 +150,27 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { None } +// This checks whether a given type is known to implement Debug. It's +// conservative, i.e. it should not return false positives, but will return +// false negatives. +fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { + let ty = walk_ptrs_ty(ty); + let debug = match cx.tcx.lang_items.debug_trait() { + Some(debug) => debug, + None => return false + }; + let debug_def = cx.tcx.lookup_trait_def(debug); + let mut debug_impl_exists = false; + debug_def.for_each_relevant_impl(cx.tcx, ty, |d| { + let self_ty = &cx.tcx.impl_trait_ref(d).and_then(|im| im.substs.self_ty()); + if let Some(self_ty) = *self_ty { + if !self_ty.flags.get().contains(ty::TypeFlags::HAS_PARAMS) { + debug_impl_exists = true; + } + } + }); + debug_impl_exists +} const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ("into_", &[ValueSelf]), diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index aeb79503504..6d543596cf5 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -54,7 +54,7 @@ fn main() { // the error type implements `Debug` let res2: Result<i32, MyError> = Ok(0); res2.ok().expect("oh noes!"); - // we're currently don't warn if the error type has a type parameter + // we currently don't warn if the error type has a type parameter // (but it would be nice if we did) let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0); res3.ok().expect("whoof"); @@ -62,6 +62,8 @@ fn main() { res4.ok().expect("argh"); //~ERROR called `ok().expect()` let res5: io::Result<u32> = Ok(0); res5.ok().expect("oops"); //~ERROR called `ok().expect()` + let res6: Result<u32, &str> = Ok(0); + res6.ok().expect("meh"); //~ERROR called `ok().expect()` } struct MyError(()); // doesn't implement Debug -- cgit 1.4.1-3-g733a5 From a36707bffd41d5197cf7b081c7594b5663106586 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 19 Nov 2015 20:19:19 +0100 Subject: Appease clippy by not shadowing variables --- src/methods.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 858a5a3dca0..b8c6402544d 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -154,14 +154,14 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { // conservative, i.e. it should not return false positives, but will return // false negatives. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { - let ty = walk_ptrs_ty(ty); + let no_ref_ty = walk_ptrs_ty(ty); let debug = match cx.tcx.lang_items.debug_trait() { Some(debug) => debug, None => return false }; let debug_def = cx.tcx.lookup_trait_def(debug); let mut debug_impl_exists = false; - debug_def.for_each_relevant_impl(cx.tcx, ty, |d| { + debug_def.for_each_relevant_impl(cx.tcx, no_ref_ty, |d| { let self_ty = &cx.tcx.impl_trait_ref(d).and_then(|im| im.substs.self_ty()); if let Some(self_ty) = *self_ty { if !self_ty.flags.get().contains(ty::TypeFlags::HAS_PARAMS) { -- cgit 1.4.1-3-g733a5 From d4cf288b385b9c58cfa0d4c97b3b548bc21b4923 Mon Sep 17 00:00:00 2001 From: John Quigley <jmquigs@gmail.com> Date: Fri, 20 Nov 2015 00:22:52 -0500 Subject: Add block_in_if lint, #434 --- README.md | 158 ++++++++++++++-------------- src/block_in_if_condition.rs | 91 ++++++++++++++++ src/lib.rs | 4 + tests/compile-fail/block_in_if_condition.rs | 64 +++++++++++ 4 files changed, 239 insertions(+), 78 deletions(-) create mode 100644 src/block_in_if_condition.rs create mode 100644 tests/compile-fail/block_in_if_condition.rs (limited to 'src') diff --git a/README.md b/README.md index b893c4e7a17..696836f417d 100644 --- a/README.md +++ b/README.md @@ -6,84 +6,86 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 74 lints included in this crate: - -name | default | meaning --------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` -[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` -[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` -[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` -[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) -[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` -[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected -[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do -[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` -[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases -[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended -[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` -[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block -[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque -[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) -[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead -[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead -[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant -[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 -[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead -[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type -[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do -[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice -[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields -[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect -[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file -[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught -[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 -[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern -[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled -[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` -[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` -[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` -[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value -[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait -[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` -[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op -[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries -[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. -[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions -[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) -[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) -[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference -[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 -[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 -[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop -[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types -[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop -[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator -[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention -[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention -[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN -[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing +There are 76 lints included in this crate: + +name | default | meaning +---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` +[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` +[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` +[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) +[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do +[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended +[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` +[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block +[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) +[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead +[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead +[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant +[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 +[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead +[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type +[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do +[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice +[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect +[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file +[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught +[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 +[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern +[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled +[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` +[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` +[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` +[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value +[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` +[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op +[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries +[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. +[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions +[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) +[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference +[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 +[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 +[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types +[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator +[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention +[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention +[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN +[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs new file mode 100644 index 00000000000..39196ed175f --- /dev/null +++ b/src/block_in_if_condition.rs @@ -0,0 +1,91 @@ +use rustc_front::hir::*; +use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; +use rustc_front::intravisit::{Visitor, walk_expr}; +use utils::*; + +declare_lint! { + pub BLOCK_IN_IF_CONDITION_EXPR, Warn, + "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" +} + +declare_lint! { + pub BLOCK_IN_IF_CONDITION_STMT, Warn, + "avoid complex blocks in conditions, instead move the block higher and bind it \ + with 'let'; e.g: `if { let x = true; x } ...`" +} + +#[derive(Copy,Clone)] +pub struct BlockInIfCondition; + +impl LintPass for BlockInIfCondition { + fn get_lints(&self) -> LintArray { + lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT) + } +} + +struct ExVisitor<'v> { + found_block: Option<&'v Expr> +} + +impl<'v> Visitor<'v> for ExVisitor<'v> { + fn visit_expr(&mut self, expr: &'v Expr) { + if let ExprClosure(_, _, ref block) = expr.node { + let complex = { + if !block.stmts.is_empty() { + true + } else { + if let Some(ref ex) = block.expr { + match ex.node { + ExprBlock(_) => true, + _ => false + } + } else { + false + } + } + }; + if complex { + self.found_block = Some(& expr); + return; + } + } + walk_expr(self, expr); + } +} + +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) { + if let ExprIf(ref check, ref then, _) = expr.node { + if let ExprBlock(ref block) = check.node { + if block.stmts.is_empty() { + if let Some(ref ex) = block.expr { + // don't dig into the expression here, just suggest that they remove + // the block + + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_EXPR, check.span, + BRACED_EXPR_MESSAGE, + &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, ".."))); + } + } else { + // move block higher + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, check.span, + COMPLEX_BLOCK_MESSAGE, + &format!("try\nlet res = {};\nif res {} ... ", + snippet_block(cx, block.span, ".."), + snippet_block(cx, then.span, ".."))); + } + } else { + let mut visitor = ExVisitor { found_block: None }; + walk_expr(&mut visitor, check); + if let Some(ref block) = visitor.found_block { + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, + COMPLEX_BLOCK_MESSAGE, ""); + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index afbf3d2a92c..9507b1d86f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub mod mut_reference; pub mod len_zero; pub mod attrs; pub mod collapsible_if; +pub mod block_in_if_condition; pub mod unicode; pub mod shadow; pub mod strings; @@ -81,6 +82,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box misc::CmpOwned); reg.register_late_lint_pass(box attrs::AttrPass); reg.register_late_lint_pass(box collapsible_if::CollapsibleIf); + reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition); reg.register_late_lint_pass(box misc::ModuloOne); reg.register_late_lint_pass(box unicode::Unicode); reg.register_late_lint_pass(box strings::StringAdd); @@ -131,6 +133,8 @@ pub fn plugin_registrar(reg: &mut Registry) { attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, + block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, + block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, eq_op::EQ_OP, eta_reduction::REDUNDANT_CLOSURE, diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs new file mode 100644 index 00000000000..c075d48297e --- /dev/null +++ b/tests/compile-fail/block_in_if_condition.rs @@ -0,0 +1,64 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(block_in_if_condition_expr)] +#![deny(block_in_if_condition_stmt)] +#![allow(unused)] + +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' + let x = 3; + x == 3 + } { + 6 + } else { + 10 + } +} + +fn condition_has_block_with_single_expression() -> i32 { + if { true } { //~ERROR omit braces around single expression condition + 6 + } else { + 10 + } +} + +fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val:T) -> bool { + pfn(val) +} + +fn pred_test() { + let v = 3; + let sky = "blue"; + // 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 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' + + } + +} + +fn condition_is_normal() -> i32 { + let x = 3; + if true && x == 3 { + 6 + } else { + 10 + } +} + +fn closure_without_block() { + if predicate(|x| x == 3, 6) { + + } +} + +fn main() { +} -- cgit 1.4.1-3-g733a5 From b40e80f039afb01fefca508e7f7c5d31fa280a6a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 23 Nov 2015 16:34:23 +0530 Subject: spurious newline --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index b8c6402544d..e40531a4d66 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -85,7 +85,7 @@ impl LateLintPass for MethodsPass { if has_debug_impl(error_type, cx) { span_lint(cx, OK_EXPECT, expr.span, "called `ok().expect()` on a Result \ - value. You can call `expect` directly + value. You can call `expect` directly \ on the `Result`"); } } -- cgit 1.4.1-3-g733a5 From a3e8091e875a34aa288f675f90c657fa0a86f0e6 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Wed, 25 Nov 2015 02:44:40 +0900 Subject: Dogfood match_ref_pats for `if let` --- src/approx_const.rs | 2 +- src/attrs.rs | 2 +- src/bit_mask.rs | 2 +- src/len_zero.rs | 2 +- src/lifetimes.rs | 2 +- src/misc.rs | 8 ++++---- src/mutex_atomic.rs | 2 +- src/ptr_arg.rs | 6 +++--- src/ranges.rs | 4 ++-- src/shadow.rs | 6 +++--- src/strings.rs | 6 +++--- 11 files changed, 21 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 89cb5204a8c..9d1d51444fa 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -44,7 +44,7 @@ impl LintPass for ApproxConstant { impl LateLintPass for ApproxConstant { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let &ExprLit(ref lit) = &e.node { + if let ExprLit(ref lit) = e.node { check_lit(cx, lit, e); } } diff --git a/src/attrs.rs b/src/attrs.rs index a0101688668..f4a5b4c1517 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -42,7 +42,7 @@ impl LateLintPass for AttrPass { } fn is_relevant_item(item: &Item) -> bool { - if let &ItemFn(_, _, _, _, _, ref block) = &item.node { + if let ItemFn(_, _, _, _, _, ref block) = item.node { is_relevant_block(block) } else { false } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index c8530b92d48..ab73086d07b 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -182,7 +182,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { - if let &LitInt(value, _) = &lit_ptr.node { + if let LitInt(value, _) = lit_ptr.node { Option::Some(value) //TODO: Handle sign } else { Option::None } } diff --git a/src/len_zero.rs b/src/len_zero.rs index 25645ea8742..9ac4ab1e0e0 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -125,7 +125,7 @@ fn check_len_zero(cx: &LateContext, span: Span, name: &Name, fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { /// get a ImplOrTraitItem and return true if it matches is_empty(self) fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { - if let &MethodTraitItemId(def_id) = id { + if let MethodTraitItemId(def_id) = *id { if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { method.name.as_str() == "is_empty" diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 9b47a4d830f..acc7b014052 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -168,7 +168,7 @@ impl <'v, 't> RefVisitor<'v, 't> { } fn record(&mut self, lifetime: &Option<Lifetime>) { - if let &Some(ref lt) = lifetime { + if let Some(ref lt) = *lifetime { if lt.name.as_str() == "'static" { self.lts.push(Static); } else { diff --git a/src/misc.rs b/src/misc.rs index 9a8ce74e997..9df751d49b7 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -84,10 +84,10 @@ impl LateLintPass for CmpNan { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { - if let &ExprPath(_, ref path) = &left.node { + if let ExprPath(_, ref path) = left.node { check_nan(cx, path, expr.span); } - if let &ExprPath(_, ref path) = &right.node { + if let ExprPath(_, ref path) = right.node { check_nan(cx, path, expr.span); } } @@ -189,7 +189,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o } } ExprCall(ref path, ref v) if v.len() == 1 => { - if let &ExprPath(None, ref path) = &path.node { + if let ExprPath(None, ref path) = path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { snippet(cx, v[0].span, "..") @@ -235,7 +235,7 @@ impl LintPass for ModuloOne { impl LateLintPass for ModuloOne { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, _, ref right) = expr.node { - if let &Spanned {node: BinOp_::BiRem, ..} = cmp { + if let Spanned {node: BinOp_::BiRem, ..} = *cmp { if is_integer_literal(right, 1) { cx.span_lint(MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 9c10a062419..e6d1fc8a888 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -34,7 +34,7 @@ pub struct MutexAtomic; impl LateLintPass for MutexAtomic { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { let ty = cx.tcx.expr_ty(expr); - if let &ty::TyStruct(_, subst) = &ty.sty { + if let ty::TyStruct(_, subst) = ty.sty { if match_type(cx, ty, &MUTEX_PATH) { let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; if let Some(atomic_name) = get_atomic_name(mutex_param) { diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 78be2af1217..6946d0549d0 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -28,13 +28,13 @@ impl LintPass for PtrArg { impl LateLintPass for PtrArg { fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let &ItemFn(ref decl, _, _, _, _, _) = &item.node { + if let ItemFn(ref decl, _, _, _, _, _) = item.node { check_fn(cx, decl); } } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if let &ImplItemKind::Method(ref sig, _) = &item.node { + if let ImplItemKind::Method(ref sig, _) = item.node { if let Some(Node::NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { if let ItemImpl(_, _, _, Some(_), _, _) = it.node { return; // ignore trait impls @@ -45,7 +45,7 @@ impl LateLintPass for PtrArg { } fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - if let &MethodTraitItem(ref sig, _) = &item.node { + if let MethodTraitItem(ref sig, _) = item.node { check_fn(cx, &sig.decl); } } diff --git a/src/ranges.rs b/src/ranges.rs index 39ff7d3cd31..31bb985230d 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -40,10 +40,10 @@ impl LateLintPass for StepByZero { if_let_chain! { [ // .iter() call - let &ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = iter, + let ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = *iter, iter_name.as_str() == "iter", // range expression in .zip() call: 0..x.len() - let &ExprRange(Some(ref from), Some(ref to)) = zip_arg, + let ExprRange(Some(ref from), Some(ref to)) = *zip_arg, is_integer_literal(from, 0), // .len() call let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = to.node, diff --git a/src/shadow.rs b/src/shadow.rs index 3f72722333b..5fb27f75c3c 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -63,8 +63,8 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if is_from_for_desugar(decl) { return; } if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, id: _, span } = **local; - if let &Some(ref t) = ty { check_ty(cx, t, bindings) } - if let &Some(ref o) = init { + if let Some(ref t) = *ty { check_ty(cx, t, bindings) } + if let Some(ref o) = *init { check_expr(cx, o, bindings); check_pat(cx, pat, &Some(o), span, bindings); } else { @@ -210,7 +210,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { 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); } + if let Some(ref o) = *otherwise { check_expr(cx, o, bindings); } } ExprWhile(ref cond, ref block, _) => { check_expr(cx, cond, bindings); diff --git a/src/strings.rs b/src/strings.rs index 08274657538..3c34e188d11 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -34,14 +34,14 @@ impl LintPass for StringAdd { impl LateLintPass for StringAdd { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node { + if let ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = e.node { if is_string(cx, left) { if let Allow = cx.current_level(STRING_ADD_ASSIGN) { // the string_add_assign is allow, so no duplicates } else { let parent = get_parent_expr(cx, e); if let Some(ref p) = parent { - if let &ExprAssign(ref target, _) = &p.node { + if let ExprAssign(ref target, _) = p.node { // avoid duplicate matches if is_exp_equal(cx, target, left) { return; } } @@ -51,7 +51,7 @@ impl LateLintPass for StringAdd { "you added something to a string. \ Consider using `String::push_str()` instead") } - } else if let &ExprAssign(ref target, ref src) = &e.node { + } else if let ExprAssign(ref target, ref src) = e.node { if is_string(cx, target) && is_add(cx, src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ -- cgit 1.4.1-3-g733a5 From 746991572fac33ba29c4d1a83574d3b7c2776998 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Wed, 25 Nov 2015 02:47:17 +0900 Subject: Extend match_ref_pats to desugared matches --- src/matches.rs | 49 ++++++++++++++++++++++++++++++------------- tests/compile-fail/matches.rs | 16 +++++++++++--- 2 files changed, 47 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index eaa3e0026a3..55eb4fe381b 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -25,9 +25,8 @@ impl LintPass for MatchPass { impl LateLintPass for MatchPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_external_macro(cx, expr.span) { return; } if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { - if in_external_macro(cx, expr.span) { return; } - // check preconditions for SINGLE_MATCH // only two arms if arms.len() == 2 && @@ -53,19 +52,6 @@ impl LateLintPass for MatchPass { expr_block(cx, &arms[0].body, None, ".."))); } - // check preconditions for MATCH_REF_PATS - if has_only_ref_pats(arms) { - if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "you don't need to add `&` to both the expression to match \ - and the patterns: use `match {} {{ ...`", snippet(cx, inner.span, ".."))); - } else { - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "instead of prefixing all patterns with `&`, you can dereference the \ - expression to match: `match *{} {{ ...`", snippet(cx, ex.span, ".."))); - } - } - // check preconditions for MATCH_BOOL // type of expression == bool if cx.tcx.expr_ty(ex).sty == ty::TyBool { @@ -123,6 +109,22 @@ impl LateLintPass for MatchPass { } } } + if let ExprMatch(ref ex, ref arms, source) = expr.node { + // check preconditions for MATCH_REF_PATS + if has_only_ref_pats(arms) { + if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { + let template = match_template(source, "", &snippet(cx, inner.span, "..")); + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "you don't need to add `&` to both the expression \ + and the patterns: use `{}`", template)); + } else { + let template = match_template(source, "*", &snippet(cx, ex.span, "..")); + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "instead of prefixing all patterns with `&`, you can dereference the \ + expression: `{}`", template)); + } + } + } } } @@ -143,3 +145,20 @@ fn has_only_ref_pats(arms: &[Arm]) -> bool { // look for Some(v) where there's at least one true element mapped.map_or(false, |v| v.iter().any(|el| *el)) } + +fn match_template(source: MatchSource, op: &str, expr: &str) -> String { + match source { + MatchSource::Normal => { + format!("match {}{} {{ ...", op, expr) + } + MatchSource::IfLetDesugar { .. } => { + format!("if let ... = {}{} {{", op, expr) + } + MatchSource::WhileLetDesugar => { + format!("while let ... = {}{} {{", op, expr) + } + MatchSource::ForLoopDesugar => { + panic!("for loop desugared to match with &-patterns!") + } + } +} diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 20d7552d77a..ea3a48a94f5 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -78,7 +78,7 @@ fn match_bool() { fn ref_pats() { { let v = &Some(0); - match v { //~ERROR instead of prefixing all patterns with `&` + match v { //~ERROR dereference the expression: `match *v { ...` &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -88,13 +88,13 @@ fn ref_pats() { } } let tup =& (1, 2); - match tup { //~ERROR instead of prefixing all patterns with `&` + match tup { //~ERROR dereference the expression: `match *tup { ...` &(v, 1) => println!("{}", v), _ => println!("none"), } // special case: using & both in expr and pats let w = Some(0); - match &w { //~ERROR you don't need to add `&` to both + match &w { //~ERROR use `match w { ...` &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -103,6 +103,16 @@ fn ref_pats() { match w { _ => println!("none"), } + + let a = &Some(0); + if let &None = a { //~ERROR dereference the expression: `if let ... = *a {` + println!("none"); + } + + let b = Some(0); + if let &None = &b { //~ERROR use `if let ... = b {` + println!("none"); + } } fn main() { -- cgit 1.4.1-3-g733a5 From b1a0abe404740e1425a8586c7519114578d20372 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Wed, 25 Nov 2015 13:57:50 +0900 Subject: Don't panic --- src/matches.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 55eb4fe381b..ec118052fbc 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -2,6 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; use syntax::ast::Lit_::LitBool; +use syntax::codemap::Span; use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; @@ -113,12 +114,12 @@ impl LateLintPass for MatchPass { // check preconditions for MATCH_REF_PATS if has_only_ref_pats(arms) { if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { - let template = match_template(source, "", &snippet(cx, inner.span, "..")); + let template = match_template(cx, expr.span, source, "", inner); span_lint(cx, MATCH_REF_PATS, expr.span, &format!( "you don't need to add `&` to both the expression \ and the patterns: use `{}`", template)); } else { - let template = match_template(source, "*", &snippet(cx, ex.span, "..")); + let template = match_template(cx, expr.span, source, "*", ex); span_lint(cx, MATCH_REF_PATS, expr.span, &format!( "instead of prefixing all patterns with `&`, you can dereference the \ expression: `{}`", template)); @@ -146,19 +147,24 @@ fn has_only_ref_pats(arms: &[Arm]) -> bool { mapped.map_or(false, |v| v.iter().any(|el| *el)) } -fn match_template(source: MatchSource, op: &str, expr: &str) -> String { +fn match_template(cx: &LateContext, + span: Span, + source: MatchSource, + op: &str, + expr: &Expr) -> String { + let expr_snippet = snippet(cx, expr.span, ".."); match source { MatchSource::Normal => { - format!("match {}{} {{ ...", op, expr) + format!("match {}{} {{ ...", op, expr_snippet) } MatchSource::IfLetDesugar { .. } => { - format!("if let ... = {}{} {{", op, expr) + format!("if let ... = {}{} {{", op, expr_snippet) } MatchSource::WhileLetDesugar => { - format!("while let ... = {}{} {{", op, expr) + format!("while let ... = {}{} {{", op, expr_snippet) } MatchSource::ForLoopDesugar => { - panic!("for loop desugared to match with &-patterns!") + cx.sess().span_bug(span, "for loop desugared to match with &-patterns!") } } } -- cgit 1.4.1-3-g733a5 From cf540064492a724bcaa155a2a484eadb26e3e66c Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 25 Nov 2015 16:28:29 +0100 Subject: Fixes to build with current rust nightly --- src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 1750495d1f3..791bf587bb5 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -195,9 +195,9 @@ impl fmt::Display for Constant { let (sign, suffix) = match *ity { LitIntType::SignedIntLit(ref sity, ref sign) => (if let Sign::Minus = *sign { "-" } else { "" }, - ast_util::int_ty_to_string(*sity, None)), + ast_util::int_ty_to_string(*sity)), LitIntType::UnsignedIntLit(ref uity) => - ("", ast_util::uint_ty_to_string(*uity, None)), + ("", ast_util::uint_ty_to_string(*uity)), LitIntType::UnsuffixedIntLit(ref sign) => (if let Sign::Minus = *sign { "-" } else { "" }, "".into()), -- cgit 1.4.1-3-g733a5 From 94dc2f567ab7cd84a1d200749ca376eb7a5d96ec Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 26 Nov 2015 00:09:01 +0100 Subject: Suppress explicit_counter_loop lint if loop variable is used after the loop --- src/loops.rs | 25 +++++++++++++++++-------- tests/compile-fail/for_loop.rs | 9 ++++----- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 92dff3a7d93..cfde1741715 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -150,7 +150,8 @@ impl LateLintPass for LoopsPass { for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), state: VarState::IncrOnce, name: None, - depth: 0, done: false }; + depth: 0, + past_loop: false }; walk_block(&mut visitor2, block); if visitor2.state == VarState::Warn { @@ -502,7 +503,7 @@ struct InitializeVisitor<'v, 't: 'v> { state: VarState, name: Option<Name>, depth: u32, // depth of conditional expressions - done: bool + past_loop: bool } impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { @@ -530,12 +531,16 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { } fn visit_expr(&mut self, expr: &'v Expr) { - if self.state == VarState::DontWarn || expr == self.end_expr { - self.done = true; + if self.state == VarState::DontWarn { + return; + } + if expr == self.end_expr { + self.past_loop = true; + return; } // No need to visit expressions before the variable is - // declared or after we've rejected it. - if self.state == VarState::IncrOnce || self.done { + // declared + if self.state == VarState::IncrOnce { return; } @@ -556,11 +561,15 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { _ => () } } + + if self.past_loop { + self.state = VarState::DontWarn; + return; + } } // If there are other loops between the declaration and the target loop, give up - else if is_loop(expr) { + else if !self.past_loop && is_loop(expr) { self.state = VarState::DontWarn; - self.done = true; return; } // Keep track of whether we're inside a conditional expression diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 02c8cc56083..3d19bd66094 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -132,11 +132,6 @@ fn main() { _index = 0; for _v in &vec { _index += 1 } //~ERROR the variable `_index` is used as a loop counter - let mut _index; - _index = 0; - for _v in &vec { _index += 1 } //~ERROR the variable `_index` is used as a loop counter - for _v in &vec { _index += 1 } // But this does not warn - // Potential false positives let mut _index = 0; _index = 1; @@ -187,4 +182,8 @@ fn main() { let mut _index = 0; { let mut _x = &mut _index; } for _v in &vec { _index += 1 } + + let mut index = 0; + for _v in &vec { index += 1 } + println!("index: {}", index); } -- cgit 1.4.1-3-g733a5 From 443e4556c2fec853cea4fb93f1c3e309ff5c98a4 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sun, 22 Nov 2015 21:48:19 -0800 Subject: Add lints suggesting map_or() and map_or_else() In accordance with the latter lint, replace map().unwrap_or_else() in src/mut_mut.rs with map_or_else() --- README.md | 4 ++- src/lib.rs | 2 ++ src/methods.rs | 72 +++++++++++++++++++++++++++++++++++++++++-- src/mut_mut.rs | 23 ++++++++------ tests/compile-fail/methods.rs | 49 +++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index ae19f6ff9d7..0a10c849ca7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 77 lints included in this crate: +There are 79 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -53,6 +53,8 @@ name [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result +[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`) +[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [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 diff --git a/src/lib.rs b/src/lib.rs index 3664803d022..12cb14f7355 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,8 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::OK_EXPECT, + methods::OPTION_MAP_UNWRAP_OR, + methods::OPTION_MAP_UNWRAP_OR_ELSE, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, diff --git a/src/methods.rs b/src/methods.rs index b8c6402544d..f1b610c6211 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -5,7 +5,7 @@ use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; -use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth, +use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, walk_ptrs_ty_depth, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; @@ -34,12 +34,18 @@ declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, declare_lint!(pub OK_EXPECT, Warn, "using `ok().expect()`, which gives worse error messages than \ calling `expect` directly on the Result"); - +declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, + "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ + `map_or(a, f)`)"); +declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, + "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ + `map_or_else(g, f)`)"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, - SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT) + SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT, OPTION_MAP_UNWRAP_OR, + OPTION_MAP_UNWRAP_OR_ELSE) } } @@ -92,6 +98,66 @@ impl LateLintPass for MethodsPass { } } } + // check Option.map(_).unwrap_or(_) + else if name.node.as_str() == "unwrap_or" { + if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + if inner_name.node.as_str() == "map" + && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { + // lint message + let msg = + "called `map(f).unwrap_or(a)` on an Option value. This can be done \ + more directly by calling `map_or(a, f)` instead"; + // get args to map() and unwrap_or() + let map_arg = snippet(cx, inner_args[1].span, ".."); + let unwrap_arg = snippet(cx, args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or() have the same span + let multiline = map_arg.lines().count() > 1 + || unwrap_arg.lines().count() > 1; + let same_span = inner_args[1].span.expn_id == args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint( + cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, + &format!("replace this with map_or({1}, {0})", + map_arg, unwrap_arg) + ); + } + else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); + }; + } + } + } + // check Option.map(_).unwrap_or_else(_) + else if name.node.as_str() == "unwrap_or_else" { + if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + if inner_name.node.as_str() == "map" + && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { + // lint message + let msg = + "called `map(f).unwrap_or_else(g)` on an Option value. This can be \ + done more directly by calling `map_or_else(g, f)` instead"; + // get args to map() and unwrap_or_else() + let map_arg = snippet(cx, inner_args[1].span, ".."); + let unwrap_arg = snippet(cx, args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or_else() have the same span + let multiline = map_arg.lines().count() > 1 + || unwrap_arg.lines().count() > 1; + let same_span = inner_args[1].span.expn_id == args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint( + cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg, expr.span, + &format!("replace this with map_or_else({1}, {0})", + map_arg, unwrap_arg) + ); + } + else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); + }; + } + } + } } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index a92338165dd..09ba7d781a2 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -39,17 +39,20 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { } unwrap_addr(expr).map_or((), |e| { - unwrap_addr(e).map(|_| { - span_lint(cx, MUT_MUT, expr.span, - "generally you want to avoid `&mut &mut _` if possible") - }).unwrap_or_else(|| { - if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = - cx.tcx.expr_ty(e).sty { - span_lint(cx, MUT_MUT, expr.span, - "this expression mutably borrows a mutable reference. \ - Consider reborrowing") + unwrap_addr(e).map_or_else( + || { + if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = + cx.tcx.expr_ty(e).sty { + span_lint(cx, MUT_MUT, expr.span, + "this expression mutably borrows a mutable reference. \ + Consider reborrowing") } - }) + }, + |_| { + span_lint(cx, MUT_MUT, expr.span, + "generally you want to avoid `&mut &mut _` if possible") + } + ) }) } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 6d543596cf5..9078a78d6fe 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -34,6 +34,55 @@ impl Mul<T> for T { fn mul(self, other: T) -> T { self } // no error, obviously } +/// Utility macro to test linting behavior in `option_methods()` +/// The lints included in `option_methods()` should not lint if the call to map is partially +/// within a macro +macro_rules! opt_map { + ($opt:expr, $map:expr) => {($opt).map($map)}; +} + +/// Checks implementation of the following lints: +/// OPTION_MAP_UNWRAP_OR +/// OPTION_MAP_UNWRAP_OR_ELSE +fn option_methods() { + let opt = Some(1); + + // Check OPTION_MAP_UNWRAP_OR + // single line case + let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)` + //~| NOTE replace this + .unwrap_or(0); // should lint even though this call is on a separate line + // multi line cases + let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)` + x + 1 + } + ).unwrap_or(0); + let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)` + .unwrap_or({ + 0 + }); + // macro case + let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint + + // Check OPTION_MAP_UNWRAP_OR_ELSE + // single line case + let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)` + //~| NOTE replace this + .unwrap_or_else(|| 0); // should lint even though this call is on a separate line + // multi line cases + let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or_else(g)` + x + 1 + } + ).unwrap_or_else(|| 0); + let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)` + .unwrap_or_else(|| + 0 + ); + // macro case + let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint + +} + fn main() { use std::io; -- cgit 1.4.1-3-g733a5 From 7d583dab80d7cadaa8283e59e7e5ce9f657b8a20 Mon Sep 17 00:00:00 2001 From: Hobofan <goisser94@gmail.com> Date: Fri, 27 Nov 2015 14:47:00 +0100 Subject: fix for latest nightly Fixes breakage introduced by rust-lang/rust#30043 --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 12cb14f7355..7f3f9009411 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,9 @@ extern crate collections; // for unicode nfc normalization extern crate unicode_normalization; -use rustc::plugin::Registry; +extern crate rustc_plugin; + +use rustc_plugin::Registry; #[macro_use] pub mod utils; -- cgit 1.4.1-3-g733a5 From ba59ed05e334d70b50fca18befa1790f509dbee1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 30 Nov 2015 23:16:28 +0530 Subject: Rust upgrade to rustc 1.6.0-nightly (52d95e644 2015-11-30) --- src/matches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index ec118052fbc..b6a7fc7fa5b 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -140,7 +140,7 @@ 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 { PatRegion(..) => Some(true), // &-patterns - PatWild(..) => Some(false), // an "anything" wildcard is also fine + PatWild => Some(false), // an "anything" wildcard is also fine _ => None, // any other pattern is not fine }).collect::<Option<Vec<bool>>>(); // look for Some(v) where there's at least one true element -- cgit 1.4.1-3-g733a5 From 26f539eaa379675b7736a652705e1fdde1c7bc9f Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Sat, 28 Nov 2015 00:47:24 +0900 Subject: Remove unused qualifications --- src/bit_mask.rs | 8 ++++---- src/mut_mut.rs | 8 ++++---- src/mut_reference.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index ab73086d07b..bee99b0f783 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -183,8 +183,8 @@ fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { if let LitInt(value, _) = lit_ptr.node { - Option::Some(value) //TODO: Handle sign - } else { Option::None } + Some(value) //TODO: Handle sign + } else { None } } ExprPath(_, _) => { // Important to let the borrow expire before the const lookup to avoid double @@ -195,8 +195,8 @@ fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { _ => None } } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None)) + .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None)) .and_then(|l| fetch_int_literal(cx, l)), - _ => Option::None + _ => None } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 09ba7d781a2..c361ab24831 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -33,8 +33,8 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { fn unwrap_addr(expr: &Expr) -> Option<&Expr> { match expr.node { - ExprAddrOf(MutMutable, ref e) => Option::Some(e), - _ => Option::None + ExprAddrOf(MutMutable, ref e) => Some(e), + _ => None } } @@ -58,7 +58,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { fn unwrap_mut(ty: &Ty) -> Option<&Ty> { match ty.node { - TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty), - _ => Option::None + TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Some(pty), + _ => None } } diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 86c272affb7..e9601e8650f 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -60,7 +60,7 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty match parameter.sty { TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { - if let Expr_::ExprAddrOf(MutMutable, _) = argument.node { + if let ExprAddrOf(MutMutable, _) = argument.node { span_lint(cx, UNNECESSARY_MUT_PASSED, argument.span, &format!("The function/method \"{}\" \ doesn't need a mutable reference", -- cgit 1.4.1-3-g733a5 From 617c820e6b0edebacdf5295cfa8333af023f98e1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 18 Nov 2015 12:35:18 +0100 Subject: compute cyclomatic complexity (adjusted to not punish Rust's `match`) --- .gitignore | 3 + README.md | 3 +- src/cyclomatic_complexity.rs | 105 +++++++++++++ src/lib.rs | 5 +- src/lifetimes.rs | 19 ++- src/loops.rs | 224 ++++++++++++++-------------- src/matches.rs | 2 +- src/utils.rs | 66 +++++++- tests/compile-fail/cyclomatic_complexity.rs | 181 ++++++++++++++++++++++ tests/compile-fail/for_loop.rs | 2 +- tests/compile-fail/while_loop.rs | 2 +- 11 files changed, 485 insertions(+), 127 deletions(-) create mode 100644 src/cyclomatic_complexity.rs create mode 100644 tests/compile-fail/cyclomatic_complexity.rs (limited to 'src') diff --git a/.gitignore b/.gitignore index ac98a7d842f..acb3c020fe7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ # We don't pin yet Cargo.lock + +# Generated by dogfood +/target_recur/ diff --git a/README.md b/README.md index 0a10c849ca7..206d86ec1ee 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 79 lints included in this crate: +There are 80 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -22,6 +22,7 @@ name [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs new file mode 100644 index 00000000000..678ebe866cb --- /dev/null +++ b/src/cyclomatic_complexity.rs @@ -0,0 +1,105 @@ +//! calculate cyclomatic complexity and warn about overly complex functions + +use rustc::lint::*; +use rustc_front::hir::*; +use rustc::middle::cfg::CFG; +use syntax::codemap::Span; +use syntax::attr::*; +use syntax::ast::Attribute; +use rustc_front::intravisit::{Visitor, walk_expr}; + +use utils::{in_macro, LimitStack}; + +declare_lint! { pub CYCLOMATIC_COMPLEXITY, Warn, + "finds functions that should be split up into multiple functions" } + +pub struct CyclomaticComplexity { + limit: LimitStack, +} + +impl CyclomaticComplexity { + pub fn new(limit: u64) -> Self { + CyclomaticComplexity { + limit: LimitStack::new(limit), + } + } +} + +impl LintPass for CyclomaticComplexity { + fn get_lints(&self) -> LintArray { + lint_array!(CYCLOMATIC_COMPLEXITY) + } +} + +impl CyclomaticComplexity { + fn check(&mut self, cx: &LateContext, block: &Block, span: Span) { + if in_macro(cx, span) { return; } + let cfg = CFG::new(cx.tcx, block); + let n = cfg.graph.len_nodes() as u64; + let e = cfg.graph.len_edges() as u64; + let cc = e + 2 - n; + let mut arm_counter = MatchArmCounter(0); + arm_counter.visit_block(block); + let mut narms = arm_counter.0; + if narms > 0 { + narms = narms - 1; + } + if cc < narms { + println!("cc = {}, arms = {}", cc, narms); + println!("{:?}", block); + println!("{:?}", span); + panic!("cc = {}, arms = {}", cc, narms); + } + let rust_cc = cc - narms; + if rust_cc > self.limit.limit() { + cx.span_lint_help(CYCLOMATIC_COMPLEXITY, span, + &format!("The function has a cyclomatic complexity of {}.", rust_cc), + "You could split it up into multiple smaller functions"); + } + } +} + +impl LateLintPass for CyclomaticComplexity { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemFn(_, _, _, _, _, ref block) = item.node { + self.check(cx, block, item.span); + } + } + + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + if let ImplItemKind::Method(_, ref block) = item.node { + self.check(cx, block, item.span); + } + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + if let MethodTraitItem(_, Some(ref block)) = item.node { + self.check(cx, block, item.span); + } + } + + fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + } + fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + } +} + +struct MatchArmCounter(u64); + +impl<'a> Visitor<'a> for MatchArmCounter { + fn visit_expr(&mut self, e: &'a Expr) { + match e.node { + ExprMatch(_, ref arms, _) => { + walk_expr(self, e); + let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum(); + if arms_n > 0 { + self.0 += arms_n - 1; + } + }, + ExprClosure(..) => {}, + _ => walk_expr(self, e), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 7f3f9009411..33ae07b7ad8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, core, collections)] -#![feature(num_bits_bytes)] +#![feature(num_bits_bytes, iter_arith)] #![allow(unknown_lints)] #[macro_use] @@ -59,6 +59,7 @@ pub mod needless_update; pub mod no_effect; pub mod temporary_assignment; pub mod transmute; +pub mod cyclomatic_complexity; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -110,6 +111,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); reg.register_late_lint_pass(box transmute::UselessTransmute); + reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25)); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -138,6 +140,7 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, + cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, eq_op::EQ_OP, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index acc7b014052..97eb7fa67a3 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -108,7 +108,7 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> // no input lifetimes? easy case! if input_lts.is_empty() { - return false; + false } else if output_lts.is_empty() { // no output lifetimes, check distinctness of input lifetimes @@ -117,9 +117,7 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> return false; } // we have no output reference, so we only need all distinct lifetimes - if input_lts.len() == unique_lifetimes(&input_lts) { - return true; - } + input_lts.len() == unique_lifetimes(&input_lts) } else { // we have output references, so we need one input reference, // and all output lifetimes must be the same @@ -128,15 +126,16 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> } if input_lts.len() == 1 { match (&input_lts[0], &output_lts[0]) { - (&Named(n1), &Named(n2)) if n1 == n2 => { return true; } - (&Named(_), &Unnamed) => { return true; } - (&Unnamed, &Named(_)) => { return true; } - _ => { } // already elided, different named lifetimes - // or something static going on + (&Named(n1), &Named(n2)) if n1 == n2 => true, + (&Named(_), &Unnamed) => true, + (&Unnamed, &Named(_)) => true, + _ => false // already elided, different named lifetimes + // or something static going on } + } else { + false } } - false } fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { diff --git a/src/loops.rs b/src/loops.rs index cfde1741715..393c92b16ef 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -56,116 +56,7 @@ impl LintPass for LoopsPass { impl LateLintPass for LoopsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let Some((pat, arg, body)) = recover_for_loop(expr) { - // check for looping over a range and then indexing a sequence with it - // -> the iteratee must be a range literal - if let ExprRange(Some(ref l), _) = arg.node { - // Range should start with `0` - if let ExprLit(ref lit) = l.node { - if let LitInt(0, _) = lit.node { - - // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { cx: cx, var: ident.node.name, - indexed: HashSet::new(), nonindex: false }; - walk_expr(&mut visitor, body); - // linting condition: we only indexed one variable - if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().expect( - "Len was nonzero, but no contents found"); - if visitor.nonindex { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is used to index `{}`. Consider using \ - `for ({}, item) in {}.iter().enumerate()` or similar iterators", - ident.node.name, indexed, ident.node.name, indexed)); - } else { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in &{}` or similar iterators", - ident.node.name, indexed, indexed)); - } - } - } - } - } - } - - // if this for loop is iterating over a two-sided range... - if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { - // ...and both sides are compile-time constant integers... - if let Some(start_idx @ Constant::ConstantInt(..)) = constant_simple(start_expr) { - if let Some(stop_idx @ Constant::ConstantInt(..)) = constant_simple(stop_expr) { - // ...and the start index is greater than the stop index, - // this loop will never run. This is often confusing for developers - // who think that this will iterate from the larger value to the - // smaller value. - if start_idx > stop_idx { - span_help_and_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run", - &format!("Consider using `({}..{}).rev()` if you are attempting to \ - iterate over this range in reverse", stop_idx, start_idx)); - } else if start_idx == stop_idx { - // if they are equal, it's also problematic - this loop - // will never run. - span_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run"); - } - } - } - } - - if let ExprMethodCall(ref method, _, ref args) = arg.node { - // just the receiver, no arguments - if args.len() == 1 { - let method_name = method.node; - // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { - if is_ref_iterable_type(cx, &args[0]) { - let object = snippet(cx, args[0].span, "_"); - span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( - "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", - if method_name.as_str() == "iter_mut" { "mut " } else { "" }, - object, object, method_name)); - } - } - // check for looping over Iterator::next() which is not what you want - else if method_name.as_str() == "next" && - match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { - span_lint(cx, ITER_NEXT_LOOP, expr.span, - "you are iterating over `Iterator::next()` which is an Option; \ - this will compile but is probably not what you want"); - } - } - } - - // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor { cx: cx, states: HashMap::new(), depth: 0, done: false }; - walk_expr(&mut visitor, body); - - // For each candidate, check the parent block to see if - // it's initialized to zero at the start of the loop. - let map = &cx.tcx.map; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id) ); - if let Some(parent_id) = parent_scope { - if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { - let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), - state: VarState::IncrOnce, name: None, - depth: 0, - past_loop: false }; - walk_block(&mut visitor2, block); - - if visitor2.state == VarState::Warn { - if let Some(name) = visitor2.name { - span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, - &format!("the variable `{0}` is used as a loop counter. Consider \ - using `for ({0}, item) in {1}.enumerate()` \ - or similar iterators", - name, snippet(cx, arg.span, "_"))); - } - } - } - } - } + check_for_loop(cx, pat, arg, body, expr); } // check for `loop { if let {} else break }` that could be `while let` // (also matches an explicit "match" instead of "if let") @@ -271,6 +162,119 @@ impl LateLintPass for LoopsPass { } } +fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { + // check for looping over a range and then indexing a sequence with it + // -> the iteratee must be a range literal + if let ExprRange(Some(ref l), _) = arg.node { + // Range should start with `0` + if let ExprLit(ref lit) = l.node { + if let LitInt(0, _) = lit.node { + + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { cx: cx, var: ident.node.name, + indexed: HashSet::new(), nonindex: false }; + walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable + if visitor.indexed.len() == 1 { + let indexed = visitor.indexed.into_iter().next().expect( + "Len was nonzero, but no contents found"); + if visitor.nonindex { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is used to index `{}`. Consider using \ + `for ({}, item) in {}.iter().enumerate()` or similar iterators", + ident.node.name, indexed, ident.node.name, indexed)); + } else { + span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( + "the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in &{}` or similar iterators", + ident.node.name, indexed, indexed)); + } + } + } + } + } + } + + // if this for loop is iterating over a two-sided range... + if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { + // ...and both sides are compile-time constant integers... + if let Some(start_idx @ Constant::ConstantInt(..)) = constant_simple(start_expr) { + if let Some(stop_idx @ Constant::ConstantInt(..)) = constant_simple(stop_expr) { + // ...and the start index is greater than the stop index, + // this loop will never run. This is often confusing for developers + // who think that this will iterate from the larger value to the + // smaller value. + if start_idx > stop_idx { + span_help_and_lint(cx, REVERSE_RANGE_LOOP, expr.span, + "this range is empty so this for loop will never run", + &format!("Consider using `({}..{}).rev()` if you are attempting to \ + iterate over this range in reverse", stop_idx, start_idx)); + } else if start_idx == stop_idx { + // if they are equal, it's also problematic - this loop + // will never run. + span_lint(cx, REVERSE_RANGE_LOOP, expr.span, + "this range is empty so this for loop will never run"); + } + } + } + } + + if let ExprMethodCall(ref method, _, ref args) = arg.node { + // just the receiver, no arguments + if args.len() == 1 { + let method_name = method.node; + // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x + if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { + if is_ref_iterable_type(cx, &args[0]) { + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( + "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", + if method_name.as_str() == "iter_mut" { "mut " } else { "" }, + object, object, method_name)); + } + } + // check for looping over Iterator::next() which is not what you want + else if method_name.as_str() == "next" && + match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + span_lint(cx, ITER_NEXT_LOOP, expr.span, + "you are iterating over `Iterator::next()` which is an Option; \ + this will compile but is probably not what you want"); + } + } + } + + // Look for variables that are incremented once per loop iteration. + let mut visitor = IncrementVisitor { cx: cx, states: HashMap::new(), depth: 0, done: false }; + walk_expr(&mut visitor, body); + + // For each candidate, check the parent block to see if + // it's initialized to zero at the start of the loop. + let map = &cx.tcx.map; + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id) ); + if let Some(parent_id) = parent_scope { + if let NodeBlock(block) = map.get(parent_id) { + for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { + let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), + state: VarState::IncrOnce, name: None, + depth: 0, + past_loop: false }; + walk_block(&mut visitor2, block); + + if visitor2.state == VarState::Warn { + if let Some(name) = visitor2.name { + span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, + &format!("the variable `{0}` is used as a loop counter. Consider \ + using `for ({0}, item) in {1}.enumerate()` \ + or similar iterators", + name, snippet(cx, arg.span, "_"))); + } + } + } + } + } +} + /// Recover the essential nodes of a desugared for loop: /// `for pat in arg { body }` becomes `(pat, arg, body)`. fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { diff --git a/src/matches.rs b/src/matches.rs index b6a7fc7fa5b..2c7f0830a53 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -59,7 +59,7 @@ impl LateLintPass for MatchPass { if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { - if let LitBool(val) = lit.node { + if let LitBool(val) = lit.node { if val { Some((&*arms[0].body, &*arms[1].body)) } else { diff --git a/src/utils.rs b/src/utils.rs index 3fcfa66259c..365fc1bf99d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,6 +9,9 @@ use std::borrow::Cow; use syntax::ast::Lit_::*; use syntax::ast; +use rustc::session::Session; +use std::str::FromStr; + // module DefPaths for certain structs/enums we check for pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; @@ -65,8 +68,8 @@ macro_rules! if_let_chain { }; } -/// returns true this expn_info was expanded by any macro -pub fn in_macro(cx: &LateContext, span: Span) -> bool { +/// returns true if this expn_info was expanded by any macro +pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) } @@ -397,3 +400,62 @@ macro_rules! if_let_chain { } }; } + +pub struct LimitStack { + stack: Vec<u64>, +} + +impl Drop for LimitStack { + fn drop(&mut self) { + assert_eq!(self.stack.len(), 1); + } +} + +impl LimitStack { + pub fn new(limit: u64) -> LimitStack { + LimitStack { + stack: vec![limit], + } + } + pub fn limit(&self) -> u64 { + *self.stack.last().expect("there should always be a value in the stack") + } + pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs( + sess, + attrs, + name, + |val| stack.push(val), + ); + } + pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs( + sess, + attrs, + name, + |val| assert_eq!(stack.pop(), Some(val)), + ); + } +} + +fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { + for attr in attrs { + let attr = &attr.node; + if attr.is_sugared_doc { continue; } + if let ast::MetaNameValue(ref key, ref value) = attr.value.node { + if *key == name { + if let LitStr(ref s, _) = value.node { + if let Ok(value) = FromStr::from_str(s) { + f(value) + } else { + sess.span_err(value.span, "not a number"); + } + } else { + unreachable!() + } + } + } + } +} diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs new file mode 100644 index 00000000000..8e3bf123c26 --- /dev/null +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -0,0 +1,181 @@ +#![feature(plugin, custom_attribute)] +#![plugin(clippy)] +#![deny(clippy)] +#![deny(cyclomatic_complexity)] +#![allow(unused)] + +fn main() { //~ ERROR: The function has a cyclomatic complexity of 28. + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } + if true { + println!("a"); + } +} + +#[cyclomatic_complexity = "0"] +fn kaboom() { //~ ERROR: The function has a cyclomatic complexity of 6 + let n = 0; + 'a: for i in 0..20 { + 'b: for j in i..20 { + for k in j..20 { + if k == 5 { + break 'b; + } + if j == 3 && k == 6 { + continue 'a; + } + if k == j { + continue; + } + println!("bake"); + } + } + println!("cake"); + } +} + +fn bloo() { + match 42 { + 0 => println!("hi"), + 1 => println!("hai"), + 2 => println!("hey"), + 3 => println!("hallo"), + 4 => println!("hello"), + 5 => println!("salut"), + 6 => println!("good morning"), + 7 => println!("good evening"), + 8 => println!("good afternoon"), + 9 => println!("good night"), + 10 => println!("bonjour"), + 11 => println!("hej"), + 12 => println!("hej hej"), + 13 => println!("greetings earthling"), + 14 => println!("take us to you leader"), + 15 | 17 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 => println!("take us to you leader"), + 35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 => println!("there is no undefined behavior"), + 55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 73 => println!("I know borrow-fu"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn baa() { //~ ERROR: The function has a cyclomatic complexity of 2 + let x = || match 99 { + 0 => true, + 1 => false, + 2 => true, + 4 => true, + 6 => true, + 9 => true, + _ => false, + }; + if x() { + println!("x"); + } else { + println!("not x"); + } +} + +#[cyclomatic_complexity = "0"] +fn bar() { //~ ERROR: The function has a cyclomatic complexity of 2 + match 99 { + 0 => println!("hi"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn barr() { //~ ERROR: The function has a cyclomatic complexity of 2 + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } +} + +enum Void {} + +#[cyclomatic_complexity = "0"] +fn void(void: Void) { //~ ERROR: The function has a cyclomatic complexity of 1 + if true { + match void { + } + } +} diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 3d19bd66094..7a18c210d0c 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -16,7 +16,7 @@ impl Unrelated { #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] -#[allow(linkedlist,shadow_unrelated,unnecessary_mut_passed)] +#[allow(linkedlist,shadow_unrelated,unnecessary_mut_passed, cyclomatic_complexity)] fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index 7d1904ad446..ee8e4622e0e 100644 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(while_let_loop, empty_loop, while_let_on_iterator)] -#![allow(dead_code, unused)] +#![allow(dead_code, unused, cyclomatic_complexity)] fn main() { let y = Some(true); -- cgit 1.4.1-3-g733a5 From 3d1b7e1957b647ae17eb26d1e1258c4ca2ba4a16 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 18 Nov 2015 17:09:48 +0100 Subject: high-speed-dogfood --- src/lib.rs | 4 ++++ tests/dogfood.rs | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/dogfood.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 33ae07b7ad8..57a92f99900 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,10 @@ #![feature(num_bits_bytes, iter_arith)] #![allow(unknown_lints)] +// this only exists to allow the "dogfood" integration test to work +#[allow(dead_code)] +fn main() { println!("What are you doing? Don't run clippy as an executable"); } + #[macro_use] extern crate syntax; #[macro_use] diff --git a/tests/dogfood.rs b/tests/dogfood.rs new file mode 100644 index 00000000000..61e37c28c94 --- /dev/null +++ b/tests/dogfood.rs @@ -0,0 +1,24 @@ +extern crate compiletest_rs as compiletest; + +use std::path::Path; +use std::env::var; + +#[test] +fn dogfood() { + let mut config = compiletest::default_config(); + + let cfg_mode = "run-pass".parse().ok().expect("Invalid mode"); + let mut s = String::new(); + s.push_str(" -L target/debug/"); + s.push_str(" -L target/debug/deps"); + s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy"); + config.target_rustcflags = Some(s); + if let Ok(name) = var::<&str>("TESTNAME") { + let s : String = name.to_owned(); + config.filter = Some(s) + } + + config.mode = cfg_mode; + + compiletest::runtest::run(config, &Path::new("src/lib.rs")); +} -- cgit 1.4.1-3-g733a5 From 04524c549eaa96a437e7ffd4c509b9de79370e3c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 3 Dec 2015 12:43:50 +0100 Subject: improve cc of function --- src/methods.rs | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index b0758bc6937..f1c868bec07 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -54,20 +54,19 @@ impl LateLintPass for MethodsPass { if let ExprMethodCall(ref name, _, ref args) = expr.node { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - if name.node.as_str() == "unwrap" { - if match_type(cx, obj_ty, &OPTION_PATH) { + match &*name.node.as_str() { + "unwrap" if match_type(cx, obj_ty, &OPTION_PATH) => { span_lint(cx, OPTION_UNWRAP_USED, expr.span, "used unwrap() on an Option value. If you don't want \ to handle the None case gracefully, consider using \ expect() to provide a better panic message"); - } else if match_type(cx, obj_ty, &RESULT_PATH) { + }, + "unwrap" if match_type(cx, obj_ty, &RESULT_PATH) => { span_lint(cx, RESULT_UNWRAP_USED, expr.span, "used unwrap() on a Result value. Graceful handling \ of Err values is preferred"); - } - } - else if name.node.as_str() == "to_string" { - if obj_ty.sty == ty::TyStr { + }, + "to_string" if obj_ty.sty == ty::TyStr => { let mut arg_str = snippet(cx, args[0].span, "_"); if ptr_depth > 1 { arg_str = Cow::Owned(format!( @@ -77,13 +76,12 @@ impl LateLintPass for MethodsPass { } span_lint(cx, STR_TO_STRING, expr.span, &format!( "`{}.to_owned()` is faster", arg_str)); - } else if match_type(cx, obj_ty, &STRING_PATH) { + }, + "to_string" if match_type(cx, obj_ty, &STRING_PATH) => { span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \ `clone()` to make a copy"); - } - } - else if name.node.as_str() == "expect" { - if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + }, + "expect" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { if inner_name.node.as_str() == "ok" && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &RESULT_PATH) { let result_type = cx.tcx.expr_ty(&inner_args[0]); @@ -96,11 +94,9 @@ impl LateLintPass for MethodsPass { } } } - } - } - // check Option.map(_).unwrap_or(_) - else if name.node.as_str() == "unwrap_or" { - if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + }, + // check Option.map(_).unwrap_or(_) + "unwrap_or" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { if inner_name.node.as_str() == "map" && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { // lint message @@ -126,11 +122,9 @@ impl LateLintPass for MethodsPass { span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); }; } - } - } - // check Option.map(_).unwrap_or_else(_) - else if name.node.as_str() == "unwrap_or_else" { - if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { + }, + // check Option.map(_).unwrap_or_else(_) + "unwrap_or_else" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { if inner_name.node.as_str() == "map" && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { // lint message @@ -156,7 +150,8 @@ impl LateLintPass for MethodsPass { span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); }; } - } + }, + _ => {}, } } } -- cgit 1.4.1-3-g733a5 From 18e81c1b59cd908bf3a1c14463533de64df74f5c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 4 Dec 2015 15:42:53 +0530 Subject: Rudimentary escape analysis for Box<T> --- README.md | 3 +- src/escape.rs | 156 ++++++++++++++++++++++++++++++++++ src/lib.rs | 3 + tests/compile-fail/escape_analysis.rs | 81 ++++++++++++++++++ 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 src/escape.rs create mode 100644 tests/compile-fail/escape_analysis.rs (limited to 'src') diff --git a/README.md b/README.md index 206d86ec1ee..e19ab474c5e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 80 lints included in this crate: +There are 81 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -15,6 +15,7 @@ name [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` [block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` [box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary [cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` [cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` [cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` diff --git a/src/escape.rs b/src/escape.rs new file mode 100644 index 00000000000..fbd545acc96 --- /dev/null +++ b/src/escape.rs @@ -0,0 +1,156 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use rustc_front::intravisit as visit; +use rustc::front::map::Node; +use rustc::middle::ty; +use rustc::middle::ty::adjustment::AutoAdjustment; +use rustc::middle::expr_use_visitor::*; +use rustc::middle::infer; +use rustc::middle::mem_categorization::{cmt, Categorization}; +use rustc::util::nodemap::NodeSet; +use syntax::ast::NodeId; +use syntax::codemap::Span; +use utils::span_lint; + +pub struct EscapePass; + +declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); + +struct EscapeDelegate<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, + set: NodeSet, +} + +impl LintPass for EscapePass { + fn get_lints(&self) -> LintArray { + lint_array!(BOXED_LOCAL) + } +} + +impl LateLintPass for EscapePass { + fn check_fn(&mut self, + cx: &LateContext, + _: visit::FnKind, + decl: &FnDecl, + body: &Block, + _: Span, + id: NodeId) { + let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), false); + let mut v = EscapeDelegate { + cx: cx, + set: NodeSet(), + }; + { + let mut vis = ExprUseVisitor::new(&mut v, &infcx); + vis.walk_fn(decl, body); + } + for node in v.set { + span_lint(cx, + BOXED_LOCAL, + cx.tcx.map.span(node), + "local variable doesn't need to be boxed here"); + } + } +} + +impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { + fn consume(&mut self, + _: NodeId, + _: Span, + cmt: cmt<'tcx>, + mode: ConsumeMode) { + + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + if let Move(DirectRefMove) = mode { + // moved out or in. clearly can't be localized + self.set.remove(&lid); + } + } + } + } + fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} + fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { + if let Categorization::Rvalue(..) = cmt.cat { + if let Some(Node::NodeStmt(st)) = self.cx + .tcx + .map + .find(self.cx.tcx.map.get_parent_node(cmt.id)) { + if let StmtDecl(ref decl, _) = st.node { + if let DeclLocal(ref loc) = decl.node { + if let Some(ref ex) = loc.init { + if let ExprBox(..) = ex.node { + if let ty::TyBox(..) = cmt.ty.sty { + // let x = box (...) + self.set.insert(consume_pat.id); + } + // TODO Box::new + // TODO vec![] + // TODO "foo".to_owned() and friends + } + } + } + } + } + } + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + // let y = x where x is known + // remove x, insert y + self.set.insert(consume_pat.id); + self.set.remove(&lid); + } + } + + } + fn borrow(&mut self, + borrow_id: NodeId, + _: Span, + cmt: cmt<'tcx>, + _: ty::Region, + _: ty::BorrowKind, + loan_cause: LoanCause) { + + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.cx + .tcx + .tables + .borrow() + .adjustments + .get(&borrow_id) { + if LoanCause::AutoRef == loan_cause { + // x.foo() + if adj.autoderefs <= 0 { + self.set.remove(&lid); // Used without autodereffing (i.e. x.clone()) + } + } else { + self.cx.sess().span_bug(cmt.span, "Unknown adjusted AutoRef"); + } + } else if LoanCause::AddrOf == loan_cause { + // &x + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = + self.cx.tcx.tables.borrow().adjustments + .get(&self.cx.tcx.map.get_parent_node(borrow_id)) { + if adj.autoderefs <= 1 { + // foo(&x) where no extra autoreffing is happening + self.set.remove(&lid); + } + } + + } else if LoanCause::MatchDiscriminant == loan_cause { + self.set.remove(&lid); // `match x` can move + } + // do nothing for matches, etc. These can't escape + } + } + } + fn decl_without_init(&mut self, _: NodeId, _: Span) {} + fn mutate(&mut self, + _: NodeId, + _: Span, + _: cmt<'tcx>, + _: MutateMode) { + } +} diff --git a/src/lib.rs b/src/lib.rs index 57a92f99900..9ead05b93b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ pub mod no_effect; pub mod temporary_assignment; pub mod transmute; pub mod cyclomatic_complexity; +pub mod escape; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -116,6 +117,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); reg.register_late_lint_pass(box transmute::UselessTransmute); reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25)); + reg.register_late_lint_pass(box escape::EscapePass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -146,6 +148,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, eq_op::EQ_OP, + escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/tests/compile-fail/escape_analysis.rs b/tests/compile-fail/escape_analysis.rs new file mode 100644 index 00000000000..3782cb96da5 --- /dev/null +++ b/tests/compile-fail/escape_analysis.rs @@ -0,0 +1,81 @@ +#![feature(plugin, box_syntax)] +#![plugin(clippy)] +#![allow(warnings, clippy)] + +#![deny(boxed_local)] + +#[derive(Clone)] +struct A; + +impl A { + fn foo(&self){} +} + +fn main() { +} + +fn warn_call() { + let x = box A; //~ ERROR local variable + x.foo(); +} + +fn warn_rename_call() { + let x = box A; + + let y = x; //~ ERROR local variable + y.foo(); // via autoderef +} + +fn warn_notuse() { + let bz = box A; //~ ERROR local variable +} + +fn warn_pass() { + let bz = box A; //~ ERROR local variable + take_ref(&bz); // via deref coercion +} + +fn nowarn_return() -> Box<A> { + let fx = box A; + fx // moved out, "escapes" +} + +fn nowarn_move() { + let bx = box A; + drop(bx) // moved in, "escapes" +} +fn nowarn_call() { + let bx = box A; + bx.clone(); // method only available to Box, not via autoderef +} + +fn nowarn_pass() { + let bx = box A; + take_box(&bx); // fn needs &Box +} + + +fn take_box(x: &Box<A>) {} +fn take_ref(x: &A) {} + + +fn nowarn_ref_take() { + // false positive, should actually warn + let x = box A; //~ ERROR local variable + let y = &x; + take_box(y); +} + +fn nowarn_match() { + let x = box A; // moved into a match + match x { + y => drop(y) + } +} + +fn warn_match() { + let x = box A; //~ ERROR local variable + match &x { // not moved + ref y => () + } +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From dc414e6c02cde7092b89cccd470a5b58fac736bd Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 5 Dec 2015 14:23:00 +0530 Subject: Make panic in CC silencable (partial #478) --- .travis.yml | 2 +- Cargo.toml | 3 ++- src/cyclomatic_complexity.rs | 33 +++++++++++++++++++++++---------- 3 files changed, 26 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/.travis.yml b/.travis.yml index 7eaa61c5572..920aaf981f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,5 +4,5 @@ sudo: false script: - python util/update_lints.py -c - - cargo test + - cargo test --features debugging - bash util/dogfood.sh diff --git a/Cargo.toml b/Cargo.toml index b9ade2ac28f..c86b7b7d522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.27" +version = "0.0.28" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", @@ -28,3 +28,4 @@ lazy_static = "*" [features] structured_logging = [] +debugging = [] diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 678ebe866cb..1379a8db15d 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -44,17 +44,16 @@ impl CyclomaticComplexity { if narms > 0 { narms = narms - 1; } + if cc < narms { - println!("cc = {}, arms = {}", cc, narms); - println!("{:?}", block); - println!("{:?}", span); - panic!("cc = {}, arms = {}", cc, narms); - } - let rust_cc = cc - narms; - if rust_cc > self.limit.limit() { - cx.span_lint_help(CYCLOMATIC_COMPLEXITY, span, - &format!("The function has a cyclomatic complexity of {}.", rust_cc), - "You could split it up into multiple smaller functions"); + report_cc_bug(cx, cc, narms, span); + } else { + let rust_cc = cc - narms; + if rust_cc > self.limit.limit() { + cx.span_lint_help(CYCLOMATIC_COMPLEXITY, span, + &format!("The function has a cyclomatic complexity of {}.", rust_cc), + "You could split it up into multiple smaller functions"); + } } } } @@ -103,3 +102,17 @@ impl<'a> Visitor<'a> for MatchArmCounter { } } } + +#[cfg(feature="debugging")] +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, span: Span) { + cx.sess().span_bug(span, &format!("Clippy encountered a bug calculating cyclomatic complexity: \ + cc = {}, arms = {}. Please file a bug report.", cc, narms));; +} +#[cfg(not(feature="debugging"))] +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, span: Span) { + if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { + cx.sess().span_note(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ + (hide this message with `#[allow(cyclomatic_complexity)]`): \ + cc = {}, arms = {}. Please file a bug report.", cc, narms)); + } +} -- cgit 1.4.1-3-g733a5 From 978c41584f9d1337ad2d6cf5d5ec0ff1a40a30c4 Mon Sep 17 00:00:00 2001 From: Robert Clipsham <robert@octarineparrot.com> Date: Sat, 5 Dec 2015 12:25:04 +0000 Subject: Fix clippy with latest Rust nightly. --- Cargo.toml | 2 +- src/shadow.rs | 2 +- tests/consts.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index c86b7b7d522..4ae56d791f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.28" +version = "0.0.29" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/shadow.rs b/src/shadow.rs index 5fb27f75c3c..2c68667fc32 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -62,7 +62,7 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } if is_from_for_desugar(decl) { return; } if let DeclLocal(ref local) = decl.node { - let Local{ ref pat, ref ty, ref init, id: _, span } = **local; + let Local{ ref pat, ref ty, ref init, id: _, span, attrs: _ } = **local; if let Some(ref t) = *ty { check_ty(cx, t, bindings) } if let Some(ref o) = *init { check_expr(cx, o, bindings); diff --git a/tests/consts.rs b/tests/consts.rs index 66a7953994b..5ddcd6df7b8 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -29,6 +29,7 @@ fn expr(n: Expr_) -> Expr { id: 1, node: n, span: COMMAND_LINE_SP, + attrs: None } } -- cgit 1.4.1-3-g733a5 From 62db39273088f216ba95e1853b982a489051c152 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Fri, 4 Dec 2015 15:56:25 +0100 Subject: Make lifetimes lint work with type aliases and non-locally-defined structs --- src/lifetimes.rs | 29 ++++++++++++++--------------- tests/compile-fail/lifetimes.rs | 13 +++++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index acc7b014052..0003c50d843 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -3,7 +3,7 @@ use reexport::*; use rustc::lint::*; use syntax::codemap::Span; use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound}; -use rustc::middle::def::Def::{DefTy, DefTrait}; +use rustc::middle::def::Def::{DefTy, DefTrait, DefStruct}; use std::collections::HashSet; use utils::{in_external_macro, span_lint}; @@ -187,23 +187,22 @@ impl <'v, 't> RefVisitor<'v, 't> { let last_path_segment = path.segments.last().map(|s| &s.parameters); if let Some(&AngleBracketedParameters(ref params)) = last_path_segment { if params.lifetimes.is_empty() { - let def = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()); - match def { - Some(DefTy(def_id, _)) => { - if let Some(ty_def) = self.cx.tcx.adt_defs.borrow().get(&def_id) { - let scheme = ty_def.type_scheme(self.cx.tcx); - for _ in scheme.generics.regions.as_slice() { + if let Some(def) = self.cx.tcx.def_map.borrow().get(&ty.id).map(|r| r.full_def()) { + match def { + DefTy(def_id, _) | DefStruct(def_id) => { + let type_scheme = self.cx.tcx.lookup_item_type(def_id); + for _ in type_scheme.generics.regions.as_slice() { self.record(&None); } - } - } - Some(DefTrait(def_id)) => { - let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; - for _ in &trait_def.generics.regions { - self.record(&None); - } + }, + DefTrait(def_id) => { + let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; + for _ in &trait_def.generics.regions { + self.record(&None); + } + }, + _ => {} } - _ => {} } } } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index f5d95aacc9a..040c3554e89 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -106,5 +106,18 @@ fn trait_obj_elided<'a>(_arg: &'a WithLifetime) -> &'a str { unimplemented!() } // unambiguous if we elided the lifetime fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() } //~ERROR explicit lifetimes given +type FooAlias<'a> = Foo<'a>; + +fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() } //~ERROR explicit lifetimes given + +// no warning, two input lifetimes (named on the reference, anonymous on Foo) +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { unimplemented!() } + +// no warning, two input lifetimes (anonymous on the reference, named on Foo) +fn alias_with_lt3<'a>(_foo: &FooAlias<'a> ) -> &'a str { unimplemented!() } + +// no warning, two input lifetimes +fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b> ) -> &'a str { unimplemented!() } + fn main() { } -- cgit 1.4.1-3-g733a5 From ac39dc290b7a2319a5bba61314bf1ee288e36057 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Sun, 6 Dec 2015 02:05:32 +0100 Subject: Remove obsolete workaround --- src/utils.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 3fcfa66259c..8be5a12ae07 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -256,7 +256,6 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if let NodeExpr(parent) = node { Some(parent) } else { None } ) } -#[allow(needless_lifetimes)] // workaround for https://github.com/Manishearth/rust-clippy/issues/417 pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { let map = &cx.tcx.map; let enclosing_node = map.get_enclosing_scope(node) -- cgit 1.4.1-3-g733a5 From c7b87a06d20a13e9fdf86d34f200ad4e444cb5b8 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 7 Dec 2015 03:06:22 +0530 Subject: Add lint for unused lifetimes (fixes #459) --- README.md | 3 ++- src/lib.rs | 1 + src/lifetimes.rs | 31 +++++++++++++++++++++++--- tests/compile-fail/lifetimes.rs | 2 +- tests/compile-fail/unused_lt.rs | 48 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/unused_lt.rs (limited to 'src') diff --git a/README.md b/README.md index e19ab474c5e..8fdaf1206f9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 81 lints included in this crate: +There are 82 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -84,6 +84,7 @@ name [unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator diff --git a/src/lib.rs b/src/lib.rs index 9ead05b93b2..3faa0427c39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,7 @@ pub fn plugin_registrar(reg: &mut Registry) { len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, + lifetimes::UNUSED_LIFETIMES, loops::EMPTY_LOOP, loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 16ba43766e0..e9591ab6ddc 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -2,9 +2,9 @@ use rustc_front::hir::*; use reexport::*; use rustc::lint::*; use syntax::codemap::Span; -use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound}; +use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl}; use rustc::middle::def::Def::{DefTy, DefTrait, DefStruct}; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use utils::{in_external_macro, span_lint}; @@ -12,12 +12,15 @@ declare_lint!(pub NEEDLESS_LIFETIMES, Warn, "using explicit lifetimes for references in function arguments when elision rules \ would allow omitting them"); +declare_lint!(pub UNUSED_LIFETIMES, Warn, + "unused lifetimes in function definitions"); + #[derive(Copy,Clone)] pub struct LifetimePass; impl LintPass for LifetimePass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_LIFETIMES) + lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES) } } @@ -61,6 +64,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, span_lint(cx, NEEDLESS_LIFETIMES, span, "explicit lifetimes given in parameter types where they could be elided"); } + report_extra_lifetimes(cx, decl, &generics.lifetimes); } fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, @@ -263,3 +267,24 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { } false } + +struct LifetimeChecker(HashMap<Name, Span>); + +impl<'v> Visitor<'v> for LifetimeChecker { + + // for lifetimes as parameters of generics + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + self.0.remove(&lifetime.name); + } +} + +fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, + named_lts: &[LifetimeDef]) { + let hs = named_lts.iter().map(|lt| (lt.lifetime.name, lt.lifetime.span)).collect(); + let mut checker = LifetimeChecker(hs); + walk_fn_decl(&mut checker, func); + for (_, v) in checker.0 { + span_lint(cx, UNUSED_LIFETIMES, v, + "this lifetime isn't used in the function definition"); + } +} diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 040c3554e89..4d454a738d9 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(needless_lifetimes)] -#![allow(dead_code)] +#![allow(dead_code, unused_lifetimes)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } //~^ERROR explicit lifetimes given diff --git a/tests/compile-fail/unused_lt.rs b/tests/compile-fail/unused_lt.rs new file mode 100644 index 00000000000..d4babdfc4fd --- /dev/null +++ b/tests/compile-fail/unused_lt.rs @@ -0,0 +1,48 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused, dead_code, needless_lifetimes)] +#![deny(unused_lifetimes)] + +fn empty() { + +} + + +fn used_lt<'a>(x: &'a u8) { + +} + + +fn unused_lt<'a>(x: u8) { //~ ERROR this lifetime + +} + +fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { //~ ERROR this lifetime + // 'a is useless here since it's not directly bound +} + +fn lt_return<'a, 'b: 'a>(x: &'b u8) -> &'a u8 { + panic!() +} + +fn lt_return_only<'a>() -> &'a u8 { + panic!() +} + +fn unused_lt_blergh<'a>(x: Option<Box<Send+'a>>) { + +} + + +trait Foo<'a> { + fn x(&self, a: &'a u8); +} + +impl<'a> Foo<'a> for u8 { + fn x(&self, a: &'a u8) { + + } +} +fn main() { + +} -- cgit 1.4.1-3-g733a5 From 72117836f17a1c68946be433d1467001af7bb8af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume1.gomez@gmail.com> Date: Sun, 6 Dec 2015 03:21:34 +0100 Subject: Add check on redundant _ bindings in structs --- README.md | 3 ++- src/lib.rs | 3 +++ src/misc_early.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/mut_mut.rs | 2 +- src/mut_reference.rs | 4 ++-- src/open_options.rs | 2 +- src/shadow.rs | 2 +- src/utils.rs | 4 ++-- 8 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/misc_early.rs (limited to 'src') diff --git a/README.md b/README.md index e19ab474c5e..af4c3e80437 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 81 lints included in this crate: +There are 82 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -81,6 +81,7 @@ name [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference +[unneeded_binding](https://github.com/Manishearth/rust-clippy/wiki#unneeded_binding) | warn | Type fields are bound when not necessary [unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop diff --git a/src/lib.rs b/src/lib.rs index 9ead05b93b2..abb3f0425df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod cyclomatic_complexity; pub mod escape; +pub mod misc_early; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -118,6 +119,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box transmute::UselessTransmute); reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25)); reg.register_late_lint_pass(box escape::EscapePass); + reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -181,6 +183,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, + misc_early::UNNEEDED_BINDING, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, diff --git a/src/misc_early.rs b/src/misc_early.rs new file mode 100644 index 00000000000..5bec753d3eb --- /dev/null +++ b/src/misc_early.rs @@ -0,0 +1,48 @@ +//use rustc_front::hir::*; + +use rustc::lint::*; + +use syntax::ast::*; + +use utils::span_lint; + +declare_lint!(pub UNNEEDED_BINDING, Warn, + "Type fields are bound when not necessary"); + +#[derive(Copy, Clone)] +pub struct MiscEarly; + +impl LintPass for MiscEarly { + fn get_lints(&self) -> LintArray { + lint_array!(UNNEEDED_BINDING) + } +} + +impl EarlyLintPass for MiscEarly { + fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { + if let PatStruct(_, ref pfields, _) = pat.node { + let mut wilds = 0; + + for field in pfields { + if field.node.pat.node == PatWild { + wilds += 1; + } + } + if !pfields.is_empty() && wilds == pfields.len() { + span_lint(cx, UNNEEDED_BINDING, pat.span, + "All the struct fields are matched to a wildcard pattern, \ + consider using `..`."); + return; + } + if wilds > 0 { + for field in pfields { + if field.node.pat.node == PatWild { + span_lint(cx, UNNEEDED_BINDING, field.span, + "You matched a field with a wildcard pattern. \ + Consider using `..` instead"); + } + } + } + } + } +} diff --git a/src/mut_mut.rs b/src/mut_mut.rs index c361ab24831..06f76479c59 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -41,7 +41,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map_or_else( || { - if let TyRef(_, TypeAndMut{ty: _, mutbl: MutMutable}) = + if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty { span_lint(cx, MUT_MUT, expr.span, "this expression mutably borrows a mutable reference. \ diff --git a/src/mut_reference.rs b/src/mut_reference.rs index e9601e8650f..8e089378929 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -58,8 +58,8 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty let parameters = &fn_type.sig.skip_binder().inputs; for (argument, parameter) in arguments.iter().zip(parameters.iter()) { match parameter.sty { - TypeVariants::TyRef(_, TypeAndMut {ty: _, mutbl: MutImmutable}) | - TypeVariants::TyRawPtr(TypeAndMut {ty: _, mutbl: MutImmutable}) => { + TypeVariants::TyRef(_, TypeAndMut {mutbl: MutImmutable, ..}) | + TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { if let ExprAddrOf(MutMutable, _) = argument.node { span_lint(cx, UNNECESSARY_MUT_PASSED, argument.span, &format!("The function/method \"{}\" \ diff --git a/src/open_options.rs b/src/open_options.rs index 732852e1686..dd375d58a60 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -58,7 +58,7 @@ 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: LitBool(lit), span: _} = **span { + if let Spanned {node: LitBool(lit), ..} = **span { if lit {Argument::True} else {Argument::False} } else { return; // The function is called with a literal diff --git a/src/shadow.rs b/src/shadow.rs index 2c68667fc32..60197fcf9df 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -62,7 +62,7 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { if in_external_macro(cx, decl.span) { return; } if is_from_for_desugar(decl) { return; } if let DeclLocal(ref local) = decl.node { - let Local{ ref pat, ref ty, ref init, id: _, span, attrs: _ } = **local; + let Local{ ref pat, ref ty, ref init, span, .. } = **local; if let Some(ref t) = *ty { check_ty(cx, t, bindings) } if let Some(ref o) = *init { check_expr(cx, o, bindings); diff --git a/src/utils.rs b/src/utils.rs index 365fc1bf99d..a602902d45f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -167,8 +167,8 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { Some(NodeItem(&Item{ ref name, .. })) | - Some(NodeTraitItem(&TraitItem{ id: _, ref name, .. })) | - Some(NodeImplItem(&ImplItem{ id: _, ref name, .. })) => { + Some(NodeTraitItem(&TraitItem{ ref name, .. })) | + Some(NodeImplItem(&ImplItem{ ref name, .. })) => { Some(*name) } _ => None, -- cgit 1.4.1-3-g733a5 From 35b5c3efdd4785a72d54104aa4a2580eaa15dfa9 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Tue, 8 Dec 2015 15:03:01 +0900 Subject: Use suggestion for redundant_closure --- src/eta_reduction.rs | 11 +++++++---- src/utils.rs | 5 +++++ tests/compile-fail/eta.rs | 12 +++++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index c4c0912464c..5ade158200c 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; -use utils::{snippet, span_lint, is_adjusted}; +use utils::{snippet_opt, span_lint, is_adjusted}; #[allow(missing_copy_implementations)] @@ -75,9 +75,12 @@ fn check_closure(cx: &LateContext, expr: &Expr) { return } } - span_lint(cx, REDUNDANT_CLOSURE, expr.span, &format!( - "redundant closure found. Consider using `{}` in its place", - snippet(cx, caller.span, ".."))); + span_lint(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found"); + if let Some(snippet) = snippet_opt(cx, caller.span) { + cx.sess().span_suggestion(expr.span, + "remove closure as shown:", + snippet); + } } } } diff --git a/src/utils.rs b/src/utils.rs index 2b38403b63a..21d1f9d16ec 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -195,6 +195,11 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow< cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) } +/// Converts a span to a code snippet. Returns None if not available. +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { + cx.sess().codemap().span_to_snippet(span).ok() +} + /// convert a span (from a block) to a code snippet if available, otherwise use default, e.g. /// `snippet(cx, expr.span, "..")` /// This trims the code of indentation, except for the first line diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index d53ea4e97d7..a51d116d9cc 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -5,11 +5,17 @@ fn main() { let a = Some(1u8).map(|a| foo(a)); - //~^ ERROR redundant closure found. Consider using `foo` in its place + //~^ ERROR redundant closure found + //~| HELP remove closure as shown + //~| SUGGESTION let a = Some(1u8).map(foo); meta(|a| foo(a)); - //~^ ERROR redundant closure found. Consider using `foo` in its place + //~^ ERROR redundant closure found + //~| HELP remove closure as shown + //~| SUGGESTION meta(foo); let c = Some(1u8).map(|a| {1+2; foo}(a)); - //~^ ERROR redundant closure found. Consider using `{1+2; foo}` in its place + //~^ ERROR redundant closure found + //~| HELP remove closure as shown + //~| SUGGESTION let c = Some(1u8).map({1+2; foo}); let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted unsafe { -- cgit 1.4.1-3-g733a5 From 213c15cd66c2291bcb95c8f9bd421c5181cb68d3 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Wed, 9 Dec 2015 01:28:35 +0900 Subject: Add span_lint_and_then and use it --- src/eta_reduction.rs | 17 ++++++++++------- src/utils.rs | 11 +++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 5ade158200c..4957c2e21bc 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::ty; -use utils::{snippet_opt, span_lint, is_adjusted}; +use utils::{snippet_opt, span_lint_and_then, is_adjusted}; #[allow(missing_copy_implementations)] @@ -75,12 +75,15 @@ fn check_closure(cx: &LateContext, expr: &Expr) { return } } - span_lint(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found"); - if let Some(snippet) = snippet_opt(cx, caller.span) { - cx.sess().span_suggestion(expr.span, - "remove closure as shown:", - snippet); - } + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, + "redundant closure found", + || { + if let Some(snippet) = snippet_opt(cx, caller.span) { + cx.sess().span_suggestion(expr.span, + "remove closure as shown:", + snippet); + } + }); } } } diff --git a/src/utils.rs b/src/utils.rs index 21d1f9d16ec..5e1671b709c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -325,6 +325,17 @@ pub fn span_note_and_lint<T: LintContext>(cx: &T, lint: &'static Lint, span: Spa } } +pub fn span_lint_and_then<T: LintContext, F>(cx: &T, lint: &'static Lint, sp: Span, + msg: &str, f: F) where F: Fn() { + cx.span_lint(lint, sp, msg); + if cx.current_level(lint) != Level::Allow { + f(); + cx.sess().fileline_help(sp, &format!("for further information visit \ + https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())) + } +} + /// return the base type for references and raw pointers pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { -- cgit 1.4.1-3-g733a5 From b865e30b49f3f0fb914ab82d152fae0f608ed540 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 9 Dec 2015 15:56:49 -0500 Subject: Upgrade rust to rustc 1.6.0-nightly (462ec0576 2015-12-09) --- Cargo.toml | 2 +- src/eq_op.rs | 1 - src/len_zero.rs | 4 ++-- src/lib.rs | 4 ++-- src/map_clone.rs | 1 - src/shadow.rs | 10 +++++----- tests/compile-fail/shadow.rs | 16 ++++++++-------- tests/compile-fail/transmute.rs | 1 - 8 files changed, 18 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 4ae56d791f5..c70e43ed78d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.29" +version = "0.0.30" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/eq_op.rs b/src/eq_op.rs index 1d2146537c9..7636267bcd8 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -66,7 +66,6 @@ fn is_path_equal(left : &Path, right : &Path) -> bool { // we have to be explicit about hygiene left.global == right.global && over(&left.segments, &right.segments, |l, r| l.identifier.name == r.identifier.name - && l.identifier.ctxt == r.identifier.ctxt && l.parameters == r.parameters) } diff --git a/src/len_zero.rs b/src/len_zero.rs index 9ac4ab1e0e0..c501ceb66fa 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -50,7 +50,7 @@ impl LateLintPass for LenZero { } } -fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>]) { +fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { item.name.as_str() == name && if let MethodTraitItem(ref sig, _) = item.node { is_self_sig(sig) } else { false } @@ -69,7 +69,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[P<TraitItem>] } } -fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[P<ImplItem>]) { +fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { item.name.as_str() == name && if let ImplItemKind::Method(ref sig, _) = item.node { is_self_sig(sig) } else { false } diff --git a/src/lib.rs b/src/lib.rs index be0db936e6b..03e0cbea19c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![feature(plugin_registrar, box_syntax)] -#![feature(rustc_private, core, collections)] +#![feature(rustc_private, collections)] #![feature(num_bits_bytes, iter_arith)] #![allow(unknown_lints)] @@ -68,7 +68,7 @@ pub mod escape; pub mod misc_early; mod reexport { - pub use syntax::ast::{Name, Ident, NodeId}; + pub use syntax::ast::{Name, NodeId}; } #[plugin_registrar] diff --git a/src/map_clone.rs b/src/map_clone.rs index ba561fbb167..d9719df0b6f 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,6 +1,5 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::ast::Ident; use utils::{CLONE_PATH, OPTION_PATH}; use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; diff --git a/src/shadow.rs b/src/shadow.rs index 60197fcf9df..b9f60e0e01a 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -39,7 +39,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { let mut bindings = Vec::new(); for arg in &decl.inputs { if let PatIdent(_, ident, _) = arg.pat.node { - bindings.push((ident.node.name, ident.span)) + bindings.push((ident.node.unhygienic_name, ident.span)) } } check_block(cx, block, &mut bindings); @@ -85,7 +85,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, //TODO: match more stuff / destructuring match pat.node { PatIdent(_, ref ident, ref inner) => { - let name = ident.node.name; + let name = ident.node.unhygienic_name; if is_binding(cx, pat) { let mut new_binding = true; for tup in bindings.iter_mut() { @@ -266,7 +266,7 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { fn path_eq_name(name: Name, path: &Path) -> bool { !path.global && path.segments.len() == 1 && - path.segments[0].identifier.name == name + path.segments[0].identifier.unhygienic_name == name } struct ContainsSelf { @@ -275,8 +275,8 @@ struct ContainsSelf { } impl<'v> Visitor<'v> for ContainsSelf { - fn visit_name(&mut self, _: Span, name: Name) { - if self.name == name { + fn visit_ident(&mut self, _: Span, ident: Ident) { + if self.name == ident.unhygienic_name { self.result = true; } } diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index d70f26ed090..0a52a9829ae 100644 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -10,15 +10,15 @@ fn first(x: (isize, isize)) -> isize { x.0 } fn main() { let mut x = 1; - let x = &mut x; //~ERROR: x is shadowed by itself in &mut x - let x = { x }; //~ERROR: x is shadowed by itself in { x } - let x = (&*x); //~ERROR: x is shadowed by itself in &*x - let x = { *x + 1 }; //~ERROR: x is shadowed by { *x + 1 } which reuses - let x = id(x); //~ERROR: x is shadowed by id(x) which reuses - let x = (1, x); //~ERROR: x is shadowed by (1, x) which reuses - let x = first(x); //~ERROR: x is shadowed by first(x) which reuses + let x = &mut x; //~ERROR x is shadowed by itself in &mut x + let x = { x }; //~ERROR x is shadowed by itself in { x } + let x = (&*x); //~ERROR x is shadowed by itself in &*x + let x = { *x + 1 }; //~ERROR x is shadowed by { *x + 1 } which reuses + let x = id(x); //~ERROR x is shadowed by id(x) which reuses + let x = (1, x); //~ERROR x is shadowed by (1, x) which reuses + let x = first(x); //~ERROR x is shadowed by first(x) which reuses let y = 1; - let x = y; //~ERROR: x is shadowed by y + let x = y; //~ERROR x is shadowed by y let o = Some(1u8); diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs index 0a2d09d9431..94dd3a18549 100644 --- a/tests/compile-fail/transmute.rs +++ b/tests/compile-fail/transmute.rs @@ -1,4 +1,3 @@ -#![feature(core)] #![feature(plugin)] #![plugin(clippy)] #![deny(useless_transmute)] -- cgit 1.4.1-3-g733a5 From b9546599e31cb8f1b3ce5124d67f1f664e89b9c0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 10 Dec 2015 11:44:12 -0500 Subject: Check for unused lifetimes in bounds (fixes #489) --- src/lifetimes.rs | 19 +++++++++++++++---- tests/compile-fail/unused_lt.rs | 9 +++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index e9591ab6ddc..3edffc3bee3 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -2,7 +2,7 @@ use rustc_front::hir::*; use reexport::*; use rustc::lint::*; use syntax::codemap::Span; -use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl}; +use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; use rustc::middle::def::Def::{DefTy, DefTrait, DefStruct}; use std::collections::{HashSet, HashMap}; @@ -64,7 +64,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, span_lint(cx, NEEDLESS_LIFETIMES, span, "explicit lifetimes given in parameter types where they could be elided"); } - report_extra_lifetimes(cx, decl, &generics.lifetimes); + report_extra_lifetimes(cx, decl, &generics); } fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, @@ -276,12 +276,23 @@ impl<'v> Visitor<'v> for LifetimeChecker { fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.0.remove(&lifetime.name); } + + fn visit_lifetime_def(&mut self, _: &'v 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 report_extra_lifetimes(cx: &LateContext, func: &FnDecl, - named_lts: &[LifetimeDef]) { - let hs = named_lts.iter().map(|lt| (lt.lifetime.name, lt.lifetime.span)).collect(); + generics: &Generics) { + let hs = generics.lifetimes.iter() + .map(|lt| (lt.lifetime.name, lt.lifetime.span)) + .collect(); let mut checker = LifetimeChecker(hs); + walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); for (_, v) in checker.0 { span_lint(cx, UNUSED_LIFETIMES, v, diff --git a/tests/compile-fail/unused_lt.rs b/tests/compile-fail/unused_lt.rs index d4babdfc4fd..85667174509 100644 --- a/tests/compile-fail/unused_lt.rs +++ b/tests/compile-fail/unused_lt.rs @@ -43,6 +43,15 @@ impl<'a> Foo<'a> for u8 { } } + +// test for #489 (used lifetimes in bounds) +pub fn parse<'a, I: Iterator<Item=&'a str>>(_it: &mut I) { + unimplemented!() +} +pub fn parse2<'a, I>(_it: &mut I) where I: Iterator<Item=&'a str>{ + unimplemented!() +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 5bbc1427fde4152d42e6159d5a3ca3eec167b02f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 11 Dec 2015 01:22:27 +0100 Subject: added wiki comments + wiki-generating python script --- src/approx_const.rs | 7 ++++ src/attrs.rs | 13 ++++++++ src/bit_mask.rs | 35 ++++++++++++++++++++ src/collapsible_if.rs | 7 ++++ src/eq_op.rs | 7 ++++ src/eta_reduction.rs | 7 ++++ src/identity_op.rs | 7 ++++ src/len_zero.rs | 19 +++++++++++ src/lifetimes.rs | 7 ++++ src/loops.rs | 75 ++++++++++++++++++++++++++++++++++++++++++ src/matches.rs | 43 ++++++++++++++++++++++++ src/methods.rs | 76 +++++++++++++++++++++++++++++++++++++++++++ src/minmax.rs | 7 ++++ src/misc.rs | 50 ++++++++++++++++++++++++++++ src/mut_mut.rs | 7 ++++ src/mut_reference.rs | 7 ++++ src/needless_bool.rs | 7 ++++ src/open_options.rs | 7 ++++ src/precedence.rs | 11 +++++++ src/ptr_arg.rs | 7 ++++ src/ranges.rs | 14 ++++++++ src/returns.rs | 14 ++++++++ src/shadow.rs | 21 ++++++++++++ src/strings.rs | 26 +++++++++++++++ src/types.rs | 69 +++++++++++++++++++++++++++++++++++++++ src/unicode.rs | 21 ++++++++++++ src/zero_div_zero.rs | 7 ++++ util/update_wiki.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ 28 files changed, 668 insertions(+) create mode 100755 util/update_wiki.py (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 9d1d51444fa..05829838903 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -6,6 +6,13 @@ use syntax::ast::Lit_::*; use syntax::ast::Lit; use syntax::ast::FloatTy::*; +/// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. This lint is `Warn` by default. +/// +/// **Why is this bad?** Usually, the definition in the standard library is more precise than what people come up with. If you find that your definition is actually more precise, please [file a Rust issue](https://github.com/rust-lang/rust/issues). +/// +/// **Known problems:** If you happen to have a value that is within 1/8192 of a known constant, but is not *and should not* be the same, this lint will report your value anyway. We have not yet noticed any false positives in code we tested clippy with (this includes servo), but YMMV. +/// +/// **Example:** `let x = 3.14;` declare_lint! { pub APPROX_CONSTANT, Warn, diff --git a/src/attrs.rs b/src/attrs.rs index f4a5b4c1517..10db4a551f9 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -8,6 +8,19 @@ use syntax::attr::*; use syntax::ast::{Attribute, MetaList, MetaWord}; use utils::{in_macro, match_path, span_lint}; +/// **What it does:** This lint warns on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. +/// +/// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it. +/// +/// As a rule of thumb, before slapping `#[inline(always)]` on a function, measure if that additional function call really affects your runtime profile sufficiently to make up for the increase in compile time. +/// +/// **Known problems:** False positives, big time. This lint is meant to be deactivated by everyone doing serious performance work. This means having done the measurement. +/// +/// **Example:** +/// ``` +/// #[inline(always)] +/// fn not_quite_hot_code(..) { ... } +/// ``` declare_lint! { pub INLINE_ALWAYS, Warn, "`#[inline(always)]` is a bad idea in most cases" } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index bee99b0f783..3d428aa0da7 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -8,6 +8,27 @@ use syntax::ast::Lit_::*; use utils::span_lint; +/// **What it does:** This lint checks for incompatible bit masks in comparisons. It is `Warn` by default. +/// +/// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: +/// +/// |Comparison |Bit-Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// +/// **Why is this bad?** If the bits that the comparison cares about are always set to zero or one by the bit mask, the comparison is constant `true` or `false` (depending on mask, compared value, and operators). +/// +/// So the code is actively misleading, and the only reason someone would write this intentionally is to win an underhanded Rust contest or create a test-case for this lint. +/// +/// **Known problems:** None +/// +/// **Example:** `x & 1 == 2` (also see table above) declare_lint! { pub BAD_BIT_MASK, Warn, @@ -15,6 +36,20 @@ declare_lint! { (because in the example `select` containing bits that `mask` doesn't have)" } +/// **What it does:** This lint checks for bit masks in comparisons which can be removed without changing the outcome. The basic structure can be seen in the following table: +/// +/// |Comparison|Bit-Op |Example |equals | +/// |----------|---------|-----------|-------| +/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| +/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| +/// +/// This lint is `Warn` by default. +/// +/// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask), but still a bit misleading, because the bit mask is ineffective. +/// +/// **Known problems:** False negatives: This lint will only match instances where we have figured out the math (which is for a power-of-two compared value). This means things like `x | 1 >= 7` (which would be better written as `x >= 6`) will not be reported (but bit masks like this are fairly uncommon). +/// +/// **Example:** `x | 1 > 3` (also see table above) declare_lint! { pub INEFFECTIVE_BIT_MASK, Warn, diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 78e3ec5e35f..775e9ec95fc 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -18,6 +18,13 @@ use syntax::codemap::Spanned; use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; +/// **What it does:** This lint checks for nested `if`-statements which can be collapsed by `&&`-combining their conditions. It is `Warn` by default. +/// +/// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. +/// +/// **Known problems:** None +/// +/// **Example:** `if x { if y { .. } }` declare_lint! { pub COLLAPSIBLE_IF, Warn, diff --git a/src/eq_op.rs b/src/eq_op.rs index 1d2146537c9..282056e4eb4 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -6,6 +6,13 @@ use syntax::ptr::P; use consts::constant; use utils::span_lint; +/// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). It is `Warn` by default. +/// +/// **Why is this bad?** This is usually just a typo. +/// +/// **Known problems:** False negatives: We had some false positives regarding calls (notably [racer](https://github.com/phildawes/racer) had one instance of `x.pop() && x.pop()`), so we removed matching any function or method calls. We may introduce a whitelist of known pure functions in the future. +/// +/// **Example:** `x + 1 == x + 1` declare_lint! { pub EQ_OP, Warn, diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 4957c2e21bc..c25228793e6 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -9,6 +9,13 @@ use utils::{snippet_opt, span_lint_and_then, is_adjusted}; pub struct EtaPass; +/// **What it does:** This lint checks for closures which just call another function where the function can be called directly. `unsafe` functions or calls where types get adjusted are ignored. It is `Warn` by default. +/// +/// **Why is this bad?** Needlessly creating a closure just costs heap space and adds code for no benefit. +/// +/// **Known problems:** None +/// +/// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact argument type of `x`. declare_lint!(pub REDUNDANT_CLOSURE, Warn, "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"); diff --git a/src/identity_op.rs b/src/identity_op.rs index 7ed784f00fc..88a03e050be 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -6,6 +6,13 @@ use consts::{constant_simple, is_negative}; use consts::Constant::ConstantInt; use utils::{span_lint, snippet, in_macro}; +/// **What it does:** This lint checks for identity operations, e.g. `x + 0`. It is `Warn` by default. +/// +/// **Why is this bad?** This code can be removed without changing the meaning. So it just obscures what's going on. Delete it mercilessly. +/// +/// **Known problems:** None +/// +/// **Example:** `x / 1 + 0 * 1 - 0 | 0` declare_lint! { pub IDENTITY_OP, Warn, "using identity operations, e.g. `x + 0` or `y / 1`" } diff --git a/src/len_zero.rs b/src/len_zero.rs index 9ac4ab1e0e0..cff2281985c 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -11,10 +11,29 @@ use syntax::ast::Lit; use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; +/// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. It is `Warn` by default. +/// +/// **Why is this bad?** Some structures can answer `.is_empty()` much faster than calculating their length. So it is good to get into the habit of using `.is_empty()`, and having it is cheap. Besides, it makes the intent clearer than a comparison. +/// +/// **Known problems:** None +/// +/// **Example:** `if x.len() == 0 { .. }` declare_lint!(pub LEN_ZERO, Warn, "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ could be used instead"); +/// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. It is `Warn` by default. +/// +/// **Why is this bad?** It is good custom to have both methods, because for some data structures, asking about the length will be a costly operation, whereas `.is_empty()` can usually answer in constant time. Also it used to lead to false positives on the [`len_zero`](#len_zero) lint – currently that lint will ignore such entities. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// impl X { +/// fn len(&self) -> usize { .. } +/// } +/// ``` declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, "traits and impls that have `.len()` but not `.is_empty()`"); diff --git a/src/lifetimes.rs b/src/lifetimes.rs index e9591ab6ddc..39ef7857b08 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -8,6 +8,13 @@ use std::collections::{HashSet, HashMap}; use utils::{in_external_macro, span_lint}; +/// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. It is `Warn` by default. +/// +/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. +/// +/// **Known problems:** Potential false negatives: we bail out if the function has a `where` clause where lifetimes are mentioned. +/// +/// **Example:** `fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }` declare_lint!(pub NEEDLESS_LIFETIMES, Warn, "using explicit lifetimes for references in function arguments when elision rules \ would allow omitting them"); diff --git a/src/loops.rs b/src/loops.rs index 393c92b16ef..3c4e023b98e 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -15,28 +15,103 @@ use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, get_enclosing_block}; use utils::{VEC_PATH, LL_PATH}; +/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. +/// +/// **Why is this bad?** Just iterating the collection itself makes the intent more clear and is probably faster. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// for i in 0..vec.len() { +/// println!("{}", vec[i]); +/// } +/// ``` declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, "for-looping over a range of indices where an iterator over items would do" } +/// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. It is `Warn` by default. +/// +/// **Why is this bad?** Readability. +/// +/// **Known problems:** False negatives. We currently only warn on some known types. +/// +/// **Example:** `for x in y.iter() { .. }` (where y is a `Vec` or slice) declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" } +/// **What it does:** This lint checks for loops on `x.next()`. It is `Warn` by default. +/// +/// **Why is this bad?** `next()` returns either `Some(value)` if there was a value, or `None` otherwise. The insidious thing is that `Option<_>` implements `IntoIterator`, so that possibly one value will be iterated, leading to some hard to find bugs. No one will want to write such code [except to win an Underhanded Rust Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). +/// +/// **Known problems:** None +/// +/// **Example:** `for x in y.next() { .. }` declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } +/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. +/// +/// **Why is this bad?** The `while let` loop is usually shorter and more readable +/// +/// **Known problems:** Sometimes the wrong binding is displayed (#383) +/// +/// **Example:** +/// +/// ``` +/// loop { +/// let x = match y { +/// Some(x) => x, +/// None => break, +/// } +/// // .. do something with x +/// } +/// // is easier written as +/// while let Some(x) = y { +/// // .. do something with x +/// } +/// ``` declare_lint!{ pub WHILE_LET_LOOP, Warn, "`loop { if let { ... } else break }` can be written as a `while let` loop" } +/// **What it does:** This lint checks for using `collect()` on an iterator without using the result. It is `Warn` by default. +/// +/// **Why is this bad?** It is more idiomatic to use a `for` loop over the iterator instead. +/// +/// **Known problems:** None +/// +/// **Example:** `vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();` declare_lint!{ pub UNUSED_COLLECT, Warn, "`collect()`ing an iterator without using the result; this is usually better \ written as a for loop" } +/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. +/// +/// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. +/// +/// **Known problems:** The lint cannot catch loops over dynamically defined ranges. Doing this would require simulating all possible inputs and code paths through the program, which would be complex and error-prone. +/// +/// **Examples**: `for x in 5..10-5 { .. }` (oops, stray `-`) declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, "Iterating over an empty range, such as `10..0` or `5..5`" } +/// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. It is `Warn` by default. +/// +/// **Why is it bad?** Not only is the version using `.enumerate()` more readable, the compiler is able to remove bounds checks which can lead to faster code in some instances. +/// +/// **Known problems:** None. +/// +/// **Example:** `for i in 0..v.len() { foo(v[i]); }` or `for i in 0..v.len() { bar(i, v[i]); }` declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, "for-looping with an explicit counter when `_.enumerate()` would do" } +/// **What it does:** This lint checks for empty `loop` expressions. It is `Warn` by default. +/// +/// **Why is this bad?** Those busy loops burn CPU cycles without doing anything. Think of the environment and either block on something or at least make the thread sleep for some microseconds. +/// +/// **Known problems:** None +/// +/// **Example:** `loop {}` declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" } diff --git a/src/matches.rs b/src/matches.rs index 2c7f0830a53..39459bafba7 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -6,12 +6,55 @@ use syntax::codemap::Span; use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; +/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. It is `Warn` by default. +/// +/// **Why is this bad?** Just readability – `if let` nests less than a `match`. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// match x { +/// Some(ref foo) -> bar(foo), +/// _ => () +/// } +/// ``` declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ is `_ => {}`) is used; recommends `if let` instead"); +/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It is `Warn` by default. +/// +/// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// match x { +/// &A(ref y) => foo(y), +/// &B => bar(), +/// _ => frob(&x), +/// } +/// ``` declare_lint!(pub MATCH_REF_PATS, Warn, "a match has all arms prefixed with `&`; the match expression can be \ dereferenced instead"); +/// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. It is `Warn` by default. +/// +/// **Why is this bad?** It makes the code less readable. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let condition: bool = true; +/// match condition { +/// true => foo(), +/// false => bar(), +/// } +/// ``` declare_lint!(pub MATCH_BOOL, Warn, "a match on boolean expression; recommends `if..else` block instead"); diff --git a/src/methods.rs b/src/methods.rs index f1c868bec07..6c629f29c41 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -15,19 +15,95 @@ use self::OutType::*; #[derive(Clone)] pub struct MethodsPass; +/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. It is `Allow` by default. +/// +/// **Why is this bad?** Usually it is better to handle the `None` case, or to at least call `.expect(_)` with a more helpful message. Still, for a lot of quick-and-dirty code, `unwrap` is a good choice, which is why this lint is `Allow` by default. +/// +/// **Known problems:** None +/// +/// **Example:** `x.unwrap()` declare_lint!(pub OPTION_UNWRAP_USED, Allow, "using `Option.unwrap()`, which should at least get a better message using `expect()`"); +/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. It is `Allow` by default. +/// +/// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`. +/// +/// Even if you want to panic on errors, not all `Error`s implement good messages on display. Therefore it may be beneficial to look at the places where they may get displayed. Activate this lint to do just that. +/// +/// **Known problems:** None +/// +/// **Example:** `x.unwrap()` declare_lint!(pub RESULT_UNWRAP_USED, Allow, "using `Result.unwrap()`, which might be better handled"); +/// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. It is `Warn` by default. +/// +/// **Why is this bad?** This uses the whole formatting machinery just to clone a string. Using `.to_owned()` is lighter on resources. You can also consider using a [`Cow<'a, str>`](http://doc.rust-lang.org/std/borrow/enum.Cow.html) instead in some cases. +/// +/// **Known problems:** None +/// +/// **Example:** `s.to_string()` where `s: &str` declare_lint!(pub STR_TO_STRING, Warn, "using `to_string()` on a str, which should be `to_owned()`"); +/// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default. +/// +/// **Why is this bad?** As our string is already owned, this whole operation is basically a no-op, but still creates a clone of the string (which, if really wanted, should be done with `.clone()`). +/// +/// **Known problems:** None +/// +/// **Example:** `s.to_string()` where `s: String` declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); +/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default. +/// +/// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// struct X; +/// impl X { +/// fn add(&self, other: &X) -> X { .. } +/// } +/// ``` declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, "defining a method that should be implementing a std trait"); +/// **What it does:** This lint checks for methods with certain name prefixes and `Warn`s (by default) if the prefix doesn't match how self is taken. The actual rules are: +/// +/// |Prefix |`self` taken | +/// |-------|--------------------| +/// |`as_` |`&self` or &mut self| +/// |`from_`| none | +/// |`into_`|`self` | +/// |`is_` |`&self` or none | +/// |`to_` |`&self` | +/// +/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_`.. function. +/// +/// **Known problems:** None +/// +/// **Example** +/// +/// ``` +/// impl X { +/// fn as_str(self) -> &str { .. } +/// } +/// ``` declare_lint!(pub WRONG_SELF_CONVENTION, Warn, "defining a method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); +/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. This lint is `Allow` by default. +/// +/// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). +/// +/// **Known problems:** Actually *renaming* the function may break clients if the function is part of the public interface. In that case, be mindful of the stability guarantees you've given your users. +/// +/// **Example:** +/// ``` +/// impl X { +/// pub fn as_str(self) -> &str { .. } +/// } +/// ``` declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, "defining a public method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); diff --git a/src/minmax.rs b/src/minmax.rs index 9eb8a030e15..ac8d6f05272 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -8,6 +8,13 @@ use consts::{Constant, constant_simple}; use utils::{match_def_path, span_lint}; use self::MinMax::{Min, Max}; +/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. +/// +/// **Why is this bad?** This is in all probability not the intended outcome. At the least it hurts readability of the code. +/// +/// **Known problems:** None +/// +/// **Example:** `min(0, max(100, x))` will always be equal to `0`. Probably the author meant to clamp the value between 0 and 100, but has erroneously swapped `min` and `max`. declare_lint!(pub MIN_MAX, Warn, "`min(_, max(_, _))` (or vice versa) with bounds clamping the result \ to a constant"); diff --git a/src/misc.rs b/src/misc.rs index 9df751d49b7..b5c3d0c514f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -13,6 +13,15 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; use utils::span_help_and_lint; +/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. +/// +/// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body. +/// +/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The type of `x` is more obvious with the former. +/// +/// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function. +/// +/// **Example:** `fn foo(ref x: u8) -> bool { .. }` declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ @@ -68,6 +77,13 @@ impl LateLintPass for TopLevelRefPass { } } +/// **What it does:** This lint checks for comparisons to NAN. It is `Deny` by default. +/// +/// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong. +/// +/// **Known problems:** None +/// +/// **Example:** `x == NAN` declare_lint!(pub CMP_NAN, Deny, "comparisons to NAN (which will always return false, which is probably not intended)"); @@ -102,6 +118,13 @@ fn check_nan(cx: &LateContext, path: &Path, span: Span) { }); } +/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats). It is `Warn` by default. +/// +/// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison). +/// +/// **Known problems:** None +/// +/// **Example:** `y == 1.23f64` declare_lint!(pub FLOAT_CMP, Warn, "using `==` or `!=` on float values (as floating-point operations \ usually involve rounding errors, it is always better to check for approximate \ @@ -155,6 +178,13 @@ fn is_float(cx: &LateContext, expr: &Expr) -> bool { } } +/// **What it does:** This lint checks for conversions to owned values just for the sake of a comparison. It is `Warn` by default. +/// +/// **Why is this bad?** The comparison can operate on a reference, so creating an owned value effectively throws it away directly afterwards, which is needlessly consuming code and heap space. +/// +/// **Known problems:** None +/// +/// **Example:** `x.to_owned() == y` declare_lint!(pub CMP_OWNED, Warn, "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"); @@ -221,6 +251,13 @@ fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { true } else { false } } +/// **What it does:** This lint checks for getting the remainder of a division by one. It is `Warn` by default. +/// +/// **Why is this bad?** The result can only ever be zero. No one will write such code deliberately, unless trying to win an Underhanded Rust Contest. Even for that contest, it's probably a bad idea. Use something more underhanded. +/// +/// **Known problems:** None +/// +/// **Example:** `x % 1` declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); #[derive(Copy,Clone)] @@ -244,6 +281,19 @@ impl LateLintPass for ModuloOne { } } +/// **What it does:** This lint checks for patterns in the form `name @ _`. +/// +/// **Why is this bad?** It's almost always more readable to just use direct bindings. +/// +/// **Known problems:** None +/// +/// **Example**: +/// ``` +/// match v { +/// Some(x) => (), +/// y @ _ => (), // easier written as `y`, +/// } +/// ``` declare_lint!(pub REDUNDANT_PATTERN, Warn, "using `name @ _` in a pattern"); #[derive(Copy,Clone)] diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 06f76479c59..ade688d377f 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -4,6 +4,13 @@ use rustc::middle::ty::{TypeAndMut, TyRef}; use utils::{in_external_macro, span_lint}; +/// **What it does:** This lint checks for instances of `mut mut` references. It is `Warn` by default. +/// +/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = &mut &mut y;` declare_lint!(pub MUT_MUT, Allow, "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ or shows a fundamental misunderstanding of references)"); diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 8e089378929..9ba9782336a 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -4,6 +4,13 @@ use utils::span_lint; use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; use syntax::ptr::P; +/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. +/// +/// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site. +/// +/// **Known problems:** None +/// +/// **Example** `my_vec.push(&mut value)` declare_lint! { pub UNNECESSARY_MUT_PASSED, Warn, diff --git a/src/needless_bool.rs b/src/needless_bool.rs index e4d3b00218e..bd2e4116fd0 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -9,6 +9,13 @@ use syntax::ast::Lit_::*; use utils::{span_lint, snippet}; +/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. It is `Warn` by default. +/// +/// **Why is this bad?** Redundant code. +/// +/// **Known problems:** Maybe false positives: Sometimes, the two branches are painstakingly documented (which we of course do not detect), so they *may* have some value. Even then, the documentation can be rewritten to match the shorter code. +/// +/// **Example:** `if x { false } else { true }` declare_lint! { pub NEEDLESS_BOOL, Warn, diff --git a/src/open_options.rs b/src/open_options.rs index dd375d58a60..31ca0d72939 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -4,6 +4,13 @@ use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; use syntax::codemap::{Span, Spanned}; use syntax::ast::Lit_::LitBool; +/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. It is `Warn` by default. +/// +/// **Why is this bad?** In the best case, the code will be harder to read than necessary. I don't know the worst case. +/// +/// **Known problems:** None +/// +/// **Example:** `OpenOptions::new().read(true).truncate(true)` declare_lint! { pub NONSENSICAL_OPEN_OPTIONS, Warn, diff --git a/src/precedence.rs b/src/precedence.rs index b659bd647a7..be5f44c823a 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -5,6 +5,17 @@ use syntax::ast_util::binop_to_string; use utils::{span_lint, snippet}; +/// **What it does:** This lint checks for operations where precedence may be unclear and `Warn`'s about them by default, suggesting to add parentheses. Currently it catches the following: +/// * mixed usage of arithmetic and bit shifting/combining operators without parentheses +/// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call +/// +/// **Why is this bad?** Because not everyone knows the precedence of those operators by heart, so expressions like these may trip others trying to reason about the code. +/// +/// **Known problems:** None +/// +/// **Examples:** +/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 +/// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 declare_lint!(pub PRECEDENCE, Warn, "catches operations where precedence may be unclear. See the wiki for a \ list of cases caught"); diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 6946d0549d0..f748dbd9cfa 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -10,6 +10,13 @@ use rustc::front::map::Node; use utils::{span_lint, match_type}; use utils::{STRING_PATH, VEC_PATH}; +/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. It is `Warn` by default. +/// +/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be obtained from other types, too. +/// +/// **Known problems:** None +/// +/// **Example:** `fn foo(&Vec<u32>) { .. }` declare_lint! { pub PTR_ARG, Warn, diff --git a/src/ranges.rs b/src/ranges.rs index 31bb985230d..48bbba734ff 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -3,10 +3,24 @@ use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::{is_integer_literal, match_type, snippet}; +/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. It is `Warn` by default. +/// +/// **Why is this bad?** This very much looks like an oversight, since with `loop { .. }` there is an obvious better way to endlessly loop. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in (5..5).step_by(0) { .. }` declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, "using Range::step_by(0), which produces an infinite iterator" } +/// **What it does:** This lint checks for zipping a collection with the range of `0.._.len()`. It is `Warn` by default. +/// +/// **Why is this bad?** The code is better expressed with `.enumerate()`. +/// +/// **Known problems:** None +/// +/// **Example:** `x.iter().zip(0..x.len())` declare_lint! { pub RANGE_ZIP_WITH_LEN, Warn, "zipping iterator with a range when enumerate() would do" diff --git a/src/returns.rs b/src/returns.rs index 3df4efd0889..cf27b117ac4 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -6,8 +6,22 @@ use syntax::visit::FnKind; use utils::{span_lint, snippet, match_path_ast, in_external_macro}; +/// **What it does:** This lint checks for return statements at the end of a block. It is `Warn` by default. +/// +/// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty. +/// +/// **Known problems:** None +/// +/// **Example:** `fn foo(x: usize) { return x; }` declare_lint!(pub NEEDLESS_RETURN, Warn, "using a return statement like `return expr;` where an expression would suffice"); +/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. It is `Warn` by default. +/// +/// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. +/// +/// **Known problems:** None +/// +/// **Example:** `{ let x = ..; x }` declare_lint!(pub LET_AND_RETURN, Warn, "creating a let-binding and then immediately returning it like `let x = expr; x` at \ the end of a block"); diff --git a/src/shadow.rs b/src/shadow.rs index 60197fcf9df..b38435656c6 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -9,11 +9,32 @@ use rustc::middle::def::Def::{DefVariant, DefStruct}; use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint}; +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. It is `Allow` by default. +/// +/// **Why is this bad?** Not much, in fact it's a very common pattern in Rust code. Still, some may opt to avoid it in their code base, they can set this lint to `Warn`. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = &x;` declare_lint!(pub SHADOW_SAME, Allow, "rebinding a name to itself, e.g. `let mut x = &mut x`"); +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. It is `Allow` by default. +/// +/// **Why is this bad?** Not too much, in fact it's a common pattern in Rust code. Still, some argue that name shadowing like this hurts readability, because a value may be bound to different things depending on position in the code. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = x + 1;` declare_lint!(pub SHADOW_REUSE, Allow, "rebinding a name to an expression that re-uses the original value, e.g. \ `let x = x + 1`"); +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. This lint is `Warn` by default. +/// +/// **Why is this bad?** Name shadowing can hurt readability, especially in large code bases, because it is easy to lose track of the active binding at any place in the code. This can be alleviated by either giving more specific names to bindings ore introducing more scopes to contain the bindings. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = y; let x = z; // shadows the earlier binding` declare_lint!(pub SHADOW_UNRELATED, Allow, "The name is re-bound without even using the original value"); diff --git a/src/strings.rs b/src/strings.rs index 3c34e188d11..b567d949330 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -11,12 +11,38 @@ use eq_op::is_exp_equal; use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; +/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!) +/// +/// **Why is this bad?** Because this expression needs another copy as opposed to `x.push_str(y)` (in practice LLVM will usually elide it, though). Despite [llogiq](https://github.com/llogiq)'s reservations, this lint also is `allow` by default, as some people opine that it's more readable. +/// +/// **Known problems:** None. Well apart from the lint being `allow` by default. :smile: +/// +/// **Example:** +/// +/// ``` +/// let mut x = "Hello".to_owned(); +/// x = x + ", World"; +/// ``` declare_lint! { pub STRING_ADD_ASSIGN, Allow, "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" } +/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match. It is `Allow` by default. +/// +/// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code. +/// +/// That said, other people think that String addition, having a long tradition in other languages is actually fine, which is why we decided to make this particular lint `allow` by default. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let x = "Hello".to_owned(); +/// x + ", World" +/// ``` declare_lint! { pub STRING_ADD, Allow, diff --git a/src/types.rs b/src/types.rs index 506509cdfed..c505b612a8c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,8 +17,26 @@ use utils::{LL_PATH, VEC_PATH}; #[allow(missing_copy_implementations)] pub struct TypePass; +/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. +/// +/// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever. +/// +/// **Known problems:** None +/// +/// **Example:** `struct X { values: Box<Vec<Foo>> }` declare_lint!(pub BOX_VEC, Warn, "usage of `Box<Vec<T>>`, vector elements are already on the heap"); +/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or `RingBuf`. +/// +/// **Why is this bad?** Gankro says: +/// +/// >The TL;DR of `LinkedList` is that it's built on a massive amount of pointers and indirection. It wastes memory, it has terrible cache locality, and is all-around slow. `RingBuf`, while "only" amortized for push/pop, should be faster in the general case for almost every possible workload, and isn't even amortized at all if you can predict the capacity you need. +/// > +/// > `LinkedList`s are only really good if you're doing a lot of merging or splitting of lists. This is because they can just mangle some pointers instead of actually copying the data. Even if you're doing a lot of insertion in the middle of the list, `RingBuf` can still be better because of how expensive it is to seek to the middle of a `LinkedList`. +/// +/// **Known problems:** False positives – the instances where using a `LinkedList` makes sense are few and far between, but they can still happen. +/// +/// **Example:** `let x = LinkedList::new();` declare_lint!(pub LINKEDLIST, Warn, "usage of LinkedList, usually a vector is faster, or a more specialized data \ structure like a VecDeque"); @@ -53,6 +71,13 @@ impl LateLintPass for TypePass { #[allow(missing_copy_implementations)] pub struct LetPass; +/// **What it does:** This lint checks for binding a unit value. It is `Warn` by default. +/// +/// **Why is this bad?** A unit value cannot usefully be used anywhere. So binding one is kind of pointless. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = { 1; };` declare_lint!(pub LET_UNIT_VALUE, Warn, "creating a let binding to a value of unit type, which usually can't be used afterwards"); @@ -82,6 +107,13 @@ impl LateLintPass for LetPass { } } +/// **What it does:** This lint checks for comparisons to unit. It is `Warn` by default. +/// +/// **Why is this bad?** Unit is always equal to itself, and thus is just a clumsily written constant. Mostly this happens when someone accidentally adds semicolons at the end of the operands. +/// +/// **Known problems:** None +/// +/// **Example:** `if { foo(); } == { bar(); } { baz(); }` is equal to `{ foo(); bar(); baz(); }` declare_lint!(pub UNIT_CMP, Warn, "comparing unit values (which is always `true` or `false`, respectively)"); @@ -115,12 +147,42 @@ impl LateLintPass for UnitCmp { pub struct CastPass; +/// **What it does:** This lint checks for casts from any numerical to a float type where the receiving type cannot store all values from the original type without rounding errors. This possible rounding is to be expected, so this lint is `Allow` by default. +/// +/// Basically, this warns on casting any integer with 32 or more bits to `f32` or any 64-bit integer to `f64`. +/// +/// **Why is this bad?** It's not bad at all. But in some applications it can be helpful to know where precision loss can take place. This lint can help find those places in the code. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = u64::MAX; x as f64` declare_lint!(pub CAST_PRECISION_LOSS, Allow, "casts that cause loss of precision, e.g `x as f32` where `x: u64`"); +/// **What it does:** This lint checks for casts from a signed to an unsigned numerical type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default. +/// +/// **Why is this bad?** Possibly surprising results. You can activate this lint as a one-time check to see where numerical wrapping can arise. +/// +/// **Known problems:** None +/// +/// **Example:** `let y : i8 = -1; y as u64` will return 18446744073709551615 declare_lint!(pub CAST_SIGN_LOSS, Allow, "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"); +/// **What it does:** This lint checks for on casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by default. +/// +/// **Why is this bad?** In some problem domains, it is good practice to avoid truncation. This lint can be activated to help assess where additional checks could be beneficial. +/// +/// **Known problems:** None +/// +/// **Example:** `fn as_u8(x: u64) -> u8 { x as u8 }` declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); +/// **What it does:** This lint checks for casts from an unsigned type to a signed type of the same size. Performing such a cast is a 'no-op' for the compiler, i.e. nothing is changed at the bit level, and the binary representation of the value is reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default. +/// +/// **Why is this bad?** While such a cast is not bad in itself, the results can be surprising when this is not the intended behavior, as demonstrated by the example below. +/// +/// **Known problems:** None +/// +/// **Example:** `u32::MAX as i32` will yield a value of `-1`. declare_lint!(pub CAST_POSSIBLE_WRAP, Allow, "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`"); @@ -262,6 +324,13 @@ impl LateLintPass for CastPass { } } +/// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold. It is `Warn` by default. +/// +/// **Why is this bad?** Too complex types make the code less readable. Consider using a `type` definition to simplify them. +/// +/// **Known problems:** None +/// +/// **Example:** `struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }` declare_lint!(pub TYPE_COMPLEXITY, Warn, "usage of very complex types; recommends factoring out parts into `type` definitions"); diff --git a/src/unicode.rs b/src/unicode.rs index 3855fafe7be..a5b03087604 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -8,11 +8,32 @@ use unicode_normalization::UnicodeNormalization; use utils::{snippet, span_help_and_lint}; +/// **What it does:** This lint checks for the unicode zero-width space in the code. It is `Warn` by default. +/// +/// **Why is this bad?** Having an invisible character in the code makes for all sorts of April fools, but otherwise is very much frowned upon. +/// +/// **Known problems:** None +/// +/// **Example:** You don't see it, but there may be a zero-width space somewhere in this text. declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, "using a zero-width space in a string literal, which is confusing" } +/// **What it does:** This lint checks for non-ascii characters in string literals. It is `Allow` by default. +/// +/// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset back. Even so, there still are editors and other programs out there that don't work well with unicode. So if the code is meant to be used internationally, on multiple operating systems, or has other portability requirements, activating this lint could be useful. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = "Hä?"` declare_lint!{ pub NON_ASCII_LITERAL, Allow, "using any literal non-ASCII chars in a string literal; suggests \ using the \\u escape instead" } +/// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). This lint is `Allow` by default. +/// +/// **Why is this bad?** If such a string is compared to another, the results may be surprising. +/// +/// **Known problems** None +/// +/// **Example:** You may not see it, but "à" and "à" aren't the same string. The former when escaped is actually "a\u{300}" while the latter is "\u{e0}". declare_lint!{ pub UNICODE_NOT_NFC, Allow, "using a unicode literal not in NFC normal form (see \ http://www.unicode.org/reports/tr15/ for further information)" } diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 484348c5a37..c4d7cf4a589 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -9,6 +9,13 @@ use consts::{Constant, constant_simple, FloatWidth}; /// 0.0/0.0 with std::f32::NaN or std::f64::NaN, depending on the precision. pub struct ZeroDivZeroPass; +/// **What it does:** This lint checks for `0.0 / 0.0` +/// +/// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN` +/// +/// **Known problems:** None +/// +/// **Example** `0.0f32 / 0.0` declare_lint!(pub ZERO_DIVIDED_BY_ZERO, Warn, "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN"); diff --git a/util/update_wiki.py b/util/update_wiki.py new file mode 100755 index 00000000000..96333c1e4b3 --- /dev/null +++ b/util/update_wiki.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# Generate the wiki Home.md page from the contained doc comments +# requires the checked out wiki in ../rust-clippy.wiki/ +# with -c option, print a warning and set exit status 1 if the file would be changed. +import os, re, sys + +def parse_path(p="src"): + d = {} + for f in os.listdir(p): + if f.endswith(".rs"): + parse_file(d, os.path.join(p, f)) + return d + +START = 0 +LINT = 1 + +def parse_file(d, f): + last_comment = [] + comment = True + lint = None + + with open(f) as rs: + for line in rs: + if comment: + if line.startswith("///"): + if line.startswith("/// "): + last_comment.append(line[4:]) + else: + last_comment.append(line[3:]) + elif line.startswith("declare_lint!"): + comment = False + else: + last_comment = [] + if not comment: + l = line.strip() + m = re.search(r"pub\s+([A-Z_]+)", l) + if m: + print "found %s in %s" % (m.group(1).lower(), f) + d[m.group(1).lower()] = last_comment + last_comment = [] + comment = True + if "}" in l: + print "Warning: Missing Lint-Name in", f + comment = True + +PREFIX = """Welcome to the rust-clippy wiki! + +Here we aim to collect further explanations on the lints clippy provides. So without further ado: + +""" + +WARNING = """ +# A word of warning + +Clippy works as a *plugin* to the compiler, which means using an unstable internal API. We have gotten quite good at keeping pace with the API evolution, but the consequence is that clippy absolutely needs to be compiled with the version of `rustc` it will run on, otherwise you will get strange errors of missing symbols.""" + +def write_wiki_page(d, f): + keys = d.keys() + keys.sort() + with open(f, "w") as w: + w.write(PREFIX) + for k in keys: + w.write("[`%s`](#%s)\n" % (k, k)) + w.write(WARNING) + for k in keys: + w.write("\n# `%s`\n\n%s" % (k, "".join(d[k]))) + +def check_wiki_page(d, f): + errors = [] + with open(f) as w: + for line in w: + m = re.match("# `([a-z_]+)`", line) + if m: + v = d.pop(m.group(1), "()") + if v == "()": + errors.append("Missing wiki entry: " + m.group(1)) + keys = d.keys() + keys.sort() + for k in keys: + errors.append("Spurious wiki entry: " + k) + if errors: + print "\n".join(errors) + sys.exit(1) + +if __name__ == "__main__": + d = parse_path() + if "-c" in sys.argv: + check_wiki_page(d, "../rust-clippy.wiki/Home.md") + else: + write_wiki_page(d, "../rust-clippy.wiki/Home.md") -- cgit 1.4.1-3-g733a5 From 974ab43453514d85bc0bb3ffa4ee44f0b0e6204e Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Fri, 11 Dec 2015 16:28:05 +0900 Subject: Use suggestion for needless_return --- src/returns.rs | 17 +++++++++++------ tests/compile-fail/needless_return.rs | 12 +++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/returns.rs b/src/returns.rs index 3df4efd0889..7347558b3a7 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -4,7 +4,7 @@ use syntax::ast::*; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; -use utils::{span_lint, snippet, match_path_ast, in_external_macro}; +use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro}; declare_lint!(pub NEEDLESS_RETURN, Warn, "using a return statement like `return expr;` where an expression would suffice"); @@ -23,7 +23,7 @@ impl ReturnPass { } else if let Some(stmt) = block.stmts.last() { if let StmtSemi(ref expr, _) = stmt.node { if let ExprRet(Some(ref inner)) = expr.node { - self.emit_return_lint(cx, (expr.span, inner.span)); + self.emit_return_lint(cx, (stmt.span, inner.span)); } } } @@ -59,10 +59,15 @@ impl ReturnPass { fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) { if in_external_macro(cx, spans.1) {return;} - span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( - "unneeded return statement. Consider using `{}` \ - without the return and trailing semicolon", - snippet(cx, spans.1, ".."))) + span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, + "unneeded return statement", + || { + if let Some(snippet) = snippet_opt(cx, spans.1) { + cx.sess().span_suggestion(spans.0, + "remove `return` as shown:", + snippet); + } + }); } // Check for "let x = EXPR; x" diff --git a/tests/compile-fail/needless_return.rs b/tests/compile-fail/needless_return.rs index e0012942906..fe29d991661 100644 --- a/tests/compile-fail/needless_return.rs +++ b/tests/compile-fail/needless_return.rs @@ -8,11 +8,17 @@ fn test_end_of_fn() -> bool { // no error! return true; } - return true; //~ERROR unneeded return statement + return true; + //~^ ERROR unneeded return statement + //~| HELP remove `return` as shown + //~| SUGGESTION true } fn test_no_semicolon() -> bool { - return true //~ERROR unneeded return statement + return true + //~^ ERROR unneeded return statement + //~| HELP remove `return` as shown + //~| SUGGESTION true } fn test_if_block() -> bool { @@ -29,7 +35,7 @@ fn test_match(x: bool) -> bool { return false; //~ERROR unneeded return statement } false => { - return true //~ERROR unneeded return statement + return true; //~ERROR unneeded return statement } } } -- cgit 1.4.1-3-g733a5 From 8e59be318c73d33adf99a76a48ebd0f655b97968 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros <cesarb@cesarb.eti.br> Date: Sat, 12 Dec 2015 20:05:06 -0200 Subject: Mention VecDeque in linkedlist lint I couldn't find anything named RingBuf in the standard library. Some search revealed that it had been renamed to VecDeque before the first stable Rust release. --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index c505b612a8c..9bc50643259 100644 --- a/src/types.rs +++ b/src/types.rs @@ -26,7 +26,7 @@ pub struct TypePass; /// **Example:** `struct X { values: Box<Vec<Foo>> }` declare_lint!(pub BOX_VEC, Warn, "usage of `Box<Vec<T>>`, vector elements are already on the heap"); -/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or `RingBuf`. +/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). /// /// **Why is this bad?** Gankro says: /// -- cgit 1.4.1-3-g733a5 From 4ae43b10f0b48bca95efa6dd830bb7281f52f05e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 13 Dec 2015 09:08:58 +0530 Subject: Add wiki note for escape analysis --- src/escape.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index fbd545acc96..1df19bcf548 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -14,6 +14,20 @@ use utils::span_lint; pub struct EscapePass; +/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine +/// +/// **Why is this bad?** This is an unnecessary allocation, and bad for performance +/// +/// It is only necessary to allocate if you wish to move the box into something. +/// +/// **Example:** +/// +/// ```rust +/// fn main() { +/// let x = Box::new(1); +/// foo(*x); +/// println!("{}", *x); +/// } declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); struct EscapeDelegate<'a, 'tcx: 'a> { -- cgit 1.4.1-3-g733a5 From 9de308ee1538ed35988dc6bcb0fd2faf43129133 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Fri, 11 Dec 2015 14:02:02 -0800 Subject: Add used_underscore_binding lint --- src/misc.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index b5c3d0c514f..7068aac781e 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -9,6 +9,7 @@ use rustc::middle::ty; use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::def::Def; use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; use utils::span_help_and_lint; @@ -316,3 +317,36 @@ impl LateLintPass for PatternPass { } } } + +declare_lint!(pub USED_UNDERSCORE_BINDING, Warn, + "using a binding which is prefixed with an underscore"); + +#[derive(Copy, Clone)] +pub struct UsedUnderscoreBinding; + +impl LintPass for UsedUnderscoreBinding { + fn get_lints(&self) -> LintArray { + lint_array!(USED_UNDERSCORE_BINDING) + } +} + +impl LateLintPass for UsedUnderscoreBinding { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + let needs_lint = match expr.node { + ExprPath(_, ref path) => { + path.segments.last().unwrap().identifier.name.as_str().chars().next() == Some('_') && + (cx.tcx.def_map.borrow()).values().any(|res| match res.base_def { + Def::DefLocal(_, _) => true, + _ => false + }) + }, + ExprField(_, spanned) => spanned.node.as_str().chars().next() == Some('_'), + _ => false + }; + if needs_lint { + cx.span_lint(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.")); + } + } +} -- cgit 1.4.1-3-g733a5 From 43b96d59ade2321bf55f2ee0f082b8f0b7080bfe Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Fri, 11 Dec 2015 15:08:59 -0800 Subject: Run update_lints.py --- README.md | 3 ++- src/lib.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/README.md b/README.md index 4e410002852..015a7d9adf2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 83 lints included in this crate: +There are 84 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -86,6 +86,7 @@ name [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions +[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator diff --git a/src/lib.rs b/src/lib.rs index 03e0cbea19c..05181e69b2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,6 +120,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25)); reg.register_late_lint_pass(box escape::EscapePass); reg.register_early_lint_pass(box misc_early::MiscEarly); + reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -184,6 +185,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, + misc::USED_UNDERSCORE_BINDING, misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, -- cgit 1.4.1-3-g733a5 From 609111269818f99918980c85753d0d1bcea488c3 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sat, 12 Dec 2015 16:31:34 -0800 Subject: Update tests --- src/misc.rs | 2 +- tests/compile-fail/used_underscore_binding.rs | 32 +++++++++++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 7068aac781e..5c3aeeb7899 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -345,7 +345,7 @@ impl LateLintPass for UsedUnderscoreBinding { }; if needs_lint { cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, &format!( - "Used binding which is prefixed with an underscore. A leading underscore signals\ + "used binding which is prefixed with an underscore. A leading underscore signals\ that a binding will not be used.")); } } diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 8c7fe4e0069..adc20d67841 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -1,22 +1,30 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(used_underscore_binding)] +#![deny(clippy)] -fn main() { - let foo = 0u32; - prefix_underscore(foo); //should fail - non_prefix_underscore(foo); //should pass - unused_underscore(foo); //should pass +fn prefix_underscore(_x: u32) -> u32{ + _x + 1 //~ ERROR used binding which is prefixed with an underscore } -fn prefix_underscore(_x: u32){ - println!("{}", _x + 1); //~Error: Used binding which is prefixed with an underscore +fn in_macro(_x: u32) { + println!("{}", _x); //~ ERROR used binding which is prefixed with an underscore } -fn non_prefix_underscore(some_foo: u32) { - println!("{}", some_foo + 1); +fn non_prefix_underscore(some_foo: u32) -> u32 { + some_foo + 1 } -fn unused_underscore(_foo: u32) { - println!("{}", 1); +fn unused_underscore(_foo: u32) -> u32 { + 1 } + +fn main() { + let foo = 0u32; + // tests of unused_underscore lint + let _ = prefix_underscore(foo); + in_macro(foo); + // possible false positives + let _ = non_prefix_underscore(foo); + let _ = unused_underscore(foo); +} + -- cgit 1.4.1-3-g733a5 From aeb5a0e60cc7b61253fa486b4e3af4d537af7322 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sat, 12 Dec 2015 17:51:58 -0800 Subject: Reduce false positives Add macro checking, and only lint for single leading underscores --- src/misc.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 5c3aeeb7899..f46a26c10e1 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -334,19 +334,24 @@ impl LateLintPass for UsedUnderscoreBinding { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { let needs_lint = match expr.node { ExprPath(_, ref path) => { - path.segments.last().unwrap().identifier.name.as_str().chars().next() == Some('_') && - (cx.tcx.def_map.borrow()).values().any(|res| match res.base_def { + let ident = path.segments.last() + .expect("path should always have at least one segment") + .identifier; + ident.name.as_str().chars().next() == Some('_') //starts with '_' + && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" + && ident.name != ident.unhygienic_name //not in macro + && cx.tcx.def_map.borrow().values().any(|res| match res.base_def { Def::DefLocal(_, _) => true, _ => false - }) + }) //local variable }, ExprField(_, spanned) => spanned.node.as_str().chars().next() == Some('_'), _ => false }; if needs_lint { - cx.span_lint(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.")); + cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, + "used binding which is prefixed with an underscore. A leading underscore\ + signals that a binding will not be used."); } } } -- cgit 1.4.1-3-g733a5 From b24e3aeea038cb207f28f868a6af1e36897d0e5b Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sat, 12 Dec 2015 21:50:36 -0800 Subject: Add wiki docs, in line with #492 --- src/misc.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index f46a26c10e1..2558d6bb4bb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -318,6 +318,29 @@ impl LateLintPass for PatternPass { } } + +/// **What it does:** This lint checks for the use of bindings with a single leading underscore +/// +/// **Why is this bad?** A single leading underscore is usually used to indicate that a binding +/// will not be used. Using such a binding breaks this expectation. +/// +/// **Known problems:** This lint's idea of a "used" variable is not quite the same as in the +/// built-in `unused_variables` lint. For example, in the following code +/// ``` +/// fn foo(_y: u32) -> u32) { +/// let _x = 1; +/// _x +=1; +/// y +/// } +/// ``` +/// _x will trigger both the `unused_variables` lint and the `used_underscore_binding` lint. +/// +/// **Example**: +/// ``` +/// let _x = 0; +/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore. +/// // We should rename `_x` to `x` +/// ``` declare_lint!(pub USED_UNDERSCORE_BINDING, Warn, "using a binding which is prefixed with an underscore"); -- cgit 1.4.1-3-g733a5 From 6960bf2ebc711385048834863eda081bae2633db Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sat, 12 Dec 2015 21:59:25 -0800 Subject: Make ExprField follow single-underscore rules --- src/misc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 2558d6bb4bb..89b4dbb4de6 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -368,7 +368,11 @@ impl LateLintPass for UsedUnderscoreBinding { _ => false }) //local variable }, - ExprField(_, spanned) => spanned.node.as_str().chars().next() == Some('_'), + ExprField(_, spanned) => { + let name = spanned.node.as_str(); + name.chars().next() == Some('_') + && name.chars().skip(1).next() != Some('_') + }, _ => false }; if needs_lint { -- cgit 1.4.1-3-g733a5 From d7292fe235bc9d72c9c528e2c2bfc5d07ad7baa2 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 14 Dec 2015 08:03:01 +0100 Subject: more docs --- src/mutex_atomic.rs | 14 ++++++++++++++ src/transmute.rs | 7 +++++++ 2 files changed, 21 insertions(+) (limited to 'src') diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index e6d1fc8a888..40f7d21f43c 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -11,12 +11,26 @@ use rustc::middle::subst::ParamSpace; use utils::{span_lint, MUTEX_PATH, match_type}; +/// **What it does:** It `Warn`s on usages of `Mutex<X>` where an atomic will do +/// +/// **Why is this bad?** Using a Mutex just to make access to a plain bool or reference sequential is shooting flies with cannons. `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and faster. +/// +/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. +/// +/// **Example:** `let x = Mutex::new(&y);` declare_lint! { pub MUTEX_ATOMIC, Warn, "using a Mutex where an atomic value could be used instead" } +/// **What it does:** It `Warn`s on usages of `Mutex<X>` where `X` is an integral type. +/// +/// **Why is this bad?** Using a Mutex just to make access to a plain integer sequential is shooting flies with cannons. `std::atomic::usize` is leaner and faster. +/// +/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. +/// +/// **Example:** `let x = Mutex::new(0usize);` declare_lint! { pub MUTEX_INTEGER, Allow, diff --git a/src/transmute.rs b/src/transmute.rs index ab1397ea7fe..c71468bf5a0 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -2,6 +2,13 @@ use rustc::lint::*; use rustc_front::hir::*; use utils; +/// **What it does:** This lint checks for transmutes to the original type of the object. It is `Warn` by default. +/// +/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type. +/// +/// **Known problems:** None. +/// +/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s. declare_lint! { pub USELESS_TRANSMUTE, Warn, -- cgit 1.4.1-3-g733a5 From c0bccc95670fc3891c1991f22815ef9a6f043850 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 14 Dec 2015 13:31:28 +0100 Subject: more doc comments --- src/block_in_if_condition.rs | 14 ++++++++++++++ src/map_clone.rs | 7 +++++++ 2 files changed, 21 insertions(+) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 39196ed175f..b4e81ac6a2b 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -3,11 +3,25 @@ use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; use rustc_front::intravisit::{Visitor, walk_expr}; use utils::*; +/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. +/// +/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions. +/// +/// **Known problems:** None +/// +/// **Example:** `if { true } ..` declare_lint! { pub BLOCK_IN_IF_CONDITION_EXPR, Warn, "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" } +/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. +/// +/// **Why is this bad?** Using blocks in the condition makes it hard to read. +/// +/// **Known problems:** None +/// +/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..` declare_lint! { pub BLOCK_IN_IF_CONDITION_STMT, Warn, "avoid complex blocks in conditions, instead move the block higher and bind it \ diff --git a/src/map_clone.rs b/src/map_clone.rs index d9719df0b6f..f5e8d20a745 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -4,6 +4,13 @@ use utils::{CLONE_PATH, OPTION_PATH}; use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; +/// **What it does:** This lint checks for mapping clone() over an iterator. It is `Warn` by default and suggests to use `.cloned()` instead. +/// +/// **Why is this bad?** It makes the code less readable. +/// +/// **Known problems:** False negative: The lint currently misses mapping `Clone::clone` directly. Issue #436 is tracking this. +/// +/// **Example:** `x.map(|e| e.clone());` declare_lint!(pub MAP_CLONE, Warn, "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ `.cloned()` instead)"); -- cgit 1.4.1-3-g733a5 From 902c7d832b6f355414632ca55dc7c7017fde5250 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Dec 2015 14:29:20 +0100 Subject: fix cc computation in the presence of diverging calls CFG treats diverging calls as its completely own path out of the function. While this makes sense, it should also mean that a panic should increase the cyclomatic complexity. Instead it decreases it. Minimal example: ```rust if a { b } else { panic!("cake"); } d ``` creates the following graph ```dot digraph G { "if a" -> "b" "if a" -> "panic!(\"cake\")" "b" -> c } ``` which has a CC of 1 (3 - 4 + 2). A CC of 1 means there is one path through the program. Obviously that is wrong. There are two paths. One returning normally, and one panicking. --- src/cyclomatic_complexity.rs | 52 +++++++++---- tests/cc_seme.rs | 25 +++++++ tests/compile-fail/cyclomatic_complexity.rs | 110 +++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 tests/cc_seme.rs (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 1379a8db15d..cb391769279 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -3,6 +3,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc::middle::cfg::CFG; +use rustc::middle::ty; use syntax::codemap::Span; use syntax::attr::*; use syntax::ast::Attribute; @@ -32,7 +33,7 @@ impl LintPass for CyclomaticComplexity { } impl CyclomaticComplexity { - fn check(&mut self, cx: &LateContext, block: &Block, span: Span) { + fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) { if in_macro(cx, span) { return; } let cfg = CFG::new(cx.tcx, block); let n = cfg.graph.len_nodes() as u64; @@ -40,15 +41,16 @@ impl CyclomaticComplexity { let cc = e + 2 - n; let mut arm_counter = MatchArmCounter(0); arm_counter.visit_block(block); - let mut narms = arm_counter.0; - if narms > 0 { - narms = narms - 1; - } - - if cc < narms { - report_cc_bug(cx, cc, narms, span); + let narms = arm_counter.0; + + let mut diverge_counter = DivergenceCounter(0, &cx.tcx); + diverge_counter.visit_block(block); + let divergence = diverge_counter.0; + + if cc + divergence < narms { + report_cc_bug(cx, cc, narms, divergence, span); } else { - let rust_cc = cc - narms; + let rust_cc = cc + divergence - narms; if rust_cc > self.limit.limit() { cx.span_lint_help(CYCLOMATIC_COMPLEXITY, span, &format!("The function has a cyclomatic complexity of {}.", rust_cc), @@ -93,8 +95,28 @@ impl<'a> Visitor<'a> for MatchArmCounter { ExprMatch(_, ref arms, _) => { walk_expr(self, e); let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum(); - if arms_n > 0 { - self.0 += arms_n - 1; + if arms_n > 1 { + self.0 += arms_n - 2; + } + }, + ExprClosure(..) => {}, + _ => walk_expr(self, e), + } + } +} + +struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::ctxt<'tcx>); + +impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> { + fn visit_expr(&mut self, e: &'a Expr) { + match e.node { + ExprCall(ref callee, _) => { + walk_expr(self, e); + let ty = self.1.node_id_to_type(callee.id); + if let ty::TyBareFn(_, ty) = ty.sty { + if ty.sig.skip_binder().output.diverges() { + self.0 += 1; + } } }, ExprClosure(..) => {}, @@ -104,15 +126,15 @@ impl<'a> Visitor<'a> for MatchArmCounter { } #[cfg(feature="debugging")] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, span: Span) { +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { cx.sess().span_bug(span, &format!("Clippy encountered a bug calculating cyclomatic complexity: \ - cc = {}, arms = {}. Please file a bug report.", cc, narms));; + cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div));; } #[cfg(not(feature="debugging"))] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, span: Span) { +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { cx.sess().span_note(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ (hide this message with `#[allow(cyclomatic_complexity)]`): \ - cc = {}, arms = {}. Please file a bug report.", cc, narms)); + cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div)); } } diff --git a/tests/cc_seme.rs b/tests/cc_seme.rs new file mode 100644 index 00000000000..a26731c396a --- /dev/null +++ b/tests/cc_seme.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[allow(dead_code)] +enum Baz { + Baz1, + Baz2, +} + +struct Test { + t: Option<usize>, + b: Baz, +} + +fn main() { + use Baz::*; + let x = Test { t: Some(0), b: Baz1 }; + + match x { + Test { t: Some(_), b: Baz1 } => unreachable!(), + Test { t: Some(42), b: Baz2 } => unreachable!(), + Test { t: None, .. } => unreachable!(), + Test { .. } => unreachable!(), + } +} diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 8e3bf123c26..1a6dfd28728 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -89,7 +89,7 @@ fn main() { //~ ERROR: The function has a cyclomatic complexity of 28. } #[cyclomatic_complexity = "0"] -fn kaboom() { //~ ERROR: The function has a cyclomatic complexity of 6 +fn kaboom() { //~ ERROR: The function has a cyclomatic complexity of 8 let n = 0; 'a: for i in 0..20 { 'b: for j in i..20 { @@ -170,6 +170,114 @@ fn barr() { //~ ERROR: The function has a cyclomatic complexity of 2 } } +#[cyclomatic_complexity = "0"] +fn barr2() { //~ ERROR: The function has a cyclomatic complexity of 3 + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn barrr() { //~ ERROR: The function has a cyclomatic complexity of 2 + match 99 { + 0 => println!("hi"), + 1 => panic!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn barrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 + match 99 { + 0 => println!("hi"), + 1 => panic!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } + match 99 { + 0 => println!("hi"), + 1 => panic!("bla"), + 2 | 3 => println!("blub"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn barrrr() { //~ ERROR: The function has a cyclomatic complexity of 2 + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => panic!("blub"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn barrrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => panic!("blub"), + _ => println!("bye"), + } + match 99 { + 0 => println!("hi"), + 1 => println!("bla"), + 2 | 3 => panic!("blub"), + _ => println!("bye"), + } +} + +#[cyclomatic_complexity = "0"] +fn cake() { //~ ERROR: The function has a cyclomatic complexity of 2 + if 4 == 5 { + println!("yea"); + } else { + panic!("meh"); + } + println!("whee"); +} + + +#[cyclomatic_complexity = "0"] +pub fn read_file(input_path: &str) -> String { //~ ERROR: The function has a cyclomatic complexity of 4 + use std::fs::File; + use std::io::{Read, Write}; + use std::path::Path; + let mut file = match File::open(&Path::new(input_path)) { + Ok(f) => f, + Err(err) => { + panic!("Can't open {}: {}", input_path, err); + } + }; + + let mut bytes = Vec::new(); + + match file.read_to_end(&mut bytes) { + Ok(..) => {}, + Err(_) => { + panic!("Can't read {}", input_path); + } + }; + + match String::from_utf8(bytes) { + Ok(contents) => contents, + Err(_) => { + panic!("{} is not UTF-8 encoded", input_path); + } + } +} + enum Void {} #[cyclomatic_complexity = "0"] -- cgit 1.4.1-3-g733a5 From cc1d696cb9df64b1da9aeebcc47717d84ec649f8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Dec 2015 14:30:09 +0100 Subject: fix fallout from CC improvements --- src/loops.rs | 27 +++++++++++---------------- src/matches.rs | 12 +++++------- 2 files changed, 16 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 3c4e023b98e..8295e186172 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -147,14 +147,8 @@ impl LateLintPass for LoopsPass { // extract the expression from the first statement (if any) in a block let inner_stmt_expr = extract_expr_from_first_stmt(block); - // extract the first expression (if any) from the block - let inner_expr = extract_first_expr(block); - let (extracted, collect_expr) = match inner_stmt_expr { - Some(_) => (inner_stmt_expr, true), // check if an expression exists in the first statement - None => (inner_expr, false), // if not, let's go for the first expression in the block - }; - - if let Some(inner) = extracted { + // or extract the first expression (if any) from the block + if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(block)) { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // collect the remaining statements below the match let mut other_stuff = block.stmts @@ -163,10 +157,11 @@ impl LateLintPass for LoopsPass { .map(|stmt| { format!("{}", snippet(cx, stmt.span, "..")) }).collect::<Vec<String>>(); - if collect_expr { // if we have a statement which has a match, - match block.expr { // then collect the expression (without semicolon) below it - Some(ref expr) => other_stuff.push(format!("{}", snippet(cx, expr.span, ".."))), - None => (), + if inner_stmt_expr.is_some() { + // if we have a statement which has a match, + if let Some(ref expr) = block.expr { + // then collect the expression (without semicolon) below it + other_stuff.push(format!("{}", snippet(cx, expr.span, ".."))); } } @@ -180,12 +175,12 @@ impl LateLintPass for LoopsPass { is_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { return; } - let loop_body = match inner_stmt_expr { + let loop_body = if inner_stmt_expr.is_some() { // FIXME: should probably be an ellipsis // tabbing and newline is probably a bad idea, especially for large blocks - Some(_) => Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))), - None => expr_block(cx, &arms[0].body, - Some(other_stuff.join("\n ")), ".."), + Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) + } else { + expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") }; span_help_and_lint(cx, WHILE_LET_LOOP, expr.span, "this loop could be written as a `while let` loop", diff --git a/src/matches.rs b/src/matches.rs index 39459bafba7..460893d93ab 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -102,13 +102,11 @@ impl LateLintPass for MatchPass { if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { - if let LitBool(val) = lit.node { - if val { - Some((&*arms[0].body, &*arms[1].body)) - } else { - Some((&*arms[1].body, &*arms[0].body)) - } - } else { None } + match lit.node { + LitBool(true) => Some((&*arms[0].body, &*arms[1].body)), + LitBool(false) => Some((&*arms[1].body, &*arms[0].body)), + _ => None, + } } else { None } } else { None }; if let Some((ref true_expr, ref false_expr)) = exprs { -- cgit 1.4.1-3-g733a5 From 827082ac41a7f05fe6b974523a54977100fda6b6 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 14 Dec 2015 21:17:11 +0100 Subject: fix boxed_local example --- src/escape.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index 1df19bcf548..63894cda9be 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -28,6 +28,7 @@ pub struct EscapePass; /// foo(*x); /// println!("{}", *x); /// } +/// ``` declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); struct EscapeDelegate<'a, 'tcx: 'a> { -- cgit 1.4.1-3-g733a5 From c645a9febe4451bec13eda67fb808f3471d5d00f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 14 Dec 2015 22:16:56 +0100 Subject: adding missing doc comments --- src/cyclomatic_complexity.rs | 7 +++++++ src/lifetimes.rs | 7 +++++++ src/loops.rs | 7 +++++++ src/methods.rs | 30 ++++++++++++++++++++++++++++++ src/misc_early.rs | 7 +++++++ src/needless_features.rs | 14 ++++++++++++++ src/needless_update.rs | 7 +++++++ src/no_effect.rs | 7 +++++++ src/temporary_assignment.rs | 7 +++++++ 9 files changed, 93 insertions(+) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index cb391769279..c2cc6a8c4ab 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -11,6 +11,13 @@ use rustc_front::intravisit::{Visitor, walk_expr}; use utils::{in_macro, LimitStack}; +/// **What it does:** It `Warn`s on methods with high cyclomatic complexity +/// +/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better. +/// +/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity +/// +/// **Example:** No. You'll see it when you get the warning. declare_lint! { pub CYCLOMATIC_COMPLEXITY, Warn, "finds functions that should be split up into multiple functions" } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 743dc366e44..6ae10c09455 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -19,6 +19,13 @@ declare_lint!(pub NEEDLESS_LIFETIMES, Warn, "using explicit lifetimes for references in function arguments when elision rules \ would allow omitting them"); +/// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. It is `Warn` by default. +/// +/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. +/// +/// **Known problems:** None +/// +/// **Example:** `fn unused_lifetime<'a>(x: u8) { .. }` declare_lint!(pub UNUSED_LIFETIMES, Warn, "unused lifetimes in function definitions"); diff --git a/src/loops.rs b/src/loops.rs index 8295e186172..5c552d2ce42 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -114,6 +114,13 @@ declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, /// **Example:** `loop {}` declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } +/// **What it does:** This lint checks for `while let` expressions on iterators. It is `Warn` by default. +/// +/// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys the intent better. +/// +/// **Known problems:** None +/// +/// **Example:** `while let Some(val) = iter() { .. }` declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" } #[derive(Copy, Clone)] diff --git a/src/methods.rs b/src/methods.rs index 6c629f29c41..ef7a58959ac 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -24,6 +24,7 @@ pub struct MethodsPass; /// **Example:** `x.unwrap()` declare_lint!(pub OPTION_UNWRAP_USED, Allow, "using `Option.unwrap()`, which should at least get a better message using `expect()`"); + /// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. It is `Allow` by default. /// /// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`. @@ -35,6 +36,7 @@ declare_lint!(pub OPTION_UNWRAP_USED, Allow, /// **Example:** `x.unwrap()` declare_lint!(pub RESULT_UNWRAP_USED, Allow, "using `Result.unwrap()`, which might be better handled"); + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. It is `Warn` by default. /// /// **Why is this bad?** This uses the whole formatting machinery just to clone a string. Using `.to_owned()` is lighter on resources. You can also consider using a [`Cow<'a, str>`](http://doc.rust-lang.org/std/borrow/enum.Cow.html) instead in some cases. @@ -44,6 +46,7 @@ declare_lint!(pub RESULT_UNWRAP_USED, Allow, /// **Example:** `s.to_string()` where `s: &str` declare_lint!(pub STR_TO_STRING, Warn, "using `to_string()` on a str, which should be `to_owned()`"); + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default. /// /// **Why is this bad?** As our string is already owned, this whole operation is basically a no-op, but still creates a clone of the string (which, if really wanted, should be done with `.clone()`). @@ -53,6 +56,7 @@ declare_lint!(pub STR_TO_STRING, Warn, /// **Example:** `s.to_string()` where `s: String` declare_lint!(pub STRING_TO_STRING, Warn, "calling `String.to_string()` which is a no-op"); + /// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default. /// /// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. @@ -68,6 +72,7 @@ declare_lint!(pub STRING_TO_STRING, Warn, /// ``` declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, "defining a method that should be implementing a std trait"); + /// **What it does:** This lint checks for methods with certain name prefixes and `Warn`s (by default) if the prefix doesn't match how self is taken. The actual rules are: /// /// |Prefix |`self` taken | @@ -92,6 +97,7 @@ declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, declare_lint!(pub WRONG_SELF_CONVENTION, Warn, "defining a method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); + /// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. This lint is `Allow` by default. /// /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). @@ -107,12 +113,36 @@ declare_lint!(pub WRONG_SELF_CONVENTION, Warn, declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, "defining a public method named with an established prefix (like \"into_\") that takes \ `self` with the wrong convention"); + +/// **What it does:** This lint `Warn`s on using `ok().expect(..)`. +/// +/// **Why is this bad?** Because you usually call `expect()` on the `Result` directly to get a good error message. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.ok().expect("why did I do this again?")` declare_lint!(pub OK_EXPECT, Warn, "using `ok().expect()`, which gives worse error messages than \ calling `expect` directly on the Result"); + +/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or(_)`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or(_, _)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.map(|a| a + 1).unwrap_or(0)` declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ `map_or(a, f)`)"); + +/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or_else(_, _)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)` declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ `map_or_else(g, f)`)"); diff --git a/src/misc_early.rs b/src/misc_early.rs index 8adff752337..1520e9c0e58 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -6,6 +6,13 @@ use syntax::ast::*; use utils::span_lint; +/// **What it does:** This lint `Warn`s on struct field patterns bound to wildcards. +/// +/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. +/// +/// **Known problems:** None. +/// +/// **Example:** `let { a: _, b: ref b, c: _ } = ..` declare_lint!(pub UNNEEDED_FIELD_PATTERN, Warn, "Struct fields are bound to a wildcard instead of using `..`"); diff --git a/src/needless_features.rs b/src/needless_features.rs index 44db5e92221..2dd53c2d783 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -8,6 +8,13 @@ use rustc_front::hir::*; use utils::span_lint; use utils; +/// **What it does:** This lint `Warn`s on use of the `as_slice(..)` function, which is unstable. +/// +/// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.as_slice(..)` declare_lint! { pub UNSTABLE_AS_SLICE, Warn, @@ -15,6 +22,13 @@ declare_lint! { see https://github.com/rust-lang/rust/issues/27729" } +/// **What it does:** This lint `Warn`s on use of the `as_mut_slice(..)` function, which is unstable. +/// +/// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.as_mut_slice(..)` declare_lint! { pub UNSTABLE_AS_MUT_SLICE, Warn, diff --git a/src/needless_update.rs b/src/needless_update.rs index c65d0c9e7d3..e1e0f481848 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -4,6 +4,13 @@ use rustc_front::hir::{Expr, ExprStruct}; use utils::span_lint; +/// **What it does:** This lint `Warn`s on needlessly including a base struct on update when all fields are changed anyway. +/// +/// **Why is this bad?** This will cost resources (because the base has to be somewhere), and make the code less readable. +/// +/// **Known problems:** None. +/// +/// **Example:** `Point { x: 1, y: 0, ..zero_point }`` declare_lint! { pub NEEDLESS_UPDATE, Warn, diff --git a/src/no_effect.rs b/src/no_effect.rs index 82fcf92fd4c..b51b4235d54 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -6,6 +6,13 @@ use rustc_front::hir::{Stmt, StmtSemi}; use utils::in_macro; use utils::span_lint; +/// **What it does:** This lint `Warn`s on statements which have no effect. +/// +/// **Why is this bad?** Similar to dead code, these statements are actually executed. However, as they have no effect, all they do is make the code less readable. +/// +/// **Known problems:** None. +/// +/// **Example:** `0;` declare_lint! { pub NO_EFFECT, Warn, diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs index 6cfcb711ff7..622bf5bc25e 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -4,6 +4,13 @@ use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTup use utils::is_adjusted; use utils::span_lint; +/// **What it does:** This lint `Warn`s on creating a struct or tuple just to assign a value in it. +/// +/// **Why is this bad?** Readability. If the struct is only created to be updated, why not write the struct you want in the first place? +/// +/// **Known problems:** None. +/// +/// **Example:** `(0, 0).0 = 1` declare_lint! { pub TEMPORARY_ASSIGNMENT, Warn, -- cgit 1.4.1-3-g733a5 From e620a1d57cb1a49b1c6e7e45c19f9102dc0876d3 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Wed, 16 Dec 2015 15:28:06 -0800 Subject: Make suggested changes --- src/misc.rs | 8 ++------ tests/compile-fail/used_underscore_binding.rs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 89b4dbb4de6..3b093027f48 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -9,7 +9,6 @@ use rustc::middle::ty; use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::def::Def; use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; use utils::span_help_and_lint; @@ -327,7 +326,7 @@ impl LateLintPass for PatternPass { /// **Known problems:** This lint's idea of a "used" variable is not quite the same as in the /// built-in `unused_variables` lint. For example, in the following code /// ``` -/// fn foo(_y: u32) -> u32) { +/// fn foo(y: u32) -> u32) { /// let _x = 1; /// _x +=1; /// y @@ -363,10 +362,7 @@ impl LateLintPass for UsedUnderscoreBinding { ident.name.as_str().chars().next() == Some('_') //starts with '_' && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" && ident.name != ident.unhygienic_name //not in macro - && cx.tcx.def_map.borrow().values().any(|res| match res.base_def { - Def::DefLocal(_, _) => true, - _ => false - }) //local variable + && cx.tcx.def_map.borrow().contains_key(&expr.id) //local variable }, ExprField(_, spanned) => { let name = spanned.node.as_str(); diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index adc20d67841..5567f23a9ff 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(clippy)] -fn prefix_underscore(_x: u32) -> u32{ +fn prefix_underscore(_x: u32) -> u32 { _x + 1 //~ ERROR used binding which is prefixed with an underscore } -- cgit 1.4.1-3-g733a5 From 02cb24de82e7dda49e7ae612a968de548c67b8f0 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Fri, 18 Dec 2015 13:45:03 -0800 Subject: Remove local variable check --- src/misc.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 3b093027f48..9954e358232 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -362,7 +362,6 @@ impl LateLintPass for UsedUnderscoreBinding { ident.name.as_str().chars().next() == Some('_') //starts with '_' && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" && ident.name != ident.unhygienic_name //not in macro - && cx.tcx.def_map.borrow().contains_key(&expr.id) //local variable }, ExprField(_, spanned) => { let name = spanned.node.as_str(); -- cgit 1.4.1-3-g733a5 From 98d21f9fc5f5dfb4391452b506d4a27ac1d452a4 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Fri, 18 Dec 2015 16:04:33 -0800 Subject: Make compatible with `unused_variables` lint --- src/misc.rs | 30 ++++++++++++++++----------- tests/compile-fail/for_loop.rs | 7 +++---- tests/compile-fail/used_underscore_binding.rs | 29 +++++++++++++++++--------- 3 files changed, 40 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 9954e358232..44d044a4384 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -10,7 +10,8 @@ use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use utils::{get_item_name, match_path, snippet, span_lint, walk_ptrs_ty, is_integer_literal}; +use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint, walk_ptrs_ty, + is_integer_literal}; use utils::span_help_and_lint; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. @@ -323,16 +324,7 @@ impl LateLintPass for PatternPass { /// **Why is this bad?** A single leading underscore is usually used to indicate that a binding /// will not be used. Using such a binding breaks this expectation. /// -/// **Known problems:** This lint's idea of a "used" variable is not quite the same as in the -/// built-in `unused_variables` lint. For example, in the following code -/// ``` -/// fn foo(y: u32) -> u32) { -/// let _x = 1; -/// _x +=1; -/// y -/// } -/// ``` -/// _x will trigger both the `unused_variables` lint and the `used_underscore_binding` lint. +/// **Known problems:** None /// /// **Example**: /// ``` @@ -362,6 +354,7 @@ impl LateLintPass for UsedUnderscoreBinding { ident.name.as_str().chars().next() == Some('_') //starts with '_' && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" && ident.name != ident.unhygienic_name //not in macro + && is_used(cx, expr) }, ExprField(_, spanned) => { let name = spanned.node.as_str(); @@ -372,8 +365,21 @@ impl LateLintPass for UsedUnderscoreBinding { }; if needs_lint { cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, - "used binding which is prefixed with an underscore. A leading underscore\ + "used binding which is prefixed with an underscore. A leading underscore \ signals that a binding will not be used."); } } } + +fn is_used(cx: &LateContext, expr: &Expr) -> bool { + if let Some(ref parent) = get_parent_expr(cx, expr) { + match parent.node { + ExprAssign(_, ref rhs) => **rhs == *expr, + ExprAssignOp(_, _, ref rhs) => **rhs == *expr, + _ => is_used(cx, &parent) + } + } + else { + true + } +} diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 59b77f6421b..f1c1adf6cc8 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -16,8 +16,7 @@ impl Unrelated { #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] -#[allow(linkedlist,shadow_unrelated,unnecessary_mut_passed, cyclomatic_complexity, - used_underscore_binding)] +#[allow(linkedlist,shadow_unrelated,unnecessary_mut_passed, cyclomatic_complexity)] fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; @@ -180,8 +179,8 @@ fn main() { if false { _index = 0 }; for _v in &vec { _index += 1 } - let mut _index = 0; - { let mut _x = &mut _index; } + let mut index = 0; + { let mut _x = &mut index; } for _v in &vec { _index += 1 } let mut index = 0; diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 0d822a29cee..e787124dce7 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -3,13 +3,13 @@ #![deny(clippy)] /// Test that we lint if we use a binding with a single leading underscore -fn prefix_underscore(_x: u32) -> u32 { - _x + 1 //~ ERROR used binding which is prefixed with an underscore +fn prefix_underscore(_foo: u32) -> u32 { + _foo + 1 //~ ERROR used binding which is prefixed with an underscore } /// Test that we lint even if the use is within a macro expansion -fn in_macro(_x: u32) { - println!("{}", _x); //~ ERROR used binding which is prefixed with an underscore +fn in_macro(_foo: u32) { + println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore } /// Test that we do not lint if the underscore is not a prefix @@ -17,14 +17,23 @@ fn non_prefix_underscore(some_foo: u32) -> u32 { some_foo + 1 } -/// Test that we do not lint if we do not use the binding -fn unused_underscore(_foo: u32) -> u32 { +/// Test that we do not lint if we do not use the binding (simple case) +fn unused_underscore_simple(_foo: u32) -> u32 { + 1 +} + +#[deny(unused_variables)] +/// Test that we do not lint if we do not use the binding (complex case). This checks for +/// compatibility with the built-in `unused_variables` lint. +fn unused_underscore_complex(mut _foo: u32) -> u32 { + _foo += 1; + _foo = 2; 1 } ///Test that we do not lint for multiple underscores -fn multiple_underscores(__x: u32) -> u32 { - __x + 1 +fn multiple_underscores(__foo: u32) -> u32 { + __foo + 1 } // Non-variable bindings with preceding underscore @@ -54,8 +63,8 @@ fn main() { in_macro(foo); // possible false positives let _ = non_prefix_underscore(foo); - let _ = unused_underscore(foo); + let _ = unused_underscore_simple(foo); + let _ = unused_underscore_complex(foo); let _ = multiple_underscores(foo); non_variables(); } - -- cgit 1.4.1-3-g733a5 From a65a7770b3e16fbe5e350c670d852c2696ce2907 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 19 Dec 2015 19:08:22 +0530 Subject: Rust upgrade to rustc 1.7.0-nightly (8ad12c3e2 2015-12-19) --- Cargo.toml | 2 +- src/consts.rs | 6 ++---- src/precedence.rs | 7 +++---- 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 832a6dff401..5306de9b8d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.30" +version = "0.0.31" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/consts.rs b/src/consts.rs index 791bf587bb5..f7069476546 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -20,10 +20,8 @@ use syntax::ast::Lit_; use syntax::ast::LitIntType::*; use syntax::ast::LitIntType; use syntax::ast::{UintTy, FloatTy, StrStyle}; -use syntax::ast::UintTy::*; use syntax::ast::FloatTy::*; use syntax::ast::Sign::{self, Plus, Minus}; -use syntax::ast_util; #[derive(PartialEq, Eq, Debug, Copy, Clone)] @@ -195,9 +193,9 @@ impl fmt::Display for Constant { let (sign, suffix) = match *ity { LitIntType::SignedIntLit(ref sity, ref sign) => (if let Sign::Minus = *sign { "-" } else { "" }, - ast_util::int_ty_to_string(*sity)), + sity.ty_to_string()), LitIntType::UnsignedIntLit(ref uity) => - ("", ast_util::uint_ty_to_string(*uity)), + ("", uity.ty_to_string()), LitIntType::UnsuffixedIntLit(ref sign) => (if let Sign::Minus = *sign { "-" } else { "" }, "".into()), diff --git a/src/precedence.rs b/src/precedence.rs index be5f44c823a..39a3e9e56c2 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use syntax::codemap::Spanned; use syntax::ast::*; -use syntax::ast_util::binop_to_string; use utils::{span_lint, snippet}; @@ -38,17 +37,17 @@ impl EarlyLintPass for Precedence { &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} ({})`", snippet(cx, left.span, ".."), - binop_to_string(op), snippet(cx, right.span, ".."))), + op.to_string(), snippet(cx, right.span, ".."))), (true, false) => span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} {}`", snippet(cx, left.span, ".."), - binop_to_string(op), snippet(cx, right.span, ".."))), + op.to_string(), snippet(cx, right.span, ".."))), (false, true) => span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `{} {} ({})`", snippet(cx, left.span, ".."), - binop_to_string(op), snippet(cx, right.span, ".."))), + op.to_string(), snippet(cx, right.span, ".."))), _ => (), } } -- cgit 1.4.1-3-g733a5 From 4a32445aa7fdc7d38fdfeb23e07536ff11c860bc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 20 Dec 2015 04:45:31 +0530 Subject: Add macro check to used_underscore --- Cargo.toml | 2 +- src/misc.rs | 8 +++++--- tests/compile-fail/used_underscore_binding.rs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 5306de9b8d0..5b1332b18f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.31" +version = "0.0.32" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/misc.rs b/src/misc.rs index 44d044a4384..3a17ff0f0cb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -10,9 +10,8 @@ use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint, walk_ptrs_ty, - is_integer_literal}; -use utils::span_help_and_lint; +use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; +use utils::{span_help_and_lint, in_external_macro, walk_ptrs_ty, is_integer_literal}; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. /// @@ -363,6 +362,9 @@ impl LateLintPass for UsedUnderscoreBinding { }, _ => false }; + if in_external_macro(cx, expr.span) { + return + } if needs_lint { cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, "used binding which is prefixed with an underscore. A leading underscore \ diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 39a33c96876..49e1aa99cc0 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -9,7 +9,7 @@ fn prefix_underscore(_foo: u32) -> u32 { /// Test that we lint even if the use is within a macro expansion fn in_macro(_foo: u32) { - println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore + println!("{}", _foo); // doesn't warn, nut should #507 } // Struct for testing use of fields prefixed with an underscore -- cgit 1.4.1-3-g733a5 From b190aa7debabc5b9d81b73b3f72701ece99d5ff0 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Mon, 21 Dec 2015 01:03:12 -0800 Subject: Implement #507 Make `used_underscore_binding` lint compatible with MacroAttributes expansions. TODO: Add a good test for this. --- src/misc.rs | 27 +++++++++++++++++++++------ tests/compile-fail/used_underscore_binding.rs | 11 ++++++++++- 2 files changed, 31 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 3a17ff0f0cb..139dfde3681 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -3,7 +3,7 @@ use syntax::ptr::P; use rustc_front::hir::*; use reexport::*; use rustc_front::util::{is_comparison_binop, binop_to_string}; -use syntax::codemap::{Span, Spanned}; +use syntax::codemap::{Span, Spanned, ExpnFormat}; use rustc_front::intravisit::FnKind; use rustc::middle::ty; use rustc::middle::const_eval::ConstVal::Float; @@ -11,7 +11,7 @@ use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; -use utils::{span_help_and_lint, in_external_macro, walk_ptrs_ty, is_integer_literal}; +use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal}; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. /// @@ -345,6 +345,9 @@ impl LintPass for UsedUnderscoreBinding { impl LateLintPass for UsedUnderscoreBinding { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_attributes_expansion(cx, expr) { // Don't lint things expanded by #[derive(...)], etc + return; + } let needs_lint = match expr.node { ExprPath(_, ref path) => { let ident = path.segments.last() @@ -352,7 +355,7 @@ impl LateLintPass for UsedUnderscoreBinding { .identifier; ident.name.as_str().chars().next() == Some('_') //starts with '_' && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" - && ident.name != ident.unhygienic_name //not in macro + && ident.name != ident.unhygienic_name //not in bang macro && is_used(cx, expr) }, ExprField(_, spanned) => { @@ -362,9 +365,6 @@ impl LateLintPass for UsedUnderscoreBinding { }, _ => false }; - if in_external_macro(cx, expr.span) { - return - } if needs_lint { cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, "used binding which is prefixed with an underscore. A leading underscore \ @@ -373,6 +373,8 @@ impl LateLintPass for UsedUnderscoreBinding { } } +/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea +/// of what it means for an expression to be "used". fn is_used(cx: &LateContext, expr: &Expr) -> bool { if let Some(ref parent) = get_parent_expr(cx, expr) { match parent.node { @@ -385,3 +387,16 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { true } } + +/// Test whether an expression is in a macro expansion (e.g. something generated by #[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| { + match info.callee.format { + ExpnFormat::MacroAttribute(_) => true, + _ => false, + } + }) + }) +} diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 49e1aa99cc0..fd1b3bfc162 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -9,7 +9,15 @@ fn prefix_underscore(_foo: u32) -> u32 { /// Test that we lint even if the use is within a macro expansion fn in_macro(_foo: u32) { - println!("{}", _foo); // doesn't warn, nut should #507 + println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore +} + +// TODO: This doesn't actually correctly test this. Need to find a #[derive(...)] which sets off +// the lint if the `in_attributes_expansion` test isn't there +/// Test that we do not lint for unused underscores in a MacroAttribute expansion +#[derive(Clone)] +struct MacroAttributesTest { + _foo: u32, } // Struct for testing use of fields prefixed with an underscore @@ -68,6 +76,7 @@ fn non_variables() { fn main() { let foo = 0u32; + let _ = MacroAttributesTest{_foo: 0}; // tests of unused_underscore lint let _ = prefix_underscore(foo); in_macro(foo); -- cgit 1.4.1-3-g733a5 From 3abdcd470901ef8cec81314558f11571c75911dd Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 21 Dec 2015 19:22:29 +0100 Subject: Implement #364 --- README.md | 3 ++- src/array_indexing.rs | 52 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ tests/compile-fail/array_indexing.rs | 12 +++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/array_indexing.rs create mode 100755 tests/compile-fail/array_indexing.rs (limited to 'src') diff --git a/README.md b/README.md index 015a7d9adf2..dc8fd37dfc9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 84 lints included in this crate: +There are 85 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -58,6 +58,7 @@ name [option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`) [option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [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 [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 diff --git a/src/array_indexing.rs b/src/array_indexing.rs new file mode 100644 index 00000000000..d72adac943f --- /dev/null +++ b/src/array_indexing.rs @@ -0,0 +1,52 @@ +use rustc::lint::*; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::ty::TyArray; +use rustc_front::hir::*; +use utils::span_lint; + +/// **What it does:** Check for out of bounds array indexing with a constant index. +/// +/// **Why is this bad?** This will always panic at runtime. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// let x = [1,2,3,4]; +/// ... +/// x[9]; +/// ``` +declare_lint! { + pub OUT_OF_BOUNDS_INDEXING, + Deny, + "out of bound constant indexing" +} + +#[derive(Copy,Clone)] +pub struct ArrayIndexing; + +impl LintPass for ArrayIndexing { + fn get_lints(&self) -> LintArray { + lint_array!(OUT_OF_BOUNDS_INDEXING) + } +} + +impl LateLintPass for ArrayIndexing { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprIndex(ref array, ref index) = e.node { + let ty = cx.tcx.expr_ty(array); + + if let TyArray(_, size) = ty.sty { + let index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); + if let Ok(ConstVal::Uint(index)) = index { + if size as u64 <= index { + span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, + "const index-expr is out of bounds"); + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 05181e69b2c..29b911a0cb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,7 @@ pub mod transmute; pub mod cyclomatic_complexity; pub mod escape; pub mod misc_early; +pub mod array_indexing; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -121,6 +122,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box escape::EscapePass); reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); + reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -143,6 +145,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, + array_indexing::OUT_OF_BOUNDS_INDEXING, attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs new file mode 100755 index 00000000000..68ab71da586 --- /dev/null +++ b/tests/compile-fail/array_indexing.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(out_of_bounds_indexing)] + +fn main() { + let x = [1,2,3,4]; + x[0]; + x[3]; + x[4]; //~ERROR: const index-expr is out of bounds + x[1 << 3]; //~ERROR: const index-expr is out of bounds +} -- cgit 1.4.1-3-g733a5 From 826827fe9422446ac6084a21f69542fe97626ea6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 21 Dec 2015 20:47:19 +0100 Subject: Fix some typos --- CONTRIBUTING.md | 2 +- src/bit_mask.rs | 2 +- src/needless_update.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5147595ab54..53caba6615c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ Also please document your lint with a doc comment akin to the following: /// **Example:** Insert a short example if you have one ``` -Our `util/update_wiki.py` script can then add your ilnt docs to the wiki. +Our `util/update_wiki.py` script can then add your lint docs to the wiki. ## Contributions diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 3d428aa0da7..f4310db0fcb 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -11,7 +11,7 @@ use utils::span_lint; /// **What it does:** This lint checks for incompatible bit masks in comparisons. It is `Warn` by default. /// /// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` -/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: +/// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: /// /// |Comparison |Bit-Op|Example |is always|Formula | /// |------------|------|------------|---------|----------------------| diff --git a/src/needless_update.rs b/src/needless_update.rs index e1e0f481848..9a314616cdc 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -10,7 +10,7 @@ use utils::span_lint; /// /// **Known problems:** None. /// -/// **Example:** `Point { x: 1, y: 0, ..zero_point }`` +/// **Example:** `Point { x: 1, y: 0, ..zero_point }` declare_lint! { pub NEEDLESS_UPDATE, Warn, -- cgit 1.4.1-3-g733a5 From acc47a3bd5aa474bbf970d3e5a9e50522408a32b Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer <markus@unterwaditzer.net> Date: Tue, 22 Dec 2015 00:22:35 +0100 Subject: Nightly fixes As of https://github.com/rust-lang/rust/commit/e3da2a90033d233bf6d77e3c725880c12cfc8728#diff-12e06f1e9ca371a11bdc4615f50a4071L59 HirVec is syntax::ptr::P instead of Vec. --- src/map_clone.rs | 2 +- src/methods.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/map_clone.rs b/src/map_clone.rs index f5e8d20a745..b1ba47a9b54 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -82,7 +82,7 @@ fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { match expr.node { ExprPath(None, ref path) => { let arg_segment = [PathSegment { identifier: id, parameters: PathParameters::none() }]; - !path.global && path.segments == arg_segment + !path.global && path.segments[..] == arg_segment } _ => false, } diff --git a/src/methods.rs b/src/methods.rs index ef7a58959ac..35207cb746c 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -435,9 +435,9 @@ impl OutType { fn matches(&self, ty: &FunctionRetTy) -> bool { match (self, ty) { (&UnitType, &DefaultReturn(_)) => true, - (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![]) => true, + (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![].into()) => true, (&BoolType, &Return(ref ty)) if is_bool(ty) => true, - (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![]) => true, + (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, (&RefType, &Return(ref ty)) => { if let TyRptr(_, _) = ty.node { true } else { false } } -- cgit 1.4.1-3-g733a5 From 0e4259a827787b5e9f50e2b5e78dbdff510b8e2a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 22 Dec 2015 00:48:50 +0100 Subject: Remove duplicated if_let_chain! macro definition --- src/utils.rs | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 5e1671b709c..92b1cb1cd3a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -370,52 +370,6 @@ pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() } -/// Produce a nested chain of if-lets and ifs from the patterns: -/// -/// if_let_chain! { -/// [ -/// Some(y) = x, -/// y.len() == 2, -/// Some(z) = y, -/// ], -/// { -/// block -/// } -/// } -/// -/// becomes -/// -/// 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) => { - if let $pat = $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([let $pat:pat = $expr:expr], $block:block) => { - if let $pat = $expr { - $block - } - }; - ([$expr:expr, $($tt:tt)+], $block:block) => { - if $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([$expr:expr], $block:block) => { - if $expr { - $block - } - }; -} - pub struct LimitStack { stack: Vec<u64>, } -- cgit 1.4.1-3-g733a5 From e4fbeb49470818d6528ea9a36f245bd9d80b3297 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 23 Dec 2015 02:12:08 +0100 Subject: Don't trigger block_in_if_condition_expr lint if the block is unsafe --- src/block_in_if_condition.rs | 30 +++++++++++++++-------------- tests/compile-fail/block_in_if_condition.rs | 9 +++++++++ 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index b4e81ac6a2b..f7c181f5fd8 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -74,23 +74,25 @@ impl LateLintPass for BlockInIfCondition { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprIf(ref check, ref then, _) = expr.node { if let ExprBlock(ref block) = check.node { - if block.stmts.is_empty() { - if let Some(ref ex) = block.expr { - // don't dig into the expression here, just suggest that they remove - // the block + if block.rules == DefaultBlock { + if block.stmts.is_empty() { + if let Some(ref ex) = block.expr { + // don't dig into the expression here, just suggest that they remove + // the block - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_EXPR, check.span, - BRACED_EXPR_MESSAGE, - &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_EXPR, check.span, + BRACED_EXPR_MESSAGE, + &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, ".."))); + } + } else { + // move block higher + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, check.span, + COMPLEX_BLOCK_MESSAGE, + &format!("try\nlet res = {};\nif res {} ... ", + snippet_block(cx, block.span, ".."), snippet_block(cx, then.span, ".."))); } - } else { - // move block higher - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, check.span, - COMPLEX_BLOCK_MESSAGE, - &format!("try\nlet res = {};\nif res {} ... ", - snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, ".."))); } } else { let mut visitor = ExVisitor { found_block: None }; diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index c075d48297e..cd95fbd202c 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -60,5 +60,14 @@ fn closure_without_block() { } } +fn condition_is_unsafe_block() { + let a: i32 = 1; + + // this should not warn because the condition is an unsafe block + if unsafe { 1u32 == std::mem::transmute(a) } { + println!("1u32 == a"); + } +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 7216e83189e2458fd5d3a311f9d1a487cfee51d9 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 01:14:10 +0100 Subject: Implement #471 --- src/lib.rs | 1 + src/matches.rs | 184 +++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/matches.rs | 31 ++++++- 3 files changed, 210 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 29b911a0cb2..2e05fd1fc43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -172,6 +172,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::WHILE_LET_ON_ITERATOR, map_clone::MAP_CLONE, matches::MATCH_BOOL, + matches::MATCH_OVERLAPPING_ARM, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::OK_EXPECT, diff --git a/src/matches.rs b/src/matches.rs index 460893d93ab..69a6fdf6016 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,10 +1,14 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::middle::const_eval::ConstVal::{Int, Uint}; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::ty; +use rustc_front::hir::*; +use std::cmp::Ordering; use syntax::ast::Lit_::LitBool; use syntax::codemap::Span; -use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block}; +use utils::{snippet, span_lint, span_note_and_lint, span_help_and_lint, in_external_macro, expr_block}; /// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. It is `Warn` by default. /// @@ -22,6 +26,7 @@ use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_bloc declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ is `_ => {}`) is used; recommends `if let` instead"); + /// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It is `Warn` by default. /// /// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. @@ -40,6 +45,7 @@ declare_lint!(pub SINGLE_MATCH, Warn, declare_lint!(pub MATCH_REF_PATS, Warn, "a match has all arms prefixed with `&`; the match expression can be \ dereferenced instead"); + /// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. It is `Warn` by default. /// /// **Why is this bad?** It makes the code less readable. @@ -58,6 +64,25 @@ declare_lint!(pub MATCH_REF_PATS, Warn, declare_lint!(pub MATCH_BOOL, Warn, "a match on boolean expression; recommends `if..else` block instead"); +/// **What it does:** This lint checks for overlapping match arms. It is `Warn` by default. +/// +/// **Why is this bad?** It is likely to be an error and if not, makes the code less obvious. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let x = 5; +/// match x { +/// 1 ... 10 => println!("1 ... 10"), +/// 5 ... 15 => println!("5 ... 15"), +/// _ => (), +/// } +/// ``` +declare_lint!(pub MATCH_OVERLAPPING_ARM, Warn, + "overlapping match arms"); + #[allow(missing_copy_implementations)] pub struct MatchPass; @@ -150,6 +175,22 @@ impl LateLintPass for MatchPass { Consider using an if..else block"); } } + + // MATCH_OVERLAPPING_ARM + if arms.len() >= 2 { + let ranges = all_ranges(cx, arms); + let overlap = match type_ranges(&ranges) { + TypedRanges::IntRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::UintRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::None => None, + }; + + if let Some((start, end)) = overlap { + span_note_and_lint(cx, MATCH_OVERLAPPING_ARM, start, + "some ranges overlap", + end, "overlaps with this"); + } + } } if let ExprMatch(ref ex, ref arms, source) = expr.node { // check preconditions for MATCH_REF_PATS @@ -170,6 +211,77 @@ impl LateLintPass for MatchPass { } } +/// Get all arms that are unbounded PatRange-s. +fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { + arms.iter() + .filter_map(|arm| { + if let Arm { ref pats, guard: None, .. } = *arm { + Some(pats.iter().filter_map(|pat| { + if_let_chain! {[ + let PatRange(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) + ], { + return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); + }} + + None + })) + } + else { + None + } + }) + .flat_map(IntoIterator::into_iter) + .collect() +} + +#[derive(Debug, Eq, PartialEq)] +struct SpannedRange<T> { + span: Span, + node: (T, T), +} + +#[derive(Debug)] +enum TypedRanges { + IntRanges(Vec<SpannedRange<i64>>), + UintRanges(Vec<SpannedRange<u64>>), + None, +} + +/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than +/// `Uint` and `Int` probably don't make sense. +fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { + if ranges.is_empty() { + TypedRanges::None + } + else { + match ranges[0].node { + (Int(_), Int(_)) => { + TypedRanges::IntRanges(ranges.iter().filter_map(|range| { + if let (Int(start), Int(end)) = range.node { + Some(SpannedRange { span: range.span, node: (start, end) }) + } + else { + None + } + }).collect()) + }, + (Uint(_), Uint(_)) => { + TypedRanges::UintRanges(ranges.iter().filter_map(|range| { + if let (Uint(start), Uint(end)) = range.node { + Some(SpannedRange { span: range.span, node: (start, end) }) + } + else { + None + } + }).collect()) + }, + _ => TypedRanges::None, + } + } +} + fn is_unit_expr(expr: &Expr) -> bool { match expr.node { ExprTup(ref v) if v.is_empty() => true, @@ -209,3 +321,71 @@ fn match_template(cx: &LateContext, } } } + +fn overlaping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> + where T: Copy + Ord { + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + enum Kind<'a, T: 'a> { + Start(T, &'a SpannedRange<T>), + End(T, &'a SpannedRange<T>), + } + + impl<'a, T: Copy> Kind<'a, T> { + fn range(&self) -> &'a SpannedRange<T> { + match *self { + Kind::Start(_, r) | Kind::End(_, r) => r + } + } + + fn value(self) -> T { + match self { + Kind::Start(t, _) | Kind::End(t, _) => t + } + } + } + + impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } + } + + impl<'a, T: Copy + Ord> Ord for Kind<'a, T> { + fn cmp(&self, other: &Self) -> Ordering { + self.value().cmp(&other.value()) + } + } + + let mut values = Vec::with_capacity(2*ranges.len()); + + for r in ranges { + values.push(Kind::Start(r.node.0, &r)); + values.push(Kind::End(r.node.1, &r)); + } + + values.sort(); + + for (a, b) in values.iter().zip(values.iter().skip(1)) { + match (a, b) { + (&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node { return Some((ra, rb)) }, + (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), + _ => return Some((&a.range(), &b.range())), + } + } + + None +} + +#[test] +fn test_overlapping() { + use syntax::codemap::DUMMY_SP; + + let sp = |s, e| SpannedRange { span: DUMMY_SP, node: (s, e) }; + + assert_eq!(None, overlaping::<u8>(&[])); + assert_eq!(None, overlaping(&[sp(1, 4)])); + assert_eq!(None, overlaping(&[sp(1, 4), sp(5, 6)])); + assert_eq!(None, overlaping(&[sp(1, 4), sp(5, 6), sp(10, 11)])); + assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlaping(&[sp(1, 4), sp(3, 6)])); + assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlaping(&[sp(1, 4), sp(5, 6), sp(6, 11)])); +} diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index ea3a48a94f5..ab181901c9c 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -51,17 +51,17 @@ fn match_bool() { true => 1, false => 0, }; - + match test { //~ ERROR you seem to be trying to match on a boolean expression true => (), false => { println!("Noooo!"); } }; - + match test { //~ ERROR you seem to be trying to match on a boolean expression false => { println!("Noooo!"); } _ => (), }; - + match test { //~ ERROR you seem to be trying to match on a boolean expression false => { println!("Noooo!"); } true => { println!("Yes!"); } @@ -70,7 +70,7 @@ fn match_bool() { // Not linted match option { 1 ... 10 => (), - 10 ... 20 => (), + 11 ... 20 => (), _ => (), }; } @@ -115,5 +115,28 @@ fn ref_pats() { } } +fn overlapping() { + const FOO : u64 = 2; + + match 42 { + 0 ... 10 => println!("0 ... 10"), //~ERROR + 0 ... 11 => println!("0 ... 10"), + _ => (), + } + + match 42 { + 0 ... 5 => println!("0 ... 10"), //~ERROR + 6 ... 7 => println!("6 ... 7"), + FOO ... 11 => println!("0 ... 10"), + _ => (), + } + + match 42 { + 0 ... 10 => println!("0 ... 10"), + 11 ... 50 => println!("0 ... 10"), + _ => (), + } +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 3373ea43c0ba0f226bc0a5e9bd578118fa564547 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 02:06:18 +0100 Subject: Consider literal patterns in MATCH_OVERLAPPING_ARM --- src/matches.rs | 7 +++++++ tests/compile-fail/matches.rs | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 69a6fdf6016..227a5bdb2df 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -225,6 +225,13 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); }} + if_let_chain! {[ + let PatLit(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 })) } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index ab181901c9c..94d24746e4d 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -125,12 +125,18 @@ fn overlapping() { } match 42 { - 0 ... 5 => println!("0 ... 10"), //~ERROR + 0 ... 5 => println!("0 ... 5"), //~ERROR 6 ... 7 => println!("6 ... 7"), FOO ... 11 => println!("0 ... 10"), _ => (), } + match 42 { + 2 => println!("2"), + 0 ... 5 => println!("0 ... 5"), //~ERROR + _ => (), + } + match 42 { 0 ... 10 => println!("0 ... 10"), 11 ... 50 => println!("0 ... 10"), -- cgit 1.4.1-3-g733a5 From 0c8de9ed52ddc14e3797f89ab260a4e45be62418 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 02:19:32 +0100 Subject: Split MatchPass::check_expr for dogfood --- src/matches.rs | 211 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 110 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 227a5bdb2df..78b39ac1791 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -96,117 +96,126 @@ impl LateLintPass for MatchPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { - // check preconditions for SINGLE_MATCH - // only two arms - if arms.len() == 2 && - // both of the arms have a single pattern and no guard - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() && - // and the second pattern is a `_` wildcard: this is not strictly necessary, - // since the exhaustiveness check will ensure the last one is a catch-all, - // but in some cases, an explicit match is preferred to catch situations - // when an enum is extended, so we don't consider these cases - arms[1].pats[0].node == PatWild && - // we don't want any content in the second arm (unit or empty block) - is_unit_expr(&arms[1].body) && - // finally, MATCH_BOOL doesn't apply here - (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) - { - span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for destructuring a \ - single pattern. Consider using `if let`", - &format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."))); - } + check_single_match(cx, ex, arms, expr); + check_match_bool(cx, ex, arms, expr); + check_overlapping_arms(cx, arms); + } + if let ExprMatch(ref ex, ref arms, source) = expr.node { + check_match_ref_pats(cx, ex, arms, source, expr); + } + } +} - // check preconditions for MATCH_BOOL - // type of expression == bool - if cx.tcx.expr_ty(ex).sty == ty::TyBool { - if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards - let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { - if let ExprLit(ref lit) = arm_bool.node { - match lit.node { - LitBool(true) => Some((&*arms[0].body, &*arms[1].body)), - LitBool(false) => Some((&*arms[1].body, &*arms[0].body)), - _ => None, - } - } else { None } - } else { None }; - if let Some((ref true_expr, ref false_expr)) = exprs { - if !is_unit_expr(true_expr) { - if !is_unit_expr(false_expr) { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."), - expr_block(cx, false_expr, None, ".."))); - } else { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."))); - } - } else if !is_unit_expr(false_expr) { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif !{} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))); - } else { - span_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); - } +fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { + if arms.len() == 2 && + // both of the arms have a single pattern and no guard + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + // and the second pattern is a `_` wildcard: this is not strictly necessary, + // since the exhaustiveness check will ensure the last one is a catch-all, + // but in some cases, an explicit match is preferred to catch situations + // when an enum is extended, so we don't consider these cases + arms[1].pats[0].node == PatWild && + // we don't want any content in the second arm (unit or empty block) + is_unit_expr(&arms[1].body) && + // finally, MATCH_BOOL doesn't apply here + (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) + { + span_help_and_lint(cx, SINGLE_MATCH, expr.span, + "you seem to be trying to use match for destructuring a \ + single pattern. Consider using `if let`", + &format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."))); + } +} + +fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { + // type of expression == bool + if cx.tcx.expr_ty(ex).sty == ty::TyBool { + if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards + let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { + if let ExprLit(ref lit) = arm_bool.node { + match lit.node { + LitBool(true) => Some((&*arms[0].body, &*arms[1].body)), + LitBool(false) => Some((&*arms[1].body, &*arms[0].body)), + _ => None, + } + } else { None } + } else { None }; + if let Some((ref true_expr, ref false_expr)) = exprs { + if !is_unit_expr(true_expr) { + if !is_unit_expr(false_expr) { + span_help_and_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block:", + &format!("try\nif {} {} else {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."), + expr_block(cx, false_expr, None, ".."))); } else { - span_lint(cx, MATCH_BOOL, expr.span, + span_help_and_lint(cx, MATCH_BOOL, expr.span, "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); + Consider using an if..else block:", + &format!("try\nif {} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."))); } + } else if !is_unit_expr(false_expr) { + span_help_and_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block:", + &format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))); } else { span_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block"); } + } else { + span_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block"); } + } else { + span_lint(cx, MATCH_BOOL, expr.span, + "you seem to be trying to match on a boolean expression. \ + Consider using an if..else block"); + } + } +} - // MATCH_OVERLAPPING_ARM - if arms.len() >= 2 { - let ranges = all_ranges(cx, arms); - let overlap = match type_ranges(&ranges) { - TypedRanges::IntRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), - TypedRanges::UintRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), - TypedRanges::None => None, - }; - - if let Some((start, end)) = overlap { - span_note_and_lint(cx, MATCH_OVERLAPPING_ARM, start, - "some ranges overlap", - end, "overlaps with this"); - } - } +fn check_overlapping_arms(cx: &LateContext, arms: &[Arm]) { + if arms.len() >= 2 { + let ranges = all_ranges(cx, arms); + let overlap = match type_ranges(&ranges) { + TypedRanges::IntRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::UintRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::None => None, + }; + + if let Some((start, end)) = overlap { + span_note_and_lint(cx, MATCH_OVERLAPPING_ARM, start, + "some ranges overlap", + end, "overlaps with this"); } - if let ExprMatch(ref ex, ref arms, source) = expr.node { - // check preconditions for MATCH_REF_PATS - if has_only_ref_pats(arms) { - if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { - let template = match_template(cx, expr.span, source, "", inner); - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "you don't need to add `&` to both the expression \ - and the patterns: use `{}`", template)); - } else { - let template = match_template(cx, expr.span, source, "*", ex); - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "instead of prefixing all patterns with `&`, you can dereference the \ - expression: `{}`", template)); - } - } + } +} + +fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) { + if has_only_ref_pats(arms) { + if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { + let template = match_template(cx, expr.span, source, "", inner); + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "you don't need to add `&` to both the expression \ + and the patterns: use `{}`", template)); + } else { + let template = match_template(cx, expr.span, source, "*", ex); + span_lint(cx, MATCH_REF_PATS, expr.span, &format!( + "instead of prefixing all patterns with `&`, you can dereference the \ + expression: `{}`", template)); } } } -- cgit 1.4.1-3-g733a5 From 1aa3956b8a84de9e2e81e9f10ad1f72a0a935918 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 02:41:20 +0100 Subject: Update README --- README.md | 3 ++- src/matches.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index dc8fd37dfc9..6d1b88688c1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 85 lints included in this crate: +There are 86 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -40,6 +40,7 @@ name [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead +[match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 diff --git a/src/matches.rs b/src/matches.rs index 78b39ac1791..1cdf76db663 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -81,7 +81,7 @@ declare_lint!(pub MATCH_BOOL, Warn, /// } /// ``` declare_lint!(pub MATCH_OVERLAPPING_ARM, Warn, - "overlapping match arms"); + "a match has overlapping arms"); #[allow(missing_copy_implementations)] pub struct MatchPass; -- cgit 1.4.1-3-g733a5 From 90efb7b76d401995eb054799dc55058aa66887c7 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 11:25:32 +0100 Subject: Fix typo --- src/matches.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 1cdf76db663..3ece02c0374 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -191,8 +191,8 @@ fn check_overlapping_arms(cx: &LateContext, arms: &[Arm]) { if arms.len() >= 2 { let ranges = all_ranges(cx, arms); let overlap = match type_ranges(&ranges) { - TypedRanges::IntRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), - TypedRanges::UintRanges(ranges) => overlaping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), + TypedRanges::UintRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), TypedRanges::None => None, }; @@ -338,7 +338,7 @@ fn match_template(cx: &LateContext, } } -fn overlaping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> +fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> where T: Copy + Ord { #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Kind<'a, T: 'a> { @@ -398,10 +398,10 @@ fn test_overlapping() { let sp = |s, e| SpannedRange { span: DUMMY_SP, node: (s, e) }; - assert_eq!(None, overlaping::<u8>(&[])); - assert_eq!(None, overlaping(&[sp(1, 4)])); - assert_eq!(None, overlaping(&[sp(1, 4), sp(5, 6)])); - assert_eq!(None, overlaping(&[sp(1, 4), sp(5, 6), sp(10, 11)])); - assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlaping(&[sp(1, 4), sp(3, 6)])); - assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlaping(&[sp(1, 4), sp(5, 6), sp(6, 11)])); + assert_eq!(None, overlapping::<u8>(&[])); + assert_eq!(None, overlapping(&[sp(1, 4)])); + assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6)])); + assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6), sp(10, 11)])); + assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlapping(&[sp(1, 4), sp(3, 6)])); + assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlapping(&[sp(1, 4), sp(5, 6), sp(6, 11)])); } -- cgit 1.4.1-3-g733a5 From 2fd3093395d989bb8ada55440fb4101264e676e5 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 11:25:44 +0100 Subject: Only run MATCH_OVERLAPPING_ARM on integral matches --- src/matches.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 3ece02c0374..053b6b072b5 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -98,7 +98,7 @@ impl LateLintPass for MatchPass { if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { check_single_match(cx, ex, arms, expr); check_match_bool(cx, ex, arms, expr); - check_overlapping_arms(cx, arms); + check_overlapping_arms(cx, ex, arms); } if let ExprMatch(ref ex, ref arms, source) = expr.node { check_match_ref_pats(cx, ex, arms, source, expr); @@ -187,8 +187,9 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } } -fn check_overlapping_arms(cx: &LateContext, arms: &[Arm]) { - if arms.len() >= 2 { +fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { + if arms.len() >= 2 && + cx.tcx.expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms); let overlap = match type_ranges(&ranges) { TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), -- cgit 1.4.1-3-g733a5 From 0fa8481ba390dc9b860123950717acbb34bd39fd Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 17:48:30 +0100 Subject: Put tests in tests folder --- src/matches.rs | 22 ++++------------------ tests/matches.rs | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 tests/matches.rs (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 053b6b072b5..e4172b40932 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -254,9 +254,9 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { } #[derive(Debug, Eq, PartialEq)] -struct SpannedRange<T> { - span: Span, - node: (T, T), +pub struct SpannedRange<T> { + pub span: Span, + pub node: (T, T), } #[derive(Debug)] @@ -339,7 +339,7 @@ fn match_template(cx: &LateContext, } } -fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> +pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> where T: Copy + Ord { #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Kind<'a, T: 'a> { @@ -392,17 +392,3 @@ fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &Span None } - -#[test] -fn test_overlapping() { - use syntax::codemap::DUMMY_SP; - - let sp = |s, e| SpannedRange { span: DUMMY_SP, node: (s, e) }; - - assert_eq!(None, overlapping::<u8>(&[])); - assert_eq!(None, overlapping(&[sp(1, 4)])); - assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6)])); - assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6), sp(10, 11)])); - assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlapping(&[sp(1, 4), sp(3, 6)])); - assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlapping(&[sp(1, 4), sp(5, 6), sp(6, 11)])); -} diff --git a/tests/matches.rs b/tests/matches.rs new file mode 100644 index 00000000000..03cc5281741 --- /dev/null +++ b/tests/matches.rs @@ -0,0 +1,20 @@ +#![allow(plugin_as_library)] +#![feature(rustc_private)] + +extern crate clippy; +extern crate syntax; + +#[test] +fn test_overlapping() { + use clippy::matches::overlapping; + use syntax::codemap::DUMMY_SP; + + let sp = |s, e| clippy::matches::SpannedRange { span: DUMMY_SP, node: (s, e) }; + + assert_eq!(None, overlapping::<u8>(&[])); + assert_eq!(None, overlapping(&[sp(1, 4)])); + assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6)])); + assert_eq!(None, overlapping(&[sp(1, 4), sp(5, 6), sp(10, 11)])); + assert_eq!(Some((&sp(1, 4), &sp(3, 6))), overlapping(&[sp(1, 4), sp(3, 6)])); + assert_eq!(Some((&sp(5, 6), &sp(6, 11))), overlapping(&[sp(1, 4), sp(5, 6), sp(6, 11)])); +} -- cgit 1.4.1-3-g733a5 From 4958878ad219d570388a1866d13761e35122cc0a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 22:36:37 +0100 Subject: Fix missing parameter in `panic!` --- src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index f7069476546..9d3a9e7d7c2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -75,7 +75,7 @@ impl Constant { if let ConstantInt(val, _) = *self { val // TODO we may want to check the sign if any } else { - panic!("Could not convert a {:?} to u64"); + panic!("Could not convert a {:?} to u64", self); } } -- cgit 1.4.1-3-g733a5 From 592ca26e902bfa9ed3648db4ef0eeb53a5d598fe Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 23 Dec 2015 22:37:52 +0100 Subject: Fix #518 --- README.md | 3 ++- src/attrs.rs | 4 ++-- src/lib.rs | 3 +++ src/panic.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/utils.rs | 1 + tests/compile-fail/panic.rs | 22 ++++++++++++++++++++++ 6 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/panic.rs create mode 100644 tests/compile-fail/panic.rs (limited to 'src') diff --git a/README.md b/README.md index dc8fd37dfc9..2c8b20f83a9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 85 lints included in this crate: +There are 86 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -59,6 +59,7 @@ name [option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing +[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [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 [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 diff --git a/src/attrs.rs b/src/attrs.rs index 10db4a551f9..0882f3af41f 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use reexport::*; use syntax::codemap::Span; use syntax::attr::*; use syntax::ast::{Attribute, MetaList, MetaWord}; -use utils::{in_macro, match_path, span_lint}; +use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// **What it does:** This lint warns on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. /// @@ -94,7 +94,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &["std", "rt", "begin_unwind"]) + !match_path(path, &BEGIN_UNWIND) } else { true } } _ => true diff --git a/src/lib.rs b/src/lib.rs index 29b911a0cb2..adc1d402e92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ pub mod cyclomatic_complexity; pub mod escape; pub mod misc_early; pub mod array_indexing; +pub mod panic; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -123,6 +124,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); reg.register_late_lint_pass(box array_indexing::ArrayIndexing); + reg.register_late_lint_pass(box panic::PanicPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -198,6 +200,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, + panic::PANIC_PARAMS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/panic.rs b/src/panic.rs new file mode 100644 index 00000000000..6f713804e8c --- /dev/null +++ b/src/panic.rs @@ -0,0 +1,42 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::ast::Lit_::LitStr; + +use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; + +/// **What it does:** Warn about missing parameters in `panic!`. +/// +/// **Known problems:** Should you want to use curly brackets in `panic!` without any parameter, +/// this lint will warn. +/// +/// **Example:** +/// ``` +/// panic!("This panic! is probably missing a parameter there: {}"); +/// ``` +declare_lint!(pub PANIC_PARAMS, Warn, "missing parameters in `panic!`"); + +#[allow(missing_copy_implementations)] +pub struct PanicPass; + +impl LintPass for PanicPass { + fn get_lints(&self) -> LintArray { + lint_array!(PANIC_PARAMS) + } +} + +impl LateLintPass for PanicPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! {[ + in_external_macro(cx, expr.span), + let ExprCall(ref fun, ref params) = expr.node, + params.len() == 2, + let ExprPath(None, ref path) = fun.node, + match_path(path, &BEGIN_UNWIND), + let ExprLit(ref lit) = params[0].node, + let LitStr(ref string, _) = lit.node, + string.contains('{') + ], { + span_lint(cx, PANIC_PARAMS, expr.span, "You probably are missing some parameter in your `panic!` call"); + }} + } +} diff --git a/src/utils.rs b/src/utils.rs index 92b1cb1cd3a..1ce97ccea4e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -21,6 +21,7 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const BEGIN_UNWIND:[&'static str; 3] = ["std", "rt", "begin_unwind"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs new file mode 100644 index 00000000000..36427f4330b --- /dev/null +++ b/tests/compile-fail/panic.rs @@ -0,0 +1,22 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(panic_params)] + +fn missing() { + panic!("{}"); //~ERROR: You probably are missing some parameter +} + +fn ok_sigle() { + panic!("foo bar"); +} + +fn ok_multiple() { + panic!("{}", "This is {ok}"); +} + +fn main() { + missing(); + ok_sigle(); + ok_multiple(); +} -- cgit 1.4.1-3-g733a5 From dbf1cdf34aa89cdaba1bb9993e6aed221dfceb90 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 24 Dec 2015 15:27:31 +0530 Subject: Fix panic lint --- src/panic.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/panic.rs b/src/panic.rs index 6f713804e8c..40d6e7d4dff 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -28,15 +28,22 @@ impl LateLintPass for PanicPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain! {[ in_external_macro(cx, expr.span), - let ExprCall(ref fun, ref params) = expr.node, + 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, ref path) = fun.node, match_path(path, &BEGIN_UNWIND), let ExprLit(ref lit) = params[0].node, let LitStr(ref string, _) = lit.node, - string.contains('{') + string.contains('{'), + let Some(sp) = cx.sess().codemap() + .with_expn_info(expr.span.expn_id, + |info| info.map(|i| i.call_site)) ], { - span_lint(cx, PANIC_PARAMS, expr.span, "You probably are missing some parameter in your `panic!` call"); + + span_lint(cx, PANIC_PARAMS, sp, + "You probably are missing some parameter in your `panic!` call"); }} } } -- cgit 1.4.1-3-g733a5 From f1aac931bdb687c12b77980e52458ae921f90f21 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sun, 27 Dec 2015 01:22:53 -0800 Subject: Refactor `check_expr()` impl for `MethodsPass` --- src/methods.rs | 269 +++++++++++++++++++++++++++++++++++---------------------- src/utils.rs | 22 +++++ 2 files changed, 188 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 35207cb746c..31e3bfb8f4a 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -5,8 +5,8 @@ use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; -use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, walk_ptrs_ty_depth, - walk_ptrs_ty}; +use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, match_method_chain, + walk_ptrs_ty_depth, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; use self::SelfKind::*; @@ -157,107 +157,21 @@ impl LintPass for MethodsPass { impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - - if let ExprMethodCall(ref name, _, ref args) = expr.node { - let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - match &*name.node.as_str() { - "unwrap" if match_type(cx, obj_ty, &OPTION_PATH) => { - span_lint(cx, OPTION_UNWRAP_USED, expr.span, - "used unwrap() on an Option value. If you don't want \ - to handle the None case gracefully, consider using \ - expect() to provide a better panic message"); - }, - "unwrap" if match_type(cx, obj_ty, &RESULT_PATH) => { - span_lint(cx, RESULT_UNWRAP_USED, expr.span, - "used unwrap() on a Result value. Graceful handling \ - of Err values is preferred"); - }, - "to_string" if obj_ty.sty == ty::TyStr => { - let mut arg_str = snippet(cx, args[0].span, "_"); - if ptr_depth > 1 { - arg_str = Cow::Owned(format!( - "({}{})", - iter::repeat('*').take(ptr_depth - 1).collect::<String>(), - arg_str)); - } - span_lint(cx, STR_TO_STRING, expr.span, &format!( - "`{}.to_owned()` is faster", arg_str)); - }, - "to_string" if match_type(cx, obj_ty, &STRING_PATH) => { - span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \ - `clone()` to make a copy"); - }, - "expect" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { - if inner_name.node.as_str() == "ok" - && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &RESULT_PATH) { - let result_type = cx.tcx.expr_ty(&inner_args[0]); - if let Some(error_type) = get_error_type(cx, result_type) { - if has_debug_impl(error_type, cx) { - span_lint(cx, OK_EXPECT, expr.span, - "called `ok().expect()` on a Result \ - value. You can call `expect` directly \ - on the `Result`"); - } - } - } - }, - // check Option.map(_).unwrap_or(_) - "unwrap_or" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { - if inner_name.node.as_str() == "map" - && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { - // lint message - let msg = - "called `map(f).unwrap_or(a)` on an Option value. This can be done \ - more directly by calling `map_or(a, f)` instead"; - // get args to map() and unwrap_or() - let map_arg = snippet(cx, inner_args[1].span, ".."); - let unwrap_arg = snippet(cx, args[1].span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or() have the same span - let multiline = map_arg.lines().count() > 1 - || unwrap_arg.lines().count() > 1; - let same_span = inner_args[1].span.expn_id == args[1].span.expn_id; - if same_span && !multiline { - span_note_and_lint( - cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, - &format!("replace this with map_or({1}, {0})", - map_arg, unwrap_arg) - ); - } - else if same_span && multiline { - span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); - }; - } - }, - // check Option.map(_).unwrap_or_else(_) - "unwrap_or_else" => if let ExprMethodCall(ref inner_name, _, ref inner_args) = args[0].node { - if inner_name.node.as_str() == "map" - && match_type(cx, cx.tcx.expr_ty(&inner_args[0]), &OPTION_PATH) { - // lint message - let msg = - "called `map(f).unwrap_or_else(g)` on an Option value. This can be \ - done more directly by calling `map_or_else(g, f)` instead"; - // get args to map() and unwrap_or_else() - let map_arg = snippet(cx, inner_args[1].span, ".."); - let unwrap_arg = snippet(cx, args[1].span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or_else() have the same span - let multiline = map_arg.lines().count() > 1 - || unwrap_arg.lines().count() > 1; - let same_span = inner_args[1].span.expn_id == args[1].span.expn_id; - if same_span && !multiline { - span_note_and_lint( - cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg, expr.span, - &format!("replace this with map_or_else({1}, {0})", - map_arg, unwrap_arg) - ); - } - else if same_span && multiline { - span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); - }; - } - }, - _ => {}, + if let ExprMethodCall(_, _, _) = expr.node { + if match_method_chain(expr, &["unwrap"]) { + lint_unwrap(cx, expr); + } + else if match_method_chain(expr, &["to_string"]) { + lint_to_string(cx, expr); + } + else if match_method_chain(expr, &["ok", "expect"]) { + lint_ok_expect(cx, expr); + } + else if match_method_chain(expr, &["map", "unwrap_or"]) { + lint_map_unwrap_or(cx, expr); + } + else if match_method_chain(expr, &["map", "unwrap_or_else"]) { + lint_map_unwrap_or_else(cx, expr); } } } @@ -304,6 +218,155 @@ impl LateLintPass for MethodsPass { } } +/// lint use of `unwrap()` for `Option`s and `Result`s +fn lint_unwrap(cx: &LateContext, expr: &Expr) { + let args = match expr.node { + ExprMethodCall(_, _, ref args) => args, + _ => panic!("clippy methods.rs: should not have called `lint_unwrap()` on a non-matching \ + expression!"), + }; + + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); + + if match_type(cx, obj_ty, &OPTION_PATH) { + span_lint(cx, OPTION_UNWRAP_USED, expr.span, + "used unwrap() on an Option value. If you don't want to handle the None case \ + gracefully, consider using expect() to provide a better panic message"); + } + else if match_type(cx, obj_ty, &RESULT_PATH) { + span_lint(cx, RESULT_UNWRAP_USED, expr.span, + "used unwrap() on a Result value. Graceful handling of Err values is preferred"); + } +} + +/// lint use of `to_string()` for `&str`s and `String`s +fn lint_to_string(cx: &LateContext, expr: &Expr) { + let args = match expr.node { + ExprMethodCall(_, _, ref args) => args, + _ => panic!("clippy methods.rs: should not have called `lint_to_string()` on a \ + non-matching expression!"), + }; + + let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); + + if obj_ty.sty == ty::TyStr { + let mut arg_str = snippet(cx, args[0].span, "_"); + if ptr_depth > 1 { + arg_str = Cow::Owned(format!( + "({}{})", + iter::repeat('*').take(ptr_depth - 1).collect::<String>(), + arg_str)); + } + span_lint(cx, STR_TO_STRING, expr.span, + &format!("`{}.to_owned()` is faster", arg_str)); + } + else if match_type(cx, obj_ty, &STRING_PATH) { + span_lint(cx, STRING_TO_STRING, expr.span, + "`String.to_string()` is a no-op; use `clone()` to make a copy"); + } +} + +/// lint use of `ok().expect()` for `Result`s +fn lint_ok_expect(cx: &LateContext, expr: &Expr) { + let expect_args = match expr.node { + ExprMethodCall(_, _, ref expect_args) => expect_args, + _ => panic!("clippy methods.rs: Should not have called `lint_ok_expect()` on a \ + non-matching expression!") + }; + let ok_args = match expect_args[0].node { + ExprMethodCall(_, _, ref ok_args) => ok_args, + _ => panic!("clippy methods.rs: Should not have called `lint_ok_expect()` on a \ + non-matching expression!") + }; + + // lint if the caller of `ok()` is a `Result` + if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &RESULT_PATH) { + let result_type = cx.tcx.expr_ty(&ok_args[0]); + if let Some(error_type) = get_error_type(cx, result_type) { + if has_debug_impl(error_type, cx) { + span_lint(cx, OK_EXPECT, expr.span, + "called `ok().expect()` on a Result value. You can call `expect` \ + directly on the `Result`"); + } + } + } +} + +/// lint use of `map().unwrap_or()` for `Option`s +fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr) { + let unwrap_args = match expr.node { + ExprMethodCall(_, _, ref unwrap_args) => unwrap_args, + _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or()` on a \ + non-matching expression!") + }; + let map_args = match unwrap_args[0].node { + ExprMethodCall(_, _, ref map_args) => map_args, + _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or()` on a \ + non-matching expression!") + }; + + // lint if the caller of `map()` is an `Option` + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { + // lint message + let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more \ + directly by calling `map_or(a, f)` instead"; + // get snippets for args to map() and unwrap_or() + let map_snippet = snippet(cx, map_args[1].span, ".."); + let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or() have the same span + let multiline = map_snippet.lines().count() > 1 + || unwrap_snippet.lines().count() > 1; + let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint( + cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, + &format!("replace this with map_or({1}, {0})", map_snippet, unwrap_snippet) + ); + } + else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); + }; + } +} + +/// lint use of `map().unwrap_or_else()` for `Option`s +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr) { + let unwrap_args = match expr.node { + ExprMethodCall(_, _, ref unwrap_args) => unwrap_args, + _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or_else()` on a \ + non-matching expression!") + }; + let map_args = match unwrap_args[0].node { + ExprMethodCall(_, _, ref map_args) => map_args, + _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or_else()` on a \ + non-matching expression!") + }; + + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { + // lint message + let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more \ + directly by calling `map_or_else(g, f)` instead"; + // get snippets for args to map() and unwrap_or_else() + let map_snippet = snippet(cx, map_args[1].span, ".."); + let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or_else() have the same span + let multiline = map_snippet.lines().count() > 1 + || unwrap_snippet.lines().count() > 1; + let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint( + cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg, expr.span, + &format!("replace this with map_or_else({1}, {0})", map_snippet, unwrap_snippet) + ); + } + else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); + }; + } +} + // Given a `Result<T, E>` type, return its error type (`E`) fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { diff --git a/src/utils.rs b/src/utils.rs index 1ce97ccea4e..479ee142514 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -136,6 +136,7 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { false } } + /// check if method call given in "expr" belongs to given trait pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); @@ -163,6 +164,27 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { |(a, b)| a.identifier.name.as_str() == *b) } +/// match an Expr against a chain of methods. For example, if `expr` represents the `.baz()` in +/// `foo.bar().baz()`, `matched_method_chain(expr, &["bar", "baz"])` will return true. +pub fn match_method_chain(expr: &Expr, methods: &[&str]) -> bool { + let mut current = &expr.node ; + for method_name in methods.iter().rev() { // method chains are stored last -> first + if let ExprMethodCall(ref name, _, ref args) = *current { + if name.node.as_str() == *method_name { + current = &args[0].node + } + else { + return false; + } + } + else { + return false; + } + } + true +} + + /// get the name of the item the expression is in, if available pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); -- cgit 1.4.1-3-g733a5 From 29b53d600f63b998eaf3d723ee0da90379b7a8b8 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Sun, 27 Dec 2015 14:15:09 -0800 Subject: Replace `match_method_chain()` with `method_chain_args()` --- src/methods.rs | 92 ++++++++++++++++++---------------------------------------- src/utils.rs | 25 ++++++++++------ 2 files changed, 44 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 31e3bfb8f4a..d4809d374a3 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -5,9 +5,10 @@ use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; -use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, match_method_chain, +use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, walk_ptrs_ty_depth, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; +use utils::MethodArgs; use self::SelfKind::*; use self::OutType::*; @@ -158,20 +159,20 @@ impl LintPass for MethodsPass { impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(_, _, _) = expr.node { - if match_method_chain(expr, &["unwrap"]) { - lint_unwrap(cx, expr); + if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + lint_unwrap(cx, expr, arglists[0]); } - else if match_method_chain(expr, &["to_string"]) { - lint_to_string(cx, expr); + else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { + lint_to_string(cx, expr, arglists[0]); } - else if match_method_chain(expr, &["ok", "expect"]) { - lint_ok_expect(cx, expr); + else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { + lint_ok_expect(cx, expr, arglists[0]); } - else if match_method_chain(expr, &["map", "unwrap_or"]) { - lint_map_unwrap_or(cx, expr); + else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { + lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); } - else if match_method_chain(expr, &["map", "unwrap_or_else"]) { - lint_map_unwrap_or_else(cx, expr); + else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { + lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); } } } @@ -218,15 +219,10 @@ impl LateLintPass for MethodsPass { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `unwrap()` for `Option`s and `Result`s -fn lint_unwrap(cx: &LateContext, expr: &Expr) { - let args = match expr.node { - ExprMethodCall(_, _, ref args) => args, - _ => panic!("clippy methods.rs: should not have called `lint_unwrap()` on a non-matching \ - expression!"), - }; - - let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); +fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); if match_type(cx, obj_ty, &OPTION_PATH) { span_lint(cx, OPTION_UNWRAP_USED, expr.span, @@ -239,18 +235,13 @@ fn lint_unwrap(cx: &LateContext, expr: &Expr) { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `to_string()` for `&str`s and `String`s -fn lint_to_string(cx: &LateContext, expr: &Expr) { - let args = match expr.node { - ExprMethodCall(_, _, ref args) => args, - _ => panic!("clippy methods.rs: should not have called `lint_to_string()` on a \ - non-matching expression!"), - }; - - let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); +fn lint_to_string(cx: &LateContext, expr: &Expr, to_string_args: &MethodArgs) { + let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&to_string_args[0])); if obj_ty.sty == ty::TyStr { - let mut arg_str = snippet(cx, args[0].span, "_"); + let mut arg_str = snippet(cx, to_string_args[0].span, "_"); if ptr_depth > 1 { arg_str = Cow::Owned(format!( "({}{})", @@ -266,19 +257,9 @@ fn lint_to_string(cx: &LateContext, expr: &Expr) { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `ok().expect()` for `Result`s -fn lint_ok_expect(cx: &LateContext, expr: &Expr) { - let expect_args = match expr.node { - ExprMethodCall(_, _, ref expect_args) => expect_args, - _ => panic!("clippy methods.rs: Should not have called `lint_ok_expect()` on a \ - non-matching expression!") - }; - let ok_args = match expect_args[0].node { - ExprMethodCall(_, _, ref ok_args) => ok_args, - _ => panic!("clippy methods.rs: Should not have called `lint_ok_expect()` on a \ - non-matching expression!") - }; - +fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { // lint if the caller of `ok()` is a `Result` if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &RESULT_PATH) { let result_type = cx.tcx.expr_ty(&ok_args[0]); @@ -292,19 +273,10 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr) { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr) { - let unwrap_args = match expr.node { - ExprMethodCall(_, _, ref unwrap_args) => unwrap_args, - _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or()` on a \ - non-matching expression!") - }; - let map_args = match unwrap_args[0].node { - ExprMethodCall(_, _, ref map_args) => map_args, - _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or()` on a \ - non-matching expression!") - }; - +fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs, + map_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message @@ -330,19 +302,11 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr) { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or_else()` for `Option`s -fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr) { - let unwrap_args = match expr.node { - ExprMethodCall(_, _, ref unwrap_args) => unwrap_args, - _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or_else()` on a \ - non-matching expression!") - }; - let map_args = match unwrap_args[0].node { - ExprMethodCall(_, _, ref map_args) => map_args, - _ => panic!("clippy methods.rs: Should not have called `lint_map_unwrap_or_else()` on a \ - non-matching expression!") - }; - +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs, + map_args: &MethodArgs) { + // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more \ diff --git a/src/utils.rs b/src/utils.rs index 479ee142514..2ff498b5646 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,10 +8,13 @@ use rustc::middle::ty; use std::borrow::Cow; use syntax::ast::Lit_::*; use syntax::ast; +use syntax::ptr::P; use rustc::session::Session; use std::str::FromStr; +pub type MethodArgs = HirVec<P<Expr>>; + // module DefPaths for certain structs/enums we check for pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; @@ -164,24 +167,28 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { |(a, b)| a.identifier.name.as_str() == *b) } -/// match an Expr against a chain of methods. For example, if `expr` represents the `.baz()` in -/// `foo.bar().baz()`, `matched_method_chain(expr, &["bar", "baz"])` will return true. -pub fn match_method_chain(expr: &Expr, methods: &[&str]) -> bool { - let mut current = &expr.node ; +/// match an Expr against a chain of methods, and return the matched Exprs. For example, if `expr` +/// represents the `.baz()` in `foo.bar().baz()`, `matched_method_chain(expr, &["bar", "baz"])` +/// will return a Vec containing the Exprs for `.bar()` and `.baz()` +pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { + let mut current = expr; + let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first - if let ExprMethodCall(ref name, _, ref args) = *current { + if let ExprMethodCall(ref name, _, ref args) = current.node { if name.node.as_str() == *method_name { - current = &args[0].node + matched.push(args); // build up `matched` backwards + current = &args[0] // go to parent expression } else { - return false; + return None; } } else { - return false; + return None; } } - true + matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` + Some(matched) } -- cgit 1.4.1-3-g733a5 From 07830c44af2bc95332b36b51434bd73300c33fc1 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Mon, 28 Dec 2015 23:12:57 +0900 Subject: Extend escape analysis to arguments --- src/escape.rs | 15 ++++++++++++++- tests/compile-fail/box_vec.rs | 3 ++- tests/compile-fail/escape_analysis.rs | 6 +++++- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index 63894cda9be..9ee9d7ff344 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -31,6 +31,13 @@ pub struct EscapePass; /// ``` declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); +fn is_box(ty: ty::Ty) -> bool { + match ty.sty { + ty::TyBox(..) => true, + _ => false + } +} + struct EscapeDelegate<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, set: NodeSet, @@ -87,6 +94,12 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { + if self.cx.tcx.map.is_argument(consume_pat.id) { + if is_box(cmt.ty) { + self.set.insert(consume_pat.id); + } + return; + } if let Categorization::Rvalue(..) = cmt.cat { if let Some(Node::NodeStmt(st)) = self.cx .tcx @@ -96,7 +109,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if let DeclLocal(ref loc) = decl.node { if let Some(ref ex) = loc.init { if let ExprBox(..) = ex.node { - if let ty::TyBox(..) = cmt.ty.sty { + if is_box(cmt.ty) { // let x = box (...) self.set.insert(consume_pat.id); } diff --git a/tests/compile-fail/box_vec.rs b/tests/compile-fail/box_vec.rs index 58e780f190c..65275923dc5 100644 --- a/tests/compile-fail/box_vec.rs +++ b/tests/compile-fail/box_vec.rs @@ -1,7 +1,8 @@ #![feature(plugin)] - #![plugin(clippy)] + #![deny(clippy)] +#![allow(boxed_local)] pub fn test(foo: Box<Vec<bool>>) { //~ ERROR you seem to be trying to use `Box<Vec<T>>` println!("{:?}", foo.get(0)) diff --git a/tests/compile-fail/escape_analysis.rs b/tests/compile-fail/escape_analysis.rs index 3782cb96da5..28154d9414e 100644 --- a/tests/compile-fail/escape_analysis.rs +++ b/tests/compile-fail/escape_analysis.rs @@ -19,6 +19,10 @@ fn warn_call() { x.foo(); } +fn warn_arg(x: Box<A>) { //~ ERROR local variable + x.foo(); +} + fn warn_rename_call() { let x = box A; @@ -78,4 +82,4 @@ fn warn_match() { match &x { // not moved ref y => () } -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From bbd439ec9ea3ef20edefa319b479cb06739ba52d Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Mon, 28 Dec 2015 16:56:58 -0800 Subject: Add FILTER_NEXT lint --- README.md | 7 ++++--- src/lib.rs | 1 + src/methods.rs | 37 ++++++++++++++++++++++++++++++++++--- tests/compile-fail/methods.rs | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 2c8b20f83a9..9840eda8d39 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 86 lints included in this crate: +There are 87 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -28,6 +28,7 @@ name [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` @@ -55,8 +56,8 @@ name [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result -[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`) -[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) +[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` +[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing [panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` diff --git a/src/lib.rs b/src/lib.rs index adc1d402e92..4caf008e330 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,6 +176,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_BOOL, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, + methods::FILTER_NEXT, methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, diff --git a/src/methods.rs b/src/methods.rs index d4809d374a3..f2f7dbdea9c 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -6,7 +6,7 @@ use std::iter; use std::borrow::Cow; use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, - walk_ptrs_ty_depth, walk_ptrs_ty}; + match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; use utils::MethodArgs; @@ -135,7 +135,7 @@ declare_lint!(pub OK_EXPECT, Warn, /// **Example:** `x.map(|a| a + 1).unwrap_or(0)` declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ - `map_or(a, f)`)"); + `map_or(a, f)`"); /// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`. /// @@ -146,7 +146,17 @@ declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, /// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)` declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ - `map_or_else(g, f)`)"); + `map_or_else(g, f)`"); + +/// **What it does:** This lint `Warn`s on `_.filter(_).next()`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.find(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `iter.filter(|x| x == 0).next()` +declare_lint!(pub FILTER_NEXT, Warn, + "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"); impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { @@ -174,6 +184,9 @@ impl LateLintPass for MethodsPass { else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); } + else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { + lint_filter_next(cx, expr, arglists[0]); + } } } @@ -331,6 +344,24 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, unwrap_args: &MethodAr } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +/// lint use of `filter().next() for Iterators` +fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { + // lint if caller of `.filter().next()` is an Iterator + if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + 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 + span_note_and_lint(cx, FILTER_NEXT, expr.span, msg, expr.span, + &format!("replace this with `find({})`)", filter_snippet)); + } + else { + span_lint(cx, FILTER_NEXT, expr.span, msg); + } + } +} + // Given a `Result<T, E>` type, return its error type (`E`) fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 9078a78d6fe..d2fed0f907b 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -83,6 +83,39 @@ fn option_methods() { } +/// Struct to generate false positive for FILTER_NEXT lint +struct FilterNextTest { + _foo: u32, +} + +impl FilterNextTest { + fn filter(self) -> FilterNextTest { + self + } + fn next(self) -> FilterNextTest { + self + } +} + +/// Checks implementation of FILTER_NEXT lint +fn filter_next() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + + // check single-line case + let _ = v.iter().filter(|&x| *x < 0).next(); //~ERROR called `filter(p).next()` on an Iterator. + //~| NOTE replace this + + // check multi-line case + let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator. + *x < 0 + } + ).next(); + + // check that we don't lint if the caller is not an Iterator + let foo = FilterNextTest { _foo: 0 }; + let _ = foo.filter().next(); +} + fn main() { use std::io; -- cgit 1.4.1-3-g733a5 From a6bd2d06227fa315c7a404d61dee9ded4a1e45bc Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Wed, 30 Dec 2015 00:38:03 -0800 Subject: Add SEARCH_IS_SOME lint --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 40 ++++++++++++++++++++++++++ tests/compile-fail/methods.rs | 66 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 102 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 9840eda8d39..9fe59d4fdaf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 87 lints included in this crate: +There are 88 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -69,6 +69,7 @@ name [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled [reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` +[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` [shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` [shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value diff --git a/src/lib.rs b/src/lib.rs index 4caf008e330..6d39cad20cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -180,6 +180,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, + methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, methods::STRING_TO_STRING, diff --git a/src/methods.rs b/src/methods.rs index f2f7dbdea9c..081e64b53ea 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -158,6 +158,18 @@ declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, declare_lint!(pub FILTER_NEXT, Warn, "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"); +/// **What it does:** This lint `Warn`s on an iterator search (such as `find()`, `position()`, or +/// `rposition()`) followed by a call to `is_some()`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.any(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `iter.find(|x| x == 0).is_some()` +declare_lint!(pub SEARCH_IS_SOME, Warn, + "using an iterator search followed by `is_some()`, which is more succinctly \ + expressed as a call to `any()`"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, @@ -187,6 +199,15 @@ impl LateLintPass for MethodsPass { else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { lint_filter_next(cx, expr, arglists[0]); } + else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { + lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); + } + else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { + lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); + } + else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { + lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); + } } } @@ -362,6 +383,25 @@ fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { } } +#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +/// lint searching an Iterator followed by `is_some()` +fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, search_args: &MethodArgs, + is_some_args: &MethodArgs) { + // lint if caller of search is an Iterator + if match_trait_method(cx, &*is_some_args[0], &["core", "iter", "Iterator"]) { + 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 { // add note if not multi-line + span_note_and_lint(cx, SEARCH_IS_SOME, expr.span, &msg, expr.span, + &format!("replace this with `any({})`)", search_snippet)); + } + else { + span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + } + } +} + // Given a `Result<T, E>` type, return its error type (`E`) fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index d2fed0f907b..1878ae15b75 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -83,18 +83,32 @@ fn option_methods() { } -/// Struct to generate false positive for FILTER_NEXT lint -struct FilterNextTest { - _foo: u32, +/// Struct to generate false positive for Iterator-based lints +#[derive(Copy, Clone)] +struct IteratorFalsePositives { + foo: u32, } -impl FilterNextTest { - fn filter(self) -> FilterNextTest { +impl IteratorFalsePositives { + fn filter(self) -> IteratorFalsePositives { self } - fn next(self) -> FilterNextTest { + + fn next(self) -> IteratorFalsePositives { self } + + fn find(self) -> Option<u32> { + Some(self.foo) + } + + fn position(self) -> Option<u32> { + Some(self.foo) + } + + fn rposition(self) -> Option<u32> { + Some(self.foo) + } } /// Checks implementation of FILTER_NEXT lint @@ -112,10 +126,48 @@ fn filter_next() { ).next(); // check that we don't lint if the caller is not an Iterator - let foo = FilterNextTest { _foo: 0 }; + let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); } +/// Checks implementation of SEARCH_IS_SOME lint +fn search_is_some() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + + // check `find().is_some()`, single-line + let _ = v.iter().find(|&x| *x < 0).is_some(); //~ERROR called `is_some()` after searching + //~| NOTE replace this + // check `find().is_some()`, multi-line + let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching + *x < 0 + } + ).is_some(); + + // check `position().is_some()`, single-line + let _ = v.iter().position(|&x| x < 0).is_some(); //~ERROR called `is_some()` after searching + //~| NOTE replace this + // check `position().is_some()`, multi-line + let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching + x < 0 + } + ).is_some(); + + // check `rposition().is_some()`, single-line + let _ = v.iter().rposition(|&x| x < 0).is_some(); //~ERROR called `is_some()` after searching + //~| NOTE replace this + // check `rposition().is_some()`, multi-line + let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching + x < 0 + } + ).is_some(); + + // check that we don't lint if the caller is not an Iterator + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.find().is_some(); + let _ = foo.position().is_some(); + let _ = foo.rposition().is_some(); +} + fn main() { use std::io; -- cgit 1.4.1-3-g733a5 From 2c42d46468e7a047841c89d1ebdd517917bb12a2 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Wed, 30 Dec 2015 00:55:38 -0800 Subject: Bug fix --- src/methods.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 081e64b53ea..5515ba17bf0 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -309,8 +309,8 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs, - map_args: &MethodArgs) { +fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, + unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message @@ -338,8 +338,8 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs, #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or_else()` for `Option`s -fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs, - map_args: &MethodArgs) { +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, + unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message -- cgit 1.4.1-3-g733a5 From 093582c102b4ca983e9b6ef620860a75f6a1d812 Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Wed, 30 Dec 2015 01:07:40 -0800 Subject: Make MethodsPass lint notes clearer --- src/methods.rs | 11 +++++++---- tests/compile-fail/methods.rs | 27 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 5515ba17bf0..a6200534e30 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -327,7 +327,8 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, if same_span && !multiline { span_note_and_lint( cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, - &format!("replace this with map_or({1}, {0})", map_snippet, unwrap_snippet) + &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", map_snippet, + unwrap_snippet) ); } else if same_span && multiline { @@ -356,7 +357,8 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, if same_span && !multiline { span_note_and_lint( cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg, expr.span, - &format!("replace this with map_or_else({1}, {0})", map_snippet, unwrap_snippet) + &format!("replace `map({0}).unwrap_or_else({1})` with `with map_or_else({1}, {0})`", + map_snippet, unwrap_snippet) ); } else if same_span && multiline { @@ -375,7 +377,7 @@ fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { // add note if not multi-line span_note_and_lint(cx, FILTER_NEXT, expr.span, msg, expr.span, - &format!("replace this with `find({})`)", filter_snippet)); + &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); @@ -394,7 +396,8 @@ fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, searc let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // add note if not multi-line span_note_and_lint(cx, SEARCH_IS_SOME, expr.span, &msg, expr.span, - &format!("replace this with `any({})`)", search_snippet)); + &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, + search_snippet)); } else { span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 1878ae15b75..b41b28dc11e 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -50,7 +50,7 @@ fn option_methods() { // Check OPTION_MAP_UNWRAP_OR // single line case let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or(a)` - //~| NOTE replace this + //~| NOTE replace `map(|x| x + 1).unwrap_or(0)` .unwrap_or(0); // should lint even though this call is on a separate line // multi line cases let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or(a)` @@ -67,7 +67,7 @@ fn option_methods() { // Check OPTION_MAP_UNWRAP_OR_ELSE // single line case let _ = opt.map(|x| x + 1) //~ ERROR called `map(f).unwrap_or_else(g)` - //~| NOTE replace this + //~| NOTE replace `map(|x| x + 1).unwrap_or_else(|| 0)` .unwrap_or_else(|| 0); // should lint even though this call is on a separate line // multi line cases let _ = opt.map(|x| { //~ ERROR called `map(f).unwrap_or_else(g)` @@ -116,8 +116,9 @@ fn filter_next() { let v = vec![3, 2, 1, 0, -1, -2, -3]; // check single-line case - let _ = v.iter().filter(|&x| *x < 0).next(); //~ERROR called `filter(p).next()` on an Iterator. - //~| NOTE replace this + let _ = v.iter().filter(|&x| *x < 0).next(); + //~^ ERROR called `filter(p).next()` on an Iterator. + //~| NOTE replace `filter(|&x| *x < 0).next()` // check multi-line case let _ = v.iter().filter(|&x| { //~ERROR called `filter(p).next()` on an Iterator. @@ -135,8 +136,10 @@ fn search_is_some() { let v = vec![3, 2, 1, 0, -1, -2, -3]; // check `find().is_some()`, single-line - let _ = v.iter().find(|&x| *x < 0).is_some(); //~ERROR called `is_some()` after searching - //~| NOTE replace this + let _ = v.iter().find(|&x| *x < 0).is_some(); + //~^ ERROR called `is_some()` after searching + //~| NOTE replace `find(|&x| *x < 0).is_some()` + // check `find().is_some()`, multi-line let _ = v.iter().find(|&x| { //~ERROR called `is_some()` after searching *x < 0 @@ -144,8 +147,10 @@ fn search_is_some() { ).is_some(); // check `position().is_some()`, single-line - let _ = v.iter().position(|&x| x < 0).is_some(); //~ERROR called `is_some()` after searching - //~| NOTE replace this + let _ = v.iter().position(|&x| x < 0).is_some(); + //~^ ERROR called `is_some()` after searching + //~| NOTE replace `position(|&x| x < 0).is_some()` + // check `position().is_some()`, multi-line let _ = v.iter().position(|&x| { //~ERROR called `is_some()` after searching x < 0 @@ -153,8 +158,10 @@ fn search_is_some() { ).is_some(); // check `rposition().is_some()`, single-line - let _ = v.iter().rposition(|&x| x < 0).is_some(); //~ERROR called `is_some()` after searching - //~| NOTE replace this + let _ = v.iter().rposition(|&x| x < 0).is_some(); + //~^ ERROR called `is_some()` after searching + //~| NOTE replace `rposition(|&x| x < 0).is_some()` + // check `rposition().is_some()`, multi-line let _ = v.iter().rposition(|&x| { //~ERROR called `is_some()` after searching x < 0 -- cgit 1.4.1-3-g733a5 From 06f30a61dd2a948c58907ef9ebb80b040e930450 Mon Sep 17 00:00:00 2001 From: Johannes Linke <johannes.linke@posteo.de> Date: Fri, 1 Jan 2016 17:48:19 +0100 Subject: Add "warn/allow by default" to lint descriptions where it was missing. --- src/attrs.rs | 2 +- src/block_in_if_condition.rs | 4 ++-- src/escape.rs | 2 +- src/loops.rs | 4 ++-- src/minmax.rs | 2 +- src/misc.rs | 2 +- src/mut_reference.rs | 2 +- src/strings.rs | 2 +- src/types.rs | 5 +++-- src/zero_div_zero.rs | 2 +- 10 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 0882f3af41f..f0dbf390ebb 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -8,7 +8,7 @@ use syntax::attr::*; use syntax::ast::{Attribute, MetaList, MetaWord}; use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; -/// **What it does:** This lint warns on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. +/// **What it does:** This lint `Warn`s on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. /// /// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it. /// diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index f7c181f5fd8..03265635b1d 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -3,7 +3,7 @@ use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; use rustc_front::intravisit::{Visitor, walk_expr}; use utils::*; -/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. +/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. It is `Warn` by default. /// /// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions. /// @@ -15,7 +15,7 @@ declare_lint! { "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" } -/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. +/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. It is `Warn` by default. /// /// **Why is this bad?** Using blocks in the condition makes it hard to read. /// diff --git a/src/escape.rs b/src/escape.rs index 63894cda9be..21bf30e131c 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -14,7 +14,7 @@ use utils::span_lint; pub struct EscapePass; -/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine +/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. It is `Warn` by default. /// /// **Why is this bad?** This is an unnecessary allocation, and bad for performance /// diff --git a/src/loops.rs b/src/loops.rs index 5c552d2ce42..9f103f4e7a8 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -50,7 +50,7 @@ declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } -/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. +/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. /// /// **Why is this bad?** The `while let` loop is usually shorter and more readable /// @@ -85,7 +85,7 @@ declare_lint!{ pub UNUSED_COLLECT, Warn, "`collect()`ing an iterator without using the result; this is usually better \ written as a for loop" } -/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. +/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. It is `Warn` by default. /// /// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. /// diff --git a/src/minmax.rs b/src/minmax.rs index ac8d6f05272..b63e839612c 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -8,7 +8,7 @@ use consts::{Constant, constant_simple}; use utils::{match_def_path, span_lint}; use self::MinMax::{Min, Max}; -/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. +/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. It is `Warn` by default. /// /// **Why is this bad?** This is in all probability not the intended outcome. At the least it hurts readability of the code. /// diff --git a/src/misc.rs b/src/misc.rs index 139dfde3681..92276961d11 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -281,7 +281,7 @@ impl LateLintPass for ModuloOne { } } -/// **What it does:** This lint checks for patterns in the form `name @ _`. +/// **What it does:** This lint checks for patterns in the form `name @ _`. It is `Warn` by default. /// /// **Why is this bad?** It's almost always more readable to just use direct bindings. /// diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 9ba9782336a..133462071e4 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -4,7 +4,7 @@ use utils::span_lint; use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; use syntax::ptr::P; -/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. +/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. It is `Warn` by default. /// /// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site. /// diff --git a/src/strings.rs b/src/strings.rs index b567d949330..d60a045aa75 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -11,7 +11,7 @@ use eq_op::is_exp_equal; use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; -/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!) +/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). It is `Allow` by default. /// /// **Why is this bad?** Because this expression needs another copy as opposed to `x.push_str(y)` (in practice LLVM will usually elide it, though). Despite [llogiq](https://github.com/llogiq)'s reservations, this lint also is `allow` by default, as some people opine that it's more readable. /// diff --git a/src/types.rs b/src/types.rs index 9bc50643259..f332659188b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,7 +17,7 @@ use utils::{LL_PATH, VEC_PATH}; #[allow(missing_copy_implementations)] pub struct TypePass; -/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. +/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. It is `Warn` by default. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever. /// @@ -26,7 +26,8 @@ pub struct TypePass; /// **Example:** `struct X { values: Box<Vec<Foo>> }` declare_lint!(pub BOX_VEC, Warn, "usage of `Box<Vec<T>>`, vector elements are already on the heap"); -/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). + +/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). It is `Warn` by default. /// /// **Why is this bad?** Gankro says: /// diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index c4d7cf4a589..5a4d3931606 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -9,7 +9,7 @@ use consts::{Constant, constant_simple, FloatWidth}; /// 0.0/0.0 with std::f32::NaN or std::f64::NaN, depending on the precision. pub struct ZeroDivZeroPass; -/// **What it does:** This lint checks for `0.0 / 0.0` +/// **What it does:** This lint checks for `0.0 / 0.0`. It is `Warn` by default. /// /// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN` /// -- cgit 1.4.1-3-g733a5 From b287739c0b2e4d6202d94eb2a20a385a69c74d63 Mon Sep 17 00:00:00 2001 From: Johannes Linke <johannes.linke@posteo.de> Date: Fri, 1 Jan 2016 17:48:46 +0100 Subject: Remove reference to a fixed issue --- src/map_clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/map_clone.rs b/src/map_clone.rs index b1ba47a9b54..ef992ad086c 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -8,7 +8,7 @@ use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; /// /// **Why is this bad?** It makes the code less readable. /// -/// **Known problems:** False negative: The lint currently misses mapping `Clone::clone` directly. Issue #436 is tracking this. +/// **Known problems:** None /// /// **Example:** `x.map(|e| e.clone());` declare_lint!(pub MAP_CLONE, Warn, -- cgit 1.4.1-3-g733a5 From f89e4005784abfe0b71a2c24fbd2fa007e57a61a Mon Sep 17 00:00:00 2001 From: Johannes Linke <johannes.linke@posteo.de> Date: Fri, 1 Jan 2016 17:49:01 +0100 Subject: Minor documentation cleanups --- src/escape.rs | 4 ++-- src/mut_reference.rs | 8 ++++---- src/precedence.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index 21bf30e131c..4b6a8258dbe 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -16,9 +16,9 @@ pub struct EscapePass; /// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. It is `Warn` by default. /// -/// **Why is this bad?** This is an unnecessary allocation, and bad for performance +/// **Why is this bad?** This is an unnecessary allocation, and bad for performance. It is only necessary to allocate if you wish to move the box into something. /// -/// It is only necessary to allocate if you wish to move the box into something. +/// **Known problems:** None /// /// **Example:** /// diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 133462071e4..ddfd9ddcc13 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -36,7 +36,7 @@ impl LateLintPass for UnnecessaryMutPassed { match borrowed_table.node_types.get(&fn_expr.id) { Some(function_type) => { if let ExprPath(_, ref path) = fn_expr.node { - check_arguments(cx, &arguments, function_type, + check_arguments(cx, &arguments, function_type, &format!("{}", path)); } } @@ -50,7 +50,7 @@ impl LateLintPass for UnnecessaryMutPassed { ExprMethodCall(ref name, _, ref arguments) => { let method_call = MethodCall::expr(e.id); match borrowed_table.method_map.get(&method_call) { - Some(method_type) => check_arguments(cx, &arguments, method_type.ty, + Some(method_type) => check_arguments(cx, &arguments, method_type.ty, &format!("{}", name.node.as_str())), None => unreachable!(), // Just like above, this should never happen. }; @@ -68,9 +68,9 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty TypeVariants::TyRef(_, TypeAndMut {mutbl: MutImmutable, ..}) | TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, UNNECESSARY_MUT_PASSED, + span_lint(cx, UNNECESSARY_MUT_PASSED, argument.span, &format!("The function/method \"{}\" \ - doesn't need a mutable reference", + doesn't need a mutable reference", name)); } } diff --git a/src/precedence.rs b/src/precedence.rs index 39a3e9e56c2..3aae9fd0d6c 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -4,7 +4,7 @@ use syntax::ast::*; use utils::{span_lint, snippet}; -/// **What it does:** This lint checks for operations where precedence may be unclear and `Warn`'s about them by default, suggesting to add parentheses. Currently it catches the following: +/// **What it does:** This lint checks for operations where precedence may be unclear and `Warn`s about them by default, suggesting to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without parentheses /// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call /// @@ -33,17 +33,17 @@ impl EarlyLintPass for Precedence { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if !is_bit_op(op) { return; } match (is_arith_expr(left), is_arith_expr(right)) { - (true, true) => span_lint(cx, PRECEDENCE, expr.span, + (true, true) => span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} ({})`", snippet(cx, left.span, ".."), op.to_string(), snippet(cx, right.span, ".."))), - (true, false) => span_lint(cx, PRECEDENCE, expr.span, + (true, false) => span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} {}`", snippet(cx, left.span, ".."), op.to_string(), snippet(cx, right.span, ".."))), - (false, true) => span_lint(cx, PRECEDENCE, expr.span, + (false, true) => span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `{} {} ({})`", snippet(cx, left.span, ".."), -- cgit 1.4.1-3-g733a5 From bd8a265000a25b5cb06fd12a5201d6e347163279 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume1.gomez@gmail.com> Date: Sat, 2 Jan 2016 05:52:13 +0100 Subject: Add help on field binding --- src/misc_early.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/misc_early.rs b/src/misc_early.rs index 1520e9c0e58..dafe7816fe4 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -4,7 +4,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::span_lint; +use utils::{span_lint, span_help_and_lint}; /// **What it does:** This lint `Warn`s on struct field patterns bound to wildcards. /// @@ -27,8 +27,12 @@ impl LintPass for MiscEarly { impl EarlyLintPass for MiscEarly { fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { - if let PatStruct(_, ref pfields, _) = pat.node { + if let PatStruct(ref npat, ref pfields, _) = pat.node { let mut wilds = 0; + let type_name = match npat.segments.last() { + Some(elem) => format!("{}", elem.identifier.name), + None => String::new(), + }; for field in pfields { if field.node.pat.node == PatWild { @@ -36,17 +40,38 @@ impl EarlyLintPass for MiscEarly { } } if !pfields.is_empty() && wilds == pfields.len() { - span_lint(cx, UNNEEDED_FIELD_PATTERN, pat.span, - "All the struct fields are matched to a wildcard pattern, \ - consider using `..`."); + span_help_and_lint(cx, UNNEEDED_FIELD_PATTERN, pat.span, + "All the struct fields are matched to a wildcard pattern, \ + consider using `..`.", + &format!("Try with `{} {{ .. }}` instead", + type_name)); return; } if wilds > 0 { + let mut normal = vec!(); + + for field in pfields { + if field.node.pat.node != PatWild { + if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) { + normal.push(n); + } + } + } for field in pfields { if field.node.pat.node == PatWild { - span_lint(cx, UNNEEDED_FIELD_PATTERN, field.span, - "You matched a field with a wildcard pattern. \ - Consider using `..` instead"); + wilds -= 1; + if wilds > 0 { + span_lint(cx, UNNEEDED_FIELD_PATTERN, field.span, + "You matched a field with a wildcard pattern. \ + Consider using `..` instead"); + } else { + span_help_and_lint(cx, UNNEEDED_FIELD_PATTERN, field.span, + "You matched a field with a wildcard pattern. \ + Consider using `..` instead", + &format!("Try with `{} {{ {}, .. }}`", + type_name, + normal[..].join(", "))); + } } } } -- cgit 1.4.1-3-g733a5 From 1605ef6ed48fded84b7b8556c9b65809c5aba1ad Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 1 Jan 2016 02:09:03 +0530 Subject: Rustup to syntax::errors changes --- Cargo.toml | 2 +- src/cyclomatic_complexity.rs | 13 ++--- src/eta_reduction.rs | 4 +- src/len_zero.rs | 2 +- src/minmax.rs | 2 +- src/mut_mut.rs | 8 +-- src/mutex_atomic.rs | 2 +- src/precedence.rs | 23 +++++--- src/returns.rs | 8 +-- src/shadow.rs | 22 ++++---- src/strings.rs | 4 +- src/utils.rs | 82 ++++++++++++++++++++--------- tests/compile-fail/cyclomatic_complexity.rs | 3 +- 13 files changed, 107 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 4bae9f5aa22..3ab2c9ef6e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.33" +version = "0.0.34" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index c2cc6a8c4ab..7beb3296aac 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -9,7 +9,7 @@ use syntax::attr::*; use syntax::ast::Attribute; use rustc_front::intravisit::{Visitor, walk_expr}; -use utils::{in_macro, LimitStack}; +use utils::{in_macro, LimitStack, span_help_and_lint}; /// **What it does:** It `Warn`s on methods with high cyclomatic complexity /// @@ -59,8 +59,8 @@ impl CyclomaticComplexity { } else { let rust_cc = cc + divergence - narms; if rust_cc > self.limit.limit() { - cx.span_lint_help(CYCLOMATIC_COMPLEXITY, span, - &format!("The function has a cyclomatic complexity of {}.", rust_cc), + span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, span, + &format!("The function has a cyclomatic complexity of {}", rust_cc), "You could split it up into multiple smaller functions"); } } @@ -140,8 +140,9 @@ fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { #[cfg(not(feature="debugging"))] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { - cx.sess().span_note(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ - (hide this message with `#[allow(cyclomatic_complexity)]`): \ - cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div)); + cx.sess().span_note_without_error(span, + &format!("Clippy encountered a bug calculating cyclomatic complexity \ + (hide this message with `#[allow(cyclomatic_complexity)]`): \ + cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div)); } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index c25228793e6..6b561ff7a05 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -84,9 +84,9 @@ fn check_closure(cx: &LateContext, expr: &Expr) { } span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", - || { + |db| { if let Some(snippet) = snippet_opt(cx, caller.span) { - cx.sess().span_suggestion(expr.span, + db.span_suggestion(expr.span, "remove closure as shown:", snippet); } diff --git a/src/len_zero.rs b/src/len_zero.rs index 589b4f6ebb1..d574fa2c336 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -135,7 +135,7 @@ fn check_len_zero(cx: &LateContext, span: Span, name: &Name, has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, span, &format!( "consider replacing the len comparison with `{}{}.is_empty()`", - op, snippet(cx, args[0].span, "_"))) + op, snippet(cx, args[0].span, "_"))); } } } diff --git a/src/minmax.rs b/src/minmax.rs index b63e839612c..2a8e064f9f4 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -37,7 +37,7 @@ impl LateLintPass for MinMaxPass { (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, - "this min/max combination leads to constant result") + "this min/max combination leads to constant result"); } } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index ade688d377f..db6f0e0320b 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -30,8 +30,8 @@ impl LateLintPass for MutMut { } fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| span_lint(cx, MUT_MUT, - ty.span, "generally you want to avoid `&mut &mut _` if possible")) + unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| { span_lint(cx, MUT_MUT, + ty.span, "generally you want to avoid `&mut &mut _` if possible"); }); } } @@ -52,12 +52,12 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { cx.tcx.expr_ty(e).sty { span_lint(cx, MUT_MUT, expr.span, "this expression mutably borrows a mutable reference. \ - Consider reborrowing") + Consider reborrowing"); } }, |_| { span_lint(cx, MUT_MUT, expr.span, - "generally you want to avoid `&mut &mut _` if possible") + "generally you want to avoid `&mut &mut _` if possible"); } ) }) diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 40f7d21f43c..8899eb56d42 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -63,7 +63,7 @@ impl LateLintPass for MutexAtomic { ty::TyInt(t) if t != ast::TyIs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg) - } + }; } } } diff --git a/src/precedence.rs b/src/precedence.rs index 3aae9fd0d6c..91ff0680b3e 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -33,21 +33,27 @@ impl EarlyLintPass for Precedence { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if !is_bit_op(op) { return; } match (is_arith_expr(left), is_arith_expr(right)) { - (true, true) => span_lint(cx, PRECEDENCE, expr.span, + (true, true) => { + span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} ({})`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))), - (true, false) => span_lint(cx, PRECEDENCE, expr.span, + op.to_string(), snippet(cx, right.span, ".."))); + }, + (true, false) => { + span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `({}) {} {}`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))), - (false, true) => span_lint(cx, PRECEDENCE, expr.span, + op.to_string(), snippet(cx, right.span, ".."))); + }, + (false, true) => { + span_lint(cx, PRECEDENCE, expr.span, &format!("operator precedence can trip the unwary. \ Consider parenthesizing your expression:\ `{} {} ({})`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))), + op.to_string(), snippet(cx, right.span, ".."))); + }, _ => (), } } @@ -57,12 +63,13 @@ impl EarlyLintPass for Precedence { if let Some(slf) = args.first() { if let ExprLit(ref lit) = slf.node { match lit.node { - LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => + LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => { span_lint(cx, PRECEDENCE, expr.span, &format!( "unary minus has lower precedence than \ method call. Consider adding parentheses \ to clarify your intent: -({})", - snippet(cx, rhs.span, ".."))), + snippet(cx, rhs.span, ".."))); + } _ => () } } diff --git a/src/returns.rs b/src/returns.rs index 3ef94a4c926..15f9bb80d95 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -75,9 +75,9 @@ impl ReturnPass { if in_external_macro(cx, spans.1) {return;} span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", - || { + |db| { if let Some(snippet) = snippet_opt(cx, spans.1) { - cx.sess().span_suggestion(spans.0, + db.span_suggestion(spans.0, "remove `return` as shown:", snippet); } @@ -105,11 +105,11 @@ impl ReturnPass { fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) { if in_external_macro(cx, note_span) {return;} - span_lint(cx, LET_AND_RETURN, lint_span, + let mut db = span_lint(cx, LET_AND_RETURN, lint_span, "returning the result of a let binding from a block. \ Consider returning the expression directly."); if cx.current_level(LET_AND_RETURN) != Level::Allow { - cx.sess().span_note(note_span, + db.span_note(note_span, "this expression can be directly returned"); } } diff --git a/src/shadow.rs b/src/shadow.rs index 27bed50c263..1210590bbcb 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -7,7 +7,7 @@ use rustc_front::intravisit::{Visitor, FnKind}; use rustc::lint::*; use rustc::middle::def::Def::{DefVariant, DefStruct}; -use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint}; +use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; /// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. It is `Allow` by default. /// @@ -180,39 +180,39 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: &Option<T>, prev_span: Span) where T: Deref<Target=Expr> { - fn note_orig(cx: &LateContext, lint: &'static Lint, span: Span) { + fn note_orig(cx: &LateContext, mut db: DiagnosticWrapper, lint: &'static Lint, span: Span) { if cx.current_level(lint) != Level::Allow { - cx.sess().span_note(span, "previous binding is here"); + db.span_note(span, "previous binding is here"); } } if let Some(ref expr) = *init { if is_self_shadow(name, expr) { - span_lint(cx, SHADOW_SAME, span, &format!( + let db = span_lint(cx, SHADOW_SAME, span, &format!( "{} is shadowed by itself in {}", snippet(cx, lspan, "_"), snippet(cx, expr.span, ".."))); - note_orig(cx, SHADOW_SAME, prev_span); + note_orig(cx, db, SHADOW_SAME, prev_span); } else { if contains_self(name, expr) { - span_note_and_lint(cx, SHADOW_REUSE, lspan, &format!( + let db = span_note_and_lint(cx, SHADOW_REUSE, lspan, &format!( "{} is shadowed by {} which reuses the original value", snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); - note_orig(cx, SHADOW_REUSE, prev_span); + note_orig(cx, db, SHADOW_REUSE, prev_span); } else { - span_note_and_lint(cx, SHADOW_UNRELATED, lspan, &format!( + let db = span_note_and_lint(cx, SHADOW_UNRELATED, lspan, &format!( "{} is shadowed by {}", snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); - note_orig(cx, SHADOW_UNRELATED, prev_span); + note_orig(cx, db, SHADOW_UNRELATED, prev_span); } } } else { - span_lint(cx, SHADOW_UNRELATED, span, &format!( + let db = span_lint(cx, SHADOW_UNRELATED, span, &format!( "{} shadows a previous declaration", snippet(cx, lspan, "_"))); - note_orig(cx, SHADOW_UNRELATED, prev_span); + note_orig(cx, db, SHADOW_UNRELATED, prev_span); } } diff --git a/src/strings.rs b/src/strings.rs index d60a045aa75..861ae0bb012 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -75,13 +75,13 @@ impl LateLintPass for StringAdd { } span_lint(cx, STRING_ADD, e.span, "you added something to a string. \ - Consider using `String::push_str()` instead") + Consider using `String::push_str()` instead"); } } else if let ExprAssign(ref target, ref src) = e.node { if is_string(cx, target) && is_add(cx, src, target) { span_lint(cx, STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. \ - Consider using `String::push_str()` instead") + Consider using `String::push_str()` instead"); } } } diff --git a/src/utils.rs b/src/utils.rs index 2ff498b5646..7c0ee09b3cd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,10 +8,12 @@ use rustc::middle::ty; use std::borrow::Cow; use syntax::ast::Lit_::*; use syntax::ast; +use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; use rustc::session::Session; use std::str::FromStr; +use std::ops::{Deref, DerefMut}; pub type MethodArgs = HirVec<P<Expr>>; @@ -307,63 +309,91 @@ pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c } else { None } } +pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); + +impl<'a> Drop for DiagnosticWrapper<'a> { + fn drop(&mut self) { + self.0.emit(); + } +} + +impl<'a> DerefMut for DiagnosticWrapper<'a> { + fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { + &mut self.0 + } +} + +impl<'a> Deref for DiagnosticWrapper<'a> { + type Target = DiagnosticBuilder<'a>; + fn deref(&self) -> &DiagnosticBuilder<'a> { + &self.0 + } +} + #[cfg(not(feature="structured_logging"))] -pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { - cx.span_lint(lint, sp, msg); +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, + sp: Span, msg: &str) -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { - cx.sess().fileline_help(sp, &format!("for further information visit \ + db.fileline_help(sp, &format!("for further information visit \ https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())) + lint.name_lower())); } + DiagnosticWrapper(db) } #[cfg(feature="structured_logging")] -pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) { +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, + sp: Span, msg: &str) -> DiagnosticWrapper<'a> { // lint.name / lint.desc is can give details of the lint // cx.sess().codemap() has all these nice functions for line/column/snippet details // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string - cx.span_lint(lint, sp, msg); + let mut db = cx.struct_span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { - cx.sess().fileline_help(sp, &format!("for further information visit \ + db.fileline_help(sp, &format!("for further information visit \ https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())) + lint.name_lower())); } + DiagnosticWrapper(db) } -pub fn span_help_and_lint<T: LintContext>(cx: &T, lint: &'static Lint, span: Span, - msg: &str, help: &str) { - cx.span_lint(lint, span, msg); +pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, + msg: &str, help: &str) -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { - cx.sess().fileline_help(span, &format!("{}\nfor further information \ + db.fileline_help(span, &format!("{}\nfor further information \ visit https://github.com/Manishearth/rust-clippy/wiki#{}", - help, lint.name_lower())) + help, lint.name_lower())); } + DiagnosticWrapper(db) } -pub fn span_note_and_lint<T: LintContext>(cx: &T, lint: &'static Lint, span: Span, - msg: &str, note_span: Span, note: &str) { - cx.span_lint(lint, span, msg); +pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, + msg: &str, note_span: Span, note: &str) -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { if note_span == span { - cx.sess().fileline_note(note_span, note) + db.fileline_note(note_span, note); } else { - cx.sess().span_note(note_span, note) + db.span_note(note_span, note); } - cx.sess().fileline_help(span, &format!("for further information visit \ + db.fileline_help(span, &format!("for further information visit \ https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())) + lint.name_lower())); } + DiagnosticWrapper(db) } -pub fn span_lint_and_then<T: LintContext, F>(cx: &T, lint: &'static Lint, sp: Span, - msg: &str, f: F) where F: Fn() { - cx.span_lint(lint, sp, msg); +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, + msg: &str, f: F) -> DiagnosticWrapper<'a> where F: Fn(&mut DiagnosticWrapper) { + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { - f(); - cx.sess().fileline_help(sp, &format!("for further information visit \ + f(&mut db); + db.fileline_help(sp, &format!("for further information visit \ https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())) + lint.name_lower())); } + db } /// return the base type for references and raw pointers diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 1a6dfd28728..f79440af121 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -4,7 +4,8 @@ #![deny(cyclomatic_complexity)] #![allow(unused)] -fn main() { //~ ERROR: The function has a cyclomatic complexity of 28. + +fn main() { //~ERROR The function has a cyclomatic complexity of 28 if true { println!("a"); } -- cgit 1.4.1-3-g733a5 From 32cf6e32f66980cea7630edacaa66d1bd0497b2e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 2 Jan 2016 16:33:44 +0530 Subject: Improve documentation on match_ref_pats (fixes #532) --- README.md | 2 +- src/matches.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 9fe59d4fdaf..0e0a60537b4 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ name [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead -[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match has all arms prefixed with `&`; the match expression can be dereferenced instead +[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/matches.rs b/src/matches.rs index 460893d93ab..aaf41a391cb 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -22,7 +22,7 @@ use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_bloc declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ is `_ => {}`) is used; recommends `if let` instead"); -/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It is `Warn` by default. +/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. It is `Warn` by default. /// /// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. /// @@ -38,7 +38,7 @@ declare_lint!(pub SINGLE_MATCH, Warn, /// } /// ``` declare_lint!(pub MATCH_REF_PATS, Warn, - "a match has all arms prefixed with `&`; the match expression can be \ + "a match or `if let` has all arms prefixed with `&`; the match expression can be \ dereferenced instead"); /// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. It is `Warn` by default. /// -- cgit 1.4.1-3-g733a5 From a745efd5665b1c9a0d7e6af3f34493093896b701 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 2 Jan 2016 21:41:48 +0530 Subject: Add smarter macro check for block_in_if (fixes #528) --- src/block_in_if_condition.rs | 7 ++++++- src/utils.rs | 4 ++++ tests/compile-fail/block_in_if_condition.rs | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 03265635b1d..ce01f591c59 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -79,13 +79,18 @@ impl LateLintPass for BlockInIfCondition { if let Some(ref ex) = block.expr { // don't dig into the expression here, just suggest that they remove // the block - + if differing_macro_contexts(expr.span, ex.span) { + return; + } span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_EXPR, check.span, BRACED_EXPR_MESSAGE, &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), snippet_block(cx, then.span, ".."))); } } else { + if differing_macro_contexts(expr.span, block.stmts[0].span) { + return; + } // move block higher span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, check.span, COMPLEX_BLOCK_MESSAGE, diff --git a/src/utils.rs b/src/utils.rs index 7c0ee09b3cd..90e8e27b4f0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -74,6 +74,10 @@ macro_rules! if_let_chain { }; } +/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one isn't) +pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { + sp1.expn_id != sp2.expn_id +} /// returns true if this expn_info was expanded by any macro pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index cd95fbd202c..0a68d80c339 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -5,6 +5,15 @@ #![deny(block_in_if_condition_stmt)] #![allow(unused)] + +macro_rules! blocky { + () => {{true}} +} + +fn macro_if() { + if blocky!() { + } +} 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' -- cgit 1.4.1-3-g733a5 From d8d3ee907bafc690f466e34ab790f568dbeeea36 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 2 Jan 2016 21:49:53 +0530 Subject: Add macro check for box vec (fixes #529) --- src/types.rs | 7 ++++--- tests/compile-fail/box_vec.rs | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index f332659188b..e119ef63436 100644 --- a/src/types.rs +++ b/src/types.rs @@ -9,9 +9,7 @@ use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; use syntax::ast::FloatTy::*; -use utils::{match_type, snippet, span_lint, span_help_and_lint}; -use utils::{is_from_for_desugar, in_macro, in_external_macro}; -use utils::{LL_PATH, VEC_PATH}; +use utils::*; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -50,6 +48,9 @@ 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 + } if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { if match_type(cx, inner, &VEC_PATH) { diff --git a/tests/compile-fail/box_vec.rs b/tests/compile-fail/box_vec.rs index 58e780f190c..4fd98cd52ff 100644 --- a/tests/compile-fail/box_vec.rs +++ b/tests/compile-fail/box_vec.rs @@ -3,6 +3,15 @@ #![plugin(clippy)] #![deny(clippy)] +macro_rules! boxit { + ($init:expr, $x:ty) => { + let _: Box<$x> = Box::new($init); + } +} + +fn test_macro() { + boxit!(Vec::new(), Vec<u8>); +} pub fn test(foo: Box<Vec<bool>>) { //~ ERROR you seem to be trying to use `Box<Vec<T>>` println!("{:?}", foo.get(0)) } @@ -14,4 +23,5 @@ pub fn test2(foo: Box<Fn(Vec<u32>)>) { // pass if #31 is fixed fn main(){ test(Box::new(Vec::new())); test2(Box::new(|v| println!("{:?}", v))); + test_macro(); } -- cgit 1.4.1-3-g733a5 From 52fbf1989df18ba669f1542bb6706a42bb5db6f1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Jan 2016 14:22:27 +0100 Subject: Add missing WRONG_PUB_SELF_CONVENTION in lint_array! and corresponding test --- src/methods.rs | 4 +-- tests/compile-fail/wrong_self_convention.rs | 45 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/wrong_self_convention.rs (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index a6200534e30..e70d26820b1 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -173,8 +173,8 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, - SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, OK_EXPECT, OPTION_MAP_UNWRAP_OR, - OPTION_MAP_UNWRAP_OR_ELSE) + SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, WRONG_PUB_SELF_CONVENTION, + OK_EXPECT, OPTION_MAP_UNWRAP_OR, OPTION_MAP_UNWRAP_OR_ELSE) } } diff --git a/tests/compile-fail/wrong_self_convention.rs b/tests/compile-fail/wrong_self_convention.rs new file mode 100644 index 00000000000..ca896a6b94b --- /dev/null +++ b/tests/compile-fail/wrong_self_convention.rs @@ -0,0 +1,45 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(wrong_self_convention)] +#![deny(wrong_pub_self_convention)] +#![allow(dead_code)] + +fn main() {} + +#[derive(Clone, Copy)] +struct Foo; + +impl Foo { + + fn as_i32(self) {} + fn into_i32(self) {} + fn is_i32(self) {} + fn to_i32(self) {} + fn from_i32(self) {} //~ERROR: methods called `from_*` usually take no self + + pub fn as_i64(self) {} + pub fn into_i64(self) {} + pub fn is_i64(self) {} + pub fn to_i64(self) {} + pub fn from_i64(self) {} //~ERROR: methods called `from_*` usually take no self + +} + +struct Bar; + +impl Bar { + + fn as_i32(self) {} //~ERROR: methods called `as_*` usually take self by reference + fn into_i32(&self) {} //~ERROR: methods called `into_*` usually take self by value + fn is_i32(self) {} //~ERROR: methods called `is_*` usually take self by reference + fn to_i32(self) {} //~ERROR: methods called `to_*` usually take self by reference + fn from_i32(self) {} //~ERROR: methods called `from_*` usually take no self + + pub fn as_i64(self) {} //~ERROR: methods called `as_*` usually take self by reference + pub fn into_i64(&self) {} //~ERROR: methods called `into_*` usually take self by value + pub fn is_i64(self) {} //~ERROR: methods called `is_*` usually take self by reference + pub fn to_i64(self) {} //~ERROR: methods called `to_*` usually take self by reference + pub fn from_i64(self) {} //~ERROR: methods called `from_*` usually take no self + +} -- cgit 1.4.1-3-g733a5 From abfb1d3ca1469d09b2c17e881f85e3f06b2357c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume1.gomez@gmail.com> Date: Sun, 3 Jan 2016 14:00:42 +0100 Subject: Add new lint on function naming check (the '_') --- README.md | 3 +- src/lib.rs | 1 + src/misc_early.rs | 38 ++++++++++++++++++++-- .../compile-fail/duplicate_underscore_argument.rs | 13 ++++++++ tests/compile-fail/unneeded_field_pattern.rs | 2 +- 5 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/duplicate_underscore_argument.rs (limited to 'src') diff --git a/README.md b/README.md index 0e0a60537b4..2cd93274952 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 88 lints included in this crate: +There are 89 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -24,6 +24,7 @@ name [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions +[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument)| warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do diff --git a/src/lib.rs b/src/lib.rs index 6d39cad20cd..6610173f2dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,6 +193,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, misc::USED_UNDERSCORE_BINDING, + misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, diff --git a/src/misc_early.rs b/src/misc_early.rs index dafe7816fe4..77114ccb493 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -1,8 +1,11 @@ -//use rustc_front::hir::*; - use rustc::lint::*; +use std::collections::HashMap; + use syntax::ast::*; +use syntax::codemap::Span; +use syntax::print::pprust; +use syntax::visit::FnKind; use utils::{span_lint, span_help_and_lint}; @@ -16,12 +19,22 @@ use utils::{span_lint, span_help_and_lint}; declare_lint!(pub UNNEEDED_FIELD_PATTERN, Warn, "Struct fields are bound to a wildcard instead of using `..`"); +/// **What it does:** This lint `Warn`s on function arguments having the same name except one starts with '_' +/// +/// **Why is this bad?** It makes source code documentation more difficult +/// +/// **Known problems:** None. +/// +/// **Example:** `fn foo(a: i32, _a: i32) {}` +declare_lint!(pub DUPLICATE_UNDERSCORE_ARGUMENT, Warn, + "Function arguments having names which only differ by an underscore"); + #[derive(Copy, Clone)] pub struct MiscEarly; impl LintPass for MiscEarly { fn get_lints(&self) -> LintArray { - lint_array!(UNNEEDED_FIELD_PATTERN) + lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT) } } @@ -77,4 +90,23 @@ impl EarlyLintPass for MiscEarly { } } } + + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + let mut registered_names : HashMap<String, Span> = HashMap::new(); + + for ref arg in &decl.inputs { + let arg_name = pprust::pat_to_string(&arg.pat); + + if arg_name.starts_with("_") { + if let Some(correspondance) = registered_names.get(&arg_name[1..].to_owned()) { + span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondance, + &format!("`{}` already exists, having another argument having almost \ + the same name makes code comprehension and documentation \ + more difficult", arg_name[1..].to_owned())); + } + } else { + registered_names.insert(arg_name.to_owned(), arg.pat.span.clone()); + } + } + } } diff --git a/tests/compile-fail/duplicate_underscore_argument.rs b/tests/compile-fail/duplicate_underscore_argument.rs new file mode 100644 index 00000000000..4d908e7f02b --- /dev/null +++ b/tests/compile-fail/duplicate_underscore_argument.rs @@ -0,0 +1,13 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(duplicate_underscore_argument)] +#[allow(dead_code, unused)] + +fn join_the_dark_side(darth: i32, _darth: i32) {} //~ERROR `darth` already exists +fn join_the_light_side(knight: i32, _master: i32) {} // the Force is strong with this one + +fn main() { + join_the_dark_side(0, 0); + join_the_light_side(0, 0); +} \ No newline at end of file diff --git a/tests/compile-fail/unneeded_field_pattern.rs b/tests/compile-fail/unneeded_field_pattern.rs index bbe72a7133e..9c7623d85b7 100644 --- a/tests/compile-fail/unneeded_field_pattern.rs +++ b/tests/compile-fail/unneeded_field_pattern.rs @@ -23,4 +23,4 @@ fn main() { Foo { b: 0, .. } => {} // should be OK Foo { .. } => {} // and the Force might be with this one } -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From 7a4d6aa8b7fbbcf1ff44bafb4cc82745c8cefee9 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Jan 2016 14:36:24 +0100 Subject: Use same error message for OPTION_UNWRAP_USED and RESULT_UNWRAP_USED IIRC, Result::expect wasn't stable until quite recently, which might be why there was 2 different error messages. --- src/methods.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index e70d26820b1..2aa3b040e55 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -258,14 +258,21 @@ impl LateLintPass for MethodsPass { fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); - if match_type(cx, obj_ty, &OPTION_PATH) { - span_lint(cx, OPTION_UNWRAP_USED, expr.span, - "used unwrap() on an Option value. If you don't want to handle the None case \ - gracefully, consider using expect() to provide a better panic message"); + let mess = if match_type(cx, obj_ty, &OPTION_PATH) { + Some((OPTION_UNWRAP_USED, "an Option", "None")) } else if match_type(cx, obj_ty, &RESULT_PATH) { - span_lint(cx, RESULT_UNWRAP_USED, expr.span, - "used unwrap() on a Result value. Graceful handling of Err values is preferred"); + Some((RESULT_UNWRAP_USED, "a Result", "Err")) + } + else { + None + }; + + if let Some((lint, kind, none_value)) = mess { + span_lint(cx, lint, expr.span, + &format!("used unwrap() on {} value. If you don't want to handle the {} \ + case gracefully, consider using expect() to provide a better panic + message", kind, none_value)); } } -- cgit 1.4.1-3-g733a5 From 780dedc500f9472d726a68bde8590c12ea54c187 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 3 Jan 2016 21:25:09 +0530 Subject: fixups --- README.md | 182 +++++++++++++++++++++++++++--------------------------- src/misc_early.rs | 25 ++++---- 2 files changed, 104 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 2cd93274952..3281adc5b51 100644 --- a/README.md +++ b/README.md @@ -8,97 +8,97 @@ A collection of lints to catch common mistakes and improve your Rust code. ##Lints There are 89 lints included in this crate: -name | default | meaning ----------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` -[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` -[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary -[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` -[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` -[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` -[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` -[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) -[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` -[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions -[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument)| warn | Function arguments having names which only differ by an underscore -[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected -[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do -[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` -[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` -[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases -[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended -[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` -[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block -[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque -[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) -[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead -[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead -[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant -[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 -[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead -[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type -[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do -[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice -[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields -[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect -[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file -[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result -[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` -[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` -[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing -[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` -[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught -[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 -[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern -[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled -[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` -[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` -[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` -[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` -[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value -[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait -[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` -[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op -[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries -[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. -[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions -[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) -[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) -[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference -[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` -[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 -[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 -[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop -[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions -[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore -[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types -[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop -[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator -[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention -[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention -[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN -[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing +name | default | meaning +---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` +[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` +[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary +[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` +[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) +[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions +[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore +[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do +[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` +[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended +[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` +[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block +[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) +[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead +[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead +[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant +[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 +[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead +[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type +[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do +[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice +[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect +[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file +[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result +[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` +[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` +[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing +[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` +[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught +[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 +[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern +[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled +[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` +[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` +[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` +[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` +[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value +[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` +[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op +[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries +[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. +[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions +[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) +[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference +[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` +[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 +[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 +[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions +[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore +[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types +[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator +[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention +[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention +[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN +[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/misc_early.rs b/src/misc_early.rs index 77114ccb493..7a59c15275f 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -4,7 +4,6 @@ use std::collections::HashMap; use syntax::ast::*; use syntax::codemap::Span; -use syntax::print::pprust; use syntax::visit::FnKind; use utils::{span_lint, span_help_and_lint}; @@ -19,9 +18,9 @@ use utils::{span_lint, span_help_and_lint}; declare_lint!(pub UNNEEDED_FIELD_PATTERN, Warn, "Struct fields are bound to a wildcard instead of using `..`"); -/// **What it does:** This lint `Warn`s on function arguments having the same name except one starts with '_' +/// **What it does:** This lint `Warn`s on function arguments having the similar names differing by an underscore /// -/// **Why is this bad?** It makes source code documentation more difficult +/// **Why is this bad?** It affects code readability /// /// **Known problems:** None. /// @@ -95,17 +94,19 @@ impl EarlyLintPass for MiscEarly { let mut registered_names : HashMap<String, Span> = HashMap::new(); for ref arg in &decl.inputs { - let arg_name = pprust::pat_to_string(&arg.pat); + if let PatIdent(_, sp_ident, None) = arg.pat.node { + let arg_name = sp_ident.node.to_string(); - if arg_name.starts_with("_") { - if let Some(correspondance) = registered_names.get(&arg_name[1..].to_owned()) { - span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondance, - &format!("`{}` already exists, having another argument having almost \ - the same name makes code comprehension and documentation \ - more difficult", arg_name[1..].to_owned())); + if arg_name.starts_with("_") { + if let Some(correspondance) = registered_names.get(&arg_name[1..]) { + span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondance, + &format!("`{}` already exists, having another argument having almost \ + the same name makes code comprehension and documentation \ + more difficult", arg_name[1..].to_owned())); + } + } else { + registered_names.insert(arg_name, arg.pat.span.clone()); } - } else { - registered_names.insert(arg_name.to_owned(), arg.pat.span.clone()); } } } -- cgit 1.4.1-3-g733a5 From 0c6e385493407815068b9ca618a0baa09ad20d08 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 22 Dec 2015 00:35:56 +0100 Subject: Implement a HashMapLint --- README.md | 3 +- src/hashmap.rs | 73 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/loops.rs | 4 +-- src/utils.rs | 17 +++++----- tests/compile-fail/hashmap.rs | 25 +++++++++++++++ 6 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 src/hashmap.rs create mode 100644 tests/compile-fail/hashmap.rs (limited to 'src') diff --git a/README.md b/README.md index 0d854b384fe..f1c28888636 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 90 lints included in this crate: +There are 91 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -31,6 +31,7 @@ name [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[hashmap_entry](https://github.com/Manishearth/rust-clippy/wiki#hashmap_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases diff --git a/src/hashmap.rs b/src/hashmap.rs new file mode 100644 index 00000000000..6448847ee2f --- /dev/null +++ b/src/hashmap.rs @@ -0,0 +1,73 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::codemap::Span; +use utils::{get_item_name, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; +use utils::HASHMAP_PATH; + +/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap`. +/// +/// **Why is this bad?** Using `HashMap::entry` is more efficient. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** `if !m.contains_key(&k) { m.insert(k, v) }` +declare_lint! { + pub HASHMAP_ENTRY, + Warn, + "use of `contains_key` followed by `insert` on a `HashMap`" +} + +#[derive(Copy,Clone)] +pub struct HashMapLint; + +impl LintPass for HashMapLint { + fn get_lints(&self) -> LintArray { + lint_array!(HASHMAP_ENTRY) + } +} + +impl LateLintPass for HashMapLint { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! { + [ + let ExprIf(ref check, ref then, _) = expr.node, + let ExprUnary(UnOp::UnNot, ref check) = check.node, + let ExprMethodCall(ref name, _, ref params) = check.node, + params.len() >= 2, + name.node.as_str() == "contains_key" + ], { + let map = ¶ms[0]; + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); + + if match_type(cx, obj_ty, &HASHMAP_PATH) { + if let Some(ref then) = then.expr { + check_for_insert(cx, expr.span, map, then); + } + else if then.stmts.len() == 1 { + if let StmtSemi(ref stmt, _) = then.stmts[0].node { + check_for_insert(cx, expr.span, map, stmt); + } + } + } + } + } + } +} + +fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, expr: &Expr) { + if_let_chain! { + [ + let ExprMethodCall(ref name, _, ref params) = expr.node, + params.len() >= 3, + name.node.as_str() == "insert", + get_item_name(cx, map) == get_item_name(cx, &*params[0]) + ], { + span_help_and_lint(cx, HASHMAP_ENTRY, span, + "usage of `contains_key` followed by `insert` on `HashMap`", + &format!("Consider using `{}.entry({}).or_insert({})`", + snippet(cx, map.span, ".."), + snippet(cx, params[1].span, ".."), + snippet(cx, params[2].span, ".."))); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e79f0f6ca22..76c04d53a0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod cyclomatic_complexity; pub mod escape; +pub mod hashmap; pub mod misc_early; pub mod array_indexing; pub mod panic; @@ -104,6 +105,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::UnitCmp); reg.register_late_lint_pass(box loops::LoopsPass); reg.register_late_lint_pass(box lifetimes::LifetimePass); + reg.register_late_lint_pass(box hashmap::HashMapLint); reg.register_late_lint_pass(box ranges::StepByZero); reg.register_late_lint_pass(box types::CastPass); reg.register_late_lint_pass(box types::TypeComplexityPass); @@ -158,6 +160,7 @@ pub fn plugin_registrar(reg: &mut Registry) { eq_op::EQ_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, + hashmap::HASHMAP_ENTRY, identity_op::IDENTITY_OP, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, diff --git a/src/loops.rs b/src/loops.rs index 9f103f4e7a8..a0454a325e4 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -13,7 +13,7 @@ use syntax::ast::Lit_::*; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal, get_enclosing_block}; -use utils::{VEC_PATH, LL_PATH}; +use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. /// @@ -457,7 +457,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { is_iterable_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || - match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) || + match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || diff --git a/src/utils.rs b/src/utils.rs index 90e8e27b4f0..76b57317c31 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,15 +18,16 @@ use std::ops::{Deref, DerefMut}; pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for -pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; -pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; -pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; -pub const BEGIN_UNWIND:[&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/hashmap.rs b/tests/compile-fail/hashmap.rs new file mode 100644 index 00000000000..9b15acf4072 --- /dev/null +++ b/tests/compile-fail/hashmap.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused)] + +#![deny(hashmap_entry)] + +use std::collections::HashMap; +use std::hash::Hash; + +fn insert_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { m.insert(k, v); } //~ERROR: usage of `contains_key` followed by `insert` on `HashMap` +} + +fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { m.insert(k, v) } else { None }; //~ERROR: usage of `contains_key` followed by `insert` on `HashMap` +} + +/* TODO +fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { + if !m.contains_key(&k) { m.insert(o, v) } else { None }; +} +*/ + +fn main() { +} -- cgit 1.4.1-3-g733a5 From 54b70ed8e1ead333c0e45d21ff3daa89061a8b05 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Jan 2016 15:49:25 +0100 Subject: Move eq_op::is_exp_equal to utils --- src/eq_op.rs | 71 +--------------------------------------------------------- src/strings.rs | 3 +-- src/utils.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 4865596b630..3d2f32e6c7f 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,10 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc_front::util as ast_util; -use syntax::ptr::P; -use consts::constant; -use utils::span_lint; +use utils::{is_exp_equal, span_lint}; /// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). It is `Warn` by default. /// @@ -40,57 +38,6 @@ impl LateLintPass for EqOp { } } -pub fn is_exp_equal(cx: &LateContext, left : &Expr, right : &Expr) -> bool { - if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { - if l == r { - return true; - } - } - match (&left.node, &right.node) { - (&ExprField(ref lfexp, ref lfident), - &ExprField(ref rfexp, ref rfident)) => - lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), - (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprPath(ref lqself, ref lsubpath), - &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, is_qself_equal) && - is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => - is_exps_equal(cx, ltup, rtup), - (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => - is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), - _ => false - } -} - -fn is_exps_equal(cx: &LateContext, left : &[P<Expr>], right : &[P<Expr>]) -> bool { - over(left, right, |l, r| is_exp_equal(cx, l, r)) -} - -fn is_path_equal(left : &Path, right : &Path) -> bool { - // The == of idents doesn't work with different contexts, - // we have to be explicit about hygiene - left.global == right.global && over(&left.segments, &right.segments, - |l, r| l.identifier.name == r.identifier.name - && l.parameters == r.parameters) -} - -fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { - left.ty.node == right.ty.node && left.position == right.position -} - -fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool { - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| - eq_fn(x, y)) -} - -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool - where F: FnMut(&X, &X) -> bool { - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, - |y| eq_fn(x, y))) -} fn is_cmp_or_bit(op : &BinOp) -> bool { match op.node { @@ -99,19 +46,3 @@ fn is_cmp_or_bit(op : &BinOp) -> bool { _ => false } } - -fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { - match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => - lmut.mutbl == rmut.mutbl && - is_cast_ty_equal(&*lmut.ty, &*rmut.ty), - (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => - lrmut.mutbl == rrmut.mutbl && - is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty), - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => - both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), - (&TyInfer, &TyInfer) => true, - _ => false - } -} diff --git a/src/strings.rs b/src/strings.rs index 861ae0bb012..2baf26095b7 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -7,8 +7,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use eq_op::is_exp_equal; -use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::{is_exp_equal, match_type, span_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). It is `Allow` by default. diff --git a/src/utils.rs b/src/utils.rs index 76b57317c31..1b6c75a3b78 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,6 +10,7 @@ use syntax::ast::Lit_::*; use syntax::ast; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; +use consts::constant; use rustc::session::Session; use std::str::FromStr; @@ -493,3 +494,71 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } } } + +pub fn is_exp_equal(cx: &LateContext, left : &Expr, right : &Expr) -> bool { + if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { + if l == r { + return true; + } + } + match (&left.node, &right.node) { + (&ExprField(ref lfexp, ref lfident), + &ExprField(ref rfexp, ref rfident)) => + lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), + (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, + (&ExprPath(ref lqself, ref lsubpath), + &ExprPath(ref rqself, ref rsubpath)) => + both(lqself, rqself, is_qself_equal) && + is_path_equal(lsubpath, rsubpath), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => + is_exps_equal(cx, ltup, rtup), + (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => + is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), + _ => false + } +} + +fn is_exps_equal(cx: &LateContext, left : &[P<Expr>], right : &[P<Expr>]) -> bool { + over(left, right, |l, r| is_exp_equal(cx, l, r)) +} + +fn is_path_equal(left : &Path, right : &Path) -> bool { + // The == of idents doesn't work with different contexts, + // we have to be explicit about hygiene + left.global == right.global && over(&left.segments, &right.segments, + |l, r| l.identifier.name == r.identifier.name + && l.parameters == r.parameters) +} + +fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { + left.ty.node == right.ty.node && left.position == right.position +} + +fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool { + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| + eq_fn(x, y)) +} + +fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool + where F: FnMut(&X, &X) -> bool { + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, + |y| eq_fn(x, y))) +} + +fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { + match (&left.node, &right.node) { + (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => + lmut.mutbl == rmut.mutbl && + is_cast_ty_equal(&*lmut.ty, &*rmut.ty), + (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => + lrmut.mutbl == rrmut.mutbl && + is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty), + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => + both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), + (&TyInfer, &TyInfer) => true, + _ => false + } +} -- cgit 1.4.1-3-g733a5 From d0bb71e6a23d45b4e367007da1099df9db424b8d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Jan 2016 16:31:28 +0100 Subject: Finish the HashMapLint --- src/hashmap.rs | 34 ++++++++++++++++++++++------------ tests/compile-fail/hashmap.rs | 4 +--- 2 files changed, 23 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/hashmap.rs b/src/hashmap.rs index 6448847ee2f..14f535b3820 100644 --- a/src/hashmap.rs +++ b/src/hashmap.rs @@ -1,14 +1,18 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use utils::{get_item_name, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; +use utils::{get_item_name, is_exp_equal, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; use utils::HASHMAP_PATH; /// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap`. /// /// **Why is this bad?** Using `HashMap::entry` is more efficient. /// -/// **Known problems:** Hopefully none. +/// **Known problems:** Some false negatives, eg.: +/// ``` +/// let k = &key; +/// if !m.contains_key(k) { m.insert(k.clone(), v); } +/// ``` /// /// **Example:** `if !m.contains_key(&k) { m.insert(k, v) }` declare_lint! { @@ -36,16 +40,22 @@ impl LateLintPass for HashMapLint { params.len() >= 2, name.node.as_str() == "contains_key" ], { + let key = match params[1].node { + ExprAddrOf(_, ref key) => key, + _ => return + }; + let map = ¶ms[0]; let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); if match_type(cx, obj_ty, &HASHMAP_PATH) { if let Some(ref then) = then.expr { - check_for_insert(cx, expr.span, map, then); + check_for_insert(cx, expr.span, map, key, then); } - else if then.stmts.len() == 1 { - if let StmtSemi(ref stmt, _) = then.stmts[0].node { - check_for_insert(cx, expr.span, map, stmt); + + for stmt in &then.stmts { + if let StmtSemi(ref stmt, _) = stmt.node { + check_for_insert(cx, expr.span, map, key, stmt); } } } @@ -54,20 +64,20 @@ impl LateLintPass for HashMapLint { } } -fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, expr: &Expr) { +fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr) { if_let_chain! { [ let ExprMethodCall(ref name, _, ref params) = expr.node, - params.len() >= 3, + params.len() == 3, name.node.as_str() == "insert", - get_item_name(cx, map) == get_item_name(cx, &*params[0]) + get_item_name(cx, map) == get_item_name(cx, &*params[0]), + is_exp_equal(cx, key, ¶ms[1]) ], { span_help_and_lint(cx, HASHMAP_ENTRY, span, "usage of `contains_key` followed by `insert` on `HashMap`", - &format!("Consider using `{}.entry({}).or_insert({})`", + &format!("Consider using `{}.entry({})`", snippet(cx, map.span, ".."), - snippet(cx, params[1].span, ".."), - snippet(cx, params[2].span, ".."))); + snippet(cx, params[1].span, ".."))); } } } diff --git a/tests/compile-fail/hashmap.rs b/tests/compile-fail/hashmap.rs index 9b15acf4072..9aeacac0e14 100644 --- a/tests/compile-fail/hashmap.rs +++ b/tests/compile-fail/hashmap.rs @@ -15,11 +15,9 @@ fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { m.insert(k, v) } else { None }; //~ERROR: usage of `contains_key` followed by `insert` on `HashMap` } -/* TODO fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { - if !m.contains_key(&k) { m.insert(o, v) } else { None }; + if !m.contains_key(&k) { m.insert(o, v); } } -*/ fn main() { } -- cgit 1.4.1-3-g733a5 From 9945bd82a8273f9c5506e9c26d51b312188d620f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Jan 2016 17:19:49 +0100 Subject: Add better error messages for HashMapLint --- src/hashmap.rs | 37 ++++++++++++++++++++++++++++--------- tests/compile-fail/hashmap.rs | 24 +++++++++++++++++++++--- 2 files changed, 49 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/hashmap.rs b/src/hashmap.rs index 14f535b3820..095a00e3777 100644 --- a/src/hashmap.rs +++ b/src/hashmap.rs @@ -14,7 +14,14 @@ use utils::HASHMAP_PATH; /// if !m.contains_key(k) { m.insert(k.clone(), v); } /// ``` /// -/// **Example:** `if !m.contains_key(&k) { m.insert(k, v) }` +/// **Example:** +/// ```rust +/// if !m.contains_key(&k) { m.insert(k, v) } +/// ``` +/// can be rewritten as: +/// ```rust +/// m.entry(k).or_insert(v); +/// ``` declare_lint! { pub HASHMAP_ENTRY, Warn, @@ -49,13 +56,15 @@ impl LateLintPass for HashMapLint { let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); if match_type(cx, obj_ty, &HASHMAP_PATH) { + let sole_expr = if then.expr.is_some() { 1 } else { 0 } + then.stmts.len() == 1; + if let Some(ref then) = then.expr { - check_for_insert(cx, expr.span, map, key, then); + check_for_insert(cx, expr.span, map, key, then, sole_expr); } for stmt in &then.stmts { if let StmtSemi(ref stmt, _) = stmt.node { - check_for_insert(cx, expr.span, map, key, stmt); + check_for_insert(cx, expr.span, map, key, stmt, sole_expr); } } } @@ -64,7 +73,7 @@ impl LateLintPass for HashMapLint { } } -fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr) { +fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr, sole_expr: bool) { if_let_chain! { [ let ExprMethodCall(ref name, _, ref params) = expr.node, @@ -73,11 +82,21 @@ fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: get_item_name(cx, map) == get_item_name(cx, &*params[0]), is_exp_equal(cx, key, ¶ms[1]) ], { - span_help_and_lint(cx, HASHMAP_ENTRY, span, - "usage of `contains_key` followed by `insert` on `HashMap`", - &format!("Consider using `{}.entry({})`", - snippet(cx, map.span, ".."), - snippet(cx, params[1].span, ".."))); + if sole_expr { + span_help_and_lint(cx, HASHMAP_ENTRY, span, + "usage of `contains_key` followed by `insert` on `HashMap`", + &format!("Consider using `{}.entry({}).or_insert({})`", + snippet(cx, map.span, ".."), + snippet(cx, params[1].span, ".."), + snippet(cx, params[2].span, ".."))); + } + else { + span_help_and_lint(cx, HASHMAP_ENTRY, span, + "usage of `contains_key` followed by `insert` on `HashMap`", + &format!("Consider using `{}.entry({})`", + snippet(cx, map.span, ".."), + snippet(cx, params[1].span, ".."))); + } } } } diff --git a/tests/compile-fail/hashmap.rs b/tests/compile-fail/hashmap.rs index 9aeacac0e14..a53566a794e 100644 --- a/tests/compile-fail/hashmap.rs +++ b/tests/compile-fail/hashmap.rs @@ -7,12 +7,30 @@ use std::collections::HashMap; use std::hash::Hash; -fn insert_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { m.insert(k, v); } //~ERROR: usage of `contains_key` followed by `insert` on `HashMap` +fn foo() {} + +fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { m.insert(k, v); } + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k).or_insert(v)` +} + +fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { foo(); m.insert(k, v); } + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k)` } fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { m.insert(k, v) } else { None }; //~ERROR: usage of `contains_key` followed by `insert` on `HashMap` + if !m.contains_key(&k) { m.insert(k, v) } else { None }; + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k).or_insert(v)` +} + +fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k)` } fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { -- cgit 1.4.1-3-g733a5 From c9342d01213ca1663d2cdf23289bae024823ae6a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 4 Jan 2016 09:56:12 +0530 Subject: fmt clippy --- src/approx_const.rs | 46 +++-- src/array_indexing.rs | 3 +- src/attrs.rs | 38 ++-- src/bit_mask.rs | 225 +++++++++++++--------- src/block_in_if_condition.rs | 37 ++-- src/collapsible_if.rs | 41 ++-- src/consts.rs | 443 +++++++++++++++++++++++++++---------------- src/cyclomatic_complexity.rs | 39 ++-- src/eq_op.rs | 24 ++- src/escape.rs | 40 ++-- src/eta_reduction.rs | 14 +- src/identity_op.rs | 20 +- src/len_zero.rs | 128 ++++++++----- src/lib.rs | 10 +- src/lifetimes.rs | 54 +++--- src/loops.rs | 374 ++++++++++++++++++++---------------- src/map_clone.rs | 20 +- src/matches.rs | 234 ++++++++++++----------- src/methods.rs | 420 ++++++++++++++++++++++++++-------------- src/minmax.rs | 35 ++-- src/misc.rs | 145 ++++++++------ src/misc_early.rs | 39 ++-- src/mut_mut.rs | 42 ++-- src/mut_reference.rs | 20 +- src/mutex_atomic.rs | 16 +- src/needless_bool.rs | 45 +++-- src/needless_features.rs | 14 +- src/needless_update.rs | 7 +- src/no_effect.rs | 7 +- src/open_options.rs | 151 +++++++++++---- src/precedence.rs | 68 ++++--- src/ptr_arg.rs | 17 +- src/ranges.rs | 19 +- src/returns.rs | 34 ++-- src/shadow.rs | 166 +++++++++------- src/strings.rs | 30 +-- src/temporary_assignment.rs | 5 +- src/transmute.rs | 3 +- src/types.rs | 253 +++++++++++++++--------- src/unicode.rs | 46 +++-- src/utils.rs | 301 ++++++++++++++--------------- 41 files changed, 2186 insertions(+), 1487 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 05829838903..2c8779ae737 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -21,24 +21,22 @@ declare_lint! { } // Tuples are of the form (constant, name, min_digits) -const KNOWN_CONSTS : &'static [(f64, &'static str, usize)] = &[ - (f64::E, "E", 4), - (f64::FRAC_1_PI, "FRAC_1_PI", 4), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), - (f64::FRAC_2_PI, "FRAC_2_PI", 5), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), - (f64::FRAC_PI_2, "FRAC_PI_2", 5), - (f64::FRAC_PI_3, "FRAC_PI_3", 5), - (f64::FRAC_PI_4, "FRAC_PI_4", 5), - (f64::FRAC_PI_6, "FRAC_PI_6", 5), - (f64::FRAC_PI_8, "FRAC_PI_8", 5), - (f64::LN_10, "LN_10", 5), - (f64::LN_2, "LN_2", 5), - (f64::LOG10_E, "LOG10_E", 5), - (f64::LOG2_E, "LOG2_E", 5), - (f64::PI, "PI", 3), - (f64::SQRT_2, "SQRT_2", 5), -]; +const KNOWN_CONSTS: &'static [(f64, &'static str, usize)] = &[(f64::E, "E", 4), + (f64::FRAC_1_PI, "FRAC_1_PI", 4), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), + (f64::FRAC_2_PI, "FRAC_2_PI", 5), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), + (f64::FRAC_PI_2, "FRAC_PI_2", 5), + (f64::FRAC_PI_3, "FRAC_PI_3", 5), + (f64::FRAC_PI_4, "FRAC_PI_4", 5), + (f64::FRAC_PI_6, "FRAC_PI_6", 5), + (f64::FRAC_PI_8, "FRAC_PI_8", 5), + (f64::LN_10, "LN_10", 5), + (f64::LN_2, "LN_2", 5), + (f64::LOG10_E, "LOG10_E", 5), + (f64::LOG2_E, "LOG2_E", 5), + (f64::PI, "PI", 3), + (f64::SQRT_2, "SQRT_2", 5)]; #[derive(Copy,Clone)] pub struct ApproxConstant; @@ -61,9 +59,8 @@ fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { match lit.node { LitFloat(ref s, TyF32) => check_known_consts(cx, e, s, "f32"), LitFloat(ref s, TyF64) => check_known_consts(cx, e, s, "f64"), - LitFloatUnsuffixed(ref s) => - check_known_consts(cx, e, s, "f{32, 64}"), - _ => () + LitFloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), + _ => (), } } @@ -71,9 +68,10 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &str, module: &str) { if let Ok(_) = s.parse::<f64>() { for &(constant, name, min_digits) in KNOWN_CONSTS { if is_approx_const(constant, s, min_digits) { - span_lint(cx, APPROX_CONSTANT, e.span, &format!( - "approximate value of `{}::{}` found. \ - Consider using it directly", module, &name)); + span_lint(cx, + APPROX_CONSTANT, + e.span, + &format!("approximate value of `{}::{}` found. Consider using it directly", module, &name)); return; } } diff --git a/src/array_indexing.rs b/src/array_indexing.rs index d72adac943f..cfa52f390d2 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -42,8 +42,7 @@ impl LateLintPass for ArrayIndexing { let index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); if let Ok(ConstVal::Uint(index)) = index { if size as u64 <= index { - span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, - "const index-expr is out of bounds"); + span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index-expr is out of bounds"); } } } diff --git a/src/attrs.rs b/src/attrs.rs index f0dbf390ebb..ec2cfcb0efc 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -57,13 +57,15 @@ impl LateLintPass for AttrPass { fn is_relevant_item(item: &Item) -> bool { if let ItemFn(_, _, _, _, _, ref block) = item.node { is_relevant_block(block) - } else { false } + } else { + false + } } fn is_relevant_impl(item: &ImplItem) -> bool { match item.node { ImplItemKind::Method(_, ref block) => is_relevant_block(block), - _ => false + _ => false, } } @@ -71,7 +73,7 @@ fn is_relevant_trait(item: &TraitItem) -> bool { match item.node { MethodTraitItem(_, None) => true, MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), - _ => false + _ => false, } } @@ -95,25 +97,33 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { !match_path(path, &BEGIN_UNWIND) - } else { true } + } else { + true + } } - _ => true + _ => true, } } -fn check_attrs(cx: &LateContext, span: Span, name: &Name, - attrs: &[Attribute]) { - if in_macro(cx, span) { return; } +fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { + if in_macro(cx, span) { + return; + } for attr in attrs { if let MetaList(ref inline, ref values) = attr.node.value.node { - if values.len() != 1 || inline != &"inline" { continue; } + if values.len() != 1 || inline != &"inline" { + continue; + } if let MetaWord(ref always) = values[0].node { - if always != &"always" { continue; } - span_lint(cx, INLINE_ALWAYS, attr.span, &format!( - "you have declared `#[inline(always)]` on `{}`. This \ - is usually a bad idea", - name)); + if always != &"always" { + continue; + } + span_lint(cx, + INLINE_ALWAYS, + attr.span, + &format!("you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", + name)); } } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index f4310db0fcb..c2fd3742066 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -95,18 +95,22 @@ impl LateLintPass for BitMask { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { if is_comparison_binop(cmp.node) { - fetch_int_literal(cx, right).map_or_else(|| - fetch_int_literal(cx, left).map_or((), |cmp_val| - check_compare(cx, right, invert_cmp(cmp.node), - cmp_val, &e.span)), - |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, - &e.span)) + fetch_int_literal(cx, right).map_or_else(|| { + fetch_int_literal(cx, left).map_or((), |cmp_val| { + check_compare(cx, + right, + invert_cmp(cmp.node), + cmp_val, + &e.span) + }) + }, + |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, &e.span)) } } } } -fn invert_cmp(cmp : BinOp_) -> BinOp_ { +fn invert_cmp(cmp: BinOp_) -> BinOp_ { match cmp { BiEq => BiEq, BiNe => BiNe, @@ -114,7 +118,7 @@ fn invert_cmp(cmp : BinOp_) -> BinOp_ { BiGt => BiLt, BiLe => BiGe, BiGe => BiLe, - _ => BiOr // Dummy + _ => BiOr, // Dummy } } @@ -124,114 +128,159 @@ fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64 if op.node != BiBitAnd && op.node != BiBitOr { return; } - fetch_int_literal(cx, right).or_else(|| fetch_int_literal( - cx, left)).map_or((), |mask| check_bit_mask(cx, op.node, - cmp_op, mask, cmp_value, span)) + fetch_int_literal(cx, right) + .or_else(|| fetch_int_literal(cx, left)) + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) } } -fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, - mask_value: u64, cmp_value: u64, span: &Span) { +fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { match cmp_op { - BiEq | BiNe => match bit_op { - BiBitAnd => if mask_value & cmp_value != cmp_value { - if cmp_value != 0 { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, cmp_value)); + BiEq | BiNe => { + match bit_op { + BiBitAnd => { + if mask_value & cmp_value != cmp_value { + if cmp_value != 0 { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` can never be equal to `{}`", + mask_value, + cmp_value)); + } + } else { + if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); + } + } } - } 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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` can never be equal to `{}`", + mask_value, + cmp_value)); + } } - }, - BiBitOr => if mask_value | cmp_value != cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, cmp_value)); - }, - _ => () - }, - BiLt | BiGe => match bit_op { - BiBitAnd => if mask_value < cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, cmp_value)); - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); + _ => (), + } + } + BiLt | BiGe => { + match bit_op { + BiBitAnd => { + if mask_value < cmp_value { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` will always be lower than `{}`", + mask_value, + cmp_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, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, cmp_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 => if mask_value <= cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, cmp_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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` will never be lower than `{}`", + mask_value, + cmp_value)); + } else { + check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); + } } - }, - BiBitOr => if mask_value > cmp_value { - span_lint(cx, BAD_BIT_MASK, *span, &format!( - "incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, cmp_value)); - } else { - check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); - }, - BiBitXor => - check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), - _ => () - }, - _ => () + BiBitXor => check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"), + _ => (), + } + } + BiLe | BiGt => { + match bit_op { + BiBitAnd => { + if mask_value <= cmp_value { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` will never be higher than `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` will always be higher than `{}`", + mask_value, + cmp_value)); + } else { + check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); + } + } + BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), + _ => (), + } + } + _ => (), } } fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { if c.is_power_of_two() && m < c { - span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c)); + span_lint(cx, + INEFFECTIVE_BIT_MASK, + span, + &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c)); } } fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { if (c + 1).is_power_of_two() && m <= c { - span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!( - "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, m, c)); + span_lint(cx, + INEFFECTIVE_BIT_MASK, + span, + &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c)); } } -fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> { +fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { if let LitInt(value, _) = lit_ptr.node { Some(value) //TODO: Handle sign - } else { None } + } 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: DefConst(def_id), ..}) => Some(def_id), - _ => None + { + // 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: DefConst(def_id), ..}) => Some(def_id), + _ => None, + } } + .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None)) + .and_then(|l| fetch_int_literal(cx, l)) } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None)) - .and_then(|l| fetch_int_literal(cx, l)), - _ => None + _ => None, } } diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index ce01f591c59..f7d8c95ee76 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -38,7 +38,7 @@ impl LintPass for BlockInIfCondition { } struct ExVisitor<'v> { - found_block: Option<&'v Expr> + found_block: Option<&'v Expr>, } impl<'v> Visitor<'v> for ExVisitor<'v> { @@ -51,7 +51,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { if let Some(ref ex) = block.expr { match ex.node { ExprBlock(_) => true, - _ => false + _ => false, } } else { false @@ -59,7 +59,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { } }; if complex { - self.found_block = Some(& expr); + self.found_block = Some(&expr); return; } } @@ -67,8 +67,9 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { } } -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'"; +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) { @@ -82,29 +83,33 @@ impl LateLintPass for BlockInIfCondition { if differing_macro_contexts(expr.span, ex.span) { return; } - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_EXPR, check.span, - BRACED_EXPR_MESSAGE, - &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), - snippet_block(cx, then.span, ".."))); + span_help_and_lint(cx, + BLOCK_IN_IF_CONDITION_EXPR, + check.span, + BRACED_EXPR_MESSAGE, + &format!("try\nif {} {} ... ", + snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, ".."))); } } else { if differing_macro_contexts(expr.span, block.stmts[0].span) { return; } // move block higher - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, check.span, - COMPLEX_BLOCK_MESSAGE, - &format!("try\nlet res = {};\nif res {} ... ", - snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, ".."))); + span_help_and_lint(cx, + BLOCK_IN_IF_CONDITION_STMT, + check.span, + COMPLEX_BLOCK_MESSAGE, + &format!("try\nlet res = {};\nif res {} ... ", + snippet_block(cx, block.span, ".."), + snippet_block(cx, then.span, ".."))); } } } else { let mut visitor = ExVisitor { found_block: None }; walk_expr(&mut visitor, check); if let Some(ref block) = visitor.found_block { - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, - COMPLEX_BLOCK_MESSAGE, ""); + span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE, ""); } } } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 775e9ec95fc..4a17d3a4608 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -52,23 +52,26 @@ impl LateLintPass for CollapsibleIf { fn check_if(cx: &LateContext, e: &Expr) { if let ExprIf(ref check, ref then, None) = e.node { if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = - single_stmt_of_block(then) { - if e.span.expn_id != sp.expn_id { - return; - } - span_help_and_lint(cx, COLLAPSIBLE_IF, e.span, - "this if statement can be collapsed", - &format!("try\nif {} && {} {}", - check_to_string(cx, check), check_to_string(cx, check_inner), - snippet_block(cx, content.span, ".."))); + single_stmt_of_block(then) { + if e.span.expn_id != sp.expn_id { + return; } + span_help_and_lint(cx, + COLLAPSIBLE_IF, + e.span, + "this if statement can be collapsed", + &format!("try\nif {} && {} {}", + check_to_string(cx, check), + check_to_string(cx, check_inner), + snippet_block(cx, content.span, ".."))); + } } } fn requires_brackets(e: &Expr) -> bool { match e.node { ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false, - _ => true + _ => true, } } @@ -84,16 +87,26 @@ fn single_stmt_of_block(block: &Block) -> Option<&Expr> { if block.stmts.len() == 1 && block.expr.is_none() { if let StmtExpr(ref expr, _) = block.stmts[0].node { single_stmt_of_expr(expr) - } else { None } + } else { + None + } } else { if block.stmts.is_empty() { - if let Some(ref p) = block.expr { Some(p) } else { None } - } else { None } + if let Some(ref p) = block.expr { + Some(p) + } else { + None + } + } else { + None + } } } fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> { if let ExprBlock(ref block) = expr.node { single_stmt_of_block(block) - } else { Some(expr) } + } else { + Some(expr) + } } diff --git a/src/consts.rs b/src/consts.rs index 9d3a9e7d7c2..171ba6f27f0 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -28,7 +28,7 @@ use syntax::ast::Sign::{self, Plus, Minus}; pub enum FloatWidth { Fw32, Fw64, - FwAny + FwAny, } impl From<FloatTy> for FloatWidth { @@ -85,9 +85,14 @@ impl Constant { match *self { ConstantByte(b) => Some(b as f64), ConstantFloat(ref s, _) => s.parse().ok(), - ConstantInt(i, ty) => Some(if is_negative(ty) { - -(i as f64) } else { i as f64 }), - _ => None + ConstantInt(i, ty) => { + Some(if is_negative(ty) { + -(i as f64) + } else { + i as f64 + }) + } + _ => None, } } } @@ -95,14 +100,14 @@ impl Constant { impl PartialEq for Constant { fn eq(&self, other: &Constant) -> bool { match (self, other) { - (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => - ls == rs && lsty == rsty, + (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => ls == rs && lsty == rsty, (&ConstantBinary(ref l), &ConstantBinary(ref r)) => l == r, (&ConstantByte(l), &ConstantByte(r)) => l == r, (&ConstantChar(l), &ConstantChar(r)) => l == r, - (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => lv == rv && - (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)), - (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => + (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => { + lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)) + } + (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => { if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -111,11 +116,13 @@ impl PartialEq for Constant { (Ok(l), Ok(r)) => l.eq(&r), _ => false, } - } else { false }, + } else { + false + } + } (&ConstantBool(l), &ConstantBool(r)) => l == r, (&ConstantVec(ref l), &ConstantVec(ref r)) => l == r, - (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => - ls == rs && lv == rv, + (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => ls == rs && lv == rv, (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l == r, _ => false, //TODO: Are there inter-type equalities? } @@ -125,19 +132,24 @@ impl PartialEq for Constant { impl PartialOrd for Constant { fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { - (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => - if lsty != rsty { None } else { Some(ls.cmp(rs)) }, + (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => { + if lsty != rsty { + None + } else { + Some(ls.cmp(rs)) + } + } (&ConstantByte(ref l), &ConstantByte(ref r)) => Some(l.cmp(r)), (&ConstantChar(ref l), &ConstantChar(ref r)) => Some(l.cmp(r)), - (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => - Some(match (is_negative(lty) && *lv != 0, - is_negative(rty) && *rv != 0) { + (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => { + Some(match (is_negative(lty) && *lv != 0, is_negative(rty) && *rv != 0) { (true, true) => rv.cmp(lv), (false, false) => lv.cmp(rv), (true, false) => Less, (false, true) => Greater, - }), - (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => + }) + } + (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => { if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -146,17 +158,21 @@ impl PartialOrd for Constant { (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), _ => None, } - } else { None }, + } else { + None + } + } (&ConstantBool(ref l), &ConstantBool(ref r)) => Some(l.cmp(r)), (&ConstantVec(ref l), &ConstantVec(ref r)) => l.partial_cmp(&r), - (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => + (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => { match lv.partial_cmp(rv) { Some(Equal) => Some(ls.cmp(rs)), x => x, - }, + } + } (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l.partial_cmp(r), - _ => None, //TODO: Are there any useful inter-type orderings? - } + _ => None, //TODO: Are there any useful inter-type orderings? + } } } @@ -178,9 +194,11 @@ impl fmt::Display for Constant { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { ConstantStr(ref s, _) => write!(fmt, "{:?}", s), - ConstantByte(ref b) => - write!(fmt, "b'").and_then(|_| format_byte(fmt, *b)) - .and_then(|_| write!(fmt, "'")), + ConstantByte(ref b) => { + write!(fmt, "b'") + .and_then(|_| format_byte(fmt, *b)) + .and_then(|_| write!(fmt, "'")) + } ConstantBinary(ref bs) => { try!(write!(fmt, "b\"")); for b in bs.iter() { @@ -191,14 +209,23 @@ impl fmt::Display for Constant { ConstantChar(ref c) => write!(fmt, "'{}'", c), ConstantInt(ref i, ref ity) => { let (sign, suffix) = match *ity { - LitIntType::SignedIntLit(ref sity, ref sign) => - (if let Sign::Minus = *sign { "-" } else { "" }, - sity.ty_to_string()), - LitIntType::UnsignedIntLit(ref uity) => - ("", uity.ty_to_string()), - LitIntType::UnsuffixedIntLit(ref sign) => - (if let Sign::Minus = *sign { "-" } else { "" }, - "".into()), + LitIntType::SignedIntLit(ref sity, ref sign) => { + (if let Sign::Minus = *sign { + "-" + } else { + "" + }, + sity.ty_to_string()) + } + LitIntType::UnsignedIntLit(ref uity) => ("", uity.ty_to_string()), + LitIntType::UnsuffixedIntLit(ref sign) => { + (if let Sign::Minus = *sign { + "-" + } else { + "" + }, + "".into()) + } }; write!(fmt, "{}{}{}", sign, i, suffix) } @@ -212,12 +239,22 @@ impl fmt::Display for Constant { } ConstantBool(ref b) => write!(fmt, "{}", b), ConstantRepeat(ref c, ref n) => write!(fmt, "[{}; {}]", c, n), - ConstantVec(ref v) => write!(fmt, "[{}]", - v.iter().map(|i| format!("{}", i)) - .collect::<Vec<_>>().join(", ")), - ConstantTuple(ref t) => write!(fmt, "({})", - t.iter().map(|i| format!("{}", i)) - .collect::<Vec<_>>().join(", ")), + ConstantVec(ref v) => { + write!(fmt, + "[{}]", + v.iter() + .map(|i| format!("{}", i)) + .collect::<Vec<_>>() + .join(", ")) + } + ConstantTuple(ref t) => { + write!(fmt, + "({})", + t.iter() + .map(|i| format!("{}", i)) + .collect::<Vec<_>>() + .join(", ")) + } } } } @@ -242,7 +279,9 @@ fn constant_not(o: Constant) -> Option<Constant> { ConstantInt(value, ty) => { let (nvalue, nty) = match ty { SignedIntLit(ity, Plus) => { - if value == ::std::u64::MAX { return None; } + if value == ::std::u64::MAX { + return None; + } (value + 1, SignedIntLit(ity, Minus)) } SignedIntLit(ity, Minus) => { @@ -258,30 +297,40 @@ fn constant_not(o: Constant) -> Option<Constant> { UintTy::TyU16 => ::std::u16::MAX as u64, UintTy::TyU32 => ::std::u32::MAX as u64, UintTy::TyU64 => ::std::u64::MAX, - UintTy::TyUs => { return None; } // refuse to guess + UintTy::TyUs => { + return None; + } // refuse to guess }; (!value & mask, UnsignedIntLit(ity)) } - UnsuffixedIntLit(_) => { return None; } // refuse to guess + UnsuffixedIntLit(_) => { + return None; + } // refuse to guess }; ConstantInt(nvalue, nty) } - _ => { return None; } + _ => { + return None; + } }) } fn constant_negate(o: Constant) -> Option<Constant> { Some(match o { - ConstantInt(value, ty) => - ConstantInt(value, match ty { - SignedIntLit(ity, sign) => - SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { return None; } - }), - ConstantFloat(is, ty) => - ConstantFloat(neg_float_str(is), ty), - _ => { return None; } + ConstantInt(value, ty) => { + ConstantInt(value, + match ty { + SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), + UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), + _ => { + return None; + } + }) + } + ConstantFloat(is, ty) => ConstantFloat(neg_float_str(is), ty), + _ => { + return None; + } }) } @@ -316,25 +365,42 @@ pub fn is_negative(ty: LitIntType) -> bool { fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { match (l, r) { - (SignedIntLit(lty, _), SignedIntLit(rty, _)) => if lty == rty { - Some(SignedIntLit(lty, s)) } else { None }, - (UnsignedIntLit(lty), UnsignedIntLit(rty)) => + (SignedIntLit(lty, _), SignedIntLit(rty, _)) => { + if lty == rty { + Some(SignedIntLit(lty, s)) + } else { + None + } + } + (UnsignedIntLit(lty), UnsignedIntLit(rty)) => { if s == Plus && lty == rty { Some(UnsignedIntLit(lty)) - } else { None }, + } else { + None + } + } (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => Some(UnsuffixedIntLit(s)), (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => Some(SignedIntLit(lty, s)), - (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => if rs == Plus { - Some(UnsignedIntLit(lty)) } else { None }, + (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => { + if rs == Plus { + Some(UnsignedIntLit(lty)) + } else { + None + } + } (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => Some(SignedIntLit(rty, s)), - (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => if ls == Plus { - Some(UnsignedIntLit(rty)) } else { None }, + (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => { + if ls == Plus { + Some(UnsignedIntLit(rty)) + } else { + None + } + } _ => None, } } -fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> - Option<Constant> { +fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> Option<Constant> { if neg > pos { unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) } else { @@ -342,70 +408,80 @@ fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> } } -fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> - Option<Constant> { - unify_int_type(lty, rty, if neg { Minus } else { Plus }).and_then( - |ty| l.checked_sub(r).map(|v| ConstantInt(v, ty))) +fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> Option<Constant> { + unify_int_type(lty, + rty, + if neg { + Minus + } else { + Plus + }) + .and_then(|ty| l.checked_sub(r).map(|v| ConstantInt(v, ty))) } pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { lcx: Some(lcx), needed_resolution: false }; + let mut cx = ConstEvalLateContext { + lcx: Some(lcx), + needed_resolution: false, + }; cx.expr(e).map(|cst| (cst, cx.needed_resolution)) } pub fn constant_simple(e: &Expr) -> Option<Constant> { - let mut cx = ConstEvalLateContext { lcx: None, needed_resolution: false }; + let mut cx = ConstEvalLateContext { + lcx: None, + needed_resolution: false, + }; cx.expr(e) } struct ConstEvalLateContext<'c, 'cc: 'c> { lcx: Option<&'c LateContext<'c, 'cc>>, - needed_resolution: bool + needed_resolution: bool, } impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { - /// simple constant folding: Insert an expression, get a constant or none. fn expr(&mut self, e: &Expr) -> Option<Constant> { match e.node { ExprPath(_, _) => self.fetch_path(e), ExprBlock(ref block) => self.block(block), - ExprIf(ref cond, ref then, ref otherwise) => - self.ifthenelse(cond, then, otherwise), + ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise), ExprLit(ref lit) => Some(lit_to_constant(&lit.node)), ExprVec(ref vec) => self.multi(vec).map(ConstantVec), ExprTup(ref tup) => self.multi(tup).map(ConstantTuple), - ExprRepeat(ref value, ref number) => - self.binop_apply(value, number, |v, n| - Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))), - ExprUnary(op, ref operand) => self.expr(operand).and_then( - |o| match op { - UnNot => constant_not(o), - UnNeg => constant_negate(o), - UnDeref => Some(o), - }), - ExprBinary(op, ref left, ref right) => - self.binop(op, left, right), - //TODO: add other expressions + ExprRepeat(ref value, ref number) => { + self.binop_apply(value, number, |v, n| Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))) + } + ExprUnary(op, ref operand) => { + self.expr(operand).and_then(|o| { + match op { + UnNot => constant_not(o), + UnNeg => constant_negate(o), + UnDeref => Some(o), + } + }) + } + ExprBinary(op, ref left, ref right) => self.binop(op, left, right), + // TODO: add other expressions _ => None, } } /// create `Some(Vec![..])` of all constants, unless there is any /// non-constant part - fn multi<E: Deref<Target=Expr> + Sized>(&mut self, vec: &[E]) -> - Option<Vec<Constant>> { - vec.iter().map(|elem| self.expr(elem)) - .collect::<Option<_>>() + fn multi<E: Deref<Target = Expr> + Sized>(&mut self, vec: &[E]) -> Option<Vec<Constant>> { + vec.iter() + .map(|elem| self.expr(elem)) + .collect::<Option<_>>() } /// lookup a possibly constant expression from a ExprPath fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { if let Some(lcx) = self.lcx { let mut maybe_id = None; - if let Some(&PathResolution { base_def: DefConst(id), ..}) = - lcx.tcx.def_map.borrow().get(&e.id) { + if let Some(&PathResolution { base_def: DefConst(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) { maybe_id = Some(id); } // separate if lets to avoid doubleborrowing the defmap @@ -426,63 +502,84 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn block(&mut self, block: &Block) -> Option<Constant> { if block.stmts.is_empty() { block.expr.as_ref().and_then(|ref b| self.expr(b)) - } else { None } + } else { + None + } } - fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) - -> Option<Constant> { + fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) -> Option<Constant> { if let Some(ConstantBool(b)) = self.expr(cond) { if b { self.block(then) } else { otherwise.as_ref().and_then(|expr| self.expr(expr)) } - } else { None } + } else { + None + } } fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { match op.node { - BiAdd => self.binop_apply(left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => - l8.checked_add(r8).map(ConstantByte), - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - if ln == rn { - unify_int_type(lty, rty, if ln { Minus } else { Plus }) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))) - } else { - if ln { - add_neg_int(r64, rty, l64, lty) + BiAdd => { + self.binop_apply(left, right, |l, r| { + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => l8.checked_add(r8).map(ConstantByte), + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + let (ln, rn) = (is_negative(lty), is_negative(rty)); + if ln == rn { + unify_int_type(lty, + rty, + if ln { + Minus + } else { + Plus + }) + .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) } else { - add_neg_int(l64, lty, r64, rty) + if ln { + add_neg_int(r64, rty, l64, lty) + } else { + add_neg_int(l64, lty, r64, rty) + } } } + // TODO: float (would need bignum library?) + _ => None, } - // TODO: float (would need bignum library?) - _ => None - }), - BiSub => self.binop_apply(left, right, |l, r| - match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => if r8 > l8 { - None } else { Some(ConstantByte(l8 - r8)) }, - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => - match (is_negative(lty), is_negative(rty)) { - (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), - (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), - (true, false) => unify_int_type(lty, rty, Minus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - (false, true) => unify_int_type(lty, rty, Plus) - .and_then(|ty| l64.checked_add(r64).map( - |v| ConstantInt(v, ty))), - }, - _ => None, - }), + }) + } + BiSub => { + self.binop_apply(left, right, |l, r| { + match (l, r) { + (ConstantByte(l8), ConstantByte(r8)) => { + if r8 > l8 { + None + } else { + Some(ConstantByte(l8 - r8)) + } + } + (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + match (is_negative(lty), is_negative(rty)) { + (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), + (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), + (true, false) => { + unify_int_type(lty, rty, Minus) + .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + } + (false, true) => { + unify_int_type(lty, rty, Plus) + .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + } + } + } + _ => None, + } + }) + } BiMul => self.divmul(left, right, u64::checked_mul), BiDiv => self.divmul(left, right, u64::checked_div), - //BiRem, + // BiRem, BiAnd => self.short_circuit(left, right, false), BiOr => self.short_circuit(left, right, true), BiBitXor => self.bitop(left, right, |x, y| x ^ y), @@ -490,70 +587,86 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BiBitOr => self.bitop(left, right, |x, y| (x | y)), BiShl => self.bitop(left, right, |x, y| x << y), BiShr => self.bitop(left, right, |x, y| x >> y), - BiEq => self.binop_apply(left, right, - |l, r| Some(ConstantBool(l == r))), - BiNe => self.binop_apply(left, right, - |l, r| Some(ConstantBool(l != r))), + BiEq => self.binop_apply(left, right, |l, r| Some(ConstantBool(l == r))), + BiNe => self.binop_apply(left, right, |l, r| Some(ConstantBool(l != r))), BiLt => self.cmp(left, right, Less, true), BiLe => self.cmp(left, right, Greater, false), BiGe => self.cmp(left, right, Less, false), BiGt => self.cmp(left, right, Greater, true), - _ => None + _ => None, } } - fn divmul<F>(&mut self, left: &Expr, right: &Expr, f: F) - -> Option<Constant> where F: Fn(u64, u64) -> Option<u64> { - self.binop_apply(left, right, |l, r| + fn divmul<F>(&mut self, left: &Expr, right: &Expr, f: F) -> Option<Constant> + where F: Fn(u64, u64) -> Option<u64> + { + self.binop_apply(left, right, |l, r| { match (l, r) { (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { - f(l64, r64).and_then(|value| - unify_int_type(lty, rty, if is_negative(lty) == - is_negative(rty) { Plus } else { Minus }) - .map(|ty| ConstantInt(value, ty))) + f(l64, r64).and_then(|value| { + unify_int_type(lty, + rty, + if is_negative(lty) == is_negative(rty) { + Plus + } else { + Minus + }) + .map(|ty| ConstantInt(value, ty)) + }) } _ => None, - }) + } + }) } - fn bitop<F>(&mut self, left: &Expr, right: &Expr, f: F) - -> Option<Constant> where F: Fn(u64, u64) -> u64 { - self.binop_apply(left, right, |l, r| match (l, r) { - (ConstantBool(l), ConstantBool(r)) => - Some(ConstantBool(f(l as u64, r as u64) != 0)), - (ConstantByte(l8), ConstantByte(r8)) => - Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), - (ConstantInt(l, lty), ConstantInt(r, rty)) => - unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)), - _ => None + fn bitop<F>(&mut self, left: &Expr, right: &Expr, f: F) -> Option<Constant> + where F: Fn(u64, u64) -> u64 + { + self.binop_apply(left, right, |l, r| { + match (l, r) { + (ConstantBool(l), ConstantBool(r)) => Some(ConstantBool(f(l as u64, r as u64) != 0)), + (ConstantByte(l8), ConstantByte(r8)) => Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), + (ConstantInt(l, lty), ConstantInt(r, rty)) => { + unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)) + } + _ => None, + } }) } fn cmp(&mut self, left: &Expr, right: &Expr, ordering: Ordering, b: bool) -> Option<Constant> { - self.binop_apply(left, right, |l, r| l.partial_cmp(&r).map(|o| - ConstantBool(b == (o == ordering)))) + self.binop_apply(left, + right, + |l, r| l.partial_cmp(&r).map(|o| ConstantBool(b == (o == ordering)))) } fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> - where F: Fn(Constant, Constant) -> Option<Constant> { + where F: Fn(Constant, Constant) -> Option<Constant> + { if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) { op(lc, rc) - } else { None } + } else { + None + } } fn short_circuit(&mut self, left: &Expr, right: &Expr, b: bool) -> Option<Constant> { - self.expr(left).and_then(|left| + self.expr(left).and_then(|left| { if let ConstantBool(lbool) = left { if lbool == b { Some(left) } else { - self.expr(right).and_then(|right| + self.expr(right).and_then(|right| { if let ConstantBool(_) = right { Some(right) - } else { None } - ) + } else { + None + } + }) } - } else { None } - ) + } else { + None + } + }) } } diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 7beb3296aac..d4375abcd05 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -27,9 +27,7 @@ pub struct CyclomaticComplexity { impl CyclomaticComplexity { pub fn new(limit: u64) -> Self { - CyclomaticComplexity { - limit: LimitStack::new(limit), - } + CyclomaticComplexity { limit: LimitStack::new(limit) } } } @@ -41,7 +39,9 @@ impl LintPass for CyclomaticComplexity { impl CyclomaticComplexity { fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) { - if in_macro(cx, span) { return; } + if in_macro(cx, span) { + return; + } let cfg = CFG::new(cx.tcx, block); let n = cfg.graph.len_nodes() as u64; let e = cfg.graph.len_edges() as u64; @@ -59,9 +59,11 @@ impl CyclomaticComplexity { } else { let rust_cc = cc + divergence - narms; if rust_cc > self.limit.limit() { - span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, span, - &format!("The function has a cyclomatic complexity of {}", rust_cc), - "You could split it up into multiple smaller functions"); + span_help_and_lint(cx, + CYCLOMATIC_COMPLEXITY, + span, + &format!("The function has a cyclomatic complexity of {}", rust_cc), + "You could split it up into multiple smaller functions"); } } } @@ -105,8 +107,8 @@ impl<'a> Visitor<'a> for MatchArmCounter { if arms_n > 1 { self.0 += arms_n - 2; } - }, - ExprClosure(..) => {}, + } + ExprClosure(..) => {} _ => walk_expr(self, e), } } @@ -125,8 +127,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> { self.0 += 1; } } - }, - ExprClosure(..) => {}, + } + ExprClosure(..) => {} _ => walk_expr(self, e), } } @@ -134,15 +136,22 @@ impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> { #[cfg(feature="debugging")] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { - cx.sess().span_bug(span, &format!("Clippy encountered a bug calculating cyclomatic complexity: \ - cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div));; + cx.sess().span_bug(span, + &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ + div = {}. Please file a bug report.", + cc, + narms, + div));; } #[cfg(not(feature="debugging"))] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { cx.sess().span_note_without_error(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ - (hide this message with `#[allow(cyclomatic_complexity)]`): \ - cc = {}, arms = {}, div = {}. Please file a bug report.", cc, narms, div)); + (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ + = {}, arms = {}, div = {}. Please file a bug report.", + cc, + narms, + div)); } } diff --git a/src/eq_op.rs b/src/eq_op.rs index 3d2f32e6c7f..31dc094385f 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -30,19 +30,29 @@ impl LateLintPass for EqOp { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { if is_cmp_or_bit(op) && is_exp_equal(cx, left, right) { - span_lint(cx, EQ_OP, e.span, &format!( - "equal expressions as operands to {}", - ast_util::binop_to_string(op.node))); + span_lint(cx, + EQ_OP, + e.span, + &format!("equal expressions as operands to {}", ast_util::binop_to_string(op.node))); } } } } -fn is_cmp_or_bit(op : &BinOp) -> bool { +fn is_cmp_or_bit(op: &BinOp) -> bool { match op.node { - BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | - BiBitXor | BiBitAnd | BiBitOr => true, - _ => false + BiEq | + BiLt | + BiLe | + BiGt | + BiGe | + BiNe | + BiAnd | + BiOr | + BiBitXor | + BiBitAnd | + BiBitOr => true, + _ => false, } } diff --git a/src/escape.rs b/src/escape.rs index 4b6a8258dbe..079fdcf09a0 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -43,13 +43,7 @@ impl LintPass for EscapePass { } impl LateLintPass for EscapePass { - fn check_fn(&mut self, - cx: &LateContext, - _: visit::FnKind, - decl: &FnDecl, - body: &Block, - _: Span, - id: NodeId) { + fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), false); let mut v = EscapeDelegate { @@ -70,11 +64,7 @@ impl LateLintPass for EscapePass { } impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { - fn consume(&mut self, - _: NodeId, - _: Span, - cmt: cmt<'tcx>, - mode: ConsumeMode) { + fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { if let Categorization::Local(lid) = cmt.cat { if self.set.contains(&lid) { @@ -119,12 +109,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn borrow(&mut self, - borrow_id: NodeId, - _: Span, - cmt: cmt<'tcx>, - _: ty::Region, - _: ty::BorrowKind, + fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, loan_cause: LoanCause) { if let Categorization::Local(lid) = cmt.cat { @@ -145,9 +130,15 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } else if LoanCause::AddrOf == loan_cause { // &x - if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = - self.cx.tcx.tables.borrow().adjustments - .get(&self.cx.tcx.map.get_parent_node(borrow_id)) { + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.cx + .tcx + .tables + .borrow() + .adjustments + .get(&self.cx + .tcx + .map + .get_parent_node(borrow_id)) { if adj.autoderefs <= 1 { // foo(&x) where no extra autoreffing is happening self.set.remove(&lid); @@ -162,10 +153,5 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } fn decl_without_init(&mut self, _: NodeId, _: Span) {} - fn mutate(&mut self, - _: NodeId, - _: Span, - _: cmt<'tcx>, - _: MutateMode) { - } + fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {} } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 6b561ff7a05..46c458c6bcb 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -73,22 +73,18 @@ fn check_closure(cx: &LateContext, expr: &Expr) { } if p.segments[0].identifier != ident.node { // The two idents should be the same - return + return; } } else { - return + return; } } else { - return + return; } } - span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, - "redundant closure found", - |db| { + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| { if let Some(snippet) = snippet_opt(cx, caller.span) { - db.span_suggestion(expr.span, - "remove closure as shown:", - snippet); + db.span_suggestion(expr.span, "remove closure as shown:", snippet); } }); } diff --git a/src/identity_op.rs b/src/identity_op.rs index 88a03e050be..fd5071d4013 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -27,26 +27,26 @@ impl LintPass for IdentityOp { impl LateLintPass for IdentityOp { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if in_macro(cx, e.span) { return; } + if in_macro(cx, e.span) { + return; + } if let ExprBinary(ref cmp, ref left, ref right) = e.node { match cmp.node { 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), + 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), + 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); } - _ => () + _ => (), } } } @@ -61,9 +61,11 @@ fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { 1 => !is_negative(ty) && v == 1, _ => unreachable!(), } { - span_lint(cx, IDENTITY_OP, span, &format!( - "the operation is ineffective. Consider reducing it to `{}`", - snippet(cx, arg, ".."))); + span_lint(cx, + IDENTITY_OP, + span, + &format!("the operation is ineffective. Consider reducing it to `{}`", + snippet(cx, arg, ".."))); } } } diff --git a/src/len_zero.rs b/src/len_zero.rs index d574fa2c336..6bc5bc4bf01 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -49,21 +49,18 @@ impl LintPass for LenZero { impl LateLintPass for LenZero { fn check_item(&mut self, cx: &LateContext, item: &Item) { match item.node { - ItemTrait(_, _, _, ref trait_items) => - check_trait_items(cx, item, trait_items), - ItemImpl(_, _, _, None, _, ref impl_items) => // only non-trait - check_impl_items(cx, item, impl_items), - _ => () + ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), + ItemImpl(_, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items), + _ => (), } } fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = - expr.node { + if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = expr.node { match cmp { BiEq => check_cmp(cx, expr.span, left, right, ""), BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), - _ => () + _ => (), } } } @@ -71,37 +68,52 @@ impl LateLintPass for LenZero { fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.name.as_str() == name && if let MethodTraitItem(ref sig, _) = - item.node { is_self_sig(sig) } else { false } + item.name.as_str() == name && + if let MethodTraitItem(ref sig, _) = item.node { + is_self_sig(sig) + } else { + false + } } if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - //span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident)); + // span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident)); for i in trait_items { if is_named_self(i, "len") { - span_lint(cx, LEN_WITHOUT_IS_EMPTY, i.span, - &format!("trait `{}` has a `.len(_: &Self)` method, but no \ - `.is_empty(_: &Self)` method. Consider adding one", + span_lint(cx, + LEN_WITHOUT_IS_EMPTY, + i.span, + &format!("trait `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ + Consider adding one", item.name)); } - }; + } } } fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.name.as_str() == name && if let ImplItemKind::Method(ref sig, _) = - item.node { is_self_sig(sig) } else { false } + item.name.as_str() == name && + if let ImplItemKind::Method(ref sig, _) = item.node { + is_self_sig(sig) + } else { + false + } } if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { for i in impl_items { if is_named_self(i, "len") { let s = i.span; - span_lint(cx, LEN_WITHOUT_IS_EMPTY, - Span{ lo: s.lo, hi: s.lo, expn_id: s.expn_id }, - &format!("item `{}` has a `.len(_: &Self)` method, but no \ - `.is_empty(_: &Self)` method. Consider adding one", + span_lint(cx, + LEN_WITHOUT_IS_EMPTY, + Span { + lo: s.lo, + hi: s.lo, + expn_id: s.expn_id, + }, + &format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ + Consider adding one", item.name)); return; } @@ -111,32 +123,40 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { fn is_self_sig(sig: &MethodSig) -> bool { if let SelfStatic = sig.explicit_self.node { - false } else { sig.decl.inputs.len() == 1 } + false + } else { + sig.decl.inputs.len() == 1 + } } fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, left) { - if name.as_str() == "is_empty" { return; } + if name.as_str() == "is_empty" { + return; + } } match (&left.node, &right.node) { - (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => - check_len_zero(cx, span, &method.node, args, lit, op), - (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => - check_len_zero(cx, span, &method.node, args, lit, op), - _ => () + (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => { + check_len_zero(cx, span, &method.node, args, lit, op) + } + (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => { + check_len_zero(cx, span, &method.node, args, lit, op) + } + _ => (), } } -fn check_len_zero(cx: &LateContext, span: Span, name: &Name, - args: &[P<Expr>], lit: &Lit, op: &str) { +fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitInt(0, _), ..} = *lit { - if name.as_str() == "len" && args.len() == 1 && - has_is_empty(cx, &args[0]) { - span_lint(cx, LEN_ZERO, span, &format!( - "consider replacing the len comparison with `{}{}.is_empty()`", - op, snippet(cx, args[0].span, "_"))); - } + if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { + span_lint(cx, + LEN_ZERO, + span, + &format!("consider replacing the len comparison with `{}{}.is_empty()`", + op, + snippet(cx, args[0].span, "_"))); + } } } @@ -145,31 +165,35 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { /// get a ImplOrTraitItem and return true if it matches is_empty(self) fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { if let MethodTraitItemId(def_id) = *id { - if let ty::MethodTraitItem(ref method) = - cx.tcx.impl_or_trait_item(def_id) { - method.name.as_str() == "is_empty" - && method.fty.sig.skip_binder().inputs.len() == 1 - } else { false } - } else { false } + if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { + method.name.as_str() == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 + } else { + false + } + } else { + false + } } /// check the inherent impl's items for an is_empty(self) method fn has_is_empty_impl(cx: &LateContext, id: &DefId) -> bool { let impl_items = cx.tcx.impl_items.borrow(); - cx.tcx.inherent_impls.borrow().get(id).map_or(false, - |ids| ids.iter().any(|iid| impl_items.get(iid).map_or(false, - |iids| iids.iter().any(|i| is_is_empty(cx, i))))) + cx.tcx.inherent_impls.borrow().get(id).map_or(false, |ids| { + ids.iter().any(|iid| impl_items.get(iid).map_or(false, |iids| iids.iter().any(|i| is_is_empty(cx, i)))) + }) } let ty = &walk_ptrs_ty(&cx.tcx.expr_ty(expr)); match ty.sty { - ty::TyTrait(_) => cx.tcx.trait_item_def_ids.borrow().get( - &ty.ty_to_def_id().expect("trait impl not found")).map_or(false, - |ids| ids.iter().any(|i| is_is_empty(cx, i))), - ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, - |id| has_is_empty_impl(cx, &id)), - ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => - has_is_empty_impl(cx, &id.did), + ty::TyTrait(_) => { + cx.tcx + .trait_item_def_ids + .borrow() + .get(&ty.ty_to_def_id().expect("trait impl not found")) + .map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))) + } + ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), + ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), ty::TyArray(..) => true, _ => false, } diff --git a/src/lib.rs b/src/lib.rs index 76c04d53a0b..2ac8e9044db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,9 @@ // this only exists to allow the "dogfood" integration test to work #[allow(dead_code)] -fn main() { println!("What are you doing? Don't run clippy as an executable"); } +fn main() { + println!("What are you doing? Don't run clippy as an executable"); +} #[macro_use] extern crate syntax; @@ -128,7 +130,8 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_late_lint_pass(box panic::PanicPass); - reg.register_lint_group("clippy_pedantic", vec![ + reg.register_lint_group("clippy_pedantic", + vec![ methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, @@ -147,7 +150,8 @@ pub fn plugin_registrar(reg: &mut Registry) { unicode::UNICODE_NOT_NFC, ]); - reg.register_lint_group("clippy", vec![ + reg.register_lint_group("clippy", + vec![ approx_const::APPROX_CONSTANT, array_indexing::OUT_OF_BOUNDS_INDEXING, attrs::INLINE_ALWAYS, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 6ae10c09455..2de916cfebc 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -47,15 +47,13 @@ impl LateLintPass for LifetimePass { fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let ImplItemKind::Method(ref sig, _) = item.node { - check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), - &sig.generics, item.span); + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); } } fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { - check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), - &sig.generics, item.span); + check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); } } } @@ -69,20 +67,20 @@ enum RefLt { } use self::RefLt::*; -fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, - generics: &Generics, span: Span) { +fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, generics: &Generics, span: Span) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } if could_use_elision(cx, decl, slf, &generics.lifetimes) { - span_lint(cx, NEEDLESS_LIFETIMES, span, + span_lint(cx, + NEEDLESS_LIFETIMES, + span, "explicit lifetimes given in parameter types where they could be elided"); } report_extra_lifetimes(cx, decl, &generics); } -fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, - named_lts: &[LifetimeDef]) -> bool { +fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, named_lts: &[LifetimeDef]) -> 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 @@ -102,7 +100,7 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> match slf.node { SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt), SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty), - _ => { } + _ => {} } } // extract lifetimes in input argument types @@ -147,8 +145,8 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> (&Named(n1), &Named(n2)) if n1 == n2 => true, (&Named(_), &Unnamed) => true, (&Unnamed, &Named(_)) => true, - _ => false // already elided, different named lifetimes - // or something static going on + _ => false, // already elided, different named lifetimes + // or something static going on } } else { false @@ -176,12 +174,15 @@ 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>, // context reference - lts: Vec<RefLt> + lts: Vec<RefLt>, } -impl <'v, 't> RefVisitor<'v, 't> { +impl<'v, 't> RefVisitor<'v, 't> { fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> { - RefVisitor { cx: cx, lts: Vec::new() } + RefVisitor { + cx: cx, + lts: Vec::new(), + } } fn record(&mut self, lifetime: &Option<Lifetime>) { @@ -211,13 +212,13 @@ impl <'v, 't> RefVisitor<'v, 't> { for _ in type_scheme.generics.regions.as_slice() { self.record(&None); } - }, + } DefTrait(def_id) => { let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; for _ in &trait_def.generics.regions { self.record(&None); } - }, + } _ => {} } } @@ -227,7 +228,6 @@ impl <'v, 't> RefVisitor<'v, 't> { } impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { - // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.record(&Some(*lifetime)); @@ -258,7 +258,9 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { let mut visitor = RefVisitor::new(cx); // walk the type F, it may not contain LT refs walk_ty(&mut visitor, &pred.bounded_ty); - if !visitor.lts.is_empty() { return true; } + if !visitor.lts.is_empty() { + return true; + } // if the bounds define new lifetimes, they are fine to occur let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); // now walk the bounds @@ -275,7 +277,9 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { WherePredicate::EqPredicate(ref pred) => { let mut visitor = RefVisitor::new(cx); walk_ty(&mut visitor, &pred.ty); - if !visitor.lts.is_empty() { return true; } + if !visitor.lts.is_empty() { + return true; + } } } } @@ -285,7 +289,6 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool { struct LifetimeChecker(HashMap<Name, Span>); impl<'v> Visitor<'v> for LifetimeChecker { - // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { self.0.remove(&lifetime.name); @@ -300,16 +303,15 @@ impl<'v> Visitor<'v> for LifetimeChecker { } } -fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, - generics: &Generics) { - let hs = generics.lifetimes.iter() +fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { + let hs = generics.lifetimes + .iter() .map(|lt| (lt.lifetime.name, lt.lifetime.span)) .collect(); let mut checker = LifetimeChecker(hs); walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); for (_, v) in checker.0 { - span_lint(cx, UNUSED_LIFETIMES, v, - "this lifetime isn't used in the function definition"); + span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); } } diff --git a/src/loops.rs b/src/loops.rs index a0454a325e4..91bb898629f 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -5,14 +5,13 @@ use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use rustc::middle::ty; use rustc::middle::def::DefLocal; use consts::{constant_simple, Constant}; -use rustc::front::map::Node::{NodeBlock}; +use rustc::front::map::Node::NodeBlock; use std::borrow::Cow; -use std::collections::{HashSet,HashMap}; +use std::collections::{HashSet, HashMap}; use syntax::ast::Lit_::*; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, - in_external_macro, expr_block, span_help_and_lint, is_integer_literal, - get_enclosing_block}; +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, + span_help_and_lint, is_integer_literal, get_enclosing_block}; use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. @@ -128,9 +127,14 @@ pub struct LoopsPass; impl LintPass for LoopsPass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP, - WHILE_LET_LOOP, UNUSED_COLLECT, REVERSE_RANGE_LOOP, - EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, + lint_array!(NEEDLESS_RANGE_LOOP, + EXPLICIT_ITER_LOOP, + ITER_NEXT_LOOP, + WHILE_LET_LOOP, + UNUSED_COLLECT, + REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, + EMPTY_LOOP, WHILE_LET_ON_ITERATOR) } } @@ -146,10 +150,11 @@ impl LateLintPass for LoopsPass { if let ExprLoop(ref block, _) = expr.node { // also check for empty `loop {}` statements if block.stmts.is_empty() && block.expr.is_none() { - span_lint(cx, EMPTY_LOOP, expr.span, - "empty `loop {}` detected. You may want to either \ - use `panic!()` or add `std::thread::sleep(..);` to \ - the loop body."); + span_lint(cx, + EMPTY_LOOP, + expr.span, + "empty `loop {}` detected. You may want to either use `panic!()` or add \ + `std::thread::sleep(..);` to the loop body."); } // extract the expression from the first statement (if any) in a block @@ -159,11 +164,10 @@ impl LateLintPass for LoopsPass { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // collect the remaining statements below the match let mut other_stuff = block.stmts - .iter() - .skip(1) - .map(|stmt| { - format!("{}", snippet(cx, stmt.span, "..")) - }).collect::<Vec<String>>(); + .iter() + .skip(1) + .map(|stmt| format!("{}", snippet(cx, stmt.span, ".."))) + .collect::<Vec<String>>(); if inner_stmt_expr.is_some() { // if we have a statement which has a match, if let Some(ref expr) = block.expr { @@ -174,29 +178,31 @@ impl LateLintPass for LoopsPass { // ensure "if let" compatible match structure match *source { - MatchSource::Normal | MatchSource::IfLetDesugar{..} => if - arms.len() == 2 && - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() && - // finally, check for "break" in the second clause - is_break_expr(&arms[1].body) - { - if in_external_macro(cx, expr.span) { return; } - let loop_body = if inner_stmt_expr.is_some() { - // FIXME: should probably be an ellipsis - // tabbing and newline is probably a bad idea, especially for large blocks - Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) - } else { - expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") - }; - span_help_and_lint(cx, WHILE_LET_LOOP, expr.span, - "this loop could be written as a `while let` loop", - &format!("try\nwhile let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, ".."), - loop_body)); - }, - _ => () + MatchSource::Normal | MatchSource::IfLetDesugar{..} => { + 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) { + return; + } + let loop_body = if inner_stmt_expr.is_some() { + // FIXME: should probably be an ellipsis + // tabbing and newline is probably a bad idea, especially for large blocks + Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) + } else { + expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") + }; + span_help_and_lint(cx, + WHILE_LET_LOOP, + expr.span, + "this loop could be written as a `while let` loop", + &format!("try\nwhile let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, ".."), + loop_body)); + } + } + _ => (), } } } @@ -204,21 +210,20 @@ impl LateLintPass for LoopsPass { if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { let pat = &arms[0].pats[0].node; if let (&PatEnum(ref path, Some(ref pat_args)), - &ExprMethodCall(method_name, _, ref method_args)) = - (pat, &match_expr.node) { + &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, &["core", "iter", "Iterator"]) && - lhs_constructor.identifier.name.as_str() == "Some" && - !is_iterator_used_after_while_let(cx, iter_expr) { + match_trait_method(cx, match_expr, &["core", "iter", "Iterator"]) && + lhs_constructor.identifier.name.as_str() == "Some" && + !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_help_and_lint(cx, WHILE_LET_ON_ITERATOR, expr.span, + span_help_and_lint(cx, + WHILE_LET_ON_ITERATOR, + expr.span, "this loop could be written as a `for` loop", - &format!("try\nfor {} in {} {{...}}", - loop_var, - iterator)); + &format!("try\nfor {} in {} {{...}}", loop_var, iterator)); } } } @@ -229,10 +234,12 @@ impl LateLintPass for LoopsPass { 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" && - match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { - span_lint(cx, UNUSED_COLLECT, expr.span, &format!( - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator")); + match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + span_lint(cx, + UNUSED_COLLECT, + expr.span, + &format!("you are collect()ing an iterator and throwing away the result. Consider \ + using an explicit for loop to exhaust the iterator")); } } } @@ -249,23 +256,38 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E // the var must be a single name if let PatIdent(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { cx: cx, var: ident.node.name, - indexed: HashSet::new(), nonindex: false }; + let mut visitor = VarVisitor { + cx: cx, + var: ident.node.name, + indexed: HashSet::new(), + nonindex: false, + }; walk_expr(&mut visitor, body); // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let indexed = visitor.indexed.into_iter().next().expect( - "Len was nonzero, but no contents found"); + let indexed = visitor.indexed + .into_iter() + .next() + .expect("Len was nonzero, but no contents found"); if visitor.nonindex { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is used to index `{}`. Consider using \ - `for ({}, item) in {}.iter().enumerate()` or similar iterators", - ident.node.name, indexed, ident.node.name, indexed)); + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is used to index `{}`. Consider using `for \ + ({}, item) in {}.iter().enumerate()` or similar iterators", + ident.node.name, + indexed, + ident.node.name, + indexed)); } else { - span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!( - "the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in &{}` or similar iterators", - ident.node.name, indexed, indexed)); + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is only used to index `{}`. Consider using \ + `for item in &{}` or similar iterators", + ident.node.name, + indexed, + indexed)); } } } @@ -283,15 +305,21 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E // who think that this will iterate from the larger value to the // smaller value. if start_idx > stop_idx { - span_help_and_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run", - &format!("Consider using `({}..{}).rev()` if you are attempting to \ - iterate over this range in reverse", stop_idx, start_idx)); + span_help_and_lint(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run", + &format!("Consider using `({}..{}).rev()` if you are attempting to iterate \ + over this range in reverse", + stop_idx, + start_idx)); } else if start_idx == stop_idx { // if they are equal, it's also problematic - this loop // will never run. - span_lint(cx, REVERSE_RANGE_LOOP, expr.span, - "this range is empty so this for loop will never run"); + span_lint(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run"); } } } @@ -305,46 +333,65 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { if is_ref_iterable_type(cx, &args[0]) { let object = snippet(cx, args[0].span, "_"); - span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!( - "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", - if method_name.as_str() == "iter_mut" { "mut " } else { "" }, - object, object, method_name)); + span_lint(cx, + EXPLICIT_ITER_LOOP, + expr.span, + &format!("it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", + if method_name.as_str() == "iter_mut" { + "mut " + } else { + "" + }, + object, + object, + method_name)); } - } - // check for looping over Iterator::next() which is not what you want - else if method_name.as_str() == "next" && - match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { - span_lint(cx, ITER_NEXT_LOOP, expr.span, - "you are iterating over `Iterator::next()` which is an Option; \ - this will compile but is probably not what you want"); + } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + span_lint(cx, + ITER_NEXT_LOOP, + expr.span, + "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ + probably not what you want"); } } } // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor { cx: cx, states: HashMap::new(), depth: 0, done: false }; + let mut visitor = IncrementVisitor { + cx: cx, + states: HashMap::new(), + depth: 0, + done: false, + }; walk_expr(&mut visitor, body); // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. let map = &cx.tcx.map; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id) ); + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id)); if let Some(parent_id) = parent_scope { if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter( |&(_,v)| *v == VarState::IncrOnce) { - let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, var_id: id.clone(), - state: VarState::IncrOnce, name: None, - depth: 0, - past_loop: false }; + for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { + let mut visitor2 = InitializeVisitor { + cx: cx, + end_expr: expr, + var_id: id.clone(), + state: VarState::IncrOnce, + name: None, + depth: 0, + past_loop: false, + }; walk_block(&mut visitor2, block); if visitor2.state == VarState::Warn { if let Some(name) = visitor2.name { - span_lint(cx, EXPLICIT_COUNTER_LOOP, expr.span, - &format!("the variable `{0}` is used as a loop counter. Consider \ - using `for ({0}, item) in {1}.enumerate()` \ - or similar iterators", - name, snippet(cx, arg.span, "_"))); + span_lint(cx, + EXPLICIT_COUNTER_LOOP, + expr.span, + &format!("the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ + item) in {1}.enumerate()` or similar iterators", + name, + snippet(cx, arg.span, "_"))); } } } @@ -378,9 +425,9 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference - var: Name, // var name to look for as index - indexed: HashSet<Name>, // indexed variables - nonindex: bool, // has the var been used otherwise? + var: Name, // var name to look for as index + indexed: HashSet<Name>, // indexed variables + nonindex: bool, // has the var been used otherwise? } impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { @@ -411,14 +458,14 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { let def_id = match var_def_id(cx, iter_expr) { Some(id) => id, - None => return false + None => return false, }; let mut visitor = VarUsedAfterLoopVisitor { cx: cx, def_id: def_id, iter_expr_id: iter_expr.id, past_while_let: false, - var_used_after_while_let: false + var_used_after_while_let: false, }; if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { walk_block(&mut visitor, enclosing_block); @@ -431,10 +478,10 @@ struct VarUsedAfterLoopVisitor<'v, 't: 'v> { def_id: NodeId, iter_expr_id: NodeId, past_while_let: bool, - var_used_after_while_let: bool + var_used_after_while_let: bool, } -impl <'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { +impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { fn visit_expr(&mut self, expr: &'v Expr) { if self.past_while_let { if Some(self.def_id) == var_def_id(self.cx, expr) { @@ -454,43 +501,52 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); - is_iterable_array(ty) || - match_type(cx, ty, &VEC_PATH) || - match_type(cx, ty, &LL_PATH) || - match_type(cx, ty, &HASHMAP_PATH) || - match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || - match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || - match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || - match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || - match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) + is_iterable_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || + match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || + match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || + match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || + match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || + match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) } fn is_iterable_array(ty: ty::Ty) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { ty::TyArray(_, 0...32) => true, - _ => false + _ => false, } } /// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { - if block.stmts.is_empty() { return None; } + if block.stmts.is_empty() { + return None; + } if let StmtDecl(ref decl, _) = block.stmts[0].node { if let DeclLocal(ref local) = decl.node { - if let Some(ref expr) = local.init { Some(expr) } else { None } - } else { None } - } else { None } + if let Some(ref expr) = local.init { + Some(expr) + } else { + None + } + } else { + None + } + } else { + None + } } /// If a block begins with an expression (with or without semicolon), return it. fn extract_first_expr(block: &Block) -> Option<&Expr> { match block.expr { Some(ref expr) => Some(expr), - None if !block.stmts.is_empty() => match block.stmts[0].node { - StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), - _ => None, - }, + None if !block.stmts.is_empty() => { + match block.stmts[0].node { + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), + _ => None, + } + } _ => None, } } @@ -500,10 +556,12 @@ fn is_break_expr(expr: &Expr) -> bool { match expr.node { ExprBreak(None) => true, // there won't be a `let <pat> = break` and so we can safely ignore the StmtDecl case - ExprBlock(ref b) => match extract_first_expr(b) { - Some(ref subexpr) => is_break_expr(subexpr), - None => false, - }, + ExprBlock(ref b) => { + match extract_first_expr(b) { + Some(ref subexpr) => is_break_expr(subexpr), + None => false, + } + } _ => false, } } @@ -513,19 +571,19 @@ fn is_break_expr(expr: &Expr) -> bool { // at the start of the loop. #[derive(PartialEq)] enum VarState { - Initial, // Not examined yet - IncrOnce, // Incremented exactly once, may be a loop counter - Declared, // Declared but not (yet) initialized to zero + Initial, // Not examined yet + IncrOnce, // Incremented exactly once, may be a loop counter + Declared, // Declared but not (yet) initialized to zero Warn, - DontWarn + DontWarn, } // Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference - states: HashMap<NodeId, VarState>, // incremented variables - depth: u32, // depth of conditional expressions - done: bool + cx: &'v LateContext<'v, 't>, // context reference + states: HashMap<NodeId, VarState>, // incremented variables + depth: u32, // depth of conditional expressions + done: bool, } impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { @@ -540,33 +598,29 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { let state = self.states.entry(def_id).or_insert(VarState::Initial); match parent.node { - ExprAssignOp(op, ref lhs, ref rhs) => + ExprAssignOp(op, ref lhs, ref rhs) => { if lhs.id == expr.id { if op.node == BiAdd && is_integer_literal(rhs, 1) { *state = match *state { VarState::Initial if self.depth == 0 => VarState::IncrOnce, - _ => VarState::DontWarn + _ => VarState::DontWarn, }; - } - else { + } else { // Assigned some other value *state = VarState::DontWarn; } - }, + } + } ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, - ExprAddrOf(mutability,_) if mutability == MutMutable => *state = VarState::DontWarn, - _ => () + ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, + _ => (), } } - } - // Give up if there are nested loops - else if is_loop(expr) { + } else if is_loop(expr) { self.states.clear(); self.done = true; return; - } - // Keep track of whether we're inside a conditional expression - else if is_conditional(expr) { + } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; @@ -579,12 +633,12 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { // 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. + end_expr: &'v Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, name: Option<Name>, - depth: u32, // depth of conditional expressions - past_loop: bool + depth: u32, // depth of conditional expressions + past_loop: bool, } impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { @@ -601,8 +655,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { } else { VarState::Declared } - } - else { + } else { VarState::Declared } } @@ -637,9 +690,10 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { VarState::Warn } else { VarState::DontWarn - }} - ExprAddrOf(mutability,_) if mutability == MutMutable => self.state = VarState::DontWarn, - _ => () + } + } + ExprAddrOf(mutability, _) if mutability == MutMutable => self.state = VarState::DontWarn, + _ => (), } } @@ -647,14 +701,10 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { self.state = VarState::DontWarn; return; } - } - // If there are other loops between the declaration and the target loop, give up - else if !self.past_loop && is_loop(expr) { + } else if !self.past_loop && is_loop(expr) { self.state = VarState::DontWarn; return; - } - // Keep track of whether we're inside a conditional expression - else if is_conditional(expr) { + } else if is_conditional(expr) { self.depth += 1; walk_expr(self, expr); self.depth -= 1; @@ -667,7 +717,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { if let DefLocal(_, node_id) = path_res.base_def { - return Some(node_id) + return Some(node_id); } } None @@ -675,14 +725,14 @@ fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { fn is_loop(expr: &Expr) -> bool { match expr.node { - ExprLoop(..) | ExprWhile(..) => true, - _ => false + ExprLoop(..) | ExprWhile(..) => true, + _ => false, } } fn is_conditional(expr: &Expr) -> bool { match expr.node { ExprIf(..) | ExprMatch(..) => true, - _ => false + _ => false, } } diff --git a/src/map_clone.rs b/src/map_clone.rs index ef992ad086c..9db97a1b9f2 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -65,10 +65,13 @@ impl LateLintPass for MapClonePass { ExprPath(_, ref path) => { if match_path(path, &CLONE_PATH) { let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); - span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( - "you seem to be using .map() to clone the contents of an {}, consider \ - using `.cloned()`", type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + span_help_and_lint(cx, + MAP_CLONE, + expr.span, + &format!("you seem to be using .map() to clone the contents of an \ + {}, consider using `.cloned()`", + type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); } } _ => (), @@ -81,7 +84,10 @@ impl LateLintPass for MapClonePass { fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { match expr.node { ExprPath(None, ref path) => { - let arg_segment = [PathSegment { identifier: id, parameters: PathParameters::none() }]; + let arg_segment = [PathSegment { + identifier: id, + parameters: PathParameters::none(), + }]; !path.global && path.segments[..] == arg_segment } _ => false, @@ -108,9 +114,7 @@ fn get_arg_name(pat: &Pat) -> Option<Ident> { fn only_derefs(cx: &LateContext, expr: &Expr, id: Ident) -> bool { match expr.node { - ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => { - only_derefs(cx, subexpr, id) - } + ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id), _ => expr_eq_ident(expr, id), } } diff --git a/src/matches.rs b/src/matches.rs index 8564c36e617..5e207093c15 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -94,7 +94,9 @@ impl LintPass for MatchPass { impl LateLintPass for MatchPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_external_macro(cx, expr.span) { return; } + if in_external_macro(cx, expr.span) { + return; + } if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { check_single_match(cx, ex, arms, expr); check_match_bool(cx, ex, arms, expr); @@ -107,23 +109,14 @@ impl LateLintPass for MatchPass { } fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { - if arms.len() == 2 && - // both of the arms have a single pattern and no guard - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() && - // and the second pattern is a `_` wildcard: this is not strictly necessary, - // since the exhaustiveness check will ensure the last one is a catch-all, - // but in some cases, an explicit match is preferred to catch situations - // when an enum is extended, so we don't consider these cases - arms[1].pats[0].node == PatWild && - // we don't want any content in the second arm (unit or empty block) - is_unit_expr(&arms[1].body) && - // finally, MATCH_BOOL doesn't apply here - (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) - { - span_help_and_lint(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for destructuring a \ - single pattern. Consider using `if let`", + if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && + arms[1].guard.is_none() && arms[1].pats[0].node == PatWild && is_unit_expr(&arms[1].body) && + (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) { + span_help_and_lint(cx, + SINGLE_MATCH, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. Consider using \ + `if let`", &format!("try\nif let {} = {} {}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), @@ -134,7 +127,8 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { // type of expression == bool if cx.tcx.expr_ty(ex).sty == ty::TyBool { - if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards + if arms.len() == 2 && arms[0].pats.len() == 1 { + // no guards let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { match lit.node { @@ -142,54 +136,67 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { LitBool(false) => Some((&*arms[1].body, &*arms[0].body)), _ => None, } - } else { None } - } else { None }; + } else { + None + } + } else { + None + }; if let Some((ref true_expr, ref false_expr)) = exprs { if !is_unit_expr(true_expr) { if !is_unit_expr(false_expr) { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."), - expr_block(cx, false_expr, None, ".."))); + span_help_and_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using \ + an if..else block:", + &format!("try\nif {} {} else {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."), + expr_block(cx, false_expr, None, ".."))); } else { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."))); + span_help_and_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using \ + an if..else block:", + &format!("try\nif {} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."))); } } else if !is_unit_expr(false_expr) { - span_help_and_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block:", - &format!("try\nif !{} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))); + span_help_and_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using an \ + if..else block:", + &format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))); } else { - span_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); + span_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using an if..else \ + block"); } } else { - span_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); + span_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using an if..else block"); } } else { - span_lint(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. \ - Consider using an if..else block"); + span_lint(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using an if..else block"); } } } fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { - if arms.len() >= 2 && - cx.tcx.expr_ty(ex).is_integral() { + if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms); let overlap = match type_ranges(&ranges) { TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), @@ -198,9 +205,12 @@ fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { }; if let Some((start, end)) = overlap { - span_note_and_lint(cx, MATCH_OVERLAPPING_ARM, start, + span_note_and_lint(cx, + MATCH_OVERLAPPING_ARM, + start, "some ranges overlap", - end, "overlaps with this"); + end, + "overlaps with this"); } } } @@ -209,14 +219,18 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match if has_only_ref_pats(arms) { if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { let template = match_template(cx, expr.span, source, "", inner); - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "you don't need to add `&` to both the expression \ - and the patterns: use `{}`", template)); + span_lint(cx, + MATCH_REF_PATS, + expr.span, + &format!("you don't need to add `&` to both the expression and the patterns: use `{}`", + template)); } else { let template = match_template(cx, expr.span, source, "*", ex); - span_lint(cx, MATCH_REF_PATS, expr.span, &format!( - "instead of prefixing all patterns with `&`, you can dereference the \ - expression: `{}`", template)); + span_lint(cx, + MATCH_REF_PATS, + expr.span, + &format!("instead of prefixing all patterns with `&`, you can dereference the expression: `{}`", + template)); } } } @@ -244,8 +258,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { None })) - } - else { + } else { None } }) @@ -271,29 +284,36 @@ enum TypedRanges { fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { if ranges.is_empty() { TypedRanges::None - } - else { + } else { match ranges[0].node { (Int(_), Int(_)) => { - TypedRanges::IntRanges(ranges.iter().filter_map(|range| { - if let (Int(start), Int(end)) = range.node { - Some(SpannedRange { span: range.span, node: (start, end) }) - } - else { - None - } - }).collect()) - }, + TypedRanges::IntRanges(ranges.iter() + .filter_map(|range| { + if let (Int(start), Int(end)) = range.node { + Some(SpannedRange { + span: range.span, + node: (start, end), + }) + } else { + None + } + }) + .collect()) + } (Uint(_), Uint(_)) => { - TypedRanges::UintRanges(ranges.iter().filter_map(|range| { - if let (Uint(start), Uint(end)) = range.node { - Some(SpannedRange { span: range.span, node: (start, end) }) - } - else { - None - } - }).collect()) - }, + TypedRanges::UintRanges(ranges.iter() + .filter_map(|range| { + if let (Uint(start), Uint(end)) = range.node { + Some(SpannedRange { + span: range.span, + node: (start, end), + }) + } else { + None + } + }) + .collect()) + } _ => TypedRanges::None, } } @@ -308,39 +328,33 @@ 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 { - PatRegion(..) => Some(true), // &-patterns - PatWild => Some(false), // an "anything" wildcard is also fine - _ => None, // any other pattern is not fine - }).collect::<Option<Vec<bool>>>(); + let mapped = arms.iter() + .flat_map(|a| &a.pats) + .map(|p| { + match p.node { + PatRegion(..) => Some(true), // &-patterns + PatWild => Some(false), // an "anything" wildcard is also fine + _ => None, // any other pattern is not fine + } + }) + .collect::<Option<Vec<bool>>>(); // look for Some(v) where there's at least one true element mapped.map_or(false, |v| v.iter().any(|el| *el)) } -fn match_template(cx: &LateContext, - span: Span, - source: MatchSource, - op: &str, - expr: &Expr) -> String { +fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, expr: &Expr) -> String { let expr_snippet = snippet(cx, expr.span, ".."); match source { - MatchSource::Normal => { - format!("match {}{} {{ ...", op, expr_snippet) - } - MatchSource::IfLetDesugar { .. } => { - format!("if let ... = {}{} {{", op, expr_snippet) - } - MatchSource::WhileLetDesugar => { - format!("while let ... = {}{} {{", op, expr_snippet) - } - MatchSource::ForLoopDesugar => { - cx.sess().span_bug(span, "for loop desugared to match with &-patterns!") - } + MatchSource::Normal => format!("match {}{} {{ ...", op, expr_snippet), + MatchSource::IfLetDesugar { .. } => format!("if let ... = {}{} {{", op, expr_snippet), + MatchSource::WhileLetDesugar => format!("while let ... = {}{} {{", op, expr_snippet), + MatchSource::ForLoopDesugar => cx.sess().span_bug(span, "for loop desugared to match with &-patterns!"), } } pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> - where T: Copy + Ord { + where T: Copy + Ord +{ #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Kind<'a, T: 'a> { Start(T, &'a SpannedRange<T>), @@ -350,13 +364,13 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & impl<'a, T: Copy> Kind<'a, T> { fn range(&self) -> &'a SpannedRange<T> { match *self { - Kind::Start(_, r) | Kind::End(_, r) => r + Kind::Start(_, r) | Kind::End(_, r) => r, } } fn value(self) -> T { match self { - Kind::Start(t, _) | Kind::End(t, _) => t + Kind::Start(t, _) | Kind::End(t, _) => t, } } } @@ -373,7 +387,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & } } - let mut values = Vec::with_capacity(2*ranges.len()); + let mut values = Vec::with_capacity(2 * ranges.len()); for r in ranges { values.push(Kind::Start(r.node.0, &r)); @@ -384,7 +398,11 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & for (a, b) in values.iter().zip(values.iter().skip(1)) { match (a, b) { - (&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node { return Some((ra, rb)) }, + (&Kind::Start(_, ra), &Kind::End(_, rb)) => { + 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/src/methods.rs b/src/methods.rs index 2aa3b040e55..83b9e60f4be 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -5,8 +5,8 @@ use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; -use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, - match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty}; +use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method, + walk_ptrs_ty_depth, walk_ptrs_ty}; use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; use utils::MethodArgs; @@ -172,9 +172,16 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, - SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, WRONG_PUB_SELF_CONVENTION, - OK_EXPECT, OPTION_MAP_UNWRAP_OR, OPTION_MAP_UNWRAP_OR_ELSE) + lint_array!(OPTION_UNWRAP_USED, + RESULT_UNWRAP_USED, + STR_TO_STRING, + STRING_TO_STRING, + SHOULD_IMPLEMENT_TRAIT, + WRONG_SELF_CONVENTION, + WRONG_PUB_SELF_CONVENTION, + OK_EXPECT, + OPTION_MAP_UNWRAP_OR, + OPTION_MAP_UNWRAP_OR_ELSE) } } @@ -183,29 +190,21 @@ impl LateLintPass for MethodsPass { if let ExprMethodCall(_, _, _) = expr.node { if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { lint_unwrap(cx, expr, arglists[0]); - } - else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { + } else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { lint_to_string(cx, expr, arglists[0]); - } - else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { + } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { lint_ok_expect(cx, expr, arglists[0]); - } - else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); - } - else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); - } - else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { + } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { lint_filter_next(cx, expr, arglists[0]); - } - else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { + } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); - } - else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { + } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); - } - else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { + } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); } } @@ -235,16 +234,22 @@ impl LateLintPass for MethodsPass { let is_copy = is_copy(cx, &ty, &item); for &(prefix, self_kinds) in &CONVENTIONS { if name.as_str().starts_with(prefix) && - !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { + !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { let lint = if item.vis == Visibility::Public { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION }; - span_lint(cx, lint, sig.explicit_self.span, &format!( - "methods called `{}*` usually take {}; consider choosing a less \ - ambiguous name", prefix, - &self_kinds.iter().map(|k| k.description()).collect::<Vec<_>>().join(" or "))); + span_lint(cx, + lint, + sig.explicit_self.span, + &format!("methods called `{}*` usually take {}; consider choosing a less \ + ambiguous name", + prefix, + &self_kinds.iter() + .map(|k| k.description()) + .collect::<Vec<_>>() + .join(" or "))); } } } @@ -253,30 +258,34 @@ impl LateLintPass for MethodsPass { } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `unwrap()` for `Option`s and `Result`s fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); let mess = if match_type(cx, obj_ty, &OPTION_PATH) { Some((OPTION_UNWRAP_USED, "an Option", "None")) - } - else if match_type(cx, obj_ty, &RESULT_PATH) { + } else if match_type(cx, obj_ty, &RESULT_PATH) { Some((RESULT_UNWRAP_USED, "a Result", "Err")) - } - else { + } else { None }; if let Some((lint, kind, none_value)) = mess { - span_lint(cx, lint, expr.span, - &format!("used unwrap() on {} value. If you don't want to handle the {} \ - case gracefully, consider using expect() to provide a better panic - message", kind, none_value)); + span_lint(cx, + lint, + expr.span, + &format!("used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ + using expect() to provide a better panic + message", + kind, + none_value)); } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `to_string()` for `&str`s and `String`s fn lint_to_string(cx: &LateContext, expr: &Expr, to_string_args: &MethodArgs) { let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&to_string_args[0])); @@ -284,21 +293,19 @@ fn lint_to_string(cx: &LateContext, expr: &Expr, to_string_args: &MethodArgs) { if obj_ty.sty == ty::TyStr { let mut arg_str = snippet(cx, to_string_args[0].span, "_"); if ptr_depth > 1 { - arg_str = Cow::Owned(format!( - "({}{})", - iter::repeat('*').take(ptr_depth - 1).collect::<String>(), - arg_str)); + arg_str = Cow::Owned(format!("({}{})", iter::repeat('*').take(ptr_depth - 1).collect::<String>(), arg_str)); } - span_lint(cx, STR_TO_STRING, expr.span, - &format!("`{}.to_owned()` is faster", arg_str)); - } - else if match_type(cx, obj_ty, &STRING_PATH) { - span_lint(cx, STRING_TO_STRING, expr.span, + span_lint(cx, STR_TO_STRING, expr.span, &format!("`{}.to_owned()` is faster", arg_str)); + } else if match_type(cx, obj_ty, &STRING_PATH) { + span_lint(cx, + STRING_TO_STRING, + expr.span, "`String.to_string()` is a no-op; use `clone()` to make a copy"); } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `ok().expect()` for `Result`s fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { // lint if the caller of `ok()` is a `Result` @@ -306,107 +313,120 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { let result_type = cx.tcx.expr_ty(&ok_args[0]); if let Some(error_type) = get_error_type(cx, result_type) { if has_debug_impl(error_type, cx) { - span_lint(cx, OK_EXPECT, expr.span, - "called `ok().expect()` on a Result value. You can call `expect` \ - directly on the `Result`"); + span_lint(cx, + OK_EXPECT, + expr.span, + "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`"); } } } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, - unwrap_args: &MethodArgs) { +fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message - let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more \ - directly by calling `map_or(a, f)` instead"; + let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling \ + `map_or(a, f)` instead"; // get snippets for args to map() and unwrap_or() let map_snippet = snippet(cx, map_args[1].span, ".."); let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); // lint, with note if neither arg is > 1 line and both map() and // unwrap_or() have the same span - let multiline = map_snippet.lines().count() > 1 - || unwrap_snippet.lines().count() > 1; + let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; if same_span && !multiline { - span_note_and_lint( - cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, - &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", map_snippet, - unwrap_snippet) - ); - } - else if same_span && multiline { + span_note_and_lint(cx, + OPTION_MAP_UNWRAP_OR, + expr.span, + msg, + expr.span, + &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", + map_snippet, + unwrap_snippet)); + } else if same_span && multiline { span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); }; } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or_else()` for `Option`s -fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, - unwrap_args: &MethodArgs) { +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { // lint message - let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more \ - directly by calling `map_or_else(g, f)` instead"; + let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ + `map_or_else(g, f)` instead"; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span - let multiline = map_snippet.lines().count() > 1 - || unwrap_snippet.lines().count() > 1; + let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; if same_span && !multiline { - span_note_and_lint( - cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg, expr.span, - &format!("replace `map({0}).unwrap_or_else({1})` with `with map_or_else({1}, {0})`", - map_snippet, unwrap_snippet) - ); - } - else if same_span && multiline { + span_note_and_lint(cx, + OPTION_MAP_UNWRAP_OR_ELSE, + expr.span, + msg, + expr.span, + &format!("replace `map({0}).unwrap_or_else({1})` with `with map_or_else({1}, {0})`", + map_snippet, + unwrap_snippet)); + } else if same_span && multiline { span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); }; } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint use of `filter().next() for Iterators` fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { // lint if caller of `.filter().next()` is an Iterator if match_trait_method(cx, expr, &["core", "iter", "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 - span_note_and_lint(cx, FILTER_NEXT, expr.span, msg, expr.span, - &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); - } - else { + if filter_snippet.lines().count() <= 1 { + // add note if not multi-line + span_note_and_lint(cx, + FILTER_NEXT, + expr.span, + msg, + expr.span, + &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); + } else { span_lint(cx, FILTER_NEXT, expr.span, msg); } } } -#[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec /// lint searching an Iterator followed by `is_some()` fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, search_args: &MethodArgs, is_some_args: &MethodArgs) { // lint if caller of search is an Iterator if match_trait_method(cx, &*is_some_args[0], &["core", "iter", "Iterator"]) { - let msg = format!("called `is_some()` after searching an iterator with {}. This is more \ - succinctly expressed by calling `any()`.", search_method); + 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 { // add note if not multi-line - span_note_and_lint(cx, SEARCH_IS_SOME, expr.span, &msg, expr.span, - &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, - search_snippet)); - } - else { + if search_snippet.lines().count() <= 1 { + // add note if not multi-line + span_note_and_lint(cx, + SEARCH_IS_SOME, + expr.span, + &msg, + expr.span, + &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet)); + } else { span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); } } @@ -432,7 +452,7 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { let no_ref_ty = walk_ptrs_ty(ty); let debug = match cx.tcx.lang_items.debug_trait() { Some(debug) => debug, - None => return false + None => return false, }; let debug_def = cx.tcx.lookup_trait_def(debug); let mut debug_impl_exists = false; @@ -447,46 +467,162 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { debug_impl_exists } -const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ - ("into_", &[ValueSelf]), - ("to_", &[RefSelf]), - ("as_", &[RefSelf, RefMutSelf]), - ("is_", &[RefSelf, NoSelf]), - ("from_", &[NoSelf]), -]; - -const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ - ("add", 2, ValueSelf, AnyType, "std::ops::Add"), - ("sub", 2, ValueSelf, AnyType, "std::ops::Sub"), - ("mul", 2, ValueSelf, AnyType, "std::ops::Mul"), - ("div", 2, ValueSelf, AnyType, "std::ops::Div"), - ("rem", 2, ValueSelf, AnyType, "std::ops::Rem"), - ("shl", 2, ValueSelf, AnyType, "std::ops::Shl"), - ("shr", 2, ValueSelf, AnyType, "std::ops::Shr"), - ("bitand", 2, ValueSelf, AnyType, "std::ops::BitAnd"), - ("bitor", 2, ValueSelf, AnyType, "std::ops::BitOr"), - ("bitxor", 2, ValueSelf, AnyType, "std::ops::BitXor"), - ("neg", 1, ValueSelf, AnyType, "std::ops::Neg"), - ("not", 1, ValueSelf, AnyType, "std::ops::Not"), - ("drop", 1, RefMutSelf, UnitType, "std::ops::Drop"), - ("index", 2, RefSelf, RefType, "std::ops::Index"), - ("index_mut", 2, RefMutSelf, RefType, "std::ops::IndexMut"), - ("deref", 1, RefSelf, RefType, "std::ops::Deref"), - ("deref_mut", 1, RefMutSelf, RefType, "std::ops::DerefMut"), - ("clone", 1, RefSelf, AnyType, "std::clone::Clone"), - ("borrow", 1, RefSelf, RefType, "std::borrow::Borrow"), - ("borrow_mut", 1, RefMutSelf, RefType, "std::borrow::BorrowMut"), - ("as_ref", 1, RefSelf, RefType, "std::convert::AsRef"), - ("as_mut", 1, RefMutSelf, RefType, "std::convert::AsMut"), - ("eq", 2, RefSelf, BoolType, "std::cmp::PartialEq"), - ("cmp", 2, RefSelf, AnyType, "std::cmp::Ord"), - ("default", 0, NoSelf, AnyType, "std::default::Default"), - ("hash", 2, RefSelf, UnitType, "std::hash::Hash"), - ("next", 1, RefMutSelf, AnyType, "std::iter::Iterator"), - ("into_iter", 1, ValueSelf, AnyType, "std::iter::IntoIterator"), - ("from_iter", 1, NoSelf, AnyType, "std::iter::FromIterator"), - ("from_str", 1, NoSelf, AnyType, "std::str::FromStr"), -]; +const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [("into_", &[ValueSelf]), + ("to_", &[RefSelf]), + ("as_", &[RefSelf, RefMutSelf]), + ("is_", &[RefSelf, NoSelf]), + ("from_", &[NoSelf])]; + +const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [("add", + 2, + ValueSelf, + AnyType, + "std::ops::Add"), + ("sub", + 2, + ValueSelf, + AnyType, + "std::ops::Sub"), + ("mul", + 2, + ValueSelf, + AnyType, + "std::ops::Mul"), + ("div", + 2, + ValueSelf, + AnyType, + "std::ops::Div"), + ("rem", + 2, + ValueSelf, + AnyType, + "std::ops::Rem"), + ("shl", + 2, + ValueSelf, + AnyType, + "std::ops::Shl"), + ("shr", + 2, + ValueSelf, + AnyType, + "std::ops::Shr"), + ("bitand", + 2, + ValueSelf, + AnyType, + "std::ops::BitAnd"), + ("bitor", + 2, + ValueSelf, + AnyType, + "std::ops::BitOr"), + ("bitxor", + 2, + ValueSelf, + AnyType, + "std::ops::BitXor"), + ("neg", + 1, + ValueSelf, + AnyType, + "std::ops::Neg"), + ("not", + 1, + ValueSelf, + AnyType, + "std::ops::Not"), + ("drop", + 1, + RefMutSelf, + UnitType, + "std::ops::Drop"), + ("index", + 2, + RefSelf, + RefType, + "std::ops::Index"), + ("index_mut", + 2, + RefMutSelf, + RefType, + "std::ops::IndexMut"), + ("deref", + 1, + RefSelf, + RefType, + "std::ops::Deref"), + ("deref_mut", + 1, + RefMutSelf, + RefType, + "std::ops::DerefMut"), + ("clone", + 1, + RefSelf, + AnyType, + "std::clone::Clone"), + ("borrow", + 1, + RefSelf, + RefType, + "std::borrow::Borrow"), + ("borrow_mut", + 1, + RefMutSelf, + RefType, + "std::borrow::BorrowMut"), + ("as_ref", + 1, + RefSelf, + RefType, + "std::convert::AsRef"), + ("as_mut", + 1, + RefMutSelf, + RefType, + "std::convert::AsMut"), + ("eq", + 2, + RefSelf, + BoolType, + "std::cmp::PartialEq"), + ("cmp", + 2, + RefSelf, + AnyType, + "std::cmp::Ord"), + ("default", + 0, + NoSelf, + AnyType, + "std::default::Default"), + ("hash", + 2, + RefSelf, + UnitType, + "std::hash::Hash"), + ("next", + 1, + RefMutSelf, + AnyType, + "std::iter::Iterator"), + ("into_iter", + 1, + ValueSelf, + AnyType, + "std::iter::IntoIterator"), + ("from_iter", + 1, + NoSelf, + AnyType, + "std::iter::FromIterator"), + ("from_str", + 1, + NoSelf, + AnyType, + "std::str::FromStr")]; #[derive(Clone, Copy)] enum SelfKind { @@ -506,7 +642,7 @@ impl SelfKind { (&RefMutSelf, &SelfValue(_)) => allow_value_for_ref, (&NoSelf, &SelfStatic) => true, (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), - _ => false + _ => false, } } @@ -517,7 +653,7 @@ impl SelfKind { (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, (&RefSelf, &TyPath(..)) => allow_value_for_ref, (&RefMutSelf, &TyPath(..)) => allow_value_for_ref, - _ => false + _ => false, } } @@ -545,11 +681,15 @@ impl OutType { (&UnitType, &DefaultReturn(_)) => true, (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![].into()) => true, (&BoolType, &Return(ref ty)) if is_bool(ty) => true, - (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, + (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, (&RefType, &Return(ref ty)) => { - if let TyRptr(_, _) = ty.node { true } else { false } + if let TyRptr(_, _) = ty.node { + true + } else { + false + } } - _ => false + _ => false, } } } diff --git a/src/minmax.rs b/src/minmax.rs index 2a8e064f9f4..2cce36f2a9c 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -32,12 +32,13 @@ impl LateLintPass for MinMaxPass { fn check_expr(&mut self, cx: &LateContext, expr: &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 { return; } + if outer_max == inner_max { + return; + } match (outer_max, outer_c.partial_cmp(&inner_c)) { (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), _ => { - span_lint(cx, MIN_MAX, expr.span, - "this min/max combination leads to constant result"); + span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); } } } @@ -65,20 +66,30 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &' None } } - } else { None } - } else { None } - } + } else { + None + } + } else { + None + } +} -fn fetch_const(args: &[P<Expr>], m: MinMax) -> - Option<(MinMax, Constant, &Expr)> { - if args.len() != 2 { return None } +fn fetch_const(args: &[P<Expr>], m: MinMax) -> Option<(MinMax, Constant, &Expr)> { + if args.len() != 2 { + return None; + } if let Some(c) = constant_simple(&args[0]) { - if let None = constant_simple(&args[1]) { // otherwise ignore + if let None = constant_simple(&args[1]) { + // otherwise ignore Some((m, c, &args[1])) - } else { None } + } else { + None + } } else { if let Some(c) = constant_simple(&args[1]) { Some((m, c, &args[0])) - } else { None } + } else { + None + } } } diff --git a/src/misc.rs b/src/misc.rs index 92276961d11..1b7f2a921b9 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -40,15 +40,14 @@ impl LateLintPass for TopLevelRefPass { fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { if let FnKind::Closure = k { // Does not apply to closures - return + return; } for ref arg in &decl.inputs { if let PatIdent(BindByRef(_), _, _) = arg.pat.node { span_lint(cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. Consider using a reference type instead." - ); + TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. Consider using a reference type instead."); } } } @@ -112,9 +111,13 @@ impl LateLintPass for CmpNan { } fn check_nan(cx: &LateContext, path: &Path, span: Span) { - path.segments.last().map(|seg| if seg.identifier.name.as_str() == "NAN" { - span_lint(cx, CMP_NAN, span, - "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); + path.segments.last().map(|seg| { + if seg.identifier.name.as_str() == "NAN" { + span_lint(cx, + CMP_NAN, + span, + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); + } }); } @@ -144,20 +147,24 @@ impl LateLintPass for FloatCmp { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { let op = cmp.node; if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { return; } + if is_allowed(cx, left) || is_allowed(cx, right) { + return; + } 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") { + if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || + name.ends_with("_eq") { return; } } - span_lint(cx, FLOAT_CMP, expr.span, &format!( - "{}-comparison of f32 or f64 detected. Consider changing this to \ - `abs({} - {}) < epsilon` for some suitable value of epsilon", - binop_to_string(op), snippet(cx, left.span, ".."), - snippet(cx, right.span, ".."))); + span_lint(cx, + FLOAT_CMP, + expr.span, + &format!("{}-comparison of f32 or f64 detected. Consider changing this to `abs({} - {}) < \ + epsilon` for some suitable value of epsilon", + binop_to_string(op), + snippet(cx, left.span, ".."), + snippet(cx, right.span, ".."))); } } } @@ -167,7 +174,9 @@ fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None); if let Ok(Float(val)) = res { val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY - } else { false } + } else { + false + } } fn is_float(cx: &LateContext, expr: &Expr) -> bool { @@ -211,44 +220,54 @@ impl LateLintPass for CmpOwned { fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, op: Span) { let snip = match expr.node { ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => { - if name.as_str() == "to_string" || - name.as_str() == "to_owned" && is_str_arg(cx, args) { - snippet(cx, args[0].span, "..") - } else { - return - } + if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { + snippet(cx, args[0].span, "..") + } else { + return; + } } ExprCall(ref path, ref v) if v.len() == 1 => { if let ExprPath(None, ref path) = path.node { - if match_path(path, &["String", "from_str"]) || - match_path(path, &["String", "from"]) { - snippet(cx, v[0].span, "..") - } else { - return - } + if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { + snippet(cx, v[0].span, "..") + } else { + return; + } } else { - return + return; } } - _ => return + _ => return, }; if left { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. Consider using \ - `{} {} {}` to compare without allocation", snip, - snippet(cx, op, "=="), snippet(cx, other_span, ".."))); + span_lint(cx, + CMP_OWNED, + expr.span, + &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ + compare without allocation", + snip, + snippet(cx, op, "=="), + snippet(cx, other_span, ".."))); } else { - span_lint(cx, CMP_OWNED, expr.span, &format!( - "this creates an owned instance just for comparison. Consider using \ - `{} {} {}` to compare without allocation", - snippet(cx, other_span, ".."), snippet(cx, op, "=="), snip)); + span_lint(cx, + CMP_OWNED, + expr.span, + &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ + compare without allocation", + snippet(cx, other_span, ".."), + snippet(cx, op, "=="), + snip)); } } fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { - args.len() == 1 && if let ty::TyStr = - walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { true } else { false } + args.len() == 1 && + if let ty::TyStr = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { + true + } else { + false + } } /// **What it does:** This lint checks for getting the remainder of a division by one. It is `Warn` by default. @@ -309,9 +328,11 @@ impl LateLintPass for PatternPass { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatIdent(_, ref ident, Some(ref right)) = pat.node { if right.node == PatWild { - cx.span_lint(REDUNDANT_PATTERN, pat.span, &format!( - "the `{} @ _` pattern can be written as just `{}`", - ident.node.name, ident.node.name)); + cx.span_lint(REDUNDANT_PATTERN, + pat.span, + &format!("the `{} @ _` pattern can be written as just `{}`", + ident.node.name, + ident.node.name)); } } } @@ -345,30 +366,31 @@ impl LintPass for UsedUnderscoreBinding { impl LateLintPass for UsedUnderscoreBinding { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_attributes_expansion(cx, expr) { // Don't lint things expanded by #[derive(...)], etc + if in_attributes_expansion(cx, expr) { + // Don't lint things expanded by #[derive(...)], etc return; } let needs_lint = match expr.node { ExprPath(_, ref path) => { - let ident = path.segments.last() + let ident = path.segments + .last() .expect("path should always have at least one segment") .identifier; - ident.name.as_str().chars().next() == Some('_') //starts with '_' - && ident.name.as_str().chars().skip(1).next() != Some('_') //doesn't start with "__" - && ident.name != ident.unhygienic_name //not in bang macro - && is_used(cx, expr) - }, + ident.name.as_str().chars().next() == Some('_') && + ident.name.as_str().chars().skip(1).next() != Some('_') && + ident.name != ident.unhygienic_name && is_used(cx, expr) + } ExprField(_, spanned) => { let name = spanned.node.as_str(); - name.chars().next() == Some('_') - && name.chars().skip(1).next() != Some('_') - }, - _ => false + name.chars().next() == Some('_') && name.chars().skip(1).next() != Some('_') + } + _ => false, }; if needs_lint { - cx.span_lint(USED_UNDERSCORE_BINDING, expr.span, - "used binding which is prefixed with an underscore. A leading underscore \ - signals that a binding will not be used."); + cx.span_lint(USED_UNDERSCORE_BINDING, + expr.span, + "used binding which is prefixed with an underscore. A leading underscore signals that a \ + binding will not be used."); } } } @@ -380,10 +402,9 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { match parent.node { ExprAssign(_, ref rhs) => **rhs == *expr, ExprAssignOp(_, _, ref rhs) => **rhs == *expr, - _ => is_used(cx, &parent) + _ => is_used(cx, &parent), } - } - else { + } else { true } } diff --git a/src/misc_early.rs b/src/misc_early.rs index 7a59c15275f..a90c901df8f 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -52,15 +52,15 @@ impl EarlyLintPass for MiscEarly { } } if !pfields.is_empty() && wilds == pfields.len() { - span_help_and_lint(cx, UNNEEDED_FIELD_PATTERN, pat.span, - "All the struct fields are matched to a wildcard pattern, \ - consider using `..`.", - &format!("Try with `{} {{ .. }}` instead", - type_name)); + span_help_and_lint(cx, + UNNEEDED_FIELD_PATTERN, + pat.span, + "All the struct fields are matched to a wildcard pattern, consider using `..`.", + &format!("Try with `{} {{ .. }}` instead", type_name)); return; } if wilds > 0 { - let mut normal = vec!(); + let mut normal = vec![]; for field in pfields { if field.node.pat.node != PatWild { @@ -73,13 +73,16 @@ impl EarlyLintPass for MiscEarly { if field.node.pat.node == PatWild { wilds -= 1; if wilds > 0 { - span_lint(cx, UNNEEDED_FIELD_PATTERN, field.span, - "You matched a field with a wildcard pattern. \ - Consider using `..` instead"); + span_lint(cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` instead"); } else { - span_help_and_lint(cx, UNNEEDED_FIELD_PATTERN, field.span, - "You matched a field with a wildcard pattern. \ - Consider using `..` instead", + span_help_and_lint(cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` \ + instead", &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", "))); @@ -91,7 +94,7 @@ impl EarlyLintPass for MiscEarly { } fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - let mut registered_names : HashMap<String, Span> = HashMap::new(); + let mut registered_names: HashMap<String, Span> = HashMap::new(); for ref arg in &decl.inputs { if let PatIdent(_, sp_ident, None) = arg.pat.node { @@ -99,10 +102,12 @@ impl EarlyLintPass for MiscEarly { if arg_name.starts_with("_") { if let Some(correspondance) = registered_names.get(&arg_name[1..]) { - span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondance, - &format!("`{}` already exists, having another argument having almost \ - the same name makes code comprehension and documentation \ - more difficult", arg_name[1..].to_owned())); + span_lint(cx, + DUPLICATE_UNDERSCORE_ARGUMENT, + *correspondance, + &format!("`{}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult", + arg_name[1..].to_owned())); } } else { registered_names.insert(arg_name, arg.pat.span.clone()); diff --git a/src/mut_mut.rs b/src/mut_mut.rs index db6f0e0320b..1bdb4e9a3d6 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -30,42 +30,46 @@ impl LateLintPass for MutMut { } fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| { span_lint(cx, MUT_MUT, - ty.span, "generally you want to avoid `&mut &mut _` if possible"); }); + unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| { + span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); + }); } } fn check_expr_mut(cx: &LateContext, expr: &Expr) { - if in_external_macro(cx, expr.span) { return; } + if in_external_macro(cx, expr.span) { + return; + } fn unwrap_addr(expr: &Expr) -> Option<&Expr> { match expr.node { ExprAddrOf(MutMutable, ref e) => Some(e), - _ => None + _ => None, } } unwrap_addr(expr).map_or((), |e| { - unwrap_addr(e).map_or_else( - || { - if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = - cx.tcx.expr_ty(e).sty { - span_lint(cx, MUT_MUT, expr.span, - "this expression mutably borrows a mutable reference. \ - Consider reborrowing"); - } - }, - |_| { - span_lint(cx, MUT_MUT, expr.span, - "generally you want to avoid `&mut &mut _` if possible"); - } - ) + unwrap_addr(e).map_or_else(|| { + if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty { + span_lint(cx, + MUT_MUT, + expr.span, + "this expression mutably borrows a mutable reference. Consider \ + reborrowing"); + } + }, + |_| { + span_lint(cx, + MUT_MUT, + expr.span, + "generally you want to avoid `&mut &mut _` if possible"); + }) }) } fn unwrap_mut(ty: &Ty) -> Option<&Ty> { match ty.node { TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Some(pty), - _ => None + _ => None, } } diff --git a/src/mut_reference.rs b/src/mut_reference.rs index ddfd9ddcc13..d92e449e7f2 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -36,13 +36,12 @@ impl LateLintPass for UnnecessaryMutPassed { match borrowed_table.node_types.get(&fn_expr.id) { Some(function_type) => { if let ExprPath(_, ref path) = fn_expr.node { - check_arguments(cx, &arguments, function_type, - &format!("{}", path)); + check_arguments(cx, &arguments, function_type, &format!("{}", path)); } } None => unreachable!(), // A function with unknown type is called. - // If this happened the compiler would have aborted the - // compilation long ago. + // If this happened the compiler would have aborted the + // compilation long ago. }; @@ -50,8 +49,9 @@ impl LateLintPass for UnnecessaryMutPassed { ExprMethodCall(ref name, _, ref arguments) => { let method_call = MethodCall::expr(e.id); match borrowed_table.method_map.get(&method_call) { - Some(method_type) => check_arguments(cx, &arguments, method_type.ty, - &format!("{}", name.node.as_str())), + Some(method_type) => { + check_arguments(cx, &arguments, method_type.ty, &format!("{}", name.node.as_str())) + } None => unreachable!(), // Just like above, this should never happen. }; } @@ -68,10 +68,10 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty TypeVariants::TyRef(_, TypeAndMut {mutbl: MutImmutable, ..}) | TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, UNNECESSARY_MUT_PASSED, - argument.span, &format!("The function/method \"{}\" \ - doesn't need a mutable reference", - name)); + span_lint(cx, + UNNECESSARY_MUT_PASSED, + argument.span, + &format!("The function/method \"{}\" doesn't need a mutable reference", name)); } } _ => {} diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 8899eb56d42..7b75bd747bb 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -52,17 +52,13 @@ impl LateLintPass for MutexAtomic { if match_type(cx, ty, &MUTEX_PATH) { let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; if let Some(atomic_name) = get_atomic_name(mutex_param) { - let msg = format!("Consider using an {} instead of a \ - Mutex here. If you just want the \ - locking behaviour and not the internal \ - type, consider using Mutex<()>.", + let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \ + behaviour and not the internal type, consider using Mutex<()>.", atomic_name); match *mutex_param { - ty::TyUint(t) if t != ast::TyUs => - span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::TyInt(t) if t != ast::TyIs => - span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg) + ty::TyUint(t) if t != ast::TyUs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + ty::TyInt(t) if t != ast::TyIs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), }; } } @@ -76,6 +72,6 @@ fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> { ty::TyUint(_) => Some("AtomicUsize"), ty::TyInt(_) => Some("AtomicIsize"), ty::TyRawPtr(_) => Some("AtomicPtr"), - _ => None + _ => None, } } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index bd2e4116fd0..22edbc272bd 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -37,30 +37,42 @@ impl LateLintPass for NeedlessBool { if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (Some(true), Some(true)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, + span_lint(cx, + NEEDLESS_BOOL, + e.span, "this if-then-else expression will always return true"); } (Some(false), Some(false)) => { - span_lint(cx, NEEDLESS_BOOL, e.span, + span_lint(cx, + NEEDLESS_BOOL, + e.span, "this if-then-else expression will always return false"); } (Some(true), Some(false)) => { let pred_snip = snippet(cx, pred.span, ".."); - let hint = if pred_snip == ".." { "its predicate".into() } else { + let hint = if pred_snip == ".." { + "its predicate".into() + } else { format!("`{}`", pred_snip) }; - span_lint(cx, NEEDLESS_BOOL, e.span, &format!( - "you can reduce this if-then-else expression to just {}", hint)); + span_lint(cx, + NEEDLESS_BOOL, + e.span, + &format!("you can reduce this if-then-else expression to just {}", hint)); } (Some(false), Some(true)) => { let pred_snip = snippet(cx, pred.span, ".."); - let hint = if pred_snip == ".." { "`!` and its predicate".into() } else { + let hint = if pred_snip == ".." { + "`!` and its predicate".into() + } else { format!("`!{}`", pred_snip) }; - span_lint(cx, NEEDLESS_BOOL, e.span, &format!( - "you can reduce this if-then-else expression to just {}", hint)); + span_lint(cx, + NEEDLESS_BOOL, + e.span, + &format!("you can reduce this if-then-else expression to just {}", hint)); } - _ => () + _ => (), } } } @@ -69,14 +81,21 @@ impl LateLintPass for NeedlessBool { fn fetch_bool_block(block: &Block) -> Option<bool> { if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) - } else { None } + } else { + None + } } fn fetch_bool_expr(expr: &Expr) -> Option<bool> { match expr.node { ExprBlock(ref block) => fetch_bool_block(block), - ExprLit(ref lit_ptr) => if let LitBool(value) = lit_ptr.node { - Some(value) } else { None }, - _ => None + ExprLit(ref lit_ptr) => { + if let LitBool(value) = lit_ptr.node { + Some(value) + } else { + None + } + } + _ => None, } } diff --git a/src/needless_features.rs b/src/needless_features.rs index 2dd53c2d783..2c293d04600 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -49,14 +49,16 @@ impl LateLintPass for NeedlessFeaturesPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(ref name, _, _) = expr.node { if name.node.as_str() == "as_slice" && check_paths(cx, expr) { - span_lint(cx, UNSTABLE_AS_SLICE, expr.span, - "used as_slice() from the 'convert' nightly feature. Use &[..] \ - instead"); + span_lint(cx, + UNSTABLE_AS_SLICE, + expr.span, + "used as_slice() from the 'convert' nightly feature. Use &[..] instead"); } if name.node.as_str() == "as_mut_slice" && check_paths(cx, expr) { - span_lint(cx, UNSTABLE_AS_MUT_SLICE, expr.span, - "used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] \ - instead"); + span_lint(cx, + UNSTABLE_AS_MUT_SLICE, + expr.span, + "used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] instead"); } } } diff --git a/src/needless_update.rs b/src/needless_update.rs index 9a314616cdc..1b306df8eed 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -32,9 +32,10 @@ impl LateLintPass for NeedlessUpdatePass { let ty = cx.tcx.expr_ty(expr); if let TyStruct(def, _) = ty.sty { if fields.len() == def.struct_variant().fields.len() { - span_lint(cx, NEEDLESS_UPDATE, base.span, - "struct update has no effect, all the fields \ - in the struct have already been specified"); + span_lint(cx, + NEEDLESS_UPDATE, + base.span, + "struct update has no effect, all the fields in the struct have already been specified"); } } } diff --git a/src/no_effect.rs b/src/no_effect.rs index b51b4235d54..3b2d91fc78e 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -37,9 +37,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); match def { Some(DefStruct(..)) | - Some(DefVariant(..)) => { - args.iter().all(|arg| has_no_effect(cx, arg)) - } + Some(DefVariant(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), _ => false, } } @@ -60,8 +58,7 @@ impl LateLintPass for NoEffectPass { fn check_stmt(&mut self, cx: &LateContext, stmt: &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"); + span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect"); } } } diff --git a/src/open_options.rs b/src/open_options.rs index 31ca0d72939..26784cb6008 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -31,7 +31,7 @@ impl LateLintPass for NonSensicalOpenOptions { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprMethodCall(ref name, _, ref arguments) = e.node { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); - if name.node.as_str() == "open" && match_type(cx, obj_ty, &OPEN_OPTIONS_PATH){ + if name.node.as_str() == "open" && match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) { let mut options = Vec::new(); get_open_options(cx, &arguments[0], &mut options); check_open_options(cx, &options, e.span); @@ -44,7 +44,7 @@ impl LateLintPass for NonSensicalOpenOptions { enum Argument { True, False, - Unknown + Unknown, } #[derive(Debug)] @@ -53,31 +53,33 @@ enum OpenOption { Read, Truncate, Create, - Append + Append, } fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { if let ExprMethodCall(ref name, _, ref arguments) = argument.node { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); - + // Only proceed if this is a call on some object of type std::fs::OpenOptions if match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) && arguments.len() >= 2 { - + let argument_option = match arguments[1].node { ExprLit(ref span) => { if let Spanned {node: LitBool(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 - } + _ => Argument::Unknown, }; - + match &*name.node.as_str() { "create" => { options.push((OpenOption::Create, argument_option)); @@ -96,7 +98,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp } _ => {} } - + get_open_options(cx, &arguments[0], options); } } @@ -104,39 +106,124 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp fn check_for_duplicates(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. - if options.iter().filter(|o| if let (OpenOption::Create, _) = **o {true} else {false}).count() > 1 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"create\" \ - is called more than once"); + if options.iter() + .filter(|o| { + if let (OpenOption::Create, _) = **o { + true + } else { + false + } + }) + .count() > 1 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"create\" is called more than once"); } - if options.iter().filter(|o| if let (OpenOption::Append, _) = **o {true} else {false}).count() > 1 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"append\" \ - is called more than once"); + if options.iter() + .filter(|o| { + if let (OpenOption::Append, _) = **o { + true + } else { + false + } + }) + .count() > 1 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"append\" is called more than once"); } - if options.iter().filter(|o| if let (OpenOption::Truncate, _) = **o {true} else {false}).count() > 1 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"truncate\" \ - is called more than once"); + if options.iter() + .filter(|o| { + if let (OpenOption::Truncate, _) = **o { + true + } else { + false + } + }) + .count() > 1 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"truncate\" is called more than once"); } - if options.iter().filter(|o| if let (OpenOption::Read, _) = **o {true} else {false}).count() > 1 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"read\" \ - is called more than once"); + if options.iter() + .filter(|o| { + if let (OpenOption::Read, _) = **o { + true + } else { + false + } + }) + .count() > 1 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"read\" is called more than once"); } - if options.iter().filter(|o| if let (OpenOption::Write, _) = **o {true} else {false}).count() > 1 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "The method \"write\" \ - is called more than once"); + if options.iter() + .filter(|o| { + if let (OpenOption::Write, _) = **o { + true + } else { + false + } + }) + .count() > 1 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"write\" is called more than once"); } } fn check_for_inconsistencies(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { // Truncate + read makes no sense. - if options.iter().filter(|o| if let (OpenOption::Read, Argument::True) = **o {true} else {false}).count() > 0 && - options.iter().filter(|o| if let (OpenOption::Truncate, Argument::True) = **o {true} else {false}).count() > 0 { + if options.iter() + .filter(|o| { + if let (OpenOption::Read, Argument::True) = **o { + true + } else { + false + } + }) + .count() > 0 && + options.iter() + .filter(|o| { + if let (OpenOption::Truncate, Argument::True) = **o { + true + } else { + false + } + }) + .count() > 0 { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"truncate\" and \"read\""); } - + // Append + truncate makes no sense. - if options.iter().filter(|o| if let (OpenOption::Append, Argument::True) = **o {true} else {false}).count() > 0 && - options.iter().filter(|o| if let (OpenOption::Truncate, Argument::True) = **o {true} else {false}).count() > 0 { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"append\" and \"truncate\""); + if options.iter() + .filter(|o| { + if let (OpenOption::Append, Argument::True) = **o { + true + } else { + false + } + }) + .count() > 0 && + options.iter() + .filter(|o| { + if let (OpenOption::Truncate, Argument::True) = **o { + true + } else { + false + } + }) + .count() > 0 { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "File opened with \"append\" and \"truncate\""); } } diff --git a/src/precedence.rs b/src/precedence.rs index 91ff0680b3e..8253471f8b0 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -31,29 +31,40 @@ impl LintPass for Precedence { impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { - if !is_bit_op(op) { return; } + if !is_bit_op(op) { + return; + } match (is_arith_expr(left), is_arith_expr(right)) { (true, true) => { - span_lint(cx, PRECEDENCE, expr.span, - &format!("operator precedence can trip the unwary. \ - Consider parenthesizing your expression:\ - `({}) {} ({})`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))); - }, + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`({}) {} ({})`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } (true, false) => { - span_lint(cx, PRECEDENCE, expr.span, - &format!("operator precedence can trip the unwary. \ - Consider parenthesizing your expression:\ - `({}) {} {}`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))); - }, + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`({}) {} {}`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } (false, true) => { - span_lint(cx, PRECEDENCE, expr.span, - &format!("operator precedence can trip the unwary. \ - Consider parenthesizing your expression:\ - `{} {} ({})`", snippet(cx, left.span, ".."), - op.to_string(), snippet(cx, right.span, ".."))); - }, + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`{} {} ({})`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } _ => (), } } @@ -64,13 +75,14 @@ impl EarlyLintPass for Precedence { if let ExprLit(ref lit) = slf.node { match lit.node { LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => { - span_lint(cx, PRECEDENCE, expr.span, &format!( - "unary minus has lower precedence than \ - method call. Consider adding parentheses \ - to clarify your intent: -({})", - snippet(cx, rhs.span, ".."))); + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("unary minus has lower precedence than method call. Consider \ + adding parentheses to clarify your intent: -({})", + snippet(cx, rhs.span, ".."))); } - _ => () + _ => (), } } } @@ -82,20 +94,20 @@ impl EarlyLintPass for Precedence { fn is_arith_expr(expr: &Expr) -> bool { match expr.node { ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), - _ => false + _ => false, } } fn is_bit_op(op: BinOp_) -> bool { match op { BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, - _ => false + _ => false, } } fn is_arith_op(op: BinOp_) -> bool { match op { BiAdd | BiSub | BiMul | BiDiv | BiRem => true, - _ => false + _ => false, } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index f748dbd9cfa..2e1e16cf22b 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -63,14 +63,17 @@ fn check_fn(cx: &LateContext, decl: &FnDecl) { if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&arg.ty.id) { if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { if match_type(cx, ty, &VEC_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference \ - and cannot be used with non-Vec-based slices. Consider changing \ - the type to `&[...]`"); + span_lint(cx, + PTR_ARG, + arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ + with non-Vec-based slices. Consider changing the type to `&[...]`"); } else if match_type(cx, ty, &STRING_PATH) { - span_lint(cx, PTR_ARG, arg.ty.span, - "writing `&String` instead of `&str` involves a new object \ - where a slice will do. Consider changing the type to `&str`"); + span_lint(cx, + PTR_ARG, + arg.ty.span, + "writing `&String` instead of `&str` involves a new object where a slice will do. \ + Consider changing the type to `&str`"); } } } diff --git a/src/ranges.rs b/src/ranges.rs index 48bbba734ff..692a5a2da1d 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -37,18 +37,15 @@ impl LintPass for StepByZero { impl LateLintPass for StepByZero { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(Spanned { node: ref name, .. }, _, - ref args) = expr.node { + if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { // Range with step_by(0). - if name.as_str() == "step_by" && args.len() == 2 && - is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { - cx.span_lint(RANGE_STEP_BY_ZERO, expr.span, - "Range::step_by(0) produces an infinite iterator. \ - Consider using `std::iter::repeat()` instead") - } - - // x.iter().zip(0..x.len()) - else if name.as_str() == "zip" && args.len() == 2 { + if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && + is_integer_literal(&args[1], 0) { + cx.span_lint(RANGE_STEP_BY_ZERO, + expr.span, + "Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \ + instead") + } else if name.as_str() == "zip" && args.len() == 2 { let iter = &args[0].node; let zip_arg = &args[1].node; if_let_chain! { diff --git a/src/returns.rs b/src/returns.rs index 15f9bb80d95..e4745b8766f 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use syntax::ast::*; -//use reexport::*; +// use reexport::*; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; @@ -67,19 +67,17 @@ impl ReturnPass { self.check_final_expr(cx, &arm.body); } } - _ => { } + _ => {} } } fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) { - if in_external_macro(cx, spans.1) {return;} - span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, - "unneeded return statement", - |db| { + if in_external_macro(cx, spans.1) { + return; + } + span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", |db| { if let Some(snippet) = snippet_opt(cx, spans.1) { - db.span_suggestion(spans.0, - "remove `return` as shown:", - snippet); + db.span_suggestion(spans.0, "remove `return` as shown:", snippet); } }); } @@ -104,13 +102,16 @@ impl ReturnPass { } fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) { - if in_external_macro(cx, note_span) {return;} - let mut db = span_lint(cx, LET_AND_RETURN, lint_span, - "returning the result of a let binding from a block. \ - Consider returning the expression directly."); + if in_external_macro(cx, note_span) { + return; + } + let mut db = span_lint(cx, + LET_AND_RETURN, + lint_span, + "returning the result of a let binding from a block. Consider returning the \ + expression directly."); if cx.current_level(LET_AND_RETURN) != Level::Allow { - db.span_note(note_span, - "this expression can be directly returned"); + db.span_note(note_span, "this expression can be directly returned"); } } } @@ -122,8 +123,7 @@ impl LintPass for ReturnPass { } impl EarlyLintPass for ReturnPass { - fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, - block: &Block, _: Span, _: NodeId) { + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { self.check_block_return(cx, block); } diff --git a/src/shadow.rs b/src/shadow.rs index 1210590bbcb..2d3e423eacb 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -45,13 +45,13 @@ impl LintPass for ShadowPass { fn get_lints(&self) -> LintArray { lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) } - } impl LateLintPass for ShadowPass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, - block: &Block, _: Span, _: NodeId) { - if in_external_macro(cx, block.span) { return; } + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, block: &Block, _: Span, _: NodeId) { + if in_external_macro(cx, block.span) { + return; + } check_fn(cx, decl, block); } } @@ -71,20 +71,27 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)> for stmt in &block.stmts { match stmt.node { StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), - StmtExpr(ref e, _) | StmtSemi(ref e, _) => - check_expr(cx, e, bindings) + StmtExpr(ref e, _) | StmtSemi(ref e, _) => check_expr(cx, e, bindings), } } - if let Some(ref o) = block.expr { check_expr(cx, o, bindings); } + if let Some(ref o) = block.expr { + check_expr(cx, o, bindings); + } bindings.truncate(len); } fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { - if in_external_macro(cx, decl.span) { return; } - if is_from_for_desugar(decl) { return; } + if in_external_macro(cx, decl.span) { + return; + } + if is_from_for_desugar(decl) { + return; + } if let DeclLocal(ref local) = decl.node { let Local{ ref pat, ref ty, ref init, span, .. } = **local; - if let Some(ref t) = *ty { check_ty(cx, t, bindings) } + if let Some(ref t) = *ty { + check_ty(cx, t, bindings) + } if let Some(ref o) = *init { check_expr(cx, o, bindings); check_pat(cx, pat, &Some(o), span, bindings); @@ -97,13 +104,12 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { fn is_binding(cx: &LateContext, pat: &Pat) -> bool { match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { Some(DefVariant(..)) | Some(DefStruct(..)) => false, - _ => true + _ => true, } } -fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, - bindings: &mut Vec<(Name, Span)>) { - //TODO: match more stuff / destructuring +fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { + // TODO: match more stuff / destructuring match pat.node { PatIdent(_, ref ident, ref inner) => { let name = ident.node.unhygienic_name; @@ -121,17 +127,19 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings.push((name, ident.span)); } } - if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); } + if let Some(ref p) = *inner { + check_pat(cx, p, init, span, bindings); + } } - //PatEnum(Path, Option<Vec<P<Pat>>>), - PatStruct(_, ref pfields, _) => + // PatEnum(Path, Option<Vec<P<Pat>>>), + PatStruct(_, ref pfields, _) => { if let Some(ref 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(|ref f| f.name.node == name) - .map(|f| &*f.expr); + .find(|ref f| f.name.node == name) + .map(|f| &*f.expr); check_pat(cx, &field.node.pat, &efield, span, bindings); } } else { @@ -143,8 +151,9 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, for field in pfields { check_pat(cx, &field.node.pat, &None, span, bindings); } - }, - PatTup(ref inner) => + } + } + PatTup(ref inner) => { if let Some(ref init_tup) = *init { if let ExprTup(ref tup) = init_tup.node { for (i, p) in inner.iter().enumerate() { @@ -159,7 +168,8 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, for p in inner { check_pat(cx, p, &None, span, bindings); } - }, + } + } PatBox(ref inner) => { if let Some(ref initp) = *init { if let ExprBox(ref inner_init) = initp.node { @@ -171,15 +181,15 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, check_pat(cx, inner, init, span, bindings); } } - PatRegion(ref inner, _) => - check_pat(cx, inner, init, span, bindings), - //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), + PatRegion(ref inner, _) => check_pat(cx, inner, init, span, bindings), + // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), _ => (), } } -fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: - &Option<T>, prev_span: Span) where T: Deref<Target=Expr> { +fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: &Option<T>, prev_span: Span) + where T: Deref<Target = Expr> +{ fn note_orig(cx: &LateContext, mut db: DiagnosticWrapper, lint: &'static Lint, span: Span) { if cx.current_level(lint) != Level::Allow { db.span_note(span, "previous binding is here"); @@ -187,51 +197,69 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: } if let Some(ref expr) = *init { if is_self_shadow(name, expr) { - let db = span_lint(cx, SHADOW_SAME, span, &format!( - "{} is shadowed by itself in {}", - snippet(cx, lspan, "_"), - snippet(cx, expr.span, ".."))); - note_orig(cx, db, SHADOW_SAME, prev_span); + let db = span_lint(cx, + SHADOW_SAME, + span, + &format!("{} is shadowed by itself in {}", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, ".."))); + note_orig(cx, db, SHADOW_SAME, prev_span); } else { if contains_self(name, expr) { - let db = span_note_and_lint(cx, SHADOW_REUSE, lspan, &format!( - "{} is shadowed by {} which reuses the original value", - snippet(cx, lspan, "_"), - snippet(cx, expr.span, "..")), - expr.span, "initialization happens here"); + let db = span_note_and_lint(cx, + SHADOW_REUSE, + lspan, + &format!("{} is shadowed by {} which reuses the original value", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); note_orig(cx, db, SHADOW_REUSE, prev_span); } else { - let db = span_note_and_lint(cx, SHADOW_UNRELATED, lspan, &format!( - "{} is shadowed by {}", - snippet(cx, lspan, "_"), - snippet(cx, expr.span, "..")), - expr.span, "initialization happens here"); + let db = span_note_and_lint(cx, + SHADOW_UNRELATED, + lspan, + &format!("{} is shadowed by {}", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); note_orig(cx, db, SHADOW_UNRELATED, prev_span); } } } else { - let db = span_lint(cx, SHADOW_UNRELATED, span, &format!( - "{} shadows a previous declaration", snippet(cx, lspan, "_"))); + let db = span_lint(cx, + SHADOW_UNRELATED, + span, + &format!("{} shadows a previous declaration", snippet(cx, lspan, "_"))); note_orig(cx, db, SHADOW_UNRELATED, prev_span); } } fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { - if in_external_macro(cx, expr.span) { return; } + if in_external_macro(cx, expr.span) { + return; + } match expr.node { - ExprUnary(_, ref e) | ExprField(ref e, _) | - ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) - => { check_expr(cx, e, bindings) } - ExprBlock(ref block) | ExprLoop(ref block, _) => - { check_block(cx, block, bindings) } - //ExprCall - //ExprMethodCall - ExprVec(ref v) | ExprTup(ref v) => - for ref e in v { check_expr(cx, e, bindings) }, + ExprUnary(_, ref e) | + ExprField(ref e, _) | + ExprTupField(ref e, _) | + ExprAddrOf(_, ref e) | + ExprBox(ref e) => check_expr(cx, e, bindings), + ExprBlock(ref block) | ExprLoop(ref block, _) => check_block(cx, block, bindings), + // ExprCall + // ExprMethodCall + ExprVec(ref v) | ExprTup(ref v) => { + for ref 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); } + if let Some(ref o) = *otherwise { + check_expr(cx, o, bindings); + } } ExprWhile(ref cond, ref block, _) => { check_expr(cx, cond, bindings); @@ -243,7 +271,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { for ref arm in arms { for ref pat in &arm.pats { check_pat(cx, &pat, &Some(&**init), pat.span, bindings); - //This is ugly, but needed to get the right type + // This is ugly, but needed to get the right type if let Some(ref guard) = arm.guard { check_expr(cx, guard, bindings); } @@ -252,7 +280,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { } } } - _ => () + _ => (), } } @@ -266,7 +294,11 @@ fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { } TyPtr(MutTy{ ty: ref mty, .. }) | TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings), - TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } } + TyTup(ref tup) => { + for ref t in tup { + check_ty(cx, t, bindings) + } + } TyTypeof(ref expr) => check_expr(cx, expr, bindings), _ => (), } @@ -276,23 +308,22 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { match expr.node { ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), - ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref(). - map_or(false, |ref e| is_self_shadow(name, e)), - ExprUnary(op, ref inner) => (UnDeref == op) && - is_self_shadow(name, inner), + ExprBlock(ref block) => { + block.stmts.is_empty() && block.expr.as_ref().map_or(false, |ref 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), _ => false, } } fn path_eq_name(name: Name, path: &Path) -> bool { - !path.global && path.segments.len() == 1 && - path.segments[0].identifier.unhygienic_name == name + !path.global && path.segments.len() == 1 && path.segments[0].identifier.unhygienic_name == name } struct ContainsSelf { name: Name, - result: bool + result: bool, } impl<'v> Visitor<'v> for ContainsSelf { @@ -304,7 +335,10 @@ impl<'v> Visitor<'v> for ContainsSelf { } fn contains_self(name: Name, expr: &Expr) -> bool { - let mut cs = ContainsSelf { name: name, result: false }; + let mut cs = ContainsSelf { + name: name, + result: false, + }; cs.visit_expr(expr); cs.result } diff --git a/src/strings.rs b/src/strings.rs index 2baf26095b7..55d1a0acf68 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -68,19 +68,24 @@ impl LateLintPass for StringAdd { if let Some(ref p) = parent { if let ExprAssign(ref target, _) = p.node { // avoid duplicate matches - if is_exp_equal(cx, target, left) { return; } + if is_exp_equal(cx, target, left) { + return; + } } } } - span_lint(cx, STRING_ADD, e.span, - "you added something to a string. \ - Consider using `String::push_str()` instead"); + span_lint(cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead"); } } else if let ExprAssign(ref target, ref src) = e.node { if is_string(cx, target) && is_add(cx, src, target) { - span_lint(cx, STRING_ADD_ASSIGN, e.span, - "you assigned the result of adding something to this string. \ - Consider using `String::push_str()` instead"); + span_lint(cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ + `String::push_str()` instead"); } } } @@ -92,11 +97,10 @@ fn is_string(cx: &LateContext, e: &Expr) -> bool { fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { - ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => - is_exp_equal(cx, target, left), - ExprBlock(ref block) => block.stmts.is_empty() && - block.expr.as_ref().map_or(false, - |expr| is_add(cx, expr, target)), - _ => false + ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left), + ExprBlock(ref block) => { + block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) + } + _ => false, } } diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs index 622bf5bc25e..7d5057d8377 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -40,11 +40,10 @@ impl LateLintPass for TemporaryAssignmentPass { match target.node { ExprField(ref base, _) | ExprTupField(ref base, _) => { if is_temporary(base) && !is_adjusted(cx, base) { - span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, - "assignment to temporary"); + span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } } - _ => () + _ => (), } } } diff --git a/src/transmute.rs b/src/transmute.rs index c71468bf5a0..24af45bc68d 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -34,7 +34,8 @@ impl LateLintPass for UselessTransmute { let to_ty = cx.tcx.expr_ty(e); if from_ty == to_ty { - cx.span_lint(USELESS_TRANSMUTE, e.span, + cx.span_lint(USELESS_TRANSMUTE, + e.span, &format!("transmute from a type (`{}`) to itself", from_ty)); } } diff --git a/src/types.rs b/src/types.rs index e119ef63436..6289e13c85a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -49,22 +49,23 @@ 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 + return; } if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { if let ty::TyBox(ref inner) = ty.sty { if match_type(cx, inner, &VEC_PATH) { - span_help_and_lint( - cx, BOX_VEC, ast_ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); + span_help_and_lint(cx, + BOX_VEC, + ast_ty.span, + "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); } - } - else if match_type(cx, ty, &LL_PATH) { - 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"); + } else if match_type(cx, ty, &LL_PATH) { + 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"); } } } @@ -87,12 +88,17 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) { if let DeclLocal(ref local) = decl.node { let bindtype = &cx.tcx.pat_ty(&local.pat).sty; if *bindtype == ty::TyTuple(vec![]) { - if in_external_macro(cx, decl.span) || - in_macro(cx, local.pat.span) { return; } - if is_from_for_desugar(decl) { return; } - span_lint(cx, LET_UNIT_VALUE, decl.span, &format!( - "this let-binding has unit value. Consider omitting `let {} =`", - snippet(cx, local.pat.span, ".."))); + if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) { + return; + } + if is_from_for_desugar(decl) { + return; + } + span_lint(cx, + LET_UNIT_VALUE, + decl.span, + &format!("this let-binding has unit value. Consider omitting `let {} =`", + snippet(cx, local.pat.span, ".."))); } } } @@ -130,18 +136,23 @@ impl LintPass for UnitCmp { impl LateLintPass for UnitCmp { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_macro(cx, expr.span) { return; } + if in_macro(cx, expr.span) { + return; + } if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; let sty = &cx.tcx.expr_ty(left).sty; if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) { let result = match op { BiEq | BiLe | BiGe => "true", - _ => "false" + _ => "false", }; - span_lint(cx, UNIT_CMP, expr.span, &format!( - "{}-comparison of unit values detected. This will always be {}", - binop_to_string(op), result)); + span_lint(cx, + UNIT_CMP, + expr.span, + &format!("{}-comparison of unit values detected. This will always be {}", + binop_to_string(op), + result)); } } } @@ -192,38 +203,64 @@ declare_lint!(pub CAST_POSSIBLE_WRAP, Allow, /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: &ty::TyS) -> usize { let n = match typ.sty { - ty::TyInt(i) => 4 << (i as usize), + ty::TyInt(i) => 4 << (i as usize), ty::TyUint(u) => 4 << (u as usize), - _ => 0 + _ => 0, }; // n == 4 is the usize/isize case - if n == 4 { ::std::usize::BITS } else { n } + if n == 4 { + ::std::usize::BITS + } else { + n + } } fn is_isize_or_usize(typ: &ty::TyS) -> bool { match typ.sty { ty::TyInt(TyIs) | ty::TyUint(TyUs) => true, - _ => false + _ => false, } } 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 {"64".to_owned()} - else if is_isize_or_usize(cast_from) {"32 or 64".to_owned()} - else {int_ty_to_nbits(cast_from).to_string()}; - span_lint(cx, CAST_PRECISION_LOSS, expr.span, - &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 arch_dependent {arch_dependent_str} else {""}, - from_nbits_str, mantissa_nbits)); + let from_nbits_str = if arch_dependent { + "64".to_owned() + } else if is_isize_or_usize(cast_from) { + "32 or 64".to_owned() + } else { + int_ty_to_nbits(cast_from).to_string() + }; + span_lint(cx, + CAST_PRECISION_LOSS, + expr.span, + &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 arch_dependent { + arch_dependent_str + } else { + "" + }, + from_nbits_str, + mantissa_nbits)); } enum ArchSuffix { - _32, _64, None + _32, + _64, + None, } fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { @@ -231,44 +268,60 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty:: let arch_32_suffix = " on targets with 32-bit wide pointers"; let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to)); - let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = - match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => ( - to_nbits < from_nbits, - ArchSuffix::None, - to_nbits == from_nbits && cast_unsigned_to_signed, + let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), + is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => { + (to_nbits < from_nbits, + 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 - ), - (true, false) => ( - to_nbits <= 32, - if to_nbits == 32 {ArchSuffix::_64} else {ArchSuffix::None}, - to_nbits <= 32 && cast_unsigned_to_signed, + }, + 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 - ), - (false, true) => ( - from_nbits == 64, - ArchSuffix::_32, - cast_unsigned_to_signed, - if from_nbits == 64 {ArchSuffix::_64} else {ArchSuffix::_32} - ), - }; + }) + } + }; if span_truncation { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, - &format!("casting {} to {} may truncate the value{}", - cast_from, cast_to, - match suffix_truncation { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "" })); + span_lint(cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + &format!("casting {} to {} may truncate the value{}", + cast_from, + cast_to, + match suffix_truncation { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + })); } if span_wrap { - span_lint(cx, CAST_POSSIBLE_WRAP, expr.span, - &format!("casting {} to {} may wrap around the value{}", - cast_from, cast_to, - match suffix_wrap { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "" })); + span_lint(cx, + CAST_POSSIBLE_WRAP, + expr.span, + &format!("casting {} to {} may wrap around the value{}", + cast_from, + cast_to, + match suffix_wrap { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + })); } } @@ -289,35 +342,42 @@ impl LateLintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = if let ty::TyFloat(TyF32) = cast_to.sty {32} else {64}; + let to_nbits = if let ty::TyFloat(TyF32) = cast_to.sty { + 32 + } else { + 64 + }; 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, expr.span, - &format!("casting {} to {} may truncate the value", - cast_from, cast_to)); + span_lint(cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + &format!("casting {} to {} may truncate the value", cast_from, cast_to)); if !cast_to.is_signed() { - span_lint(cx, CAST_SIGN_LOSS, expr.span, - &format!("casting {} to {} may lose the sign of the value", - cast_from, cast_to)); + span_lint(cx, + CAST_SIGN_LOSS, + 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, CAST_SIGN_LOSS, expr.span, - &format!("casting {} to {} may lose the sign of the value", - cast_from, cast_to)); + span_lint(cx, + CAST_SIGN_LOSS, + expr.span, + &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(TyF64), - &ty::TyFloat(TyF32)) = (&cast_from.sty, &cast_to.sty) { - span_lint(cx, CAST_POSSIBLE_TRUNCATION, - expr.span, - "casting f64 to f32 may truncate the value"); + if let (&ty::TyFloat(TyF64), &ty::TyFloat(TyF32)) = (&cast_from.sty, &cast_to.sty) { + span_lint(cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + "casting f64 to f32 may truncate the value"); } } } @@ -360,7 +420,7 @@ impl LateLintPass for TypeComplexityPass { ItemStatic(ref ty, _, _) | ItemConst(ref ty, _) => check_type(cx, ty), // functions, enums, structs, impls and traits are covered - _ => () + _ => (), } } @@ -370,7 +430,7 @@ impl LateLintPass for TypeComplexityPass { TypeTraitItem(_, Some(ref ty)) => check_type(cx, ty), MethodTraitItem(MethodSig { ref decl, .. }, None) => check_fndecl(cx, decl), // methods with default impl are covered by check_fn - _ => () + _ => (), } } @@ -379,7 +439,7 @@ impl LateLintPass for TypeComplexityPass { ImplItemKind::Const(ref ty, _) | ImplItemKind::Type(ref ty) => check_type(cx, ty), // methods are covered by check_fn - _ => () + _ => (), } } @@ -400,16 +460,23 @@ fn check_fndecl(cx: &LateContext, decl: &FnDecl) { } fn check_type(cx: &LateContext, ty: &Ty) { - if in_macro(cx, ty.span) { return; } + if in_macro(cx, ty.span) { + return; + } let score = { - let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; + let mut visitor = TypeComplexityVisitor { + score: 0, + nest: 1, + }; visitor.visit_ty(ty); visitor.score }; // println!("{:?} --> {}", ty, score); if score > 250 { - span_lint(cx, TYPE_COMPLEXITY, ty.span, &format!( - "very complex type used. Consider factoring parts into `type` definitions")); + span_lint(cx, + TYPE_COMPLEXITY, + ty.span, + &format!("very complex type used. Consider factoring parts into `type` definitions")); } } @@ -442,7 +509,7 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { TyBareFn(..) | TyPolyTraitRef(..) => (50 * self.nest, 1), - _ => (0, 0) + _ => (0, 0), }; self.score += add_score; self.nest += sub_nest; diff --git a/src/unicode.rs b/src/unicode.rs index a5b03087604..d5ea7199e10 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -58,11 +58,13 @@ impl LateLintPass for Unicode { } } -fn escape<T: Iterator<Item=char>>(s: T) -> String { +fn escape<T: Iterator<Item = char>>(s: T) -> String { let mut result = String::new(); for c in s { if c as u32 > 0x7F { - for d in c.escape_unicode() { result.push(d) }; + for d in c.escape_unicode() { + result.push(d) + } } else { result.push(c); } @@ -73,26 +75,30 @@ fn escape<T: Iterator<Item=char>>(s: T) -> String { fn check_str(cx: &LateContext, span: Span) { let string = snippet(cx, span, ""); if string.contains('\u{200B}') { - span_help_and_lint(cx, ZERO_WIDTH_SPACE, span, - "zero-width space detected", - &format!("Consider replacing the string with:\n\"{}\"", - string.replace("\u{200B}", "\\u{200B}"))); + span_help_and_lint(cx, + ZERO_WIDTH_SPACE, + span, + "zero-width space detected", + &format!("Consider replacing the string with:\n\"{}\"", + string.replace("\u{200B}", "\\u{200B}"))); } if string.chars().any(|c| c as u32 > 0x7F) { - span_help_and_lint(cx, NON_ASCII_LITERAL, span, - "literal non-ASCII character detected", - &format!("Consider replacing the string with:\n\"{}\"", - if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { - escape(string.chars()) - } else { - escape(string.nfc()) - })); + span_help_and_lint(cx, + NON_ASCII_LITERAL, + span, + "literal non-ASCII character detected", + &format!("Consider replacing the string with:\n\"{}\"", + if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { + escape(string.chars()) + } else { + escape(string.nfc()) + })); } - if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && - string.chars().zip(string.nfc()).any(|(a, b)| a != b) { - span_help_and_lint(cx, UNICODE_NOT_NFC, span, - "non-nfc unicode sequence detected", - &format!("Consider replacing the string with:\n\"{}\"", - string.nfc().collect::<String>())); + if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && string.chars().zip(string.nfc()).any(|(a, b)| a != b) { + span_help_and_lint(cx, + UNICODE_NOT_NFC, + span, + "non-nfc unicode sequence detected", + &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>())); } } diff --git a/src/utils.rs b/src/utils.rs index 1b6c75a3b78..74a15927ad1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -19,15 +19,15 @@ use std::ops::{Deref, DerefMut}; pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for -pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; -pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; -pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; /// Produce a nested chain of if-lets and ifs from the patterns: @@ -82,8 +82,7 @@ pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { } /// returns true if this expn_info was expanded by any macro pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, - |info| info.is_some()) + cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) } /// returns true if the macro that expanded the crate was outside of @@ -95,42 +94,35 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { if let ExpnFormat::MacroAttribute(..) = info.callee.format { - // these are all plugins - return true; + // these are all plugins + return true; } // no span for the callee = external macro info.callee.span.map_or(true, |span| { // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| - // macro doesn't start with "macro_rules" - // = compiler plugin - !code.starts_with("macro_rules") - ) + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) }) }) } - cx.sess().codemap().with_expn_info(span.expn_id, - |info| in_macro_ext(cx, info)) + cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) } /// check if a DefId's path matches the given absolute type path /// usage e.g. with /// `match_def_path(cx, id, &["core", "option", "Option"])` pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| iter.zip(path) - .all(|(nm, p)| nm.name().as_str() == *p)) + cx.tcx.with_path(def_id, |iter| { + iter.zip(path) + .all(|(nm, p)| nm.name().as_str() == *p) + }) } /// check if type is struct or enum type with given def path pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { match ty.sty { - ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => { - match_def_path(cx, adt.did, path) - } - _ => { - false - } + ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), + _ => false, } } @@ -138,9 +130,12 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { 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)); + let trt_id = cx.tcx + .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 { @@ -151,9 +146,12 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { /// check if method call given in "expr" belongs to given trait pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); - let trt_id = cx.tcx.tables - .borrow().method_map.get(&method_call) - .and_then(|callee| cx.tcx.trait_of_item(callee.def_id)); + let trt_id = cx.tcx + .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 { @@ -164,15 +162,13 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a, b)| a.identifier.name.as_str() == *b) + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) } /// match a Path against a slice of segment string literals, e.g. /// `match_path(path, &["std", "rt", "begin_unwind"])` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a, b)| a.identifier.name.as_str() == *b) + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) } /// match an Expr against a chain of methods, and return the matched Exprs. For example, if `expr` @@ -181,17 +177,16 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); - for method_name in methods.iter().rev() { // method chains are stored last -> first + for method_name in methods.iter().rev() { + // method chains are stored last -> first if let ExprMethodCall(ref name, _, ref args) = current.node { if name.node.as_str() == *method_name { matched.push(args); // build up `matched` backwards current = &args[0] // go to parent expression - } - else { + } else { return None; } - } - else { + } else { return None; } } @@ -206,9 +201,7 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { match cx.tcx.map.find(parent_id) { Some(NodeItem(&Item{ ref name, .. })) | Some(NodeTraitItem(&TraitItem{ ref name, .. })) | - Some(NodeImplItem(&ImplItem{ ref name, .. })) => { - Some(*name) - } + Some(NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), _ => None, } } @@ -249,9 +242,7 @@ pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) - /// Like snippet_block, but add braces if the expr is not an ExprBlock /// Also takes an Option<String> which can be put inside the braces -pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, - option: Option<String>, - default: &'a str) -> Cow<'a, str> { +pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.map_or("".to_owned(), |s| s); if let ExprBlock(_) = expr.node { @@ -272,21 +263,33 @@ pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { } fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { - let x = s.lines().skip(ignore_first as usize) - .filter_map(|l| { if l.len() > 0 { // ignore empty lines - Some(l.char_indices() - .find(|&(_,x)| x != ch) - .unwrap_or((l.len(), ch)).0) - } else {None}}) - .min().unwrap_or(0); + let x = s.lines() + .skip(ignore_first as usize) + .filter_map(|l| { + if l.len() > 0 { + // ignore empty lines + Some(l.char_indices() + .find(|&(_, x)| x != ch) + .unwrap_or((l.len(), ch)) + .0) + } else { + None + } + }) + .min() + .unwrap_or(0); if x > 0 { - Cow::Owned(s.lines().enumerate().map(|(i,l)| if (ignore_first && i == 0) || - l.len() == 0 { - l - } else { - l.split_at(x).1 - }).collect::<Vec<_>>() - .join("\n")) + Cow::Owned(s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.len() == 0 { + l + } else { + l.split_at(x).1 + } + }) + .collect::<Vec<_>>() + .join("\n")) } else { s } @@ -295,11 +298,18 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { /// get a parent expr if any – this is useful to constrain a lint pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.map; - let node_id : NodeId = e.id; - let parent_id : NodeId = map.get_parent_node(node_id); - if node_id == parent_id { return None; } - map.find(parent_id).and_then(|node| - if let NodeExpr(parent) = node { Some(parent) } else { None } ) + let node_id: NodeId = e.id; + let parent_id: NodeId = map.get_parent_node(node_id); + if node_id == parent_id { + return None; + } + map.find(parent_id).and_then(|node| { + if let NodeExpr(parent) = node { + Some(parent) + } else { + None + } + }) } pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { @@ -310,9 +320,11 @@ pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c match node { NodeBlock(ref block) => Some(block), NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), - _ => None + _ => None, } - } else { None } + } else { + None + } } pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); @@ -326,56 +338,57 @@ impl<'a> Drop for DiagnosticWrapper<'a> { impl<'a> DerefMut for DiagnosticWrapper<'a> { fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { &mut self.0 - } + } } impl<'a> Deref for DiagnosticWrapper<'a> { type Target = DiagnosticBuilder<'a>; fn deref(&self) -> &DiagnosticBuilder<'a> { &self.0 - } + } } #[cfg(not(feature="structured_logging"))] -pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, - sp: Span, msg: &str) -> DiagnosticWrapper<'a> { +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { let mut db = cx.struct_span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { - db.fileline_help(sp, &format!("for further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.fileline_help(sp, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); } DiagnosticWrapper(db) } #[cfg(feature="structured_logging")] -pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, - sp: Span, msg: &str) -> DiagnosticWrapper<'a> { +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { // lint.name / lint.desc is can give details of the lint // cx.sess().codemap() has all these nice functions for line/column/snippet details // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string let mut db = cx.struct_span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { - db.fileline_help(sp, &format!("for further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.fileline_help(sp, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); } DiagnosticWrapper(db) } -pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, - msg: &str, help: &str) -> DiagnosticWrapper<'a> { +pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) + -> DiagnosticWrapper<'a> { let mut db = cx.struct_span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { - db.fileline_help(span, &format!("{}\nfor further information \ - visit https://github.com/Manishearth/rust-clippy/wiki#{}", - help, lint.name_lower())); + db.fileline_help(span, + &format!("{}\nfor further information visit \ + https://github.com/Manishearth/rust-clippy/wiki#{}", + help, + lint.name_lower())); } DiagnosticWrapper(db) } -pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, - msg: &str, note_span: Span, note: &str) -> DiagnosticWrapper<'a> { +pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, + note: &str) + -> DiagnosticWrapper<'a> { let mut db = cx.struct_span_lint(lint, span, msg); if cx.current_level(lint) != Level::Allow { if note_span == span { @@ -383,21 +396,23 @@ pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp } else { db.span_note(note_span, note); } - db.fileline_help(span, &format!("for further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.fileline_help(span, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); } DiagnosticWrapper(db) } -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, - msg: &str, f: F) -> DiagnosticWrapper<'a> where F: Fn(&mut DiagnosticWrapper) { +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) + -> DiagnosticWrapper<'a> + where F: Fn(&mut DiagnosticWrapper) +{ let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { f(&mut db); - db.fileline_help(sp, &format!("for further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.fileline_help(sp, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); } db } @@ -406,7 +421,7 @@ pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), - _ => ty + _ => ty, } } @@ -415,14 +430,13 @@ pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { match ty.sty { ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), - _ => (ty, depth) + _ => (ty, depth), } } inner(ty, 0) } -pub fn is_integer_literal(expr: &Expr, value: u64) -> bool -{ +pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { // FIXME: use constant folding if let ExprLit(ref spanned) = expr.node { if let LitInt(v, _) = spanned.node { @@ -448,37 +462,27 @@ impl Drop for LimitStack { impl LimitStack { pub fn new(limit: u64) -> LimitStack { - LimitStack { - stack: vec![limit], - } + LimitStack { stack: vec![limit] } } pub fn limit(&self) -> u64 { *self.stack.last().expect("there should always be a value in the stack") } pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { let stack = &mut self.stack; - parse_attrs( - sess, - attrs, - name, - |val| stack.push(val), - ); + parse_attrs(sess, attrs, name, |val| stack.push(val)); } pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { let stack = &mut self.stack; - parse_attrs( - sess, - attrs, - name, - |val| assert_eq!(stack.pop(), Some(val)), - ); + parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); } } fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { for attr in attrs { let attr = &attr.node; - if attr.is_sugared_doc { continue; } + if attr.is_sugared_doc { + continue; + } if let ast::MetaNameValue(ref key, ref value) = attr.value.node { if *key == name { if let LitStr(ref s, _) = value.node { @@ -495,70 +499,67 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } } -pub fn is_exp_equal(cx: &LateContext, left : &Expr, right : &Expr) -> bool { +pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr) -> bool { if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { if l == r { return true; } } match (&left.node, &right.node) { - (&ExprField(ref lfexp, ref lfident), - &ExprField(ref rfexp, ref rfident)) => - lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp), + (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { + lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp) + } (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprPath(ref lqself, ref lsubpath), - &ExprPath(ref rqself, ref rsubpath)) => - both(lqself, rqself, is_qself_equal) && - is_path_equal(lsubpath, rsubpath), - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => - is_exps_equal(cx, ltup, rtup), + (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { + both(lqself, rqself, is_qself_equal) && is_path_equal(lsubpath, rsubpath) + } + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup), (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => - is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), - _ => false + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), + _ => false, } } -fn is_exps_equal(cx: &LateContext, left : &[P<Expr>], right : &[P<Expr>]) -> bool { +fn is_exps_equal(cx: &LateContext, left: &[P<Expr>], right: &[P<Expr>]) -> bool { over(left, right, |l, r| is_exp_equal(cx, l, r)) } -fn is_path_equal(left : &Path, right : &Path) -> bool { +fn is_path_equal(left: &Path, right: &Path) -> bool { // The == of idents doesn't work with different contexts, // we have to be explicit about hygiene - left.global == right.global && over(&left.segments, &right.segments, - |l, r| l.identifier.name == r.identifier.name - && l.parameters == r.parameters) + left.global == right.global && + over(&left.segments, + &right.segments, + |l, r| l.identifier.name == r.identifier.name && l.parameters == r.parameters) } -fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool { +fn is_qself_equal(left: &QSelf, right: &QSelf) -> bool { left.ty.node == right.ty.node && left.position == right.position } fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool { - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| - eq_fn(x, y)) + where F: FnMut(&X, &X) -> bool +{ + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool - where F: FnMut(&X, &X) -> bool { - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, - |y| eq_fn(x, y))) +fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool +{ + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) } fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { match (&left.node, &right.node) { (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => - lmut.mutbl == rmut.mutbl && - is_cast_ty_equal(&*lmut.ty, &*rmut.ty), - (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => - lrmut.mutbl == rrmut.mutbl && - is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty), - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => - both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && is_cast_ty_equal(&*lmut.ty, &*rmut.ty), + (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => { + lrmut.mutbl == rrmut.mutbl && is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty) + } + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => { + both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath) + } (&TyInfer, &TyInfer) => true, - _ => false + _ => false, } } -- cgit 1.4.1-3-g733a5 From c1a99fdd90df92d5cb9a1b5b5f6ee66aad627766 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 4 Jan 2016 10:13:56 +0530 Subject: Fix dogfood failures by refactoring open_options --- src/lib.rs | 9 +-- src/open_options.rs | 186 +++++++++++++++++++--------------------------------- 2 files changed, 74 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 2ac8e9044db..8227be92543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] #![feature(num_bits_bytes, iter_arith)] +#![feature(custom_attribute)] #![allow(unknown_lints)] // this only exists to allow the "dogfood" integration test to work @@ -77,6 +78,7 @@ mod reexport { } #[plugin_registrar] +#[rustfmt_skip] pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::TypePass); reg.register_late_lint_pass(box misc::TopLevelRefPass); @@ -130,8 +132,8 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_late_lint_pass(box panic::PanicPass); - reg.register_lint_group("clippy_pedantic", - vec![ + + reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, @@ -150,8 +152,7 @@ pub fn plugin_registrar(reg: &mut Registry) { unicode::UNICODE_NOT_NFC, ]); - reg.register_lint_group("clippy", - vec![ + reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, array_indexing::OUT_OF_BOUNDS_INDEXING, attrs::INLINE_ALWAYS, diff --git a/src/open_options.rs b/src/open_options.rs index 26784cb6008..541ed2444f4 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -40,7 +40,7 @@ impl LateLintPass for NonSensicalOpenOptions { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] enum Argument { True, False, @@ -104,130 +104,82 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp } } -fn check_for_duplicates(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { +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); // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. - if options.iter() - .filter(|o| { - if let (OpenOption::Create, _) = **o { - true - } else { - false - } - }) - .count() > 1 { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "The method \"create\" is called more than once"); - } - if options.iter() - .filter(|o| { - if let (OpenOption::Append, _) = **o { - true - } else { - false - } - }) - .count() > 1 { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "The method \"append\" is called more than once"); - } - if options.iter() - .filter(|o| { - if let (OpenOption::Truncate, _) = **o { - true - } else { - false - } - }) - .count() > 1 { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "The method \"truncate\" is called more than once"); - } - if options.iter() - .filter(|o| { - if let (OpenOption::Read, _) = **o { - true - } else { - false - } - }) - .count() > 1 { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "The method \"read\" is called more than once"); - } - if options.iter() - .filter(|o| { - if let (OpenOption::Write, _) = **o { - true - } else { - false - } - }) - .count() > 1 { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "The method \"write\" is called more than once"); + + for option in options { + match *option { + (OpenOption::Create, arg) => { + if create { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"create\" is called more than once"); + } else { + create = true + } + create_arg = create_arg || (arg == Argument::True);; + } + (OpenOption::Append, arg) => { + if append { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"append\" is called more than once"); + } else { + append = true + } + append_arg = append_arg || (arg == Argument::True);; + } + (OpenOption::Truncate, arg) => { + if truncate { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"truncate\" is called more than once"); + } else { + truncate = true + } + truncate_arg = truncate_arg || (arg == Argument::True); + } + (OpenOption::Read, arg) => { + if read { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"read\" is called more than once"); + } else { + read = true + } + read_arg = read_arg || (arg == Argument::True);; + } + (OpenOption::Write, arg) => { + if write { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "The method \"write\" is called more than once"); + } else { + write = true + } + write_arg = write_arg || (arg == Argument::True);; + } + } } -} -fn check_for_inconsistencies(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { - // Truncate + read makes no sense. - if options.iter() - .filter(|o| { - if let (OpenOption::Read, Argument::True) = **o { - true - } else { - false - } - }) - .count() > 0 && - options.iter() - .filter(|o| { - if let (OpenOption::Truncate, Argument::True) = **o { - true - } else { - false - } - }) - .count() > 0 { + if read && truncate && read_arg && truncate_arg { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"truncate\" and \"read\""); } - - // Append + truncate makes no sense. - if options.iter() - .filter(|o| { - if let (OpenOption::Append, Argument::True) = **o { - true - } else { - false - } - }) - .count() > 0 && - options.iter() - .filter(|o| { - if let (OpenOption::Truncate, Argument::True) = **o { - true - } else { - false - } - }) - .count() > 0 { + if append && truncate && append_arg && truncate_arg { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"append\" and \"truncate\""); } } - -fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { - check_for_duplicates(cx, options, span); - check_for_inconsistencies(cx, options, span); -} -- cgit 1.4.1-3-g733a5 From 002c8c34f8be15c35e2fc8fd640a250f5227d95b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 4 Jan 2016 20:01:08 +0530 Subject: re-add missing comments --- src/misc.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 1b7f2a921b9..4cee123909b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -365,9 +365,10 @@ impl LintPass for UsedUnderscoreBinding { } impl LateLintPass for UsedUnderscoreBinding { + #[rustfmt_skip] fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_attributes_expansion(cx, expr) { - // Don't lint things expanded by #[derive(...)], etc + // Don't lint things expanded by #[derive(...)], etc return; } let needs_lint = match expr.node { @@ -376,9 +377,9 @@ impl LateLintPass for UsedUnderscoreBinding { .last() .expect("path should always have at least one segment") .identifier; - ident.name.as_str().chars().next() == Some('_') && - ident.name.as_str().chars().skip(1).next() != Some('_') && - ident.name != ident.unhygienic_name && is_used(cx, expr) + ident.name.as_str().chars().next() == Some('_') && // starts with '_' + ident.name.as_str().chars().skip(1).next() != Some('_') && // doesn't start with "__" + ident.name != ident.unhygienic_name && is_used(cx, expr) // not in bang macro } ExprField(_, spanned) => { let name = spanned.node.as_str(); -- cgit 1.4.1-3-g733a5 From f27cfdb51a50c92031f3432ed98eb0ba54cb740e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 7 Jan 2016 12:06:16 +0530 Subject: Fix warnings for unused attributes --- src/lib.rs | 1 + src/misc.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8227be92543..45f47fe3d63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,6 +77,7 @@ mod reexport { pub use syntax::ast::{Name, NodeId}; } +#[allow(unused_attributes)] #[plugin_registrar] #[rustfmt_skip] pub fn plugin_registrar(reg: &mut Registry) { diff --git a/src/misc.rs b/src/misc.rs index 4cee123909b..a8fabaa3fcf 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -365,6 +365,7 @@ impl LintPass for UsedUnderscoreBinding { } impl LateLintPass for UsedUnderscoreBinding { + #[allow(unused_attributes)] #[rustfmt_skip] fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_attributes_expansion(cx, expr) { -- cgit 1.4.1-3-g733a5 From a21108a2963c63310d9c5b452e7faf3e622c47de Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 8 Jan 2016 21:21:12 +0530 Subject: Stronger macro check --- src/block_in_if_condition.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index f7d8c95ee76..53f11366cae 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -80,7 +80,7 @@ impl LateLintPass for BlockInIfCondition { if let Some(ref ex) = block.expr { // don't dig into the expression here, just suggest that they remove // the block - if differing_macro_contexts(expr.span, ex.span) { + if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, ex.span) { return; } span_help_and_lint(cx, @@ -92,7 +92,7 @@ impl LateLintPass for BlockInIfCondition { snippet_block(cx, then.span, ".."))); } } else { - if differing_macro_contexts(expr.span, block.stmts[0].span) { + if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, block.stmts[0].span) { return; } // move block higher -- cgit 1.4.1-3-g733a5 From 37707b5a34752e950ee09e9d0e5effb1f481fff1 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sat, 9 Jan 2016 02:05:43 +0100 Subject: added semver lint --- Cargo.toml | 1 + README.md | 3 ++- src/attrs.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 4 ++++ tests/compile-fail/attrs.rs | 12 ++++++++++-- 5 files changed, 60 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 2b203e8b796..792326d6c1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ plugin = true [dependencies] unicode-normalization = "0.1" +semver = "0.2.1" [dev-dependencies] compiletest_rs = "0.0.11" diff --git a/README.md b/README.md index f1c28888636..13105087706 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 91 lints included in this crate: +There are 92 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -24,6 +24,7 @@ name [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions +[deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) diff --git a/src/attrs.rs b/src/attrs.rs index ec2cfcb0efc..853e2ab5910 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -3,9 +3,10 @@ use rustc::lint::*; use rustc_front::hir::*; use reexport::*; +use semver::Version; use syntax::codemap::Span; use syntax::attr::*; -use syntax::ast::{Attribute, MetaList, MetaWord}; +use syntax::ast::{Attribute, Lit, Lit_, MetaList, MetaWord, MetaNameValue}; use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// **What it does:** This lint `Warn`s on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. @@ -24,17 +25,45 @@ use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; declare_lint! { pub INLINE_ALWAYS, Warn, "`#[inline(always)]` is a bad idea in most cases" } +/// **What it does:** This lint `Warn`s on `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. +/// +/// **Why is this bad?** For checking the version of the deprecation, it must be valid semver. Failing that, the contained information is useless. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// #[deprecated(since = "forever")] +/// fn something_else(..) { ... } +/// ``` +declare_lint! { pub DEPRECATED_SEMVER, Warn, + "`Warn` on `#[deprecated(since = \"x\")]` where x is not semver" } #[derive(Copy,Clone)] pub struct AttrPass; impl LintPass for AttrPass { fn get_lints(&self) -> LintArray { - lint_array!(INLINE_ALWAYS) + lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER) } } impl LateLintPass for AttrPass { + fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) { + if let MetaList(ref name, ref items) = attr.node.value.node { + if items.is_empty() || name != &"deprecated" { + return; + } + for ref item in items { + if let MetaNameValue(ref name, ref lit) = item.node { + if name == &"since" { + check_semver(cx, item.span, lit); + } + } + } + } + } + fn check_item(&mut self, cx: &LateContext, item: &Item) { if is_relevant_item(item) { check_attrs(cx, item.span, &item.name, &item.attrs) @@ -128,3 +157,15 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { } } } + +fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { + if let Lit_::LitStr(ref is, _) = lit.node { + if Version::parse(&*is).is_ok() { + return; + } + } + span_lint(cx, + DEPRECATED_SEMVER, + span, + "the since field must contain a semver-compliant version"); +} diff --git a/src/lib.rs b/src/lib.rs index 45f47fe3d63..f8db15605ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,9 @@ extern crate collections; // for unicode nfc normalization extern crate unicode_normalization; +// for semver check in attrs.rs +extern crate semver; + extern crate rustc_plugin; use rustc_plugin::Registry; @@ -156,6 +159,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, array_indexing::OUT_OF_BOUNDS_INDEXING, + attrs::DEPRECATED_SEMVER, attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, diff --git a/tests/compile-fail/attrs.rs b/tests/compile-fail/attrs.rs index ca7a0d5c07b..c7a4af60982 100644 --- a/tests/compile-fail/attrs.rs +++ b/tests/compile-fail/attrs.rs @@ -1,7 +1,7 @@ -#![feature(plugin)] +#![feature(plugin, deprecated)] #![plugin(clippy)] -#![deny(inline_always)] +#![deny(inline_always, deprecated_semver)] #[inline(always)] //~ERROR you have declared `#[inline(always)]` on `test_attr_lint`. fn test_attr_lint() { @@ -24,6 +24,14 @@ fn empty_and_false_positive_stmt() { unreachable!(); } +#[deprecated(since = "forever")] //~ERROR the since field must contain a semver-compliant version +pub const SOME_CONST : u8 = 42; + +#[deprecated(since = "1")] //~ERROR the since field must contain a semver-compliant version +pub const ANOTHER_CONST : u8 = 23; + +#[deprecated(since = "0.1.1")] +pub const YET_ANOTHER_CONST : u8 = 0; fn main() { test_attr_lint(); -- cgit 1.4.1-3-g733a5 From 9f641a1009e92431b4a49a835c4e80c51ce44c88 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Jan 2016 01:19:27 +0100 Subject: Add known enums to SINGLE_MATCH --- src/matches.rs | 53 +++++++++++++++++++++++++++++++++++++++---- src/utils.rs | 1 + tests/compile-fail/matches.rs | 49 +++++++++++++++++++++++++++++++++++---- 3 files changed, 94 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 5e207093c15..217c4abf45b 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -8,7 +8,8 @@ use std::cmp::Ordering; use syntax::ast::Lit_::LitBool; use syntax::codemap::Span; -use utils::{snippet, span_lint, span_note_and_lint, span_help_and_lint, in_external_macro, expr_block}; +use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; +use utils::{match_type, snippet, span_lint, span_note_and_lint, span_help_and_lint, in_external_macro, expr_block}; /// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. It is `Warn` by default. /// @@ -109,9 +110,20 @@ impl LateLintPass for MatchPass { } fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { - if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && - arms[1].guard.is_none() && arms[1].pats[0].node == PatWild && is_unit_expr(&arms[1].body) && - (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow) { + 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_unit_expr(&arms[1].body) { + let ty = cx.tcx.expr_ty(ex); + if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { + check_single_match_single_pattern(cx, ex, arms, expr); + check_single_match_opt_like(cx, ex, arms, expr, ty); + } + } +} + +fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { + if arms[1].pats[0].node == PatWild { span_help_and_lint(cx, SINGLE_MATCH, expr.span, @@ -124,6 +136,39 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } } +fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: ty::Ty) { + // list of candidate Enums we know will never get any more membre + let candidates = &[ + (&COW_PATH, "Borrowed"), + (&COW_PATH, "Cow::Borrowed"), + (&COW_PATH, "Cow::Owned"), + (&COW_PATH, "Owned"), + (&OPTION_PATH, "None"), + (&RESULT_PATH, "Err"), + (&RESULT_PATH, "Ok"), + ]; + + let path = match arms[1].pats[0].node { + PatEnum(ref path, _) => path.to_string(), + PatIdent(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), + _ => return + }; + + for &(ty_path, pat_path) in candidates { + if &path == pat_path && match_type(cx, ty, ty_path) { + span_help_and_lint(cx, + SINGLE_MATCH, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. Consider using \ + `if let`", + &format!("try\nif let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."))); + } + } +} + fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { // type of expression == bool if cx.tcx.expr_ty(ex).sty == ty::TyBool { diff --git a/src/utils.rs b/src/utils.rs index 74a15927ad1..77e63fe4458 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -29,6 +29,7 @@ pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index b569f9566ef..c58e62419c6 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -4,8 +4,14 @@ #![deny(clippy)] #![allow(unused)] +use std::borrow::Cow; + +enum Foo { Bar, Baz(u8) } +use Foo::*; + fn single_match(){ let x = Some(1u8); + match x { //~ ERROR you seem to be trying to use match //~^ HELP try Some(y) => { @@ -13,11 +19,7 @@ fn single_match(){ } _ => () } - // Not linted - match x { - Some(y) => println!("{:?}", y), - None => () - } + let z = (1u8,1u8); match z { //~ ERROR you seem to be trying to use match //~^ HELP try @@ -38,6 +40,43 @@ fn single_match(){ } } +fn single_match_know_enum() { + let x = Some(1u8); + let y : Result<_, i8> = Ok(1i8); + + match x { //~ ERROR you seem to be trying to use match + //~^ HELP try + Some(y) => println!("{:?}", y), + None => () + } + + match y { //~ ERROR you seem to be trying to use match + //~^ HELP try + Ok(y) => println!("{:?}", y), + Err(..) => () + } + + let c = Cow::Borrowed(""); + + match c { //~ ERROR you seem to be trying to use match + //~^ HELP try + Cow::Borrowed(..) => println!("42"), + Cow::Owned(..) => (), + } + + let z = Foo::Bar; + // no warning + match z { + Bar => println!("42"), + Baz(_) => (), + } + + match z { + Baz(_) => println!("42"), + Bar => (), + } +} + fn match_bool() { let test: bool = true; -- cgit 1.4.1-3-g733a5 From 44daa8bd72d29b281741a6fc11e07faa03d5fb1e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Jan 2016 12:57:44 +0100 Subject: Use span_suggestion in matches lints Ref #442 --- src/matches.rs | 100 ++++++++++++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 217c4abf45b..4cb4df19bf8 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -9,7 +9,7 @@ use syntax::ast::Lit_::LitBool; use syntax::codemap::Span; use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; -use utils::{match_type, snippet, span_lint, span_note_and_lint, span_help_and_lint, in_external_macro, expr_block}; +use utils::{match_type, snippet, span_lint, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; /// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. It is `Warn` by default. /// @@ -124,15 +124,17 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms[1].pats[0].node == PatWild { - span_help_and_lint(cx, + span_lint_and_then(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for destructuring a single pattern. Consider using \ - `if let`", - &format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."))); + "you seem to be trying to use match for destructuring a single pattern. \ + Consider using `if let`", |db| { + db.span_suggestion(expr.span, "try this", + format!("if let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."))); + }); } } @@ -156,15 +158,17 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: for &(ty_path, pat_path) in candidates { if &path == pat_path && match_type(cx, ty, ty_path) { - span_help_and_lint(cx, + span_lint_and_then(cx, SINGLE_MATCH, expr.span, - "you seem to be trying to use match for destructuring a single pattern. Consider using \ - `if let`", - &format!("try\nif let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."))); + "you seem to be trying to use match for destructuring a single pattern. \ + Consider using `if let`", |db| { + db.span_suggestion(expr.span, "try this", + format!("if let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."))); + }); } } } @@ -172,7 +176,7 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { // type of expression == bool if cx.tcx.expr_ty(ex).sty == ty::TyBool { - if arms.len() == 2 && arms[0].pats.len() == 1 { + let sugg = if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { @@ -187,56 +191,42 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } else { None }; + if let Some((ref true_expr, ref false_expr)) = exprs { if !is_unit_expr(true_expr) { if !is_unit_expr(false_expr) { - span_help_and_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using \ - an if..else block:", - &format!("try\nif {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."), - expr_block(cx, false_expr, None, ".."))); + Some(format!("if {} {} else {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."), + expr_block(cx, false_expr, None, ".."))) } else { - span_help_and_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using \ - an if..else block:", - &format!("try\nif {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."))); + Some(format!("if {} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, true_expr, None, ".."))) } } else if !is_unit_expr(false_expr) { - span_help_and_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using an \ - if..else block:", - &format!("try\nif !{} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))); + Some(format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))) } else { - span_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using an if..else \ - block"); + None } } else { - span_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using an if..else block"); + None } } else { - span_lint(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using an if..else block"); - } + None + }; + + span_lint_and_then(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using \ + an if..else block:", move |db| { + if let Some(ref sugg) = sugg { + db.span_suggestion(expr.span, "try this", sugg.clone()); + } + }); } } -- cgit 1.4.1-3-g733a5 From 09129c1b416cf0101b75e72e6a3ffdfbbef78542 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 12 Jan 2016 20:23:28 +0100 Subject: Add BTreeMap to the HASHMAP_ENTRY rule Fixes #433 --- README.md | 2 +- src/entry.rs | 111 ++++++++++++++++++++++++++++++++++++++++++ src/hashmap.rs | 102 -------------------------------------- src/lib.rs | 6 +-- src/utils.rs | 15 +++--- tests/compile-fail/entry.rs | 47 ++++++++++++++++++ tests/compile-fail/hashmap.rs | 41 ---------------- 7 files changed, 170 insertions(+), 154 deletions(-) create mode 100644 src/entry.rs delete mode 100644 src/hashmap.rs create mode 100644 tests/compile-fail/entry.rs delete mode 100644 tests/compile-fail/hashmap.rs (limited to 'src') diff --git a/README.md b/README.md index 13105087706..631c1d7f1d2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ name [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[hashmap_entry](https://github.com/Manishearth/rust-clippy/wiki#hashmap_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases @@ -43,6 +42,7 @@ name [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) +[map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap` [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead diff --git a/src/entry.rs b/src/entry.rs new file mode 100644 index 00000000000..1885bea164b --- /dev/null +++ b/src/entry.rs @@ -0,0 +1,111 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::codemap::Span; +use utils::{get_item_name, is_exp_equal, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; +use utils::{BTREEMAP_PATH, HASHMAP_PATH}; + +/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or +/// `BTreeMap`. +/// +/// **Why is this bad?** Using `entry` is more efficient. +/// +/// **Known problems:** Some false negatives, eg.: +/// ``` +/// let k = &key; +/// if !m.contains_key(k) { m.insert(k.clone(), v); } +/// ``` +/// +/// **Example:** +/// ```rust +/// if !m.contains_key(&k) { m.insert(k, v) } +/// ``` +/// can be rewritten as: +/// ```rust +/// m.entry(k).or_insert(v); +/// ``` +declare_lint! { + pub MAP_ENTRY, + Warn, + "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`" +} + +#[derive(Copy,Clone)] +pub struct HashMapLint; + +impl LintPass for HashMapLint { + fn get_lints(&self) -> LintArray { + lint_array!(MAP_ENTRY) + } +} + +impl LateLintPass for HashMapLint { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! { + [ + let ExprIf(ref check, ref then, _) = expr.node, + let ExprUnary(UnOp::UnNot, ref check) = check.node, + let ExprMethodCall(ref name, _, ref params) = check.node, + params.len() >= 2, + name.node.as_str() == "contains_key" + ], { + let key = match params[1].node { + ExprAddrOf(_, ref key) => key, + _ => return + }; + + let map = ¶ms[0]; + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); + + let kind = if match_type(cx, obj_ty, &BTREEMAP_PATH) { + "BTreeMap" + } + else if match_type(cx, obj_ty, &HASHMAP_PATH) { + "HashMap" + } + else { + return + }; + + let sole_expr = if then.expr.is_some() { 1 } else { 0 } + then.stmts.len() == 1; + + if let Some(ref then) = then.expr { + check_for_insert(cx, expr.span, map, key, then, sole_expr, kind); + } + + for stmt in &then.stmts { + if let StmtSemi(ref stmt, _) = stmt.node { + check_for_insert(cx, expr.span, map, key, stmt, sole_expr, kind); + } + } + } + } + } +} + +fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr, sole_expr: bool, kind: &str) { + if_let_chain! { + [ + let ExprMethodCall(ref name, _, ref params) = expr.node, + params.len() == 3, + name.node.as_str() == "insert", + get_item_name(cx, map) == get_item_name(cx, &*params[0]), + is_exp_equal(cx, key, ¶ms[1]) + ], { + let help = if sole_expr { + format!("Consider using `{}.entry({}).or_insert({})`", + snippet(cx, map.span, ".."), + snippet(cx, params[1].span, ".."), + snippet(cx, params[2].span, "..")) + } + else { + format!("Consider using `{}.entry({})`", + snippet(cx, map.span, ".."), + snippet(cx, params[1].span, "..")) + }; + + span_help_and_lint(cx, MAP_ENTRY, span, + &format!("usage of `contains_key` followed by `insert` on `{}`", kind), + &help); + } + } +} diff --git a/src/hashmap.rs b/src/hashmap.rs deleted file mode 100644 index 095a00e3777..00000000000 --- a/src/hashmap.rs +++ /dev/null @@ -1,102 +0,0 @@ -use rustc::lint::*; -use rustc_front::hir::*; -use syntax::codemap::Span; -use utils::{get_item_name, is_exp_equal, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; -use utils::HASHMAP_PATH; - -/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap`. -/// -/// **Why is this bad?** Using `HashMap::entry` is more efficient. -/// -/// **Known problems:** Some false negatives, eg.: -/// ``` -/// let k = &key; -/// if !m.contains_key(k) { m.insert(k.clone(), v); } -/// ``` -/// -/// **Example:** -/// ```rust -/// if !m.contains_key(&k) { m.insert(k, v) } -/// ``` -/// can be rewritten as: -/// ```rust -/// m.entry(k).or_insert(v); -/// ``` -declare_lint! { - pub HASHMAP_ENTRY, - Warn, - "use of `contains_key` followed by `insert` on a `HashMap`" -} - -#[derive(Copy,Clone)] -pub struct HashMapLint; - -impl LintPass for HashMapLint { - fn get_lints(&self) -> LintArray { - lint_array!(HASHMAP_ENTRY) - } -} - -impl LateLintPass for HashMapLint { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if_let_chain! { - [ - let ExprIf(ref check, ref then, _) = expr.node, - let ExprUnary(UnOp::UnNot, ref check) = check.node, - let ExprMethodCall(ref name, _, ref params) = check.node, - params.len() >= 2, - name.node.as_str() == "contains_key" - ], { - let key = match params[1].node { - ExprAddrOf(_, ref key) => key, - _ => return - }; - - let map = ¶ms[0]; - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); - - if match_type(cx, obj_ty, &HASHMAP_PATH) { - let sole_expr = if then.expr.is_some() { 1 } else { 0 } + then.stmts.len() == 1; - - if let Some(ref then) = then.expr { - check_for_insert(cx, expr.span, map, key, then, sole_expr); - } - - for stmt in &then.stmts { - if let StmtSemi(ref stmt, _) = stmt.node { - check_for_insert(cx, expr.span, map, key, stmt, sole_expr); - } - } - } - } - } - } -} - -fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr, sole_expr: bool) { - if_let_chain! { - [ - let ExprMethodCall(ref name, _, ref params) = expr.node, - params.len() == 3, - name.node.as_str() == "insert", - get_item_name(cx, map) == get_item_name(cx, &*params[0]), - is_exp_equal(cx, key, ¶ms[1]) - ], { - if sole_expr { - span_help_and_lint(cx, HASHMAP_ENTRY, span, - "usage of `contains_key` followed by `insert` on `HashMap`", - &format!("Consider using `{}.entry({}).or_insert({})`", - snippet(cx, map.span, ".."), - snippet(cx, params[1].span, ".."), - snippet(cx, params[2].span, ".."))); - } - else { - span_help_and_lint(cx, HASHMAP_ENTRY, span, - "usage of `contains_key` followed by `insert` on `HashMap`", - &format!("Consider using `{}.entry({})`", - snippet(cx, map.span, ".."), - snippet(cx, params[1].span, ".."))); - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs index f8db15605ff..9bb59693795 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod cyclomatic_complexity; pub mod escape; -pub mod hashmap; +pub mod entry; pub mod misc_early; pub mod array_indexing; pub mod panic; @@ -113,7 +113,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::UnitCmp); reg.register_late_lint_pass(box loops::LoopsPass); reg.register_late_lint_pass(box lifetimes::LifetimePass); - reg.register_late_lint_pass(box hashmap::HashMapLint); + reg.register_late_lint_pass(box entry::HashMapLint); reg.register_late_lint_pass(box ranges::StepByZero); reg.register_late_lint_pass(box types::CastPass); reg.register_late_lint_pass(box types::TypeComplexityPass); @@ -167,10 +167,10 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, + entry::MAP_ENTRY, eq_op::EQ_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, - hashmap::HASHMAP_ENTRY, identity_op::IDENTITY_OP, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, diff --git a/src/utils.rs b/src/utils.rs index 77e63fe4458..d3ebe809ac9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -19,17 +19,18 @@ use std::ops::{Deref, DerefMut}; pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for +pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; +pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; -pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; -pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; -pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; -pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/entry.rs b/tests/compile-fail/entry.rs new file mode 100644 index 00000000000..7ea0e3952b0 --- /dev/null +++ b/tests/compile-fail/entry.rs @@ -0,0 +1,47 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused)] + +#![deny(map_entry)] + +use std::collections::{BTreeMap, HashMap}; +use std::hash::Hash; + +fn foo() {} + +fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { m.insert(k, v); } + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k).or_insert(v)` +} + +fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { foo(); m.insert(k, v); } + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k)` +} + +fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { m.insert(k, v) } else { None }; + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k).or_insert(v)` +} + +fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; + //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` + //~^^HELP: Consider using `m.entry(k)` +} + +fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) { + if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; + //~^ERROR: usage of `contains_key` followed by `insert` on `BTreeMap` + //~^^HELP: Consider using `m.entry(k)` +} + +fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { + if !m.contains_key(&k) { m.insert(o, v); } +} + +fn main() { +} diff --git a/tests/compile-fail/hashmap.rs b/tests/compile-fail/hashmap.rs deleted file mode 100644 index a53566a794e..00000000000 --- a/tests/compile-fail/hashmap.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] -#![allow(unused)] - -#![deny(hashmap_entry)] - -use std::collections::HashMap; -use std::hash::Hash; - -fn foo() {} - -fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { m.insert(k, v); } - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k).or_insert(v)` -} - -fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { foo(); m.insert(k, v); } - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k)` -} - -fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { m.insert(k, v) } else { None }; - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k).or_insert(v)` -} - -fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { - if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k)` -} - -fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { - if !m.contains_key(&k) { m.insert(o, v); } -} - -fn main() { -} -- cgit 1.4.1-3-g733a5 From f63329761fe66395acb17ccd89a6202c2b5dadab Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 12 Jan 2016 23:17:54 +0100 Subject: Cleanup utils, mostly doc --- Cargo.toml | 1 - src/utils.rs | 109 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 58 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 792326d6c1d..db5944ab9b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,5 +29,4 @@ rustc-serialize = "0.3" [features] -structured_logging = [] debugging = [] diff --git a/src/utils.rs b/src/utils.rs index d3ebe809ac9..53f83d6921a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -78,20 +78,21 @@ macro_rules! if_let_chain { }; } -/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one isn't) +/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one +/// isn't). pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { sp1.expn_id != sp2.expn_id } -/// returns true if this expn_info was expanded by any macro +/// Returns true if this `expn_info` was expanded by any macro. pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) } -/// returns true if the macro that expanded the crate was outside of -/// the current crate or was a compiler plugin +/// Returns true if the macro that expanded the crate was outside of the current crate or was a +/// compiler plugin. pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { - /// invokes in_macro with the expansion info of the given span - /// slightly heavy, try to use this after other checks have already happened + /// Invokes in_macro with the expansion info of the given span slightly heavy, try to use this + /// after other checks have already happened. fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { @@ -110,9 +111,12 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) } -/// check if a DefId's path matches the given absolute type path -/// usage e.g. with -/// `match_def_path(cx, id, &["core", "option", "Option"])` +/// Check if a `DefId`'s path matches the given absolute type path usage. +/// +/// # Examples +/// ``` +/// match_def_path(cx, id, &["core", "option", "Option"]) +/// ``` pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { cx.tcx.with_path(def_id, |iter| { iter.zip(path) @@ -120,7 +124,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { }) } -/// check if type is struct or enum type with given def path +/// Check if type is struct or enum type with given def path. pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { match ty.sty { ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), @@ -128,7 +132,7 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { } } -/// check if method call given in "expr" belongs to given trait +/// Check if the method call given in `expr` belongs to given trait. pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); @@ -145,9 +149,10 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { } } -/// check if method call given in "expr" belongs to given trait +/// Check if the method call given in `expr` belongs to given trait. pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); + let trt_id = cx.tcx .tables .borrow() @@ -161,21 +166,31 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool } } -/// match a Path against a slice of segment string literals, e.g. -/// `match_path(path, &["std", "rt", "begin_unwind"])` +/// Match a `Path` against a slice of segment string literals. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` pub fn match_path(path: &Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) } -/// match a Path against a slice of segment string literals, e.g. -/// `match_path(path, &["std", "rt", "begin_unwind"])` +/// Match a `Path` against a slice of segment string literals, e.g. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) } -/// match an Expr against a chain of methods, and return the matched Exprs. For example, if `expr` -/// represents the `.baz()` in `foo.bar().baz()`, `matched_method_chain(expr, &["bar", "baz"])` -/// will return a Vec containing the Exprs for `.bar()` and `.baz()` +/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. +/// +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, +/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for +/// `.bar()` and `.baz()` pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); @@ -197,7 +212,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a } -/// get the name of the item the expression is in, if available +/// Get the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { @@ -208,7 +223,7 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { } } -/// checks if a `let` decl is from a for loop desugaring +/// Checks if a `let` decl is from a `for` loop desugaring. pub fn is_from_for_desugar(decl: &Decl) -> bool { if_let_chain! { [ @@ -222,31 +237,39 @@ pub fn is_from_for_desugar(decl: &Decl) -> bool { } -/// convert a span to a code snippet if available, otherwise use default, e.g. -/// `snippet(cx, expr.span, "..")` +/// Convert a span to a code snippet if available, otherwise use default. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) } -/// Converts a span to a code snippet. Returns None if not available. +/// Convert a span to a code snippet. Returns `None` if not available. pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { cx.sess().codemap().span_to_snippet(span).ok() } -/// convert a span (from a block) to a code snippet if available, otherwise use default, e.g. -/// `snippet(cx, expr.span, "..")` -/// This trims the code of indentation, except for the first line -/// Use it for blocks or block-like things which need to be printed as such +/// Convert a span (from a block) to a code snippet if available, otherwise use default. +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// things which need to be printed as such. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { let snip = snippet(cx, span, default); trim_multiline(snip, true) } -/// Like snippet_block, but add braces if the expr is not an ExprBlock -/// Also takes an Option<String> which can be put inside the braces +/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. +/// Also takes an `Option<String>` which can be put inside the braces. pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); - let string = option.map_or("".to_owned(), |s| s); + let string = option.unwrap_or_default(); if let ExprBlock(_) = expr.node { Cow::Owned(format!("{}{}", code, string)) } else if string.is_empty() { @@ -256,8 +279,7 @@ pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String } } -/// Trim indentation from a multiline string -/// with possibility of ignoring the first line +/// Trim indentation from a multiline string with possibility of ignoring the first line. pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { let s_space = trim_multiline_inner(s, ignore_first, ' '); let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); @@ -297,7 +319,7 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { } } -/// get a parent expr if any – this is useful to constrain a lint +/// Get a parent expressions if any – this is useful to constrain a lint. pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.map; let node_id: NodeId = e.id; @@ -350,22 +372,7 @@ impl<'a> Deref for DiagnosticWrapper<'a> { } } -#[cfg(not(feature="structured_logging"))] -pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, sp, msg); - if cx.current_level(lint) != Level::Allow { - db.fileline_help(sp, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); - } - DiagnosticWrapper(db) -} - -#[cfg(feature="structured_logging")] pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { - // lint.name / lint.desc is can give details of the lint - // cx.sess().codemap() has all these nice functions for line/column/snippet details - // http://doc.rust-lang.org/syntax/codemap/struct.CodeMap.html#method.span_to_string let mut db = cx.struct_span_lint(lint, sp, msg); if cx.current_level(lint) != Level::Allow { db.fileline_help(sp, @@ -419,7 +426,7 @@ pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, db } -/// return the base type for references and raw pointers +/// Return the base type for references and raw pointers. pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), @@ -427,7 +434,7 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { } } -/// return the base type for references and raw pointers, and count reference depth +/// Return the base type for references and raw pointers, and count reference depth. pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { match ty.sty { -- cgit 1.4.1-3-g733a5 From 6fa9bf64d73d90ec35f30dcbb7d77f7418fff071 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Jan 2016 17:17:19 +0100 Subject: Use span_suggestion in ENTRY lint --- src/entry.rs | 13 +++++++------ tests/compile-fail/entry.rs | 25 +++++++++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/entry.rs b/src/entry.rs index 1885bea164b..d9fb7269be6 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use utils::{get_item_name, is_exp_equal, match_type, snippet, span_help_and_lint, walk_ptrs_ty}; +use utils::{get_item_name, is_exp_equal, match_type, snippet, span_lint_and_then, walk_ptrs_ty}; use utils::{BTREEMAP_PATH, HASHMAP_PATH}; /// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or @@ -92,20 +92,21 @@ fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: is_exp_equal(cx, key, ¶ms[1]) ], { let help = if sole_expr { - format!("Consider using `{}.entry({}).or_insert({})`", + format!("{}.entry({}).or_insert({})", snippet(cx, map.span, ".."), snippet(cx, params[1].span, ".."), snippet(cx, params[2].span, "..")) } else { - format!("Consider using `{}.entry({})`", + format!("{}.entry({})", snippet(cx, map.span, ".."), snippet(cx, params[1].span, "..")) }; - span_help_and_lint(cx, MAP_ENTRY, span, - &format!("usage of `contains_key` followed by `insert` on `{}`", kind), - &help); + span_lint_and_then(cx, MAP_ENTRY, span, + &format!("usage of `contains_key` followed by `insert` on `{}`", kind), |db| { + db.span_suggestion(span, "Consider using", help.clone()); + }); } } } diff --git a/tests/compile-fail/entry.rs b/tests/compile-fail/entry.rs index 7ea0e3952b0..a7460282007 100644 --- a/tests/compile-fail/entry.rs +++ b/tests/compile-fail/entry.rs @@ -11,32 +11,37 @@ fn foo() {} fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { m.insert(k, v); } - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k).or_insert(v)` + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| HELP Consider + //~| SUGGESTION m.entry(k).or_insert(v) } fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v); } - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k)` + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| HELP Consider + //~| SUGGESTION m.entry(k) } fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { m.insert(k, v) } else { None }; - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k).or_insert(v)` + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| HELP Consider + //~| SUGGESTION m.entry(k).or_insert(v) } fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; - //~^ERROR: usage of `contains_key` followed by `insert` on `HashMap` - //~^^HELP: Consider using `m.entry(k)` + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| HELP Consider + //~| SUGGESTION m.entry(k) } fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; - //~^ERROR: usage of `contains_key` followed by `insert` on `BTreeMap` - //~^^HELP: Consider using `m.entry(k)` + //~^ ERROR usage of `contains_key` followed by `insert` on `BTreeMap` + //~| HELP Consider + //~| SUGGESTION m.entry(k) } fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { -- cgit 1.4.1-3-g733a5 From 375b8168e48f7af89c754a41581f3a7102fae066 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Jan 2016 18:32:05 +0100 Subject: Remove useless curly braces in else { if .. } --- src/bit_mask.rs | 19 +++++++------------ src/consts.rs | 8 +++----- src/minmax.rs | 8 +++----- src/shadow.rs | 41 ++++++++++++++++++++--------------------- 4 files changed, 33 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index c2fd3742066..133212daf14 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -148,11 +148,10 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: mask_value, cmp_value)); } - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); - } + } else if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } + } BiBitOr => { if mask_value | cmp_value != cmp_value { @@ -177,10 +176,8 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: &format!("incompatible bit mask: `_ & {}` will always be lower than `{}`", mask_value, cmp_value)); - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); - } + } else if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } } BiBitOr => { @@ -209,10 +206,8 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: &format!("incompatible bit mask: `_ & {}` will never be higher than `{}`", mask_value, cmp_value)); - } else { - if mask_value == 0 { - span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); - } + } else if mask_value == 0 { + span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); } } BiBitOr => { diff --git a/src/consts.rs b/src/consts.rs index 171ba6f27f0..68320705fb6 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -536,12 +536,10 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { Plus }) .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + } else if ln { + add_neg_int(r64, rty, l64, lty) } else { - if ln { - add_neg_int(r64, rty, l64, lty) - } else { - add_neg_int(l64, lty, r64, rty) - } + add_neg_int(l64, lty, r64, rty) } } // TODO: float (would need bignum library?) diff --git a/src/minmax.rs b/src/minmax.rs index 2cce36f2a9c..e72f2392054 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -59,12 +59,10 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &' if match_def_path(cx, def_id, &["core", "cmp", "min"]) { fetch_const(args, Min) + } else if match_def_path(cx, def_id, &["core", "cmp", "max"]) { + fetch_const(args, Max) } else { - if match_def_path(cx, def_id, &["core", "cmp", "max"]) { - fetch_const(args, Max) - } else { - None - } + None } } else { None diff --git a/src/shadow.rs b/src/shadow.rs index 2d3e423eacb..bcf3ce7116a 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -204,29 +204,28 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & snippet(cx, lspan, "_"), snippet(cx, expr.span, ".."))); note_orig(cx, db, SHADOW_SAME, prev_span); + } else if contains_self(name, expr) { + let db = span_note_and_lint(cx, + SHADOW_REUSE, + lspan, + &format!("{} is shadowed by {} which reuses the original value", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); + note_orig(cx, db, SHADOW_REUSE, prev_span); } else { - if contains_self(name, expr) { - let db = span_note_and_lint(cx, - SHADOW_REUSE, - lspan, - &format!("{} is shadowed by {} which reuses the original value", - snippet(cx, lspan, "_"), - snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); - note_orig(cx, db, SHADOW_REUSE, prev_span); - } else { - let db = span_note_and_lint(cx, - SHADOW_UNRELATED, - lspan, - &format!("{} is shadowed by {}", - snippet(cx, lspan, "_"), - snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); - note_orig(cx, db, SHADOW_UNRELATED, prev_span); - } + let db = span_note_and_lint(cx, + SHADOW_UNRELATED, + lspan, + &format!("{} is shadowed by {}", + snippet(cx, lspan, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); + note_orig(cx, db, SHADOW_UNRELATED, prev_span); } + } else { let db = span_lint(cx, SHADOW_UNRELATED, -- cgit 1.4.1-3-g733a5 From c2444c604388f96a6949bb39bcf3730c6ef78c0f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Jan 2016 18:32:55 +0100 Subject: Lint about `else { if .. }` with useless braces --- README.md | 2 +- src/collapsible_if.rs | 71 ++++++++++++++++++++++++------------ tests/compile-fail/collapsible_if.rs | 24 ++++++++++++ 3 files changed, 73 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 631c1d7f1d2..33bca7f871f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ name [cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` +[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to `else if` [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 4a17d3a4608..fb1d7f696d1 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -16,9 +16,11 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::{in_macro, span_help_and_lint, snippet, snippet_block}; +use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; -/// **What it does:** This lint checks for nested `if`-statements which can be collapsed by `&&`-combining their conditions. It is `Warn` by default. +/// **What it does:** This lint checks for nested `if`-statements which can be collapsed by +/// `&&`-combining their conditions and for `else { if .. } expressions that can be collapsed to +/// `else if ..`. It is `Warn` by default. /// /// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. /// @@ -29,7 +31,8 @@ declare_lint! { pub COLLAPSIBLE_IF, Warn, "two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` \ - can be written as `if x && y { foo() }`" + can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to \ + `else if`" } #[derive(Copy,Clone)] @@ -50,20 +53,44 @@ impl LateLintPass for CollapsibleIf { } fn check_if(cx: &LateContext, e: &Expr) { - if let ExprIf(ref check, ref then, None) = e.node { - if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = - single_stmt_of_block(then) { - if e.span.expn_id != sp.expn_id { - return; + if let ExprIf(ref check, ref then, ref else_) = e.node { + match *else_ { + Some(ref else_) => { + if_let_chain! {[ + let ExprBlock(ref block) = else_.node, + block.stmts.is_empty(), + block.rules == BlockCheckMode::DefaultBlock, + let Some(ref else_) = block.expr, + let ExprIf(_, _, _) = else_.node + ], { + span_lint_and_then(cx, + COLLAPSIBLE_IF, + block.span, + "this `else { if .. }` block can be collapsed", |db| { + db.span_suggestion(block.span, "try", + format!("else {}", + snippet_block(cx, else_.span, ".."))); + }); + }} + } + None => { + if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = + single_stmt_of_block(then) { + if e.span.expn_id != sp.expn_id { + return; + } + span_lint_and_then(cx, + COLLAPSIBLE_IF, + e.span, + "this if statement can be collapsed", |db| { + db.span_suggestion(e.span, "try", + format!("if {} && {} {}", + check_to_string(cx, check), + check_to_string(cx, check_inner), + snippet_block(cx, content.span, ".."))); + }); + } } - span_help_and_lint(cx, - COLLAPSIBLE_IF, - e.span, - "this if statement can be collapsed", - &format!("try\nif {} && {} {}", - check_to_string(cx, check), - check_to_string(cx, check_inner), - snippet_block(cx, content.span, ".."))); } } } @@ -90,16 +117,14 @@ fn single_stmt_of_block(block: &Block) -> Option<&Expr> { } else { None } - } else { - if block.stmts.is_empty() { - if let Some(ref p) = block.expr { - Some(p) - } else { - None - } + } else if block.stmts.is_empty() { + if let Some(ref p) = block.expr { + Some(p) } else { None } + } else { + None } } diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs index cc63e895f1c..85eac28dc38 100644 --- a/tests/compile-fail/collapsible_if.rs +++ b/tests/compile-fail/collapsible_if.rs @@ -17,6 +17,30 @@ fn main() { } } + // Collaspe `else { if .. }` to `else if ..` + if x == "hello" { + print!("Hello "); + } else { //~ERROR: this `else { if .. }` + //~| HELP try + //~| SUGGESTION else if y == "world" + if y == "world" { + println!("world!") + } + } + + if x == "hello" { + print!("Hello "); + } else { //~ERROR this `else { if .. }` + //~| HELP try + //~| SUGGESTION else if y == "world" + if y == "world" { + println!("world") + } + else { + println!("!") + } + } + // Works because any if with an else statement cannot be collapsed. if x == "hello" { if y == "world" { -- cgit 1.4.1-3-g733a5 From 7499f3c7a945f7dc32c3b9a7fd553874a2adff43 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Thu, 14 Jan 2016 19:27:24 +0100 Subject: Consider lifetime in self paramter in unused_lifetime lint --- src/lifetimes.rs | 15 +++++++++++++-- tests/compile-fail/lifetimes.rs | 4 ++-- tests/compile-fail/unused_lt.rs | 7 +++++++ 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 2de916cfebc..1edd75a45aa 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -77,7 +77,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g span, "explicit lifetimes given in parameter types where they could be elided"); } - report_extra_lifetimes(cx, decl, &generics); + report_extra_lifetimes(cx, decl, &generics, slf); } fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, named_lts: &[LifetimeDef]) -> bool { @@ -303,14 +303,25 @@ impl<'v> Visitor<'v> for LifetimeChecker { } } -fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { +fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, + generics: &Generics, slf: Option<&ExplicitSelf>) { let hs = generics.lifetimes .iter() .map(|lt| (lt.lifetime.name, lt.lifetime.span)) .collect(); let mut checker = LifetimeChecker(hs); + walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); + + if let Some(slf) = slf { + match slf.node { + SelfRegion(Some(ref lt), _, _) => checker.visit_lifetime(lt), + SelfExplicit(ref t, _) => walk_ty(&mut checker, t), + _ => {} + } + } + for (_, v) in checker.0 { span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 4d454a738d9..99c16917426 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -1,8 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(needless_lifetimes)] -#![allow(dead_code, unused_lifetimes)] +#![deny(needless_lifetimes, unused_lifetimes)] +#![allow(dead_code)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } //~^ERROR explicit lifetimes given diff --git a/tests/compile-fail/unused_lt.rs b/tests/compile-fail/unused_lt.rs index 85667174509..a35718b5848 100644 --- a/tests/compile-fail/unused_lt.rs +++ b/tests/compile-fail/unused_lt.rs @@ -52,6 +52,13 @@ pub fn parse2<'a, I>(_it: &mut I) where I: Iterator<Item=&'a str>{ unimplemented!() } +struct X { x: u32 } + +impl X { + fn self_ref_with_lifetime<'a>(&'a self) {} + fn explicit_self_with_lifetime<'a>(self: &'a Self) {} +} + fn main() { } -- cgit 1.4.1-3-g733a5 From 387e0991e3be528ab85fce8f57c489949a7a41a5 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 14 Jan 2016 20:58:32 +0100 Subject: Handle more iterator adapter cases in for loops --- src/loops.rs | 138 ++++++++++++++++++++++++++++------------- src/utils.rs | 1 + tests/compile-fail/for_loop.rs | 24 ++++++- 3 files changed, 117 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 91bb898629f..614b561749f 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -8,7 +8,6 @@ use consts::{constant_simple, Constant}; use rustc::front::map::Node::NodeBlock; use std::borrow::Cow; use std::collections::{HashSet, HashMap}; -use syntax::ast::Lit_::*; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal, get_enclosing_block}; @@ -247,54 +246,102 @@ impl LateLintPass for LoopsPass { } fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { - // check for looping over a range and then indexing a sequence with it - // -> the iteratee must be a range literal - if let ExprRange(Some(ref l), _) = arg.node { - // Range should start with `0` - if let ExprLit(ref lit) = l.node { - if let LitInt(0, _) = lit.node { - - // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { - cx: cx, - var: ident.node.name, - indexed: HashSet::new(), - nonindex: false, - }; - walk_expr(&mut visitor, body); - // linting condition: we only indexed one variable - if visitor.indexed.len() == 1 { - let indexed = visitor.indexed - .into_iter() - .next() - .expect("Len was nonzero, but no contents found"); - if visitor.nonindex { - span_lint(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is used to index `{}`. Consider using `for \ - ({}, item) in {}.iter().enumerate()` or similar iterators", - ident.node.name, - indexed, - ident.node.name, - indexed)); - } else { - span_lint(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is only used to index `{}`. Consider using \ - `for item in &{}` or similar iterators", - ident.node.name, - indexed, - indexed)); - } + check_for_loop_range(cx, pat, arg, body, expr); + check_for_loop_reverse_range(cx, arg, expr); + check_for_loop_explicit_iter(cx, arg, expr); + check_for_loop_explicit_counter(cx, arg, body, expr); +} + +/// 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) { + if let ExprRange(Some(ref l), ref r) = arg.node { + // the var must be a single name + if let PatIdent(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { + cx: cx, + var: ident.node.name, + indexed: HashSet::new(), + nonindex: false, + }; + walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable + if visitor.indexed.len() == 1 { + let indexed = visitor.indexed + .into_iter() + .next() + .expect("Len was nonzero, but no contents found"); + + let starts_at_zero = is_integer_literal(l, 0); + + let skip: Cow<_> = if starts_at_zero { + "".into() + } + else { + format!(".skip({})", snippet(cx, l.span, "..")).into() + }; + + let take: Cow<_> = if let Some(ref r) = *r { + if !is_len_call(&r, &indexed) { + format!(".take({})", snippet(cx, r.span, "..")).into() + } + else { + "".into() + } + } else { + "".into() + }; + + if visitor.nonindex { + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is used to index `{}`. \ + Consider using `for ({}, item) in {}.iter().enumerate(){}{}` or similar iterators", + ident.node.name, + indexed, + ident.node.name, + indexed, + take, + skip)); + } else { + let repl = if starts_at_zero && take.is_empty() { + format!("&{}", indexed) } + else { + format!("{}.iter(){}{}", indexed, take, skip) + }; + + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in {}` or similar iterators", + ident.node.name, + indexed, + repl)); } } } } +} + +fn is_len_call(expr: &Expr, var: &Name) -> bool { + if_let_chain! {[ + 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, + path.segments.len() == 1, + &path.segments[0].identifier.name == var + ], { + return true; + }} + + false +} +fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { // ...and both sides are compile-time constant integers... @@ -324,7 +371,9 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E } } } +} +fn check_for_loop_explicit_iter(cx: &LateContext, arg: &Expr, expr: &Expr) { if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments if args.len() == 1 { @@ -356,6 +405,9 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E } } +} + +fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { // Look for variables that are incremented once per loop iteration. let mut visitor = IncrementVisitor { cx: cx, diff --git a/src/utils.rs b/src/utils.rs index 53f83d6921a..312cf77d068 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -445,6 +445,7 @@ pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { inner(ty, 0) } +/// Check whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { // FIXME: use constant folding if let ExprLit(ref spanned) = expr.node { diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index f1c1adf6cc8..6791d71ca36 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -20,20 +20,38 @@ impl Unrelated { fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; - for i in 0..vec.len() { //~ERROR the loop variable `i` is only used to index `vec`. + for i in 0..vec.len() { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in &vec` println!("{}", vec[i]); } - for i in 0..vec.len() { //~ERROR the loop variable `i` is used to index `vec`. + for i in 0..vec.len() { + //~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate()` println!("{} {}", vec[i], i); } for i in 0..vec.len() { // not an error, indexing more than one variable println!("{} {}", vec[i], vec2[i]); } - for i in 5..vec.len() { // not an error, not starting with 0 + for i in 5..vec.len() { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().skip(5)` println!("{}", vec[i]); } + for i in 5..10 { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)` + println!("{}", vec[i]); + } + + for i in 5..vec.len() { + //~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate().skip(5)` + println!("{} {}", vec[i], i); + } + + for i in 5..10 { + //~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate().take(10).skip(5)` + println!("{} {}", vec[i], i); + } + for i in 10..0 { //~ERROR this range is empty so this for loop will never run println!("{}", i); } -- cgit 1.4.1-3-g733a5 From c6604bb281d6f8ca77c33f15e67a26e0ceeb95a3 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 16 Jan 2016 18:47:45 +0100 Subject: Add a lint to warn about call to `.*or(foo(..))` --- README.md | 3 ++- src/lib.rs | 1 + src/methods.rs | 61 +++++++++++++++++++++++++++++++++++++++++-- src/utils.rs | 2 +- tests/compile-fail/methods.rs | 27 +++++++++++++++++++ 5 files changed, 90 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 631c1d7f1d2..29644a14fc4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 92 lints included in this crate: +There are 93 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -63,6 +63,7 @@ name [option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` [option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method when the `*or_else` would do [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing [panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught diff --git a/src/lib.rs b/src/lib.rs index 9bb59693795..4e13ba5c458 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -194,6 +194,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, + methods::OR_FUN_CALL, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, methods::STR_TO_STRING, diff --git a/src/methods.rs b/src/methods.rs index 83b9e60f4be..ff91759be23 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -4,6 +4,7 @@ use rustc::middle::ty; use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; +use syntax::ptr::P; use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty}; @@ -170,6 +171,25 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, "using an iterator search followed by `is_some()`, which is more succinctly \ expressed as a call to `any()`"); +/// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and +/// suggests to use `or_else`, `unwrap_or_else`, etc., instead. +/// +/// **Why is this bad?** The function will always be called and potentially allocate an object +/// in expressions such as: +/// ```rust +/// foo.unwrap_or(String::new()) +/// ``` +/// this can instead be written: +/// ```rust +/// foo.unwrap_or_else(String::new) +/// ``` +/// +/// **Known problems:** If the function as side-effects, not calling it will change the semantic of +/// the program, but you shouldn't rely on that anyway. The will won't catch +/// `foo.unwrap_or(vec![])`. +declare_lint!(pub OR_FUN_CALL, Warn, + "using any `*or` method when the `*or_else` would do"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_UNWRAP_USED, @@ -181,13 +201,15 @@ impl LintPass for MethodsPass { WRONG_PUB_SELF_CONVENTION, OK_EXPECT, OPTION_MAP_UNWRAP_OR, - OPTION_MAP_UNWRAP_OR_ELSE) + OPTION_MAP_UNWRAP_OR_ELSE, + OR_FUN_CALL) } } impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(_, _, _) = expr.node { + if let ExprMethodCall(name, _, ref args) = expr.node { + // Chain calls if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { lint_unwrap(cx, expr, arglists[0]); } else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { @@ -207,6 +229,8 @@ impl LateLintPass for MethodsPass { } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); } + + lint_or_fun_call(cx, expr, &name.node.as_str(), &args); } } @@ -258,6 +282,39 @@ impl LateLintPass for MethodsPass { } } +/// Checks for the `OR_FUN_CALL` lint. +fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { + if args.len() == 2 && ["map_or", "ok_or", "or", "unwrap_or"].contains(&name) { + let self_ty = cx.tcx.expr_ty(&args[0]); + + let is_result = if match_type(cx, self_ty, &RESULT_PATH) { + true + } + else if match_type(cx, self_ty, &OPTION_PATH) { + false + } + else { + return; + }; + + if let ExprCall(ref fun, ref or_args) = args[1].node { + let sugg = match (is_result, or_args.is_empty()) { + (true, _) => format!("|_| {}", snippet(cx, args[1].span, "..")), + (false, false) => format!("|| {}", snippet(cx, args[1].span, "..")), + (false, true) => format!("{}", snippet(cx, fun.span, "..")), + }; + + span_lint(cx, OR_FUN_CALL, expr.span, + &format!("use of `{}` followed by a function call", name)) + .span_suggestion(expr.span, "try this", + format!("{}.{}_else({})", + snippet(cx, args[0].span, "_"), + name, + sugg)); + } + } +} + #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `unwrap()` for `Option`s and `Result`s diff --git a/src/utils.rs b/src/utils.rs index 312cf77d068..4b144452063 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -244,7 +244,7 @@ pub fn is_from_for_desugar(decl: &Decl) -> bool { /// snippet(cx, expr.span, "..") /// ``` pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or(Cow::Borrowed(default)) + 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. diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index b41b28dc11e..570715db6af 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -175,6 +175,33 @@ fn search_is_some() { let _ = foo.rposition().is_some(); } +/// Checks implementation of the OR_FUN_CALL lint +fn or_fun_call() { + let foo = Some(vec![1]); + foo.unwrap_or(Vec::new()); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION foo.unwrap_or_else(Vec::new); + + let bar = Some(vec![1]); + bar.unwrap_or(Vec::with_capacity(12)); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION bar.unwrap_or_else(|| Vec::with_capacity(12)); + + let baz : Result<_, ()> = Ok(vec![1]); + baz.unwrap_or(Vec::new()); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION baz.unwrap_or_else(|_| Vec::new()); + + let qux : Result<_, ()> = Ok(vec![1]); + qux.unwrap_or(Vec::with_capacity(12)); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION qux.unwrap_or_else(|_| Vec::with_capacity(12)); +} + fn main() { use std::io; -- cgit 1.4.1-3-g733a5 From 7e85db645e35061d11897c049715c845fb4cf073 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Sun, 17 Jan 2016 17:53:41 +0100 Subject: Fix another false positive in lifetime elision lint The false positive occurred when we have an anonymous input lifetime and a named output lifetime. This is not elidable, because if we elided the output lifetime, it would be inferred to be the same as the input. --- src/lifetimes.rs | 1 - tests/compile-fail/lifetimes.rs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 1edd75a45aa..83da3d8644a 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -144,7 +144,6 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> match (&input_lts[0], &output_lts[0]) { (&Named(n1), &Named(n2)) if n1 == n2 => true, (&Named(_), &Unnamed) => true, - (&Unnamed, &Named(_)) => true, _ => false, // already elided, different named lifetimes // or something static going on } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 99c16917426..eb161af9dc3 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -119,5 +119,9 @@ fn alias_with_lt3<'a>(_foo: &FooAlias<'a> ) -> &'a str { unimplemented!() } // no warning, two input lifetimes fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b> ) -> &'a str { unimplemented!() } +fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() } //~ERROR explicit lifetimes given + +fn elided_input_named_output<'a>(_arg: &str) -> &'a str { unimplemented!() } + fn main() { } -- cgit 1.4.1-3-g733a5 From 90cbc858e983e302d97f2bd72be7af9a94def51a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 13:09:46 +0100 Subject: Fix spelling mistake --- src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 171ba6f27f0..36191993474 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -484,7 +484,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { if let Some(&PathResolution { base_def: DefConst(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) { maybe_id = Some(id); } - // separate if lets to avoid doubleborrowing the defmap + // separate if lets to avoid double borrowing the def_map if let Some(id) = maybe_id { if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None) { let ret = self.expr(const_expr); -- cgit 1.4.1-3-g733a5 From fb6b3bed0fc5701287035fc9c445a202e492a0d8 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 13:10:13 +0100 Subject: Add utility functions to check for trait impl --- src/utils.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 4b144452063..c41c0a8681b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,20 +1,20 @@ -use rustc::lint::*; -use rustc_front::hir::*; +use consts::constant; use reexport::*; -use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use rustc::front::map::Node::*; +use rustc::lint::*; use rustc::middle::def_id::DefId; -use rustc::middle::ty; +use rustc::middle::{cstore, def, infer, ty, traits}; +use rustc::session::Session; +use rustc_front::hir::*; use std::borrow::Cow; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::str::FromStr; use syntax::ast::Lit_::*; use syntax::ast; +use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; -use consts::constant; - -use rustc::session::Session; -use std::str::FromStr; -use std::ops::{Deref, DerefMut}; pub type MethodArgs = HirVec<P<Expr>>; @@ -23,6 +23,7 @@ pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; @@ -132,7 +133,7 @@ pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { } } -/// Check if the method call given in `expr` belongs to given trait. +/// Check if the method call given in `expr` belongs to given type. pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { let method_call = ty::MethodCall::expr(expr.id); @@ -186,6 +187,73 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) } +/// Get the definition associated to a path. +/// TODO: investigate if there is something more efficient for that. +pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { + let cstore = &cx.tcx.sess.cstore; + + let crates = cstore.crates(); + let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); + if let Some(krate) = krate { + let mut items = cstore.crate_top_level_items(*krate); + let mut path_it = path.iter().skip(1).peekable(); + + loop { + let segment = match path_it.next() { + Some(segment) => segment, + None => return None + }; + + for item in &mem::replace(&mut items, vec![]) { + if item.name.as_str() == *segment { + if path_it.peek().is_none() { + return Some(item.def); + } + + let def_id = match item.def { + cstore::DefLike::DlDef(def) => def.def_id(), + cstore::DefLike::DlImpl(def_id) => def_id, + _ => panic!("Unexpected {:?}", item.def), + }; + + items = cstore.item_children(def_id); + break; + } + } + } + } + else { + None + } +} + +/// Convenience function to get the `DefId` of a trait by path. +pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { + let def = match path_to_def(cx, path) { + Some(def) => def, + None => return None, + }; + + match def { + cstore::DlDef(def::DefTrait(trait_id)) => Some(trait_id), + _ => None, + } +} + +/// 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) -> bool { + cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); + + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, true); + let obligation = traits::predicate_for_trait_def(cx.tcx, + traits::ObligationCause::dummy(), + trait_id, 0, ty, + vec![]); + + traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) +} + /// Match an `Expr` against a chain of methods, and return the matched `Expr`s. /// /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, -- cgit 1.4.1-3-g733a5 From b5f65ec699c8a89155c4aa214cf2510030a88a6d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 13:11:07 +0100 Subject: Improve OR_FUN_CALL to suggest unwrap_or_default --- src/methods.rs | 105 ++++++++++++++++++++++++++++++++++-------- tests/compile-fail/methods.rs | 50 +++++++++++++++----- 2 files changed, 123 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index ff91759be23..b5ce82f1a43 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -5,11 +5,13 @@ use rustc::middle::subst::{Subst, TypeSpace}; use std::iter; use std::borrow::Cow; use syntax::ptr::P; +use syntax::codemap::Span; use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method, - walk_ptrs_ty_depth, walk_ptrs_ty}; -use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH}; + walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait}; +use utils::{DEFAULT_TRAIT_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH}; use utils::MethodArgs; +use rustc::middle::cstore::CrateStore; use self::SelfKind::*; use self::OutType::*; @@ -172,7 +174,7 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, expressed as a call to `any()`"); /// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and -/// suggests to use `or_else`, `unwrap_or_else`, etc., instead. +/// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead. /// /// **Why is this bad?** The function will always be called and potentially allocate an object /// in expressions such as: @@ -183,10 +185,13 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, /// ```rust /// foo.unwrap_or_else(String::new) /// ``` +/// or +/// ```rust +/// foo.unwrap_or_default() +/// ``` /// /// **Known problems:** If the function as side-effects, not calling it will change the semantic of -/// the program, but you shouldn't rely on that anyway. The will won't catch -/// `foo.unwrap_or(vec![])`. +/// the program, but you shouldn't rely on that anyway. declare_lint!(pub OR_FUN_CALL, Warn, "using any `*or` method when the `*or_else` would do"); @@ -284,8 +289,61 @@ impl LateLintPass for MethodsPass { /// Checks for the `OR_FUN_CALL` lint. fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { - if args.len() == 2 && ["map_or", "ok_or", "or", "unwrap_or"].contains(&name) { - let self_ty = cx.tcx.expr_ty(&args[0]); + /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + fn check_unwrap_or_default( + cx: &LateContext, + name: &str, + fun: &Expr, + self_expr: &Expr, + arg: &Expr, + or_has_args: bool, + span: Span + ) -> bool { + if or_has_args { + return false; + } + + if name == "unwrap_or" { + if let ExprPath(_, ref path) = fun.node { + let path : &str = &path.segments.last() + .expect("A path must have at least one segment") + .identifier.name.as_str(); + + if ["default", "new"].contains(&path) { + let arg_ty = cx.tcx.expr_ty(arg); + let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { + default_trait_id + } + else { + return false; + }; + + if implements_trait(cx, arg_ty, default_trait_id) { + span_lint(cx, OR_FUN_CALL, span, + &format!("use of `{}` followed by a call to `{}`", name, path)) + .span_suggestion(span, "try this", + format!("{}.unwrap_or_default()", + snippet(cx, self_expr.span, "_"))); + return true; + } + } + } + } + + false + } + + /// Check for `*or(foo())`. + fn check_general_case( + cx: &LateContext, + name: &str, + fun: &Expr, + self_expr: &Expr, + arg: &Expr, + or_has_args: bool, + span: Span + ) { + let self_ty = cx.tcx.expr_ty(self_expr); let is_result = if match_type(cx, self_ty, &RESULT_PATH) { true @@ -297,20 +355,27 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) return; }; + let sugg = match (is_result, !or_has_args) { + (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")), + (false, false) => format!("|| {}", snippet(cx, arg.span, "..")), + (false, true) => format!("{}", snippet(cx, fun.span, "..")), + }; + + span_lint(cx, OR_FUN_CALL, span, + &format!("use of `{}` followed by a function call", name)) + .span_suggestion(span, "try this", + format!("{}.{}_else({})", + snippet(cx, self_expr.span, "_"), + name, + sugg)); + } + + if args.len() == 2 && ["map_or", "ok_or", "or", "unwrap_or"].contains(&name) { if let ExprCall(ref fun, ref or_args) = args[1].node { - let sugg = match (is_result, or_args.is_empty()) { - (true, _) => format!("|_| {}", snippet(cx, args[1].span, "..")), - (false, false) => format!("|| {}", snippet(cx, args[1].span, "..")), - (false, true) => format!("{}", snippet(cx, fun.span, "..")), - }; - - span_lint(cx, OR_FUN_CALL, expr.span, - &format!("use of `{}` followed by a function call", name)) - .span_suggestion(expr.span, "try this", - format!("{}.{}_else({})", - snippet(cx, args[0].span, "_"), - name, - sugg)); + let or_has_args = !or_args.is_empty(); + if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { + check_general_case(cx, name, fun, &args[0], &args[1], or_has_args, expr.span); + } } } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 570715db6af..d357fb0a54a 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -177,29 +177,55 @@ fn search_is_some() { /// Checks implementation of the OR_FUN_CALL lint fn or_fun_call() { - let foo = Some(vec![1]); - foo.unwrap_or(Vec::new()); + fn make<T>() -> T { unimplemented!(); } + + let with_constructor = Some(vec![1]); + with_constructor.unwrap_or(make()); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION with_constructor.unwrap_or_else(make) + + let with_new = Some(vec![1]); + with_new.unwrap_or(Vec::new()); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION with_new.unwrap_or_default(); + + let with_const_args = Some(vec![1]); + with_const_args.unwrap_or(Vec::with_capacity(12)); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION with_const_args.unwrap_or_else(|| Vec::with_capacity(12)); + + let with_err : Result<_, ()> = Ok(vec![1]); + with_err.unwrap_or(make()); + //~^ERROR use of `unwrap_or` + //~|HELP try this + //~|SUGGESTION with_err.unwrap_or_else(|_| make()); + + let with_err_args : Result<_, ()> = Ok(vec![1]); + with_err_args.unwrap_or(Vec::with_capacity(12)); //~^ERROR use of `unwrap_or` //~|HELP try this - //~|SUGGESTION foo.unwrap_or_else(Vec::new); + //~|SUGGESTION with_err_args.unwrap_or_else(|_| Vec::with_capacity(12)); - let bar = Some(vec![1]); - bar.unwrap_or(Vec::with_capacity(12)); + let with_default_trait = Some(1); + with_default_trait.unwrap_or(Default::default()); //~^ERROR use of `unwrap_or` //~|HELP try this - //~|SUGGESTION bar.unwrap_or_else(|| Vec::with_capacity(12)); + //~|SUGGESTION with_default_trait.unwrap_or_default(); - let baz : Result<_, ()> = Ok(vec![1]); - baz.unwrap_or(Vec::new()); + let with_default_type = Some(1); + with_default_type.unwrap_or(u64::default()); //~^ERROR use of `unwrap_or` //~|HELP try this - //~|SUGGESTION baz.unwrap_or_else(|_| Vec::new()); + //~|SUGGESTION with_default_type.unwrap_or_default(); - let qux : Result<_, ()> = Ok(vec![1]); - qux.unwrap_or(Vec::with_capacity(12)); + let with_vec = Some(vec![1]); + with_vec.unwrap_or(vec![]); //~^ERROR use of `unwrap_or` //~|HELP try this - //~|SUGGESTION qux.unwrap_or_else(|_| Vec::with_capacity(12)); + //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]); } fn main() { -- cgit 1.4.1-3-g733a5 From 21ba3151025c4438a16ee110d99b9d6a525c695f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 13:27:42 +0100 Subject: Update to rustc 1.7.0-nightly (d0bac3f14 2016-01-18) --- src/bit_mask.rs | 2 +- src/consts.rs | 2 +- src/escape.rs | 2 +- src/utils.rs | 2 +- tests/compile-fail/needless_features.rs | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index c2fd3742066..0e98f5a93a9 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -278,7 +278,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { _ => None, } } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None)) + .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None, None)) .and_then(|l| fetch_int_literal(cx, l)) } _ => None, diff --git a/src/consts.rs b/src/consts.rs index 36191993474..7b022947719 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -486,7 +486,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } // separate if lets to avoid double borrowing the def_map if let Some(id) = maybe_id { - if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None) { + if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None, None) { let ret = self.expr(const_expr); if ret.is_some() { self.needed_resolution = true; diff --git a/src/escape.rs b/src/escape.rs index 079fdcf09a0..3e59a801f68 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -45,7 +45,7 @@ impl LintPass for EscapePass { impl LateLintPass for EscapePass { fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), false); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env)); let mut v = EscapeDelegate { cx: cx, set: NodeSet(), diff --git a/src/utils.rs b/src/utils.rs index c41c0a8681b..446303f8bb1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -245,7 +245,7 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId) -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, true); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); let obligation = traits::predicate_for_trait_def(cx.tcx, traits::ObligationCause::dummy(), trait_id, 0, ty, diff --git a/tests/compile-fail/needless_features.rs b/tests/compile-fail/needless_features.rs index dee2a19d5d0..c5c82c7072b 100644 --- a/tests/compile-fail/needless_features.rs +++ b/tests/compile-fail/needless_features.rs @@ -1,5 +1,4 @@ #![feature(plugin)] -#![feature(convert)] #![plugin(clippy)] #![deny(clippy)] -- cgit 1.4.1-3-g733a5 From 3713fd3dce39e94fb5903554300df1db63a5c422 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 15:35:50 +0100 Subject: Check types in the CMP_OWNED lint --- src/methods.rs | 2 +- src/misc.rs | 29 ++++++++++++++++++++--------- src/utils.rs | 4 ++-- tests/compile-fail/cmp_owned.rs | 2 ++ 4 files changed, 25 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index b5ce82f1a43..254b68deb11 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -318,7 +318,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) return false; }; - if implements_trait(cx, arg_ty, default_trait_id) { + if implements_trait(cx, arg_ty, default_trait_id, None) { span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a call to `{}`", name, path)) .span_suggestion(span, "try this", diff --git a/src/misc.rs b/src/misc.rs index a8fabaa3fcf..52234fd61af 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -11,7 +11,7 @@ use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; -use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal}; +use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal, implements_trait}; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. /// @@ -210,18 +210,18 @@ impl LateLintPass for CmpOwned { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { if is_comparison_binop(cmp.node) { - check_to_owned(cx, left, right.span, true, cmp.span); - check_to_owned(cx, right, left.span, false, cmp.span) + check_to_owned(cx, left, right, true, cmp.span); + check_to_owned(cx, right, left, false, cmp.span) } } } } -fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, op: Span) { - let snip = match expr.node { +fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) { + let (arg_ty, snip) = match expr.node { ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => { if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { - snippet(cx, args[0].span, "..") + (cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { return; } @@ -229,7 +229,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o ExprCall(ref path, ref v) if v.len() == 1 => { if let ExprPath(None, ref path) = path.node { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { - snippet(cx, v[0].span, "..") + (cx.tcx.expr_ty(&v[0]), snippet(cx, v[0].span, "..")) } else { return; } @@ -239,6 +239,17 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o } _ => return, }; + + let other_ty = cx.tcx.expr_ty(other); + let partial_eq_trait_id = match cx.tcx.lang_items.eq_trait() { + Some(id) => id, + None => return, + }; + + if !implements_trait(cx, arg_ty, partial_eq_trait_id, Some(vec![other_ty])) { + return; + } + if left { span_lint(cx, CMP_OWNED, @@ -247,14 +258,14 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other_span: Span, left: bool, o compare without allocation", snip, snippet(cx, op, "=="), - snippet(cx, other_span, ".."))); + snippet(cx, other.span, ".."))); } else { span_lint(cx, CMP_OWNED, expr.span, &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ compare without allocation", - snippet(cx, other_span, ".."), + snippet(cx, other.span, ".."), snippet(cx, op, "=="), snip)); } diff --git a/src/utils.rs b/src/utils.rs index 446303f8bb1..65a7bc86031 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -242,14 +242,14 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { /// 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) -> bool { +pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, ty_params: Option<Vec<ty::Ty<'tcx>>>) -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); let obligation = traits::predicate_for_trait_def(cx.tcx, traits::ObligationCause::dummy(), trait_id, 0, ty, - vec![]); + ty_params.unwrap_or_default()); traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) } diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index afca83e1d32..c4c9ee60fab 100644 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -21,4 +21,6 @@ fn main() { // as of 2015-08-14 x != String::from("foo"); //~ERROR this creates an owned instance + + 42.to_string() == "42"; } -- cgit 1.4.1-3-g733a5 From 9d5e9cfd97e69ddef1e25562ecd4d351e655ae17 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 18 Jan 2016 19:28:06 +0100 Subject: Fix redundant_closure false positive --- src/eta_reduction.rs | 5 +++-- tests/compile-fail/eta.rs | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 46c458c6bcb..fcc1a6893b2 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -45,6 +45,7 @@ fn check_closure(cx: &LateContext, expr: &Expr) { // || {foo(); bar()}; can't be reduced here return; } + if let Some(ref ex) = blk.expr { if let ExprCall(ref caller, ref args) = ex.node { if args.len() != decl.inputs.len() { @@ -52,8 +53,8 @@ fn check_closure(cx: &LateContext, expr: &Expr) { // is no way the closure is the same as the function return; } - if args.iter().any(|arg| is_adjusted(cx, arg)) { - // Are the arguments type-adjusted? Then we need the closure + if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) { + // Are the expression or the arguments type-adjusted? Then we need the closure return; } let fn_ty = cx.tcx.expr_ty(caller); diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index a51d116d9cc..1ffca9ac5ce 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -21,6 +21,10 @@ fn main() { unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } + + // See #515 + let a: Option<Box<::std::ops::Deref<Target = [i32]>>> = + Some(vec![1i32, 2]).map(|v| -> Box<::std::ops::Deref<Target = [i32]>> { Box::new(v) }); } fn meta<F>(f: F) where F: Fn(u8) { -- cgit 1.4.1-3-g733a5 From 6a4d77aa32a5a0c80264fa7d385707c4e1e45ffd Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Tue, 19 Jan 2016 13:53:49 +0100 Subject: Fix deprecation warning on latest nightly --- src/lib.rs | 2 +- src/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4e13ba5c458..6c60d403e1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] -#![feature(num_bits_bytes, iter_arith)] +#![feature(iter_arith)] #![feature(custom_attribute)] #![allow(unknown_lints)] diff --git a/src/types.rs b/src/types.rs index 6289e13c85a..427b695d385 100644 --- a/src/types.rs +++ b/src/types.rs @@ -209,7 +209,7 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize { }; // n == 4 is the usize/isize case if n == 4 { - ::std::usize::BITS + ::std::mem::size_of::<usize>() * 8 } else { n } -- cgit 1.4.1-3-g733a5 From 01eda52cb5c2d3a787b2c6e81f3c699370525387 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Tue, 19 Jan 2016 19:14:49 +0100 Subject: Add lint for "string literal".as_bytes() --- README.md | 3 ++- src/lib.rs | 2 ++ src/strings.rs | 49 +++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/strings.rs | 8 +++++++ 4 files changed, 61 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/README.md b/README.md index 29644a14fc4..f76157a249d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 93 lints included in this crate: +There are 94 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -83,6 +83,7 @@ name [str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. diff --git a/src/lib.rs b/src/lib.rs index 6c60d403e1c..76d9426b25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_late_lint_pass(box panic::PanicPass); + reg.register_late_lint_pass(box strings::StringLitAsBytes); reg.register_lint_group("clippy_pedantic", vec![ @@ -225,6 +226,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_ZIP_WITH_LEN, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, + strings::STRING_LIT_AS_BYTES, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, types::BOX_VEC, diff --git a/src/strings.rs b/src/strings.rs index 55d1a0acf68..c32289f84fd 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -48,6 +48,22 @@ declare_lint! { "using `x + ..` where x is a `String`; suggests using `push_str()` instead" } +/// **What it does:** This lint matches the `as_bytes` method called on string +/// literals that contain only ascii characters. It is `Warn` by default. +/// +/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`. +/// +/// **Example:** +/// +/// ``` +/// let bs = "a byte string".as_bytes(); +/// ``` +declare_lint! { + pub STRING_LIT_AS_BYTES, + Warn, + "calling `as_bytes` on a string literal; suggests using a byte string literal instead" +} + #[derive(Copy, Clone)] pub struct StringAdd; @@ -104,3 +120,36 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { _ => false, } } + +#[derive(Copy, Clone)] +pub struct StringLitAsBytes; + +impl LintPass for StringLitAsBytes { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_LIT_AS_BYTES) + } +} + +impl LateLintPass for StringLitAsBytes { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + use std::ascii::AsciiExt; + use syntax::ast::Lit_::LitStr; + use utils::snippet; + + if let ExprMethodCall(ref name, _, ref args) = e.node { + if name.node.as_str() == "as_bytes" { + if let ExprLit(ref lit) = args[0].node { + if let LitStr(ref lit_content, _) = lit.node { + if lit_content.chars().all(|c| c.is_ascii()) { + let msg = format!("calling `as_bytes()` on a string literal. \ + Consider using a byte string literal instead: \ + `b{}`", + snippet(cx, args[0].span, r#""foo""#)); + span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg); + } + } + } + } + } + } +} diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 1ba8616ed29..7ed93737ffa 100644 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -44,6 +44,14 @@ fn both() { assert_eq!(&x, &z); } +#[allow(dead_code, unused_variables)] +#[deny(string_lit_as_bytes)] +fn str_lit_as_bytes() { + let bs = "hello there".as_bytes(); //~ERROR calling `as_bytes()` + // no warning, because this cannot be written as a byte string literal: + let ubs = "☃".as_bytes(); +} + fn main() { add_only(); add_assign_only(); -- cgit 1.4.1-3-g733a5 From ea26ae3888bd10046e723ef0c2939605cd57bb6c Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Tue, 19 Jan 2016 19:43:29 +0100 Subject: Add macro check --- src/strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index c32289f84fd..16ee08b1894 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -134,13 +134,13 @@ impl LateLintPass for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { use std::ascii::AsciiExt; use syntax::ast::Lit_::LitStr; - use utils::snippet; + use utils::{snippet, in_macro}; if let ExprMethodCall(ref name, _, ref args) = e.node { if name.node.as_str() == "as_bytes" { if let ExprLit(ref lit) = args[0].node { if let LitStr(ref lit_content, _) = lit.node { - if lit_content.chars().all(|c| c.is_ascii()) { + if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, e.span) { let msg = format!("calling `as_bytes()` on a string literal. \ Consider using a byte string literal instead: \ `b{}`", -- cgit 1.4.1-3-g733a5 From 5ac6659814f6605628618ef79cc994df7c6a049b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 20 Jan 2016 00:53:26 +0100 Subject: Handle Entry types in OR_FUN_CALL lint --- src/methods.rs | 40 ++++++++++++++++++++++++++++------------ src/utils.rs | 2 ++ tests/compile-fail/methods.rs | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 254b68deb11..7be2e0ee1d8 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -9,7 +9,10 @@ use syntax::codemap::Span; use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait}; -use utils::{DEFAULT_TRAIT_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH}; +use utils::{ + BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, + RESULT_PATH, STRING_PATH +}; use utils::MethodArgs; use rustc::middle::cstore::CrateStore; @@ -343,19 +346,31 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) or_has_args: bool, span: Span ) { + // (path, fn_has_argument, methods) + let know_types : &[(&[_], _, &[_], _)] = &[ + (&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"), + (&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"), + (&OPTION_PATH, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&RESULT_PATH, true, &["or", "unwrap_or"], "else"), + ]; + let self_ty = cx.tcx.expr_ty(self_expr); - let is_result = if match_type(cx, self_ty, &RESULT_PATH) { - true - } - else if match_type(cx, self_ty, &OPTION_PATH) { - false + 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) + }) { + (fn_has_arguments, poss, suffix) + } + else { + return + }; + + if !poss.contains(&name) { + return } - else { - return; - }; - let sugg = match (is_result, !or_has_args) { + let sugg = match (fn_has_arguments, !or_has_args) { (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")), (false, false) => format!("|| {}", snippet(cx, arg.span, "..")), (false, true) => format!("{}", snippet(cx, fun.span, "..")), @@ -364,13 +379,14 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name)) .span_suggestion(span, "try this", - format!("{}.{}_else({})", + format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, + suffix, sugg)); } - if args.len() == 2 && ["map_or", "ok_or", "or", "unwrap_or"].contains(&name) { + if args.len() == 2 { if let ExprCall(ref fun, ref or_args) = args[1].node { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { diff --git a/src/utils.rs b/src/utils.rs index 65a7bc86031..97d0d2ecf11 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,10 +20,12 @@ pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; +pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index f8642cb3ed8..1e2e881c308 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -4,6 +4,8 @@ #![allow(unused)] #![deny(clippy, clippy_pedantic)] +use std::collections::BTreeMap; +use std::collections::HashMap; use std::ops::Mul; struct T; @@ -238,6 +240,18 @@ fn or_fun_call() { //~^ERROR use of `unwrap_or` //~|HELP try this //~|SUGGESTION without_default.unwrap_or_else(Foo::new); + + let mut map = HashMap::<u64, String>::new(); + map.entry(42).or_insert(String::new()); + //~^ERROR use of `or_insert` followed by a function call + //~|HELP try this + //~|SUGGESTION map.entry(42).or_insert_with(String::new); + + let mut btree = BTreeMap::<u64, String>::new(); + btree.entry(42).or_insert(String::new()); + //~^ERROR use of `or_insert` followed by a function call + //~|HELP try this + //~|SUGGESTION btree.entry(42).or_insert_with(String::new); } fn main() { -- cgit 1.4.1-3-g733a5 From 91ff1db5bc51c8513038ce510b182b7cd75de9d4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 20 Jan 2016 02:23:39 +0100 Subject: Add a lint for starts_with --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 112 ++++++++++++++++++++++++++++++++---------- src/misc.rs | 9 ++-- tests/compile-fail/methods.rs | 12 +++++ 5 files changed, 105 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index f76157a249d..ba257ce43a1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 94 lints included in this crate: +There are 95 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ name [cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` [cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` [cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` diff --git a/src/lib.rs b/src/lib.rs index 76d9426b25a..1a4501ffce6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,6 +191,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_OVERLAPPING_ARM, matches::MATCH_REF_PATS, matches::SINGLE_MATCH, + methods::CHARS_NEXT_CMP, methods::FILTER_NEXT, methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, diff --git a/src/methods.rs b/src/methods.rs index 7be2e0ee1d8..3f57f8189c3 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -7,11 +7,14 @@ use std::borrow::Cow; use syntax::ptr::P; use syntax::codemap::Span; -use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method, - walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait}; use utils::{ - BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, - RESULT_PATH, STRING_PATH + snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, + match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait, + span_lint_and_then +}; +use utils::{ + BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, + STRING_PATH }; use utils::MethodArgs; use rustc::middle::cstore::CrateStore; @@ -176,6 +179,17 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, "using an iterator search followed by `is_some()`, which is more succinctly \ expressed as a call to `any()`"); +/// **What it does:** This lint `Warn`s on using `.chars().next()` on a `str` to check if it +/// starts with a given char. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.starts_with(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `name.chars().next() == Some('_')` +declare_lint!(pub CHARS_NEXT_CMP, Warn, + "using `.chars().next()` to check if a string starts with a char"); + /// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and /// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead. /// @@ -210,35 +224,44 @@ impl LintPass for MethodsPass { OK_EXPECT, OPTION_MAP_UNWRAP_OR, OPTION_MAP_UNWRAP_OR_ELSE, - OR_FUN_CALL) + OR_FUN_CALL, + CHARS_NEXT_CMP) } } impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(name, _, ref args) = expr.node { - // Chain calls - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - lint_unwrap(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { - lint_to_string(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { - lint_ok_expect(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { - lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { - lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { - lint_filter_next(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { - lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { - lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { - lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); - } + match expr.node { + ExprMethodCall(name, _, ref args) => { + // Chain calls + if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + lint_unwrap(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { + lint_to_string(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { + lint_ok_expect(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { + lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { + lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { + lint_filter_next(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { + lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { + lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { + lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); + } - lint_or_fun_call(cx, expr, &name.node.as_str(), &args); + lint_or_fun_call(cx, expr, &name.node.as_str(), &args); + } + ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { + if !lint_chars_next(cx, expr, lhs, rhs, op.node == BiEq) { + lint_chars_next(cx, expr, rhs, lhs, op.node == BiEq); + } + } + _ => (), } } @@ -570,6 +593,41 @@ fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, searc } } +/// Checks for the `CHARS_NEXT_CMP` lint. +fn lint_chars_next(cx: &LateContext, expr: &Expr, chain: &Expr, other: &Expr, eq: bool) -> bool { + if_let_chain! {[ + let Some(args) = method_chain_args(chain, &["chars", "next"]), + let ExprCall(ref fun, ref arg_char) = other.node, + arg_char.len() == 1, + let ExprPath(None, ref path) = fun.node, + path.segments.len() == 1 && path.segments[0].identifier.name.as_str() == "Some" + ], { + let self_ty = walk_ptrs_ty(cx.tcx.expr_ty_adjusted(&args[0][0])); + + if self_ty.sty != ty::TyStr { + return false; + } + + span_lint_and_then(cx, + CHARS_NEXT_CMP, + expr.span, + "you should use the `starts_with` method", + |db| { + let sugg = format!("{}{}.starts_with({})", + if eq { "" } else { "!" }, + snippet(cx, args[0][0].span, "_"), + snippet(cx, arg_char[0].span, "_") + ); + + db.span_suggestion(expr.span, "like this", sugg); + }); + + return true; + }} + + false +} + // Given a `Result<T, E>` type, return its error type (`E`) fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { diff --git a/src/misc.rs b/src/misc.rs index 52234fd61af..4b6170cf164 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -389,13 +389,14 @@ impl LateLintPass for UsedUnderscoreBinding { .last() .expect("path should always have at least one segment") .identifier; - ident.name.as_str().chars().next() == Some('_') && // starts with '_' - ident.name.as_str().chars().skip(1).next() != Some('_') && // doesn't start with "__" - ident.name != ident.unhygienic_name && is_used(cx, expr) // not in bang macro + ident.name.as_str().starts_with('_') && + !ident.name.as_str().starts_with("__") && + ident.name != ident.unhygienic_name && + is_used(cx, expr) // not in bang macro } ExprField(_, spanned) => { let name = spanned.node.as_str(); - name.chars().next() == Some('_') && name.chars().skip(1).next() != Some('_') + name.starts_with('_') && !name.starts_with("__") } _ => false, }; diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 1e2e881c308..535e8cc4a26 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -292,3 +292,15 @@ struct MyError(()); // doesn't implement Debug struct MyErrorWithParam<T> { x: T } + +fn starts_with() { + "".chars().next() == Some(' '); + //~^ ERROR starts_with + //~| HELP like this + //~| SUGGESTION "".starts_with(' ') + + Some(' ') != "".chars().next(); + //~^ ERROR starts_with + //~| HELP like this + //~| SUGGESTION !"".starts_with(' ') +} -- cgit 1.4.1-3-g733a5 From 7a26cfc991c1d8e60def820d133df39e30e105fd Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 20 Jan 2016 18:32:17 +0100 Subject: Add macro checks in src/methods.rs lints --- src/methods.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 3f57f8189c3..6338961b56b 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -8,9 +8,9 @@ use syntax::ptr::P; use syntax::codemap::Span; use utils::{ - snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, - match_trait_method, walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait, - span_lint_and_then + get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, + match_trait_method, match_type, method_chain_args, snippet, span_lint, span_lint_and_then, + span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, }; use utils::{ BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, @@ -231,6 +231,10 @@ impl LintPass for MethodsPass { impl LateLintPass for MethodsPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_macro(cx, expr.span) { + return; + } + match expr.node { ExprMethodCall(name, _, ref args) => { // Chain calls @@ -266,6 +270,10 @@ impl LateLintPass for MethodsPass { } fn check_item(&mut self, cx: &LateContext, item: &Item) { + if in_external_macro(cx, item.span) { + return; + } + if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { for implitem in items { let name = implitem.name; -- cgit 1.4.1-3-g733a5 From c6c0edb19b755aeeb7ab37aba4e43d0fbd28a916 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 21 Jan 2016 18:19:02 +0100 Subject: Add a lint about deriving Hash and implementing PartialEq --- README.md | 3 +- src/derive.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/utils.rs | 1 + tests/compile-fail/derive.rs | 29 +++++++++++++ 5 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/derive.rs create mode 100755 tests/compile-fail/derive.rs (limited to 'src') diff --git a/README.md b/README.md index ba257ce43a1..c45acf4af77 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 95 lints included in this crate: +There are 96 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -26,6 +26,7 @@ name [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver +[derive_hash_not_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_not_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) diff --git a/src/derive.rs b/src/derive.rs new file mode 100644 index 00000000000..6306bb8f09d --- /dev/null +++ b/src/derive.rs @@ -0,0 +1,98 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::ast::{Attribute, MetaItem_}; +use utils::{match_path, span_lint_and_then}; +use utils::HASH_PATH; + +use rustc::middle::ty::fast_reject::simplify_type; + +/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` +/// explicitely. +/// +/// **Why is this bad?** The implementation of these traits must agree (for example for use with +/// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation with +/// an explicitely defined `PartialEq`. In particular, the following must hold for any type: +/// +/// ```rust +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// #[derive(Hash)] +/// struct Foo; +/// +/// impl PartialEq for Foo { +/// .. +/// } +declare_lint! { + pub DERIVE_HASH_NOT_EQ, + Warn, + "deriving `Hash` but implementing `PartialEq` explicitly" +} + +pub struct Derive; + +impl LintPass for Derive { + fn get_lints(&self) -> LintArray { + lint_array!(DERIVE_HASH_NOT_EQ) + } +} + +impl LateLintPass for Derive { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + /// A `#[derive]`d implementation has a `#[automatically_derived]` attribute. + fn is_automatically_derived(attr: &Attribute) -> bool { + if let MetaItem_::MetaWord(ref word) = attr.node.value.node { + word == &"automatically_derived" + } + else { + false + } + } + + // If `item` is an automatically derived `Hash` implementation + if_let_chain! {[ + let ItemImpl(_, _, _, Some(ref trait_ref), ref ast_ty, _) = item.node, + match_path(&trait_ref.path, &HASH_PATH), + item.attrs.iter().any(is_automatically_derived), + 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); + + cx.tcx.populate_implementations_for_trait_if_necessary(peq_trait_def.trait_ref.def_id); + let peq_impls = peq_trait_def.borrow_impl_lists(cx.tcx).1; + let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + + + // Look for the PartialEq implementations for `ty` + if_let_chain! {[ + let Some(ty) = ast_ty_to_ty_cache.get(&ast_ty.id), + let Some(simpl_ty) = simplify_type(cx.tcx, ty, false), + let Some(impl_ids) = peq_impls.get(&simpl_ty) + ], { + for &impl_id in impl_ids { + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialEq<Foo> for Foo` + if trait_ref.input_types()[0] == *ty && + !cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived) { + span_lint_and_then( + cx, DERIVE_HASH_NOT_EQ, item.span, + &format!("you are deriving `Hash` but have implemented \ + `PartialEq` explicitely"), |db| { + if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { + db.span_note( + cx.tcx.map.span(node_id), + "`PartialEq` implemented here" + ); + } + }); + } + } + }} + }} + } +} diff --git a/src/lib.rs b/src/lib.rs index 1a4501ffce6..4a832cc7b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ pub mod entry; pub mod misc_early; pub mod array_indexing; pub mod panic; +pub mod derive; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -136,6 +137,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box array_indexing::ArrayIndexing); reg.register_late_lint_pass(box panic::PanicPass); reg.register_late_lint_pass(box strings::StringLitAsBytes); + reg.register_late_lint_pass(box derive::Derive); reg.register_lint_group("clippy_pedantic", vec![ @@ -168,6 +170,7 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, + derive::DERIVE_HASH_NOT_EQ, entry::MAP_ENTRY, eq_op::EQ_OP, escape::BOXED_LOCAL, diff --git a/src/utils.rs b/src/utils.rs index 97d0d2ecf11..c5483997f90 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,6 +27,7 @@ pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; diff --git a/tests/compile-fail/derive.rs b/tests/compile-fail/derive.rs new file mode 100755 index 00000000000..a879be28292 --- /dev/null +++ b/tests/compile-fail/derive.rs @@ -0,0 +1,29 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(warnings)] + +#[derive(PartialEq, Hash)] +struct Foo; + +impl PartialEq<u64> for Foo { + fn eq(&self, _: &u64) -> bool { true } +} + +#[derive(Hash)] +//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitely +struct Bar; + +impl PartialEq for Bar { + fn eq(&self, _: &Bar) -> bool { true } +} + +#[derive(Hash)] +//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitely +struct Baz; + +impl PartialEq<Baz> for Baz { + fn eq(&self, _: &Baz) -> bool { true } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From c86a5ccd2ee3165690386faad06ffdb4f4b59187 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 22 Jan 2016 17:54:44 +0530 Subject: Upgrade Rust to rustc 1.8.0-nightly (18b851bc5 2016-01-22) fixes #573 --- Cargo.toml | 2 +- src/bit_mask.rs | 4 ++-- src/consts.rs | 4 ++-- src/escape.rs | 4 ++-- src/lifetimes.rs | 6 +++--- src/loops.rs | 4 ++-- src/no_effect.rs | 6 +++--- src/ptr_arg.rs | 4 ++-- src/shadow.rs | 4 ++-- src/utils.rs | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 4cdc1bd9be4..36b95ebe30f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.36" +version = "0.0.37" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 0e98f5a93a9..6c6d277e25b 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::*; +use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; use syntax::codemap::Span; @@ -274,7 +274,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { // borrowing. let def_map = cx.tcx.def_map.borrow(); match def_map.get(&lit.id) { - Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id), + Some(&PathResolution { base_def: Def::Const(def_id), ..}) => Some(def_id), _ => None, } } diff --git a/src/consts.rs b/src/consts.rs index 7b022947719..34f7e924de7 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,7 +3,7 @@ use rustc::lint::LateContext; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::PathResolution; -use rustc::middle::def::Def::*; +use rustc::middle::def::Def; use rustc_front::hir::*; use syntax::ptr::P; use std::char; @@ -481,7 +481,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { if let Some(lcx) = self.lcx { let mut maybe_id = None; - if let Some(&PathResolution { base_def: DefConst(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) { + 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 diff --git a/src/escape.rs b/src/escape.rs index 70151054e95..32dbbb99226 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,7 +1,7 @@ use rustc::lint::*; +use rustc::front::map::Node::NodeStmt; use rustc_front::hir::*; use rustc_front::intravisit as visit; -use rustc::front::map::Node; use rustc::middle::ty; use rustc::middle::ty::adjustment::AutoAdjustment; use rustc::middle::expr_use_visitor::*; @@ -91,7 +91,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { return; } if let Categorization::Rvalue(..) = cmt.cat { - if let Some(Node::NodeStmt(st)) = self.cx + if let Some(NodeStmt(st)) = self.cx .tcx .map .find(self.cx.tcx.map.get_parent_node(cmt.id)) { diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 83da3d8644a..b83ac390edf 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -3,7 +3,7 @@ use reexport::*; use rustc::lint::*; use syntax::codemap::Span; use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; -use rustc::middle::def::Def::{DefTy, DefTrait, DefStruct}; +use rustc::middle::def::Def; use std::collections::{HashSet, HashMap}; use utils::{in_external_macro, span_lint}; @@ -206,13 +206,13 @@ impl<'v, 't> RefVisitor<'v, 't> { 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 { - DefTy(def_id, _) | DefStruct(def_id) => { + Def::TyAlias(def_id) | Def::Struct(def_id) => { let type_scheme = self.cx.tcx.lookup_item_type(def_id); for _ in type_scheme.generics.regions.as_slice() { self.record(&None); } } - DefTrait(def_id) => { + Def::Trait(def_id) => { let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; for _ in &trait_def.generics.regions { self.record(&None); diff --git a/src/loops.rs b/src/loops.rs index 614b561749f..699e6e525da 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -3,7 +3,7 @@ use rustc_front::hir::*; use reexport::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use rustc::middle::ty; -use rustc::middle::def::DefLocal; +use rustc::middle::def::Def; use consts::{constant_simple, Constant}; use rustc::front::map::Node::NodeBlock; use std::borrow::Cow; @@ -768,7 +768,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { - if let DefLocal(_, node_id) = path_res.base_def { + if let Def::Local(_, node_id) = path_res.base_def { return Some(node_id); } } diff --git a/src/no_effect.rs b/src/no_effect.rs index 3b2d91fc78e..075b9b62800 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,5 +1,5 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::middle::def::{DefStruct, DefVariant}; +use rustc::middle::def::Def; use rustc_front::hir::{Expr, ExprCall, ExprLit, ExprPath, ExprStruct}; use rustc_front::hir::{Stmt, StmtSemi}; @@ -36,8 +36,8 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { ExprCall(ref callee, ref args) => { let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); match def { - Some(DefStruct(..)) | - Some(DefVariant(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), + Some(Def::Struct(..)) | + Some(Def::Variant(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), _ => false, } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 2e1e16cf22b..75ce96f6350 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -4,8 +4,8 @@ use rustc::lint::*; use rustc_front::hir::*; +use rustc::front::map::NodeItem; use rustc::middle::ty; -use rustc::front::map::Node; use utils::{span_lint, match_type}; use utils::{STRING_PATH, VEC_PATH}; @@ -42,7 +42,7 @@ impl LateLintPass for PtrArg { fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let ImplItemKind::Method(ref sig, _) = item.node { - if let Some(Node::NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { + if let Some(NodeItem(it)) = cx.tcx.map.find(cx.tcx.map.get_parent(item.id)) { if let ItemImpl(_, _, _, Some(_), _, _) = it.node { return; // ignore trait impls } diff --git a/src/shadow.rs b/src/shadow.rs index 2d3e423eacb..1c445f42b55 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -5,7 +5,7 @@ use syntax::codemap::Span; use rustc_front::intravisit::{Visitor, FnKind}; use rustc::lint::*; -use rustc::middle::def::Def::{DefVariant, DefStruct}; +use rustc::middle::def::Def; use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; @@ -103,7 +103,7 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { fn is_binding(cx: &LateContext, pat: &Pat) -> bool { match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { - Some(DefVariant(..)) | Some(DefStruct(..)) => false, + Some(Def::Variant(..)) | Some(Def::Struct(..)) => false, _ => true, } } diff --git a/src/utils.rs b/src/utils.rs index 446303f8bb1..323f0592d97 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -235,7 +235,7 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { }; match def { - cstore::DlDef(def::DefTrait(trait_id)) => Some(trait_id), + cstore::DlDef(def::Def::Trait(trait_id)) => Some(trait_id), _ => None, } } -- cgit 1.4.1-3-g733a5 From 2a51f8d2becadffee4eeb96937d14060889178cc Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <rust19446194516@oli-obk.de> Date: Sun, 24 Jan 2016 10:16:56 +0100 Subject: lint on items following statements --- README.md | 3 +- src/items_after_statements.rs | 62 ++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/mut_mut.rs | 8 ++-- tests/compile-fail/cmp_owned.rs | 5 ++- tests/compile-fail/item_after_statement.rs | 9 +++++ 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 src/items_after_statements.rs create mode 100644 tests/compile-fail/item_after_statement.rs (limited to 'src') diff --git a/README.md b/README.md index c45acf4af77..5848759c2b8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 96 lints included in this crate: +There are 97 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -37,6 +37,7 @@ name [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` [len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs new file mode 100644 index 00000000000..5f109dac058 --- /dev/null +++ b/src/items_after_statements.rs @@ -0,0 +1,62 @@ +//! lint when items are used after statements + +use rustc::lint::*; +use syntax::attr::*; +use syntax::ast::*; +use utils::in_macro; + +/// **What it does:** It `Warn`s on blocks where there are items that are declared in the middle of or after the statements +/// +/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are processed in order. This might cause confusion as it's hard to figure out which item is meant in a statement. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// fn foo() { +/// println!("cake"); +/// } +/// fn main() { +/// foo(); // prints "foo" +/// fn foo() { +/// println!("foo"); +/// } +/// foo(); // prints "foo" +/// } +declare_lint! { pub ITEMS_AFTER_STATEMENTS, Warn, "finds blocks where an item comes after a statement" } + +pub struct ItemsAfterStatemets; + +impl LintPass for ItemsAfterStatemets { + fn get_lints(&self) -> LintArray { + lint_array!(ITEMS_AFTER_STATEMENTS) + } +} + +impl EarlyLintPass for ItemsAfterStatemets { + fn check_block(&mut self, cx: &EarlyContext, item: &Block) { + if in_macro(cx, item.span) { + return; + } + let mut stmts = item.stmts.iter().map(|stmt| &stmt.node); + // skip initial items + while let Some(&StmtDecl(ref decl, _)) = stmts.next() { + if let DeclLocal(_) = decl.node { + break; + } + } + // lint on all further items + for stmt in stmts { + if let StmtDecl(ref decl, _) = *stmt { + if let DeclItem(ref it) = decl.node { + if in_macro(cx, it.span) { + return; + } + cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, it.span, + "adding items after statements is confusing, since items exist from the start of the scope") + .emit(); + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 4a832cc7b89..cd69ac23c19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; pub mod identity_op; +pub mod items_after_statements; pub mod minmax; pub mod mut_mut; pub mod mut_reference; @@ -97,6 +98,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box precedence::Precedence); reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box identity_op::IdentityOp); + reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatemets); reg.register_late_lint_pass(box mut_mut::MutMut); reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); reg.register_late_lint_pass(box len_zero::LenZero); @@ -176,6 +178,7 @@ pub fn plugin_registrar(reg: &mut Registry) { escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, identity_op::IDENTITY_OP, + items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 1bdb4e9a3d6..4623ca38533 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -37,10 +37,6 @@ impl LateLintPass for MutMut { } fn check_expr_mut(cx: &LateContext, expr: &Expr) { - if in_external_macro(cx, expr.span) { - return; - } - fn unwrap_addr(expr: &Expr) -> Option<&Expr> { match expr.node { ExprAddrOf(MutMutable, ref e) => Some(e), @@ -48,6 +44,10 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { } } + if in_external_macro(cx, expr.span) { + return; + } + unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map_or_else(|| { if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty { diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index c4c9ee60fab..c06949eb01a 100644 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -3,8 +3,6 @@ #[deny(cmp_owned)] fn main() { - let x = "oh"; - #[allow(str_to_string)] fn with_to_string(x : &str) { x != "foo".to_string(); @@ -13,6 +11,9 @@ fn main() { "foo".to_string() != x; //~^ ERROR this creates an owned instance just for comparison. Consider using `"foo" != x` to compare without allocation } + + let x = "oh"; + with_to_string(x); x != "foo".to_owned(); //~ERROR this creates an owned instance diff --git a/tests/compile-fail/item_after_statement.rs b/tests/compile-fail/item_after_statement.rs new file mode 100644 index 00000000000..f104081faa9 --- /dev/null +++ b/tests/compile-fail/item_after_statement.rs @@ -0,0 +1,9 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(items_after_statements)] + +fn main() { + foo(); + fn foo() { println!("foo"); } //~ ERROR adding items after statements is confusing + foo(); +} -- cgit 1.4.1-3-g733a5 From 8ef0b86fab63cb548eb640f6fcebd8c5c9e451f0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 24 Jan 2016 13:56:23 +0100 Subject: Lint explicit Clone implementations on Copy type --- README.md | 3 +- src/derive.rs | 167 ++++++++++++++++++++++++++++++++----------- src/lib.rs | 1 + src/utils.rs | 3 +- tests/compile-fail/derive.rs | 43 ++++++++++- 5 files changed, 170 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 5848759c2b8..83ff6daa9f5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 97 lints included in this crate: +There are 98 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -30,6 +30,7 @@ name [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` diff --git a/src/derive.rs b/src/derive.rs index 6306bb8f09d..b1c0bde40a2 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,13 +1,15 @@ use rustc::lint::*; +use rustc::middle::ty::fast_reject::simplify_type; +use rustc::middle::ty; use rustc_front::hir::*; use syntax::ast::{Attribute, MetaItem_}; +use syntax::codemap::Span; +use utils::{CLONE_TRAIT_PATH, HASH_PATH}; use utils::{match_path, span_lint_and_then}; -use utils::HASH_PATH; - -use rustc::middle::ty::fast_reject::simplify_type; +use rustc::middle::ty::TypeVariants; /// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` -/// explicitely. +/// explicitly. /// /// **Why is this bad?** The implementation of these traits must agree (for example for use with /// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation with @@ -33,66 +35,145 @@ declare_lint! { "deriving `Hash` but implementing `PartialEq` explicitly" } +/// **What it does:** This lint warns about explicit `Clone` implementation for `Copy` types. +/// +/// **Why is this bad?** To avoid surprising behaviour, these traits should agree and the behaviour +/// of `Copy` cannot be overridden. In almost all situations a `Copy` type should have a `Clone` +/// implementation that does nothing more than copy the object, which is what +/// `#[derive(Copy, Clone)]` gets you. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// #[derive(Copy)] +/// struct Foo; +/// +/// impl Clone for Foo { +/// .. +/// } +declare_lint! { + pub EXPL_IMPL_CLONE_ON_COPY, + Warn, + "implementing `Clone` explicitly on `Copy` types" +} + pub struct Derive; impl LintPass for Derive { fn get_lints(&self) -> LintArray { - lint_array!(DERIVE_HASH_NOT_EQ) + lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_NOT_EQ) } } impl LateLintPass for Derive { fn check_item(&mut self, cx: &LateContext, item: &Item) { - /// A `#[derive]`d implementation has a `#[automatically_derived]` attribute. - fn is_automatically_derived(attr: &Attribute) -> bool { - if let MetaItem_::MetaWord(ref word) = attr.node.value.node { - word == &"automatically_derived" + let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + + if_let_chain! {[ + let ItemImpl(_, _, _, Some(ref trait_ref), ref ast_ty, _) = item.node, + let Some(&ty) = ast_ty_to_ty_cache.get(&ast_ty.id) + ], { + if item.attrs.iter().any(is_automatically_derived) { + check_hash_peq(cx, item.span, trait_ref, ty); } else { - false + check_copy_clone(cx, item.span, trait_ref, ty); } - } + }} + } +} - // If `item` is an automatically derived `Hash` implementation +/// Implementation of the `DERIVE_HASH_NOT_EQ` lint. +fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty) { + // If `item` is an automatically derived `Hash` implementation + if_let_chain! {[ + match_path(&trait_ref.path, &HASH_PATH), + 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); + + cx.tcx.populate_implementations_for_trait_if_necessary(peq_trait_def.trait_ref.def_id); + let peq_impls = peq_trait_def.borrow_impl_lists(cx.tcx).1; + + // Look for the PartialEq implementations for `ty` if_let_chain! {[ - let ItemImpl(_, _, _, Some(ref trait_ref), ref ast_ty, _) = item.node, - match_path(&trait_ref.path, &HASH_PATH), - item.attrs.iter().any(is_automatically_derived), - let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() + let Some(simpl_ty) = simplify_type(cx.tcx, ty, false), + let Some(impl_ids) = peq_impls.get(&simpl_ty) ], { - let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id); + for &impl_id in impl_ids { + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - cx.tcx.populate_implementations_for_trait_if_necessary(peq_trait_def.trait_ref.def_id); - let peq_impls = peq_trait_def.borrow_impl_lists(cx.tcx).1; - let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + // Only care about `impl PartialEq<Foo> for Foo` + if trait_ref.input_types()[0] == ty && + !cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived) { + span_lint_and_then( + cx, DERIVE_HASH_NOT_EQ, span, + "you are deriving `Hash` but have implemented `PartialEq` explicitly", + |db| { + if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { + db.span_note( + cx.tcx.map.span(node_id), + "`PartialEq` implemented here" + ); + } + }); + } + } + }} + }} +} +/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. +fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { + if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) { + let parameter_environment = cx.tcx.empty_parameter_environment(); - // Look for the PartialEq implementations for `ty` - if_let_chain! {[ - let Some(ty) = ast_ty_to_ty_cache.get(&ast_ty.id), - let Some(simpl_ty) = simplify_type(cx.tcx, ty, false), - let Some(impl_ids) = peq_impls.get(&simpl_ty) - ], { - for &impl_id in impl_ids { - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + if ty.moves_by_default(¶meter_environment, span) { + return; // ty is not Copy + } - // Only care about `impl PartialEq<Foo> for Foo` - if trait_ref.input_types()[0] == *ty && - !cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived) { - span_lint_and_then( - cx, DERIVE_HASH_NOT_EQ, item.span, - &format!("you are deriving `Hash` but have implemented \ - `PartialEq` explicitely"), |db| { - if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { - db.span_note( - cx.tcx.map.span(node_id), - "`PartialEq` implemented here" - ); + // Some types are not Clone by default but could be cloned `by hand` if necessary + match ty.sty { + TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => { + for variant in &def.variants { + for field in &variant.fields { + match field.ty(cx.tcx, substs).sty { + TypeVariants::TyArray(_, size) if size > 32 => { + return; } - }); + TypeVariants::TyBareFn(..) => { + return; + } + TypeVariants::TyTuple(ref tys) if tys.len() > 12 => { + return; + } + _ => (), + } } } - }} - }} + } + _ => (), + } + + span_lint_and_then( + cx, DERIVE_HASH_NOT_EQ, span, + "you are implementing `Clone` explicitly on a `Copy` type", + |db| { + db.span_note( + span, + "consider deriving `Clone` or removing `Copy`" + ); + }); + } +} + +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have. +fn is_automatically_derived(attr: &Attribute) -> bool { + if let MetaItem_::MetaWord(ref word) = attr.node.value.node { + word == &"automatically_derived" + } + else { + false } } diff --git a/src/lib.rs b/src/lib.rs index cd69ac23c19..c43c01268fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,6 +173,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_NOT_EQ, + derive::EXPL_IMPL_CLONE_ON_COPY, entry::MAP_ENTRY, eq_op::EQ_OP, escape::BOXED_LOCAL, diff --git a/src/utils.rs b/src/utils.rs index 7b9866d8530..139e94dbc91 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -22,7 +22,8 @@ pub type MethodArgs = HirVec<P<Expr>>; pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; -pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; +pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; diff --git a/tests/compile-fail/derive.rs b/tests/compile-fail/derive.rs index a879be28292..66b04a66d0f 100755 --- a/tests/compile-fail/derive.rs +++ b/tests/compile-fail/derive.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(warnings)] +#![allow(dead_code)] #[derive(PartialEq, Hash)] struct Foo; @@ -11,7 +12,7 @@ impl PartialEq<u64> for Foo { } #[derive(Hash)] -//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitely +//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitly struct Bar; impl PartialEq for Bar { @@ -19,11 +20,49 @@ impl PartialEq for Bar { } #[derive(Hash)] -//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitely +//~^ ERROR you are deriving `Hash` but have implemented `PartialEq` explicitly struct Baz; impl PartialEq<Baz> for Baz { fn eq(&self, _: &Baz) -> bool { true } } +#[derive(Copy)] +struct Qux; + +impl Clone for Qux { +//~^ ERROR you are implementing `Clone` explicitly on a `Copy` type + fn clone(&self) -> Self { Qux } +} + +// Ok, `Clone` cannot be derived because of the big array +#[derive(Copy)] +struct BigArray { + a: [u8; 65], +} + +impl Clone for BigArray { + fn clone(&self) -> Self { unimplemented!() } +} + +// Ok, function pointers are not always Clone +#[derive(Copy)] +struct FnPtr { + a: fn() -> !, +} + +impl Clone for FnPtr { + fn clone(&self) -> Self { unimplemented!() } +} + +// Ok, generics +#[derive(Copy)] +struct Generic<T> { + a: T, +} + +impl<T> Clone for Generic<T> { + fn clone(&self) -> Self { unimplemented!() } +} + fn main() {} -- cgit 1.4.1-3-g733a5 From ed96583677a955e4dcd935e35031e434ac9ea5e5 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 25 Jan 2016 14:02:47 +0100 Subject: extend_from_slice lint --- README.md | 3 ++- src/lib.rs | 1 + src/methods.rs | 46 +++++++++++++++++++++++++++++++++++++++++-- tests/compile-fail/methods.rs | 7 +++++++ 4 files changed, 54 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 83ff6daa9f5..290684d3bad 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 98 lints included in this crate: +There are 99 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -33,6 +33,7 @@ name [expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` diff --git a/src/lib.rs b/src/lib.rs index c43c01268fe..f44191b562d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -199,6 +199,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::CHARS_NEXT_CMP, + methods::EXTEND_FROM_SLICE, methods::FILTER_NEXT, methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, diff --git a/src/methods.rs b/src/methods.rs index 6338961b56b..0f09d67485a 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -14,7 +14,7 @@ use utils::{ }; use utils::{ BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, - STRING_PATH + STRING_PATH, VEC_PATH, }; use utils::MethodArgs; use rustc::middle::cstore::CrateStore; @@ -212,9 +212,20 @@ declare_lint!(pub CHARS_NEXT_CMP, Warn, declare_lint!(pub OR_FUN_CALL, Warn, "using any `*or` method when the `*or_else` would do"); +/// **What it does:** This lint `Warn`s on using `.extend(s)` on a `vec` to extend the vec by a slice. +/// +/// **Why is this bad?** Since Rust 1.6, the `extend_from_slice(_)` method is stable and at least for now faster. +/// +/// **Known problems:** None. +/// +/// **Example:** `my_vec.extend(&xs)` +declare_lint!(pub EXTEND_FROM_SLICE, Warn, + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, + lint_array!(EXTEND_FROM_SLICE, + OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING, @@ -256,6 +267,8 @@ impl LateLintPass for MethodsPass { lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["extend"]) { + lint_extend(cx, expr, arglists[0]); } lint_or_fun_call(cx, expr, &name.node.as_str(), &args); @@ -427,6 +440,35 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } } +fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); + let arg_ty = cx.tcx.expr_ty(&args[1]); + + if !match_type(cx, obj_ty, &VEC_PATH) { + return; // for your Vecs only + } + + if derefs_to_slice(&arg_ty) { + span_lint(cx, EXTEND_FROM_SLICE, expr.span, + &format!("use of `extend` to extend a Vec by a slice")) + .span_suggestion(expr.span, "try this", + format!("{}.extend_from_slice({})", + snippet(cx, args[0].span, "_"), + snippet(cx, args[1].span, "_"))); + } +} + +fn derefs_to_slice(ty: &ty::Ty) -> bool { + match ty.sty { + ty::TySlice(_) | + ty::TyStr => true, + ty::TyBox(ref inner) => derefs_to_slice(inner), + ty::TyArray(_, size) => size < 32, + ty::TyRef(_, ty::TypeAndMut { ty: ref t, .. }) => derefs_to_slice(t), + _ => false + } +} + #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `unwrap()` for `Option`s and `Result`s diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 535e8cc4a26..64b31b75597 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -304,3 +304,10 @@ fn starts_with() { //~| HELP like this //~| SUGGESTION !"".starts_with(' ') } + +fn use_extend_from_slice() { + let mut v : Vec<&'static str> = vec![]; + v.extend(&["Hello", "World"]); //~ERROR use of `extend` + + +} -- cgit 1.4.1-3-g733a5 From 2d97f916ebdcb53f22b65e8142382c9624079297 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 25 Jan 2016 19:46:56 +0100 Subject: added more test, now works with vecs and iter --- src/methods.rs | 16 ++++++++++------ tests/compile-fail/methods.rs | 7 +++++-- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 0f09d67485a..5377dd1bc52 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -448,7 +448,7 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { return; // for your Vecs only } - if derefs_to_slice(&arg_ty) { + if derefs_to_slice(cx, &args[1], &arg_ty) { span_lint(cx, EXTEND_FROM_SLICE, expr.span, &format!("use of `extend` to extend a Vec by a slice")) .span_suggestion(expr.span, "try this", @@ -458,13 +458,17 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } } -fn derefs_to_slice(ty: &ty::Ty) -> bool { +fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> bool { + if let ExprMethodCall(name, _, ref args) = expr.node { + return &name.node.as_str() == &"iter" && + derefs_to_slice(cx, &args[0], &cx.tcx.expr_ty(&args[0])) + } match ty.sty { - ty::TySlice(_) | - ty::TyStr => true, - ty::TyBox(ref inner) => derefs_to_slice(inner), + ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), + ty::TySlice(_) => true, ty::TyArray(_, size) => size < 32, - ty::TyRef(_, ty::TypeAndMut { ty: ref t, .. }) => derefs_to_slice(t), + ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | + ty::TyBox(ref inner) => derefs_to_slice(cx, expr, inner), _ => false } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 64b31b75597..752427847f3 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -308,6 +308,9 @@ fn starts_with() { fn use_extend_from_slice() { let mut v : Vec<&'static str> = vec![]; v.extend(&["Hello", "World"]); //~ERROR use of `extend` - - + v.extend(vec!["Some", "more"]); //~ERROR use of `extend` + v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend` + let o : Option<&'static str> = None; + v.extend(o); + v.extend(Some("Bye")); } -- cgit 1.4.1-3-g733a5 From d152e5c683165b9ba43de1e65aadd08f137d999d Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 26 Jan 2016 23:51:06 +0100 Subject: fixed argument check --- src/methods.rs | 22 ++++++++++++++-------- tests/compile-fail/methods.rs | 3 ++- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 5377dd1bc52..f1021c839cd 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -442,12 +442,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - let arg_ty = cx.tcx.expr_ty(&args[1]); - if !match_type(cx, obj_ty, &VEC_PATH) { - return; // for your Vecs only + return; } - + let arg_ty = cx.tcx.expr_ty(&args[1]); if derefs_to_slice(cx, &args[1], &arg_ty) { span_lint(cx, EXTEND_FROM_SLICE, expr.span, &format!("use of `extend` to extend a Vec by a slice")) @@ -459,16 +457,24 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> bool { + fn may_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> bool { + match ty.sty { + ty::TySlice(_) => true, + ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), + ty::TyArray(_, size) => size < 32, + ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | + ty::TyBox(ref inner) => may_slice(cx, expr, inner), + _ => false + } + } if let ExprMethodCall(name, _, ref args) = expr.node { return &name.node.as_str() == &"iter" && - derefs_to_slice(cx, &args[0], &cx.tcx.expr_ty(&args[0])) + may_slice(cx, &args[0], &cx.tcx.expr_ty(&args[0])) } match ty.sty { - ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), ty::TySlice(_) => true, - ty::TyArray(_, size) => size < 32, ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => derefs_to_slice(cx, expr, inner), + ty::TyBox(ref inner) => may_slice(cx, expr, inner), _ => false } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 752427847f3..3156a38cdeb 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -308,9 +308,10 @@ fn starts_with() { fn use_extend_from_slice() { let mut v : Vec<&'static str> = vec![]; v.extend(&["Hello", "World"]); //~ERROR use of `extend` - v.extend(vec!["Some", "more"]); //~ERROR use of `extend` + v.extend(&vec!["Some", "more"]); //~ERROR use of `extend` v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend` let o : Option<&'static str> = None; v.extend(o); v.extend(Some("Bye")); + v.extend(vec!["Not", "like", "this"]); } -- cgit 1.4.1-3-g733a5 From 5d5e50d67edd071aa82035435d522577bd03b2d8 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Wed, 27 Jan 2016 14:51:30 +0100 Subject: fixed suggestion for iter case --- src/methods.rs | 36 ++++++++++++++++++++++-------------- tests/compile-fail/methods.rs | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index f1021c839cd..a5f27440f94 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -446,36 +446,44 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { return; } let arg_ty = cx.tcx.expr_ty(&args[1]); - if derefs_to_slice(cx, &args[1], &arg_ty) { + if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { span_lint(cx, EXTEND_FROM_SLICE, expr.span, &format!("use of `extend` to extend a Vec by a slice")) .span_suggestion(expr.span, "try this", - format!("{}.extend_from_slice({})", + format!("{}.extend_from_slice({}{})", snippet(cx, args[0].span, "_"), - snippet(cx, args[1].span, "_"))); + r, snippet(cx, span, "_"))); } } -fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> bool { - fn may_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> bool { +fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) + -> Option<(Span, &'static str)> { + fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { ty::TySlice(_) => true, ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), ty::TyArray(_, size) => size < 32, ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => may_slice(cx, expr, inner), + ty::TyBox(ref inner) => may_slice(cx, inner), _ => false } } if let ExprMethodCall(name, _, ref args) = expr.node { - return &name.node.as_str() == &"iter" && - may_slice(cx, &args[0], &cx.tcx.expr_ty(&args[0])) - } - match ty.sty { - ty::TySlice(_) => true, - ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => may_slice(cx, expr, inner), - _ => false + if &name.node.as_str() == &"iter" && + may_slice(cx, &cx.tcx.expr_ty(&args[0])) { + Some((args[0].span, "&")) + } else { + None + } + } else { + match ty.sty { + ty::TySlice(_) => Some((expr.span, "")), + ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | + ty::TyBox(ref inner) => if may_slice(cx, inner) { + Some((expr.span, "")) + } else { None }, + _ => None + } } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 3156a38cdeb..5172aa9e9df 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -314,4 +314,5 @@ fn use_extend_from_slice() { v.extend(o); v.extend(Some("Bye")); v.extend(vec!["Not", "like", "this"]); + v.extend(["Nor", "this"].iter()); } -- cgit 1.4.1-3-g733a5 From 04f9d35f64b0a08a6ea2ff6ce8ceab358526cade Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 27 Jan 2016 20:23:59 +0100 Subject: Add a lint for casts from char literals to u8 --- src/lib.rs | 1 + src/types.rs | 38 ++++++++++++++++++++++++++++++++++++ tests/compile-fail/char_lit_as_u8.rs | 8 ++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/compile-fail/char_lit_as_u8.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c43c01268fe..731778db606 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,6 +140,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box panic::PanicPass); reg.register_late_lint_pass(box strings::StringLitAsBytes); reg.register_late_lint_pass(box derive::Derive); + reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_lint_group("clippy_pedantic", vec![ diff --git a/src/types.rs b/src/types.rs index 427b695d385..42824c36ec6 100644 --- a/src/types.rs +++ b/src/types.rs @@ -517,3 +517,41 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { self.nest -= sub_nest; } } + +/// **What it does:** This lint points out expressions where a character literal is casted to u8 and suggests using a byte literal instead. +/// +/// **Why is this bad?** In general, casting values to smaller types is error-prone and should be avoided where possible. In the particular case of converting a character literal to u8, it is easy to avoid by just using a byte literal instead. As an added bonus, `b'a'` is even slightly shorter than `'a' as u8`. +/// +/// **Known problems:** None +/// +/// **Example:** `'x' as u8` +declare_lint!(pub CHAR_LIT_AS_U8, Warn, + "Casting a character literal to u8"); + +pub struct CharLitAsU8; + +impl LintPass for CharLitAsU8 { + fn get_lints(&self) -> LintArray { + lint_array!(CHAR_LIT_AS_U8) + } +} + +impl LateLintPass for CharLitAsU8 { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + use syntax::ast::{Lit_, UintTy}; + + if let ExprCast(ref e, _) = expr.node { + if let ExprLit(ref l) = e.node { + if let Lit_::LitChar(_) = l.node { + if ty::TyUint(UintTy::TyU8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { + let msg = "casting character literal to u8."; + 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); + } + } + } + } + } +} diff --git a/tests/compile-fail/char_lit_as_u8.rs b/tests/compile-fail/char_lit_as_u8.rs new file mode 100644 index 00000000000..4fca878c4da --- /dev/null +++ b/tests/compile-fail/char_lit_as_u8.rs @@ -0,0 +1,8 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(char_lit_as_u8)] +#![allow(unused_variables)] +fn main() { + let c = 'a' as u8; //~ERROR casting character literal +} -- cgit 1.4.1-3-g733a5 From 23dfb2fbc0e10150ec00053406d372321a09bbd6 Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 27 Jan 2016 20:59:19 +0100 Subject: Make update_lints script accept digits in lint names --- README.md | 3 ++- src/lib.rs | 1 + util/update_lints.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 83ff6daa9f5..63ecbf11fcf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 98 lints included in this crate: +There are 99 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ name [cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` [cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` [cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | Casting a character literal to u8 [chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` diff --git a/src/lib.rs b/src/lib.rs index 731778db606..b0cf4d46972 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,6 +239,7 @@ pub fn plugin_registrar(reg: &mut Registry) { temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, types::BOX_VEC, + types::CHAR_LIT_AS_U8, types::LET_UNIT_VALUE, types::LINKEDLIST, types::TYPE_COMPLEXITY, diff --git a/util/update_lints.py b/util/update_lints.py index 94b2a3a57ba..6a59abcdc15 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -9,7 +9,7 @@ import sys declare_lint_re = re.compile(r''' declare_lint! \s* [{(] \s* - pub \s+ (?P<name>[A-Z_]+) \s*,\s* + pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s* (?P<level>Forbid|Deny|Warn|Allow) \s*,\s* " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] ''', re.X | re.S) -- cgit 1.4.1-3-g733a5 From cee96fab39299449f877c3db997d1cf421abc8af Mon Sep 17 00:00:00 2001 From: Florian Hartwig <florian.j.hartwig@gmail.com> Date: Wed, 27 Jan 2016 21:10:35 +0100 Subject: Point out that char is 32 bit value --- src/types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 42824c36ec6..d41896cd490 100644 --- a/src/types.rs +++ b/src/types.rs @@ -544,7 +544,9 @@ impl LateLintPass for CharLitAsU8 { if let ExprLit(ref l) = e.node { if let Lit_::LitChar(_) = l.node { if ty::TyUint(UintTy::TyU8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { - let msg = "casting character literal to u8."; + 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'")); -- cgit 1.4.1-3-g733a5 From da93643357128faf432d2d03c29d87e81084dce2 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 28 Jan 2016 19:29:59 +0100 Subject: Add a lint to warn about use of `print{,ln}!` --- README.md | 3 ++- src/lib.rs | 4 ++++ src/print.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/utils.rs | 27 +++++++++++++++++++++++++ tests/compile-fail/print.rs | 11 ++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/print.rs create mode 100755 tests/compile-fail/print.rs (limited to 'src') diff --git a/README.md b/README.md index 04b0bd0e384..2673d81f808 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 100 lints included in this crate: +There are 101 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -73,6 +73,7 @@ name [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing [panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught +[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout [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 [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 diff --git a/src/lib.rs b/src/lib.rs index 6d706888fc3..8b115a304e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ // this only exists to allow the "dogfood" integration test to work #[allow(dead_code)] +#[allow(print_stdout)] fn main() { println!("What are you doing? Don't run clippy as an executable"); } @@ -77,6 +78,7 @@ pub mod misc_early; pub mod array_indexing; pub mod panic; pub mod derive; +pub mod print; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -141,6 +143,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box strings::StringLitAsBytes); reg.register_late_lint_pass(box derive::Derive); reg.register_late_lint_pass(box types::CharLitAsU8); + reg.register_late_lint_pass(box print::PrintLint); reg.register_lint_group("clippy_pedantic", vec![ @@ -149,6 +152,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::WRONG_PUB_SELF_CONVENTION, mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, + print::PRINT_STDOUT, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, diff --git a/src/print.rs b/src/print.rs new file mode 100644 index 00000000000..a47fa69b2e8 --- /dev/null +++ b/src/print.rs @@ -0,0 +1,49 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::{IO_PRINT_PATH, is_expn_of, match_path, span_lint}; + +/// **What it does:** This lint warns whenever you print on *stdout*. This lint is `Allow` by +/// default, the purpose is to catch debugging remnants. +/// +/// **Why is this bad?** People often print on *stdout* while debugging an application and might +/// forget to remove those prints afterward. +/// +/// **Known problems:** Only catches `print!` and `println!` calls. +/// +/// **Example:** `println!("Hello world!");` +declare_lint! { + pub PRINT_STDOUT, + Allow, + "printing on stdout" +} + +#[derive(Copy, Clone, Debug)] +pub struct PrintLint; + +impl LintPass for PrintLint { + fn get_lints(&self) -> LintArray { + lint_array!(PRINT_STDOUT) + } +} + +impl LateLintPass for PrintLint { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprCall(ref fun, _) = expr.node { + if let ExprPath(_, ref path) = fun.node { + if match_path(path, &IO_PRINT_PATH) { + if let Some(span) = is_expn_of(cx, expr.span, "print") { + let (span, name) = match is_expn_of(cx, span, "println") { + Some(span) => (span, "println"), + None => (span, "print"), + }; + + span_lint(cx, + PRINT_STDOUT, + span, + &format!("use of `{}!`", name)); + } + } + } + } + } +} diff --git a/src/utils.rs b/src/utils.rs index 139e94dbc91..c59e35c5c5b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -29,6 +29,7 @@ pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"] pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; +pub const IO_PRINT_PATH: [&'static str; 3] = ["std", "io", "_print"]; pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; @@ -645,3 +646,29 @@ fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { _ => false, } } + +/// Return the pre-expansion span is this comes from a expansion of the macro `name`. +pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { + 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) + }) + }); + + return match span_name_span { + Some((mac_name, new_span)) => { + if mac_name.as_str() == name { + Some(new_span) + } + else { + span = new_span; + continue; + } + } + None => { + None + } + }; + } +} diff --git a/tests/compile-fail/print.rs b/tests/compile-fail/print.rs new file mode 100755 index 00000000000..8141cdd2645 --- /dev/null +++ b/tests/compile-fail/print.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(print_stdout)] + +fn main() { + println!("Hello"); //~ERROR use of `println!` + print!("Hello"); //~ERROR use of `print!` + + vec![1, 2]; +} -- cgit 1.4.1-3-g733a5 From f5cc94c96a1f00d4ed7360df13b3ce78721c623d Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Thu, 28 Jan 2016 23:34:09 -0800 Subject: Add for_loop_over_option lint --- README.md | 3 ++- src/lib.rs | 1 + src/loops.rs | 36 +++++++++++++++++++++++++++++++++--- tests/compile-fail/for_loop.rs | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 2673d81f808..b58d2f67ac2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 101 lints included in this crate: +There are 102 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -37,6 +37,7 @@ name [extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an Option, which is more clear as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases diff --git a/src/lib.rs b/src/lib.rs index 8b115a304e9..b955a337076 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,6 +192,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EMPTY_LOOP, loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, + loops::FOR_LOOP_OVER_OPTION, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, loops::REVERSE_RANGE_LOOP, diff --git a/src/loops.rs b/src/loops.rs index 699e6e525da..dd7f7cbe3eb 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -11,7 +11,7 @@ use std::collections::{HashSet, HashMap}; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal, get_enclosing_block}; -use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH}; +use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH, OPTION_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. /// @@ -48,6 +48,16 @@ declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } +/// **What it does:** This lint checks for `for` loops over Option values. It is `Warn` by default. +/// +/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in option { .. }`. This should be `if let Some(x) = option { .. }`. +declare_lint!{ pub FOR_LOOP_OVER_OPTION, Warn, + "for-looping over an Option, which is more clear as an `if let`" } + /// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. /// /// **Why is this bad?** The `while let` loop is usually shorter and more readable @@ -248,7 +258,7 @@ impl LateLintPass for LoopsPass { fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { check_for_loop_range(cx, pat, arg, body, expr); check_for_loop_reverse_range(cx, arg, expr); - check_for_loop_explicit_iter(cx, arg, expr); + check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); } @@ -373,7 +383,8 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { } } -fn check_for_loop_explicit_iter(cx: &LateContext, arg: &Expr, expr: &Expr) { +fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { + let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used if let ExprMethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments if args.len() == 1 { @@ -401,10 +412,29 @@ fn check_for_loop_explicit_iter(cx: &LateContext, arg: &Expr, expr: &Expr) { expr.span, "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ probably not what you want"); + next_loop_linted = true; } } } + if !next_loop_linted { + check_option_looping(cx, pat, arg); + } +} +/// Check for `for` loops over `Option`s +fn check_option_looping(cx: &LateContext, pat: &Pat, arg: &Expr) { + let ty = cx.tcx.expr_ty(arg); + if match_type(cx, ty, &OPTION_PATH) { + span_help_and_lint( + cx, + FOR_LOOP_OVER_OPTION, + arg.span, + &format!("for loop over `{0}`, which is an Option. This is more readably written as \ + an `if let` statement.", snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", + snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_")) + ); + } } fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 37ecd290175..a45dc4bbb35 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -3,6 +3,39 @@ use std::collections::*; +#[deny(clippy)] +fn for_loop_over_option() { + let option = Some(1); + let v = vec![0,1,2]; + + // check FOR_LOOP_OVER_OPTION lint + for x in option { + //~^ ERROR for loop over `option`, which is an Option. + //~| HELP consider replacing `for x in option` with `if let Some(x) = option` + println!("{}", x); + } + + // make sure LOOP_OVER_NEXT lint takes precedence + for x in v.iter().next() { + //~^ ERROR you are iterating over `Iterator::next()` which is an Option + // TODO: make sure we don't lint twice + println!("{}", x); + } + + // check for false positives + + // for loop false positive + for x in v { + println!("{}", x); + } + + // while let false positive + while let Some(x) = option { + println!("{}", x); + break; + } +} + struct Unrelated(Vec<u8>); impl Unrelated { fn next(&self) -> std::slice::Iter<u8> { @@ -209,4 +242,6 @@ fn main() { let mut index = 0; for _v in &vec { index += 1 } println!("index: {}", index); + + for_loop_over_option(); } -- cgit 1.4.1-3-g733a5 From afb7e6721797484c704a01ed94ae67c086cdc007 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 29 Jan 2016 01:54:10 +0100 Subject: Add a lint to warn about &vec![_] if &[_] would do --- README.md | 3 +- src/lib.rs | 3 ++ src/utils.rs | 4 +- src/vec.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/vec.rs | 44 ++++++++++++++++++ 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/vec.rs create mode 100755 tests/compile-fail/vec.rs (limited to 'src') diff --git a/README.md b/README.md index fbd6f4ebfe6..212d868c698 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 101 lints included in this crate: +There are 102 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -105,6 +105,7 @@ name [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types +[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop [while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator [wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention diff --git a/src/lib.rs b/src/lib.rs index 8b115a304e9..90625e4bb5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,7 @@ pub mod array_indexing; pub mod panic; pub mod derive; pub mod print; +pub mod vec; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -144,6 +145,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box derive::Derive); reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box print::PrintLint); + reg.register_late_lint_pass(box vec::UselessVec); reg.register_lint_group("clippy_pedantic", vec![ @@ -250,6 +252,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, + vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); } diff --git a/src/utils.rs b/src/utils.rs index c59e35c5c5b..a6dbcfd9e2f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,6 +20,7 @@ pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"]; pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; @@ -36,6 +37,7 @@ pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; /// Produce a nested chain of if-lets and ifs from the patterns: @@ -487,7 +489,7 @@ 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) -> DiagnosticWrapper<'a> - where F: Fn(&mut DiagnosticWrapper) + where F: FnOnce(&mut DiagnosticWrapper) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { diff --git a/src/vec.rs b/src/vec.rs new file mode 100644 index 00000000000..b46795a3cdd --- /dev/null +++ b/src/vec.rs @@ -0,0 +1,111 @@ +use rustc::lint::*; +use rustc::middle::ty::TypeVariants; +use rustc_front::hir::*; +use syntax::codemap::Span; +use syntax::ptr::P; +use utils::{BOX_NEW_PATH, VEC_FROM_ELEM_PATH}; +use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; + +/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. +/// It is `Warn` by default. +/// +/// **Why is this bad?** This is less efficient. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust, ignore +/// foo(&vec![1, 2]) +/// ``` +declare_lint! { + pub USELESS_VEC, + Warn, + "useless `vec!`" +} + +#[derive(Copy, Clone, Debug)] +pub struct UselessVec; + +impl LintPass for UselessVec { + fn get_lints(&self) -> LintArray { + lint_array!(USELESS_VEC) + } +} + +impl LateLintPass for UselessVec { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + unexpand_vec(cx, expr); + + // search for `&!vec[_]` expressions where the adjusted type is `&[_]` + if_let_chain!{[ + let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, + let TypeVariants::TySlice(..) = ty.ty.sty, + let ExprAddrOf(_, ref addressee) = expr.node, + let Some(vec_args) = unexpand_vec(cx, addressee) + ], { + let snippet = match vec_args { + VecArgs::Repeat(elem, len) => { + format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() + } + VecArgs::Vec(args) => { + if let Some(last) = args.iter().last() { + let span = Span { + lo: args[0].span.lo, + hi: last.span.hi, + expn_id: args[0].span.expn_id, + }; + + format!("&[{}]", snippet(cx, span, "..")).into() + } + else { + "&[]".into() + } + } + }; + + span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { + db.span_suggestion(expr.span, "you can use a slice directly", snippet); + }); + }} + } +} + +/// Represent the pre-expansion arguments of a `vec!` invocation. +pub enum VecArgs<'a> { + /// `vec![elem, len]` + Repeat(&'a P<Expr>, &'a P<Expr>), + /// `vec![a, b, c]` + Vec(&'a [P<Expr>]), +} + +/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. +pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>> { + if_let_chain!{[ + let ExprCall(ref fun, ref args) = expr.node, + let ExprPath(_, ref path) = fun.node, + is_expn_of(cx, fun.span, "vec").is_some() + ], { + return if match_path(path, &VEC_FROM_ELEM_PATH) && args.len() == 2 { + // `vec![elem; size]` case + Some(VecArgs::Repeat(&args[0], &args[1])) + } + else if match_path(path, &["into_vec"]) && args.len() == 1 { + // `vec![a, b, c]` case + if_let_chain!{[ + let ExprCall(ref fun, ref args) = args[0].node, + let ExprPath(_, ref path) = fun.node, + match_path(path, &BOX_NEW_PATH) && args.len() == 1, + let ExprVec(ref args) = args[0].node + ], { + return Some(VecArgs::Vec(&*args)); + }} + + None + } + else { + None + }; + }} + + None +} diff --git a/tests/compile-fail/vec.rs b/tests/compile-fail/vec.rs new file mode 100755 index 00000000000..b4f52ecadc5 --- /dev/null +++ b/tests/compile-fail/vec.rs @@ -0,0 +1,44 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(useless_vec)] + +fn on_slice(_: &[u8]) {} +#[allow(ptr_arg)] +fn on_vec(_: &Vec<u8>) {} + +fn main() { + on_slice(&vec![]); + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION on_slice(&[]) + on_slice(&[]); + + on_slice(&vec![1, 2]); + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION on_slice(&[1, 2]) + on_slice(&[1, 2]); + + on_slice(&vec ![1, 2]); + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION on_slice(&[1, 2]) + on_slice(&[1, 2]); + + on_slice(&vec!(1, 2)); + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION on_slice(&[1, 2]) + on_slice(&[1, 2]); + + on_slice(&vec![1; 2]); + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION on_slice(&[1; 2]) + on_slice(&[1; 2]); + + on_vec(&vec![]); + on_vec(&vec![1, 2]); + on_vec(&vec![1; 2]); +} -- cgit 1.4.1-3-g733a5 From 1b9fbd8801019b9235c08e09acb92d21ac0c8c74 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 29 Jan 2016 22:18:14 +0100 Subject: Fix false positive in NEEDLESS_LIFETIMES --- src/lifetimes.rs | 60 ++++++++++++++++++++++++++++++----------- tests/compile-fail/lifetimes.rs | 5 ++++ 2 files changed, 50 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/lifetimes.rs b/src/lifetimes.rs index b83ac390edf..1441015eb0e 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -65,13 +65,30 @@ enum RefLt { Static, Named(Name), } -use self::RefLt::*; + +fn bound_lifetimes(bound: &TyParamBound) -> Option<HirVec<&Lifetime>> { + if let TraitTyParamBound(ref trait_ref, _) = *bound { + let lt = trait_ref.trait_ref.path.segments + .last().expect("a path must have at least one segment") + .parameters.lifetimes(); + + Some(lt) + } else { + None + } +} fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, generics: &Generics, span: Span) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } - if could_use_elision(cx, decl, slf, &generics.lifetimes) { + + let bounds_lts = + generics.ty_params + .iter() + .flat_map(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); + + if could_use_elision(cx, decl, slf, &generics.lifetimes, bounds_lts) { span_lint(cx, NEEDLESS_LIFETIMES, span, @@ -80,7 +97,10 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g report_extra_lifetimes(cx, decl, &generics, slf); } -fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, named_lts: &[LifetimeDef]) -> bool { +fn could_use_elision<'a, T: Iterator<Item=&'a Lifetime>>( + cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, + named_lts: &[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 @@ -112,7 +132,7 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> output_visitor.visit_ty(ty); } - let input_lts = input_visitor.into_vec(); + let input_lts = lts_from_bounds(input_visitor.into_vec(), bounds_lts); let output_lts = output_visitor.into_vec(); // check for lifetimes from higher scopes @@ -129,7 +149,7 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> // no output lifetimes, check distinctness of input lifetimes // only unnamed and static, ok - if input_lts.iter().all(|lt| *lt == Unnamed || *lt == Static) { + if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) { return false; } // we have no output reference, so we only need all distinct lifetimes @@ -142,8 +162,8 @@ fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf> } if input_lts.len() == 1 { match (&input_lts[0], &output_lts[0]) { - (&Named(n1), &Named(n2)) if n1 == n2 => true, - (&Named(_), &Unnamed) => true, + (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true, + (&RefLt::Named(_), &RefLt::Unnamed) => true, _ => false, // already elided, different named lifetimes // or something static going on } @@ -157,22 +177,32 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { let mut allowed_lts = HashSet::new(); for lt in named_lts { if lt.bounds.is_empty() { - allowed_lts.insert(Named(lt.lifetime.name)); + allowed_lts.insert(RefLt::Named(lt.lifetime.name)); } } - allowed_lts.insert(Unnamed); - allowed_lts.insert(Static); + allowed_lts.insert(RefLt::Unnamed); + allowed_lts.insert(RefLt::Static); allowed_lts } +fn lts_from_bounds<'a, T: Iterator<Item=&'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> { + for lt in bounds_lts { + if lt.name.as_str() != "'static" { + vec.push(RefLt::Named(lt.name)); + } + } + + vec +} + /// Number of unique lifetimes in the given vector. fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::<HashSet<_>>().len() } -/// A visitor usable for rustc_front::visit::walk_ty(). +/// A visitor usable for `rustc_front::visit::walk_ty()`. struct RefVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference + cx: &'v LateContext<'v, 't>, lts: Vec<RefLt>, } @@ -187,12 +217,12 @@ impl<'v, 't> RefVisitor<'v, 't> { fn record(&mut self, lifetime: &Option<Lifetime>) { if let Some(ref lt) = *lifetime { if lt.name.as_str() == "'static" { - self.lts.push(Static); + self.lts.push(RefLt::Static); } else { - self.lts.push(Named(lt.name)); + self.lts.push(RefLt::Named(lt.name)); } } else { - self.lts.push(Unnamed); + self.lts.push(RefLt::Unnamed); } } diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index eb161af9dc3..408b6762df6 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -3,6 +3,7 @@ #![deny(needless_lifetimes, unused_lifetimes)] #![allow(dead_code)] + fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } //~^ERROR explicit lifetimes given @@ -97,6 +98,7 @@ fn struct_with_lt3<'a>(_foo: &Foo<'a> ) -> &'a str { unimplemented!() } fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b> ) -> &'a str { unimplemented!() } trait WithLifetime<'a> {} + type WithLifetimeAlias<'a> = WithLifetime<'a>; // should not warn because it won't build without the lifetime @@ -123,5 +125,8 @@ fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() } //~ fn elided_input_named_output<'a>(_arg: &str) -> &'a str { unimplemented!() } +fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() } //~ERROR explicit lifetimes given +fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { unimplemented!() } + fn main() { } -- cgit 1.4.1-3-g733a5 From 3a39bbaf741f74342c694e59a3e0b1888279131c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 29 Jan 2016 22:19:14 +0100 Subject: Small cleanup --- src/entry.rs | 6 +++--- src/matches.rs | 4 ++-- src/utils.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/entry.rs b/src/entry.rs index d9fb7269be6..64d6fa7be38 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -93,19 +93,19 @@ fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: ], { let help = if sole_expr { format!("{}.entry({}).or_insert({})", - snippet(cx, map.span, ".."), + snippet(cx, map.span, "map"), snippet(cx, params[1].span, ".."), snippet(cx, params[2].span, "..")) } else { format!("{}.entry({})", - snippet(cx, map.span, ".."), + snippet(cx, map.span, "map"), snippet(cx, params[1].span, "..")) }; span_lint_and_then(cx, MAP_ENTRY, span, &format!("usage of `contains_key` followed by `insert` on `{}`", kind), |db| { - db.span_suggestion(span, "Consider using", help.clone()); + db.span_suggestion(span, "Consider using", help); }); } } diff --git a/src/matches.rs b/src/matches.rs index 4cb4df19bf8..0c18d35fa12 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -223,8 +223,8 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { expr.span, "you seem to be trying to match on a boolean expression. Consider using \ an if..else block:", move |db| { - if let Some(ref sugg) = sugg { - db.span_suggestion(expr.span, "try this", sugg.clone()); + if let Some(sugg) = sugg { + db.span_suggestion(expr.span, "try this", sugg); } }); } diff --git a/src/utils.rs b/src/utils.rs index a6dbcfd9e2f..b5355919496 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -649,7 +649,7 @@ fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { } } -/// Return the pre-expansion span is this comes from a expansion of the macro `name`. +/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { loop { let span_name_span = cx.tcx.sess.codemap().with_expn_info(span.expn_id, |expn| { -- cgit 1.4.1-3-g733a5 From 95599c6a620efcb39f130be5a77c46900a71ad0e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 29 Jan 2016 22:42:19 +0100 Subject: Synchronise comments with wiki Wiki commits bfa439b and 9b8ced8. --- src/collapsible_if.rs | 2 +- src/derive.rs | 2 ++ src/items_after_statements.rs | 8 ++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index fb1d7f696d1..dd89b22a40f 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -19,7 +19,7 @@ use syntax::codemap::Spanned; use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; /// **What it does:** This lint checks for nested `if`-statements which can be collapsed by -/// `&&`-combining their conditions and for `else { if .. } expressions that can be collapsed to +/// `&&`-combining their conditions and for `else { if .. }` expressions that can be collapsed to /// `else if ..`. It is `Warn` by default. /// /// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. diff --git a/src/derive.rs b/src/derive.rs index b1c0bde40a2..ca7649f75b3 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -29,6 +29,7 @@ use rustc::middle::ty::TypeVariants; /// impl PartialEq for Foo { /// .. /// } +/// ``` declare_lint! { pub DERIVE_HASH_NOT_EQ, Warn, @@ -52,6 +53,7 @@ declare_lint! { /// impl Clone for Foo { /// .. /// } +/// ``` declare_lint! { pub EXPL_IMPL_CLONE_ON_COPY, Warn, diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 5f109dac058..8eb3364b2bd 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -5,9 +5,12 @@ use syntax::attr::*; use syntax::ast::*; use utils::in_macro; -/// **What it does:** It `Warn`s on blocks where there are items that are declared in the middle of or after the statements +/// **What it does:** It `Warn`s on blocks where there are items that are declared in the middle of +/// or after the statements /// -/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are processed in order. This might cause confusion as it's hard to figure out which item is meant in a statement. +/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are +/// processed in order. This might cause confusion as it's hard to figure out which item is meant +/// in a statement. /// /// **Known problems:** None /// @@ -23,6 +26,7 @@ use utils::in_macro; /// } /// foo(); // prints "foo" /// } +/// ``` declare_lint! { pub ITEMS_AFTER_STATEMENTS, Warn, "finds blocks where an item comes after a statement" } pub struct ItemsAfterStatemets; -- cgit 1.4.1-3-g733a5 From f7bab322f65c3cbc5a312ea02fb6f4781c167e1e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 29 Jan 2016 22:49:48 +0100 Subject: Fix formatting on wiki --- src/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vec.rs b/src/vec.rs index b46795a3cdd..41a477c34ff 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -14,7 +14,7 @@ use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; /// **Known problems:** None. /// /// **Example:** -/// ```rust, ignore +/// ```rust,ignore /// foo(&vec![1, 2]) /// ``` declare_lint! { -- cgit 1.4.1-3-g733a5 From 405d7c691e2ad6b21e044b39c736b1e1a7db99cf Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Fri, 29 Jan 2016 15:15:57 -0800 Subject: Add for_loop_over_result lint --- README.md | 5 +++-- src/lib.rs | 1 + src/loops.rs | 35 ++++++++++++++++++++++++------ tests/compile-fail/for_loop.rs | 48 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 74 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index b58d2f67ac2..39b848d036b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 102 lints included in this crate: +There are 103 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -37,7 +37,8 @@ name [extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an Option, which is more clear as an `if let` +[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` +[for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases diff --git a/src/lib.rs b/src/lib.rs index b955a337076..a6f5aa97485 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,6 +193,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, loops::FOR_LOOP_OVER_OPTION, + loops::FOR_LOOP_OVER_RESULT, loops::ITER_NEXT_LOOP, loops::NEEDLESS_RANGE_LOOP, loops::REVERSE_RANGE_LOOP, diff --git a/src/loops.rs b/src/loops.rs index dd7f7cbe3eb..74ff9edcb6b 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -11,7 +11,7 @@ use std::collections::{HashSet, HashMap}; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal, get_enclosing_block}; -use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH, OPTION_PATH}; +use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH, OPTION_PATH, RESULT_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. /// @@ -48,7 +48,7 @@ declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, declare_lint!{ pub ITER_NEXT_LOOP, Warn, "for-looping over `_.next()` which is probably not intended" } -/// **What it does:** This lint checks for `for` loops over Option values. It is `Warn` by default. +/// **What it does:** This lint checks for `for` loops over `Option` values. It is `Warn` by default. /// /// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. /// @@ -56,7 +56,17 @@ declare_lint!{ pub ITER_NEXT_LOOP, Warn, /// /// **Example:** `for x in option { .. }`. This should be `if let Some(x) = option { .. }`. declare_lint!{ pub FOR_LOOP_OVER_OPTION, Warn, - "for-looping over an Option, which is more clear as an `if let`" } + "for-looping over an `Option`, which is more clearly expressed as an `if let`" } + +/// **What it does:** This lint checks for `for` loops over `Result` values. It is `Warn` by default. +/// +/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in result { .. }`. This should be `if let Ok(x) = result { .. }`. +declare_lint!{ pub FOR_LOOP_OVER_RESULT, Warn, + "for-looping over a `Result`, which is more clearly expressed as an `if let`" } /// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. /// @@ -417,24 +427,35 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { } } if !next_loop_linted { - check_option_looping(cx, pat, arg); + check_arg_type(cx, pat, arg); } } -/// Check for `for` loops over `Option`s -fn check_option_looping(cx: &LateContext, pat: &Pat, arg: &Expr) { +/// Check for `for` loops over `Option`s and `Results` +fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { let ty = cx.tcx.expr_ty(arg); if match_type(cx, ty, &OPTION_PATH) { span_help_and_lint( cx, FOR_LOOP_OVER_OPTION, arg.span, - &format!("for loop over `{0}`, which is an Option. This is more readably written as \ + &format!("for loop over `{0}`, which is an `Option`. This is more readably written as \ an `if let` statement.", snippet(cx, arg.span, "_")), &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_")) ); } + else if match_type(cx, ty, &RESULT_PATH) { + span_help_and_lint( + cx, + FOR_LOOP_OVER_RESULT, + arg.span, + &format!("for loop over `{0}`, which is a `Result`. This is more readably written as \ + an `if let` statement.", snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", + snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_")) + ); + } } fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index a45dc4bbb35..1fcbbf54d1f 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -4,21 +4,51 @@ use std::collections::*; #[deny(clippy)] -fn for_loop_over_option() { +fn for_loop_over_option_and_result() { let option = Some(1); + let result = option.ok_or("x not found"); let v = vec![0,1,2]; // check FOR_LOOP_OVER_OPTION lint + for x in option { - //~^ ERROR for loop over `option`, which is an Option. + //~^ ERROR for loop over `option`, which is an `Option`. //~| HELP consider replacing `for x in option` with `if let Some(x) = option` println!("{}", x); } - // make sure LOOP_OVER_NEXT lint takes precedence + // check FOR_LOOP_OVER_RESULT lint + + for x in result { + //~^ ERROR for loop over `result`, which is a `Result`. + //~| HELP consider replacing `for x in result` with `if let Ok(x) = result` + println!("{}", x); + } + + for x in option.ok_or("x not found") { + //~^ ERROR for loop over `option.ok_or("x not found")`, which is a `Result`. + //~| HELP consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")` + println!("{}", x); + } + + // make sure LOOP_OVER_NEXT lint takes precedence when next() is the last call in the chain + for x in v.iter().next() { //~^ ERROR you are iterating over `Iterator::next()` which is an Option - // TODO: make sure we don't lint twice + println!("{}", x); + } + + // make sure we lint when next() is not the last call in the chain + + for x in v.iter().next().and(Some(0)) { + //~^ ERROR for loop over `v.iter().next().and(Some(0))`, which is an `Option` + //~| HELP consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` + println!("{}", x); + } + + for x in v.iter().next().ok_or("x not found") { + //~^ ERROR for loop over `v.iter().next().ok_or("x not found")`, which is a `Result` + //~| HELP consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")` println!("{}", x); } @@ -29,11 +59,17 @@ fn for_loop_over_option() { println!("{}", x); } - // while let false positive + // while let false positive for Option while let Some(x) = option { println!("{}", x); break; } + + // while let false positive for Option + while let Ok(x) = result { + println!("{}", x); + break; + } } struct Unrelated(Vec<u8>); @@ -243,5 +279,5 @@ fn main() { for _v in &vec { index += 1 } println!("index: {}", index); - for_loop_over_option(); + for_loop_over_option_and_result(); } -- cgit 1.4.1-3-g733a5 From e48fbba864dad14bb554bc60b445da41c8dd72d5 Mon Sep 17 00:00:00 2001 From: scurest <scurest@users.noreply.github.com> Date: Fri, 29 Jan 2016 00:39:13 -0600 Subject: Add a lint to suggest uint == 0 over uint <= 0 --- README.md | 3 +- src/escape.rs | 2 +- src/lib.rs | 2 + src/types.rs | 52 +++++++++++++++++++++++ tests/compile-fail/absurd_unsigned_comparisons.rs | 14 ++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/absurd_unsigned_comparisons.rs (limited to 'src') diff --git a/README.md b/README.md index ec1dd7f6dbb..0c94fb3383e 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,11 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 104 lints included in this crate: +There are 105 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +[absurd_unsigned_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_unsigned_comparisons) | warn | testing whether an unsigned integer is non-positive [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` diff --git a/src/escape.rs b/src/escape.rs index 32dbbb99226..c54c4395335 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { .get(&borrow_id) { if LoanCause::AutoRef == loan_cause { // x.foo() - if adj.autoderefs <= 0 { + if adj.autoderefs == 0 { self.set.remove(&lid); // Used without autodereffing (i.e. x.clone()) } } else { diff --git a/src/lib.rs b/src/lib.rs index 82bd2d39a12..3519fb9ee88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,6 +146,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); + reg.register_late_lint_pass(box types::AbsurdUnsignedComparisons); reg.register_lint_group("clippy_pedantic", vec![ @@ -247,6 +248,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_LIT_AS_BYTES, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, + types::ABSURD_UNSIGNED_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, types::LET_UNIT_VALUE, diff --git a/src/types.rs b/src/types.rs index d41896cd490..0ab373bfa35 100644 --- a/src/types.rs +++ b/src/types.rs @@ -557,3 +557,55 @@ impl LateLintPass for CharLitAsU8 { } } } + +/// **What it does:** This lint checks for expressions where an unsigned integer is tested to be non-positive and suggests testing for equality with zero instead. +/// +/// **Why is this bad?** `x <= 0` may mislead the reader into thinking `x` can be negative. `x == 0` makes explicit that zero is the only possibility. +/// +/// **Known problems:** None +/// +/// **Example:** `vec.len() <= 0` +declare_lint!(pub ABSURD_UNSIGNED_COMPARISONS, Warn, + "testing whether an unsigned integer is non-positive"); + +pub struct AbsurdUnsignedComparisons; + +impl LintPass for AbsurdUnsignedComparisons { + fn get_lints(&self) -> LintArray { + lint_array!(ABSURD_UNSIGNED_COMPARISONS) + } +} + +fn is_zero_lit(expr: &Expr) -> bool { + use syntax::ast::Lit_; + + if let ExprLit(ref l) = expr.node { + if let Lit_::LitInt(val, _) = l.node { + return val == 0; + } + } + false +} + +impl LateLintPass for AbsurdUnsignedComparisons { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { + let op = cmp.node; + + let comparee = match op { + BiLe if is_zero_lit(rhs) => lhs, // x <= 0 + BiGe if is_zero_lit(lhs) => rhs, // 0 >= x + _ => return, + }; + + if let ty::TyUint(_) = cx.tcx.expr_ty(comparee).sty { + if !in_macro(cx, expr.span) { + let msg = "testing whether an unsigned integer is non-positive"; + let help = format!("consider using {} == 0 instead", + snippet(cx, comparee.span, "x")); + span_help_and_lint(cx, ABSURD_UNSIGNED_COMPARISONS, expr.span, msg, &help); + } + } + } + } +} diff --git a/tests/compile-fail/absurd_unsigned_comparisons.rs b/tests/compile-fail/absurd_unsigned_comparisons.rs new file mode 100644 index 00000000000..d7817daf204 --- /dev/null +++ b/tests/compile-fail/absurd_unsigned_comparisons.rs @@ -0,0 +1,14 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(unused)] + +#[deny(absurd_unsigned_comparisons)] +fn main() { + 1u32 <= 0; //~ERROR testing whether an unsigned integer is non-positive + 1u8 <= 0; //~ERROR testing whether an unsigned integer is non-positive + 1i32 <= 0; + 0 >= 1u32; //~ERROR testing whether an unsigned integer is non-positive + 0 >= 1; + 1u32 > 0; +} -- cgit 1.4.1-3-g733a5 From a2ad0c66953cae54d43773fa51fa98e2d68d10d7 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 31 Jan 2016 23:25:10 +0100 Subject: fixed #528 --- src/block_in_if_condition.rs | 4 +++- tests/compile-fail/block_in_if_condition.rs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 53f11366cae..0162ef92dd6 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -92,7 +92,9 @@ impl LateLintPass for BlockInIfCondition { snippet_block(cx, then.span, ".."))); } } else { - if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, block.stmts[0].span) { + let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, + |e| e.span); + if in_macro(cx, span) || differing_macro_contexts(expr.span, span) { return; } // move block higher diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index 0a68d80c339..5158e74c1e0 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -3,17 +3,28 @@ #![deny(block_in_if_condition_expr)] #![deny(block_in_if_condition_stmt)] -#![allow(unused)] +#![allow(unused, let_and_return)] macro_rules! blocky { () => {{true}} } +macro_rules! blocky_too { + () => {{ + let r = true; + r + }} +} + 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' -- cgit 1.4.1-3-g733a5 From d6c0435c81c594c9fb3d563d0306ac24c25cc2ca Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <rust19446194516@oli-obk.de> Date: Sun, 24 Jan 2016 12:24:16 +0100 Subject: lint on single match expressions with a value in the else path --- README.md | 3 +- src/lib.rs | 1 + src/matches.rs | 76 ++++++++++++++++++++++++++++++++++--------- tests/compile-fail/matches.rs | 22 ++++++++++++- 4 files changed, 85 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index ec1dd7f6dbb..36037036147 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 104 lints included in this crate: +There are 105 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -89,6 +89,7 @@ name [shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value [should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait [single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead [str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead diff --git a/src/lib.rs b/src/lib.rs index 82bd2d39a12..6d8ea99ebcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,6 +149,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy_pedantic", vec![ + matches::SINGLE_MATCH_ELSE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, diff --git a/src/matches.rs b/src/matches.rs index 0c18d35fa12..c866a48d223 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -28,6 +28,23 @@ declare_lint!(pub SINGLE_MATCH, Warn, "a match statement with a single nontrivial arm (i.e, where the other arm \ is `_ => {}`) is used; recommends `if let` instead"); +/// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. It is `Allow` by default. +/// +/// **Why is this bad?** Just readability – `if let` nests less than a `match`. +/// +/// **Known problems:** Personal style preferences may differ +/// +/// **Example:** +/// ``` +/// match x { +/// Some(ref foo) -> bar(foo), +/// _ => bar(other_ref), +/// } +/// ``` +declare_lint!(pub SINGLE_MATCH_ELSE, Allow, + "a match statement with a two arms where the second arm's pattern is a wildcard; \ + recommends `if let` instead"); + /// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. It is `Warn` by default. /// /// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. @@ -89,7 +106,7 @@ pub struct MatchPass; impl LintPass for MatchPass { fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL) + lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE) } } @@ -112,34 +129,49 @@ impl LateLintPass for MatchPass { fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { 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_unit_expr(&arms[1].body) { + arms[1].pats.len() == 1 && arms[1].guard.is_none() { + let els = if is_unit_expr(&arms[1].body) { + None + } else if let ExprBlock(_) = arms[1].body.node { + // matches with blocks that contain statements are prettier as `if let + else` + Some(&*arms[1].body) + } else { + // allow match arms with just expressions + return; + }; let ty = cx.tcx.expr_ty(ex); if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { - check_single_match_single_pattern(cx, ex, arms, expr); - check_single_match_opt_like(cx, ex, arms, expr, ty); + check_single_match_single_pattern(cx, ex, arms, expr, els); + check_single_match_opt_like(cx, ex, arms, expr, ty, els); } } } -fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { +fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { if arms[1].pats[0].node == PatWild { + let lint = if els.is_some() { + SINGLE_MATCH_ELSE + } else { + SINGLE_MATCH + }; + let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); span_lint_and_then(cx, - SINGLE_MATCH, + lint, expr.span, "you seem to be trying to use match for destructuring a single pattern. \ Consider using `if let`", |db| { db.span_suggestion(expr.span, "try this", - format!("if let {} = {} {}", + format!("if let {} = {} {}{}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."))); + expr_block(cx, &arms[0].body, None, ".."), + els_str)); }); } } -fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: ty::Ty) { - // list of candidate Enums we know will never get any more membre +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 = &[ (&COW_PATH, "Borrowed"), (&COW_PATH, "Cow::Borrowed"), @@ -151,23 +183,37 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: ]; let path = match arms[1].pats[0].node { - PatEnum(ref path, _) => path.to_string(), + PatEnum(ref path, Some(ref inner)) => { + // contains any non wildcard patterns? e.g. Err(err) + if inner.iter().any(|pat| if let PatWild = pat.node { false } else { true }) { + return; + } + path.to_string() + }, + PatEnum(ref path, None) => path.to_string(), PatIdent(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), _ => return }; for &(ty_path, pat_path) in candidates { if &path == pat_path && match_type(cx, ty, ty_path) { + let lint = if els.is_some() { + SINGLE_MATCH_ELSE + } else { + SINGLE_MATCH + }; + let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); span_lint_and_then(cx, - SINGLE_MATCH, + lint, expr.span, "you seem to be trying to use match for destructuring a single pattern. \ Consider using `if let`", |db| { db.span_suggestion(expr.span, "try this", - format!("if let {} = {} {}", + format!("if let {} = {} {}{}", snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."))); + expr_block(cx, &arms[0].body, None, ".."), + els_str)); }); } } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index c58e62419c6..71cc7c59f8f 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -3,12 +3,32 @@ #![plugin(clippy)] #![deny(clippy)] #![allow(unused)] +#![deny(single_match_else)] use std::borrow::Cow; enum Foo { Bar, Baz(u8) } use Foo::*; +enum ExprNode { + ExprAddrOf, + Butterflies, + Unicorns, +} + +static NODE: ExprNode = ExprNode::Unicorns; + +fn unwrap_addr() -> Option<&'static ExprNode> { + match ExprNode::Butterflies { //~ ERROR you seem to be trying to use match + //~^ HELP try + ExprNode::ExprAddrOf => Some(&NODE), + _ => { + let x = 5; + None + }, + } +} + fn single_match(){ let x = Some(1u8); @@ -33,7 +53,7 @@ fn single_match(){ _ => () } - // Not linted (content in the else) + // Not linted (no block with statements in the single arm) match z { (2...3, 7...9) => println!("{:?}", z), _ => println!("nope"), -- cgit 1.4.1-3-g733a5 From 07ace32ac91875be65c40a8957eb0982c027bd16 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 1 Feb 2016 11:28:39 +0100 Subject: fallout --- src/collapsible_if.rs | 65 ++++++++++++++++++++++++--------------------------- src/mut_reference.rs | 28 ++++++++-------------- src/utils.rs | 20 ++++------------ 3 files changed, 45 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index dd89b22a40f..4b3c4174df7 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -54,43 +54,38 @@ impl LateLintPass for CollapsibleIf { fn check_if(cx: &LateContext, e: &Expr) { if let ExprIf(ref check, ref then, ref else_) = e.node { - match *else_ { - Some(ref else_) => { - if_let_chain! {[ - let ExprBlock(ref block) = else_.node, - block.stmts.is_empty(), - block.rules == BlockCheckMode::DefaultBlock, - let Some(ref else_) = block.expr, - let ExprIf(_, _, _) = else_.node - ], { - span_lint_and_then(cx, - COLLAPSIBLE_IF, - block.span, - "this `else { if .. }` block can be collapsed", |db| { - db.span_suggestion(block.span, "try", - format!("else {}", - snippet_block(cx, else_.span, ".."))); - }); - }} - } - None => { - if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = + if let Some(ref else_) = *else_ { + if_let_chain! {[ + let ExprBlock(ref block) = else_.node, + block.stmts.is_empty(), + block.rules == BlockCheckMode::DefaultBlock, + let Some(ref else_) = block.expr, + let ExprIf(_, _, _) = else_.node + ], { + span_lint_and_then(cx, + COLLAPSIBLE_IF, + block.span, + "this `else { if .. }` block can be collapsed", |db| { + db.span_suggestion(block.span, "try", + format!("else {}", + snippet_block(cx, else_.span, ".."))); + }); + }} + } else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = single_stmt_of_block(then) { - if e.span.expn_id != sp.expn_id { - return; - } - span_lint_and_then(cx, - COLLAPSIBLE_IF, - e.span, - "this if statement can be collapsed", |db| { - db.span_suggestion(e.span, "try", - format!("if {} && {} {}", - check_to_string(cx, check), - check_to_string(cx, check_inner), - snippet_block(cx, content.span, ".."))); - }); - } + if e.span.expn_id != sp.expn_id { + return; } + span_lint_and_then(cx, + COLLAPSIBLE_IF, + e.span, + "this if statement can be collapsed", |db| { + db.span_suggestion(e.span, "try", + format!("if {} && {} {}", + check_to_string(cx, check), + check_to_string(cx, check_inner), + snippet_block(cx, content.span, ".."))); + }); } } } diff --git a/src/mut_reference.rs b/src/mut_reference.rs index d92e449e7f2..15e8d310cd6 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -33,27 +33,19 @@ impl LateLintPass for UnnecessaryMutPassed { let borrowed_table = cx.tcx.tables.borrow(); match e.node { ExprCall(ref fn_expr, ref arguments) => { - match borrowed_table.node_types.get(&fn_expr.id) { - Some(function_type) => { - if let ExprPath(_, ref path) = fn_expr.node { - check_arguments(cx, &arguments, function_type, &format!("{}", path)); - } - } - None => unreachable!(), // A function with unknown type is called. - // If this happened the compiler would have aborted the - // compilation long ago. - }; - - + let function_type = borrowed_table.node_types + .get(&fn_expr.id) + .expect("A function with an unknown type is called. \ + If this happened, the compiler would have \ + aborted the compilation long ago"); + if let ExprPath(_, ref path) = fn_expr.node { + check_arguments(cx, &arguments, function_type, &format!("{}", path)); + } } ExprMethodCall(ref name, _, ref arguments) => { let method_call = MethodCall::expr(e.id); - match borrowed_table.method_map.get(&method_call) { - Some(method_type) => { - check_arguments(cx, &arguments, method_type.ty, &format!("{}", name.node.as_str())) - } - None => unreachable!(), // Just like above, this should never happen. - }; + let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen."); + check_arguments(cx, &arguments, method_type.ty, &format!("{}", name.node.as_str())) } _ => {} } diff --git a/src/utils.rs b/src/utils.rs index b5355919496..ff0c59ab290 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -657,20 +657,10 @@ pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> (ei.callee.name(), ei.call_site) }) }); - - return match span_name_span { - Some((mac_name, new_span)) => { - if mac_name.as_str() == name { - Some(new_span) - } - else { - span = new_span; - continue; - } - } - None => { - None - } - }; + match span_name_span { + Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), + None => return None, + Some((_, new_span)) => span = new_span, + } } } -- cgit 1.4.1-3-g733a5 From 35ec57c116ed4a37c6858b682542f9677835fae5 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Mon, 1 Feb 2016 20:35:01 +0900 Subject: Skip escape analysis for closure arguments --- src/escape.rs | 14 ++++++++------ tests/compile-fail/escape_analysis.rs | 5 +++++ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index 32dbbb99226..edc7b5c6fbb 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::front::map::Node::NodeStmt; +use rustc::front::map::Node::{NodeExpr, NodeStmt}; use rustc_front::hir::*; use rustc_front::intravisit as visit; use rustc::middle::ty; @@ -84,17 +84,19 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { - if self.cx.tcx.map.is_argument(consume_pat.id) { + let map = &self.cx.tcx.map; + if map.is_argument(consume_pat.id) { + // Skip closure arguments + if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) { + return; + } if is_box(cmt.ty) { self.set.insert(consume_pat.id); } return; } if let Categorization::Rvalue(..) = cmt.cat { - if let Some(NodeStmt(st)) = self.cx - .tcx - .map - .find(self.cx.tcx.map.get_parent_node(cmt.id)) { + if let Some(NodeStmt(st)) = map.find(map.get_parent_node(cmt.id)) { if let StmtDecl(ref decl, _) = st.node { if let DeclLocal(ref loc) = decl.node { if let Some(ref ex) = loc.init { diff --git a/tests/compile-fail/escape_analysis.rs b/tests/compile-fail/escape_analysis.rs index 28154d9414e..f3aa8bff41c 100644 --- a/tests/compile-fail/escape_analysis.rs +++ b/tests/compile-fail/escape_analysis.rs @@ -23,6 +23,11 @@ fn warn_arg(x: Box<A>) { //~ ERROR local variable x.foo(); } +fn nowarn_closure_arg() { + let x = Some(box A); + x.map_or((), |x| take_ref(&x)); +} + fn warn_rename_call() { let x = box A; -- cgit 1.4.1-3-g733a5 From 328d2c76260631aa8da7d0c64eeb95f2592630d1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 1 Feb 2016 12:47:31 +0100 Subject: add lint to check for enums where all variants have the same pre-/postfix --- README.md | 3 +- src/enum_variants.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/enum_variants.rs (limited to 'src') diff --git a/README.md b/README.md index 36037036147..9b249636c66 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 105 lints included in this crate: +There are 106 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -30,6 +30,7 @@ name [derive_hash_not_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_not_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types [explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do diff --git a/src/enum_variants.rs b/src/enum_variants.rs new file mode 100644 index 00000000000..bf0025e021c --- /dev/null +++ b/src/enum_variants.rs @@ -0,0 +1,90 @@ +//! lint on enum variants that are prefixed or suffixed by the same characters + +use rustc::lint::*; +use syntax::attr::*; +use syntax::ast::*; +use syntax::parse::token::InternedString; + +use utils::span_help_and_lint; + +/// **What it does:** Warns on enum variants that are prefixed or suffixed by the same characters +/// +/// **Why is this bad?** Enum variant names should specify their variant, not the enum, too. +/// +/// **Known problems:** None +/// +/// **Example:** enum Cake { BlackForestCake, HummingbirdCake } +declare_lint! { pub ENUM_VARIANT_NAMES, Warn, + "finds enums where all variants share a prefix/postfix" } + +pub struct EnumVariantNames; + +impl LintPass for EnumVariantNames { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_VARIANT_NAMES) + } +} + +fn var2str(var: &Variant) -> InternedString { + var.node.name.name.as_str() +} + +fn partial_match(left: &str, right: &str) -> usize { + left.chars().zip(right.chars()).take_while(|&(l, r)| l == r).count() +} + +fn partial_rmatch(left: &str, right: &str) -> usize { + left.chars().rev().zip(right.chars().rev()).take_while(|&(l, r)| l == r).count() +} + +impl EarlyLintPass for EnumVariantNames { + fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + if let ItemEnum(ref def, _) = item.node { + if def.variants.len() < 2 { + return; + } + let first = var2str(&*def.variants[0]); + let mut pre = first.to_string(); + let mut post = pre.clone(); + for var in &def.variants[1..] { + let name = var2str(var); + let pre_match = partial_match(&pre, &name); + let post_match = partial_rmatch(&post, &name); + pre.truncate(pre_match); + let post_end = post.len() - post_match; + post.drain(..post_end); + } + if let Some(c) = first[pre.len()..].chars().next() { + if !c.is_uppercase() { + // non camel case prefix + pre.clear() + } + } + if let Some(c) = first[..(first.len() - post.len())].chars().rev().next() { + if let Some(c1) = post.chars().next() { + if !c.is_lowercase() || !c1.is_uppercase() { + // non camel case postfix + post.clear() + } + } + } + if pre == "_" { + // don't lint on underscores which are meant to allow dead code + pre.clear(); + } + let (what, value) = if !pre.is_empty() { + ("pre", pre) + } else if !post.is_empty() { + ("post", post) + } else { + return + }; + span_help_and_lint(cx, + ENUM_VARIANT_NAMES, + item.span, + &format!("All variants have the same {}fix: `{}`", what, value), + &format!("remove the {}fixes and use full paths to \ + the variants instead of glob imports", what)); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 6d8ea99ebcc..15d1db19d97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ pub mod ptr_arg; pub mod needless_bool; pub mod approx_const; pub mod eta_reduction; +pub mod enum_variants; pub mod identity_op; pub mod items_after_statements; pub mod minmax; @@ -93,6 +94,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box misc::TopLevelRefPass); reg.register_late_lint_pass(box misc::CmpNan); reg.register_late_lint_pass(box eq_op::EqOp); + reg.register_early_lint_pass(box enum_variants::EnumVariantNames); reg.register_late_lint_pass(box bit_mask::BitMask); reg.register_late_lint_pass(box ptr_arg::PtrArg); reg.register_late_lint_pass(box needless_bool::NeedlessBool); @@ -183,6 +185,7 @@ pub fn plugin_registrar(reg: &mut Registry) { derive::DERIVE_HASH_NOT_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, entry::MAP_ENTRY, + enum_variants::ENUM_VARIANT_NAMES, eq_op::EQ_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, -- cgit 1.4.1-3-g733a5 From 3b1df8d3814752b704fb741af2b10ebb2fd98243 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 1 Feb 2016 12:51:33 +0100 Subject: fallout --- src/consts.rs | 167 +++++++++++----------- src/identity_op.rs | 5 +- src/loops.rs | 4 +- src/methods.rs | 197 +++++++++++++------------- src/zero_div_zero.rs | 4 +- tests/cc_seme.rs | 10 +- tests/compile-fail/complex_types.rs | 4 +- tests/compile-fail/no_effect.rs | 12 +- tests/compile-fail/used_underscore_binding.rs | 10 +- tests/consts.rs | 13 +- 10 files changed, 210 insertions(+), 216 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 31094e5b6c6..f590095d9f2 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -12,7 +12,6 @@ use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; use std::fmt; -use self::Constant::*; use self::FloatWidth::*; use syntax::ast::Lit_::*; @@ -44,25 +43,25 @@ impl From<FloatTy> for FloatWidth { #[derive(Eq, Debug, Clone)] pub enum Constant { /// a String "abc" - ConstantStr(String, StrStyle), + Str(String, StrStyle), /// a Binary String b"abc" - ConstantBinary(Rc<Vec<u8>>), + Binary(Rc<Vec<u8>>), /// a single byte b'a' - ConstantByte(u8), + Byte(u8), /// a single char 'a' - ConstantChar(char), + Char(char), /// an integer - ConstantInt(u64, LitIntType), + Int(u64, LitIntType), /// a float with given type - ConstantFloat(String, FloatWidth), + Float(String, FloatWidth), /// true or false - ConstantBool(bool), + Bool(bool), /// an array of constants - ConstantVec(Vec<Constant>), + Vec(Vec<Constant>), /// also an array, but with only one constant, repeated N times - ConstantRepeat(Box<Constant>, usize), + Repeat(Box<Constant>, usize), /// a tuple of constants - ConstantTuple(Vec<Constant>), + Tuple(Vec<Constant>), } impl Constant { @@ -72,7 +71,7 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let ConstantInt(val, _) = *self { + if let Constant::Int(val, _) = *self { val // TODO we may want to check the sign if any } else { panic!("Could not convert a {:?} to u64", self); @@ -83,9 +82,9 @@ impl Constant { #[allow(cast_precision_loss)] pub fn as_float(&self) -> Option<f64> { match *self { - ConstantByte(b) => Some(b as f64), - ConstantFloat(ref s, _) => s.parse().ok(), - ConstantInt(i, ty) => { + Constant::Byte(b) => Some(b as f64), + Constant::Float(ref s, _) => s.parse().ok(), + Constant::Int(i, ty) => { Some(if is_negative(ty) { -(i as f64) } else { @@ -100,14 +99,14 @@ impl Constant { impl PartialEq for Constant { fn eq(&self, other: &Constant) -> bool { match (self, other) { - (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => ls == rs && lsty == rsty, - (&ConstantBinary(ref l), &ConstantBinary(ref r)) => l == r, - (&ConstantByte(l), &ConstantByte(r)) => l == r, - (&ConstantChar(l), &ConstantChar(r)) => l == r, - (&ConstantInt(lv, lty), &ConstantInt(rv, rty)) => { + (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => ls == rs && lsty == rsty, + (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, + (&Constant::Byte(l), &Constant::Byte(r)) => l == r, + (&Constant::Char(l), &Constant::Char(r)) => l == r, + (&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => { lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)) } - (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => { + (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -120,10 +119,10 @@ impl PartialEq for Constant { false } } - (&ConstantBool(l), &ConstantBool(r)) => l == r, - (&ConstantVec(ref l), &ConstantVec(ref r)) => l == r, - (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => ls == rs && lv == rv, - (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l == r, + (&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, + (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, _ => false, //TODO: Are there inter-type equalities? } } @@ -132,16 +131,16 @@ impl PartialEq for Constant { impl PartialOrd for Constant { fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { - (&ConstantStr(ref ls, ref lsty), &ConstantStr(ref rs, ref rsty)) => { + (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => { if lsty != rsty { None } else { Some(ls.cmp(rs)) } } - (&ConstantByte(ref l), &ConstantByte(ref r)) => Some(l.cmp(r)), - (&ConstantChar(ref l), &ConstantChar(ref r)) => Some(l.cmp(r)), - (&ConstantInt(ref lv, lty), &ConstantInt(ref rv, rty)) => { + (&Constant::Byte(ref l), &Constant::Byte(ref r)) => Some(l.cmp(r)), + (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), + (&Constant::Int(ref lv, lty), &Constant::Int(ref rv, rty)) => { Some(match (is_negative(lty) && *lv != 0, is_negative(rty) && *rv != 0) { (true, true) => rv.cmp(lv), (false, false) => lv.cmp(rv), @@ -149,7 +148,7 @@ impl PartialOrd for Constant { (false, true) => Greater, }) } - (&ConstantFloat(ref ls, lw), &ConstantFloat(ref rs, rw)) => { + (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -162,15 +161,15 @@ impl PartialOrd for Constant { None } } - (&ConstantBool(ref l), &ConstantBool(ref r)) => Some(l.cmp(r)), - (&ConstantVec(ref l), &ConstantVec(ref r)) => l.partial_cmp(&r), - (&ConstantRepeat(ref lv, ref ls), &ConstantRepeat(ref rv, ref rs)) => { + (&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)), + (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r), + (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { match lv.partial_cmp(rv) { Some(Equal) => Some(ls.cmp(rs)), x => x, } } - (&ConstantTuple(ref l), &ConstantTuple(ref r)) => l.partial_cmp(r), + (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l.partial_cmp(r), _ => None, //TODO: Are there any useful inter-type orderings? } } @@ -193,21 +192,21 @@ fn format_byte(fmt: &mut fmt::Formatter, b: u8) -> fmt::Result { impl fmt::Display for Constant { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { - ConstantStr(ref s, _) => write!(fmt, "{:?}", s), - ConstantByte(ref b) => { + Constant::Str(ref s, _) => write!(fmt, "{:?}", s), + Constant::Byte(ref b) => { write!(fmt, "b'") .and_then(|_| format_byte(fmt, *b)) .and_then(|_| write!(fmt, "'")) } - ConstantBinary(ref bs) => { + Constant::Binary(ref bs) => { try!(write!(fmt, "b\"")); for b in bs.iter() { try!(format_byte(fmt, *b)); } write!(fmt, "\"") } - ConstantChar(ref c) => write!(fmt, "'{}'", c), - ConstantInt(ref i, ref ity) => { + Constant::Char(ref c) => write!(fmt, "'{}'", c), + Constant::Int(ref i, ref ity) => { let (sign, suffix) = match *ity { LitIntType::SignedIntLit(ref sity, ref sign) => { (if let Sign::Minus = *sign { @@ -229,7 +228,7 @@ impl fmt::Display for Constant { }; write!(fmt, "{}{}{}", sign, i, suffix) } - ConstantFloat(ref s, ref fw) => { + Constant::Float(ref s, ref fw) => { let suffix = match *fw { FloatWidth::Fw32 => "f32", FloatWidth::Fw64 => "f64", @@ -237,9 +236,9 @@ impl fmt::Display for Constant { }; write!(fmt, "{}{}", s, suffix) } - ConstantBool(ref b) => write!(fmt, "{}", b), - ConstantRepeat(ref c, ref n) => write!(fmt, "[{}; {}]", c, n), - ConstantVec(ref v) => { + Constant::Bool(ref b) => write!(fmt, "{}", b), + Constant::Repeat(ref c, ref n) => write!(fmt, "[{}; {}]", c, n), + Constant::Vec(ref v) => { write!(fmt, "[{}]", v.iter() @@ -247,7 +246,7 @@ impl fmt::Display for Constant { .collect::<Vec<_>>() .join(", ")) } - ConstantTuple(ref t) => { + Constant::Tuple(ref t) => { write!(fmt, "({})", t.iter() @@ -262,21 +261,21 @@ impl fmt::Display for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { match *lit { - LitStr(ref is, style) => ConstantStr(is.to_string(), style), - LitByte(b) => ConstantByte(b), - LitByteStr(ref s) => ConstantBinary(s.clone()), - LitChar(c) => ConstantChar(c), - LitInt(value, ty) => ConstantInt(value, ty), - LitFloat(ref is, ty) => ConstantFloat(is.to_string(), ty.into()), - LitFloatUnsuffixed(ref is) => ConstantFloat(is.to_string(), FwAny), - LitBool(b) => ConstantBool(b), + LitStr(ref is, style) => Constant::Str(is.to_string(), style), + LitByte(b) => Constant::Byte(b), + LitByteStr(ref s) => Constant::Binary(s.clone()), + LitChar(c) => Constant::Char(c), + LitInt(value, ty) => Constant::Int(value, ty), + LitFloat(ref is, ty) => Constant::Float(is.to_string(), ty.into()), + LitFloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FwAny), + LitBool(b) => Constant::Bool(b), } } fn constant_not(o: Constant) -> Option<Constant> { Some(match o { - ConstantBool(b) => ConstantBool(!b), - ConstantInt(value, ty) => { + Constant::Bool(b) => Constant::Bool(!b), + Constant::Int(value, ty) => { let (nvalue, nty) = match ty { SignedIntLit(ity, Plus) => { if value == ::std::u64::MAX { @@ -307,7 +306,7 @@ fn constant_not(o: Constant) -> Option<Constant> { return None; } // refuse to guess }; - ConstantInt(nvalue, nty) + Constant::Int(nvalue, nty) } _ => { return None; @@ -317,8 +316,8 @@ fn constant_not(o: Constant) -> Option<Constant> { fn constant_negate(o: Constant) -> Option<Constant> { Some(match o { - ConstantInt(value, ty) => { - ConstantInt(value, + Constant::Int(value, ty) => { + Constant::Int(value, match ty { SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), @@ -327,7 +326,7 @@ fn constant_negate(o: Constant) -> Option<Constant> { } }) } - ConstantFloat(is, ty) => ConstantFloat(neg_float_str(is), ty), + Constant::Float(is, ty) => Constant::Float(neg_float_str(is), ty), _ => { return None; } @@ -402,9 +401,9 @@ fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> Option<Constant> { if neg > pos { - unify_int_type(nty, pty, Minus).map(|ty| ConstantInt(neg - pos, ty)) + unify_int_type(nty, pty, Minus).map(|ty| Constant::Int(neg - pos, ty)) } else { - unify_int_type(nty, pty, Plus).map(|ty| ConstantInt(pos - neg, ty)) + unify_int_type(nty, pty, Plus).map(|ty| Constant::Int(pos - neg, ty)) } } @@ -416,7 +415,7 @@ fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> Optio } else { Plus }) - .and_then(|ty| l.checked_sub(r).map(|v| ConstantInt(v, ty))) + .and_then(|ty| l.checked_sub(r).map(|v| Constant::Int(v, ty))) } @@ -449,10 +448,10 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { 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)), - ExprVec(ref vec) => self.multi(vec).map(ConstantVec), - ExprTup(ref tup) => self.multi(tup).map(ConstantTuple), + ExprVec(ref vec) => self.multi(vec).map(Constant::Vec), + ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprRepeat(ref value, ref number) => { - self.binop_apply(value, number, |v, n| Some(ConstantRepeat(Box::new(v), n.as_u64() as usize))) + 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| { @@ -508,7 +507,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) -> Option<Constant> { - if let Some(ConstantBool(b)) = self.expr(cond) { + if let Some(Constant::Bool(b)) = self.expr(cond) { if b { self.block(then) } else { @@ -524,8 +523,8 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BiAdd => { self.binop_apply(left, right, |l, r| { match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => l8.checked_add(r8).map(ConstantByte), - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + (Constant::Byte(l8), Constant::Byte(r8)) => l8.checked_add(r8).map(Constant::Byte), + (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { let (ln, rn) = (is_negative(lty), is_negative(rty)); if ln == rn { unify_int_type(lty, @@ -535,7 +534,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } else { Plus }) - .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) } else if ln { add_neg_int(r64, rty, l64, lty) } else { @@ -550,24 +549,24 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BiSub => { self.binop_apply(left, right, |l, r| { match (l, r) { - (ConstantByte(l8), ConstantByte(r8)) => { + (Constant::Byte(l8), Constant::Byte(r8)) => { if r8 > l8 { None } else { - Some(ConstantByte(l8 - r8)) + Some(Constant::Byte(l8 - r8)) } } - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { match (is_negative(lty), is_negative(rty)) { (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), (true, false) => { unify_int_type(lty, rty, Minus) - .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) } (false, true) => { unify_int_type(lty, rty, Plus) - .and_then(|ty| l64.checked_add(r64).map(|v| ConstantInt(v, ty))) + .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) } } } @@ -585,8 +584,8 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BiBitOr => self.bitop(left, right, |x, y| (x | y)), BiShl => self.bitop(left, right, |x, y| x << y), BiShr => self.bitop(left, right, |x, y| x >> y), - BiEq => self.binop_apply(left, right, |l, r| Some(ConstantBool(l == r))), - BiNe => self.binop_apply(left, right, |l, r| Some(ConstantBool(l != r))), + BiEq => self.binop_apply(left, right, |l, r| Some(Constant::Bool(l == r))), + BiNe => self.binop_apply(left, right, |l, r| Some(Constant::Bool(l != r))), BiLt => self.cmp(left, right, Less, true), BiLe => self.cmp(left, right, Greater, false), BiGe => self.cmp(left, right, Less, false), @@ -600,7 +599,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { { self.binop_apply(left, right, |l, r| { match (l, r) { - (ConstantInt(l64, lty), ConstantInt(r64, rty)) => { + (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { f(l64, r64).and_then(|value| { unify_int_type(lty, rty, @@ -609,7 +608,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } else { Minus }) - .map(|ty| ConstantInt(value, ty)) + .map(|ty| Constant::Int(value, ty)) }) } _ => None, @@ -622,10 +621,10 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { { self.binop_apply(left, right, |l, r| { match (l, r) { - (ConstantBool(l), ConstantBool(r)) => Some(ConstantBool(f(l as u64, r as u64) != 0)), - (ConstantByte(l8), ConstantByte(r8)) => Some(ConstantByte(f(l8 as u64, r8 as u64) as u8)), - (ConstantInt(l, lty), ConstantInt(r, rty)) => { - unify_int_type(lty, rty, Plus).map(|ty| ConstantInt(f(l, r), ty)) + (Constant::Bool(l), Constant::Bool(r)) => Some(Constant::Bool(f(l as u64, r as u64) != 0)), + (Constant::Byte(l8), Constant::Byte(r8)) => Some(Constant::Byte(f(l8 as u64, r8 as u64) as u8)), + (Constant::Int(l, lty), Constant::Int(r, rty)) => { + unify_int_type(lty, rty, Plus).map(|ty| Constant::Int(f(l, r), ty)) } _ => None, } @@ -635,7 +634,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn cmp(&mut self, left: &Expr, right: &Expr, ordering: Ordering, b: bool) -> Option<Constant> { self.binop_apply(left, right, - |l, r| l.partial_cmp(&r).map(|o| ConstantBool(b == (o == ordering)))) + |l, r| l.partial_cmp(&r).map(|o| Constant::Bool(b == (o == ordering)))) } fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> @@ -650,12 +649,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn short_circuit(&mut self, left: &Expr, right: &Expr, b: bool) -> Option<Constant> { self.expr(left).and_then(|left| { - if let ConstantBool(lbool) = left { + if let Constant::Bool(lbool) = left { if lbool == b { Some(left) } else { self.expr(right).and_then(|right| { - if let ConstantBool(_) = right { + if let Constant::Bool(_) = right { Some(right) } else { None diff --git a/src/identity_op.rs b/src/identity_op.rs index fd5071d4013..5fa9c7588cd 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -2,8 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use consts::{constant_simple, is_negative}; -use consts::Constant::ConstantInt; +use consts::{constant_simple, is_negative, Constant}; use utils::{span_lint, snippet, in_macro}; /// **What it does:** This lint checks for identity operations, e.g. `x + 0`. It is `Warn` by default. @@ -54,7 +53,7 @@ impl LateLintPass for IdentityOp { fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(ConstantInt(v, ty)) = constant_simple(e) { + if let Some(Constant::Int(v, ty)) = constant_simple(e) { if match m { 0 => v == 0, -1 => is_negative(ty) && v == 1, diff --git a/src/loops.rs b/src/loops.rs index 74ff9edcb6b..1baaab6abc0 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -365,8 +365,8 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { // ...and both sides are compile-time constant integers... - if let Some(start_idx @ Constant::ConstantInt(..)) = constant_simple(start_expr) { - if let Some(stop_idx @ Constant::ConstantInt(..)) = constant_simple(stop_expr) { + if let Some(start_idx @ Constant::Int(..)) = constant_simple(start_expr) { + if let Some(stop_idx @ Constant::Int(..)) = constant_simple(stop_expr) { // ...and the start index is greater than the stop index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the diff --git a/src/methods.rs b/src/methods.rs index a5f27440f94..111f4d56424 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -19,9 +19,6 @@ use utils::{ use utils::MethodArgs; use rustc::middle::cstore::CrateStore; -use self::SelfKind::*; -use self::OutType::*; - #[derive(Clone)] pub struct MethodsPass; @@ -456,11 +453,11 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } } -fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) +fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { - ty::TySlice(_) => true, + ty::TySlice(_) => true, ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), ty::TyArray(_, size) => size < 32, ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | @@ -469,7 +466,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) } } if let ExprMethodCall(name, _, ref args) = expr.node { - if &name.node.as_str() == &"iter" && + if &name.node.as_str() == &"iter" && may_slice(cx, &cx.tcx.expr_ty(&args[0])) { Some((args[0].span, "&")) } else { @@ -479,7 +476,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) match ty.sty { ty::TySlice(_) => Some((expr.span, "")), ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => if may_slice(cx, inner) { + ty::TyBox(ref inner) => if may_slice(cx, inner) { Some((expr.span, "")) } else { None }, _ => None @@ -731,180 +728,180 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { debug_impl_exists } -const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [("into_", &[ValueSelf]), - ("to_", &[RefSelf]), - ("as_", &[RefSelf, RefMutSelf]), - ("is_", &[RefSelf, NoSelf]), - ("from_", &[NoSelf])]; +const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [("into_", &[SelfKind::Value]), + ("to_", &[SelfKind::Ref]), + ("as_", &[SelfKind::Ref, SelfKind::RefMut]), + ("is_", &[SelfKind::Ref, SelfKind::No]), + ("from_", &[SelfKind::No])]; const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [("add", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Add"), ("sub", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Sub"), ("mul", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Mul"), ("div", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Div"), ("rem", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Rem"), ("shl", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Shl"), ("shr", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Shr"), ("bitand", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::BitAnd"), ("bitor", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::BitOr"), ("bitxor", 2, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::BitXor"), ("neg", 1, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Neg"), ("not", 1, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::ops::Not"), ("drop", 1, - RefMutSelf, - UnitType, + SelfKind::RefMut, + OutType::Unit, "std::ops::Drop"), ("index", 2, - RefSelf, - RefType, + SelfKind::Ref, + OutType::Ref, "std::ops::Index"), ("index_mut", 2, - RefMutSelf, - RefType, + SelfKind::RefMut, + OutType::Ref, "std::ops::IndexMut"), ("deref", 1, - RefSelf, - RefType, + SelfKind::Ref, + OutType::Ref, "std::ops::Deref"), ("deref_mut", 1, - RefMutSelf, - RefType, + SelfKind::RefMut, + OutType::Ref, "std::ops::DerefMut"), ("clone", 1, - RefSelf, - AnyType, + SelfKind::Ref, + OutType::Any, "std::clone::Clone"), ("borrow", 1, - RefSelf, - RefType, + SelfKind::Ref, + OutType::Ref, "std::borrow::Borrow"), ("borrow_mut", 1, - RefMutSelf, - RefType, + SelfKind::RefMut, + OutType::Ref, "std::borrow::BorrowMut"), ("as_ref", 1, - RefSelf, - RefType, + SelfKind::Ref, + OutType::Ref, "std::convert::AsRef"), ("as_mut", 1, - RefMutSelf, - RefType, + SelfKind::RefMut, + OutType::Ref, "std::convert::AsMut"), ("eq", 2, - RefSelf, - BoolType, + SelfKind::Ref, + OutType::Bool, "std::cmp::PartialEq"), ("cmp", 2, - RefSelf, - AnyType, + SelfKind::Ref, + OutType::Any, "std::cmp::Ord"), ("default", 0, - NoSelf, - AnyType, + SelfKind::No, + OutType::Any, "std::default::Default"), ("hash", 2, - RefSelf, - UnitType, + SelfKind::Ref, + OutType::Unit, "std::hash::Hash"), ("next", 1, - RefMutSelf, - AnyType, + SelfKind::RefMut, + OutType::Any, "std::iter::Iterator"), ("into_iter", 1, - ValueSelf, - AnyType, + SelfKind::Value, + OutType::Any, "std::iter::IntoIterator"), ("from_iter", 1, - NoSelf, - AnyType, + SelfKind::No, + OutType::Any, "std::iter::FromIterator"), ("from_str", 1, - NoSelf, - AnyType, + SelfKind::No, + OutType::Any, "std::str::FromStr")]; #[derive(Clone, Copy)] enum SelfKind { - ValueSelf, - RefSelf, - RefMutSelf, - NoSelf, + Value, + Ref, + RefMut, + No, } impl SelfKind { fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool { match (self, slf) { - (&ValueSelf, &SelfValue(_)) => true, - (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true, - (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true, - (&RefSelf, &SelfValue(_)) => allow_value_for_ref, - (&RefMutSelf, &SelfValue(_)) => allow_value_for_ref, - (&NoSelf, &SelfStatic) => true, + (&SelfKind::Value, &SelfValue(_)) => true, + (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) => true, + (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) => true, + (&SelfKind::Ref, &SelfValue(_)) => allow_value_for_ref, + (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, + (&SelfKind::No, &SelfStatic) => true, (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), _ => false, } @@ -912,41 +909,41 @@ impl SelfKind { fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool { match (self, &ty.node) { - (&ValueSelf, &TyPath(..)) => true, - (&RefSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true, - (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, - (&RefSelf, &TyPath(..)) => allow_value_for_ref, - (&RefMutSelf, &TyPath(..)) => allow_value_for_ref, + (&SelfKind::Value, &TyPath(..)) => true, + (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true, + (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, + (&SelfKind::Ref, &TyPath(..)) => allow_value_for_ref, + (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, _ => false, } } fn description(&self) -> &'static str { match *self { - ValueSelf => "self by value", - RefSelf => "self by reference", - RefMutSelf => "self by mutable reference", - NoSelf => "no self", + SelfKind::Value => "self by value", + SelfKind::Ref => "self by reference", + SelfKind::RefMut => "self by mutable reference", + SelfKind::No => "no self", } } } #[derive(Clone, Copy)] enum OutType { - UnitType, - BoolType, - AnyType, - RefType, + Unit, + Bool, + Any, + Ref, } impl OutType { fn matches(&self, ty: &FunctionRetTy) -> bool { match (self, ty) { - (&UnitType, &DefaultReturn(_)) => true, - (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![].into()) => true, - (&BoolType, &Return(ref ty)) if is_bool(ty) => true, - (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, - (&RefType, &Return(ref ty)) => { + (&OutType::Unit, &DefaultReturn(_)) => true, + (&OutType::Unit, &Return(ref ty)) if ty.node == TyTup(vec![].into()) => true, + (&OutType::Bool, &Return(ref ty)) if is_bool(ty) => true, + (&OutType::Any, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, + (&OutType::Ref, &Return(ref ty)) => { if let TyRptr(_, _) = ty.node { true } else { diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 5a4d3931606..2c3ec86936c 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -35,8 +35,8 @@ impl LateLintPass for ZeroDivZeroPass { // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. - let Some(Constant::ConstantFloat(ref lhs_value, lhs_width)) = constant_simple(left), - let Some(Constant::ConstantFloat(ref rhs_value, rhs_width)) = constant_simple(right), + let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(left), + let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(right), let Some(0.0) = lhs_value.parse().ok(), let Some(0.0) = rhs_value.parse().ok() ], diff --git a/tests/cc_seme.rs b/tests/cc_seme.rs index a26731c396a..cc02853c70a 100644 --- a/tests/cc_seme.rs +++ b/tests/cc_seme.rs @@ -3,8 +3,8 @@ #[allow(dead_code)] enum Baz { - Baz1, - Baz2, + One, + Two, } struct Test { @@ -14,11 +14,11 @@ struct Test { fn main() { use Baz::*; - let x = Test { t: Some(0), b: Baz1 }; + let x = Test { t: Some(0), b: One }; match x { - Test { t: Some(_), b: Baz1 } => unreachable!(), - Test { t: Some(42), b: Baz2 } => unreachable!(), + Test { t: Some(_), b: One } => unreachable!(), + Test { t: Some(42), b: Two } => unreachable!(), Test { t: None, .. } => unreachable!(), Test { .. } => unreachable!(), } diff --git a/tests/compile-fail/complex_types.rs b/tests/compile-fail/complex_types.rs index 995132ba88c..ad01e4fadd5 100644 --- a/tests/compile-fail/complex_types.rs +++ b/tests/compile-fail/complex_types.rs @@ -16,8 +16,8 @@ struct S { struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type enum E { - V1(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type - V2 { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type + Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type + Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type } impl S { diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index 8da119eb16d..21118b82718 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -11,8 +11,8 @@ struct Struct { field: i32 } enum Enum { - TupleVariant(i32), - StructVariant { field: i32 }, + Tuple(i32), + Struct { field: i32 }, } fn get_number() -> i32 { 0 } @@ -26,14 +26,14 @@ fn main() { Tuple(0); //~ERROR statement with no effect Struct { field: 0 }; //~ERROR statement with no effect Struct { ..s }; //~ERROR statement with no effect - Enum::TupleVariant(0); //~ERROR statement with no effect - Enum::StructVariant { field: 0 }; //~ERROR statement with no effect + Enum::Tuple(0); //~ERROR statement with no effect + Enum::Struct { field: 0 }; //~ERROR statement with no effect // Do not warn get_number(); Tuple(get_number()); Struct { field: get_number() }; Struct { ..get_struct() }; - Enum::TupleVariant(get_number()); - Enum::StructVariant { field: get_number() }; + Enum::Tuple(get_number()); + Enum::Struct { field: get_number() }; } diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 39a33c96876..281d92c46df 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -50,17 +50,17 @@ fn multiple_underscores(__foo: u32) -> u32 { fn _fn_test() {} struct _StructTest; enum _EnumTest { - _FieldA, - _FieldB(_StructTest) + _Empty, + _Value(_StructTest) } /// Test that we do not lint for non-variable bindings fn non_variables() { _fn_test(); let _s = _StructTest; - let _e = match _EnumTest::_FieldB(_StructTest) { - _EnumTest::_FieldA => 0, - _EnumTest::_FieldB(_st) => 1, + let _e = match _EnumTest::_Value(_StructTest) { + _EnumTest::_Empty => 0, + _EnumTest::_Value(_st) => 1, }; let f = _fn_test; f(); diff --git a/tests/consts.rs b/tests/consts.rs index 5ddcd6df7b8..75082e646a0 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -18,7 +18,6 @@ use syntax::ast::StrStyle::*; use syntax::ast::Sign::*; use clippy::consts::{constant_simple, Constant}; -use clippy::consts::Constant::*; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } @@ -45,18 +44,18 @@ fn check(expect: Constant, expr: &Expr) { assert_eq!(Some(expect), constant_simple(expr)) } -const TRUE : Constant = ConstantBool(true); -const FALSE : Constant = ConstantBool(false); -const ZERO : Constant = ConstantInt(0, UnsuffixedIntLit(Plus)); -const ONE : Constant = ConstantInt(1, UnsuffixedIntLit(Plus)); -const TWO : Constant = ConstantInt(2, UnsuffixedIntLit(Plus)); +const TRUE : Constant = Constant::Bool(true); +const FALSE : Constant = Constant::Bool(false); +const ZERO : Constant = Constant::Int(0, UnsuffixedIntLit(Plus)); +const ONE : Constant = Constant::Int(1, UnsuffixedIntLit(Plus)); +const TWO : Constant = Constant::Int(2, UnsuffixedIntLit(Plus)); #[test] fn test_lit() { check(TRUE, &lit(LitBool(true))); check(FALSE, &lit(LitBool(false))); check(ZERO, &lit(LitInt(0, UnsuffixedIntLit(Plus)))); - check(ConstantStr("cool!".into(), CookedStr), &lit(LitStr( + check(Constant::Str("cool!".into(), CookedStr), &lit(LitStr( InternedString::new("cool!"), CookedStr))); } -- cgit 1.4.1-3-g733a5 From 3a31576d76f5cab4554da5b511f4a065bf5f92b5 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 1 Feb 2016 20:37:07 +0100 Subject: fixed #606 --- src/escape.rs | 8 ++++---- tests/compile-fail/escape_analysis.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index edc7b5c6fbb..68dd2307e3f 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -31,9 +31,9 @@ pub struct EscapePass; /// ``` declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); -fn is_box(ty: ty::Ty) -> bool { +fn is_non_trait_box(ty: ty::Ty) -> bool { match ty.sty { - ty::TyBox(..) => true, + ty::TyBox(ref inner) => !inner.is_trait(), _ => false } } @@ -90,7 +90,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) { return; } - if is_box(cmt.ty) { + if is_non_trait_box(cmt.ty) { self.set.insert(consume_pat.id); } return; @@ -101,7 +101,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if let DeclLocal(ref loc) = decl.node { if let Some(ref ex) = loc.init { if let ExprBox(..) = ex.node { - if is_box(cmt.ty) { + if is_non_trait_box(cmt.ty) { // let x = box (...) self.set.insert(consume_pat.id); } diff --git a/tests/compile-fail/escape_analysis.rs b/tests/compile-fail/escape_analysis.rs index f3aa8bff41c..c0893bcd767 100644 --- a/tests/compile-fail/escape_analysis.rs +++ b/tests/compile-fail/escape_analysis.rs @@ -11,9 +11,24 @@ impl A { fn foo(&self){} } +trait Z { + fn bar(&self); +} + +impl Z for A { + fn bar(&self) { + //nothing + } +} + fn main() { } +fn ok_box_trait(boxed_trait: &Box<Z>) { + let boxed_local = boxed_trait; + // done +} + fn warn_call() { let x = box A; //~ ERROR local variable x.foo(); -- cgit 1.4.1-3-g733a5 From bd86922c4f33e2528bb87a7f693e57935970f1cf Mon Sep 17 00:00:00 2001 From: inrustwetrust <inrustwetrust@users.noreply.github.com> Date: Mon, 1 Feb 2016 19:53:03 +0100 Subject: Add lint to warn for calls to `std::mem::drop` with a reference argument --- README.md | 3 ++- src/drop_ref.rs | 61 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ src/utils.rs | 1 + tests/compile-fail/drop_ref.rs | 43 +++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/drop_ref.rs create mode 100644 tests/compile-fail/drop_ref.rs (limited to 'src') diff --git a/README.md b/README.md index 9b249636c66..d24dc3de1bd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 106 lints included in this crate: +There are 107 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -28,6 +28,7 @@ name [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [derive_hash_not_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_not_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly +[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix diff --git a/src/drop_ref.rs b/src/drop_ref.rs new file mode 100644 index 00000000000..fecb69f5c14 --- /dev/null +++ b/src/drop_ref.rs @@ -0,0 +1,61 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use rustc::middle::ty; +use syntax::codemap::Span; + +use utils::DROP_PATH; +use utils::{match_def_path, span_note_and_lint}; + +/// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value. +/// +/// **Why is this bad?** Calling `drop` on a reference will only drop the reference itself, which is a no-op. It will not call the `drop` method (from the `Drop` trait implementation) on the underlying referenced value, which is likely what was intended. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// let mut lock_guard = mutex.lock(); +/// std::mem::drop(&lock_guard) //Should have been drop(lock_guard), mutex still locked +/// operation_that_requires_mutex_to_be_unlocked(); +/// ``` +declare_lint!(pub DROP_REF, Warn, + "call to `std::mem::drop` with a reference instead of an owned value, \ + which will not not call the `Drop::drop` method on the underlying value"); + +#[allow(missing_copy_implementations)] +pub struct DropRefPass; + +impl LintPass for DropRefPass { + fn get_lints(&self) -> LintArray { + lint_array!(DROP_REF) + } +} + +impl LateLintPass for DropRefPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprCall(ref path, ref args) = expr.node { + if let ExprPath(None, _) = path.node { + let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); + if match_def_path(cx, def_id, &DROP_PATH) { + if args.len() != 1 { + return; + } + check_drop_arg(cx, expr.span, &*args[0]); + } + } + } + } +} + +fn check_drop_arg(cx: &LateContext, call_span: Span, arg: &Expr) { + let arg_ty = cx.tcx.expr_ty(arg); + if let ty::TyRef(..) = arg_ty.sty { + span_note_and_lint(cx, + DROP_REF, + call_span, + "call to `std::mem::drop` with a reference argument. \ + Dropping a reference does nothing", + arg.span, + &format!("argument has type {}", arg_ty.sty)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 15d1db19d97..e2596dd58ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,6 +81,7 @@ pub mod panic; pub mod derive; pub mod print; pub mod vec; +pub mod drop_ref; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -148,6 +149,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); + reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_lint_group("clippy_pedantic", vec![ @@ -184,6 +186,7 @@ pub fn plugin_registrar(reg: &mut Registry) { cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_NOT_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, + drop_ref::DROP_REF, entry::MAP_ENTRY, enum_variants::ENUM_VARIANT_NAMES, eq_op::EQ_OP, diff --git a/src/utils.rs b/src/utils.rs index ff0c59ab290..bc6fcd44891 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,6 +27,7 @@ pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; +pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; diff --git a/tests/compile-fail/drop_ref.rs b/tests/compile-fail/drop_ref.rs new file mode 100644 index 00000000000..3e4c0a9d8ec --- /dev/null +++ b/tests/compile-fail/drop_ref.rs @@ -0,0 +1,43 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(drop_ref)] +#![allow(toplevel_ref_arg)] + +use std::mem::drop; + +struct DroppableStruct; +impl Drop for DroppableStruct { fn drop(&mut self) {} } + +fn main() { + drop(&DroppableStruct); //~ERROR call to `std::mem::drop` with a reference argument + + let mut owned = DroppableStruct; + drop(&owned); //~ERROR call to `std::mem::drop` with a reference argument + drop(&&owned); //~ERROR call to `std::mem::drop` with a reference argument + drop(&mut owned); //~ERROR call to `std::mem::drop` with a reference argument + drop(owned); //OK + + let reference1 = &DroppableStruct; + drop(reference1); //~ERROR call to `std::mem::drop` with a reference argument + drop(&*reference1); //~ERROR call to `std::mem::drop` with a reference argument + + let reference2 = &mut DroppableStruct; + drop(reference2); //~ERROR call to `std::mem::drop` with a reference argument + + let ref reference3 = DroppableStruct; + drop(reference3); //~ERROR call to `std::mem::drop` with a reference argument +} + +#[allow(dead_code)] +fn test_generic_fn<T>(val: T) { + drop(&val); //~ERROR call to `std::mem::drop` with a reference argument + drop(val); //OK +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn drop<T>(_val: T) {} + drop(&DroppableStruct); //OK; call to unrelated function which happens to have the same name + std::mem::drop(&DroppableStruct); //~ERROR call to `std::mem::drop` with a reference argument +} -- cgit 1.4.1-3-g733a5 From d93eca29fc5ca6bf127405f156c3bbf7b69611d2 Mon Sep 17 00:00:00 2001 From: inrustwetrust <inrustwetrust@users.noreply.github.com> Date: Tue, 2 Feb 2016 20:38:14 +0100 Subject: Fix typo in drop_ref lint description. --- README.md | 2 +- src/drop_ref.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index d24dc3de1bd..0c5b12df8ae 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ name [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [derive_hash_not_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_not_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly -[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not not call the `Drop::drop` method on the underlying value +[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected [enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix diff --git a/src/drop_ref.rs b/src/drop_ref.rs index fecb69f5c14..c15689d8cd6 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -20,7 +20,7 @@ use utils::{match_def_path, span_note_and_lint}; /// ``` declare_lint!(pub DROP_REF, Warn, "call to `std::mem::drop` with a reference instead of an owned value, \ - which will not not call the `Drop::drop` method on the underlying value"); + which will not call the `Drop::drop` method on the underlying value"); #[allow(missing_copy_implementations)] pub struct DropRefPass; -- cgit 1.4.1-3-g733a5 From 0c726e8077f9effe36dfa1358f87e71c941961f0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 13:39:16 +0100 Subject: Restore some of rustfmt madness --- src/methods.rs | 198 ++++++++++++--------------------------------------------- 1 file changed, 42 insertions(+), 156 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 111f4d56424..dfa9a90d9cf 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -728,162 +728,48 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { debug_impl_exists } -const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [("into_", &[SelfKind::Value]), - ("to_", &[SelfKind::Ref]), - ("as_", &[SelfKind::Ref, SelfKind::RefMut]), - ("is_", &[SelfKind::Ref, SelfKind::No]), - ("from_", &[SelfKind::No])]; - -const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [("add", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Add"), - ("sub", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Sub"), - ("mul", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Mul"), - ("div", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Div"), - ("rem", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Rem"), - ("shl", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Shl"), - ("shr", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::Shr"), - ("bitand", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::BitAnd"), - ("bitor", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::BitOr"), - ("bitxor", - 2, - SelfKind::Value, - OutType::Any, - "std::ops::BitXor"), - ("neg", - 1, - SelfKind::Value, - OutType::Any, - "std::ops::Neg"), - ("not", - 1, - SelfKind::Value, - OutType::Any, - "std::ops::Not"), - ("drop", - 1, - SelfKind::RefMut, - OutType::Unit, - "std::ops::Drop"), - ("index", - 2, - SelfKind::Ref, - OutType::Ref, - "std::ops::Index"), - ("index_mut", - 2, - SelfKind::RefMut, - OutType::Ref, - "std::ops::IndexMut"), - ("deref", - 1, - SelfKind::Ref, - OutType::Ref, - "std::ops::Deref"), - ("deref_mut", - 1, - SelfKind::RefMut, - OutType::Ref, - "std::ops::DerefMut"), - ("clone", - 1, - SelfKind::Ref, - OutType::Any, - "std::clone::Clone"), - ("borrow", - 1, - SelfKind::Ref, - OutType::Ref, - "std::borrow::Borrow"), - ("borrow_mut", - 1, - SelfKind::RefMut, - OutType::Ref, - "std::borrow::BorrowMut"), - ("as_ref", - 1, - SelfKind::Ref, - OutType::Ref, - "std::convert::AsRef"), - ("as_mut", - 1, - SelfKind::RefMut, - OutType::Ref, - "std::convert::AsMut"), - ("eq", - 2, - SelfKind::Ref, - OutType::Bool, - "std::cmp::PartialEq"), - ("cmp", - 2, - SelfKind::Ref, - OutType::Any, - "std::cmp::Ord"), - ("default", - 0, - SelfKind::No, - OutType::Any, - "std::default::Default"), - ("hash", - 2, - SelfKind::Ref, - OutType::Unit, - "std::hash::Hash"), - ("next", - 1, - SelfKind::RefMut, - OutType::Any, - "std::iter::Iterator"), - ("into_iter", - 1, - SelfKind::Value, - OutType::Any, - "std::iter::IntoIterator"), - ("from_iter", - 1, - SelfKind::No, - OutType::Any, - "std::iter::FromIterator"), - ("from_str", - 1, - SelfKind::No, - OutType::Any, - "std::str::FromStr")]; +#[rustfmt_skip] +const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ + ("into_", &[SelfKind::Value]), + ("to_", &[SelfKind::Ref]), + ("as_", &[SelfKind::Ref, SelfKind::RefMut]), + ("is_", &[SelfKind::Ref, SelfKind::No]), + ("from_", &[SelfKind::No]), +]; + +#[rustfmt_skip] +const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ + ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"), + ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), + ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"), + ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"), + ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"), + ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"), + ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"), + ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), + ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"), + ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"), + ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"), + ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"), + ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), + ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"), + ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), + ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), + ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), + ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"), + ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), + ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), + ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), + ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), + ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), + ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), + ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"), + ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), + ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), + ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), + ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"), + ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"), +]; #[derive(Clone, Copy)] enum SelfKind { -- cgit 1.4.1-3-g733a5 From c0d2fdc723bff9e271e00da4d24c125b1e19762a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 13:48:39 +0100 Subject: Partially apply rustfmt --- src/attrs.rs | 6 +++--- src/bit_mask.rs | 1 - src/derive.rs | 19 ++++++++----------- src/escape.rs | 2 +- src/items_after_statements.rs | 6 ++++-- src/lifetimes.rs | 29 ++++++++++++++-------------- src/loops.rs | 9 +++------ src/matches.rs | 34 +++++++++++++++++---------------- src/methods.rs | 44 +++++++++++++++++++++++++------------------ src/print.rs | 5 +---- src/shadow.rs | 8 ++++---- src/utils.rs | 14 +++++++++----- 12 files changed, 92 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 853e2ab5910..012c4e502b4 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -60,10 +60,10 @@ impl LateLintPass for AttrPass { check_semver(cx, item.span, lit); } } - } + } } } - + fn check_item(&mut self, cx: &LateContext, item: &Item) { if is_relevant_item(item) { check_attrs(cx, item.span, &item.name, &item.attrs) @@ -164,7 +164,7 @@ fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { return; } } - span_lint(cx, + span_lint(cx, DEPRECATED_SEMVER, span, "the since field must contain a semver-compliant version"); diff --git a/src/bit_mask.rs b/src/bit_mask.rs index b0d3c3d3f78..0fce772010a 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -151,7 +151,6 @@ 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 { diff --git a/src/derive.rs b/src/derive.rs index ca7649f75b3..d8f331ef5ff 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -158,15 +158,13 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: _ => (), } - span_lint_and_then( - cx, DERIVE_HASH_NOT_EQ, span, - "you are implementing `Clone` explicitly on a `Copy` type", - |db| { - db.span_note( - span, - "consider deriving `Clone` or removing `Copy`" - ); - }); + span_lint_and_then(cx, + DERIVE_HASH_NOT_EQ, + span, + "you are implementing `Clone` explicitly on a `Copy` type", + |db| { + db.span_note(span, "consider deriving `Clone` or removing `Copy`"); + }); } } @@ -174,8 +172,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: fn is_automatically_derived(attr: &Attribute) -> bool { if let MetaItem_::MetaWord(ref word) = attr.node.value.node { word == &"automatically_derived" - } - else { + } else { false } } diff --git a/src/escape.rs b/src/escape.rs index 68dd2307e3f..bd6687e3f0d 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -34,7 +34,7 @@ declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); fn is_non_trait_box(ty: ty::Ty) -> bool { match ty.sty { ty::TyBox(ref inner) => !inner.is_trait(), - _ => false + _ => false, } } diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 8eb3364b2bd..ad666a3bf3f 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -56,8 +56,10 @@ impl EarlyLintPass for ItemsAfterStatemets { if in_macro(cx, it.span) { return; } - cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, it.span, - "adding items after statements is confusing, since items exist from the start of the scope") + cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, + it.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope") .emit(); } } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 1441015eb0e..b6f8ebe5fd8 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -68,9 +68,13 @@ enum RefLt { fn bound_lifetimes(bound: &TyParamBound) -> Option<HirVec<&Lifetime>> { if let TraitTyParamBound(ref trait_ref, _) = *bound { - let lt = trait_ref.trait_ref.path.segments - .last().expect("a path must have at least one segment") - .parameters.lifetimes(); + let lt = trait_ref.trait_ref + .path + .segments + .last() + .expect("a path must have at least one segment") + .parameters + .lifetimes(); Some(lt) } else { @@ -83,10 +87,9 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g return; } - let bounds_lts = - generics.ty_params - .iter() - .flat_map(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); + let bounds_lts = generics.ty_params + .iter() + .flat_map(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); if could_use_elision(cx, decl, slf, &generics.lifetimes, bounds_lts) { span_lint(cx, @@ -97,10 +100,9 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g report_extra_lifetimes(cx, decl, &generics, slf); } -fn could_use_elision<'a, T: Iterator<Item=&'a Lifetime>>( - cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, - named_lts: &[LifetimeDef], bounds_lts: T -) -> bool { +fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, + named_lts: &[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 @@ -185,7 +187,7 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { allowed_lts } -fn lts_from_bounds<'a, T: Iterator<Item=&'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> { +fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> { for lt in bounds_lts { if lt.name.as_str() != "'static" { vec.push(RefLt::Named(lt.name)); @@ -332,8 +334,7 @@ impl<'v> Visitor<'v> for LifetimeChecker { } } -fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, - generics: &Generics, slf: Option<&ExplicitSelf>) { +fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics, slf: Option<&ExplicitSelf>) { let hs = generics.lifetimes .iter() .map(|lt| (lt.lifetime.name, lt.lifetime.span)) diff --git a/src/loops.rs b/src/loops.rs index 1baaab6abc0..20c75e08d23 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -296,16 +296,14 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex let skip: Cow<_> = if starts_at_zero { "".into() - } - else { + } else { format!(".skip({})", snippet(cx, l.span, "..")).into() }; let take: Cow<_> = if let Some(ref r) = *r { if !is_len_call(&r, &indexed) { format!(".take({})", snippet(cx, r.span, "..")).into() - } - else { + } else { "".into() } } else { @@ -327,8 +325,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex } else { let repl = if starts_at_zero && take.is_empty() { format!("&{}", indexed) - } - else { + } else { format!("{}.iter(){}{}", indexed, take, skip) }; diff --git a/src/matches.rs b/src/matches.rs index c866a48d223..e690f04bdb0 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -192,7 +192,7 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: }, PatEnum(ref path, None) => path.to_string(), PatIdent(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), - _ => return + _ => return, }; for &(ty_path, pat_path) in candidates { @@ -206,15 +206,17 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: span_lint_and_then(cx, lint, expr.span, - "you seem to be trying to use match for destructuring a single pattern. \ - Consider using `if let`", |db| { - db.span_suggestion(expr.span, "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + "you seem to be trying to use match for destructuring a single pattern. Consider \ + using `if let`", + |db| { + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); } } } @@ -267,12 +269,12 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { span_lint_and_then(cx, MATCH_BOOL, expr.span, - "you seem to be trying to match on a boolean expression. Consider using \ - an if..else block:", move |db| { - if let Some(sugg) = sugg { - db.span_suggestion(expr.span, "try this", sugg); - } - }); + "you seem to be trying to match on a boolean expression. Consider using an if..else block:", + move |db| { + if let Some(sugg) = sugg { + db.span_suggestion(expr.span, "try this", sugg); + } + }); } } diff --git a/src/methods.rs b/src/methods.rs index dfa9a90d9cf..d40ab250a7f 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -349,16 +349,18 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) if name == "unwrap_or" { if let ExprPath(_, ref path) = fun.node { - let path : &str = &path.segments.last() - .expect("A path must have at least one segment") - .identifier.name.as_str(); + let path: &str = &path.segments + .last() + .expect("A path must have at least one segment") + .identifier + .name + .as_str(); if ["default", "new"].contains(&path) { let arg_ty = cx.tcx.expr_ty(arg); let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { default_trait_id - } - else { + } else { return false; }; @@ -408,7 +410,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) }; if !poss.contains(&name) { - return + return; } let sugg = match (fn_has_arguments, !or_has_args) { @@ -444,17 +446,20 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } let arg_ty = cx.tcx.expr_ty(&args[1]); if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { - span_lint(cx, EXTEND_FROM_SLICE, expr.span, + span_lint(cx, + EXTEND_FROM_SLICE, + expr.span, &format!("use of `extend` to extend a Vec by a slice")) - .span_suggestion(expr.span, "try this", + .span_suggestion(expr.span, + "try this", format!("{}.extend_from_slice({}{})", snippet(cx, args[0].span, "_"), - r, snippet(cx, span, "_"))); + r, + snippet(cx, span, "_"))); } } -fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) - -> Option<(Span, &'static str)> { +fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { ty::TySlice(_) => true, @@ -462,12 +467,11 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) ty::TyArray(_, size) => size < 32, ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | ty::TyBox(ref inner) => may_slice(cx, inner), - _ => false + _ => false, } } if let ExprMethodCall(name, _, ref args) = expr.node { - if &name.node.as_str() == &"iter" && - may_slice(cx, &cx.tcx.expr_ty(&args[0])) { + if &name.node.as_str() == &"iter" && may_slice(cx, &cx.tcx.expr_ty(&args[0])) { Some((args[0].span, "&")) } else { None @@ -476,10 +480,14 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) match ty.sty { ty::TySlice(_) => Some((expr.span, "")), ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => if may_slice(cx, inner) { - Some((expr.span, "")) - } else { None }, - _ => None + ty::TyBox(ref inner) => { + if may_slice(cx, inner) { + Some((expr.span, "")) + } else { + None + } + } + _ => None, } } } diff --git a/src/print.rs b/src/print.rs index a47fa69b2e8..930952bdbaf 100644 --- a/src/print.rs +++ b/src/print.rs @@ -37,10 +37,7 @@ impl LateLintPass for PrintLint { None => (span, "print"), }; - span_lint(cx, - PRINT_STDOUT, - span, - &format!("use of `{}!`", name)); + span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); } } } diff --git a/src/shadow.rs b/src/shadow.rs index 5bd392abb3c..1beb00e9056 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -211,8 +211,8 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & &format!("{} is shadowed by {} which reuses the original value", snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); + expr.span, + "initialization happens here"); note_orig(cx, db, SHADOW_REUSE, prev_span); } else { let db = span_note_and_lint(cx, @@ -221,8 +221,8 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & &format!("{} is shadowed by {}", snippet(cx, lspan, "_"), snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); + expr.span, + "initialization happens here"); note_orig(cx, db, SHADOW_UNRELATED, prev_span); } diff --git a/src/utils.rs b/src/utils.rs index bc6fcd44891..78fb45cd6cf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -209,7 +209,7 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { loop { let segment = match path_it.next() { Some(segment) => segment, - None => return None + None => return None, }; for item in &mem::replace(&mut items, vec![]) { @@ -229,8 +229,7 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { } } } - } - else { + } else { None } } @@ -250,13 +249,17 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { /// 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: Option<Vec<ty::Ty<'tcx>>>) -> bool { +pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, + ty_params: Option<Vec<ty::Ty<'tcx>>>) + -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); let obligation = traits::predicate_for_trait_def(cx.tcx, traits::ObligationCause::dummy(), - trait_id, 0, ty, + trait_id, + 0, + ty, ty_params.unwrap_or_default()); traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) @@ -658,6 +661,7 @@ pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> (ei.callee.name(), ei.call_site) }) }); + match span_name_span { Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), None => return None, -- cgit 1.4.1-3-g733a5 From 47e26ab287447c7321214f6b9451a5238d47e9cb Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 14:01:26 +0100 Subject: Fix warnings about the rustfmt_skip attribute --- src/lib.rs | 3 +-- src/methods.rs | 4 ++-- src/misc.rs | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index e2596dd58ca..e7302ea5829 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,9 +87,8 @@ mod reexport { pub use syntax::ast::{Name, NodeId}; } -#[allow(unused_attributes)] #[plugin_registrar] -#[rustfmt_skip] +#[cfg_attr(rustfmt, rustfmt_skip)] pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::TypePass); reg.register_late_lint_pass(box misc::TopLevelRefPass); diff --git a/src/methods.rs b/src/methods.rs index d40ab250a7f..5768a6e8f85 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -736,7 +736,7 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { debug_impl_exists } -#[rustfmt_skip] +#[cfg_attr(rustfmt, rustfmt_skip)] const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ("into_", &[SelfKind::Value]), ("to_", &[SelfKind::Ref]), @@ -745,7 +745,7 @@ const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ ("from_", &[SelfKind::No]), ]; -#[rustfmt_skip] +#[cfg_attr(rustfmt, rustfmt_skip)] const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"), ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), diff --git a/src/misc.rs b/src/misc.rs index 4b6170cf164..d436d98c981 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -376,8 +376,7 @@ impl LintPass for UsedUnderscoreBinding { } impl LateLintPass for UsedUnderscoreBinding { - #[allow(unused_attributes)] - #[rustfmt_skip] + #[cfg_attr(rustfmt, rustfmt_skip)] fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_attributes_expansion(cx, expr) { // Don't lint things expanded by #[derive(...)], etc -- cgit 1.4.1-3-g733a5 From db205c82a4125446d47296c3d3463c81efb0dd3d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 2 Feb 2016 22:35:01 +0100 Subject: Add a lint about using `clone` on `Copy` types --- README.md | 3 ++- src/lib.rs | 1 + src/loops.rs | 2 +- src/methods.rs | 36 +++++++++++++++++++++++++++++++----- src/misc_early.rs | 2 +- tests/compile-fail/map_clone.rs | 2 +- tests/compile-fail/methods.rs | 15 +++++++++++++-- 7 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 0c5b12df8ae..d7086a6dac8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 107 lints included in this crate: +There are 108 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -22,6 +22,7 @@ name [cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` [char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | Casting a character literal to u8 [chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char +[clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to `else if` diff --git a/src/lib.rs b/src/lib.rs index e7302ea5829..36954284184 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -214,6 +214,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::CHARS_NEXT_CMP, + methods::CLONE_ON_COPY, methods::EXTEND_FROM_SLICE, methods::FILTER_NEXT, methods::OK_EXPECT, diff --git a/src/loops.rs b/src/loops.rs index 20c75e08d23..49e073aacd0 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -475,7 +475,7 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, - var_id: id.clone(), + var_id: *id, state: VarState::IncrOnce, name: None, depth: 0, diff --git a/src/methods.rs b/src/methods.rs index 5768a6e8f85..0584d39330d 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -219,6 +219,17 @@ declare_lint!(pub OR_FUN_CALL, Warn, declare_lint!(pub EXTEND_FROM_SLICE, Warn, "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"); +/// **What it does:** This lint warns on using `.clone()` on a `Copy` type. +/// +/// **Why is this bad?** The only reason `Copy` types implement `Clone` is for generics, not for +/// using the `clone` method on a concrete type. +/// +/// **Known problems:** None. +/// +/// **Example:** `42u64.clone()` +declare_lint!(pub CLONE_ON_COPY, Warn, + "using `clone` on a `Copy` type"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(EXTEND_FROM_SLICE, @@ -233,7 +244,8 @@ impl LintPass for MethodsPass { OPTION_MAP_UNWRAP_OR, OPTION_MAP_UNWRAP_OR_ELSE, OR_FUN_CALL, - CHARS_NEXT_CMP) + CHARS_NEXT_CMP, + CLONE_ON_COPY) } } @@ -269,6 +281,7 @@ impl LateLintPass for MethodsPass { } lint_or_fun_call(cx, expr, &name.node.as_str(), &args); + lint_clone_on_copy(cx, expr, &name.node.as_str(), &args); } ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { if !lint_chars_next(cx, expr, lhs, rhs, op.node == BiEq) { @@ -439,6 +452,19 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } } +/// Checks for the `CLONE_ON_COPY` lint. +fn lint_clone_on_copy(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { + if args.len() == 1 && name == "clone" { + let ty = cx.tcx.expr_ty(expr); + let parent = cx.tcx.map.get_parent(expr.id); + let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); + + if !ty.moves_by_default(¶meter_environment, expr.span) { + span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); + } + } +} + fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); if !match_type(cx, obj_ty, &VEC_PATH) { @@ -701,7 +727,7 @@ fn lint_chars_next(cx: &LateContext, expr: &Expr, chain: &Expr, other: &Expr, eq false } -// Given a `Result<T, E>` type, return its error type (`E`) +/// Given a `Result<T, E>` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { return None; @@ -714,9 +740,9 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { None } -// This checks whether a given type is known to implement Debug. It's -// conservative, i.e. it should not return false positives, but will return -// false negatives. +/// This checks whether a given type is known to implement Debug. It's +/// conservative, i.e. it should not return false positives, but will return +/// false negatives. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { let no_ref_ty = walk_ptrs_ty(ty); let debug = match cx.tcx.lang_items.debug_trait() { diff --git a/src/misc_early.rs b/src/misc_early.rs index a90c901df8f..1573aff2a4d 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -110,7 +110,7 @@ impl EarlyLintPass for MiscEarly { arg_name[1..].to_owned())); } } else { - registered_names.insert(arg_name, arg.pat.span.clone()); + registered_names.insert(arg_name, arg.pat.span); } } } diff --git a/tests/compile-fail/map_clone.rs b/tests/compile-fail/map_clone.rs index 2e60300afda..bd630211f19 100644 --- a/tests/compile-fail/map_clone.rs +++ b/tests/compile-fail/map_clone.rs @@ -3,7 +3,7 @@ #![plugin(clippy)] #![deny(map_clone)] -#![allow(unused)] +#![allow(clone_on_copy, unused)] use std::ops::Deref; diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index c72e602ac2b..f998a83e831 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -312,14 +312,25 @@ fn use_extend_from_slice() { //~^ERROR use of `extend` //~| HELP try this //~| SUGGESTION v.extend_from_slice(&vec!["Some", "more"]); - + v.extend(vec!["And", "even", "more"].iter()); //~ERROR use of `extend` let o : Option<&'static str> = None; v.extend(o); v.extend(Some("Bye")); v.extend(vec!["Not", "like", "this"]); - v.extend(["But", "this"].iter()); + v.extend(["But", "this"].iter()); //~^ERROR use of `extend //~| HELP try this //~| SUGGESTION v.extend_from_slice(&["But", "this"]); } + +fn clone_on_copy() { + 42.clone(); //~ERROR using `clone` on a `Copy` type + vec![1].clone(); // ok, not a Copy type + Some(vec![1]).clone(); // ok, not a Copy type +} + +fn clone_on_copy_generic<T: Copy>(t: T) { + t.clone(); //~ERROR using `clone` on a `Copy` type + Some(t).clone(); //~ERROR using `clone` on a `Copy` type +} -- cgit 1.4.1-3-g733a5 From 908fb143ef06cc50f759ef38053a41d190dc73d5 Mon Sep 17 00:00:00 2001 From: scurest <scurest@users.noreply.github.com> Date: Tue, 2 Feb 2016 21:48:52 -0600 Subject: Extend ABSURD_UNSIGNED_COMPARISONS to handle more types --- README.md | 2 +- src/lib.rs | 4 +- src/types.rs | 165 ++++++++++++++++++---- tests/compile-fail/absurd-extreme-comparisons.rs | 44 ++++++ tests/compile-fail/absurd_unsigned_comparisons.rs | 14 -- 5 files changed, 183 insertions(+), 46 deletions(-) create mode 100644 tests/compile-fail/absurd-extreme-comparisons.rs delete mode 100644 tests/compile-fail/absurd_unsigned_comparisons.rs (limited to 'src') diff --git a/README.md b/README.md index 006ddcd7a7f..75d3279f9c7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ There are 109 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[absurd_unsigned_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_unsigned_comparisons) | warn | testing whether an unsigned integer is non-positive +[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` diff --git a/src/lib.rs b/src/lib.rs index 44dd9fa8c86..ec609bfe206 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); reg.register_late_lint_pass(box drop_ref::DropRefPass); - reg.register_late_lint_pass(box types::AbsurdUnsignedComparisons); + reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); reg.register_lint_group("clippy_pedantic", vec![ @@ -255,7 +255,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_LIT_AS_BYTES, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, - types::ABSURD_UNSIGNED_COMPARISONS, + types::ABSURD_EXTREME_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, types::LET_UNIT_VALUE, diff --git a/src/types.rs b/src/types.rs index 0ab373bfa35..fb9b05da612 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,6 +5,7 @@ use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; +use rustc::middle::const_eval; use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; use syntax::ast::FloatTy::*; @@ -558,52 +559,158 @@ impl LateLintPass for CharLitAsU8 { } } -/// **What it does:** This lint checks for expressions where an unsigned integer is tested to be non-positive and suggests testing for equality with zero instead. +/// **What it does:** This lint checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked. /// -/// **Why is this bad?** `x <= 0` may mislead the reader into thinking `x` can be negative. `x == 0` makes explicit that zero is the only possibility. +/// **Why is this bad?** An expression like `min <= x` may misleadingly imply that is is possible for `x` to be less than the minimum. Expressions like `max < x` are probably mistakes. /// /// **Known problems:** None /// -/// **Example:** `vec.len() <= 0` -declare_lint!(pub ABSURD_UNSIGNED_COMPARISONS, Warn, - "testing whether an unsigned integer is non-positive"); +/// **Example:** `vec.len() <= 0`, `100 > std::i32::MAX` +declare_lint!(pub ABSURD_EXTREME_COMPARISONS, Warn, + "a comparison involving a maximum or minimum value involves a case that is always \ + true or always false"); -pub struct AbsurdUnsignedComparisons; +pub struct AbsurdExtremeComparisons; -impl LintPass for AbsurdUnsignedComparisons { +impl LintPass for AbsurdExtremeComparisons { fn get_lints(&self) -> LintArray { - lint_array!(ABSURD_UNSIGNED_COMPARISONS) + lint_array!(ABSURD_EXTREME_COMPARISONS) } } -fn is_zero_lit(expr: &Expr) -> bool { - use syntax::ast::Lit_; +enum ExtremeType { + Minimum, + Maximum, +} + +struct ExtremeExpr<'a> { + which: ExtremeType, + expr: &'a Expr, +} + +enum AbsurdComparisonResult { + AlwaysFalse, + AlwaysTrue, + InequalityImpossible, +} + +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::*; + type Extr<'a> = ExtremeExpr<'a>; + + // Put the expression in the form lhs < rhs or lhs <= rhs. + enum Rel { Lt, Le }; + let (rel, lhs2, rhs2) = match op { + BiLt => (Rel::Lt, lhs, rhs), + BiLe => (Rel::Le, lhs, rhs), + BiGt => (Rel::Lt, rhs, lhs), + BiGe => (Rel::Le, rhs, lhs), + _ => return None, + }; + + let lx = detect_extreme_expr(cx, lhs2); + let rx = detect_extreme_expr(cx, rhs2); - if let ExprLit(ref l) = expr.node { - if let Lit_::LitInt(val, _) = l.node { - return val == 0; + 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 + _ => return None, + } } - } - false + 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 + _ => return None, + } + } + }) } -impl LateLintPass for AbsurdUnsignedComparisons { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { - let op = cmp.node; +fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> { + use rustc::middle::const_eval::EvalHint::ExprTypeChecked; + use types::ExtremeType::*; + use rustc::middle::const_eval::ConstVal::*; - let comparee = match op { - BiLe if is_zero_lit(rhs) => lhs, // x <= 0 - BiGe if is_zero_lit(lhs) => rhs, // 0 >= x - _ => return, - }; + let ty = &cx.tcx.expr_ty(expr).sty; - if let ty::TyUint(_) = cx.tcx.expr_ty(comparee).sty { + match *ty { + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (), + _ => return None, + }; + + let cv = match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + Ok(val) => val, + Err(_) => return None, + }; + + let which = match (ty, cv) { + (&ty::TyBool, Bool(false)) => Minimum, + + (&ty::TyInt(TyIs), Int(x)) if x == ::std::isize::MIN as i64 => Minimum, + (&ty::TyInt(TyI8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum, + (&ty::TyInt(TyI16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum, + (&ty::TyInt(TyI32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum, + (&ty::TyInt(TyI64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum, + + (&ty::TyUint(TyUs), Uint(x)) if x == ::std::usize::MIN as u64 => Minimum, + (&ty::TyUint(TyU8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum, + (&ty::TyUint(TyU16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum, + (&ty::TyUint(TyU32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum, + (&ty::TyUint(TyU64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum, + + (&ty::TyBool, Bool(true)) => Maximum, + + (&ty::TyInt(TyIs), Int(x)) if x == ::std::isize::MAX as i64 => Maximum, + (&ty::TyInt(TyI8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum, + (&ty::TyInt(TyI16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum, + (&ty::TyInt(TyI32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum, + (&ty::TyInt(TyI64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum, + + (&ty::TyUint(TyUs), Uint(x)) if x == ::std::usize::MAX as u64 => Maximum, + (&ty::TyUint(TyU8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum, + (&ty::TyUint(TyU16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum, + (&ty::TyUint(TyU32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum, + (&ty::TyUint(TyU64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum, + + _ => return None, + }; + Some(ExtremeExpr { which: which, expr: expr }) +} + +impl LateLintPass for AbsurdExtremeComparisons { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + use types::ExtremeType::*; + use types::AbsurdComparisonResult::*; + + if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { + if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { if !in_macro(cx, expr.span) { - let msg = "testing whether an unsigned integer is non-positive"; - let help = format!("consider using {} == 0 instead", - snippet(cx, comparee.span, "x")); - span_help_and_lint(cx, ABSURD_UNSIGNED_COMPARISONS, expr.span, msg, &help); + let msg = "this comparison involving the minimum or maximum element for this \ + type contains a case that is always true or always false"; + + let conclusion = match result { + AlwaysFalse => "this comparison is always false".to_owned(), + AlwaysTrue => "this comparison is always true".to_owned(), + InequalityImpossible => + format!("the case where the two sides are not equal never occurs, \ + consider using {} == {} instead", + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs")), + }; + + let help = format!("because {} is the {} value for this type, {}", + snippet(cx, culprit.expr.span, "x"), + match culprit.which { Minimum => "minimum", Maximum => "maximum" }, + conclusion); + + span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); } } } diff --git a/tests/compile-fail/absurd-extreme-comparisons.rs b/tests/compile-fail/absurd-extreme-comparisons.rs new file mode 100644 index 00000000000..fea5f24b63f --- /dev/null +++ b/tests/compile-fail/absurd-extreme-comparisons.rs @@ -0,0 +1,44 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(absurd_extreme_comparisons)] +#![allow(unused)] +fn main() { + const Z: u32 = 0; + + 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 + u <= Z; //~ERROR this comparison involving + u < Z; //~ERROR this comparison involving + Z >= u; //~ERROR this comparison involving + Z > u; //~ERROR this comparison involving + u > std::u32::MAX; //~ERROR this comparison involving + u >= std::u32::MAX; //~ERROR this comparison involving + std::u32::MAX < u; //~ERROR this comparison involving + std::u32::MAX <= u; //~ERROR this comparison involving + + 1-1 > u; + //~^ ERROR this comparison involving + //~| 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 + 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 + + let i: i8 = 0; + i < -127 - 1; //~ERROR this comparison involving + std::i8::MAX >= i; //~ERROR this comparison involving + 3-7 < std::i32::MIN; //~ERROR this comparison involving + + let b = false; + b >= true; //~ERROR this comparison involving + false > b; //~ERROR this comparison involving + + u > 0; // ok + + // this is handled by unit_cmp + () < {}; //~WARNING <-comparison of unit values detected. +} diff --git a/tests/compile-fail/absurd_unsigned_comparisons.rs b/tests/compile-fail/absurd_unsigned_comparisons.rs deleted file mode 100644 index d7817daf204..00000000000 --- a/tests/compile-fail/absurd_unsigned_comparisons.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -#![allow(unused)] - -#[deny(absurd_unsigned_comparisons)] -fn main() { - 1u32 <= 0; //~ERROR testing whether an unsigned integer is non-positive - 1u8 <= 0; //~ERROR testing whether an unsigned integer is non-positive - 1i32 <= 0; - 0 >= 1u32; //~ERROR testing whether an unsigned integer is non-positive - 0 >= 1; - 1u32 > 0; -} -- cgit 1.4.1-3-g733a5 From fab10c07e8012b1190550615173ba6e5bca45c5e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 3 Feb 2016 13:42:46 +0100 Subject: Fix confusing message for STRING_TO_STRING --- README.md | 2 +- src/methods.rs | 7 ++++--- tests/compile-fail/methods.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 006ddcd7a7f..3f99b73c4cb 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ name [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead [string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String.to_string()` which is a no-op +[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions diff --git a/src/methods.rs b/src/methods.rs index 0584d39330d..0a06351afac 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -56,13 +56,14 @@ declare_lint!(pub STR_TO_STRING, Warn, /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default. /// -/// **Why is this bad?** As our string is already owned, this whole operation is basically a no-op, but still creates a clone of the string (which, if really wanted, should be done with `.clone()`). +/// **Why is this bad?** This is an non-efficient way to clone a `String`, `.clone()` should be used +/// instead. `String` implements `ToString` mostly for generics. /// /// **Known problems:** None /// /// **Example:** `s.to_string()` where `s: String` declare_lint!(pub STRING_TO_STRING, Warn, - "calling `String.to_string()` which is a no-op"); + "calling `String::to_string` which is inefficient"); /// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default. /// @@ -560,7 +561,7 @@ fn lint_to_string(cx: &LateContext, expr: &Expr, to_string_args: &MethodArgs) { span_lint(cx, STRING_TO_STRING, expr.span, - "`String.to_string()` is a no-op; use `clone()` to make a copy"); + "`String::to_string` is an inefficient way to clone a `String`; use `clone()` instead"); } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index f998a83e831..464a7c26e44 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -267,7 +267,7 @@ fn main() { let v = &"str"; let string = v.to_string(); //~ERROR `(*v).to_owned()` is faster - let _again = string.to_string(); //~ERROR `String.to_string()` is a no-op + let _again = string.to_string(); //~ERROR `String::to_string` is an inefficient way to clone a `String`; use `clone()` instead res.ok().expect("disaster!"); //~ERROR called `ok().expect()` // the following should not warn, since `expect` isn't implemented unless -- cgit 1.4.1-3-g733a5 From 3b8375d90b0e7d04c992b368bb7632ddab6841ff Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 3 Feb 2016 15:38:23 +0100 Subject: warn on `use`ing all variants of an enum --- README.md | 3 +- src/enum_glob_use.rs | 61 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ tests/compile-fail/enum_glob_use.rs | 20 ++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/enum_glob_use.rs create mode 100644 tests/compile-fail/enum_glob_use.rs (limited to 'src') diff --git a/README.md b/README.md index 006ddcd7a7f..424c89b28b8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 109 lints included in this crate: +There are 110 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -33,6 +33,7 @@ name [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | finds use items that import all variants of an enum [enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) [expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs new file mode 100644 index 00000000000..d6df307fec2 --- /dev/null +++ b/src/enum_glob_use.rs @@ -0,0 +1,61 @@ +//! lint on `use`ing all variants of an enum + +use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; +use rustc_front::hir::*; +use rustc::front::map::Node::NodeItem; +use rustc::front::map::PathElem::PathName; +use rustc::middle::ty::TyEnum; +use utils::span_lint; +use syntax::codemap::Span; +use syntax::ast::NodeId; + +/// **What it does:** Warns when `use`ing all variants of an enum +/// +/// **Why is this bad?** It is usually better style to use the prefixed name of an enum variant, rather than importing variants +/// +/// **Known problems:** Old-style enums that prefix the variants are still around +/// +/// **Example:** `use std::cmp::Ordering::*;` +declare_lint! { pub ENUM_GLOB_USE, Allow, + "finds use items that import all variants of an enum" } + +pub struct EnumGlobUse; + +impl LintPass for EnumGlobUse { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_GLOB_USE) + } +} + +impl LateLintPass for EnumGlobUse { + fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { + // only check top level `use` statements + for item in &m.item_ids { + self.lint_item(cx, cx.krate.item(item.id)); + } + } +} + +impl EnumGlobUse { + fn lint_item(&self, cx: &LateContext, item: &Item) { + 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 { + let def = cx.tcx.def_map.borrow()[&item.id]; + if let Some(NodeItem(it)) = cx.tcx.map.get_if_local(def.def_id()) { + if let ItemEnum(..) = it.node { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + } + } else { + if let Some(&PathName(_)) = cx.sess().cstore.item_path(def.def_id()).last() { + if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + } + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 44dd9fa8c86..4f3de70db4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub mod utils; pub mod consts; pub mod types; pub mod misc; +pub mod enum_glob_use; pub mod eq_op; pub mod bit_mask; pub mod ptr_arg; @@ -95,6 +96,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box misc::CmpNan); reg.register_late_lint_pass(box eq_op::EqOp); reg.register_early_lint_pass(box enum_variants::EnumVariantNames); + reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); reg.register_late_lint_pass(box bit_mask::BitMask); reg.register_late_lint_pass(box ptr_arg::PtrArg); reg.register_late_lint_pass(box needless_bool::NeedlessBool); @@ -153,6 +155,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy_pedantic", vec![ + enum_glob_use::ENUM_GLOB_USE, matches::SINGLE_MATCH_ELSE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/tests/compile-fail/enum_glob_use.rs b/tests/compile-fail/enum_glob_use.rs new file mode 100644 index 00000000000..fc5f531ba90 --- /dev/null +++ b/tests/compile-fail/enum_glob_use.rs @@ -0,0 +1,20 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy, clippy_pedantic)] +#![allow(unused_imports, dead_code)] + +use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants + +enum Enum {} + +use self::Enum::*; //~ ERROR: don't use glob imports for enum variants + +fn blarg() { + use self::Enum::*; // ok, just for a function +} + +mod blurg { + pub use std::cmp::Ordering::*; // ok, re-export +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From af07ccc16cbf9a736a5aba2759f296242636fecc Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 3 Feb 2016 15:39:22 +0100 Subject: fallout --- src/approx_const.rs | 10 ++--- src/bit_mask.rs | 4 +- src/consts.rs | 110 ++++++++++++++++++++------------------------------- src/len_zero.rs | 5 +-- src/minmax.rs | 5 +-- src/needless_bool.rs | 4 +- src/types.rs | 10 ++--- src/unicode.rs | 4 +- src/utils.rs | 22 +++++------ 9 files changed, 71 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 2c8779ae737..f42c723e27a 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -2,9 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use std::f64::consts as f64; use utils::span_lint; -use syntax::ast::Lit_::*; -use syntax::ast::Lit; -use syntax::ast::FloatTy::*; +use syntax::ast::{Lit, Lit_, FloatTy}; /// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. This lint is `Warn` by default. /// @@ -57,9 +55,9 @@ impl LateLintPass for ApproxConstant { fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { match lit.node { - LitFloat(ref s, TyF32) => check_known_consts(cx, e, s, "f32"), - LitFloat(ref s, TyF64) => check_known_consts(cx, e, s, "f64"), - LitFloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), + Lit_::LitFloat(ref s, FloatTy::TyF32) => check_known_consts(cx, e, s, "f32"), + Lit_::LitFloat(ref s, FloatTy::TyF64) => check_known_consts(cx, e, s, "f64"), + Lit_::LitFloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), _ => (), } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 0fce772010a..5a8b00f8b1a 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -4,7 +4,7 @@ use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; use syntax::codemap::Span; -use syntax::ast::Lit_::*; +use syntax::ast::Lit_; use utils::span_lint; @@ -256,7 +256,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { - if let LitInt(value, _) = lit_ptr.node { + if let Lit_::LitInt(value, _) = lit_ptr.node { Some(value) //TODO: Handle sign } else { None diff --git a/src/consts.rs b/src/consts.rs index f590095d9f2..5f40aff92cc 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -12,14 +12,10 @@ use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; use std::fmt; -use self::FloatWidth::*; -use syntax::ast::Lit_::*; use syntax::ast::Lit_; -use syntax::ast::LitIntType::*; use syntax::ast::LitIntType; use syntax::ast::{UintTy, FloatTy, StrStyle}; -use syntax::ast::FloatTy::*; use syntax::ast::Sign::{self, Plus, Minus}; @@ -33,8 +29,8 @@ pub enum FloatWidth { impl From<FloatTy> for FloatWidth { fn from(ty: FloatTy) -> FloatWidth { match ty { - TyF32 => Fw32, - TyF64 => Fw64, + FloatTy::TyF32 => FloatWidth::Fw32, + FloatTy::TyF64 => FloatWidth::Fw64, } } } @@ -107,6 +103,7 @@ impl PartialEq for Constant { lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)) } (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { + use self::FloatWidth::*; if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -149,6 +146,7 @@ impl PartialOrd for Constant { }) } (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { + use self::FloatWidth::*; if match (lw, rw) { (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, _ => false, @@ -261,76 +259,51 @@ impl fmt::Display for Constant { fn lit_to_constant(lit: &Lit_) -> Constant { match *lit { - LitStr(ref is, style) => Constant::Str(is.to_string(), style), - LitByte(b) => Constant::Byte(b), - LitByteStr(ref s) => Constant::Binary(s.clone()), - LitChar(c) => Constant::Char(c), - LitInt(value, ty) => Constant::Int(value, ty), - LitFloat(ref is, ty) => Constant::Float(is.to_string(), ty.into()), - LitFloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FwAny), - LitBool(b) => Constant::Bool(b), + Lit_::LitStr(ref is, style) => Constant::Str(is.to_string(), style), + Lit_::LitByte(b) => Constant::Byte(b), + Lit_::LitByteStr(ref s) => Constant::Binary(s.clone()), + Lit_::LitChar(c) => Constant::Char(c), + Lit_::LitInt(value, ty) => Constant::Int(value, ty), + Lit_::LitFloat(ref is, ty) => Constant::Float(is.to_string(), ty.into()), + Lit_::LitFloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::FwAny), + Lit_::LitBool(b) => Constant::Bool(b), } } fn constant_not(o: Constant) -> Option<Constant> { - Some(match o { - Constant::Bool(b) => Constant::Bool(!b), - Constant::Int(value, ty) => { - let (nvalue, nty) = match ty { - SignedIntLit(ity, Plus) => { - if value == ::std::u64::MAX { - return None; - } - (value + 1, SignedIntLit(ity, Minus)) - } - SignedIntLit(ity, Minus) => { - if value == 0 { - (1, SignedIntLit(ity, Minus)) - } else { - (value - 1, SignedIntLit(ity, Plus)) - } - } - UnsignedIntLit(ity) => { - let mask = match ity { - UintTy::TyU8 => ::std::u8::MAX as u64, - UintTy::TyU16 => ::std::u16::MAX as u64, - UintTy::TyU32 => ::std::u32::MAX as u64, - UintTy::TyU64 => ::std::u64::MAX, - UintTy::TyUs => { - return None; - } // refuse to guess - }; - (!value & mask, UnsignedIntLit(ity)) - } - UnsuffixedIntLit(_) => { + use syntax::ast::LitIntType::*; + use self::Constant::*; + match o { + Bool(b) => Some(Bool(!b)), + Int(::std::u64::MAX, SignedIntLit(_, Plus)) => None, + Int(value, SignedIntLit(ity, Plus)) => Some(Int(value + 1, SignedIntLit(ity, Minus))), + Int(0, SignedIntLit(ity, Minus)) => Some(Int(1, SignedIntLit(ity, Minus))), + Int(value, SignedIntLit(ity, Minus)) => Some(Int(value - 1, SignedIntLit(ity, Plus))), + Int(value, UnsignedIntLit(ity)) => { + let mask = match ity { + UintTy::TyU8 => ::std::u8::MAX as u64, + UintTy::TyU16 => ::std::u16::MAX as u64, + UintTy::TyU32 => ::std::u32::MAX as u64, + UintTy::TyU64 => ::std::u64::MAX, + UintTy::TyUs => { return None; } // refuse to guess }; - Constant::Int(nvalue, nty) - } - _ => { - return None; - } - }) + Some(Int(!value & mask, UnsignedIntLit(ity))) + }, + _ => None, + } } fn constant_negate(o: Constant) -> Option<Constant> { - Some(match o { - Constant::Int(value, ty) => { - Constant::Int(value, - match ty { - SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)), - UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)), - _ => { - return None; - } - }) - } - Constant::Float(is, ty) => Constant::Float(neg_float_str(is), ty), - _ => { - return None; - } - }) + use syntax::ast::LitIntType::*; + use self::Constant::*; + match o { + Int(value, SignedIntLit(ity, sign)) => Some(Int(value, SignedIntLit(ity, neg_sign(sign)))), + Int(value, UnsuffixedIntLit(sign)) => Some(Int(value, UnsuffixedIntLit(neg_sign(sign)))), + Float(is, ty) => Some(Float(neg_float_str(is), ty)), + _ => None, + } } fn neg_sign(s: Sign) -> Sign { @@ -357,12 +330,13 @@ fn neg_float_str(s: String) -> String { /// ``` pub fn is_negative(ty: LitIntType) -> bool { match ty { - SignedIntLit(_, sign) | UnsuffixedIntLit(sign) => sign == Minus, - UnsignedIntLit(_) => false, + LitIntType::SignedIntLit(_, sign) | LitIntType::UnsuffixedIntLit(sign) => sign == Minus, + LitIntType::UnsignedIntLit(_) => false, } } fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { + use syntax::ast::LitIntType::*; match (l, r) { (SignedIntLit(lty, _), SignedIntLit(rty, _)) => { if lty == rty { diff --git a/src/len_zero.rs b/src/len_zero.rs index 6bc5bc4bf01..a79c488b778 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -6,8 +6,7 @@ use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use syntax::ast::Lit_::*; -use syntax::ast::Lit; +use syntax::ast::{Lit, Lit_}; use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; @@ -148,7 +147,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { - if let Spanned{node: LitInt(0, _), ..} = *lit { + if let Spanned{node: Lit_::LitInt(0, _), ..} = *lit { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, diff --git a/src/minmax.rs b/src/minmax.rs index e72f2392054..3a74105d0df 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,8 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ptr::P; -use std::cmp::PartialOrd; -use std::cmp::Ordering::*; +use std::cmp::{PartialOrd, Ordering}; use consts::{Constant, constant_simple}; use utils::{match_def_path, span_lint}; @@ -36,7 +35,7 @@ impl LateLintPass for MinMaxPass { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { - (_, None) | (Max, Some(Less)) | (Min, Some(Greater)) => (), + (_, None) | (Max, Some(Ordering::Less)) | (Min, Some(Ordering::Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 22edbc272bd..34fd2204dc0 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -5,7 +5,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::ast::Lit_::*; +use syntax::ast::Lit_; use utils::{span_lint, snippet}; @@ -90,7 +90,7 @@ fn fetch_bool_expr(expr: &Expr) -> Option<bool> { match expr.node { ExprBlock(ref block) => fetch_bool_block(block), ExprLit(ref lit_ptr) => { - if let LitBool(value) = lit_ptr.node { + if let Lit_::LitBool(value) = lit_ptr.node { Some(value) } else { None diff --git a/src/types.rs b/src/types.rs index 0ab373bfa35..329813fdc4e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,9 +5,7 @@ use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::Span; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc::middle::ty; -use syntax::ast::IntTy::*; -use syntax::ast::UintTy::*; -use syntax::ast::FloatTy::*; +use syntax::ast::{IntTy, UintTy, FloatTy}; use utils::*; @@ -217,7 +215,7 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize { fn is_isize_or_usize(typ: &ty::TyS) -> bool { match typ.sty { - ty::TyInt(TyIs) | ty::TyUint(TyUs) => true, + ty::TyInt(IntTy::TyIs) | ty::TyUint(UintTy::TyUs) => true, _ => false, } } @@ -342,7 +340,7 @@ impl LateLintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = if let ty::TyFloat(TyF32) = cast_to.sty { + let to_nbits = if let ty::TyFloat(FloatTy::TyF32) = cast_to.sty { 32 } else { 64 @@ -373,7 +371,7 @@ impl LateLintPass for CastPass { check_truncation_and_wrapping(cx, expr, cast_from, cast_to); } (false, false) => { - if let (&ty::TyFloat(TyF64), &ty::TyFloat(TyF32)) = (&cast_from.sty, &cast_to.sty) { + if let (&ty::TyFloat(FloatTy::TyF64), &ty::TyFloat(FloatTy::TyF32)) = (&cast_from.sty, &cast_to.sty) { span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, diff --git a/src/unicode.rs b/src/unicode.rs index d5ea7199e10..1e4ebda5821 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use syntax::ast::Lit_::*; +use syntax::ast::Lit_; use unicode_normalization::UnicodeNormalization; @@ -51,7 +51,7 @@ impl LintPass for Unicode { impl LateLintPass for Unicode { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprLit(ref lit) = expr.node { - if let LitStr(_, _) = lit.node { + if let Lit_::LitStr(_, _) = lit.node { check_str(cx, lit.span) } } diff --git a/src/utils.rs b/src/utils.rs index 78fb45cd6cf..156d18cbe4c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ use consts::constant; use reexport::*; -use rustc::front::map::Node::*; -use rustc::lint::*; +use rustc::front::map::Node; +use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::middle::def_id::DefId; use rustc::middle::{cstore, def, infer, ty, traits}; use rustc::session::Session; @@ -10,7 +10,7 @@ use std::borrow::Cow; use std::mem; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use syntax::ast::Lit_::*; +use syntax::ast::Lit_; use syntax::ast; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; @@ -295,9 +295,9 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { - Some(NodeItem(&Item{ ref name, .. })) | - Some(NodeTraitItem(&TraitItem{ ref name, .. })) | - Some(NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), + Some(Node::NodeItem(&Item{ ref name, .. })) | + Some(Node::NodeTraitItem(&TraitItem{ ref name, .. })) | + Some(Node::NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), _ => None, } } @@ -407,7 +407,7 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { return None; } map.find(parent_id).and_then(|node| { - if let NodeExpr(parent) = node { + if let Node::NodeExpr(parent) = node { Some(parent) } else { None @@ -421,8 +421,8 @@ pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c .and_then(|enclosing_id| map.find(enclosing_id)); if let Some(node) = enclosing_node { match node { - NodeBlock(ref block) => Some(block), - NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), + Node::NodeBlock(ref block) => Some(block), + Node::NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), _ => None, } } else { @@ -528,7 +528,7 @@ pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { // FIXME: use constant folding if let ExprLit(ref spanned) = expr.node { - if let LitInt(v, _) = spanned.node { + if let Lit_::LitInt(v, _) = spanned.node { return v == value; } } @@ -574,7 +574,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } if let ast::MetaNameValue(ref key, ref value) = attr.value.node { if *key == name { - if let LitStr(ref s, _) = value.node { + if let Lit_::LitStr(ref s, _) = value.node { if let Ok(value) = FromStr::from_str(s) { f(value) } else { -- cgit 1.4.1-3-g733a5 From 3d85cc24e7c9a62359ca837570d5e08105d22036 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 5 Feb 2016 00:36:06 +0100 Subject: new regex syntax lint, fixes #597 --- Cargo.toml | 1 + README.md | 4 +++- src/lib.rs | 8 +++++-- src/regex.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++ src/utils.rs | 1 + tests/compile-fail/regex.rs | 16 ++++++++++++++ tests/compile-test.rs | 2 +- 7 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/regex.rs create mode 100644 tests/compile-fail/regex.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index b74db8f95ac..c0d600e418c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ plugin = true [dependencies] unicode-normalization = "0.1" semver = "0.2.1" +regex-syntax = "0.2.2" [dev-dependencies] compiletest_rs = "0.0.11" diff --git a/README.md b/README.md index 3f99b73c4cb..05cc5031fce 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 109 lints included in this crate: +There are 111 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -46,6 +46,7 @@ name [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` @@ -85,6 +86,7 @@ name [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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern +[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | allow | finds use of `regex!(_)`, suggests `Regex::new(_)` instead [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled [reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` [search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` diff --git a/src/lib.rs b/src/lib.rs index 44dd9fa8c86..87d23c96d36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,9 @@ extern crate unicode_normalization; // for semver check in attrs.rs extern crate semver; +// for regex checking +extern crate regex_syntax; + extern crate rustc_plugin; use rustc_plugin::Registry; @@ -82,6 +85,7 @@ pub mod derive; pub mod print; pub mod vec; pub mod drop_ref; +pub mod regex; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -150,7 +154,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box vec::UselessVec); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdUnsignedComparisons); - + reg.register_late_lint_pass(box regex::RegexPass); reg.register_lint_group("clippy_pedantic", vec![ matches::SINGLE_MATCH_ELSE, @@ -163,7 +167,6 @@ pub fn plugin_registrar(reg: &mut Registry) { shadow::SHADOW_REUSE, shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, - strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::CAST_POSSIBLE_TRUNCATION, types::CAST_POSSIBLE_WRAP, @@ -250,6 +253,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, ranges::RANGE_ZIP_WITH_LEN, + regex::INVALID_REGEX, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, strings::STRING_LIT_AS_BYTES, diff --git a/src/regex.rs b/src/regex.rs new file mode 100644 index 00000000000..e3363ad1df0 --- /dev/null +++ b/src/regex.rs @@ -0,0 +1,53 @@ +use regex_syntax; +use std::error::Error; +use syntax::codemap::{Span, BytePos, Pos}; +use rustc_front::hir::*; +use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::lint::*; + +use utils::{match_path, REGEX_NEW_PATH, span_lint}; + +/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. It is `deny` by default. +/// +/// **Why is this bad?** This will lead to a runtime panic. +/// +/// **Known problems:** None. +/// +/// **Example:** `Regex::new("|")` +declare_lint! { + pub INVALID_REGEX, + Deny, + "finds invalid regular expressions in `Regex::new(_)` invocations" +} + +#[derive(Copy,Clone)] +pub struct RegexPass; + +impl LintPass for RegexPass { + fn get_lints(&self) -> LintArray { + lint_array!(INVALID_REGEX) + } +} + +impl LateLintPass for RegexPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain!{[ + let ExprCall(ref fun, ref args) = expr.node, + let ExprPath(_, ref path) = fun.node, + match_path(path, ®EX_NEW_PATH) && args.len() == 1, + let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, + &*args[0], + ExprTypeChecked, + None), + let Err(e) = regex_syntax::Expr::parse(&r) + ], { + let lo = args[0].span.lo + BytePos::from_usize(e.position()); + let span = Span{ lo: lo, hi: lo, expn_id: args[0].span.expn_id }; + span_lint(cx, + INVALID_REGEX, + span, + &format!("Regex syntax error: {}", e.description())); + }} + } +} diff --git a/src/utils.rs b/src/utils.rs index 78fb45cd6cf..8f542431d64 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -36,6 +36,7 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedLis pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs new file mode 100644 index 00000000000..e2be26a999e --- /dev/null +++ b/tests/compile-fail/regex.rs @@ -0,0 +1,16 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(unused)] +#![deny(invalid_regex)] + +extern crate regex; + +use regex::Regex; + +fn main() { + let pipe_in_wrong_position = Regex::new("|"); + //~^ERROR: Regex syntax error: empty alternate + let wrong_char_range = Regex::new("[z-a]"); + //~^ERROR: Regex syntax error: invalid character class range +} diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 602937a40af..92d2671eaa7 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -7,7 +7,7 @@ fn run_mode(mode: &'static str) { let mut config = compiletest::default_config(); let cfg_mode = mode.parse().ok().expect("Invalid mode"); - config.target_rustcflags = Some("-L target/debug/".to_owned()); + config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps".to_owned()); if let Ok(name) = var::<&str>("TESTNAME") { let s : String = name.to_owned(); config.filter = Some(s) -- cgit 1.4.1-3-g733a5 From 4eb9a921d4a3658bb38f6831281a594ad6e3359f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 5 Feb 2016 16:04:15 +0530 Subject: Lint on cloning double pointer fixes #620 --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 146 ++++++++++++++++++++++++++++++++------------------------- 3 files changed, 84 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 3f99b73c4cb..d6daa49c521 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 109 lints included in this crate: +There are 110 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -23,6 +23,7 @@ name [cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` [char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | Casting a character literal to u8 [chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char +[clone_double_ref](https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref) | warn | using `clone` on `&&T` [clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type [cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) [cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` diff --git a/src/lib.rs b/src/lib.rs index 44dd9fa8c86..482472b6651 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,6 +215,7 @@ pub fn plugin_registrar(reg: &mut Registry) { matches::MATCH_REF_PATS, matches::SINGLE_MATCH, methods::CHARS_NEXT_CMP, + methods::CLONE_DOUBLE_REF, methods::CLONE_ON_COPY, methods::EXTEND_FROM_SLICE, methods::FILTER_NEXT, diff --git a/src/methods.rs b/src/methods.rs index 0a06351afac..61a910a65ab 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -7,15 +7,11 @@ use std::borrow::Cow; use syntax::ptr::P; use syntax::codemap::Span; -use utils::{ - get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, - match_trait_method, match_type, method_chain_args, snippet, span_lint, span_lint_and_then, - span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, -}; -use utils::{ - BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, - STRING_PATH, VEC_PATH, -}; +use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, + match_type, method_chain_args, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, + walk_ptrs_ty, walk_ptrs_ty_depth}; +use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, + VEC_PATH,}; use utils::MethodArgs; use rustc::middle::cstore::CrateStore; @@ -231,6 +227,26 @@ declare_lint!(pub EXTEND_FROM_SLICE, Warn, declare_lint!(pub CLONE_ON_COPY, Warn, "using `clone` on a `Copy` type"); +/// **What it does:** This lint warns on using `.clone()` on an `&&T` +/// +/// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of cloning the underlying +/// `T` +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// fn main() { +/// let x = vec![1]; +/// let y = &&x; +/// let z = y.clone(); +/// println!("{:p} {:p}",*y, z); // prints out the same pointer +/// } +/// ``` +/// +declare_lint!(pub CLONE_DOUBLE_REF, Warn, + "using `clone` on `&&T`"); + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(EXTEND_FROM_SLICE, @@ -246,7 +262,8 @@ impl LintPass for MethodsPass { OPTION_MAP_UNWRAP_OR_ELSE, OR_FUN_CALL, CHARS_NEXT_CMP, - CLONE_ON_COPY) + CLONE_ON_COPY, + CLONE_DOUBLE_REF) } } @@ -280,9 +297,11 @@ impl LateLintPass for MethodsPass { } else if let Some(arglists) = method_chain_args(expr, &["extend"]) { lint_extend(cx, expr, arglists[0]); } - lint_or_fun_call(cx, expr, &name.node.as_str(), &args); - lint_clone_on_copy(cx, expr, &name.node.as_str(), &args); + if args.len() == 1 && name.node.as_str() == "clone" { + lint_clone_on_copy(cx, expr); + lint_clone_double_ref(cx, expr, &args[0]); + } } ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { if !lint_chars_next(cx, expr, lhs, rhs, op.node == BiEq) { @@ -348,15 +367,9 @@ impl LateLintPass for MethodsPass { /// Checks for the `OR_FUN_CALL` lint. fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. - fn check_unwrap_or_default( - cx: &LateContext, - name: &str, - fun: &Expr, - self_expr: &Expr, - arg: &Expr, - or_has_args: bool, - span: Span - ) -> bool { + fn check_unwrap_or_default(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, + or_has_args: bool, span: Span) + -> bool { if or_has_args { return false; } @@ -379,11 +392,13 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) }; if implements_trait(cx, arg_ty, default_trait_id, None) { - span_lint(cx, OR_FUN_CALL, span, + span_lint(cx, + OR_FUN_CALL, + span, &format!("use of `{}` followed by a call to `{}`", name, path)) - .span_suggestion(span, "try this", - format!("{}.unwrap_or_default()", - snippet(cx, self_expr.span, "_"))); + .span_suggestion(span, + "try this", + format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); return true; } } @@ -394,34 +409,25 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } /// Check for `*or(foo())`. - fn check_general_case( - cx: &LateContext, - name: &str, - fun: &Expr, - self_expr: &Expr, - arg: &Expr, - or_has_args: bool, - span: Span - ) { + fn check_general_case(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, or_has_args: bool, + span: Span) { // (path, fn_has_argument, methods) - let know_types : &[(&[_], _, &[_], _)] = &[ - (&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"), - (&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"), - (&OPTION_PATH, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&RESULT_PATH, true, &["or", "unwrap_or"], "else"), - ]; + let know_types: &[(&[_], _, &[_], _)] = &[(&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"), + (&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"), + (&OPTION_PATH, + false, + &["map_or", "ok_or", "or", "unwrap_or"], + "else"), + (&RESULT_PATH, true, &["or", "unwrap_or"], "else")]; let self_ty = cx.tcx.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) - }) { - (fn_has_arguments, poss, suffix) - } - else { - return - }; + 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)) { + (fn_has_arguments, poss, suffix) + } else { + return; + }; if !poss.contains(&name) { return; @@ -433,14 +439,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) (false, true) => format!("{}", snippet(cx, fun.span, "..")), }; - span_lint(cx, OR_FUN_CALL, span, - &format!("use of `{}` followed by a function call", name)) - .span_suggestion(span, "try this", - format!("{}.{}_{}({})", - snippet(cx, self_expr.span, "_"), - name, - suffix, - sugg)); + span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name)) + .span_suggestion(span, + "try this", + format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); } if args.len() == 2 { @@ -454,14 +456,28 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } /// Checks for the `CLONE_ON_COPY` lint. -fn lint_clone_on_copy(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { - if args.len() == 1 && name == "clone" { - let ty = cx.tcx.expr_ty(expr); - let parent = cx.tcx.map.get_parent(expr.id); - let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); - - if !ty.moves_by_default(¶meter_environment, expr.span) { - span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); +fn lint_clone_on_copy(cx: &LateContext, expr: &Expr) { + let ty = cx.tcx.expr_ty(expr); + let parent = cx.tcx.map.get_parent(expr.id); + let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); + + if !ty.moves_by_default(¶meter_environment, expr.span) { + span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); + } +} + +/// Checks for the `CLONE_DOUBLE_REF` lint. +fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) { + let ty = cx.tcx.expr_ty(arg); + if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { + if let ty::TyRef(..) = inner.sty { + let mut db = span_lint(cx, CLONE_DOUBLE_REF, expr.span, + "using `clone` on a double-reference; \ + this will copy the reference instead of cloning \ + the inner type"); + if let Some(snip) = snippet_opt(cx, arg.span) { + db.span_suggestion(expr.span, "try dereferencing it", format!("(*{}).clone()", snip)); + } } } } -- cgit 1.4.1-3-g733a5 From a14514f7c8a9a93ed09f6c1ee3e3a21560ab66b8 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Fri, 5 Feb 2016 16:48:35 +0100 Subject: fixed span position and README --- README.md | 3 +-- src/lib.rs | 1 + src/regex.rs | 56 ++++++++++++++++++++++++++++++++++----------- tests/compile-fail/regex.rs | 10 +++++++- 4 files changed, 54 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 05cc5031fce..eb843daab20 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 111 lints included in this crate: +There are 110 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -86,7 +86,6 @@ name [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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern -[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | allow | finds use of `regex!(_)`, suggests `Regex::new(_)` instead [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled [reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` [search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` diff --git a/src/lib.rs b/src/lib.rs index 87d23c96d36..a77f6829b90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,6 +167,7 @@ pub fn plugin_registrar(reg: &mut Registry) { shadow::SHADOW_REUSE, shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, + strings::STRING_ADD, strings::STRING_ADD_ASSIGN, types::CAST_POSSIBLE_TRUNCATION, types::CAST_POSSIBLE_WRAP, diff --git a/src/regex.rs b/src/regex.rs index e3363ad1df0..259bbb1b64b 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,6 +1,8 @@ use regex_syntax; use std::error::Error; -use syntax::codemap::{Span, BytePos, Pos}; +use syntax::ast::Lit_::LitStr; +use syntax::codemap::{Span, BytePos}; +use syntax::parse::token::InternedString; use rustc_front::hir::*; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; @@ -35,19 +37,47 @@ impl LateLintPass for RegexPass { if_let_chain!{[ let ExprCall(ref fun, ref args) = expr.node, let ExprPath(_, ref path) = fun.node, - match_path(path, ®EX_NEW_PATH) && args.len() == 1, - let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, - &*args[0], - ExprTypeChecked, - None), - let Err(e) = regex_syntax::Expr::parse(&r) + match_path(path, ®EX_NEW_PATH) && args.len() == 1 ], { - let lo = args[0].span.lo + BytePos::from_usize(e.position()); - let span = Span{ lo: lo, hi: lo, expn_id: args[0].span.expn_id }; - span_lint(cx, - INVALID_REGEX, - span, - &format!("Regex syntax error: {}", e.description())); + if let ExprLit(ref lit) = args[0].node { + if let LitStr(ref r, _) = lit.node { + if let Err(e) = regex_syntax::Expr::parse(r) { + span_lint(cx, + INVALID_REGEX, + str_span(args[0].span, &r, e.position()), + &format!("Regex syntax error: {}", + e.description())); + } + } + } else { + if_let_chain!{[ + let Some(r) = const_str(cx, &*args[0]), + let Err(e) = regex_syntax::Expr::parse(&r) + ], { + span_lint(cx, + INVALID_REGEX, + args[0].span, + &format!("Regex syntax error on position {}: {}", + e.position(), + e.description())); + }} + } }} } } + +#[allow(cast_possible_truncation)] +fn str_span(base: Span, s: &str, c: usize) -> Span { + let lo = match s.char_indices().nth(c) { + Some((b, _)) => base.lo + BytePos(b as u32), + _ => base.hi + }; + Span{ lo: lo, hi: lo, ..base } +} + +fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { + match eval_const_expr_partial(cx.tcx, e, ExprTypeChecked, None) { + Ok(ConstVal::Str(r)) => Some(r), + _ => None + } +} diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index e2be26a999e..34dfc1ef25b 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -8,9 +8,17 @@ extern crate regex; use regex::Regex; +const OPENING_PAREN : &'static str = "("; + fn main() { let pipe_in_wrong_position = Regex::new("|"); //~^ERROR: Regex syntax error: empty alternate - let wrong_char_range = Regex::new("[z-a]"); + let wrong_char_ranice = Regex::new("[z-a]"); //~^ERROR: Regex syntax error: invalid character class range + + let some_regex = Regex::new(OPENING_PAREN); + //~^ERROR: Regex syntax error on position 0: unclosed + + let closing_paren = ")"; + let not_linted = Regex::new(closing_paren); } -- cgit 1.4.1-3-g733a5 From 431c446746a7893ca6c78048adebc55f2f308979 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 19 Jan 2016 21:10:00 +0100 Subject: Lint looping on maps ignoring the keys or values --- README.md | 3 +- src/lib.rs | 1 + src/lifetimes.rs | 2 +- src/loops.rs | 82 ++++++++++++++++++++++++++++++++++++++---- tests/compile-fail/for_loop.rs | 16 +++++++++ 5 files changed, 96 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index f7908ffdcab..59a12e09b17 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 111 lints included in this crate: +There are 112 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -42,6 +42,7 @@ name [extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` [for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` diff --git a/src/lib.rs b/src/lib.rs index 56a2a072421..3f18bcb17ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,6 +205,7 @@ pub fn plugin_registrar(reg: &mut Registry) { loops::EMPTY_LOOP, loops::EXPLICIT_COUNTER_LOOP, loops::EXPLICIT_ITER_LOOP, + loops::FOR_KV_MAP, loops::FOR_LOOP_OVER_OPTION, loops::FOR_LOOP_OVER_RESULT, loops::ITER_NEXT_LOOP, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index b6f8ebe5fd8..3e9880d5932 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -352,7 +352,7 @@ fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics, } } - for (_, v) in checker.0 { + for &v in checker.0.values() { span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); } } diff --git a/src/loops.rs b/src/loops.rs index 49e073aacd0..830fac94e46 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -10,8 +10,8 @@ use std::borrow::Cow; use std::collections::{HashSet, HashMap}; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, - span_help_and_lint, is_integer_literal, get_enclosing_block}; -use utils::{HASHMAP_PATH, VEC_PATH, LL_PATH, OPTION_PATH, RESULT_PATH}; + span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty}; +use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. /// @@ -141,6 +141,24 @@ declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } /// **Example:** `while let Some(val) = iter() { .. }` declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" } +/// **What it does:** This warns when you iterate on a map (`HashMap` or `BTreeMap`) and ignore +/// either the keys or values. +/// +/// **Why is this bad?** Readability. There are `keys` and `values` methods that can be used to +/// express that don't need the values or keys. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// for (k, _) in &map { .. } +/// ``` +/// could be replaced by +/// ```rust +/// for k in map.keys() { .. } +/// ``` +declare_lint!{ pub FOR_KV_MAP, Warn, "looping on a map using `iter` when `keys` or `values` would do" } + #[derive(Copy, Clone)] pub struct LoopsPass; @@ -154,7 +172,8 @@ impl LintPass for LoopsPass { REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, - WHILE_LET_ON_ITERATOR) + WHILE_LET_ON_ITERATOR, + FOR_KV_MAP) } } @@ -270,6 +289,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E check_for_loop_reverse_range(cx, arg, expr); check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); + check_for_loop_over_map_kv(cx, pat, arg, expr); } /// Check for looping over a range and then indexing a sequence with it. @@ -499,6 +519,53 @@ 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, expr: &Expr) { + if let PatTup(ref pat) = pat.node { + if pat.len() == 2 { + let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { + (key, _) if pat_is_wild(key) => (&pat[1].span, "values"), + (_, value) if pat_is_wild(value) => (&pat[0].span, "keys"), + _ => return + }; + + let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); + let arg_span = if let ExprAddrOf(_, ref expr) = arg.node { + expr.span + } + else { + arg.span + }; + + if match_type(cx, ty, &HASHMAP_PATH) || + match_type(cx, ty, &BTREEMAP_PATH) { + span_lint_and_then(cx, + FOR_KV_MAP, + expr.span, + &format!("you seem to want to iterate on a map's {}", kind), + |db| { + db.span_suggestion(expr.span, + "use the corresponding method", + format!("for {} in {}.{}()", + snippet(cx, *pat_span, ".."), + snippet(cx, arg_span, ".."), + kind)); + }); + } + } + } + +} + +// Return true if the pattern is a `PatWild` or an ident prefixed with '_'. +fn pat_is_wild(pat: &Pat_) -> bool { + match *pat { + PatWild => true, + PatIdent(_, ident, None) if ident.node.name.as_str().starts_with('_') => true, + _ => false, + } +} + /// Recover the essential nodes of a desugared for loop: /// `for pat in arg { body }` becomes `(pat, arg, body)`. fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { @@ -601,11 +668,14 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); - is_iterable_array(ty) || match_type(cx, ty, &VEC_PATH) || match_type(cx, ty, &LL_PATH) || - match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || + is_iterable_array(ty) || + match_type(cx, ty, &VEC_PATH) || + match_type(cx, ty, &LL_PATH) || + match_type(cx, ty, &HASHMAP_PATH) || + match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || - match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) || + match_type(cx, ty, &BTREEMAP_PATH) || match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 1fcbbf54d1f..7049a21b15e 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -280,4 +280,20 @@ fn main() { println!("index: {}", index); for_loop_over_option_and_result(); + + let m : HashMap<u64, u64> = HashMap::new(); + for (_, v) in &m { + //~^ you seem to want to iterate on a map's values + //~| HELP use the corresponding method + //~| SUGGESTION for v in &m.values() + let _v = v; + } + + let rm = &m; + for (k, _values) in rm { + //~^ you seem to want to iterate on a map's keys + //~| HELP use the corresponding method + //~| SUGGESTION for k in rm.keys() + let _k = k; + } } -- cgit 1.4.1-3-g733a5 From 0f50b0981d33c2fcb591e2aab46bd8bd0497daff Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 5 Feb 2016 19:14:02 +0100 Subject: Check for pattern use in FOR_KV_MAP --- src/loops.rs | 38 ++++++++++++++++++++++++++++++++------ tests/compile-fail/for_loop.rs | 15 ++++++++++++++- 2 files changed, 46 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 830fac94e46..22dfef55ec1 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -289,7 +289,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E check_for_loop_reverse_range(cx, arg, expr); check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); - check_for_loop_over_map_kv(cx, pat, arg, expr); + check_for_loop_over_map_kv(cx, pat, arg, body, expr); } /// Check for looping over a range and then indexing a sequence with it. @@ -520,12 +520,13 @@ 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, expr: &Expr) { +fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { if let PatTup(ref pat) = pat.node { if pat.len() == 2 { + let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { - (key, _) if pat_is_wild(key) => (&pat[1].span, "values"), - (_, value) if pat_is_wild(value) => (&pat[0].span, "keys"), + (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), + (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), _ => return }; @@ -558,14 +559,39 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Ex } // Return true if the pattern is a `PatWild` or an ident prefixed with '_'. -fn pat_is_wild(pat: &Pat_) -> bool { +fn pat_is_wild(pat: &Pat_, body: &Expr) -> bool { match *pat { PatWild => true, - PatIdent(_, ident, None) if ident.node.name.as_str().starts_with('_') => true, + PatIdent(_, ident, None) if ident.node.name.as_str().starts_with('_') => { + let mut visitor = UsedVisitor { + var: ident.node, + used: false, + }; + walk_expr(&mut visitor, body); + !visitor.used + }, _ => false, } } +struct UsedVisitor { + var: Ident, // var to look for + used: bool, // has the var been used otherwise? +} + +impl<'a> Visitor<'a> for UsedVisitor { + fn visit_expr(&mut self, expr: &Expr) { + if let ExprPath(None, ref path) = expr.node { + if path.segments.len() == 1 && path.segments[0].identifier == self.var { + self.used = true; + return + } + } + + walk_expr(self, expr); + } +} + /// Recover the essential nodes of a desugared for loop: /// `for pat in arg { body }` becomes `(pat, arg, body)`. fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 7049a21b15e..e361ebe777f 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -290,10 +290,23 @@ fn main() { } let rm = &m; - for (k, _values) in rm { + for (k, _value) in rm { //~^ you seem to want to iterate on a map's keys //~| HELP use the corresponding method //~| SUGGESTION for k in rm.keys() let _k = k; } + + test_for_kv_map(); +} + +#[allow(used_underscore_binding)] +fn test_for_kv_map() { + let m : HashMap<u64, u64> = HashMap::new(); + + // No error, _value is actually used + for (k, _value) in &m { + let _ = _value; + let _k = k; + } } -- cgit 1.4.1-3-g733a5 From c0063e172de4854b6da3f097e5eb1da43dd3bd7a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 5 Feb 2016 19:46:11 +0100 Subject: Improve error message --- src/loops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 22dfef55ec1..3f430a1aaf0 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -547,7 +547,7 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex |db| { db.span_suggestion(expr.span, "use the corresponding method", - format!("for {} in {}.{}()", + format!("for {} in {}.{}() {{...}}", snippet(cx, *pat_span, ".."), snippet(cx, arg_span, ".."), kind)); -- cgit 1.4.1-3-g733a5 From 70124cf5917e0b9d6597c3e3f855687182a9d071 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 5 Feb 2016 21:54:29 +0100 Subject: Fix case conventions --- src/cyclomatic_complexity.rs | 4 ++-- src/open_options.rs | 14 +++++++------- src/regex.rs | 4 ++-- tests/compile-fail/cyclomatic_complexity.rs | 26 +++++++++++++------------- tests/compile-fail/open_options.rs | 16 ++++++++-------- tests/compile-fail/regex.rs | 10 +++++----- 6 files changed, 37 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index d4375abcd05..84fb9b874ff 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -62,8 +62,8 @@ impl CyclomaticComplexity { span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, span, - &format!("The function has a cyclomatic complexity of {}", rust_cc), - "You could split it up into multiple smaller functions"); + &format!("the function has a cyclomatic complexity of {}", rust_cc), + "you could split it up into multiple smaller functions"); } } } diff --git a/src/open_options.rs b/src/open_options.rs index 541ed2444f4..e0b51cdfa2a 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -120,7 +120,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "The method \"create\" is called more than once"); + "the method \"create\" is called more than once"); } else { create = true } @@ -131,7 +131,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "The method \"append\" is called more than once"); + "the method \"append\" is called more than once"); } else { append = true } @@ -142,7 +142,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "The method \"truncate\" is called more than once"); + "the method \"truncate\" is called more than once"); } else { truncate = true } @@ -153,7 +153,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "The method \"read\" is called more than once"); + "the method \"read\" is called more than once"); } else { read = true } @@ -164,7 +164,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "The method \"write\" is called more than once"); + "the method \"write\" is called more than once"); } else { write = true } @@ -174,12 +174,12 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span } if read && truncate && read_arg && truncate_arg { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "File opened with \"truncate\" and \"read\""); + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\""); } if append && truncate && append_arg && truncate_arg { span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, - "File opened with \"append\" and \"truncate\""); + "file opened with \"append\" and \"truncate\""); } } diff --git a/src/regex.rs b/src/regex.rs index 259bbb1b64b..c24edc564ae 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -45,7 +45,7 @@ impl LateLintPass for RegexPass { span_lint(cx, INVALID_REGEX, str_span(args[0].span, &r, e.position()), - &format!("Regex syntax error: {}", + &format!("regex syntax error: {}", e.description())); } } @@ -57,7 +57,7 @@ impl LateLintPass for RegexPass { span_lint(cx, INVALID_REGEX, args[0].span, - &format!("Regex syntax error on position {}: {}", + &format!("regex syntax error on position {}: {}", e.position(), e.description())); }} diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index f79440af121..5bdca7f3629 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -5,7 +5,7 @@ #![allow(unused)] -fn main() { //~ERROR The function has a cyclomatic complexity of 28 +fn main() { //~ERROR the function has a cyclomatic complexity of 28 if true { println!("a"); } @@ -90,7 +90,7 @@ fn main() { //~ERROR The function has a cyclomatic complexity of 28 } #[cyclomatic_complexity = "0"] -fn kaboom() { //~ ERROR: The function has a cyclomatic complexity of 8 +fn kaboom() { //~ ERROR: the function has a cyclomatic complexity of 8 let n = 0; 'a: for i in 0..20 { 'b: for j in i..20 { @@ -136,7 +136,7 @@ fn bloo() { } #[cyclomatic_complexity = "0"] -fn baa() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn baa() { //~ ERROR: the function has a cyclomatic complexity of 2 let x = || match 99 { 0 => true, 1 => false, @@ -154,7 +154,7 @@ fn baa() { //~ ERROR: The function has a cyclomatic complexity of 2 } #[cyclomatic_complexity = "0"] -fn bar() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn bar() { //~ ERROR: the function has a cyclomatic complexity of 2 match 99 { 0 => println!("hi"), _ => println!("bye"), @@ -162,7 +162,7 @@ fn bar() { //~ ERROR: The function has a cyclomatic complexity of 2 } #[cyclomatic_complexity = "0"] -fn barr() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn barr() { //~ ERROR: the function has a cyclomatic complexity of 2 match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -172,7 +172,7 @@ fn barr() { //~ ERROR: The function has a cyclomatic complexity of 2 } #[cyclomatic_complexity = "0"] -fn barr2() { //~ ERROR: The function has a cyclomatic complexity of 3 +fn barr2() { //~ ERROR: the function has a cyclomatic complexity of 3 match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -188,7 +188,7 @@ fn barr2() { //~ ERROR: The function has a cyclomatic complexity of 3 } #[cyclomatic_complexity = "0"] -fn barrr() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn barrr() { //~ ERROR: the function has a cyclomatic complexity of 2 match 99 { 0 => println!("hi"), 1 => panic!("bla"), @@ -198,7 +198,7 @@ fn barrr() { //~ ERROR: The function has a cyclomatic complexity of 2 } #[cyclomatic_complexity = "0"] -fn barrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 +fn barrr2() { //~ ERROR: the function has a cyclomatic complexity of 3 match 99 { 0 => println!("hi"), 1 => panic!("bla"), @@ -214,7 +214,7 @@ fn barrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 } #[cyclomatic_complexity = "0"] -fn barrrr() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn barrrr() { //~ ERROR: the function has a cyclomatic complexity of 2 match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -224,7 +224,7 @@ fn barrrr() { //~ ERROR: The function has a cyclomatic complexity of 2 } #[cyclomatic_complexity = "0"] -fn barrrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 +fn barrrr2() { //~ ERROR: the function has a cyclomatic complexity of 3 match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -240,7 +240,7 @@ fn barrrr2() { //~ ERROR: The function has a cyclomatic complexity of 3 } #[cyclomatic_complexity = "0"] -fn cake() { //~ ERROR: The function has a cyclomatic complexity of 2 +fn cake() { //~ ERROR: the function has a cyclomatic complexity of 2 if 4 == 5 { println!("yea"); } else { @@ -251,7 +251,7 @@ fn cake() { //~ ERROR: The function has a cyclomatic complexity of 2 #[cyclomatic_complexity = "0"] -pub fn read_file(input_path: &str) -> String { //~ ERROR: The function has a cyclomatic complexity of 4 +pub fn read_file(input_path: &str) -> String { //~ ERROR: the function has a cyclomatic complexity of 4 use std::fs::File; use std::io::{Read, Write}; use std::path::Path; @@ -282,7 +282,7 @@ pub fn read_file(input_path: &str) -> String { //~ ERROR: The function has a cyc enum Void {} #[cyclomatic_complexity = "0"] -fn void(void: Void) { //~ ERROR: The function has a cyclomatic complexity of 1 +fn void(void: Void) { //~ ERROR: the function has a cyclomatic complexity of 1 if true { match void { } diff --git a/tests/compile-fail/open_options.rs b/tests/compile-fail/open_options.rs index 35cc91c9d0f..08024e37d4a 100644 --- a/tests/compile-fail/open_options.rs +++ b/tests/compile-fail/open_options.rs @@ -5,12 +5,12 @@ use std::fs::OpenOptions; #[allow(unused_must_use)] #[deny(nonsensical_open_options)] fn main() { - OpenOptions::new().read(true).truncate(true).open("foo.txt"); //~ERROR File opened with "truncate" and "read" - OpenOptions::new().append(true).truncate(true).open("foo.txt"); //~ERROR File opened with "append" and "truncate" - - OpenOptions::new().read(true).read(false).open("foo.txt"); //~ERROR The method "read" is called more than once - OpenOptions::new().create(true).create(false).open("foo.txt"); //~ERROR The method "create" is called more than once - OpenOptions::new().write(true).write(false).open("foo.txt"); //~ERROR The method "write" is called more than once - OpenOptions::new().append(true).append(false).open("foo.txt"); //~ERROR The method "append" is called more than once - OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); //~ERROR The method "truncate" is called more than once + OpenOptions::new().read(true).truncate(true).open("foo.txt"); //~ERROR file opened with "truncate" and "read" + OpenOptions::new().append(true).truncate(true).open("foo.txt"); //~ERROR file opened with "append" and "truncate" + + OpenOptions::new().read(true).read(false).open("foo.txt"); //~ERROR the method "read" is called more than once + OpenOptions::new().create(true).create(false).open("foo.txt"); //~ERROR the method "create" is called more than once + OpenOptions::new().write(true).write(false).open("foo.txt"); //~ERROR the method "write" is called more than once + OpenOptions::new().append(true).append(false).open("foo.txt"); //~ERROR the method "append" is called more than once + OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); //~ERROR the method "truncate" is called more than once } diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index 34dfc1ef25b..5a3f8b1a368 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -12,12 +12,12 @@ const OPENING_PAREN : &'static str = "("; fn main() { let pipe_in_wrong_position = Regex::new("|"); - //~^ERROR: Regex syntax error: empty alternate - let wrong_char_ranice = Regex::new("[z-a]"); - //~^ERROR: Regex syntax error: invalid character class range - + //~^ERROR: regex syntax error: empty alternate + let wrong_char_ranice = Regex::new("[z-a]"); + //~^ERROR: regex syntax error: invalid character class range + let some_regex = Regex::new(OPENING_PAREN); - //~^ERROR: Regex syntax error on position 0: unclosed + //~^ERROR: regex syntax error on position 0: unclosed let closing_paren = ")"; let not_linted = Regex::new(closing_paren); -- cgit 1.4.1-3-g733a5 From a02b8124de9b778e822814608217ca774ec231fa Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 5 Feb 2016 23:10:48 +0100 Subject: Lint about trivial regexes --- README.md | 3 ++- src/lib.rs | 1 + src/regex.rs | 60 +++++++++++++++++++++++++++++++++++++++------ tests/compile-fail/regex.rs | 47 +++++++++++++++++++++++++++++++++-- 4 files changed, 100 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 59a12e09b17..08ad214e690 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 112 lints included in this crate: +There are 113 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -104,6 +104,7 @@ name [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. +[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) diff --git a/src/lib.rs b/src/lib.rs index 3f18bcb17ce..33de4d6fb79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,6 +257,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_STEP_BY_ZERO, ranges::RANGE_ZIP_WITH_LEN, regex::INVALID_REGEX, + regex::TRIVIAL_REGEX, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, strings::STRING_LIT_AS_BYTES, diff --git a/src/regex.rs b/src/regex.rs index c24edc564ae..0558b77acb0 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -8,7 +8,7 @@ use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; -use utils::{match_path, REGEX_NEW_PATH, span_lint}; +use utils::{match_path, REGEX_NEW_PATH, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. It is `deny` by default. /// @@ -23,12 +23,26 @@ declare_lint! { "finds invalid regular expressions in `Regex::new(_)` invocations" } +/// **What it does:** This lint checks for `Regex::new(_)` invocations with trivial regex. +/// +/// **Why is this bad?** This can likely be replaced by `==` or `str::starts_with`, +/// `str::ends_with` or `std::contains` or other `str` methods. +/// +/// **Known problems:** None. +/// +/// **Example:** `Regex::new("^foobar")` +declare_lint! { + pub TRIVIAL_REGEX, + Warn, + "finds trivial regular expressions in `Regex::new(_)` invocations" +} + #[derive(Copy,Clone)] pub struct RegexPass; impl LintPass for RegexPass { fn get_lints(&self) -> LintArray { - lint_array!(INVALID_REGEX) + lint_array!(INVALID_REGEX, TRIVIAL_REGEX) } } @@ -48,19 +62,26 @@ impl LateLintPass for RegexPass { &format!("regex syntax error: {}", e.description())); } + else if let Some(repl) = is_trivial_regex(r) { + span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, + &"trivial regex", + &format!("consider using {}", repl)); + } } - } else { - if_let_chain!{[ - let Some(r) = const_str(cx, &*args[0]), - let Err(e) = regex_syntax::Expr::parse(&r) - ], { + } else if let Some(r) = const_str(cx, &*args[0]) { + if let Err(e) = regex_syntax::Expr::parse(&r) { span_lint(cx, INVALID_REGEX, args[0].span, &format!("regex syntax error on position {}: {}", e.position(), e.description())); - }} + } + else if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, + &"trivial regex", + &format!("{}", repl)); + } } }} } @@ -81,3 +102,26 @@ fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { _ => None } } + +fn is_trivial_regex(s: &str) -> Option<&'static str> { + // some unlikely but valid corner cases + match s { + "" | "^" | "$" => return Some("the regex is unlikely to be useful as it is"), + "^$" => return Some("consider using `str::is_empty`"), + _ => (), + } + + let (start, end, repl) = match (s.starts_with('^'), s.ends_with('$')) { + (true, true) => (1, s.len()-1, "consider using `==` on `str`s"), + (false, true) => (0, s.len()-1, "consider using `str::ends_with`"), + (true, false) => (1, s.len(), "consider using `str::starts_with`"), + (false, false) => (0, s.len(), "consider using `str::contains`"), + }; + + if !s.chars().take(end).skip(start).any(regex_syntax::is_punct) { + Some(repl) + } + else { + None + } +} diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index 5a3f8b1a368..cd10d47c1bb 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -2,15 +2,16 @@ #![plugin(clippy)] #![allow(unused)] -#![deny(invalid_regex)] +#![deny(invalid_regex, trivial_regex)] extern crate regex; use regex::Regex; const OPENING_PAREN : &'static str = "("; +const NOT_A_REAL_REGEX : &'static str = "foobar"; -fn main() { +fn syntax_error() { let pipe_in_wrong_position = Regex::new("|"); //~^ERROR: regex syntax error: empty alternate let wrong_char_ranice = Regex::new("[z-a]"); @@ -22,3 +23,45 @@ fn main() { let closing_paren = ")"; let not_linted = Regex::new(closing_paren); } + +fn trivial_regex() { + let trivial_eq = Regex::new("^foobar$"); + //~^ERROR: trivial regex + //~|HELP consider using `==` on `str`s + + let trivial_starts_with = Regex::new("^foobar"); + //~^ERROR: trivial regex + //~|HELP consider using `str::starts_with` + + let trivial_ends_with = Regex::new("foobar$"); + //~^ERROR: trivial regex + //~|HELP consider using `str::ends_with` + + let trivial_contains = Regex::new("foobar"); + //~^ERROR: trivial regex + //~|HELP consider using `str::contains` + + let trivial_contains = Regex::new(NOT_A_REAL_REGEX); + //~^ERROR: trivial regex + //~|HELP consider using `str::contains` + + // unlikely corner cases + let trivial_empty = Regex::new(""); + //~^ERROR: trivial regex + //~|HELP the regex is unlikely to be useful + + let trivial_empty = Regex::new("^$"); + //~^ERROR: trivial regex + //~|HELP consider using `str::is_empty` + + // non-trivial regexes + let non_trivial_eq = Regex::new("^foo|bar$"); + let non_trivial_starts_with = Regex::new("^foo|bar"); + let non_trivial_ends_with = Regex::new("^foo|bar"); + let non_trivial_ends_with = Regex::new("foo|bar"); +} + +fn main() { + syntax_error(); + trivial_regex(); +} -- cgit 1.4.1-3-g733a5 From 13f245f6c951e6dca16dd02851237e5f271a31d0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 6 Feb 2016 00:13:29 +0100 Subject: Fix util/update_wiki.py warnings and be consistent in declare_lint! invocations --- src/attrs.rs | 12 +++-- src/cyclomatic_complexity.rs | 6 ++- src/drop_ref.rs | 6 ++- src/enum_variants.rs | 6 ++- src/escape.rs | 4 +- src/eta_reduction.rs | 6 ++- src/identity_op.rs | 6 ++- src/items_after_statements.rs | 6 ++- src/len_zero.rs | 14 ++++-- src/lifetimes.rs | 16 ++++-- src/loops.rs | 83 ++++++++++++++++++++++--------- src/map_clone.rs | 8 +-- src/matches.rs | 35 ++++++++----- src/methods.rs | 112 +++++++++++++++++++++++++++--------------- src/minmax.rs | 7 +-- src/misc.rs | 10 ++-- src/misc_early.rs | 12 +++-- src/mut_mut.rs | 9 ++-- src/panic.rs | 4 +- src/precedence.rs | 8 +-- src/returns.rs | 15 ++++-- src/shadow.rs | 20 +++++--- src/types.rs | 71 +++++++++++++++++--------- src/unicode.rs | 24 ++++++--- src/zero_div_zero.rs | 7 ++- 25 files changed, 341 insertions(+), 166 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 012c4e502b4..f224b7dff29 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -22,8 +22,10 @@ use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// #[inline(always)] /// fn not_quite_hot_code(..) { ... } /// ``` -declare_lint! { pub INLINE_ALWAYS, Warn, - "`#[inline(always)]` is a bad idea in most cases" } +declare_lint! { + pub INLINE_ALWAYS, Warn, + "`#[inline(always)]` is a bad idea in most cases" +} /// **What it does:** This lint `Warn`s on `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. /// @@ -36,8 +38,10 @@ declare_lint! { pub INLINE_ALWAYS, Warn, /// #[deprecated(since = "forever")] /// fn something_else(..) { ... } /// ``` -declare_lint! { pub DEPRECATED_SEMVER, Warn, - "`Warn` on `#[deprecated(since = \"x\")]` where x is not semver" } +declare_lint! { + pub DEPRECATED_SEMVER, Warn, + "`Warn` on `#[deprecated(since = \"x\")]` where x is not semver" +} #[derive(Copy,Clone)] pub struct AttrPass; diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index d4375abcd05..7eab7c1935f 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -18,8 +18,10 @@ use utils::{in_macro, LimitStack, span_help_and_lint}; /// **Known problems:** Sometimes it's hard to find a way to reduce the complexity /// /// **Example:** No. You'll see it when you get the warning. -declare_lint! { pub CYCLOMATIC_COMPLEXITY, Warn, - "finds functions that should be split up into multiple functions" } +declare_lint! { + pub CYCLOMATIC_COMPLEXITY, Warn, + "finds functions that should be split up into multiple functions" +} pub struct CyclomaticComplexity { limit: LimitStack, diff --git a/src/drop_ref.rs b/src/drop_ref.rs index c15689d8cd6..f7a0ca59f01 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -18,9 +18,11 @@ use utils::{match_def_path, span_note_and_lint}; /// std::mem::drop(&lock_guard) //Should have been drop(lock_guard), mutex still locked /// operation_that_requires_mutex_to_be_unlocked(); /// ``` -declare_lint!(pub DROP_REF, Warn, +declare_lint! { + pub DROP_REF, Warn, "call to `std::mem::drop` with a reference instead of an owned value, \ - which will not call the `Drop::drop` method on the underlying value"); + which will not call the `Drop::drop` method on the underlying value" +} #[allow(missing_copy_implementations)] pub struct DropRefPass; diff --git a/src/enum_variants.rs b/src/enum_variants.rs index bf0025e021c..8ceaca1bbf3 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -14,8 +14,10 @@ use utils::span_help_and_lint; /// **Known problems:** None /// /// **Example:** enum Cake { BlackForestCake, HummingbirdCake } -declare_lint! { pub ENUM_VARIANT_NAMES, Warn, - "finds enums where all variants share a prefix/postfix" } +declare_lint! { + pub ENUM_VARIANT_NAMES, Warn, + "finds enums where all variants share a prefix/postfix" +} pub struct EnumVariantNames; diff --git a/src/escape.rs b/src/escape.rs index 123b2b5c307..b7bec46c3fd 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -29,7 +29,9 @@ pub struct EscapePass; /// println!("{}", *x); /// } /// ``` -declare_lint!(pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary"); +declare_lint! { + pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary" +} fn is_non_trait_box(ty: ty::Ty) -> bool { match ty.sty { diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index fcc1a6893b2..39063f91ba3 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -16,8 +16,10 @@ pub struct EtaPass; /// **Known problems:** None /// /// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact argument type of `x`. -declare_lint!(pub REDUNDANT_CLOSURE, Warn, - "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"); +declare_lint! { + pub REDUNDANT_CLOSURE, Warn, + "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)" +} impl LintPass for EtaPass { fn get_lints(&self) -> LintArray { diff --git a/src/identity_op.rs b/src/identity_op.rs index 5fa9c7588cd..093c37783eb 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -12,8 +12,10 @@ use utils::{span_lint, snippet, in_macro}; /// **Known problems:** None /// /// **Example:** `x / 1 + 0 * 1 - 0 | 0` -declare_lint! { pub IDENTITY_OP, Warn, - "using identity operations, e.g. `x + 0` or `y / 1`" } +declare_lint! { + pub IDENTITY_OP, Warn, + "using identity operations, e.g. `x + 0` or `y / 1`" +} #[derive(Copy,Clone)] pub struct IdentityOp; diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index ad666a3bf3f..2f061d32546 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -27,7 +27,11 @@ use utils::in_macro; /// foo(); // prints "foo" /// } /// ``` -declare_lint! { pub ITEMS_AFTER_STATEMENTS, Warn, "finds blocks where an item comes after a statement" } +declare_lint! { + pub ITEMS_AFTER_STATEMENTS, + Warn, + "finds blocks where an item comes after a statement" +} pub struct ItemsAfterStatemets; diff --git a/src/len_zero.rs b/src/len_zero.rs index 6bc5bc4bf01..48fc10ef236 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -18,9 +18,11 @@ use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; /// **Known problems:** None /// /// **Example:** `if x.len() == 0 { .. }` -declare_lint!(pub LEN_ZERO, Warn, - "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ - could be used instead"); +declare_lint! { + pub LEN_ZERO, Warn, + "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ + could be used instead" +} /// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. It is `Warn` by default. /// @@ -34,8 +36,10 @@ declare_lint!(pub LEN_ZERO, Warn, /// fn len(&self) -> usize { .. } /// } /// ``` -declare_lint!(pub LEN_WITHOUT_IS_EMPTY, Warn, - "traits and impls that have `.len()` but not `.is_empty()`"); +declare_lint! { + pub LEN_WITHOUT_IS_EMPTY, Warn, + "traits and impls that have `.len()` but not `.is_empty()`" +} #[derive(Copy,Clone)] pub struct LenZero; diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 3e9880d5932..f2f33a634bc 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -15,9 +15,12 @@ use utils::{in_external_macro, span_lint}; /// **Known problems:** Potential false negatives: we bail out if the function has a `where` clause where lifetimes are mentioned. /// /// **Example:** `fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }` -declare_lint!(pub NEEDLESS_LIFETIMES, Warn, - "using explicit lifetimes for references in function arguments when elision rules \ - would allow omitting them"); +declare_lint! { + pub NEEDLESS_LIFETIMES, + Warn, + "using explicit lifetimes for references in function arguments when elision rules \ + would allow omitting them" +} /// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. It is `Warn` by default. /// @@ -26,8 +29,11 @@ declare_lint!(pub NEEDLESS_LIFETIMES, Warn, /// **Known problems:** None /// /// **Example:** `fn unused_lifetime<'a>(x: u8) { .. }` -declare_lint!(pub UNUSED_LIFETIMES, Warn, - "unused lifetimes in function definitions"); +declare_lint! { + pub UNUSED_LIFETIMES, + Warn, + "unused lifetimes in function definitions" +} #[derive(Copy,Clone)] pub struct LifetimePass; diff --git a/src/loops.rs b/src/loops.rs index 3f430a1aaf0..bfd0e9895e5 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -25,8 +25,11 @@ use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_ /// println!("{}", vec[i]); /// } /// ``` -declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, - "for-looping over a range of indices where an iterator over items would do" } +declare_lint! { + pub NEEDLESS_RANGE_LOOP, + Warn, + "for-looping over a range of indices where an iterator over items would do" +} /// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. It is `Warn` by default. /// @@ -35,8 +38,11 @@ declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn, /// **Known problems:** False negatives. We currently only warn on some known types. /// /// **Example:** `for x in y.iter() { .. }` (where y is a `Vec` or slice) -declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, - "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" } +declare_lint! { + pub EXPLICIT_ITER_LOOP, + Warn, + "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" +} /// **What it does:** This lint checks for loops on `x.next()`. It is `Warn` by default. /// @@ -45,8 +51,11 @@ declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn, /// **Known problems:** None /// /// **Example:** `for x in y.next() { .. }` -declare_lint!{ pub ITER_NEXT_LOOP, Warn, - "for-looping over `_.next()` which is probably not intended" } +declare_lint! { + pub ITER_NEXT_LOOP, + Warn, + "for-looping over `_.next()` which is probably not intended" +} /// **What it does:** This lint checks for `for` loops over `Option` values. It is `Warn` by default. /// @@ -55,8 +64,11 @@ declare_lint!{ pub ITER_NEXT_LOOP, Warn, /// **Known problems:** None /// /// **Example:** `for x in option { .. }`. This should be `if let Some(x) = option { .. }`. -declare_lint!{ pub FOR_LOOP_OVER_OPTION, Warn, - "for-looping over an `Option`, which is more clearly expressed as an `if let`" } +declare_lint! { + pub FOR_LOOP_OVER_OPTION, + Warn, + "for-looping over an `Option`, which is more clearly expressed as an `if let`" +} /// **What it does:** This lint checks for `for` loops over `Result` values. It is `Warn` by default. /// @@ -65,8 +77,11 @@ declare_lint!{ pub FOR_LOOP_OVER_OPTION, Warn, /// **Known problems:** None /// /// **Example:** `for x in result { .. }`. This should be `if let Ok(x) = result { .. }`. -declare_lint!{ pub FOR_LOOP_OVER_RESULT, Warn, - "for-looping over a `Result`, which is more clearly expressed as an `if let`" } +declare_lint! { + pub FOR_LOOP_OVER_RESULT, + Warn, + "for-looping over a `Result`, which is more clearly expressed as an `if let`" +} /// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. /// @@ -89,8 +104,11 @@ declare_lint!{ pub FOR_LOOP_OVER_RESULT, Warn, /// // .. do something with x /// } /// ``` -declare_lint!{ pub WHILE_LET_LOOP, Warn, - "`loop { if let { ... } else break }` can be written as a `while let` loop" } +declare_lint! { + pub WHILE_LET_LOOP, + Warn, + "`loop { if let { ... } else break }` can be written as a `while let` loop" +} /// **What it does:** This lint checks for using `collect()` on an iterator without using the result. It is `Warn` by default. /// @@ -99,9 +117,12 @@ declare_lint!{ pub WHILE_LET_LOOP, Warn, /// **Known problems:** None /// /// **Example:** `vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();` -declare_lint!{ pub UNUSED_COLLECT, Warn, - "`collect()`ing an iterator without using the result; this is usually better \ - written as a for loop" } +declare_lint! { + pub UNUSED_COLLECT, + Warn, + "`collect()`ing an iterator without using the result; this is usually better \ + written as a for loop" +} /// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. It is `Warn` by default. /// @@ -110,8 +131,11 @@ declare_lint!{ pub UNUSED_COLLECT, Warn, /// **Known problems:** The lint cannot catch loops over dynamically defined ranges. Doing this would require simulating all possible inputs and code paths through the program, which would be complex and error-prone. /// /// **Examples**: `for x in 5..10-5 { .. }` (oops, stray `-`) -declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, - "Iterating over an empty range, such as `10..0` or `5..5`" } +declare_lint! { + pub REVERSE_RANGE_LOOP, + Warn, + "Iterating over an empty range, such as `10..0` or `5..5`" +} /// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. It is `Warn` by default. /// @@ -120,8 +144,11 @@ declare_lint!{ pub REVERSE_RANGE_LOOP, Warn, /// **Known problems:** None. /// /// **Example:** `for i in 0..v.len() { foo(v[i]); }` or `for i in 0..v.len() { bar(i, v[i]); }` -declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, - "for-looping with an explicit counter when `_.enumerate()` would do" } +declare_lint! { + pub EXPLICIT_COUNTER_LOOP, + Warn, + "for-looping with an explicit counter when `_.enumerate()` would do" +} /// **What it does:** This lint checks for empty `loop` expressions. It is `Warn` by default. /// @@ -130,7 +157,11 @@ declare_lint!{ pub EXPLICIT_COUNTER_LOOP, Warn, /// **Known problems:** None /// /// **Example:** `loop {}` -declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } +declare_lint! { + pub EMPTY_LOOP, + Warn, + "empty `loop {}` detected" +} /// **What it does:** This lint checks for `while let` expressions on iterators. It is `Warn` by default. /// @@ -139,7 +170,11 @@ declare_lint!{ pub EMPTY_LOOP, Warn, "empty `loop {}` detected" } /// **Known problems:** None /// /// **Example:** `while let Some(val) = iter() { .. }` -declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead of a for loop on an iterator" } +declare_lint! { + pub WHILE_LET_ON_ITERATOR, + Warn, + "using a while-let loop instead of a for loop on an iterator" +} /// **What it does:** This warns when you iterate on a map (`HashMap` or `BTreeMap`) and ignore /// either the keys or values. @@ -157,7 +192,11 @@ declare_lint!{ pub WHILE_LET_ON_ITERATOR, Warn, "using a while-let loop instead /// ```rust /// for k in map.keys() { .. } /// ``` -declare_lint!{ pub FOR_KV_MAP, Warn, "looping on a map using `iter` when `keys` or `values` would do" } +declare_lint! { + pub FOR_KV_MAP, + Warn, + "looping on a map using `iter` when `keys` or `values` would do" +} #[derive(Copy, Clone)] pub struct LoopsPass; diff --git a/src/map_clone.rs b/src/map_clone.rs index 9db97a1b9f2..d4773986399 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -11,9 +11,11 @@ use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; /// **Known problems:** None /// /// **Example:** `x.map(|e| e.clone());` -declare_lint!(pub MAP_CLONE, Warn, - "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ - `.cloned()` instead)"); +declare_lint! { + pub MAP_CLONE, Warn, + "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ + `.cloned()` instead)" +} #[derive(Copy, Clone)] pub struct MapClonePass; diff --git a/src/matches.rs b/src/matches.rs index e690f04bdb0..fb0663117fa 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -24,9 +24,11 @@ use utils::{match_type, snippet, span_lint, span_note_and_lint, span_lint_and_th /// _ => () /// } /// ``` -declare_lint!(pub SINGLE_MATCH, Warn, - "a match statement with a single nontrivial arm (i.e, where the other arm \ - is `_ => {}`) is used; recommends `if let` instead"); +declare_lint! { + pub SINGLE_MATCH, Warn, + "a match statement with a single nontrivial arm (i.e, where the other arm \ + is `_ => {}`) is used; recommends `if let` instead" +} /// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. It is `Allow` by default. /// @@ -41,9 +43,11 @@ declare_lint!(pub SINGLE_MATCH, Warn, /// _ => bar(other_ref), /// } /// ``` -declare_lint!(pub SINGLE_MATCH_ELSE, Allow, - "a match statement with a two arms where the second arm's pattern is a wildcard; \ - recommends `if let` instead"); +declare_lint! { + pub SINGLE_MATCH_ELSE, Allow, + "a match statement with a two arms where the second arm's pattern is a wildcard; \ + recommends `if let` instead" +} /// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. It is `Warn` by default. /// @@ -60,9 +64,11 @@ declare_lint!(pub SINGLE_MATCH_ELSE, Allow, /// _ => frob(&x), /// } /// ``` -declare_lint!(pub MATCH_REF_PATS, Warn, - "a match or `if let` has all arms prefixed with `&`; the match expression can be \ - dereferenced instead"); +declare_lint! { + pub MATCH_REF_PATS, Warn, + "a match or `if let` has all arms prefixed with `&`; the match expression can be \ + dereferenced instead" +} /// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. It is `Warn` by default. /// @@ -79,8 +85,10 @@ declare_lint!(pub MATCH_REF_PATS, Warn, /// false => bar(), /// } /// ``` -declare_lint!(pub MATCH_BOOL, Warn, - "a match on boolean expression; recommends `if..else` block instead"); +declare_lint! { + pub MATCH_BOOL, Warn, + "a match on boolean expression; recommends `if..else` block instead" +} /// **What it does:** This lint checks for overlapping match arms. It is `Warn` by default. /// @@ -98,8 +106,9 @@ declare_lint!(pub MATCH_BOOL, Warn, /// _ => (), /// } /// ``` -declare_lint!(pub MATCH_OVERLAPPING_ARM, Warn, - "a match has overlapping arms"); +declare_lint! { + pub MATCH_OVERLAPPING_ARM, Warn, "a match has overlapping arms" +} #[allow(missing_copy_implementations)] pub struct MatchPass; diff --git a/src/methods.rs b/src/methods.rs index 61a910a65ab..4cd957d0fe7 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -25,8 +25,10 @@ pub struct MethodsPass; /// **Known problems:** None /// /// **Example:** `x.unwrap()` -declare_lint!(pub OPTION_UNWRAP_USED, Allow, - "using `Option.unwrap()`, which should at least get a better message using `expect()`"); +declare_lint! { + pub OPTION_UNWRAP_USED, Allow, + "using `Option.unwrap()`, which should at least get a better message using `expect()`" +} /// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. It is `Allow` by default. /// @@ -37,8 +39,10 @@ declare_lint!(pub OPTION_UNWRAP_USED, Allow, /// **Known problems:** None /// /// **Example:** `x.unwrap()` -declare_lint!(pub RESULT_UNWRAP_USED, Allow, - "using `Result.unwrap()`, which might be better handled"); +declare_lint! { + pub RESULT_UNWRAP_USED, Allow, + "using `Result.unwrap()`, which might be better handled" +} /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. It is `Warn` by default. /// @@ -47,8 +51,10 @@ declare_lint!(pub RESULT_UNWRAP_USED, Allow, /// **Known problems:** None /// /// **Example:** `s.to_string()` where `s: &str` -declare_lint!(pub STR_TO_STRING, Warn, - "using `to_string()` on a str, which should be `to_owned()`"); +declare_lint! { + pub STR_TO_STRING, Warn, + "using `to_string()` on a str, which should be `to_owned()`" +} /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default. /// @@ -58,8 +64,10 @@ declare_lint!(pub STR_TO_STRING, Warn, /// **Known problems:** None /// /// **Example:** `s.to_string()` where `s: String` -declare_lint!(pub STRING_TO_STRING, Warn, - "calling `String::to_string` which is inefficient"); +declare_lint! { + pub STRING_TO_STRING, Warn, + "calling `String::to_string` which is inefficient" +} /// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default. /// @@ -74,8 +82,10 @@ declare_lint!(pub STRING_TO_STRING, Warn, /// fn add(&self, other: &X) -> X { .. } /// } /// ``` -declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, - "defining a method that should be implementing a std trait"); +declare_lint! { + pub SHOULD_IMPLEMENT_TRAIT, Warn, + "defining a method that should be implementing a std trait" +} /// **What it does:** This lint checks for methods with certain name prefixes and `Warn`s (by default) if the prefix doesn't match how self is taken. The actual rules are: /// @@ -98,9 +108,11 @@ declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn, /// fn as_str(self) -> &str { .. } /// } /// ``` -declare_lint!(pub WRONG_SELF_CONVENTION, Warn, - "defining a method named with an established prefix (like \"into_\") that takes \ - `self` with the wrong convention"); +declare_lint! { + pub WRONG_SELF_CONVENTION, Warn, + "defining a method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention" +} /// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. This lint is `Allow` by default. /// @@ -114,9 +126,11 @@ declare_lint!(pub WRONG_SELF_CONVENTION, Warn, /// pub fn as_str(self) -> &str { .. } /// } /// ``` -declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, - "defining a public method named with an established prefix (like \"into_\") that takes \ - `self` with the wrong convention"); +declare_lint! { + pub WRONG_PUB_SELF_CONVENTION, Allow, + "defining a public method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention" +} /// **What it does:** This lint `Warn`s on using `ok().expect(..)`. /// @@ -125,9 +139,11 @@ declare_lint!(pub WRONG_PUB_SELF_CONVENTION, Allow, /// **Known problems:** None. /// /// **Example:** `x.ok().expect("why did I do this again?")` -declare_lint!(pub OK_EXPECT, Warn, - "using `ok().expect()`, which gives worse error messages than \ - calling `expect` directly on the Result"); +declare_lint! { + pub OK_EXPECT, Warn, + "using `ok().expect()`, which gives worse error messages than \ + calling `expect` directly on the Result" +} /// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or(_)`. /// @@ -136,9 +152,11 @@ declare_lint!(pub OK_EXPECT, Warn, /// **Known problems:** None. /// /// **Example:** `x.map(|a| a + 1).unwrap_or(0)` -declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, - "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ - `map_or(a, f)`"); +declare_lint! { + pub OPTION_MAP_UNWRAP_OR, Warn, + "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ + `map_or(a, f)`" +} /// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`. /// @@ -147,9 +165,11 @@ declare_lint!(pub OPTION_MAP_UNWRAP_OR, Warn, /// **Known problems:** None. /// /// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)` -declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, - "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ - `map_or_else(g, f)`"); +declare_lint! { + pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, + "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ + `map_or_else(g, f)`" +} /// **What it does:** This lint `Warn`s on `_.filter(_).next()`. /// @@ -158,8 +178,10 @@ declare_lint!(pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, /// **Known problems:** None. /// /// **Example:** `iter.filter(|x| x == 0).next()` -declare_lint!(pub FILTER_NEXT, Warn, - "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"); +declare_lint! { + pub FILTER_NEXT, Warn, + "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`" +} /// **What it does:** This lint `Warn`s on an iterator search (such as `find()`, `position()`, or /// `rposition()`) followed by a call to `is_some()`. @@ -169,9 +191,11 @@ declare_lint!(pub FILTER_NEXT, Warn, /// **Known problems:** None. /// /// **Example:** `iter.find(|x| x == 0).is_some()` -declare_lint!(pub SEARCH_IS_SOME, Warn, - "using an iterator search followed by `is_some()`, which is more succinctly \ - expressed as a call to `any()`"); +declare_lint! { + pub SEARCH_IS_SOME, Warn, + "using an iterator search followed by `is_some()`, which is more succinctly \ + expressed as a call to `any()`" +} /// **What it does:** This lint `Warn`s on using `.chars().next()` on a `str` to check if it /// starts with a given char. @@ -181,8 +205,10 @@ declare_lint!(pub SEARCH_IS_SOME, Warn, /// **Known problems:** None. /// /// **Example:** `name.chars().next() == Some('_')` -declare_lint!(pub CHARS_NEXT_CMP, Warn, - "using `.chars().next()` to check if a string starts with a char"); +declare_lint! { + pub CHARS_NEXT_CMP, Warn, + "using `.chars().next()` to check if a string starts with a char" +} /// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and /// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead. @@ -203,8 +229,10 @@ declare_lint!(pub CHARS_NEXT_CMP, Warn, /// /// **Known problems:** If the function as side-effects, not calling it will change the semantic of /// the program, but you shouldn't rely on that anyway. -declare_lint!(pub OR_FUN_CALL, Warn, - "using any `*or` method when the `*or_else` would do"); +declare_lint! { + pub OR_FUN_CALL, Warn, + "using any `*or` method when the `*or_else` would do" +} /// **What it does:** This lint `Warn`s on using `.extend(s)` on a `vec` to extend the vec by a slice. /// @@ -213,8 +241,10 @@ declare_lint!(pub OR_FUN_CALL, Warn, /// **Known problems:** None. /// /// **Example:** `my_vec.extend(&xs)` -declare_lint!(pub EXTEND_FROM_SLICE, Warn, - "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"); +declare_lint! { + pub EXTEND_FROM_SLICE, Warn, + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice" +} /// **What it does:** This lint warns on using `.clone()` on a `Copy` type. /// @@ -224,8 +254,9 @@ declare_lint!(pub EXTEND_FROM_SLICE, Warn, /// **Known problems:** None. /// /// **Example:** `42u64.clone()` -declare_lint!(pub CLONE_ON_COPY, Warn, - "using `clone` on a `Copy` type"); +declare_lint! { + pub CLONE_ON_COPY, Warn, "using `clone` on a `Copy` type" +} /// **What it does:** This lint warns on using `.clone()` on an `&&T` /// @@ -244,8 +275,9 @@ declare_lint!(pub CLONE_ON_COPY, Warn, /// } /// ``` /// -declare_lint!(pub CLONE_DOUBLE_REF, Warn, - "using `clone` on `&&T`"); +declare_lint! { + pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`" +} impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { diff --git a/src/minmax.rs b/src/minmax.rs index e72f2392054..2e199345579 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -15,9 +15,10 @@ use self::MinMax::{Min, Max}; /// **Known problems:** None /// /// **Example:** `min(0, max(100, x))` will always be equal to `0`. Probably the author meant to clamp the value between 0 and 100, but has erroneously swapped `min` and `max`. -declare_lint!(pub MIN_MAX, Warn, - "`min(_, max(_, _))` (or vice versa) with bounds clamping the result \ - to a constant"); +declare_lint! { + pub MIN_MAX, Warn, + "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant" +} #[allow(missing_copy_implementations)] pub struct MinMaxPass; diff --git a/src/misc.rs b/src/misc.rs index d436d98c981..099b1797e8e 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -22,10 +22,12 @@ use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal, implements_tra /// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function. /// /// **Example:** `fn foo(ref x: u8) -> bool { .. }` -declare_lint!(pub TOPLEVEL_REF_ARG, Warn, - "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ - or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ - references with `&`."); +declare_lint! { + pub TOPLEVEL_REF_ARG, Warn, + "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ + or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ + references with `&`." +} #[allow(missing_copy_implementations)] pub struct TopLevelRefPass; diff --git a/src/misc_early.rs b/src/misc_early.rs index 1573aff2a4d..de3c4289353 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -15,8 +15,10 @@ use utils::{span_lint, span_help_and_lint}; /// **Known problems:** None. /// /// **Example:** `let { a: _, b: ref b, c: _ } = ..` -declare_lint!(pub UNNEEDED_FIELD_PATTERN, Warn, - "Struct fields are bound to a wildcard instead of using `..`"); +declare_lint! { + pub UNNEEDED_FIELD_PATTERN, Warn, + "Struct fields are bound to a wildcard instead of using `..`" +} /// **What it does:** This lint `Warn`s on function arguments having the similar names differing by an underscore /// @@ -25,8 +27,10 @@ declare_lint!(pub UNNEEDED_FIELD_PATTERN, Warn, /// **Known problems:** None. /// /// **Example:** `fn foo(a: i32, _a: i32) {}` -declare_lint!(pub DUPLICATE_UNDERSCORE_ARGUMENT, Warn, - "Function arguments having names which only differ by an underscore"); +declare_lint! { + pub DUPLICATE_UNDERSCORE_ARGUMENT, Warn, + "Function arguments having names which only differ by an underscore" +} #[derive(Copy, Clone)] pub struct MiscEarly; diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 4623ca38533..99c1d040fd2 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -11,9 +11,12 @@ use utils::{in_external_macro, span_lint}; /// **Known problems:** None /// /// **Example:** `let x = &mut &mut y;` -declare_lint!(pub MUT_MUT, Allow, - "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ - or shows a fundamental misunderstanding of references)"); +declare_lint! { + pub MUT_MUT, + Allow, + "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ + or shows a fundamental misunderstanding of references)" +} #[derive(Copy,Clone)] pub struct MutMut; diff --git a/src/panic.rs b/src/panic.rs index 40d6e7d4dff..dc30f710830 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -13,7 +13,9 @@ use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; /// ``` /// panic!("This panic! is probably missing a parameter there: {}"); /// ``` -declare_lint!(pub PANIC_PARAMS, Warn, "missing parameters in `panic!`"); +declare_lint! { + pub PANIC_PARAMS, Warn, "missing parameters in `panic!`" +} #[allow(missing_copy_implementations)] pub struct PanicPass; diff --git a/src/precedence.rs b/src/precedence.rs index 8253471f8b0..a316f183863 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -15,9 +15,11 @@ use utils::{span_lint, snippet}; /// **Examples:** /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 -declare_lint!(pub PRECEDENCE, Warn, - "catches operations where precedence may be unclear. See the wiki for a \ - list of cases caught"); +declare_lint! { + pub PRECEDENCE, Warn, + "catches operations where precedence may be unclear. See the wiki for a \ + list of cases caught" +} #[derive(Copy,Clone)] pub struct Precedence; diff --git a/src/returns.rs b/src/returns.rs index e4745b8766f..0b0c4d14bdf 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -13,8 +13,11 @@ use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_exter /// **Known problems:** None /// /// **Example:** `fn foo(x: usize) { return x; }` -declare_lint!(pub NEEDLESS_RETURN, Warn, - "using a return statement like `return expr;` where an expression would suffice"); +declare_lint! { + pub NEEDLESS_RETURN, Warn, + "using a return statement like `return expr;` where an expression would suffice" +} + /// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. It is `Warn` by default. /// /// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. @@ -22,9 +25,11 @@ declare_lint!(pub NEEDLESS_RETURN, Warn, /// **Known problems:** None /// /// **Example:** `{ let x = ..; x }` -declare_lint!(pub LET_AND_RETURN, Warn, - "creating a let-binding and then immediately returning it like `let x = expr; x` at \ - the end of a block"); +declare_lint! { + pub LET_AND_RETURN, Warn, + "creating a let-binding and then immediately returning it like `let x = expr; x` at \ + the end of a block" +} #[derive(Copy, Clone)] pub struct ReturnPass; diff --git a/src/shadow.rs b/src/shadow.rs index 1beb00e9056..f772f97c81e 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -16,8 +16,11 @@ use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_not /// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. /// /// **Example:** `let x = &x;` -declare_lint!(pub SHADOW_SAME, Allow, - "rebinding a name to itself, e.g. `let mut x = &mut x`"); +declare_lint! { + pub SHADOW_SAME, Allow, + "rebinding a name to itself, e.g. `let mut x = &mut x`" +} + /// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. It is `Allow` by default. /// /// **Why is this bad?** Not too much, in fact it's a common pattern in Rust code. Still, some argue that name shadowing like this hurts readability, because a value may be bound to different things depending on position in the code. @@ -25,9 +28,12 @@ declare_lint!(pub SHADOW_SAME, Allow, /// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. /// /// **Example:** `let x = x + 1;` -declare_lint!(pub SHADOW_REUSE, Allow, +declare_lint! { + pub SHADOW_REUSE, Allow, "rebinding a name to an expression that re-uses the original value, e.g. \ - `let x = x + 1`"); + `let x = x + 1`" +} + /// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. This lint is `Warn` by default. /// /// **Why is this bad?** Name shadowing can hurt readability, especially in large code bases, because it is easy to lose track of the active binding at any place in the code. This can be alleviated by either giving more specific names to bindings ore introducing more scopes to contain the bindings. @@ -35,8 +41,10 @@ declare_lint!(pub SHADOW_REUSE, Allow, /// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. /// /// **Example:** `let x = y; let x = z; // shadows the earlier binding` -declare_lint!(pub SHADOW_UNRELATED, Allow, - "The name is re-bound without even using the original value"); +declare_lint! { + pub SHADOW_UNRELATED, Allow, + "The name is re-bound without even using the original value" +} #[derive(Copy, Clone)] pub struct ShadowPass; diff --git a/src/types.rs b/src/types.rs index 0ab373bfa35..bb1201547b3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,8 +22,10 @@ pub struct TypePass; /// **Known problems:** None /// /// **Example:** `struct X { values: Box<Vec<Foo>> }` -declare_lint!(pub BOX_VEC, Warn, - "usage of `Box<Vec<T>>`, vector elements are already on the heap"); +declare_lint! { + pub BOX_VEC, Warn, + "usage of `Box<Vec<T>>`, vector elements are already on the heap" +} /// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). It is `Warn` by default. /// @@ -36,9 +38,11 @@ declare_lint!(pub BOX_VEC, Warn, /// **Known problems:** False positives – the instances where using a `LinkedList` makes sense are few and far between, but they can still happen. /// /// **Example:** `let x = LinkedList::new();` -declare_lint!(pub LINKEDLIST, Warn, - "usage of LinkedList, usually a vector is faster, or a more specialized data \ - structure like a VecDeque"); +declare_lint! { + pub LINKEDLIST, Warn, + "usage of LinkedList, usually a vector is faster, or a more specialized data \ + structure like a VecDeque" +} impl LintPass for TypePass { fn get_lints(&self) -> LintArray { @@ -81,8 +85,10 @@ pub struct LetPass; /// **Known problems:** None /// /// **Example:** `let x = { 1; };` -declare_lint!(pub LET_UNIT_VALUE, Warn, - "creating a let binding to a value of unit type, which usually can't be used afterwards"); +declare_lint! { + pub LET_UNIT_VALUE, Warn, + "creating a let binding to a value of unit type, which usually can't be used afterwards" +} fn check_let_unit(cx: &LateContext, decl: &Decl) { if let DeclLocal(ref local) = decl.node { @@ -122,8 +128,10 @@ impl LateLintPass for LetPass { /// **Known problems:** None /// /// **Example:** `if { foo(); } == { bar(); } { baz(); }` is equal to `{ foo(); bar(); baz(); }` -declare_lint!(pub UNIT_CMP, Warn, - "comparing unit values (which is always `true` or `false`, respectively)"); +declare_lint! { + pub UNIT_CMP, Warn, + "comparing unit values (which is always `true` or `false`, respectively)" +} #[allow(missing_copy_implementations)] pub struct UnitCmp; @@ -169,8 +177,11 @@ pub struct CastPass; /// **Known problems:** None /// /// **Example:** `let x = u64::MAX; x as f64` -declare_lint!(pub CAST_PRECISION_LOSS, Allow, - "casts that cause loss of precision, e.g `x as f32` where `x: u64`"); +declare_lint! { + pub CAST_PRECISION_LOSS, Allow, + "casts that cause loss of precision, e.g `x as f32` where `x: u64`" +} + /// **What it does:** This lint checks for casts from a signed to an unsigned numerical type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default. /// /// **Why is this bad?** Possibly surprising results. You can activate this lint as a one-time check to see where numerical wrapping can arise. @@ -178,8 +189,11 @@ declare_lint!(pub CAST_PRECISION_LOSS, Allow, /// **Known problems:** None /// /// **Example:** `let y : i8 = -1; y as u64` will return 18446744073709551615 -declare_lint!(pub CAST_SIGN_LOSS, Allow, - "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`"); +declare_lint! { + pub CAST_SIGN_LOSS, Allow, + "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`" +} + /// **What it does:** This lint checks for on casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by default. /// /// **Why is this bad?** In some problem domains, it is good practice to avoid truncation. This lint can be activated to help assess where additional checks could be beneficial. @@ -187,8 +201,11 @@ declare_lint!(pub CAST_SIGN_LOSS, Allow, /// **Known problems:** None /// /// **Example:** `fn as_u8(x: u64) -> u8 { x as u8 }` -declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, - "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`"); +declare_lint! { + pub CAST_POSSIBLE_TRUNCATION, Allow, + "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`" +} + /// **What it does:** This lint checks for casts from an unsigned type to a signed type of the same size. Performing such a cast is a 'no-op' for the compiler, i.e. nothing is changed at the bit level, and the binary representation of the value is reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default. /// /// **Why is this bad?** While such a cast is not bad in itself, the results can be surprising when this is not the intended behavior, as demonstrated by the example below. @@ -196,8 +213,10 @@ declare_lint!(pub CAST_POSSIBLE_TRUNCATION, Allow, /// **Known problems:** None /// /// **Example:** `u32::MAX as i32` will yield a value of `-1`. -declare_lint!(pub CAST_POSSIBLE_WRAP, Allow, - "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`"); +declare_lint! { + pub CAST_POSSIBLE_WRAP, Allow, + "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`" +} /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant @@ -393,8 +412,10 @@ impl LateLintPass for CastPass { /// **Known problems:** None /// /// **Example:** `struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }` -declare_lint!(pub TYPE_COMPLEXITY, Warn, - "usage of very complex types; recommends factoring out parts into `type` definitions"); +declare_lint! { + pub TYPE_COMPLEXITY, Warn, + "usage of very complex types; recommends factoring out parts into `type` definitions" +} #[allow(missing_copy_implementations)] pub struct TypeComplexityPass; @@ -525,8 +546,10 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { /// **Known problems:** None /// /// **Example:** `'x' as u8` -declare_lint!(pub CHAR_LIT_AS_U8, Warn, - "Casting a character literal to u8"); +declare_lint! { + pub CHAR_LIT_AS_U8, Warn, + "Casting a character literal to u8" +} pub struct CharLitAsU8; @@ -565,8 +588,10 @@ impl LateLintPass for CharLitAsU8 { /// **Known problems:** None /// /// **Example:** `vec.len() <= 0` -declare_lint!(pub ABSURD_UNSIGNED_COMPARISONS, Warn, - "testing whether an unsigned integer is non-positive"); +declare_lint! { + pub ABSURD_UNSIGNED_COMPARISONS, Warn, + "testing whether an unsigned integer is non-positive" +} pub struct AbsurdUnsignedComparisons; diff --git a/src/unicode.rs b/src/unicode.rs index d5ea7199e10..92d365f0323 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -15,8 +15,11 @@ use utils::{snippet, span_help_and_lint}; /// **Known problems:** None /// /// **Example:** You don't see it, but there may be a zero-width space somewhere in this text. -declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, - "using a zero-width space in a string literal, which is confusing" } +declare_lint! { + pub ZERO_WIDTH_SPACE, Deny, + "using a zero-width space in a string literal, which is confusing" +} + /// **What it does:** This lint checks for non-ascii characters in string literals. It is `Allow` by default. /// /// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset back. Even so, there still are editors and other programs out there that don't work well with unicode. So if the code is meant to be used internationally, on multiple operating systems, or has other portability requirements, activating this lint could be useful. @@ -24,9 +27,12 @@ declare_lint!{ pub ZERO_WIDTH_SPACE, Deny, /// **Known problems:** None /// /// **Example:** `let x = "Hä?"` -declare_lint!{ pub NON_ASCII_LITERAL, Allow, - "using any literal non-ASCII chars in a string literal; suggests \ - using the \\u escape instead" } +declare_lint! { + pub NON_ASCII_LITERAL, Allow, + "using any literal non-ASCII chars in a string literal; suggests \ + using the \\u escape instead" +} + /// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). This lint is `Allow` by default. /// /// **Why is this bad?** If such a string is compared to another, the results may be surprising. @@ -34,9 +40,11 @@ declare_lint!{ pub NON_ASCII_LITERAL, Allow, /// **Known problems** None /// /// **Example:** You may not see it, but "à" and "à" aren't the same string. The former when escaped is actually "a\u{300}" while the latter is "\u{e0}". -declare_lint!{ pub UNICODE_NOT_NFC, Allow, - "using a unicode literal not in NFC normal form (see \ - http://www.unicode.org/reports/tr15/ for further information)" } +declare_lint! { + pub UNICODE_NOT_NFC, Allow, + "using a unicode literal not in NFC normal form (see \ + http://www.unicode.org/reports/tr15/ for further information)" +} #[derive(Copy, Clone)] diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 2c3ec86936c..9c5c07cd678 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -16,8 +16,11 @@ pub struct ZeroDivZeroPass; /// **Known problems:** None /// /// **Example** `0.0f32 / 0.0` -declare_lint!(pub ZERO_DIVIDED_BY_ZERO, Warn, - "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN"); +declare_lint! { + pub ZERO_DIVIDED_BY_ZERO, + Warn, + "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN" +} impl LintPass for ZeroDivZeroPass { fn get_lints(&self) -> LintArray { -- cgit 1.4.1-3-g733a5 From 83a82a1d86b0a5b9fe39ca7b33e7bca2687a733b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 6 Feb 2016 00:41:54 +0100 Subject: Remove redundancy in lint documentation The default level is always given in the declare_lint! macro, no need to add it inconsistently in the documentation. --- src/approx_const.rs | 2 +- src/attrs.rs | 4 ++-- src/bit_mask.rs | 4 +--- src/block_in_if_condition.rs | 4 ++-- src/collapsible_if.rs | 2 +- src/cyclomatic_complexity.rs | 2 +- src/drop_ref.rs | 2 +- src/eq_op.rs | 2 +- src/escape.rs | 2 +- src/eta_reduction.rs | 2 +- src/identity_op.rs | 2 +- src/items_after_statements.rs | 3 +-- src/len_zero.rs | 4 ++-- src/lifetimes.rs | 4 ++-- src/loops.rs | 22 +++++++++++----------- src/map_clone.rs | 2 +- src/matches.rs | 10 +++++----- src/methods.rs | 22 +++++++++++----------- src/minmax.rs | 2 +- src/misc.rs | 12 ++++++------ src/misc_early.rs | 4 ++-- src/mut_mut.rs | 2 +- src/mut_reference.rs | 2 +- src/mutex_atomic.rs | 4 ++-- src/needless_bool.rs | 2 +- src/needless_features.rs | 4 ++-- src/needless_update.rs | 2 +- src/no_effect.rs | 2 +- src/open_options.rs | 2 +- src/panic.rs | 4 ++-- src/precedence.rs | 2 +- src/print.rs | 3 +-- src/ptr_arg.rs | 2 +- src/ranges.rs | 4 ++-- src/regex.rs | 2 +- src/returns.rs | 4 ++-- src/shadow.rs | 6 +++--- src/strings.rs | 6 +++--- src/temporary_assignment.rs | 4 ++-- src/transmute.rs | 2 +- src/types.rs | 12 ++++++------ src/unicode.rs | 6 +++--- src/vec.rs | 1 - src/zero_div_zero.rs | 8 ++++---- 44 files changed, 97 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 2c8779ae737..98e2fa97eba 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -6,7 +6,7 @@ use syntax::ast::Lit_::*; use syntax::ast::Lit; use syntax::ast::FloatTy::*; -/// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. This lint is `Warn` by default. +/// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. /// /// **Why is this bad?** Usually, the definition in the standard library is more precise than what people come up with. If you find that your definition is actually more precise, please [file a Rust issue](https://github.com/rust-lang/rust/issues). /// diff --git a/src/attrs.rs b/src/attrs.rs index f224b7dff29..231a08779cc 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -9,7 +9,7 @@ use syntax::attr::*; use syntax::ast::{Attribute, Lit, Lit_, MetaList, MetaWord, MetaNameValue}; use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; -/// **What it does:** This lint `Warn`s on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. +/// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. /// /// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it. /// @@ -27,7 +27,7 @@ declare_lint! { "`#[inline(always)]` is a bad idea in most cases" } -/// **What it does:** This lint `Warn`s on `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. +/// **What it does:** This lint checks for `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. /// /// **Why is this bad?** For checking the version of the deprecation, it must be valid semver. Failing that, the contained information is useless. /// diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 0fce772010a..b9925f10fa2 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -8,7 +8,7 @@ use syntax::ast::Lit_::*; use utils::span_lint; -/// **What it does:** This lint checks for incompatible bit masks in comparisons. It is `Warn` by default. +/// **What it does:** This lint checks for incompatible bit masks in comparisons. /// /// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` /// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: @@ -43,8 +43,6 @@ declare_lint! { /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| /// -/// This lint is `Warn` by default. -/// /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask), but still a bit misleading, because the bit mask is ineffective. /// /// **Known problems:** False negatives: This lint will only match instances where we have figured out the math (which is for a power-of-two compared value). This means things like `x | 1 >= 7` (which would be better written as `x >= 6`) will not be reported (but bit masks like this are fairly uncommon). diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 0162ef92dd6..65fbce640cf 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -3,7 +3,7 @@ use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; use rustc_front::intravisit::{Visitor, walk_expr}; use utils::*; -/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. It is `Warn` by default. +/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. /// /// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions. /// @@ -15,7 +15,7 @@ declare_lint! { "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" } -/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. It is `Warn` by default. +/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. /// /// **Why is this bad?** Using blocks in the condition makes it hard to read. /// diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 4b3c4174df7..03c43ef5dc8 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -20,7 +20,7 @@ use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; /// **What it does:** This lint checks for nested `if`-statements which can be collapsed by /// `&&`-combining their conditions and for `else { if .. }` expressions that can be collapsed to -/// `else if ..`. It is `Warn` by default. +/// `else if ..`. /// /// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. /// diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 7eab7c1935f..b2be1dddbee 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -11,7 +11,7 @@ use rustc_front::intravisit::{Visitor, walk_expr}; use utils::{in_macro, LimitStack, span_help_and_lint}; -/// **What it does:** It `Warn`s on methods with high cyclomatic complexity +/// **What it does:** This lint checks for methods with high cyclomatic complexity /// /// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better. /// diff --git a/src/drop_ref.rs b/src/drop_ref.rs index f7a0ca59f01..6dc3d734196 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -15,7 +15,7 @@ use utils::{match_def_path, span_note_and_lint}; /// **Example:** /// ```rust /// let mut lock_guard = mutex.lock(); -/// std::mem::drop(&lock_guard) //Should have been drop(lock_guard), mutex still locked +/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex still locked /// operation_that_requires_mutex_to_be_unlocked(); /// ``` declare_lint! { diff --git a/src/eq_op.rs b/src/eq_op.rs index 31dc094385f..49037cd9ae7 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -4,7 +4,7 @@ use rustc_front::util as ast_util; use utils::{is_exp_equal, span_lint}; -/// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). It is `Warn` by default. +/// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). /// /// **Why is this bad?** This is usually just a typo. /// diff --git a/src/escape.rs b/src/escape.rs index b7bec46c3fd..60bfbbc59c3 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -14,7 +14,7 @@ use utils::span_lint; pub struct EscapePass; -/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. It is `Warn` by default. +/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. /// /// **Why is this bad?** This is an unnecessary allocation, and bad for performance. It is only necessary to allocate if you wish to move the box into something. /// diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 39063f91ba3..280392a50b1 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -9,7 +9,7 @@ use utils::{snippet_opt, span_lint_and_then, is_adjusted}; pub struct EtaPass; -/// **What it does:** This lint checks for closures which just call another function where the function can be called directly. `unsafe` functions or calls where types get adjusted are ignored. It is `Warn` by default. +/// **What it does:** This lint checks for closures which just call another function where the function can be called directly. `unsafe` functions or calls where types get adjusted are ignored. /// /// **Why is this bad?** Needlessly creating a closure just costs heap space and adds code for no benefit. /// diff --git a/src/identity_op.rs b/src/identity_op.rs index 093c37783eb..1a62ffb4ae0 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -5,7 +5,7 @@ use syntax::codemap::Span; use consts::{constant_simple, is_negative, Constant}; use utils::{span_lint, snippet, in_macro}; -/// **What it does:** This lint checks for identity operations, e.g. `x + 0`. It is `Warn` by default. +/// **What it does:** This lint checks for identity operations, e.g. `x + 0`. /// /// **Why is this bad?** This code can be removed without changing the meaning. So it just obscures what's going on. Delete it mercilessly. /// diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 2f061d32546..2aa2fc6da34 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -5,8 +5,7 @@ use syntax::attr::*; use syntax::ast::*; use utils::in_macro; -/// **What it does:** It `Warn`s on blocks where there are items that are declared in the middle of -/// or after the statements +/// **What it does:** This lints checks for items declared after some statement in a block /// /// **Why is this bad?** Items live for the entire scope they are declared in. But statements are /// processed in order. This might cause confusion as it's hard to figure out which item is meant diff --git a/src/len_zero.rs b/src/len_zero.rs index 48fc10ef236..120e880cde6 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -11,7 +11,7 @@ use syntax::ast::Lit; use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; -/// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. It is `Warn` by default. +/// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. /// /// **Why is this bad?** Some structures can answer `.is_empty()` much faster than calculating their length. So it is good to get into the habit of using `.is_empty()`, and having it is cheap. Besides, it makes the intent clearer than a comparison. /// @@ -24,7 +24,7 @@ declare_lint! { could be used instead" } -/// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. It is `Warn` by default. +/// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. /// /// **Why is this bad?** It is good custom to have both methods, because for some data structures, asking about the length will be a costly operation, whereas `.is_empty()` can usually answer in constant time. Also it used to lead to false positives on the [`len_zero`](#len_zero) lint – currently that lint will ignore such entities. /// diff --git a/src/lifetimes.rs b/src/lifetimes.rs index f2f33a634bc..f30163f4656 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -8,7 +8,7 @@ use std::collections::{HashSet, HashMap}; use utils::{in_external_macro, span_lint}; -/// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. It is `Warn` by default. +/// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. /// /// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. /// @@ -22,7 +22,7 @@ declare_lint! { would allow omitting them" } -/// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. It is `Warn` by default. +/// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. /// /// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. /// diff --git a/src/loops.rs b/src/loops.rs index bfd0e9895e5..4620d6a3e81 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -13,7 +13,7 @@ use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty}; use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; -/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. It is `Warn` by default. +/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. /// /// **Why is this bad?** Just iterating the collection itself makes the intent more clear and is probably faster. /// @@ -31,7 +31,7 @@ declare_lint! { "for-looping over a range of indices where an iterator over items would do" } -/// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. It is `Warn` by default. +/// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. /// /// **Why is this bad?** Readability. /// @@ -44,7 +44,7 @@ declare_lint! { "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" } -/// **What it does:** This lint checks for loops on `x.next()`. It is `Warn` by default. +/// **What it does:** This lint checks for loops on `x.next()`. /// /// **Why is this bad?** `next()` returns either `Some(value)` if there was a value, or `None` otherwise. The insidious thing is that `Option<_>` implements `IntoIterator`, so that possibly one value will be iterated, leading to some hard to find bugs. No one will want to write such code [except to win an Underhanded Rust Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). /// @@ -57,7 +57,7 @@ declare_lint! { "for-looping over `_.next()` which is probably not intended" } -/// **What it does:** This lint checks for `for` loops over `Option` values. It is `Warn` by default. +/// **What it does:** This lint checks for `for` loops over `Option` values. /// /// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. /// @@ -70,7 +70,7 @@ declare_lint! { "for-looping over an `Option`, which is more clearly expressed as an `if let`" } -/// **What it does:** This lint checks for `for` loops over `Result` values. It is `Warn` by default. +/// **What it does:** This lint checks for `for` loops over `Result` values. /// /// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. /// @@ -83,7 +83,7 @@ declare_lint! { "for-looping over a `Result`, which is more clearly expressed as an `if let`" } -/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. It is `Warn` by default. +/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. /// /// **Why is this bad?** The `while let` loop is usually shorter and more readable /// @@ -110,7 +110,7 @@ declare_lint! { "`loop { if let { ... } else break }` can be written as a `while let` loop" } -/// **What it does:** This lint checks for using `collect()` on an iterator without using the result. It is `Warn` by default. +/// **What it does:** This lint checks for using `collect()` on an iterator without using the result. /// /// **Why is this bad?** It is more idiomatic to use a `for` loop over the iterator instead. /// @@ -124,7 +124,7 @@ declare_lint! { written as a for loop" } -/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. It is `Warn` by default. +/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. /// /// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. /// @@ -137,7 +137,7 @@ declare_lint! { "Iterating over an empty range, such as `10..0` or `5..5`" } -/// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. It is `Warn` by default. +/// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. /// /// **Why is it bad?** Not only is the version using `.enumerate()` more readable, the compiler is able to remove bounds checks which can lead to faster code in some instances. /// @@ -150,7 +150,7 @@ declare_lint! { "for-looping with an explicit counter when `_.enumerate()` would do" } -/// **What it does:** This lint checks for empty `loop` expressions. It is `Warn` by default. +/// **What it does:** This lint checks for empty `loop` expressions. /// /// **Why is this bad?** Those busy loops burn CPU cycles without doing anything. Think of the environment and either block on something or at least make the thread sleep for some microseconds. /// @@ -163,7 +163,7 @@ declare_lint! { "empty `loop {}` detected" } -/// **What it does:** This lint checks for `while let` expressions on iterators. It is `Warn` by default. +/// **What it does:** This lint checks for `while let` expressions on iterators. /// /// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys the intent better. /// diff --git a/src/map_clone.rs b/src/map_clone.rs index d4773986399..e0255c52fb5 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -4,7 +4,7 @@ use utils::{CLONE_PATH, OPTION_PATH}; use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint}; use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; -/// **What it does:** This lint checks for mapping clone() over an iterator. It is `Warn` by default and suggests to use `.cloned()` instead. +/// **What it does:** This lint checks for mapping clone() over an iterator. /// /// **Why is this bad?** It makes the code less readable. /// diff --git a/src/matches.rs b/src/matches.rs index fb0663117fa..6be5d0bf24f 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -11,7 +11,7 @@ use syntax::codemap::Span; use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; use utils::{match_type, snippet, span_lint, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; -/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. It is `Warn` by default. +/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. /// /// **Why is this bad?** Just readability – `if let` nests less than a `match`. /// @@ -30,7 +30,7 @@ declare_lint! { is `_ => {}`) is used; recommends `if let` instead" } -/// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. It is `Allow` by default. +/// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. /// /// **Why is this bad?** Just readability – `if let` nests less than a `match`. /// @@ -49,7 +49,7 @@ declare_lint! { recommends `if let` instead" } -/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. It is `Warn` by default. +/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. /// /// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. /// @@ -70,7 +70,7 @@ declare_lint! { dereferenced instead" } -/// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. It is `Warn` by default. +/// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. /// /// **Why is this bad?** It makes the code less readable. /// @@ -90,7 +90,7 @@ declare_lint! { "a match on boolean expression; recommends `if..else` block instead" } -/// **What it does:** This lint checks for overlapping match arms. It is `Warn` by default. +/// **What it does:** This lint checks for overlapping match arms. /// /// **Why is this bad?** It is likely to be an error and if not, makes the code less obvious. /// diff --git a/src/methods.rs b/src/methods.rs index 4cd957d0fe7..40d975545e9 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -18,7 +18,7 @@ use rustc::middle::cstore::CrateStore; #[derive(Clone)] pub struct MethodsPass; -/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. It is `Allow` by default. +/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. /// /// **Why is this bad?** Usually it is better to handle the `None` case, or to at least call `.expect(_)` with a more helpful message. Still, for a lot of quick-and-dirty code, `unwrap` is a good choice, which is why this lint is `Allow` by default. /// @@ -30,7 +30,7 @@ declare_lint! { "using `Option.unwrap()`, which should at least get a better message using `expect()`" } -/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. It is `Allow` by default. +/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. /// /// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`. /// @@ -44,7 +44,7 @@ declare_lint! { "using `Result.unwrap()`, which might be better handled" } -/// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. It is `Warn` by default. +/// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. /// /// **Why is this bad?** This uses the whole formatting machinery just to clone a string. Using `.to_owned()` is lighter on resources. You can also consider using a [`Cow<'a, str>`](http://doc.rust-lang.org/std/borrow/enum.Cow.html) instead in some cases. /// @@ -56,7 +56,7 @@ declare_lint! { "using `to_string()` on a str, which should be `to_owned()`" } -/// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. It is `Warn` by default. +/// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. /// /// **Why is this bad?** This is an non-efficient way to clone a `String`, `.clone()` should be used /// instead. `String` implements `ToString` mostly for generics. @@ -69,7 +69,7 @@ declare_lint! { "calling `String::to_string` which is inefficient" } -/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. It is `Warn` by default. +/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. /// /// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. /// @@ -87,7 +87,7 @@ declare_lint! { "defining a method that should be implementing a std trait" } -/// **What it does:** This lint checks for methods with certain name prefixes and `Warn`s (by default) if the prefix doesn't match how self is taken. The actual rules are: +/// **What it does:** This lint checks for methods with certain name prefixes and which doesn't match how self is taken. The actual rules are: /// /// |Prefix |`self` taken | /// |-------|--------------------| @@ -97,7 +97,7 @@ declare_lint! { /// |`is_` |`&self` or none | /// |`to_` |`&self` | /// -/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_`.. function. +/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_..` function. /// /// **Known problems:** None /// @@ -114,7 +114,7 @@ declare_lint! { `self` with the wrong convention" } -/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. This lint is `Allow` by default. +/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. /// /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). /// @@ -132,7 +132,7 @@ declare_lint! { `self` with the wrong convention" } -/// **What it does:** This lint `Warn`s on using `ok().expect(..)`. +/// **What it does:** This lint checks for usage of `ok().expect(..)`. /// /// **Why is this bad?** Because you usually call `expect()` on the `Result` directly to get a good error message. /// @@ -145,7 +145,7 @@ declare_lint! { calling `expect` directly on the Result" } -/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or(_)`. +/// **What it does:** This lint checks for usage of `_.map(_).unwrap_or(_)`. /// /// **Why is this bad?** Readability, this can be written more concisely as `_.map_or(_, _)`. /// @@ -234,7 +234,7 @@ declare_lint! { "using any `*or` method when the `*or_else` would do" } -/// **What it does:** This lint `Warn`s on using `.extend(s)` on a `vec` to extend the vec by a slice. +/// **What it does:** This lint checks for usage of `.extend(s)` on a `Vec` to extend the vector by a slice. /// /// **Why is this bad?** Since Rust 1.6, the `extend_from_slice(_)` method is stable and at least for now faster. /// diff --git a/src/minmax.rs b/src/minmax.rs index 2e199345579..57ec9d91734 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -8,7 +8,7 @@ use consts::{Constant, constant_simple}; use utils::{match_def_path, span_lint}; use self::MinMax::{Min, Max}; -/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. It is `Warn` by default. +/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. /// /// **Why is this bad?** This is in all probability not the intended outcome. At the least it hurts readability of the code. /// diff --git a/src/misc.rs b/src/misc.rs index 099b1797e8e..c0aed78225a 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -13,7 +13,7 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal, implements_trait}; -/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. It is `Warn` by default. +/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. /// /// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body. /// @@ -78,7 +78,7 @@ impl LateLintPass for TopLevelRefPass { } } -/// **What it does:** This lint checks for comparisons to NAN. It is `Deny` by default. +/// **What it does:** This lint checks for comparisons to NAN. /// /// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong. /// @@ -123,7 +123,7 @@ fn check_nan(cx: &LateContext, path: &Path, span: Span) { }); } -/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats). It is `Warn` by default. +/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats). /// /// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison). /// @@ -189,7 +189,7 @@ fn is_float(cx: &LateContext, expr: &Expr) -> bool { } } -/// **What it does:** This lint checks for conversions to owned values just for the sake of a comparison. It is `Warn` by default. +/// **What it does:** This lint checks for conversions to owned values just for the sake of a comparison. /// /// **Why is this bad?** The comparison can operate on a reference, so creating an owned value effectively throws it away directly afterwards, which is needlessly consuming code and heap space. /// @@ -283,7 +283,7 @@ fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { } } -/// **What it does:** This lint checks for getting the remainder of a division by one. It is `Warn` by default. +/// **What it does:** This lint checks for getting the remainder of a division by one. /// /// **Why is this bad?** The result can only ever be zero. No one will write such code deliberately, unless trying to win an Underhanded Rust Contest. Even for that contest, it's probably a bad idea. Use something more underhanded. /// @@ -313,7 +313,7 @@ impl LateLintPass for ModuloOne { } } -/// **What it does:** This lint checks for patterns in the form `name @ _`. It is `Warn` by default. +/// **What it does:** This lint checks for patterns in the form `name @ _`. /// /// **Why is this bad?** It's almost always more readable to just use direct bindings. /// diff --git a/src/misc_early.rs b/src/misc_early.rs index de3c4289353..59a0102aacf 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -8,7 +8,7 @@ use syntax::visit::FnKind; use utils::{span_lint, span_help_and_lint}; -/// **What it does:** This lint `Warn`s on struct field patterns bound to wildcards. +/// **What it does:** This lint checks for structure field patterns bound to wildcards. /// /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. /// @@ -20,7 +20,7 @@ declare_lint! { "Struct fields are bound to a wildcard instead of using `..`" } -/// **What it does:** This lint `Warn`s on function arguments having the similar names differing by an underscore +/// **What it does:** This lint checks for function arguments having the similar names differing by an underscore /// /// **Why is this bad?** It affects code readability /// diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 99c1d040fd2..1759a89242b 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -4,7 +4,7 @@ use rustc::middle::ty::{TypeAndMut, TyRef}; use utils::{in_external_macro, span_lint}; -/// **What it does:** This lint checks for instances of `mut mut` references. It is `Warn` by default. +/// **What it does:** This lint checks for instances of `mut mut` references. /// /// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source. /// diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 15e8d310cd6..35904533719 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -4,7 +4,7 @@ use utils::span_lint; use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; use syntax::ptr::P; -/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. It is `Warn` by default. +/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. /// /// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site. /// diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 7b75bd747bb..cf1c347750c 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -11,7 +11,7 @@ use rustc::middle::subst::ParamSpace; use utils::{span_lint, MUTEX_PATH, match_type}; -/// **What it does:** It `Warn`s on usages of `Mutex<X>` where an atomic will do +/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do. /// /// **Why is this bad?** Using a Mutex just to make access to a plain bool or reference sequential is shooting flies with cannons. `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and faster. /// @@ -24,7 +24,7 @@ declare_lint! { "using a Mutex where an atomic value could be used instead" } -/// **What it does:** It `Warn`s on usages of `Mutex<X>` where `X` is an integral type. +/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type. /// /// **Why is this bad?** Using a Mutex just to make access to a plain integer sequential is shooting flies with cannons. `std::atomic::usize` is leaner and faster. /// diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 22edbc272bd..52b3108f6fa 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -9,7 +9,7 @@ use syntax::ast::Lit_::*; use utils::{span_lint, snippet}; -/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. It is `Warn` by default. +/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. /// /// **Why is this bad?** Redundant code. /// diff --git a/src/needless_features.rs b/src/needless_features.rs index 2c293d04600..646ebbbd015 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -8,7 +8,7 @@ use rustc_front::hir::*; use utils::span_lint; use utils; -/// **What it does:** This lint `Warn`s on use of the `as_slice(..)` function, which is unstable. +/// **What it does:** This lint checks for usage of the `as_slice(..)` function, which is unstable. /// /// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. /// @@ -22,7 +22,7 @@ declare_lint! { see https://github.com/rust-lang/rust/issues/27729" } -/// **What it does:** This lint `Warn`s on use of the `as_mut_slice(..)` function, which is unstable. +/// **What it does:** This lint checks for usage of the `as_mut_slice(..)` function, which is unstable. /// /// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. /// diff --git a/src/needless_update.rs b/src/needless_update.rs index 1b306df8eed..d18930c8ccc 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -4,7 +4,7 @@ use rustc_front::hir::{Expr, ExprStruct}; use utils::span_lint; -/// **What it does:** This lint `Warn`s on needlessly including a base struct on update when all fields are changed anyway. +/// **What it does:** This lint warns on needlessly including a base struct on update when all fields are changed anyway. /// /// **Why is this bad?** This will cost resources (because the base has to be somewhere), and make the code less readable. /// diff --git a/src/no_effect.rs b/src/no_effect.rs index 075b9b62800..e1067f27ab9 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -6,7 +6,7 @@ use rustc_front::hir::{Stmt, StmtSemi}; use utils::in_macro; use utils::span_lint; -/// **What it does:** This lint `Warn`s on statements which have no effect. +/// **What it does:** This lint checks for statements which have no effect. /// /// **Why is this bad?** Similar to dead code, these statements are actually executed. However, as they have no effect, all they do is make the code less readable. /// diff --git a/src/open_options.rs b/src/open_options.rs index 541ed2444f4..a5766604cec 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -4,7 +4,7 @@ use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; use syntax::codemap::{Span, Spanned}; use syntax::ast::Lit_::LitBool; -/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. It is `Warn` by default. +/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. /// /// **Why is this bad?** In the best case, the code will be harder to read than necessary. I don't know the worst case. /// diff --git a/src/panic.rs b/src/panic.rs index dc30f710830..5337942b4e0 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -4,14 +4,14 @@ use syntax::ast::Lit_::LitStr; use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; -/// **What it does:** Warn about missing parameters in `panic!`. +/// **What it does:** This lint checks for missing parameters in `panic!`. /// /// **Known problems:** Should you want to use curly brackets in `panic!` without any parameter, /// this lint will warn. /// /// **Example:** /// ``` -/// panic!("This panic! is probably missing a parameter there: {}"); +/// panic!("This `panic!` is probably missing a parameter there: {}"); /// ``` declare_lint! { pub PANIC_PARAMS, Warn, "missing parameters in `panic!`" diff --git a/src/precedence.rs b/src/precedence.rs index a316f183863..009a79b1673 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -4,7 +4,7 @@ use syntax::ast::*; use utils::{span_lint, snippet}; -/// **What it does:** This lint checks for operations where precedence may be unclear and `Warn`s about them by default, suggesting to add parentheses. Currently it catches the following: +/// **What it does:** This lint checks for operations where precedence may be unclear and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without parentheses /// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call /// diff --git a/src/print.rs b/src/print.rs index 930952bdbaf..d8f5fd488aa 100644 --- a/src/print.rs +++ b/src/print.rs @@ -2,8 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::{IO_PRINT_PATH, is_expn_of, match_path, span_lint}; -/// **What it does:** This lint warns whenever you print on *stdout*. This lint is `Allow` by -/// default, the purpose is to catch debugging remnants. +/// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants. /// /// **Why is this bad?** People often print on *stdout* while debugging an application and might /// forget to remove those prints afterward. diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 75ce96f6350..707adcfeb07 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -10,7 +10,7 @@ use rustc::middle::ty; use utils::{span_lint, match_type}; use utils::{STRING_PATH, VEC_PATH}; -/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. It is `Warn` by default. +/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. /// /// **Why is this bad?** Requiring the argument to be of the specific size makes the function less useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be obtained from other types, too. /// diff --git a/src/ranges.rs b/src/ranges.rs index 692a5a2da1d..895bd180168 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -3,7 +3,7 @@ use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::{is_integer_literal, match_type, snippet}; -/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. It is `Warn` by default. +/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. /// /// **Why is this bad?** This very much looks like an oversight, since with `loop { .. }` there is an obvious better way to endlessly loop. /// @@ -14,7 +14,7 @@ declare_lint! { pub RANGE_STEP_BY_ZERO, Warn, "using Range::step_by(0), which produces an infinite iterator" } -/// **What it does:** This lint checks for zipping a collection with the range of `0.._.len()`. It is `Warn` by default. +/// **What it does:** This lint checks for zipping a collection with the range of `0.._.len()`. /// /// **Why is this bad?** The code is better expressed with `.enumerate()`. /// diff --git a/src/regex.rs b/src/regex.rs index 259bbb1b64b..81193793a23 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -10,7 +10,7 @@ use rustc::lint::*; use utils::{match_path, REGEX_NEW_PATH, span_lint}; -/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. It is `deny` by default. +/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. /// diff --git a/src/returns.rs b/src/returns.rs index 0b0c4d14bdf..3d830e9e372 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -6,7 +6,7 @@ use syntax::visit::FnKind; use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro}; -/// **What it does:** This lint checks for return statements at the end of a block. It is `Warn` by default. +/// **What it does:** This lint checks for return statements at the end of a block. /// /// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty. /// @@ -18,7 +18,7 @@ declare_lint! { "using a return statement like `return expr;` where an expression would suffice" } -/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. It is `Warn` by default. +/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. /// /// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. /// diff --git a/src/shadow.rs b/src/shadow.rs index f772f97c81e..ff9ea47f065 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -9,7 +9,7 @@ use rustc::middle::def::Def; use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. It is `Allow` by default. +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. /// /// **Why is this bad?** Not much, in fact it's a very common pattern in Rust code. Still, some may opt to avoid it in their code base, they can set this lint to `Warn`. /// @@ -21,7 +21,7 @@ declare_lint! { "rebinding a name to itself, e.g. `let mut x = &mut x`" } -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. It is `Allow` by default. +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. /// /// **Why is this bad?** Not too much, in fact it's a common pattern in Rust code. Still, some argue that name shadowing like this hurts readability, because a value may be bound to different things depending on position in the code. /// @@ -34,7 +34,7 @@ declare_lint! { `let x = x + 1`" } -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. This lint is `Warn` by default. +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. /// /// **Why is this bad?** Name shadowing can hurt readability, especially in large code bases, because it is easy to lose track of the active binding at any place in the code. This can be alleviated by either giving more specific names to bindings ore introducing more scopes to contain the bindings. /// diff --git a/src/strings.rs b/src/strings.rs index 16ee08b1894..f1a1341460e 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -10,7 +10,7 @@ use syntax::codemap::Spanned; use utils::{is_exp_equal, match_type, span_lint, walk_ptrs_ty, get_parent_expr}; use utils::STRING_PATH; -/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). It is `Allow` by default. +/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). /// /// **Why is this bad?** Because this expression needs another copy as opposed to `x.push_str(y)` (in practice LLVM will usually elide it, though). Despite [llogiq](https://github.com/llogiq)'s reservations, this lint also is `allow` by default, as some people opine that it's more readable. /// @@ -28,7 +28,7 @@ declare_lint! { "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" } -/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match. It is `Allow` by default. +/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match. /// /// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code. /// @@ -49,7 +49,7 @@ declare_lint! { } /// **What it does:** This lint matches the `as_bytes` method called on string -/// literals that contain only ascii characters. It is `Warn` by default. +/// literals that contain only ascii characters. /// /// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`. /// diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs index 7d5057d8377..417ec540856 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -4,9 +4,9 @@ use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTup use utils::is_adjusted; use utils::span_lint; -/// **What it does:** This lint `Warn`s on creating a struct or tuple just to assign a value in it. +/// **What it does:** This lint checks for construction of a structure or tuple just to assign a value in it. /// -/// **Why is this bad?** Readability. If the struct is only created to be updated, why not write the struct you want in the first place? +/// **Why is this bad?** Readability. If the structure is only created to be updated, why not write the structure you want in the first place? /// /// **Known problems:** None. /// diff --git a/src/transmute.rs b/src/transmute.rs index 24af45bc68d..0dd5b60e77a 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use utils; -/// **What it does:** This lint checks for transmutes to the original type of the object. It is `Warn` by default. +/// **What it does:** This lint checks for transmutes to the original type of the object. /// /// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type. /// diff --git a/src/types.rs b/src/types.rs index bb1201547b3..498a084984f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -15,7 +15,7 @@ use utils::*; #[allow(missing_copy_implementations)] pub struct TypePass; -/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. It is `Warn` by default. +/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever. /// @@ -27,7 +27,7 @@ declare_lint! { "usage of `Box<Vec<T>>`, vector elements are already on the heap" } -/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). It is `Warn` by default. +/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). /// /// **Why is this bad?** Gankro says: /// @@ -78,7 +78,7 @@ impl LateLintPass for TypePass { #[allow(missing_copy_implementations)] pub struct LetPass; -/// **What it does:** This lint checks for binding a unit value. It is `Warn` by default. +/// **What it does:** This lint checks for binding a unit value. /// /// **Why is this bad?** A unit value cannot usefully be used anywhere. So binding one is kind of pointless. /// @@ -121,7 +121,7 @@ impl LateLintPass for LetPass { } } -/// **What it does:** This lint checks for comparisons to unit. It is `Warn` by default. +/// **What it does:** This lint checks for comparisons to unit. /// /// **Why is this bad?** Unit is always equal to itself, and thus is just a clumsily written constant. Mostly this happens when someone accidentally adds semicolons at the end of the operands. /// @@ -405,7 +405,7 @@ impl LateLintPass for CastPass { } } -/// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold. It is `Warn` by default. +/// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold. /// /// **Why is this bad?** Too complex types make the code less readable. Consider using a `type` definition to simplify them. /// @@ -539,7 +539,7 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { } } -/// **What it does:** This lint points out expressions where a character literal is casted to u8 and suggests using a byte literal instead. +/// **What it does:** This lint points out expressions where a character literal is casted to `u8` and suggests using a byte literal instead. /// /// **Why is this bad?** In general, casting values to smaller types is error-prone and should be avoided where possible. In the particular case of converting a character literal to u8, it is easy to avoid by just using a byte literal instead. As an added bonus, `b'a'` is even slightly shorter than `'a' as u8`. /// diff --git a/src/unicode.rs b/src/unicode.rs index 92d365f0323..63ffe219d9b 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -8,7 +8,7 @@ use unicode_normalization::UnicodeNormalization; use utils::{snippet, span_help_and_lint}; -/// **What it does:** This lint checks for the unicode zero-width space in the code. It is `Warn` by default. +/// **What it does:** This lint checks for the unicode zero-width space in the code. /// /// **Why is this bad?** Having an invisible character in the code makes for all sorts of April fools, but otherwise is very much frowned upon. /// @@ -20,7 +20,7 @@ declare_lint! { "using a zero-width space in a string literal, which is confusing" } -/// **What it does:** This lint checks for non-ascii characters in string literals. It is `Allow` by default. +/// **What it does:** This lint checks for non-ascii characters in string literals. /// /// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset back. Even so, there still are editors and other programs out there that don't work well with unicode. So if the code is meant to be used internationally, on multiple operating systems, or has other portability requirements, activating this lint could be useful. /// @@ -33,7 +33,7 @@ declare_lint! { using the \\u escape instead" } -/// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). This lint is `Allow` by default. +/// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). /// /// **Why is this bad?** If such a string is compared to another, the results may be surprising. /// diff --git a/src/vec.rs b/src/vec.rs index 41a477c34ff..fe3c1f90199 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -7,7 +7,6 @@ use utils::{BOX_NEW_PATH, VEC_FROM_ELEM_PATH}; use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. -/// It is `Warn` by default. /// /// **Why is this bad?** This is less efficient. /// diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 9c5c07cd678..1576d699a4a 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -4,12 +4,12 @@ use rustc_front::hir::*; use utils::span_help_and_lint; use consts::{Constant, constant_simple, FloatWidth}; -/// ZeroDivZeroPass is a pass that checks for a binary expression that consists -/// of 0.0/0.0, which is always NaN. It is more clear to replace instances of -/// 0.0/0.0 with std::f32::NaN or std::f64::NaN, depending on the precision. +/// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists +/// `of 0.0/0.0`, which is always NaN. It is more clear to replace instances of +/// `0.0/0.0` with `std::f32::NaN` or `std::f64::NaN`, depending on the precision. pub struct ZeroDivZeroPass; -/// **What it does:** This lint checks for `0.0 / 0.0`. It is `Warn` by default. +/// **What it does:** This lint checks for `0.0 / 0.0`. /// /// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN` /// -- cgit 1.4.1-3-g733a5 From d9a2a7ac3c992f6093babb7770acfaac3a08833f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 6 Feb 2016 18:06:39 +0100 Subject: Fix false negative in TRIVIAL_REGEX --- src/regex.rs | 96 ++++++++++++++++++++++++++------------------- tests/compile-fail/regex.rs | 9 +++++ 2 files changed, 64 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/regex.rs b/src/regex.rs index 76412f17880..cf19c764361 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -55,32 +55,40 @@ impl LateLintPass for RegexPass { ], { if let ExprLit(ref lit) = args[0].node { if let LitStr(ref r, _) = lit.node { - if let Err(e) = regex_syntax::Expr::parse(r) { + match regex_syntax::Expr::parse(r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, + &"trivial regex", + &format!("consider using {}", repl)); + } + } + Err(e) => { + span_lint(cx, + INVALID_REGEX, + str_span(args[0].span, &r, e.position()), + &format!("regex syntax error: {}", + e.description())); + } + } + } + } else if let Some(r) = const_str(cx, &*args[0]) { + match regex_syntax::Expr::parse(&r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, + &"trivial regex", + &format!("consider using {}", repl)); + } + } + Err(e) => { span_lint(cx, INVALID_REGEX, - str_span(args[0].span, &r, e.position()), - &format!("regex syntax error: {}", + args[0].span, + &format!("regex syntax error on position {}: {}", + e.position(), e.description())); } - else if let Some(repl) = is_trivial_regex(r) { - span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - &"trivial regex", - &format!("consider using {}", repl)); - } - } - } else if let Some(r) = const_str(cx, &*args[0]) { - if let Err(e) = regex_syntax::Expr::parse(&r) { - span_lint(cx, - INVALID_REGEX, - args[0].span, - &format!("regex syntax error on position {}: {}", - e.position(), - e.description())); - } - else if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - &"trivial regex", - &format!("{}", repl)); } } }} @@ -103,25 +111,31 @@ fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { } } -fn is_trivial_regex(s: &str) -> Option<&'static str> { - // some unlikely but valid corner cases - match s { - "" | "^" | "$" => return Some("the regex is unlikely to be useful as it is"), - "^$" => return Some("consider using `str::is_empty`"), - _ => (), - } - - let (start, end, repl) = match (s.starts_with('^'), s.ends_with('$')) { - (true, true) => (1, s.len()-1, "consider using `==` on `str`s"), - (false, true) => (0, s.len()-1, "consider using `str::ends_with`"), - (true, false) => (1, s.len(), "consider using `str::starts_with`"), - (false, false) => (0, s.len(), "consider using `str::contains`"), - }; +fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { + use regex_syntax::Expr; - if !s.chars().take(end).skip(start).any(regex_syntax::is_punct) { - Some(repl) - } - else { - None + match *s { + Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), + Expr::Literal {..} => Some("consider using `str::contains`"), + Expr::Concat(ref exprs) => { + match exprs.len() { + 2 => match (&exprs[0], &exprs[1]) { + (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), + (&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"), + (&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]) { + Some("consider using `==` on `str`s") + } + else { + None + } + }, + _ => None, + } + } + _ => None, } } diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index cd10d47c1bb..2e8228a823d 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -45,16 +45,25 @@ fn trivial_regex() { //~^ERROR: trivial regex //~|HELP consider using `str::contains` + let trivial_backslash = Regex::new("a\\.b"); + //~^ERROR: trivial regex + //~|HELP consider using `str::contains` + // unlikely corner cases let trivial_empty = Regex::new(""); //~^ERROR: trivial regex //~|HELP the regex is unlikely to be useful + let trivial_empty = Regex::new("^"); + //~^ERROR: trivial regex + //~|HELP the regex is unlikely to be useful + let trivial_empty = Regex::new("^$"); //~^ERROR: trivial regex //~|HELP consider using `str::is_empty` // non-trivial regexes + let non_trivial_dot = Regex::new("a.b"); let non_trivial_eq = Regex::new("^foo|bar$"); let non_trivial_starts_with = Regex::new("^foo|bar"); let non_trivial_ends_with = Regex::new("^foo|bar"); -- cgit 1.4.1-3-g733a5 From fe6f2a22ba48f8187ed69cd3d479d7a0dfa3b432 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 18:03:53 +0100 Subject: Lint about consecutive ifs with same condition --- README.md | 1 + src/copies.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/utils.rs | 24 +++++++++++++++- tests/compile-fail/copies.rs | 31 ++++++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/copies.rs create mode 100755 tests/compile-fail/copies.rs (limited to 'src') diff --git a/README.md b/README.md index 20aaa03c51c..93921f01f6e 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ name [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` [for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations diff --git a/src/copies.rs b/src/copies.rs new file mode 100644 index 00000000000..33461a29670 --- /dev/null +++ b/src/copies.rs @@ -0,0 +1,68 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::{get_parent_expr, is_exp_equal, span_lint}; + +/// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is +/// `Warn` by default. +/// +/// **Why is this bad?** This is probably a copy & paste error. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** `if a == b { .. } else if a == b { .. }` +declare_lint! { + pub IFS_SAME_COND, + Warn, + "consecutive `ifs` with the same condition" +} + +#[derive(Copy, Clone, Debug)] +pub struct CopyAndPaste; + +impl LintPass for CopyAndPaste { + fn get_lints(&self) -> LintArray { + lint_array![ + IFS_SAME_COND + ] + } +} + +impl LateLintPass for CopyAndPaste { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + // 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) { + if else_expr.id == expr.id { + return; + } + } + + let conds = condition_sequence(expr); + + for (n, i) in conds.iter().enumerate() { + for j in conds.iter().skip(n+1) { + if is_exp_equal(cx, i, j) { + span_lint(cx, IFS_SAME_COND, j.span, "this if as the same condition as a previous if"); + } + } + } + } +} + +/// Return the list of conditions expression in a sequence of `if/else`. +/// Eg. would return `[a, b]` for the expression `if a {..} else if b {..}`. +fn condition_sequence(mut expr: &Expr) -> Vec<&Expr> { + let mut result = vec![]; + + while let ExprIf(ref cond, _, ref else_expr) = expr.node { + result.push(&**cond); + + if let Some(ref else_expr) = *else_expr { + expr = else_expr; + } + else { + break; + } + } + + result +} diff --git a/src/lib.rs b/src/lib.rs index fa98beb8d74..6b2a43db795 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ use rustc_plugin::Registry; #[macro_use] pub mod utils; +pub mod copies; pub mod consts; pub mod types; pub mod misc; @@ -157,6 +158,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdUnsignedComparisons); reg.register_late_lint_pass(box regex::RegexPass); + reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -190,6 +192,7 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, + copies::IFS_SAME_COND, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_NOT_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, diff --git a/src/utils.rs b/src/utils.rs index 74c1de6976f..72c6fe94ce2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -596,16 +596,38 @@ pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr) -> bool { } } match (&left.node, &right.node) { + (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => { + lmut == rmut && is_exp_equal(cx, le, re) + } + (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { + lop.node == rop.node && is_exp_equal(cx, ll, rl) && is_exp_equal(cx, lr, rr) + } + (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { + is_exp_equal(cx, lfun, rfun) && is_exps_equal(cx, largs, rargs) + } + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp) } + (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { + is_exp_equal(cx, la, ra) && is_exp_equal(cx, li, ri) + } (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, + (&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { + // TODO: tys + lname.node == rname.node && ltys.is_empty() && rtys.is_empty() && is_exps_equal(cx, largs, rargs) + } (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { both(lqself, rqself, is_qself_equal) && is_path_equal(lsubpath, rsubpath) } (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup), + (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { + li.node == ri.node && is_exp_equal(cx, le, re) + } + (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => { + lop == rop && is_exp_equal(cx, le, re) + } (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), _ => false, } } diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs new file mode 100755 index 00000000000..a29fd392c5e --- /dev/null +++ b/tests/compile-fail/copies.rs @@ -0,0 +1,31 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(clippy)] + +fn foo() -> bool { unimplemented!() } + +fn main() { + let a = 0; + + if a == 1 { + } + else if a == 1 { //~ERROR this if as the same condition as a previous if + } + + if 2*a == 1 { + } + else if 2*a == 2 { + } + else if 2*a == 1 { //~ERROR this if as the same condition as a previous if + } + else if a == 1 { + } + + // Ok, maybe `foo` isn’t pure and this actually makes sense. But you should probably refactor + // this to make the intention clearer anyway. + if foo() { + } + else if foo() { //~ERROR this if as the same condition as a previous if + } +} -- cgit 1.4.1-3-g733a5 From d862495d191dc432e92015a724780477f743152e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 19:16:49 +0100 Subject: Lint ifs with the same then and else blocks --- README.md | 1 + src/copies.rs | 72 ++++++++++++++++++++++++++++++------- src/lib.rs | 1 + src/utils.rs | 10 +++++- tests/compile-fail/copies.rs | 48 ++++++++++++++++++++++--- tests/compile-fail/needless_bool.rs | 1 + 6 files changed, 115 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 93921f01f6e..01999cce70b 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ name [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` [for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks [ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases diff --git a/src/copies.rs b/src/copies.rs index 33461a29670..f8fe09c3133 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{get_parent_expr, is_exp_equal, span_lint}; +use utils::{get_parent_expr, in_macro, is_exp_equal, is_stmt_equal, over, span_lint, span_note_and_lint}; /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is /// `Warn` by default. @@ -16,33 +16,79 @@ declare_lint! { "consecutive `ifs` with the same condition" } +/// **What it does:** This lint checks for `if/else` with the same body as the *then* part and the +/// *else* part. This lint is `Warn` by default. +/// +/// **Why is this bad?** This is probably a copy & paste error. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** `if .. { 42 } else { 42 }` +declare_lint! { + pub IF_SAME_THEN_ELSE, + Warn, + "if with the same *then* and *else* blocks" +} + #[derive(Copy, Clone, Debug)] pub struct CopyAndPaste; impl LintPass for CopyAndPaste { fn get_lints(&self) -> LintArray { lint_array![ - IFS_SAME_COND + IFS_SAME_COND, + IF_SAME_THEN_ELSE ] } } impl LateLintPass for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - // 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) { - if else_expr.id == expr.id { - return; - } + if !in_macro(cx, expr.span) { + lint_same_then_else(cx, expr); + lint_same_cond(cx, expr); } + } +} - let conds = condition_sequence(expr); - - for (n, i) in conds.iter().enumerate() { - for j in conds.iter().skip(n+1) { - if is_exp_equal(cx, i, j) { - span_lint(cx, IFS_SAME_COND, j.span, "this if as the same condition as a previous if"); +/// Implementation of `IF_SAME_THEN_ELSE`. +fn lint_same_then_else(cx: &LateContext, expr: &Expr) { + if let ExprIf(_, ref then_block, Some(ref else_expr)) = expr.node { + let must_lint = if let ExprBlock(ref else_block) = else_expr.node { + over(&then_block.stmts, &else_block.stmts, |l, r| is_stmt_equal(cx, l, r)) && + match (&then_block.expr, &else_block.expr) { + (&Some(ref then_expr), &Some(ref else_expr)) => { + is_exp_equal(cx, &then_expr, &else_expr) + } + (&None, &None) => true, + _ => false, } + } + else { + false + }; + + if must_lint { + span_lint(cx, IF_SAME_THEN_ELSE, expr.span, "this if has the same then and else blocks"); + } + } +} + +/// Implementation of `IFS_SAME_COND`. +fn lint_same_cond(cx: &LateContext, expr: &Expr) { + // 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) { + if else_expr.id == expr.id { + return; + } + } + + let conds = condition_sequence(expr); + + for (n, i) in conds.iter().enumerate() { + for j in conds.iter().skip(n+1) { + if is_exp_equal(cx, i, j) { + span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); } } } diff --git a/src/lib.rs b/src/lib.rs index 6b2a43db795..35ec0e13c3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,6 +192,7 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, + copies::IF_SAME_THEN_ELSE, copies::IFS_SAME_COND, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_NOT_EQ, diff --git a/src/utils.rs b/src/utils.rs index 72c6fe94ce2..13fd849993f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -589,6 +589,14 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } } +pub fn is_stmt_equal(cx: &LateContext, left: &Stmt, right: &Stmt) -> bool { + match (&left.node, &right.node) { + (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => is_exp_equal(cx, l, r), + (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => is_exp_equal(cx, l, r), + _ => false, + } +} + pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr) -> bool { if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { if l == r { @@ -649,7 +657,7 @@ fn is_qself_equal(left: &QSelf, right: &QSelf) -> bool { left.ty.node == right.ty.node && left.position == right.position } -fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool +pub fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index a29fd392c5e..94c5c620f34 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -1,23 +1,61 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(dead_code)] #![deny(clippy)] fn foo() -> bool { unimplemented!() } -fn main() { +fn if_same_then_else() { + if true { //~ERROR this if has the same then and else blocks + foo(); + } + else { + foo(); + } + + if true { + foo(); + foo(); + } + else { + foo(); + } + + let _ = if true { //~ERROR this if has the same then and else blocks + foo(); + 42 + } + else { + foo(); + 42 + }; + + if true { + foo(); + } + + let _ = if true { //~ERROR this if has the same then and else blocks + 42 + } + else { + 42 + }; +} + +fn ifs_same_cond() { let a = 0; if a == 1 { } - else if a == 1 { //~ERROR this if as the same condition as a previous if + else if a == 1 { //~ERROR this if has the same condition as a previous if } if 2*a == 1 { } else if 2*a == 2 { } - else if 2*a == 1 { //~ERROR this if as the same condition as a previous if + else if 2*a == 1 { //~ERROR this if has the same condition as a previous if } else if a == 1 { } @@ -26,6 +64,8 @@ fn main() { // this to make the intention clearer anyway. if foo() { } - else if foo() { //~ERROR this if as the same condition as a previous if + else if foo() { //~ERROR this if has the same condition as a previous if } } + +fn main() {} diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index 39fdf6353fd..c2ad24bc4ee 100644 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -1,6 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] +#[allow(if_same_then_else)] #[deny(needless_bool)] fn main() { let x = true; -- cgit 1.4.1-3-g733a5 From 8e22d08129dc242cebcdb25b824fa4ffb57d4f7a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 20:10:14 +0100 Subject: Improve is_exp_equal --- src/copies.rs | 13 +--- src/entry.rs | 2 +- src/eq_op.rs | 2 +- src/strings.rs | 4 +- src/utils.rs | 164 ++++++++++++++++++++++++++++++++++++++----- tests/compile-fail/copies.rs | 76 ++++++++++++++++++-- tests/compile-fail/eq_op.rs | 5 ++ 7 files changed, 227 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index f8fe09c3133..38f1be92d30 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{get_parent_expr, in_macro, is_exp_equal, is_stmt_equal, over, span_lint, span_note_and_lint}; +use utils::{get_parent_expr, in_macro, is_block_equal, is_exp_equal, span_lint, span_note_and_lint}; /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is /// `Warn` by default. @@ -55,14 +55,7 @@ impl LateLintPass for CopyAndPaste { fn lint_same_then_else(cx: &LateContext, expr: &Expr) { if let ExprIf(_, ref then_block, Some(ref else_expr)) = expr.node { let must_lint = if let ExprBlock(ref else_block) = else_expr.node { - over(&then_block.stmts, &else_block.stmts, |l, r| is_stmt_equal(cx, l, r)) && - match (&then_block.expr, &else_block.expr) { - (&Some(ref then_expr), &Some(ref else_expr)) => { - is_exp_equal(cx, &then_expr, &else_expr) - } - (&None, &None) => true, - _ => false, - } + is_block_equal(cx, &then_block, &else_block, false) } else { false @@ -87,7 +80,7 @@ fn lint_same_cond(cx: &LateContext, expr: &Expr) { for (n, i) in conds.iter().enumerate() { for j in conds.iter().skip(n+1) { - if is_exp_equal(cx, i, j) { + if is_exp_equal(cx, i, j, true) { span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); } } diff --git a/src/entry.rs b/src/entry.rs index 64d6fa7be38..d5bb086fc21 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -89,7 +89,7 @@ fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: params.len() == 3, name.node.as_str() == "insert", get_item_name(cx, map) == get_item_name(cx, &*params[0]), - is_exp_equal(cx, key, ¶ms[1]) + is_exp_equal(cx, key, ¶ms[1], false) ], { let help = if sole_expr { format!("{}.entry({}).or_insert({})", diff --git a/src/eq_op.rs b/src/eq_op.rs index 49037cd9ae7..06e4fdc6cb7 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -29,7 +29,7 @@ impl LintPass for EqOp { impl LateLintPass for EqOp { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { - if is_cmp_or_bit(op) && is_exp_equal(cx, left, right) { + if is_cmp_or_bit(op) && is_exp_equal(cx, left, right, true) { span_lint(cx, EQ_OP, e.span, diff --git a/src/strings.rs b/src/strings.rs index f1a1341460e..b78db7f4b77 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -84,7 +84,7 @@ impl LateLintPass for StringAdd { if let Some(ref p) = parent { if let ExprAssign(ref target, _) = p.node { // avoid duplicate matches - if is_exp_equal(cx, target, left) { + if is_exp_equal(cx, target, left, false) { return; } } @@ -113,7 +113,7 @@ fn is_string(cx: &LateContext, e: &Expr) -> bool { fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { - ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left), + ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left, false), ExprBlock(ref block) => { block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) } diff --git a/src/utils.rs b/src/utils.rs index 13fd849993f..a8890f31cb0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -589,59 +589,183 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } } -pub fn is_stmt_equal(cx: &LateContext, left: &Stmt, right: &Stmt) -> bool { +/// Check whether two statements are the same. +/// See also `is_exp_equal`. +pub fn is_stmt_equal(cx: &LateContext, left: &Stmt, right: &Stmt, ignore_fn: bool) -> bool { match (&left.node, &right.node) { - (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => is_exp_equal(cx, l, r), - (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => is_exp_equal(cx, l, r), + (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { + if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { + // TODO: tys + l.ty.is_none() && r.ty.is_none() && + both(&l.init, &r.init, |l, r| is_exp_equal(cx, l, r, ignore_fn)) + } + else { + false + } + } + (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => is_exp_equal(cx, l, r, ignore_fn), + (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => is_exp_equal(cx, l, r, ignore_fn), + _ => false, + } +} + +/// Check whether two blocks are the same. +/// See also `is_exp_equal`. +pub fn is_block_equal(cx: &LateContext, left: &Block, right: &Block, ignore_fn: bool) -> bool { + over(&left.stmts, &right.stmts, |l, r| is_stmt_equal(cx, l, r, ignore_fn)) && + both(&left.expr, &right.expr, |l, r| is_exp_equal(cx, l, r, ignore_fn)) +} + +/// Check whether two pattern are the same. +/// See also `is_exp_equal`. +pub fn is_pat_equal(cx: &LateContext, left: &Pat, right: &Pat, ignore_fn: bool) -> bool { + match (&left.node, &right.node) { + (&PatBox(ref l), &PatBox(ref r)) => { + is_pat_equal(cx, l, r, ignore_fn) + } + (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => { + is_path_equal(lp, rp) && + both(la, ra, |l, r| { + over(l, r, |l, r| is_pat_equal(cx, l, r, ignore_fn)) + }) + } + (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => { + lb == rb && li.node.name.as_str() == ri.node.name.as_str() && + both(lp, rp, |l, r| is_pat_equal(cx, l, r, ignore_fn)) + } + (&PatLit(ref l), &PatLit(ref r)) => { + is_exp_equal(cx, l, r, ignore_fn) + } + (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => { + is_qself_equal(ls, rs) && is_path_equal(lp, rp) + } + (&PatTup(ref l), &PatTup(ref r)) => { + over(l, r, |l, r| is_pat_equal(cx, l, r, ignore_fn)) + } + (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => { + is_exp_equal(cx, ls, rs, ignore_fn) && + is_exp_equal(cx, le, re, ignore_fn) + } + (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => { + lm == rm && is_pat_equal(cx, le, re, ignore_fn) + } + (&PatVec(ref ls, ref li, ref le), &PatVec(ref rs, ref ri, ref re)) => { + over(ls, rs, |l, r| is_pat_equal(cx, l, r, ignore_fn)) && + over(le, re, |l, r| is_pat_equal(cx, l, r, ignore_fn)) && + both(li, ri, |l, r| is_pat_equal(cx, l, r, ignore_fn)) + } + (&PatWild, &PatWild) => true, _ => false, } } -pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr) -> bool { +/// Check whether two expressions are the same. This is different from the operator `==` on +/// expression as this operator would compare true equality with ID and span. +/// If `ignore_fn` is true, never consider as equal fonction calls. +/// +/// Note that some expression kinds are not considered but could be added. +#[allow(cyclomatic_complexity)] // ok, it’s a big function, but mostly one big match with simples cases +pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr, ignore_fn: bool) -> bool { if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { if l == r { return true; } } + match (&left.node, &right.node) { (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => { - lmut == rmut && is_exp_equal(cx, le, re) + lmut == rmut && is_exp_equal(cx, le, re, ignore_fn) + } + (&ExprAgain(li), &ExprAgain(ri)) => { + both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) + } + (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => { + is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) + } + (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => { + lo.node == ro.node && is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) + } + (&ExprBlock(ref l), &ExprBlock(ref r)) => { + is_block_equal(cx, l, r, ignore_fn) } (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { - lop.node == rop.node && is_exp_equal(cx, ll, rl) && is_exp_equal(cx, lr, rr) + lop.node == rop.node && is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) + } + (&ExprBreak(li), &ExprBreak(ri)) => { + both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) + } + (&ExprBox(ref l), &ExprBox(ref r)) => { + is_exp_equal(cx, l, r, ignore_fn) } (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { - is_exp_equal(cx, lfun, rfun) && is_exps_equal(cx, largs, rargs) + !ignore_fn && + is_exp_equal(cx, lfun, rfun, ignore_fn) && + is_exps_equal(cx, largs, rargs, ignore_fn) + } + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => { + is_exp_equal(cx, lx, rx, ignore_fn) && is_cast_ty_equal(lt, rt) } - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt), (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { - lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp) + lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp, ignore_fn) } (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { - is_exp_equal(cx, la, ra) && is_exp_equal(cx, li, ri) + is_exp_equal(cx, la, ra, ignore_fn) && is_exp_equal(cx, li, ri, ignore_fn) + } + (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => { + is_exp_equal(cx, lc, rc, ignore_fn) && + is_block_equal(cx, lt, rt, ignore_fn) && + both(le, re, |l, r| is_exp_equal(cx, l, r, ignore_fn)) } (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, + (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { + ls == rs && + is_exp_equal(cx, le, re, ignore_fn) && + over(la, ra, |l, r| { + is_exp_equal(cx, &l.body, &r.body, ignore_fn) && + both(&l.guard, &r.guard, |l, r| is_exp_equal(cx, l, r, ignore_fn)) && + over(&l.pats, &r.pats, |l, r| is_pat_equal(cx, l, r, ignore_fn)) + }) + } (&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { // TODO: tys - lname.node == rname.node && ltys.is_empty() && rtys.is_empty() && is_exps_equal(cx, largs, rargs) + !ignore_fn && + lname.node == rname.node && + ltys.is_empty() && + rtys.is_empty() && + is_exps_equal(cx, largs, rargs, ignore_fn) + } + (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { + both(lb, rb, |l, r| is_exp_equal(cx, l, r, ignore_fn)) && + both(le, re, |l, r| is_exp_equal(cx, l, r, ignore_fn)) + } + (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => { + is_exp_equal(cx, le, re, ignore_fn) && is_exp_equal(cx, ll, rl, ignore_fn) + } + (&ExprRet(ref l), &ExprRet(ref r)) => { + both(l, r, |l, r| is_exp_equal(cx, l, r, ignore_fn)) } (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { both(lqself, rqself, is_qself_equal) && is_path_equal(lsubpath, rsubpath) } - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup), + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup, ignore_fn), (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { - li.node == ri.node && is_exp_equal(cx, le, re) + li.node == ri.node && is_exp_equal(cx, le, re, ignore_fn) } (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => { - lop == rop && is_exp_equal(cx, le, re) + lop == rop && is_exp_equal(cx, le, re, ignore_fn) + } + (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r, ignore_fn), + (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => { + is_exp_equal(cx, lc, rc, ignore_fn) && + is_block_equal(cx, lb, rb, ignore_fn) && + both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) } - (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r), _ => false, } } -fn is_exps_equal(cx: &LateContext, left: &[P<Expr>], right: &[P<Expr>]) -> bool { - over(left, right, |l, r| is_exp_equal(cx, l, r)) +fn is_exps_equal(cx: &LateContext, left: &[P<Expr>], right: &[P<Expr>], ignore_fn: bool) -> bool { + over(left, right, |l, r| is_exp_equal(cx, l, r, ignore_fn)) } fn is_path_equal(left: &Path, right: &Path) -> bool { @@ -650,20 +774,22 @@ fn is_path_equal(left: &Path, right: &Path) -> bool { left.global == right.global && over(&left.segments, &right.segments, - |l, r| l.identifier.name == r.identifier.name && l.parameters == r.parameters) + |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters) } fn is_qself_equal(left: &QSelf, right: &QSelf) -> bool { left.ty.node == right.ty.node && left.position == right.position } +/// Check if two slices are equal as per `eq_fn`. pub fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool +/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. +pub fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool { l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 94c5c620f34..0f57b619ccc 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -2,11 +2,15 @@ #![plugin(clippy)] #![allow(dead_code)] -#![deny(clippy)] +#![allow(let_and_return)] +#![allow(needless_return)] +#![allow(unused_variables)] +#![deny(if_same_then_else)] +#![deny(ifs_same_cond)] fn foo() -> bool { unimplemented!() } -fn if_same_then_else() { +fn if_same_then_else() -> &'static str { if true { //~ERROR this if has the same then and else blocks foo(); } @@ -41,6 +45,62 @@ fn if_same_then_else() { else { 42 }; + + if true { //~ERROR this if has the same then and else blocks + let bar = if true { + 42 + } + else { + 43 + }; + + while foo() { break; } + bar + 1; + } + else { + let bar = if true { + 42 + } + else { + 43 + }; + + while foo() { break; } + bar + 1; + } + + if true { //~ERROR this if has the same then and else blocks + match 42 { + 42 => (), + a if a > 0 => (), + 10...15 => (), + _ => (), + } + } + else { + match 42 { + 42 => (), + a if a > 0 => (), + 10...15 => (), + _ => (), + } + } + + if true { //~ERROR this if has the same then and else blocks + if let Some(a) = Some(42) {} + } + else { + if let Some(a) = Some(42) {} + } + + if true { //~ERROR this if has the same then and else blocks + let foo = ""; + return &foo[0..]; + } + else { + let foo = ""; + return &foo[0..]; + } } fn ifs_same_cond() { @@ -60,11 +120,15 @@ fn ifs_same_cond() { else if a == 1 { } - // Ok, maybe `foo` isn’t pure and this actually makes sense. But you should probably refactor - // this to make the intention clearer anyway. - if foo() { + let mut v = vec![1]; + if v.pop() == None { // ok, functions + } + else if v.pop() == None { + } + + if v.len() == 42 { // ok, functions } - else if foo() { //~ERROR this if has the same condition as a previous if + else if v.len() == 42 { } } diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index fc59c2739a2..fe74d182da1 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -32,4 +32,9 @@ fn main() { // const folding 1 + 1 == 2; //~ERROR equal expressions 1 - 1 == 0; //~ERROR equal expressions + + let mut a = vec![1]; + a == a; //~ERROR equal expressions + 2*a.len() == 2*a.len(); // ok, functions + a.pop() == a.pop(); // ok, functions } -- cgit 1.4.1-3-g733a5 From cd7a9132001e0a6de7ee2f7420c63bdf98ca6eff Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 3 Feb 2016 20:42:05 +0100 Subject: Add `-` and `/` to EQ_OP --- src/eq_op.rs | 14 +++++++++----- tests/compile-fail/eq_op.rs | 14 ++++++++++---- tests/compile-fail/identity_op.rs | 1 + tests/compile-fail/zero_div_zero.rs | 4 ++++ 4 files changed, 24 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/eq_op.rs b/src/eq_op.rs index 06e4fdc6cb7..aecd0693ff1 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -4,9 +4,11 @@ use rustc_front::util as ast_util; use utils::{is_exp_equal, span_lint}; -/// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). +/// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, +/// difference and division binary operators (`==`, `>`, etc., `&&`, `||`, `&`, `|`, `^`, `-` and +/// `/`). /// -/// **Why is this bad?** This is usually just a typo. +/// **Why is this bad?** This is usually just a typo or a copy and paste error. /// /// **Known problems:** False negatives: We had some false positives regarding calls (notably [racer](https://github.com/phildawes/racer) had one instance of `x.pop() && x.pop()`), so we removed matching any function or method calls. We may introduce a whitelist of known pure functions in the future. /// @@ -29,19 +31,21 @@ impl LintPass for EqOp { impl LateLintPass for EqOp { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { - if is_cmp_or_bit(op) && is_exp_equal(cx, left, right, true) { + if is_valid_operator(op) && is_exp_equal(cx, left, right, true) { span_lint(cx, EQ_OP, e.span, - &format!("equal expressions as operands to {}", ast_util::binop_to_string(op.node))); + &format!("equal expressions as operands to `{}`", ast_util::binop_to_string(op.node))); } } } } -fn is_cmp_or_bit(op: &BinOp) -> bool { +fn is_valid_operator(op: &BinOp) -> bool { match op.node { + BiSub | + BiDiv | BiEq | BiLt | BiLe | diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index fe74d182da1..7be5ef11ce6 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -19,9 +19,9 @@ fn main() { // unary and binary operators (-(2) < -(2)); //~ERROR equal expressions ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); - //~^ ERROR equal expressions - //~^^ ERROR equal expressions - //~^^^ ERROR equal expressions + //~^ ERROR equal expressions as operands to `==` + //~^^ ERROR equal expressions as operands to `&` + //~^^^ ERROR equal expressions as operands to `&` (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; //~ERROR equal expressions // various other things @@ -31,7 +31,13 @@ fn main() { // const folding 1 + 1 == 2; //~ERROR equal expressions - 1 - 1 == 0; //~ERROR equal expressions + 1 - 1 == 0; //~ERROR equal expressions as operands to `==` + //~^ ERROR equal expressions as operands to `-` + + 1 - 1; //~ERROR equal expressions + 1 / 1; //~ERROR equal expressions + true && true; //~ERROR equal expressions + true || true; //~ERROR equal expressions let mut a = vec![1]; a == a; //~ERROR equal expressions diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs index 54551852d5e..c1141e0b460 100644 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -5,6 +5,7 @@ const ONE : i64 = 1; const NEG_ONE : i64 = -1; const ZERO : i64 = 0; +#[allow(eq_op)] #[deny(identity_op)] fn main() { let x = 0; diff --git a/tests/compile-fail/zero_div_zero.rs b/tests/compile-fail/zero_div_zero.rs index 8c40923d3ed..c422e83873b 100644 --- a/tests/compile-fail/zero_div_zero.rs +++ b/tests/compile-fail/zero_div_zero.rs @@ -5,9 +5,13 @@ #[deny(zero_divided_by_zero)] fn main() { let nan = 0.0 / 0.0; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + //~^ equal expressions as operands to `/` let f64_nan = 0.0 / 0.0f64; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + //~^ equal expressions as operands to `/` let other_f64_nan = 0.0f64 / 0.0; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + //~^ equal expressions as operands to `/` let one_more_f64_nan = 0.0f64/0.0f64; //~ERROR constant division of 0.0 with 0.0 will always result in NaN + //~^ equal expressions as operands to `/` let zero = 0.0; let other_zero = 0.0; let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants. -- cgit 1.4.1-3-g733a5 From 344698377f04124a5df01e498e55c3e27eac294d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 5 Feb 2016 19:43:21 +0100 Subject: Fix typo --- README.md | 2 +- src/copies.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 01999cce70b..d134afe8a8e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 114 lints included in this crate: +There are 116 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/copies.rs b/src/copies.rs index 38f1be92d30..84324dffc85 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -87,7 +87,7 @@ fn lint_same_cond(cx: &LateContext, expr: &Expr) { } } -/// Return the list of conditions expression in a sequence of `if/else`. +/// Return the list of condition expressions in a sequence of `if/else`. /// Eg. would return `[a, b]` for the expression `if a {..} else if b {..}`. fn condition_sequence(mut expr: &Expr) -> Vec<&Expr> { let mut result = vec![]; -- cgit 1.4.1-3-g733a5 From a9e1b1fba05ce94a65f511e2c07bd086c1b0f00f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 7 Feb 2016 14:40:45 +0100 Subject: Small cleanup --- src/copies.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 84324dffc85..525c7b7a6fd 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -54,15 +54,10 @@ impl LateLintPass for CopyAndPaste { /// Implementation of `IF_SAME_THEN_ELSE`. fn lint_same_then_else(cx: &LateContext, expr: &Expr) { if let ExprIf(_, ref then_block, Some(ref else_expr)) = expr.node { - let must_lint = if let ExprBlock(ref else_block) = else_expr.node { - is_block_equal(cx, &then_block, &else_block, false) - } - else { - false - }; - - if must_lint { - span_lint(cx, IF_SAME_THEN_ELSE, expr.span, "this if has the same then and else blocks"); + if let ExprBlock(ref else_block) = else_expr.node { + if is_block_equal(cx, &then_block, &else_block, false) { + span_lint(cx, IF_SAME_THEN_ELSE, expr.span, "this if has the same then and else blocks"); + } } } } -- cgit 1.4.1-3-g733a5 From ceb9a8bdd79e4c2081d88d40d3a8a2b6f080268f Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 7 Feb 2016 22:50:54 +0100 Subject: regex macro lint --- src/regex.rs | 56 +++++++++++++++++++++++++++++++++++++++++++-- tests/compile-fail/regex.rs | 11 +++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/regex.rs b/src/regex.rs index cf19c764361..e7abc9be876 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,14 +1,16 @@ use regex_syntax; use std::error::Error; use syntax::ast::Lit_::LitStr; +use syntax::ast::NodeId; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; +use rustc_front::intravisit::{Visitor, walk_block, FnKind}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; -use utils::{match_path, REGEX_NEW_PATH, span_lint, span_help_and_lint}; +use utils::{is_expn_of, match_path, REGEX_NEW_PATH, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// @@ -37,16 +39,41 @@ declare_lint! { "finds trivial regular expressions in `Regex::new(_)` invocations" } +/// **What it does:** This lint checks for usage of `regex!(_)` which as of now is usually slower than `Regex::new(_)` unless called in a loop (which is a bad idea anyway). +/// +/// **Why is this bad?** Performance, at least for now. The macro version is likely to catch up long-term, but for now the dynamic version is faster. +/// +/// **Known problems:** None +/// +/// **Example:** `regex!("foo|bar")` +declare_lint! { + pub REGEX_MACRO, + Allow, + "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" +} + #[derive(Copy,Clone)] pub struct RegexPass; impl LintPass for RegexPass { fn get_lints(&self) -> LintArray { - lint_array!(INVALID_REGEX, TRIVIAL_REGEX) + lint_array!(INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX) } } impl LateLintPass for RegexPass { + fn check_fn(&mut self, + cx: &LateContext, + _: FnKind, + _: &FnDecl, + block: &Block, + _: Span, + _: NodeId) { + let mut visitor = RegexVisitor { cx: cx, last: BytePos(0) }; + visitor.visit_block(block); + } + + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain!{[ let ExprCall(ref fun, ref args) = expr.node, @@ -139,3 +166,28 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { _ => None, } } + +struct RegexVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, + last: BytePos +} + +impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { + fn visit_block(&mut self, block: &'v Block) { + if let Some(ref expr) = block.expr { + if let Some(span) = is_expn_of(self.cx, expr.span, "regex") { + if span.lo == BytePos(0) || span.lo == self.last { + return; + } + span_lint(self.cx, + REGEX_MACRO, + span, + &format!("regex!(_): {:?}, {:?}", self.last, span.lo)); + //"`regex!(_)` found. Use `Regex::new(_)`, which is faster for now."); + self.last = span.lo; + return; + } + } + walk_block(self, block); + } +} diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index 2e8228a823d..df52cc3dff0 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -1,8 +1,8 @@ #![feature(plugin)] -#![plugin(clippy)] +#![plugin(clippy, regex_macros)] #![allow(unused)] -#![deny(invalid_regex, trivial_regex)] +#![deny(invalid_regex, trivial_regex, regex_macro)] extern crate regex; @@ -70,7 +70,14 @@ fn trivial_regex() { let non_trivial_ends_with = Regex::new("foo|bar"); } +fn regex_macro() { + let some_regex = regex!("for real!"); //~ERROR `regex!(_)` + let other_regex = regex!("[a-z]_[A-Z]"); //~ERROR `regex!(_)` +} + + fn main() { + regex_macro(); syntax_error(); trivial_regex(); } -- cgit 1.4.1-3-g733a5 From 672beb4138011446ee55360e71a857197ae18d97 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 8 Feb 2016 11:28:18 +0100 Subject: prevent panic in enum glob import lint if a crate's elements are glob imported fixes #639 --- src/enum_glob_use.rs | 10 ++++++---- tests/compile-test.rs | 1 + tests/run-pass/enum-glob-import-crate.rs | 7 +++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/enum-glob-import-crate.rs (limited to 'src') diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index d6df307fec2..c6561461e04 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -3,7 +3,7 @@ use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; use rustc_front::hir::*; use rustc::front::map::Node::NodeItem; -use rustc::front::map::PathElem::PathName; +use rustc::front::map::definitions::DefPathData; use rustc::middle::ty::TyEnum; use utils::span_lint; use syntax::codemap::Span; @@ -49,9 +49,11 @@ impl EnumGlobUse { span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } } else { - if let Some(&PathName(_)) = cx.sess().cstore.item_path(def.def_id()).last() { - if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() { + if let DefPathData::Type(_) = dp.data { + if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + } } } } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 92d2671eaa7..822d9339ba3 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -21,5 +21,6 @@ fn run_mode(mode: &'static str) { #[test] fn compile_test() { + run_mode("run-pass"); run_mode("compile-fail"); } diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs new file mode 100644 index 00000000000..5b54698605a --- /dev/null +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -0,0 +1,7 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy)] + +use std::*; + +fn main() { } -- cgit 1.4.1-3-g733a5 From 652547121490c642f033668043711ba7009b8169 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Mon, 8 Feb 2016 23:48:04 +0100 Subject: fix #595 --- src/lib.rs | 1 + src/regex.rs | 44 ++++++++++++++++++-------------------------- tests/mut_mut_macro.rs | 1 + 3 files changed, 20 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 33de4d6fb79..6f47dfea2f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,6 +257,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ranges::RANGE_STEP_BY_ZERO, ranges::RANGE_ZIP_WITH_LEN, regex::INVALID_REGEX, + regex::REGEX_MACRO, regex::TRIVIAL_REGEX, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, diff --git a/src/regex.rs b/src/regex.rs index e7abc9be876..1f5d7faba06 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,11 +1,11 @@ use regex_syntax; use std::error::Error; +use std::collections::HashSet; use syntax::ast::Lit_::LitStr; -use syntax::ast::NodeId; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_block, FnKind}; +use rustc_front::intravisit::{Visitor, walk_expr}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; @@ -48,7 +48,7 @@ declare_lint! { /// **Example:** `regex!("foo|bar")` declare_lint! { pub REGEX_MACRO, - Allow, + Warn, "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" } @@ -62,15 +62,9 @@ impl LintPass for RegexPass { } impl LateLintPass for RegexPass { - fn check_fn(&mut self, - cx: &LateContext, - _: FnKind, - _: &FnDecl, - block: &Block, - _: Span, - _: NodeId) { - let mut visitor = RegexVisitor { cx: cx, last: BytePos(0) }; - visitor.visit_block(block); + fn check_crate(&mut self, cx: &LateContext, krate: &Crate) { + let mut visitor = RegexVisitor { cx: cx, spans: HashSet::new() }; + krate.visit_all_items(&mut visitor); } @@ -169,25 +163,23 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { struct RegexVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, - last: BytePos + spans: HashSet<Span>, } impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { - fn visit_block(&mut self, block: &'v Block) { - if let Some(ref expr) = block.expr { - if let Some(span) = is_expn_of(self.cx, expr.span, "regex") { - if span.lo == BytePos(0) || span.lo == self.last { - return; - } - span_lint(self.cx, - REGEX_MACRO, - span, - &format!("regex!(_): {:?}, {:?}", self.last, span.lo)); - //"`regex!(_)` found. Use `Regex::new(_)`, which is faster for now."); - self.last = span.lo; + fn visit_expr(&mut self, expr: &'v Expr) { + if let Some(span) = is_expn_of(self.cx, expr.span, "regex") { + if self.spans.contains(&span) { return; } + span_lint(self.cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now."); + self.spans.insert(span); + return; } - walk_block(self, block); + walk_expr(self, expr); } } diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs index ebfd3ed2e1f..67d73ce0ac4 100644 --- a/tests/mut_mut_macro.rs +++ b/tests/mut_mut_macro.rs @@ -9,6 +9,7 @@ use std::collections::HashMap; #[test] #[deny(mut_mut)] +#[allow(regex_macro)] fn test_regex() { let pattern = regex!(r"^(?P<level>[#]+)\s(?P<title>.+)$"); assert!(pattern.is_match("# headline")); -- cgit 1.4.1-3-g733a5 From 275795fab321d860cd9f01243f861bf804b1e53c Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Tue, 9 Feb 2016 06:18:08 +0100 Subject: speed up lint using blocks and types --- src/regex.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/regex.rs b/src/regex.rs index 1f5d7faba06..cf938dcf4b3 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -5,12 +5,12 @@ use syntax::ast::Lit_::LitStr; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_expr}; +use rustc_front::intravisit::{Visitor, walk_block}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; -use utils::{is_expn_of, match_path, REGEX_NEW_PATH, span_lint, span_help_and_lint}; +use utils::{is_expn_of, match_path, match_type, REGEX_NEW_PATH, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// @@ -167,19 +167,23 @@ struct RegexVisitor<'v, 't: 'v> { } impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { - if let Some(span) = is_expn_of(self.cx, expr.span, "regex") { - if self.spans.contains(&span) { + fn visit_block(&mut self, block: &'v Block) { + if_let_chain!{[ + let Some(ref expr) = block.expr, + match_type(self.cx, self.cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), + let Some(span) = is_expn_of(self.cx, expr.span, "regex") + ], { + if self.spans.contains(&span) { + return; + } + span_lint(self.cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now."); + self.spans.insert(span); return; - } - span_lint(self.cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); - self.spans.insert(span); - return; - } - walk_expr(self, expr); + }} + walk_block(self, block); } } -- cgit 1.4.1-3-g733a5 From 56b3e7b4c2308be84ce4eed18f03743cc592b780 Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Tue, 9 Feb 2016 14:10:22 -0500 Subject: lint comparison to bool (e.g. `y == true`) Addresses #630 --- src/lib.rs | 2 ++ src/needless_bool.rs | 66 +++++++++++++++++++++++++++++++++++ tests/compile-fail/bool_comparison.rs | 12 +++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/compile-fail/bool_comparison.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 728aa124a18..c1e8c3c9f01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,6 +105,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box bit_mask::BitMask); reg.register_late_lint_pass(box ptr_arg::PtrArg); reg.register_late_lint_pass(box needless_bool::NeedlessBool); + reg.register_late_lint_pass(box needless_bool::BoolComparison); reg.register_late_lint_pass(box approx_const::ApproxConstant); reg.register_late_lint_pass(box misc::FloatCmp); reg.register_early_lint_pass(box precedence::Precedence); @@ -253,6 +254,7 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::NEEDLESS_BOOL, + needless_bool::BOOL_COMPARISON, needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, diff --git a/src/needless_bool.rs b/src/needless_bool.rs index bfd819edcb6..a2a0d13e17c 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -6,6 +6,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::Lit_; +use syntax::codemap::Spanned; use utils::{span_lint, snippet}; @@ -23,6 +24,20 @@ declare_lint! { `if p { true } else { false }`" } +/// **What it does:** This lint checks for expressions of the form `x == true` (or vice versa) and suggest using the variable directly. +/// +/// **Why is this bad?** Unnecessary code. +/// +/// **Known problems:** None. +/// +/// **Example:** `if x == true { }` could be `if x { }` +declare_lint! { + pub BOOL_COMPARISON, + Warn, + "comparing a variable to a boolean, e.g. \ + `if x == true`" +} + #[derive(Copy,Clone)] pub struct NeedlessBool; @@ -78,6 +93,57 @@ impl LateLintPass for NeedlessBool { } } +#[derive(Copy,Clone)] +pub struct BoolComparison; + +impl LintPass for BoolComparison { + fn get_lints(&self) -> LintArray { + lint_array!(BOOL_COMPARISON) + } +} + +impl LateLintPass for BoolComparison { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + 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)) { + (Some(true), None) => { + let side_snip = snippet(cx, right_side.span, ".."); + let hint = format!("`{}`", side_snip); + span_lint(cx, + BOOL_COMPARISON, + e.span, + &format!("you can simplify this boolean comparison to {}", hint)); + } + (None, Some(true)) => { + let side_snip = snippet(cx, left_side.span, ".."); + let hint = format!("`{}`", side_snip); + span_lint(cx, + BOOL_COMPARISON, + e.span, + &format!("you can simplify this boolean comparison to {}", hint)); + } + (Some(false), None) => { + let side_snip = snippet(cx, right_side.span, ".."); + let hint = format!("`!{}`", side_snip); + span_lint(cx, + BOOL_COMPARISON, + e.span, + &format!("you can simplify this boolean comparison to {}", hint)); + } + (None, Some(false)) => { + let side_snip = snippet(cx, left_side.span, ".."); + let hint = format!("`!{}`", side_snip); + span_lint(cx, + BOOL_COMPARISON, + e.span, + &format!("you can simplify this boolean comparison to {}", hint)); + } + _ => (), + } + } + } +} + fn fetch_bool_block(block: &Block) -> Option<bool> { if block.stmts.is_empty() { block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) diff --git a/tests/compile-fail/bool_comparison.rs b/tests/compile-fail/bool_comparison.rs new file mode 100644 index 00000000000..d2a362af2f4 --- /dev/null +++ b/tests/compile-fail/bool_comparison.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[allow(needless_bool)] +#[deny(bool_comparison)] +fn main() { + let x = true; + if x == true { true } else { false }; //~ERROR you can simplify this boolean comparison to `x` + if x == false { true } else { false }; //~ERROR you can simplify this boolean comparison to `!x` + if true == x { true } else { false }; //~ERROR you can simplify this boolean comparison to `x` + if false == x { true } else { false }; //~ERROR you can simplify this boolean comparison to `!x` +} -- cgit 1.4.1-3-g733a5 From 14292674b0cc828ced88731d15c86035045fa206 Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Tue, 9 Feb 2016 14:44:42 -0500 Subject: display suggestion separately from lint --- src/needless_bool.rs | 46 ++++++++++++++++++++++------------- tests/compile-fail/bool_comparison.rs | 21 ++++++++++++---- 2 files changed, 45 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/needless_bool.rs b/src/needless_bool.rs index a2a0d13e17c..a40b4b3a252 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -8,7 +8,7 @@ use rustc_front::hir::*; use syntax::ast::Lit_; use syntax::codemap::Spanned; -use utils::{span_lint, snippet}; +use utils::{span_lint, span_lint_and_then, snippet}; /// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. /// @@ -109,34 +109,46 @@ impl LateLintPass for BoolComparison { (Some(true), None) => { let side_snip = snippet(cx, right_side.span, ".."); let hint = format!("`{}`", side_snip); - span_lint(cx, - BOOL_COMPARISON, - e.span, - &format!("you can simplify this boolean comparison to {}", hint)); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against booleans are unnecesary", + |db| { + db.span_suggestion(e.span, "try simplifying it:", hint); + }); } (None, Some(true)) => { let side_snip = snippet(cx, left_side.span, ".."); let hint = format!("`{}`", side_snip); - span_lint(cx, - BOOL_COMPARISON, - e.span, - &format!("you can simplify this boolean comparison to {}", hint)); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against booleans are unnecesary", + |db| { + db.span_suggestion(e.span, "try simplifying it:", hint); + }); } (Some(false), None) => { let side_snip = snippet(cx, right_side.span, ".."); let hint = format!("`!{}`", side_snip); - span_lint(cx, - BOOL_COMPARISON, - e.span, - &format!("you can simplify this boolean comparison to {}", hint)); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against booleans are unnecesary", + |db| { + db.span_suggestion(e.span, "try simplifying it:", hint); + }); } (None, Some(false)) => { let side_snip = snippet(cx, left_side.span, ".."); let hint = format!("`!{}`", side_snip); - span_lint(cx, - BOOL_COMPARISON, - e.span, - &format!("you can simplify this boolean comparison to {}", hint)); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against booleans are unnecesary", + |db| { + db.span_suggestion(e.span, "try simplifying it:", hint); + }); } _ => (), } diff --git a/tests/compile-fail/bool_comparison.rs b/tests/compile-fail/bool_comparison.rs index d2a362af2f4..468b8382e94 100644 --- a/tests/compile-fail/bool_comparison.rs +++ b/tests/compile-fail/bool_comparison.rs @@ -1,12 +1,23 @@ #![feature(plugin)] #![plugin(clippy)] -#[allow(needless_bool)] #[deny(bool_comparison)] fn main() { let x = true; - if x == true { true } else { false }; //~ERROR you can simplify this boolean comparison to `x` - if x == false { true } else { false }; //~ERROR you can simplify this boolean comparison to `!x` - if true == x { true } else { false }; //~ERROR you can simplify this boolean comparison to `x` - if false == x { true } else { false }; //~ERROR you can simplify this boolean comparison to `!x` + if x == true { "yes" } else { "no" }; + //~^ ERROR equality checks against booleans are unnecesary + //~| HELP try simplifying it: + //~| SUGGESTION x + if x == false { "yes" } else { "no" }; + //~^ ERROR equality checks against booleans are unnecesary + //~| HELP try simplifying it: + //~| SUGGESTION !x + if true == x { "yes" } else { "no" }; + //~^ ERROR equality checks against booleans are unnecesary + //~| HELP try simplifying it: + //~| SUGGESTION x + if false == x { "yes" } else { "no" }; + //~^ ERROR equality checks against booleans are unnecesary + //~| HELP try simplifying it: + //~| SUGGESTION !x } -- cgit 1.4.1-3-g733a5 From 2687a3f6b590f7175d87a95dd49ccf2f11c9d2e3 Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Tue, 9 Feb 2016 14:52:20 -0500 Subject: Update lints --- README.md | 3 ++- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index cbb8646c672..4f5cdf30606 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 117 lints included in this crate: +There are 118 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -15,6 +15,7 @@ name [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` [block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` +[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true` [box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap [boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary [cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` diff --git a/src/lib.rs b/src/lib.rs index c1e8c3c9f01..3485b83a18b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,8 +253,8 @@ pub fn plugin_registrar(reg: &mut Registry) { misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, - needless_bool::NEEDLESS_BOOL, needless_bool::BOOL_COMPARISON, + needless_bool::NEEDLESS_BOOL, needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, -- cgit 1.4.1-3-g733a5 From 34812e82d066dc1b3ef89df4272300662374f907 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 7 Feb 2016 18:10:03 +0100 Subject: Use const_eval in loops --- src/loops.rs | 43 ++++++++++++++++++++++++++++-------------- tests/compile-fail/for_loop.rs | 22 ++++++++++++++++++--- 2 files changed, 48 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 4620d6a3e81..cecf47daf55 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,11 +1,12 @@ +use reexport::*; +use rustc::front::map::Node::NodeBlock; use rustc::lint::*; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; +use rustc::middle::def::Def; +use rustc::middle::ty; use rustc_front::hir::*; -use reexport::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; -use rustc::middle::ty; -use rustc::middle::def::Def; -use consts::{constant_simple, Constant}; -use rustc::front::map::Node::NodeBlock; use std::borrow::Cow; use std::collections::{HashSet, HashMap}; @@ -421,22 +422,36 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { // ...and both sides are compile-time constant integers... - if let Some(start_idx @ Constant::Int(..)) = constant_simple(start_expr) { - if let Some(stop_idx @ Constant::Int(..)) = constant_simple(stop_expr) { + if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start_expr, ExprTypeChecked, None) { + if let Ok(stop_idx) = eval_const_expr_partial(&cx.tcx, stop_expr, ExprTypeChecked, None) { // ...and the start index is greater than the stop index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the // smaller value. - if start_idx > stop_idx { - span_help_and_lint(cx, + let (sup, eq) = match (start_idx, stop_idx) { + (ConstVal::Int(start_idx), ConstVal::Int(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), + (ConstVal::Uint(start_idx), ConstVal::Uint(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), + _ => (false, false), + }; + + if sup { + let start_snippet = snippet(cx, start_expr.span, "_"); + let stop_snippet = snippet(cx, stop_expr.span, "_"); + + span_lint_and_then(cx, REVERSE_RANGE_LOOP, expr.span, "this range is empty so this for loop will never run", - &format!("Consider using `({}..{}).rev()` if you are attempting to iterate \ - over this range in reverse", - stop_idx, - start_idx)); - } else if start_idx == stop_idx { + |db| { + db.span_suggestion(expr.span, + "consider using the following if \ + you are attempting to iterate \ + over this range in reverse", + format!("({}..{}).rev()` ", + stop_snippet, + start_snippet)); + }); + } else if eq { // if they are equal, it's also problematic - this loop // will never run. span_lint(cx, diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index e361ebe777f..4609c840836 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -65,7 +65,7 @@ fn for_loop_over_option_and_result() { break; } - // while let false positive for Option + // while let false positive for Result while let Ok(x) = result { println!("{}", x); break; @@ -85,8 +85,10 @@ impl Unrelated { #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] -#[allow(linkedlist,shadow_unrelated,unnecessary_mut_passed, cyclomatic_complexity)] +#[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity)] fn main() { + const MAX_LEN: usize = 42; + let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; for i in 0..vec.len() { @@ -111,6 +113,11 @@ fn main() { println!("{}", vec[i]); } + for i in 0..MAX_LEN { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(MAX_LEN)` + println!("{}", vec[i]); + } + for i in 5..10 { //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)` println!("{}", vec[i]); @@ -126,7 +133,16 @@ fn main() { println!("{} {}", vec[i], i); } - for i in 10..0 { //~ERROR this range is empty so this for loop will never run + for i in 10..0 { + //~^ERROR this range is empty so this for loop will never run + //~|HELP consider + //~|SUGGESTION (0..10).rev() + println!("{}", i); + } + + for i in MAX_LEN..0 { //~ERROR this range is empty so this for loop will never run + //~|HELP consider + //~|SUGGESTION (0..MAX_LEN).rev() println!("{}", i); } -- cgit 1.4.1-3-g733a5 From d27aa960b605f69a22b83917ba3830bd2d5690ec Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 7 Feb 2016 18:14:03 +0100 Subject: Remove unused Display implementation for consts --- src/consts.rs | 86 ----------------------------------------------------------- 1 file changed, 86 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 5f40aff92cc..ddc8560c9b3 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -6,12 +6,10 @@ use rustc::middle::def::PathResolution; use rustc::middle::def::Def; use rustc_front::hir::*; use syntax::ptr::P; -use std::char; use std::cmp::PartialOrd; use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; -use std::fmt; use syntax::ast::Lit_; use syntax::ast::LitIntType; @@ -173,90 +171,6 @@ impl PartialOrd for Constant { } } -fn format_byte(fmt: &mut fmt::Formatter, b: u8) -> fmt::Result { - if b == b'\\' { - write!(fmt, "\\\\") - } else if 0x20 <= b && b <= 0x7e { - write!(fmt, "{}", char::from_u32(b as u32).expect("all u8 are valid char")) - } else if b == 0x0a { - write!(fmt, "\\n") - } else if b == 0x0d { - write!(fmt, "\\r") - } else { - write!(fmt, "\\x{:02x}", b) - } -} - -impl fmt::Display for Constant { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - Constant::Str(ref s, _) => write!(fmt, "{:?}", s), - Constant::Byte(ref b) => { - write!(fmt, "b'") - .and_then(|_| format_byte(fmt, *b)) - .and_then(|_| write!(fmt, "'")) - } - Constant::Binary(ref bs) => { - try!(write!(fmt, "b\"")); - for b in bs.iter() { - try!(format_byte(fmt, *b)); - } - write!(fmt, "\"") - } - Constant::Char(ref c) => write!(fmt, "'{}'", c), - Constant::Int(ref i, ref ity) => { - let (sign, suffix) = match *ity { - LitIntType::SignedIntLit(ref sity, ref sign) => { - (if let Sign::Minus = *sign { - "-" - } else { - "" - }, - sity.ty_to_string()) - } - LitIntType::UnsignedIntLit(ref uity) => ("", uity.ty_to_string()), - LitIntType::UnsuffixedIntLit(ref sign) => { - (if let Sign::Minus = *sign { - "-" - } else { - "" - }, - "".into()) - } - }; - write!(fmt, "{}{}{}", sign, i, suffix) - } - Constant::Float(ref s, ref fw) => { - let suffix = match *fw { - FloatWidth::Fw32 => "f32", - FloatWidth::Fw64 => "f64", - FloatWidth::FwAny => "", - }; - write!(fmt, "{}{}", s, suffix) - } - Constant::Bool(ref b) => write!(fmt, "{}", b), - Constant::Repeat(ref c, ref n) => write!(fmt, "[{}; {}]", c, n), - Constant::Vec(ref v) => { - write!(fmt, - "[{}]", - v.iter() - .map(|i| format!("{}", i)) - .collect::<Vec<_>>() - .join(", ")) - } - Constant::Tuple(ref t) => { - write!(fmt, - "({})", - t.iter() - .map(|i| format!("{}", i)) - .collect::<Vec<_>>() - .join(", ")) - } - } - } -} - - fn lit_to_constant(lit: &Lit_) -> Constant { match *lit { Lit_::LitStr(ref is, style) => Constant::Str(is.to_string(), style), -- cgit 1.4.1-3-g733a5 From 1a8b8cd28f3e452a1c4bfc2208ada1a2f4a0ebda Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 7 Feb 2016 18:28:37 +0100 Subject: Don’t use `{:?}` and use span_suggestion in TOPLEVEL_REF_ARG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/misc.rs | 16 +++++++++++----- tests/compile-fail/toplevel_ref_arg.rs | 12 ++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index c0aed78225a..f570c18b742 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -11,7 +11,7 @@ use rustc::middle::const_eval::eval_const_expr_partial; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; -use utils::{span_help_and_lint, walk_ptrs_ty, is_integer_literal, implements_trait}; +use utils::{span_lint_and_then, walk_ptrs_ty, is_integer_literal, implements_trait}; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. /// @@ -62,16 +62,22 @@ impl LateLintPass for TopLevelRefPass { let Some(ref init) = l.init ], { let tyopt = if let Some(ref ty) = l.ty { - format!(": {:?} ", ty) + format!(": {}", snippet(cx, ty.span, "_")) } else { "".to_owned() }; - span_help_and_lint(cx, + span_lint_and_then(cx, TOPLEVEL_REF_ARG, l.pat.span, "`ref` on an entire `let` pattern is discouraged, take a reference with & instead", - &format!("try `let {} {}= &{};`", snippet(cx, i.span, "_"), - tyopt, snippet(cx, init.span, "_")) + |db| { + db.span_suggestion(s.span, + "try", + format!("let {}{} = &{};", + snippet(cx, i.span, "_"), + tyopt, + snippet(cx, init.span, "_"))); + } ); } }; diff --git a/tests/compile-fail/toplevel_ref_arg.rs b/tests/compile-fail/toplevel_ref_arg.rs index 05ad1af0034..de1556ed0e3 100644 --- a/tests/compile-fail/toplevel_ref_arg.rs +++ b/tests/compile-fail/toplevel_ref_arg.rs @@ -15,11 +15,15 @@ fn main() { let y = |ref x| { println!("{:?}", x) }; y(1u8); - let ref x = 1; //~ ERROR `ref` on an entire `let` pattern is discouraged - //~^ HELP try `let x = &1;` + let ref x = 1; + //~^ ERROR `ref` on an entire `let` pattern is discouraged + //~| HELP try + //~| SUGGESTION let x = &1; - let ref y = (&1, 2); //~ ERROR `ref` on an entire `let` pattern is discouraged - //~^ HELP try `let y = &(&1, 2);` + let ref y : (&_, u8) = (&1, 2); + //~^ ERROR `ref` on an entire `let` pattern is discouraged + //~| HELP try + //~| SUGGESTION let y: (&_, u8) = &(&1, 2); let (ref x, _) = (1,2); // okay, not top level println!("The answer is {}.", x); -- cgit 1.4.1-3-g733a5 From 2db6965c81ee9f01b12874c115ec2a593b5f2c5f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 7 Feb 2016 18:30:57 +0100 Subject: Lint usage of `Debug`-based formatting --- README.md | 3 ++- src/lib.rs | 1 + src/print.rs | 48 ++++++++++++++++++++++++++++++++++++++++++--- src/utils.rs | 2 ++ tests/compile-fail/print.rs | 32 +++++++++++++++++++++++++++++- 5 files changed, 81 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 4d655c85951..87b58b320ff 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 117 lints included in this crate: +There are 118 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -118,6 +118,7 @@ name [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions +[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` diff --git a/src/lib.rs b/src/lib.rs index cd9ac226321..ba9236012d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,6 +169,7 @@ pub fn plugin_registrar(reg: &mut Registry) { mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, print::PRINT_STDOUT, + print::USE_DEBUG, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, shadow::SHADOW_UNRELATED, diff --git a/src/print.rs b/src/print.rs index d8f5fd488aa..3c10b4bed13 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,6 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{IO_PRINT_PATH, is_expn_of, match_path, span_lint}; +use rustc::front::map::Node::{NodeItem, NodeImplItem}; +use utils::{FMT_ARGUMENTV1_NEW_PATH, DEBUG_FMT_METHOD_PATH, IO_PRINT_PATH}; +use utils::{is_expn_of, match_path, span_lint}; /// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants. /// @@ -16,21 +18,36 @@ declare_lint! { "printing on stdout" } +/// **What it does:** This lint warns whenever you use `Debug` formatting. The purpose of this lint is to catch debugging remnants. +/// +/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate debugging Rust code. It +/// should not be used in in user-facing output. +/// +/// **Example:** `println!("{:?}", foo);` +declare_lint! { + pub USE_DEBUG, + Allow, + "use `Debug`-based formatting" +} + #[derive(Copy, Clone, Debug)] pub struct PrintLint; impl LintPass for PrintLint { fn get_lints(&self) -> LintArray { - lint_array!(PRINT_STDOUT) + lint_array!(PRINT_STDOUT, USE_DEBUG) } } impl LateLintPass for PrintLint { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprCall(ref fun, _) = expr.node { + if let ExprCall(ref fun, ref args) = expr.node { if let ExprPath(_, ref path) = fun.node { + // Search for `std::io::_print(..)` which is unique in a + // `print!` expansion. if match_path(path, &IO_PRINT_PATH) { if let Some(span) = is_expn_of(cx, expr.span, "print") { + // `println!` uses `print!`. let (span, name) = match is_expn_of(cx, span, "println") { Some(span) => (span, "println"), None => (span, "print"), @@ -39,7 +56,32 @@ impl LateLintPass for PrintLint { span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); } } + // Search for something like + // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` + else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) { + if let ExprPath(None, ref path) = args[1].node { + if match_path(path, &DEBUG_FMT_METHOD_PATH) && + !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"); + } + } + } } } } } + +fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { + let map = &cx.tcx.map; + + if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { // `fmt` method + if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) { // `Debug` impl + if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node { + return match_path(&tr.path, &["Debug"]); + } + } + } + + false +} diff --git a/src/utils.rs b/src/utils.rs index a8890f31cb0..4c89b7f113d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,8 +26,10 @@ pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BT pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; +pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; diff --git a/tests/compile-fail/print.rs b/tests/compile-fail/print.rs index 8141cdd2645..34c38dca286 100755 --- a/tests/compile-fail/print.rs +++ b/tests/compile-fail/print.rs @@ -1,11 +1,41 @@ #![feature(plugin)] #![plugin(clippy)] +#![deny(print_stdout, use_debug)] -#[deny(print_stdout)] +use std::fmt::{Debug, Display, Formatter, Result}; + +#[allow(dead_code)] +struct Foo; + +impl Display for Foo { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "{:?}", 43.1415) + //~^ ERROR use of `Debug`-based formatting + } +} + +impl Debug for Foo { + fn fmt(&self, f: &mut Formatter) -> Result { + // ok, we can use `Debug` formatting in `Debug` implementations + write!(f, "{:?}", 42.718) + } +} fn main() { println!("Hello"); //~ERROR use of `println!` print!("Hello"); //~ERROR use of `print!` + print!("Hello {}", "World"); //~ERROR use of `print!` + + print!("Hello {:?}", "World"); + //~^ ERROR use of `print!` + //~| ERROR use of `Debug`-based formatting + + print!("Hello {:#?}", "#orld"); + //~^ ERROR use of `print!` + //~| ERROR use of `Debug`-based formatting + + assert_eq!(42, 1337); + vec![1, 2]; } -- cgit 1.4.1-3-g733a5 From 7e06737d6f54ed6ecae339c625a5a2e2d679ad7e Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Tue, 9 Feb 2016 15:44:07 -0500 Subject: Improve testing and suggestion messages on bool_comparison --- src/needless_bool.rs | 28 ++++++++++++---------------- tests/compile-fail/bool_comparison.rs | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/needless_bool.rs b/src/needless_bool.rs index a40b4b3a252..5382b8f0f04 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -107,47 +107,43 @@ impl LateLintPass for BoolComparison { 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)) { (Some(true), None) => { - let side_snip = snippet(cx, right_side.span, ".."); - let hint = format!("`{}`", side_snip); + let hint = format!("{}", snippet(cx, right_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against booleans are unnecesary", + "equality checks against true are unnecesary", |db| { - db.span_suggestion(e.span, "try simplifying it:", hint); + db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } (None, Some(true)) => { - let side_snip = snippet(cx, left_side.span, ".."); - let hint = format!("`{}`", side_snip); + let hint = format!("{}", snippet(cx, left_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against booleans are unnecesary", + "equality checks against true are unnecesary", |db| { - db.span_suggestion(e.span, "try simplifying it:", hint); + db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } (Some(false), None) => { - let side_snip = snippet(cx, right_side.span, ".."); - let hint = format!("`!{}`", side_snip); + let hint = format!("!{}", snippet(cx, right_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against booleans are unnecesary", + "equality checks against false can be replaced by a negation", |db| { - db.span_suggestion(e.span, "try simplifying it:", hint); + db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } (None, Some(false)) => { - let side_snip = snippet(cx, left_side.span, ".."); - let hint = format!("`!{}`", side_snip); + let hint = format!("!{}", snippet(cx, left_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against booleans are unnecesary", + "equality checks against false can be replaced by a negation", |db| { - db.span_suggestion(e.span, "try simplifying it:", hint); + db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } _ => (), diff --git a/tests/compile-fail/bool_comparison.rs b/tests/compile-fail/bool_comparison.rs index 468b8382e94..8a792931d02 100644 --- a/tests/compile-fail/bool_comparison.rs +++ b/tests/compile-fail/bool_comparison.rs @@ -5,19 +5,19 @@ fn main() { let x = true; if x == true { "yes" } else { "no" }; - //~^ ERROR equality checks against booleans are unnecesary - //~| HELP try simplifying it: - //~| SUGGESTION x + //~^ ERROR equality checks against true are unnecesary + //~| HELP try simplifying it as shown: + //~| SUGGESTION if x { "yes" } else { "no" }; if x == false { "yes" } else { "no" }; - //~^ ERROR equality checks against booleans are unnecesary - //~| HELP try simplifying it: - //~| SUGGESTION !x + //~^ ERROR equality checks against false can be replaced by a negation + //~| HELP try simplifying it as shown: + //~| SUGGESTION if !x { "yes" } else { "no" }; if true == x { "yes" } else { "no" }; - //~^ ERROR equality checks against booleans are unnecesary - //~| HELP try simplifying it: - //~| SUGGESTION x + //~^ ERROR equality checks against true are unnecesary + //~| HELP try simplifying it as shown: + //~| SUGGESTION if x { "yes" } else { "no" }; if false == x { "yes" } else { "no" }; - //~^ ERROR equality checks against booleans are unnecesary - //~| HELP try simplifying it: - //~| SUGGESTION !x + //~^ ERROR equality checks against false can be replaced by a negation + //~| HELP try simplifying it as shown: + //~| SUGGESTION if !x { "yes" } else { "no" }; } -- cgit 1.4.1-3-g733a5 From eed9ec15fb2f38f4ea315f0a112f726d5623264f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 11 Feb 2016 13:50:41 +0100 Subject: improve the `no_effect` lint --- src/no_effect.rs | 27 +++++++++++++++---- tests/compile-fail/absurd-extreme-comparisons.rs | 2 +- tests/compile-fail/array_indexing.rs | 1 + tests/compile-fail/bit_masks.rs | 4 +-- tests/compile-fail/cast.rs | 1 + tests/compile-fail/cmp_nan.rs | 2 +- tests/compile-fail/copies.rs | 2 +- tests/compile-fail/eq_op.rs | 1 + tests/compile-fail/eta.rs | 2 +- tests/compile-fail/float_cmp.rs | 2 +- tests/compile-fail/identity_op.rs | 2 +- tests/compile-fail/modulo_one.rs | 1 + tests/compile-fail/mut_mut.rs | 2 +- tests/compile-fail/no_effect.rs | 33 +++++++++++++++++++++++- 14 files changed, 67 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/no_effect.rs b/src/no_effect.rs index e1067f27ab9..0df5ede82da 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::middle::def::Def; -use rustc_front::hir::{Expr, ExprCall, ExprLit, ExprPath, ExprStruct}; +use rustc_front::hir::{Expr, Expr_}; use rustc_front::hir::{Stmt, StmtSemi}; use utils::in_macro; @@ -24,16 +24,33 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { return false; } match expr.node { - ExprLit(..) | - ExprPath(..) => true, - ExprStruct(_, ref fields, ref base) => { + Expr_::ExprLit(..) | + Expr_::ExprClosure(..) | + Expr_::ExprRange(None, None) | + Expr_::ExprPath(..) => true, + Expr_::ExprIndex(ref a, ref b) | + Expr_::ExprRange(Some(ref a), Some(ref b)) | + Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b), + Expr_::ExprVec(ref v) | + Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), + Expr_::ExprRange(Some(ref inner), None) | + Expr_::ExprRange(None, Some(ref inner)) | + Expr_::ExprRepeat(ref inner, _) | + Expr_::ExprCast(ref inner, _) | + Expr_::ExprType(ref inner, _) | + Expr_::ExprUnary(_, ref inner) | + Expr_::ExprField(ref inner, _) | + Expr_::ExprTupField(ref inner, _) | + Expr_::ExprAddrOf(_, ref inner) | + Expr_::ExprBox(ref inner) => has_no_effect(cx, inner), + Expr_::ExprStruct(_, ref fields, ref base) => { fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base { Some(ref base) => has_no_effect(cx, base), None => true, } } - ExprCall(ref callee, ref args) => { + 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(..)) | diff --git a/tests/compile-fail/absurd-extreme-comparisons.rs b/tests/compile-fail/absurd-extreme-comparisons.rs index 9718225d203..7e2ad1fede5 100644 --- a/tests/compile-fail/absurd-extreme-comparisons.rs +++ b/tests/compile-fail/absurd-extreme-comparisons.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(absurd_extreme_comparisons)] -#![allow(unused, eq_op)] +#![allow(unused, eq_op, no_effect)] fn main() { const Z: u32 = 0; diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs index 68ab71da586..1d9492bc0ab 100644 --- a/tests/compile-fail/array_indexing.rs +++ b/tests/compile-fail/array_indexing.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(out_of_bounds_indexing)] +#![allow(no_effect)] fn main() { let x = [1,2,3,4]; diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index f78012864a0..98135295862 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -5,7 +5,7 @@ const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] -#[allow(ineffective_bit_mask, identity_op)] +#[allow(ineffective_bit_mask, identity_op, no_effect)] fn main() { let x = 5; @@ -45,7 +45,7 @@ fn main() { } #[deny(ineffective_bit_mask)] -#[allow(bad_bit_mask)] +#[allow(bad_bit_mask, no_effect)] fn ineffective() { let x = 5; diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index 70cc1919be4..0f44fa2c1fd 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap)] +#[allow(no_effect)] fn main() { // Test cast_precision_loss 1i32 as f32; //~ERROR casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide) diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs index b2369e164ff..d2188130a61 100644 --- a/tests/compile-fail/cmp_nan.rs +++ b/tests/compile-fail/cmp_nan.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(cmp_nan)] -#[allow(float_cmp)] +#[allow(float_cmp, no_effect)] fn main() { let x = 5f32; x == std::f32::NAN; //~ERROR doomed comparison with NAN diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 0f57b619ccc..d6e666f299b 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(dead_code)] +#![allow(dead_code, no_effect)] #![allow(let_and_return)] #![allow(needless_return)] #![allow(unused_variables)] diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 7be5ef11ce6..487185516bf 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -3,6 +3,7 @@ #[deny(eq_op)] #[allow(identity_op)] +#[allow(no_effect)] fn main() { // simple values and comparisons 1 == 1; //~ERROR equal expressions diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index 1ffca9ac5ce..46680f2b8d8 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -1,6 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unknown_lints, unused)] +#![allow(unknown_lints, unused, no_effect)] #![deny(redundant_closure)] fn main() { diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index 27cde245f68..d1ecb37cdd5 100644 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(float_cmp)] -#![allow(unused)] +#![allow(unused, no_effect)] use std::ops::Add; diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs index c1141e0b460..28873ee6b73 100644 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -5,7 +5,7 @@ const ONE : i64 = 1; const NEG_ONE : i64 = -1; const ZERO : i64 = 0; -#[allow(eq_op)] +#[allow(eq_op, no_effect)] #[deny(identity_op)] fn main() { let x = 0; diff --git a/tests/compile-fail/modulo_one.rs b/tests/compile-fail/modulo_one.rs index 1301b4e499c..e84209a6d1e 100644 --- a/tests/compile-fail/modulo_one.rs +++ b/tests/compile-fail/modulo_one.rs @@ -1,6 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] #![deny(modulo_one)] +#![allow(no_effect)] fn main() { 10 % 1; //~ERROR any number modulo 1 will be 0 diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 2560a54c0ef..0db9cb3bdef 100644 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused)] +#![allow(unused, no_effect)] //#![plugin(regex_macros)] //extern crate regex; diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index 21118b82718..52ea423a57d 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -1,4 +1,4 @@ -#![feature(plugin)] +#![feature(plugin, box_syntax)] #![plugin(clippy)] #![deny(no_effect)] @@ -20,14 +20,32 @@ fn get_struct() -> Struct { Struct { field: 0 } } fn main() { let s = get_struct(); + let s2 = get_struct(); 0; //~ERROR statement with no effect + s2; //~ERROR statement with no effect Unit; //~ERROR statement with no effect Tuple(0); //~ERROR statement with no effect Struct { field: 0 }; //~ERROR statement with no effect Struct { ..s }; //~ERROR statement with no effect Enum::Tuple(0); //~ERROR statement with no effect Enum::Struct { field: 0 }; //~ERROR statement with no effect + 5 + 6; //~ERROR statement with no effect + *&42; //~ERROR statement with no effect + &6; //~ERROR statement with no effect + (5, 6, 7); //~ERROR statement with no effect + box 42; //~ERROR statement with no effect + ..; //~ERROR statement with no effect + 5..; //~ERROR statement with no effect + ..5; //~ERROR statement with no effect + 5..6; //~ERROR statement with no effect + [42, 55]; //~ERROR statement with no effect + [42, 55][1]; //~ERROR statement with no effect + (42, 55).1; //~ERROR statement with no effect + [42; 55]; //~ERROR statement with no effect + [42; 55][13]; //~ERROR statement with no effect + let mut x = 0; + || x += 5; //~ERROR statement with no effect // Do not warn get_number(); @@ -36,4 +54,17 @@ fn main() { Struct { ..get_struct() }; Enum::Tuple(get_number()); Enum::Struct { field: get_number() }; + 5 + get_number(); + *&get_number(); + &get_number(); + (5, 6, get_number()); + box get_number(); + get_number()..; + ..get_number(); + 5..get_number(); + [42, get_number()]; + [42, 55][get_number() as usize]; + (42, get_number()).1; + [get_number(); 55]; + [42; 55][get_number() as usize]; } -- cgit 1.4.1-3-g733a5 From e1c7914c2e1afe34073f01acb5638963029cb961 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 30 Jan 2016 18:03:53 +0100 Subject: Add missing ExprIndex to is_exp_equal --- src/utils.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/utils.rs b/src/utils.rs index 4c89b7f113d..9adbff90e66 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -718,6 +718,9 @@ pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr, ignore_fn: bool is_block_equal(cx, lt, rt, ignore_fn) && both(le, re, |l, r| is_exp_equal(cx, l, r, ignore_fn)) } + (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { + is_exp_equal(cx, la, ra) && is_exp_equal(cx, li, ri) + } (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { ls == rs && -- cgit 1.4.1-3-g733a5 From 91c16fc8e605ddb7f0b4f967bd7fbf62ccd6a292 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 6 Feb 2016 20:13:25 +0100 Subject: Refactor Expr comparisons --- src/copies.rs | 7 +- src/entry.rs | 5 +- src/eq_op.rs | 4 +- src/strings.rs | 7 +- src/utils.rs | 833 ------------------------------------------------------- src/utils/hir.rs | 239 ++++++++++++++++ src/utils/mod.rs | 610 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 862 insertions(+), 843 deletions(-) delete mode 100644 src/utils.rs create mode 100644 src/utils/hir.rs create mode 100644 src/utils/mod.rs (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 525c7b7a6fd..b1ea8f0c347 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,6 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{get_parent_expr, in_macro, is_block_equal, is_exp_equal, span_lint, span_note_and_lint}; +use utils::SpanlessEq; +use utils::{get_parent_expr, in_macro, span_lint, span_note_and_lint}; /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is /// `Warn` by default. @@ -55,7 +56,7 @@ impl LateLintPass for CopyAndPaste { fn lint_same_then_else(cx: &LateContext, expr: &Expr) { if let ExprIf(_, ref then_block, Some(ref else_expr)) = expr.node { if let ExprBlock(ref else_block) = else_expr.node { - if is_block_equal(cx, &then_block, &else_block, false) { + if SpanlessEq::new(cx).eq_block(&then_block, &else_block) { span_lint(cx, IF_SAME_THEN_ELSE, expr.span, "this if has the same then and else blocks"); } } @@ -75,7 +76,7 @@ fn lint_same_cond(cx: &LateContext, expr: &Expr) { for (n, i) in conds.iter().enumerate() { for j in conds.iter().skip(n+1) { - if is_exp_equal(cx, i, j, true) { + if SpanlessEq::new(cx).ignore_fn().eq_expr(i, j) { span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); } } diff --git a/src/entry.rs b/src/entry.rs index d5bb086fc21..c2f2e956e5e 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,8 +1,9 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use utils::{get_item_name, is_exp_equal, match_type, snippet, span_lint_and_then, walk_ptrs_ty}; +use utils::SpanlessEq; use utils::{BTREEMAP_PATH, HASHMAP_PATH}; +use utils::{get_item_name, match_type, snippet, span_lint_and_then, walk_ptrs_ty}; /// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or /// `BTreeMap`. @@ -89,7 +90,7 @@ fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: params.len() == 3, name.node.as_str() == "insert", get_item_name(cx, map) == get_item_name(cx, &*params[0]), - is_exp_equal(cx, key, ¶ms[1], false) + SpanlessEq::new(cx).eq_expr(key, ¶ms[1]) ], { let help = if sole_expr { format!("{}.entry({}).or_insert({})", diff --git a/src/eq_op.rs b/src/eq_op.rs index aecd0693ff1..fc1cab2cd71 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc_front::util as ast_util; -use utils::{is_exp_equal, span_lint}; +use utils::{SpanlessEq, span_lint}; /// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, /// difference and division binary operators (`==`, `>`, etc., `&&`, `||`, `&`, `|`, `^`, `-` and @@ -31,7 +31,7 @@ impl LintPass for EqOp { impl LateLintPass for EqOp { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref op, ref left, ref right) = e.node { - if is_valid_operator(op) && is_exp_equal(cx, left, right, true) { + if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) { span_lint(cx, EQ_OP, e.span, diff --git a/src/strings.rs b/src/strings.rs index b78db7f4b77..40d137101a6 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -7,7 +7,8 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::{is_exp_equal, match_type, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::SpanlessEq; use utils::STRING_PATH; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). @@ -84,7 +85,7 @@ impl LateLintPass for StringAdd { if let Some(ref p) = parent { if let ExprAssign(ref target, _) = p.node { // avoid duplicate matches - if is_exp_equal(cx, target, left, false) { + if SpanlessEq::new(cx).eq_expr(target, left) { return; } } @@ -113,7 +114,7 @@ fn is_string(cx: &LateContext, e: &Expr) -> bool { fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { - ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => is_exp_equal(cx, target, left, false), + 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)) } diff --git a/src/utils.rs b/src/utils.rs deleted file mode 100644 index 9adbff90e66..00000000000 --- a/src/utils.rs +++ /dev/null @@ -1,833 +0,0 @@ -use consts::constant; -use reexport::*; -use rustc::front::map::Node; -use rustc::lint::{LintContext, LateContext, Level, Lint}; -use rustc::middle::def_id::DefId; -use rustc::middle::{cstore, def, infer, ty, traits}; -use rustc::session::Session; -use rustc_front::hir::*; -use std::borrow::Cow; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::str::FromStr; -use syntax::ast::Lit_; -use syntax::ast; -use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; -use syntax::errors::DiagnosticBuilder; -use syntax::ptr::P; - -pub type MethodArgs = HirVec<P<Expr>>; - -// module DefPaths for certain structs/enums we check for -pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; -pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"]; -pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; -pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; -pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; -pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; -pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; -pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; -pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; -pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; -pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; -pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; -pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; -pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; -pub const IO_PRINT_PATH: [&'static str; 3] = ["std", "io", "_print"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; -pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; -pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; -pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; -pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; -pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; - -/// 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 -/// } -/// } -/// -/// becomes -/// -/// 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) => { - if let $pat = $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([let $pat:pat = $expr:expr], $block:block) => { - if let $pat = $expr { - $block - } - }; - ([$expr:expr, $($tt:tt)+], $block:block) => { - if $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([$expr:expr], $block:block) => { - if $expr { - $block - } - }; -} - -/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one -/// isn't). -pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { - sp1.expn_id != sp2.expn_id -} -/// Returns true if this `expn_info` was expanded by any macro. -pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) -} - -/// Returns true if the macro that expanded the crate was outside of the current crate or was a -/// compiler plugin. -pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { - /// Invokes in_macro with the expansion info of the given span slightly heavy, try to use this - /// after other checks have already happened. - fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { - // no ExpnInfo = no macro - opt_info.map_or(false, |info| { - if let ExpnFormat::MacroAttribute(..) = info.callee.format { - // these are all plugins - return true; - } - // no span for the callee = external macro - info.callee.span.map_or(true, |span| { - // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) - }) - }) - } - - cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) -} - -/// Check if a `DefId`'s path matches the given absolute type path usage. -/// -/// # Examples -/// ``` -/// match_def_path(cx, id, &["core", "option", "Option"]) -/// ``` -pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| { - iter.zip(path) - .all(|(nm, p)| nm.name().as_str() == *p) - }) -} - -/// Check if type is struct or enum type with given def path. -pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { - match ty.sty { - ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), - _ => false, - } -} - -/// Check if the method call given in `expr` belongs to given type. -pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { - let method_call = ty::MethodCall::expr(expr.id); - - let trt_id = cx.tcx - .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 { - false - } -} - -/// Check if the method call given in `expr` belongs to given trait. -pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { - let method_call = ty::MethodCall::expr(expr.id); - - let trt_id = cx.tcx - .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 { - false - } -} - -/// Match a `Path` against a slice of segment string literals. -/// -/// # Examples -/// ``` -/// match_path(path, &["std", "rt", "begin_unwind"]) -/// ``` -pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) -} - -/// Match a `Path` against a slice of segment string literals, e.g. -/// -/// # Examples -/// ``` -/// match_path(path, &["std", "rt", "begin_unwind"]) -/// ``` -pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) -} - -/// Get the definition associated to a path. -/// TODO: investigate if there is something more efficient for that. -pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { - let cstore = &cx.tcx.sess.cstore; - - let crates = cstore.crates(); - let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); - if let Some(krate) = krate { - let mut items = cstore.crate_top_level_items(*krate); - let mut path_it = path.iter().skip(1).peekable(); - - loop { - let segment = match path_it.next() { - Some(segment) => segment, - None => return None, - }; - - for item in &mem::replace(&mut items, vec![]) { - if item.name.as_str() == *segment { - if path_it.peek().is_none() { - return Some(item.def); - } - - let def_id = match item.def { - cstore::DefLike::DlDef(def) => def.def_id(), - cstore::DefLike::DlImpl(def_id) => def_id, - _ => panic!("Unexpected {:?}", item.def), - }; - - items = cstore.item_children(def_id); - break; - } - } - } - } else { - None - } -} - -/// Convenience function to get the `DefId` of a trait by path. -pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { - let def = match path_to_def(cx, path) { - Some(def) => def, - None => return None, - }; - - match def { - cstore::DlDef(def::Def::Trait(trait_id)) => Some(trait_id), - _ => None, - } -} - -/// 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: Option<Vec<ty::Ty<'tcx>>>) - -> bool { - cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); - - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); - let obligation = traits::predicate_for_trait_def(cx.tcx, - traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params.unwrap_or_default()); - - traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) -} - -/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. -/// -/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, -/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for -/// `.bar()` and `.baz()` -pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { - let mut current = expr; - let mut matched = Vec::with_capacity(methods.len()); - for method_name in methods.iter().rev() { - // method chains are stored last -> first - if let ExprMethodCall(ref name, _, ref args) = current.node { - if name.node.as_str() == *method_name { - matched.push(args); // build up `matched` backwards - current = &args[0] // go to parent expression - } else { - return None; - } - } else { - return None; - } - } - matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` - Some(matched) -} - - -/// Get the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { - let parent_id = cx.tcx.map.get_parent(expr.id); - match cx.tcx.map.find(parent_id) { - Some(Node::NodeItem(&Item{ ref name, .. })) | - Some(Node::NodeTraitItem(&TraitItem{ ref name, .. })) | - Some(Node::NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), - _ => None, - } -} - -/// Checks if a `let` decl is from a `for` loop desugaring. -pub fn is_from_for_desugar(decl: &Decl) -> bool { - if_let_chain! { - [ - let DeclLocal(ref loc) = decl.node, - let Some(ref expr) = loc.init, - let ExprMatch(_, _, MatchSource::ForLoopDesugar) = expr.node - ], - { return true; } - }; - false -} - - -/// Convert a span to a code snippet if available, otherwise use default. -/// -/// # Example -/// ``` -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) -} - -/// Convert a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { - cx.sess().codemap().span_to_snippet(span).ok() -} - -/// Convert a span (from a block) to a code snippet if available, otherwise use default. -/// This trims the code of indentation, except for the first line. Use it for blocks or block-like -/// things which need to be printed as such. -/// -/// # Example -/// ``` -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - let snip = snippet(cx, span, default); - trim_multiline(snip, true) -} - -/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. -/// Also takes an `Option<String>` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default); - let string = option.unwrap_or_default(); - if let ExprBlock(_) = expr.node { - Cow::Owned(format!("{}{}", code, string)) - } else if string.is_empty() { - Cow::Owned(format!("{{ {} }}", code)) - } else { - Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) - } -} - -/// Trim indentation from a multiline string with possibility of ignoring the first line. -pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { - let s_space = trim_multiline_inner(s, ignore_first, ' '); - let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); - trim_multiline_inner(s_tab, ignore_first, ' ') -} - -fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { - let x = s.lines() - .skip(ignore_first as usize) - .filter_map(|l| { - if l.len() > 0 { - // ignore empty lines - Some(l.char_indices() - .find(|&(_, x)| x != ch) - .unwrap_or((l.len(), ch)) - .0) - } else { - None - } - }) - .min() - .unwrap_or(0); - if x > 0 { - Cow::Owned(s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.len() == 0 { - l - } else { - l.split_at(x).1 - } - }) - .collect::<Vec<_>>() - .join("\n")) - } else { - s - } -} - -/// Get a parent expressions if any – this is useful to constrain a lint. -pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { - let map = &cx.tcx.map; - let node_id: NodeId = e.id; - let parent_id: NodeId = map.get_parent_node(node_id); - if node_id == parent_id { - return None; - } - map.find(parent_id).and_then(|node| { - if let Node::NodeExpr(parent) = node { - Some(parent) - } else { - None - } - }) -} - -pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { - let map = &cx.tcx.map; - let enclosing_node = map.get_enclosing_scope(node) - .and_then(|enclosing_id| map.find(enclosing_id)); - if let Some(node) = enclosing_node { - match node { - Node::NodeBlock(ref block) => Some(block), - Node::NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), - _ => None, - } - } else { - None - } -} - -pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); - -impl<'a> Drop for DiagnosticWrapper<'a> { - fn drop(&mut self) { - self.0.emit(); - } -} - -impl<'a> DerefMut for DiagnosticWrapper<'a> { - fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { - &mut self.0 - } -} - -impl<'a> Deref for DiagnosticWrapper<'a> { - type Target = DiagnosticBuilder<'a>; - fn deref(&self) -> &DiagnosticBuilder<'a> { - &self.0 - } -} - -pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, sp, msg); - if cx.current_level(lint) != Level::Allow { - db.fileline_help(sp, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); - } - DiagnosticWrapper(db) -} - -pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) - -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, span, msg); - if cx.current_level(lint) != Level::Allow { - db.fileline_help(span, - &format!("{}\nfor further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - help, - lint.name_lower())); - } - DiagnosticWrapper(db) -} - -pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, - note: &str) - -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, span, msg); - if cx.current_level(lint) != Level::Allow { - if note_span == span { - db.fileline_note(note_span, note); - } else { - db.span_note(note_span, note); - } - db.fileline_help(span, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); - } - DiagnosticWrapper(db) -} - -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) - -> DiagnosticWrapper<'a> - where F: FnOnce(&mut DiagnosticWrapper) -{ - let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); - if cx.current_level(lint) != Level::Allow { - f(&mut db); - db.fileline_help(sp, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); - } - db -} - -/// Return the base type for references and raw pointers. -pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { - match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), - _ => ty, - } -} - -/// Return the base type for references and raw pointers, and count reference depth. -pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { - fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { - match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), - _ => (ty, depth), - } - } - inner(ty, 0) -} - -/// Check whether the given expression is a constant literal of the given value. -pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { - // FIXME: use constant folding - if let ExprLit(ref spanned) = expr.node { - if let Lit_::LitInt(v, _) = spanned.node { - return v == value; - } - } - false -} - -pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { - cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() -} - -pub struct LimitStack { - stack: Vec<u64>, -} - -impl Drop for LimitStack { - fn drop(&mut self) { - assert_eq!(self.stack.len(), 1); - } -} - -impl LimitStack { - pub fn new(limit: u64) -> LimitStack { - LimitStack { stack: vec![limit] } - } - pub fn limit(&self) -> u64 { - *self.stack.last().expect("there should always be a value in the stack") - } - pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { - let stack = &mut self.stack; - parse_attrs(sess, attrs, name, |val| stack.push(val)); - } - pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { - let stack = &mut self.stack; - parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); - } -} - -fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { - for attr in attrs { - let attr = &attr.node; - if attr.is_sugared_doc { - continue; - } - if let ast::MetaNameValue(ref key, ref value) = attr.value.node { - if *key == name { - if let Lit_::LitStr(ref s, _) = value.node { - if let Ok(value) = FromStr::from_str(s) { - f(value) - } else { - sess.span_err(value.span, "not a number"); - } - } else { - unreachable!() - } - } - } - } -} - -/// Check whether two statements are the same. -/// See also `is_exp_equal`. -pub fn is_stmt_equal(cx: &LateContext, left: &Stmt, right: &Stmt, ignore_fn: bool) -> bool { - match (&left.node, &right.node) { - (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { - if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { - // TODO: tys - l.ty.is_none() && r.ty.is_none() && - both(&l.init, &r.init, |l, r| is_exp_equal(cx, l, r, ignore_fn)) - } - else { - false - } - } - (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => is_exp_equal(cx, l, r, ignore_fn), - (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => is_exp_equal(cx, l, r, ignore_fn), - _ => false, - } -} - -/// Check whether two blocks are the same. -/// See also `is_exp_equal`. -pub fn is_block_equal(cx: &LateContext, left: &Block, right: &Block, ignore_fn: bool) -> bool { - over(&left.stmts, &right.stmts, |l, r| is_stmt_equal(cx, l, r, ignore_fn)) && - both(&left.expr, &right.expr, |l, r| is_exp_equal(cx, l, r, ignore_fn)) -} - -/// Check whether two pattern are the same. -/// See also `is_exp_equal`. -pub fn is_pat_equal(cx: &LateContext, left: &Pat, right: &Pat, ignore_fn: bool) -> bool { - match (&left.node, &right.node) { - (&PatBox(ref l), &PatBox(ref r)) => { - is_pat_equal(cx, l, r, ignore_fn) - } - (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => { - is_path_equal(lp, rp) && - both(la, ra, |l, r| { - over(l, r, |l, r| is_pat_equal(cx, l, r, ignore_fn)) - }) - } - (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => { - lb == rb && li.node.name.as_str() == ri.node.name.as_str() && - both(lp, rp, |l, r| is_pat_equal(cx, l, r, ignore_fn)) - } - (&PatLit(ref l), &PatLit(ref r)) => { - is_exp_equal(cx, l, r, ignore_fn) - } - (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => { - is_qself_equal(ls, rs) && is_path_equal(lp, rp) - } - (&PatTup(ref l), &PatTup(ref r)) => { - over(l, r, |l, r| is_pat_equal(cx, l, r, ignore_fn)) - } - (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => { - is_exp_equal(cx, ls, rs, ignore_fn) && - is_exp_equal(cx, le, re, ignore_fn) - } - (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => { - lm == rm && is_pat_equal(cx, le, re, ignore_fn) - } - (&PatVec(ref ls, ref li, ref le), &PatVec(ref rs, ref ri, ref re)) => { - over(ls, rs, |l, r| is_pat_equal(cx, l, r, ignore_fn)) && - over(le, re, |l, r| is_pat_equal(cx, l, r, ignore_fn)) && - both(li, ri, |l, r| is_pat_equal(cx, l, r, ignore_fn)) - } - (&PatWild, &PatWild) => true, - _ => false, - } -} - -/// Check whether two expressions are the same. This is different from the operator `==` on -/// expression as this operator would compare true equality with ID and span. -/// If `ignore_fn` is true, never consider as equal fonction calls. -/// -/// Note that some expression kinds are not considered but could be added. -#[allow(cyclomatic_complexity)] // ok, it’s a big function, but mostly one big match with simples cases -pub fn is_exp_equal(cx: &LateContext, left: &Expr, right: &Expr, ignore_fn: bool) -> bool { - if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) { - if l == r { - return true; - } - } - - match (&left.node, &right.node) { - (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => { - lmut == rmut && is_exp_equal(cx, le, re, ignore_fn) - } - (&ExprAgain(li), &ExprAgain(ri)) => { - both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) - } - (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => { - is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) - } - (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => { - lo.node == ro.node && is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) - } - (&ExprBlock(ref l), &ExprBlock(ref r)) => { - is_block_equal(cx, l, r, ignore_fn) - } - (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { - lop.node == rop.node && is_exp_equal(cx, ll, rl, ignore_fn) && is_exp_equal(cx, lr, rr, ignore_fn) - } - (&ExprBreak(li), &ExprBreak(ri)) => { - both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) - } - (&ExprBox(ref l), &ExprBox(ref r)) => { - is_exp_equal(cx, l, r, ignore_fn) - } - (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { - !ignore_fn && - is_exp_equal(cx, lfun, rfun, ignore_fn) && - is_exps_equal(cx, largs, rargs, ignore_fn) - } - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => { - is_exp_equal(cx, lx, rx, ignore_fn) && is_cast_ty_equal(lt, rt) - } - (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { - lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp, ignore_fn) - } - (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { - is_exp_equal(cx, la, ra, ignore_fn) && is_exp_equal(cx, li, ri, ignore_fn) - } - (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => { - is_exp_equal(cx, lc, rc, ignore_fn) && - is_block_equal(cx, lt, rt, ignore_fn) && - both(le, re, |l, r| is_exp_equal(cx, l, r, ignore_fn)) - } - (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { - is_exp_equal(cx, la, ra) && is_exp_equal(cx, li, ri) - } - (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, - (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { - ls == rs && - is_exp_equal(cx, le, re, ignore_fn) && - over(la, ra, |l, r| { - is_exp_equal(cx, &l.body, &r.body, ignore_fn) && - both(&l.guard, &r.guard, |l, r| is_exp_equal(cx, l, r, ignore_fn)) && - over(&l.pats, &r.pats, |l, r| is_pat_equal(cx, l, r, ignore_fn)) - }) - } - (&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { - // TODO: tys - !ignore_fn && - lname.node == rname.node && - ltys.is_empty() && - rtys.is_empty() && - is_exps_equal(cx, largs, rargs, ignore_fn) - } - (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { - both(lb, rb, |l, r| is_exp_equal(cx, l, r, ignore_fn)) && - both(le, re, |l, r| is_exp_equal(cx, l, r, ignore_fn)) - } - (&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => { - is_exp_equal(cx, le, re, ignore_fn) && is_exp_equal(cx, ll, rl, ignore_fn) - } - (&ExprRet(ref l), &ExprRet(ref r)) => { - both(l, r, |l, r| is_exp_equal(cx, l, r, ignore_fn)) - } - (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { - both(lqself, rqself, is_qself_equal) && is_path_equal(lsubpath, rsubpath) - } - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => is_exps_equal(cx, ltup, rtup, ignore_fn), - (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { - li.node == ri.node && is_exp_equal(cx, le, re, ignore_fn) - } - (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => { - lop == rop && is_exp_equal(cx, le, re, ignore_fn) - } - (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r, ignore_fn), - (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => { - is_exp_equal(cx, lc, rc, ignore_fn) && - is_block_equal(cx, lb, rb, ignore_fn) && - both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) - } - _ => false, - } -} - -fn is_exps_equal(cx: &LateContext, left: &[P<Expr>], right: &[P<Expr>], ignore_fn: bool) -> bool { - over(left, right, |l, r| is_exp_equal(cx, l, r, ignore_fn)) -} - -fn is_path_equal(left: &Path, right: &Path) -> bool { - // The == of idents doesn't work with different contexts, - // we have to be explicit about hygiene - left.global == right.global && - over(&left.segments, - &right.segments, - |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters) -} - -fn is_qself_equal(left: &QSelf, right: &QSelf) -> bool { - left.ty.node == right.ty.node && left.position == right.position -} - -/// Check if two slices are equal as per `eq_fn`. -pub fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool -{ - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) -} - -/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. -pub fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool -{ - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) -} - -fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool { - match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec), - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && is_cast_ty_equal(&*lmut.ty, &*rmut.ty), - (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => { - lrmut.mutbl == rrmut.mutbl && is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty) - } - (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => { - both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath) - } - (&TyInfer, &TyInfer) => true, - _ => false, - } -} - -/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. -pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { - 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) - }) - }); - - match span_name_span { - Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), - None => return None, - Some((_, new_span)) => span = new_span, - } - } -} diff --git a/src/utils/hir.rs b/src/utils/hir.rs new file mode 100644 index 00000000000..95356772e60 --- /dev/null +++ b/src/utils/hir.rs @@ -0,0 +1,239 @@ +use consts::constant; +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::ptr::P; + +/// Type used to check whether two ast are the same. This is different from the operator +/// `==` on ast types as this operator would compare true equality with ID and span. +/// +/// Note that some expressions kinds are not considered but could be added. +pub struct SpanlessEq<'a, 'tcx: 'a> { + /// Context used to evaluate constant expressions. + cx: &'a LateContext<'a, 'tcx>, + /// If is true, never consider as equal expressions containing fonction calls. + ignore_fn: bool, +} + +impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { + pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + SpanlessEq { cx: cx, ignore_fn: false } + } + + pub fn ignore_fn(self) -> Self { + SpanlessEq { cx: self.cx, ignore_fn: true } + } + + /// Check whether two statements are the same. + pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool { + match (&left.node, &right.node) { + (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { + if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { + // TODO: tys + l.ty.is_none() && r.ty.is_none() && + both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) + } + else { + false + } + } + (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => self.eq_expr(l, r), + (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), + _ => false, + } + } + + /// Check whether two blocks are the same. + pub fn eq_block(&self, left: &Block, right: &Block) -> bool { + over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && + both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) + } + + // ok, it’s a big function, but mostly one big match with simples cases + #[allow(cyclomatic_complexity)] + pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { + if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) { + if l == r { + return true; + } + } + + match (&left.node, &right.node) { + (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => { + lmut == rmut && self.eq_expr(le, re) + } + (&ExprAgain(li), &ExprAgain(ri)) => { + both(&li, &ri, |l, r| l.node.name.as_str() == r.node.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(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { + lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) + } + (&ExprBreak(li), &ExprBreak(ri)) => { + both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) + } + (&ExprBox(ref l), &ExprBox(ref r)) => { + self.eq_expr(l, r) + } + (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { + !self.ignore_fn && + self.eq_expr(lfun, rfun) && + self.eq_exprs(largs, rargs) + } + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => { + self.eq_expr(lx, rx) && self.eq_ty(lt, rt) + } + (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { + lfident.node == rfident.node && self.eq_expr(lfexp, rfexp) + } + (&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, + (&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 lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { + // TODO: tys + !self.ignore_fn && + lname.node == rname.node && + ltys.is_empty() && + rtys.is_empty() && + self.eq_exprs(largs, rargs) + } + (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { + both(lb, rb, |l, r| self.eq_expr(l, r)) && + both(le, re, |l, r| self.eq_expr(l, r)) + } + (&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 lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { + both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath) + } + (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup), + (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { + li.node == ri.node && self.eq_expr(le, re) + } + (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => { + lop == rop && self.eq_expr(le, re) + } + (&ExprVec(ref l), &ExprVec(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.name.as_str() == r.name.as_str()) + } + _ => false, + } + } + + fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool { + over(left, right, |l, r| self.eq_expr(l, r)) + } + + /// Check whether two patterns are the same. + pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { + match (&left.node, &right.node) { + (&PatBox(ref l), &PatBox(ref r)) => { + self.eq_pat(l, r) + } + (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => { + self.eq_path(lp, rp) && + both(la, ra, |l, r| { + over(l, r, |l, r| self.eq_pat(l, r)) + }) + } + (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => { + lb == rb && li.node.name.as_str() == ri.node.name.as_str() && + both(lp, rp, |l, r| self.eq_pat(l, r)) + } + (&PatLit(ref l), &PatLit(ref r)) => { + self.eq_expr(l, r) + } + (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => { + self.eq_qself(ls, rs) && self.eq_path(lp, rp) + } + (&PatTup(ref l), &PatTup(ref r)) => { + over(l, r, |l, r| self.eq_pat(l, r)) + } + (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => { + self.eq_expr(ls, rs) && + self.eq_expr(le, re) + } + (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => { + lm == rm && self.eq_pat(le, re) + } + (&PatVec(ref ls, ref li, ref le), &PatVec(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)) + } + (&PatWild, &PatWild) => true, + _ => false, + } + } + + fn eq_path(&self, left: &Path, right: &Path) -> bool { + // The == of idents doesn't work with different contexts, + // we have to be explicit about hygiene + left.global == right.global && + over(&left.segments, + &right.segments, + |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters) + } + + fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool { + left.ty.node == right.ty.node && left.position == right.position + } + + fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { + match (&left.node, &right.node) { + (&TyVec(ref lvec), &TyVec(ref rvec)) => self.eq_ty(lvec, rvec), + (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && self.eq_ty(&*lmut.ty, &*rmut.ty), + (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => { + lrmut.mutbl == rrmut.mutbl && self.eq_ty(&*lrmut.ty, &*rrmut.ty) + } + (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => { + both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(lpath, rpath) + } + (&TyInfer, &TyInfer) => true, + _ => false, + } + } +} + +/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. +fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool +{ + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) +} + +/// Check if two slices are equal as per `eq_fn`. +fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool +{ + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 00000000000..d666ee36bce --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,610 @@ +use reexport::*; +use rustc::front::map::Node; +use rustc::lint::{LintContext, LateContext, Level, Lint}; +use rustc::middle::def_id::DefId; +use rustc::middle::{cstore, def, infer, ty, traits}; +use rustc::session::Session; +use rustc_front::hir::*; +use std::borrow::Cow; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::str::FromStr; +use syntax::ast::Lit_; +use syntax::ast; +use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; +use syntax::errors::DiagnosticBuilder; +use syntax::ptr::P; + +mod hir; +pub use self::hir::SpanlessEq; +pub type MethodArgs = HirVec<P<Expr>>; + +// module DefPaths for certain structs/enums we check for +pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"]; +pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; +pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; +pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; +pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; +pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; +pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; +pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; +pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; +pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; +pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; +pub const IO_PRINT_PATH: [&'static str; 3] = ["std", "io", "_print"]; +pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; +pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; +pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; +pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; + +/// 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 +/// } +/// } +/// +/// becomes +/// +/// 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) => { + if let $pat = $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([let $pat:pat = $expr:expr], $block:block) => { + if let $pat = $expr { + $block + } + }; + ([$expr:expr, $($tt:tt)+], $block:block) => { + if $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([$expr:expr], $block:block) => { + if $expr { + $block + } + }; +} + +/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one +/// isn't). +pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { + sp1.expn_id != sp2.expn_id +} +/// Returns true if this `expn_info` was expanded by any macro. +pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { + cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) +} + +/// Returns true if the macro that expanded the crate was outside of the current crate or was a +/// compiler plugin. +pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { + /// Invokes in_macro with the expansion info of the given span slightly heavy, try to use this + /// after other checks have already happened. + fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { + // no ExpnInfo = no macro + opt_info.map_or(false, |info| { + if let ExpnFormat::MacroAttribute(..) = info.callee.format { + // these are all plugins + return true; + } + // no span for the callee = external macro + info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) + }) + }) + } + + cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) +} + +/// Check if a `DefId`'s path matches the given absolute type path usage. +/// +/// # Examples +/// ``` +/// match_def_path(cx, id, &["core", "option", "Option"]) +/// ``` +pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { + cx.tcx.with_path(def_id, |iter| { + iter.zip(path) + .all(|(nm, p)| nm.name().as_str() == *p) + }) +} + +/// Check if type is struct or enum type with given def path. +pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { + match ty.sty { + ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), + _ => false, + } +} + +/// Check if the method call given in `expr` belongs to given type. +pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { + let method_call = ty::MethodCall::expr(expr.id); + + let trt_id = cx.tcx + .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 { + false + } +} + +/// Check if the method call given in `expr` belongs to given trait. +pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { + let method_call = ty::MethodCall::expr(expr.id); + + let trt_id = cx.tcx + .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 { + false + } +} + +/// Match a `Path` against a slice of segment string literals. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` +pub fn match_path(path: &Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) +} + +/// Match a `Path` against a slice of segment string literals, e.g. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` +pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) +} + +/// Get the definition associated to a path. +/// TODO: investigate if there is something more efficient for that. +pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { + let cstore = &cx.tcx.sess.cstore; + + let crates = cstore.crates(); + let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); + if let Some(krate) = krate { + let mut items = cstore.crate_top_level_items(*krate); + let mut path_it = path.iter().skip(1).peekable(); + + loop { + let segment = match path_it.next() { + Some(segment) => segment, + None => return None, + }; + + for item in &mem::replace(&mut items, vec![]) { + if item.name.as_str() == *segment { + if path_it.peek().is_none() { + return Some(item.def); + } + + let def_id = match item.def { + cstore::DefLike::DlDef(def) => def.def_id(), + cstore::DefLike::DlImpl(def_id) => def_id, + _ => panic!("Unexpected {:?}", item.def), + }; + + items = cstore.item_children(def_id); + break; + } + } + } + } else { + None + } +} + +/// Convenience function to get the `DefId` of a trait by path. +pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { + let def = match path_to_def(cx, path) { + Some(def) => def, + None => return None, + }; + + match def { + cstore::DlDef(def::Def::Trait(trait_id)) => Some(trait_id), + _ => None, + } +} + +/// 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: Option<Vec<ty::Ty<'tcx>>>) + -> bool { + cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); + + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); + let obligation = traits::predicate_for_trait_def(cx.tcx, + traits::ObligationCause::dummy(), + trait_id, + 0, + ty, + ty_params.unwrap_or_default()); + + traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) +} + +/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. +/// +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, +/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for +/// `.bar()` and `.baz()` +pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { + let mut current = expr; + let mut matched = Vec::with_capacity(methods.len()); + for method_name in methods.iter().rev() { + // method chains are stored last -> first + if let ExprMethodCall(ref name, _, ref args) = current.node { + if name.node.as_str() == *method_name { + matched.push(args); // build up `matched` backwards + current = &args[0] // go to parent expression + } else { + return None; + } + } else { + return None; + } + } + matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` + Some(matched) +} + + +/// Get the name of the item the expression is in, if available. +pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { + let parent_id = cx.tcx.map.get_parent(expr.id); + match cx.tcx.map.find(parent_id) { + Some(Node::NodeItem(&Item{ ref name, .. })) | + Some(Node::NodeTraitItem(&TraitItem{ ref name, .. })) | + Some(Node::NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), + _ => None, + } +} + +/// Checks if a `let` decl is from a `for` loop desugaring. +pub fn is_from_for_desugar(decl: &Decl) -> bool { + if_let_chain! { + [ + let DeclLocal(ref loc) = decl.node, + let Some(ref expr) = loc.init, + let ExprMatch(_, _, MatchSource::ForLoopDesugar) = expr.node + ], + { return true; } + }; + false +} + + +/// Convert a span to a code snippet if available, otherwise use default. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) +} + +/// Convert a span to a code snippet. Returns `None` if not available. +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { + cx.sess().codemap().span_to_snippet(span).ok() +} + +/// Convert a span (from a block) to a code snippet if available, otherwise use default. +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// things which need to be printed as such. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + let snip = snippet(cx, span, default); + trim_multiline(snip, true) +} + +/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. +/// Also takes an `Option<String>` which can be put inside the braces. +pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { + let code = snippet_block(cx, expr.span, default); + let string = option.unwrap_or_default(); + if let ExprBlock(_) = expr.node { + Cow::Owned(format!("{}{}", code, string)) + } else if string.is_empty() { + Cow::Owned(format!("{{ {} }}", code)) + } else { + Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) + } +} + +/// Trim indentation from a multiline string with possibility of ignoring the first line. +pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { + let s_space = trim_multiline_inner(s, ignore_first, ' '); + let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); + trim_multiline_inner(s_tab, ignore_first, ' ') +} + +fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { + let x = s.lines() + .skip(ignore_first as usize) + .filter_map(|l| { + if l.len() > 0 { + // ignore empty lines + Some(l.char_indices() + .find(|&(_, x)| x != ch) + .unwrap_or((l.len(), ch)) + .0) + } else { + None + } + }) + .min() + .unwrap_or(0); + if x > 0 { + Cow::Owned(s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.len() == 0 { + l + } else { + l.split_at(x).1 + } + }) + .collect::<Vec<_>>() + .join("\n")) + } else { + s + } +} + +/// Get a parent expressions if any – this is useful to constrain a lint. +pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { + let map = &cx.tcx.map; + let node_id: NodeId = e.id; + let parent_id: NodeId = map.get_parent_node(node_id); + if node_id == parent_id { + return None; + } + map.find(parent_id).and_then(|node| { + if let Node::NodeExpr(parent) = node { + Some(parent) + } else { + None + } + }) +} + +pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { + let map = &cx.tcx.map; + let enclosing_node = map.get_enclosing_scope(node) + .and_then(|enclosing_id| map.find(enclosing_id)); + if let Some(node) = enclosing_node { + match node { + Node::NodeBlock(ref block) => Some(block), + Node::NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), + _ => None, + } + } else { + None + } +} + +pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); + +impl<'a> Drop for DiagnosticWrapper<'a> { + fn drop(&mut self) { + self.0.emit(); + } +} + +impl<'a> DerefMut for DiagnosticWrapper<'a> { + fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { + &mut self.0 + } +} + +impl<'a> Deref for DiagnosticWrapper<'a> { + type Target = DiagnosticBuilder<'a>; + fn deref(&self) -> &DiagnosticBuilder<'a> { + &self.0 + } +} + +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, sp, msg); + if cx.current_level(lint) != Level::Allow { + db.fileline_help(sp, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); + } + DiagnosticWrapper(db) +} + +pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) + -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, span, msg); + if cx.current_level(lint) != Level::Allow { + db.fileline_help(span, + &format!("{}\nfor further information visit \ + https://github.com/Manishearth/rust-clippy/wiki#{}", + help, + lint.name_lower())); + } + DiagnosticWrapper(db) +} + +pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, + note: &str) + -> DiagnosticWrapper<'a> { + let mut db = cx.struct_span_lint(lint, span, msg); + if cx.current_level(lint) != Level::Allow { + if note_span == span { + db.fileline_note(note_span, note); + } else { + db.span_note(note_span, note); + } + db.fileline_help(span, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); + } + DiagnosticWrapper(db) +} + +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) + -> DiagnosticWrapper<'a> + where F: FnOnce(&mut DiagnosticWrapper) +{ + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); + if cx.current_level(lint) != Level::Allow { + f(&mut db); + db.fileline_help(sp, + &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); + } + db +} + +/// Return the base type for references and raw pointers. +pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { + match ty.sty { + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), + _ => ty, + } +} + +/// Return the base type for references and raw pointers, and count reference depth. +pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { + fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { + match ty.sty { + ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), + _ => (ty, depth), + } + } + inner(ty, 0) +} + +/// Check whether the given expression is a constant literal of the given value. +pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { + // FIXME: use constant folding + if let ExprLit(ref spanned) = expr.node { + if let Lit_::LitInt(v, _) = spanned.node { + return v == value; + } + } + false +} + +pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { + cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() +} + +pub struct LimitStack { + stack: Vec<u64>, +} + +impl Drop for LimitStack { + fn drop(&mut self) { + assert_eq!(self.stack.len(), 1); + } +} + +impl LimitStack { + pub fn new(limit: u64) -> LimitStack { + LimitStack { stack: vec![limit] } + } + pub fn limit(&self) -> u64 { + *self.stack.last().expect("there should always be a value in the stack") + } + pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs(sess, attrs, name, |val| stack.push(val)); + } + pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); + } +} + +fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { + for attr in attrs { + let attr = &attr.node; + if attr.is_sugared_doc { + continue; + } + if let ast::MetaNameValue(ref key, ref value) = attr.value.node { + if *key == name { + if let Lit_::LitStr(ref s, _) = value.node { + if let Ok(value) = FromStr::from_str(s) { + f(value) + } else { + sess.span_err(value.span, "not a number"); + } + } else { + unreachable!() + } + } + } + } +} + +/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. +pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { + 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) + }) + }); + + match span_name_span { + Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), + None => return None, + Some((_, new_span)) => span = new_span, + } + } +} -- cgit 1.4.1-3-g733a5 From afee209d5a85c41f02145869ca360f23a69344d1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 6 Feb 2016 22:41:12 +0100 Subject: Add missing ExprLoop to SpanlessEq --- src/utils/hir.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 95356772e60..457f11a0d26 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } match (&left.node, &right.node) { - (&ExprAddrOf(ref lmut, ref le), &ExprAddrOf(ref rmut, ref re)) => { + (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => { lmut == rmut && self.eq_expr(le, re) } (&ExprAgain(li), &ExprAgain(ri)) => { @@ -102,6 +102,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { 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), &ExprLoop(ref rb, ref rl)) => { + self.eq_block(lb, rb) && + both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) + + } (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { ls == rs && self.eq_expr(le, re) && -- cgit 1.4.1-3-g733a5 From 88beb351940e888932b30c555c273f18a0254aff Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 9 Feb 2016 15:18:27 +0100 Subject: Implement Expr spanless-hashing --- src/consts.rs | 4 +- src/copies.rs | 93 ++++++++++---- src/utils/hir.rs | 287 +++++++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 2 +- tests/compile-fail/copies.rs | 6 + 5 files changed, 364 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index ddc8560c9b3..4469853ddf9 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -17,7 +17,7 @@ use syntax::ast::{UintTy, FloatTy, StrStyle}; use syntax::ast::Sign::{self, Plus, Minus}; -#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)] pub enum FloatWidth { Fw32, Fw64, @@ -34,7 +34,7 @@ impl From<FloatTy> for FloatWidth { } /// a Lit_-like enum to fold constant `Expr`s into -#[derive(Eq, Debug, Clone)] +#[derive(Eq, Debug, Clone, Hash)] pub enum Constant { /// a String "abc" Str(String, StrStyle), diff --git a/src/copies.rs b/src/copies.rs index b1ea8f0c347..1899b47accd 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,6 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::SpanlessEq; +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use utils::{SpanlessEq, SpanlessHash}; use utils::{get_parent_expr, in_macro, span_lint, span_note_and_lint}; /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is @@ -46,8 +48,16 @@ impl LintPass for CopyAndPaste { impl LateLintPass for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext, expr: &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) { + if else_expr.id == expr.id { + return; + } + } + + let (conds, blocks) = if_sequence(expr); lint_same_then_else(cx, expr); - lint_same_cond(cx, expr); + lint_same_cond(cx, &conds); } } } @@ -64,32 +74,22 @@ fn lint_same_then_else(cx: &LateContext, expr: &Expr) { } /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext, expr: &Expr) { - // 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) { - if else_expr.id == expr.id { - return; - } - } - - let conds = condition_sequence(expr); - - for (n, i) in conds.iter().enumerate() { - for j in conds.iter().skip(n+1) { - if SpanlessEq::new(cx).ignore_fn().eq_expr(i, j) { - span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); - } - } +fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { + if let Some((i, j)) = search_same(cx, conds) { + span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); } } -/// Return the list of condition expressions in a sequence of `if/else`. -/// Eg. would return `[a, b]` for the expression `if a {..} else if b {..}`. -fn condition_sequence(mut expr: &Expr) -> Vec<&Expr> { - let mut result = vec![]; +/// Return the list of condition expressions and the list of blocks in a sequence of `if/else`. +/// Eg. would return `([a, b], [c, d, e])` for the expression +/// `if a { c } else if b { d } else { e }`. +fn if_sequence(mut expr: &Expr) -> (Vec<&Expr>, Vec<&Block>) { + let mut conds = vec![]; + let mut blocks = vec![]; - while let ExprIf(ref cond, _, ref else_expr) = expr.node { - result.push(&**cond); + while let ExprIf(ref cond, ref then_block, ref else_expr) = expr.node { + conds.push(&**cond); + blocks.push(&**then_block); if let Some(ref else_expr) = *else_expr { expr = else_expr; @@ -99,5 +99,48 @@ fn condition_sequence(mut expr: &Expr) -> Vec<&Expr> { } } - result + // final `else {..}` + if !blocks.is_empty() { + if let ExprBlock(ref block) = expr.node { + blocks.push(&**block); + } + } + + (conds, blocks) +} + +fn search_same<'a>(cx: &LateContext, exprs: &[&'a Expr]) -> Option<(&'a Expr, &'a Expr)> { + // common cases + if exprs.len() < 2 { + return None; + } + else if exprs.len() == 2 { + return if SpanlessEq::new(cx).ignore_fn().eq_expr(&exprs[0], &exprs[1]) { + Some((&exprs[0], &exprs[1])) + } + else { + None + } + } + + let mut map : HashMap<_, Vec<&'a _>> = HashMap::with_capacity(exprs.len()); + + for &expr in exprs { + let mut h = SpanlessHash::new(cx); + h.hash_expr(expr); + let h = h.finish(); + + match map.entry(h) { + Entry::Occupied(o) => { + for o in o.get() { + if SpanlessEq::new(cx).ignore_fn().eq_expr(o, expr) { + return Some((o, expr)) + } + } + } + Entry::Vacant(v) => { v.insert(vec![expr]); } + } + } + + None } diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 457f11a0d26..bd2aebfd013 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -1,6 +1,8 @@ use consts::constant; use rustc::lint::*; use rustc_front::hir::*; +use std::hash::{Hash, Hasher, SipHasher}; +use syntax::ast::Name; use syntax::ptr::P; /// Type used to check whether two ast are the same. This is different from the operator @@ -242,3 +244,288 @@ fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } + + +pub struct SpanlessHash<'a, 'tcx: 'a> { + /// Context used to evaluate constant expressions. + cx: &'a LateContext<'a, 'tcx>, + s: SipHasher, +} + +impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { + pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + SpanlessHash { cx: cx, s: SipHasher::new() } + } + + pub fn finish(&self) -> u64 { + self.s.finish() + } + + pub fn hash_block(&mut self, b: &Block) { + for s in &b.stmts { + self.hash_stmt(s); + } + + if let Some(ref e) = b.expr { + self.hash_expr(e); + } + + b.rules.hash(&mut self.s); + } + + pub fn hash_expr(&mut self, e: &Expr) { + if let Some(e) = constant(self.cx, e) { + return e.hash(&mut self.s); + } + + match e.node { + ExprAddrOf(m, ref e) => { + let c: fn(_, _) -> _ = ExprAddrOf; + 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.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) => { + let c: fn(_) -> _ = ExprBreak; + c.hash(&mut self.s); + if let Some(i) = i { + self.hash_name(&i.node.name); + } + } + 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 b) => { + let c: fn(_, _, _) -> _ = ExprClosure; + c.hash(&mut self.s); + cap.hash(&mut self.s); + self.hash_block(b); + } + 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); + self.hash_expr(cond); + self.hash_block(t); + 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) => { + let c: fn(_, _) -> _ = ExprLoop; + c.hash(&mut self.s); + self.hash_block(b); + if let Some(i) = *i { + self.hash_name(&i.name); + } + } + ExprMatch(ref e, ref arms, ref s) => { + let c: fn(_, _, _) -> _ = ExprMatch; + c.hash(&mut self.s); + self.hash_expr(e); + + for arm in arms { + // TODO: arm.pat? + if let Some(ref e) = arm.guard { + self.hash_expr(e); + } + self.hash_expr(&arm.body); + } + + 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); + } + ExprRange(ref b, ref e) => { + let c: fn(_, _) -> _ = ExprRange; + c.hash(&mut self.s); + if let Some(ref b) = *b { + self.hash_expr(b); + } + if let Some(ref e) = *e { + self.hash_expr(e); + } + } + 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; + c.hash(&mut self.s); + self.hash_path(subpath); + } + ExprStruct(ref path, ref fields, ref expr) => { + let c: fn(_, _, _) -> _ = ExprStruct; + c.hash(&mut self.s); + + self.hash_path(path); + + for f in fields { + self.hash_name(&f.name.node); + self.hash_expr(&f.expr); + } + + 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(_, _) => { + let c: fn(_, _) -> _ = ExprType; + c.hash(&mut self.s); + // what’s an ExprType anyway? + } + ExprUnary(lop, ref le) => { + let c: fn(_, _) -> _ = ExprUnary; + c.hash(&mut self.s); + + lop.hash(&mut self.s); + self.hash_expr(le); + } + ExprVec(ref v) => { + let c: fn(_) -> _ = ExprVec; + c.hash(&mut self.s); + + self.hash_exprs(v); + }, + ExprWhile(ref cond, ref b, l) => { + let c: fn(_, _, _) -> _ = ExprWhile; + c.hash(&mut self.s); + + self.hash_expr(cond); + self.hash_block(b); + if let Some(l) = l { + self.hash_name(&l.name); + } + } + } + } + + pub fn hash_exprs(&mut self, e: &[P<Expr>]) { + for e in e { + self.hash_expr(e); + } + } + + pub fn hash_name(&mut self, n: &Name) { + n.as_str().hash(&mut self.s); + } + + pub fn hash_path(&mut self, p: &Path) { + p.global.hash(&mut self.s); + for p in &p.segments { + self.hash_name(&p.identifier.name); + } + } + + pub fn hash_stmt(&mut self, b: &Stmt) { + match b.node { + StmtDecl(ref _decl, _) => { + let c: fn(_, _) -> _ = StmtDecl; + c.hash(&mut self.s); + // TODO: decl + } + 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/src/utils/mod.rs b/src/utils/mod.rs index d666ee36bce..f5a028219ed 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -16,7 +16,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; mod hir; -pub use self::hir::SpanlessEq; +pub use self::hir::{SpanlessEq, SpanlessHash}; pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index d6e666f299b..9ae90043948 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -105,6 +105,12 @@ fn if_same_then_else() -> &'static str { fn ifs_same_cond() { let a = 0; + let b = false; + + if b { + } + else if b { //~ERROR this if has the same condition as a previous if + } if a == 1 { } -- cgit 1.4.1-3-g733a5 From ee830ba55e12b9f360b41768078db805332dbea4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 9 Feb 2016 16:45:47 +0100 Subject: Extend IF_SAME_THEN_ELSE to ifs sequences --- src/copies.rs | 50 ++++++++++++++++++++++++++++---------------- src/utils/hir.rs | 4 ++++ tests/compile-fail/copies.rs | 47 +++++++++++++++++++++++++++-------------- 3 files changed, 67 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 1899b47accd..5f7e7a2a643 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -3,7 +3,7 @@ use rustc_front::hir::*; use std::collections::HashMap; use std::collections::hash_map::Entry; use utils::{SpanlessEq, SpanlessHash}; -use utils::{get_parent_expr, in_macro, span_lint, span_note_and_lint}; +use utils::{get_parent_expr, in_macro, span_note_and_lint}; /// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is /// `Warn` by default. @@ -56,26 +56,40 @@ impl LateLintPass for CopyAndPaste { } let (conds, blocks) = if_sequence(expr); - lint_same_then_else(cx, expr); + lint_same_then_else(cx, &blocks); lint_same_cond(cx, &conds); } } } /// Implementation of `IF_SAME_THEN_ELSE`. -fn lint_same_then_else(cx: &LateContext, expr: &Expr) { - if let ExprIf(_, ref then_block, Some(ref else_expr)) = expr.node { - if let ExprBlock(ref else_block) = else_expr.node { - if SpanlessEq::new(cx).eq_block(&then_block, &else_block) { - span_lint(cx, IF_SAME_THEN_ELSE, expr.span, "this if has the same then and else blocks"); - } - } +fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { + let hash = |block| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_block(block); + h.finish() + }; + let eq = |lhs, rhs| -> bool { + SpanlessEq::new(cx).eq_block(lhs, rhs) + }; + + if let Some((i, j)) = search_same(blocks, hash, eq) { + span_note_and_lint(cx, IF_SAME_THEN_ELSE, j.span, "this if has identical blocks", i.span, "same as this"); } } /// Implementation of `IFS_SAME_COND`. fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { - if let Some((i, j)) = search_same(cx, conds) { + let hash = |expr| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_expr(expr); + h.finish() + }; + let eq = |lhs, rhs| -> bool { + SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) + }; + + if let Some((i, j)) = search_same(conds, hash, eq) { span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); } } @@ -109,13 +123,17 @@ fn if_sequence(mut expr: &Expr) -> (Vec<&Expr>, Vec<&Block>) { (conds, blocks) } -fn search_same<'a>(cx: &LateContext, exprs: &[&'a Expr]) -> Option<(&'a Expr, &'a Expr)> { +fn search_same<'a, T, Hash, Eq>(exprs: &[&'a T], + hash: Hash, + eq: Eq) -> Option<(&'a T, &'a T)> +where Hash: Fn(&'a T) -> u64, + Eq: Fn(&'a T, &'a T) -> bool { // common cases if exprs.len() < 2 { return None; } else if exprs.len() == 2 { - return if SpanlessEq::new(cx).ignore_fn().eq_expr(&exprs[0], &exprs[1]) { + return if eq(&exprs[0], &exprs[1]) { Some((&exprs[0], &exprs[1])) } else { @@ -126,14 +144,10 @@ fn search_same<'a>(cx: &LateContext, exprs: &[&'a Expr]) -> Option<(&'a Expr, &' let mut map : HashMap<_, Vec<&'a _>> = HashMap::with_capacity(exprs.len()); for &expr in exprs { - let mut h = SpanlessHash::new(cx); - h.hash_expr(expr); - let h = h.finish(); - - match map.entry(h) { + match map.entry(hash(expr)) { Entry::Occupied(o) => { for o in o.get() { - if SpanlessEq::new(cx).ignore_fn().eq_expr(o, expr) { + if eq(o, expr) { return Some((o, expr)) } } diff --git a/src/utils/hir.rs b/src/utils/hir.rs index bd2aebfd013..c982510b3c3 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -246,6 +246,10 @@ fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool } +/// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this +/// trait would consider IDs and spans. +/// +/// All expressions kind are hashed, but some might have a weaker hash. pub struct SpanlessHash<'a, 'tcx: 'a> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'a, 'tcx>, diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 9ae90043948..f465141248a 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -5,16 +5,15 @@ #![allow(let_and_return)] #![allow(needless_return)] #![allow(unused_variables)] -#![deny(if_same_then_else)] -#![deny(ifs_same_cond)] fn foo() -> bool { unimplemented!() } +#[deny(if_same_then_else)] fn if_same_then_else() -> &'static str { - if true { //~ERROR this if has the same then and else blocks + if true { foo(); } - else { + else { //~ERROR this if has identical blocks foo(); } @@ -26,11 +25,11 @@ fn if_same_then_else() -> &'static str { foo(); } - let _ = if true { //~ERROR this if has the same then and else blocks + let _ = if true { foo(); 42 } - else { + else { //~ERROR this if has identical blocks foo(); 42 }; @@ -39,14 +38,14 @@ fn if_same_then_else() -> &'static str { foo(); } - let _ = if true { //~ERROR this if has the same then and else blocks + let _ = if true { 42 } - else { + else { //~ERROR this if has identical blocks 42 }; - if true { //~ERROR this if has the same then and else blocks + if true { let bar = if true { 42 } @@ -57,7 +56,7 @@ fn if_same_then_else() -> &'static str { while foo() { break; } bar + 1; } - else { + else { //~ERROR this if has identical blocks let bar = if true { 42 } @@ -69,7 +68,7 @@ fn if_same_then_else() -> &'static str { bar + 1; } - if true { //~ERROR this if has the same then and else blocks + if true { match 42 { 42 => (), a if a > 0 => (), @@ -77,7 +76,10 @@ fn if_same_then_else() -> &'static str { _ => (), } } - else { + else if false { + foo(); + } + else if foo() { //~ERROR this if has identical blocks match 42 { 42 => (), a if a > 0 => (), @@ -86,23 +88,36 @@ fn if_same_then_else() -> &'static str { } } - if true { //~ERROR this if has the same then and else blocks + if true { + if let Some(a) = Some(42) {} + } + else { //~ERROR this if has identical blocks + if let Some(a) = Some(42) {} + } + + if true { if let Some(a) = Some(42) {} } else { - if let Some(a) = Some(42) {} + if let Some(a) = Some(43) {} } - if true { //~ERROR this if has the same then and else blocks + if true { let foo = ""; return &foo[0..]; } - else { + else if false { + let foo = "bar"; + return &foo[0..]; + } + else { //~ERROR this if has identical blocks let foo = ""; return &foo[0..]; } } +#[deny(ifs_same_cond)] +#[allow(if_same_then_else)] // all empty blocks fn ifs_same_cond() { let a = 0; let b = false; -- cgit 1.4.1-3-g733a5 From 5ddc615a40d1f33ab23899a4fe63856be9f96435 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 9 Feb 2016 17:10:50 +0100 Subject: Add missing types to eq_ty --- src/utils/hir.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/utils/hir.rs b/src/utils/hir.rs index c982510b3c3..1ccb411b775 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -218,6 +218,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { match (&left.node, &right.node) { (&TyVec(ref lvec), &TyVec(ref rvec)) => self.eq_ty(lvec, rvec), + (&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(ref rt, ref rl)) => { + self.eq_ty(lt, rt) && self.eq_expr(ll, rl) + } (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && self.eq_ty(&*lmut.ty, &*rmut.ty), (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => { lrmut.mutbl == rrmut.mutbl && self.eq_ty(&*lrmut.ty, &*rrmut.ty) @@ -225,6 +228,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) => { both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(lpath, rpath) } + (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyInfer, &TyInfer) => true, _ => false, } -- cgit 1.4.1-3-g733a5 From cbbc667b1b77764949714285356f475159bd2491 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 10 Feb 2016 00:38:53 +0100 Subject: Dogfood for future MATCH_SAME_ARMS lint --- src/len_zero.rs | 4 +--- src/methods.rs | 21 ++++++++++----------- src/misc.rs | 3 +-- src/utils/hir.rs | 4 ++-- tests/compile-fail/cyclomatic_complexity.rs | 16 ++++++++-------- tests/compile-fail/matches.rs | 10 +++++----- 6 files changed, 27 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index ea0c873cb54..125a7c0ae78 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -140,9 +140,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } } match (&left.node, &right.node) { - (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) => { - check_len_zero(cx, span, &method.node, args, lit, op) - } + (&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) } diff --git a/src/methods.rs b/src/methods.rs index 40d975545e9..9263d657371 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -865,12 +865,11 @@ enum SelfKind { impl SelfKind { fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool { match (self, slf) { - (&SelfKind::Value, &SelfValue(_)) => true, - (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) => true, - (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) => true, - (&SelfKind::Ref, &SelfValue(_)) => allow_value_for_ref, - (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, - (&SelfKind::No, &SelfStatic) => true, + (&SelfKind::Value, &SelfValue(_)) | + (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) | + (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) | + (&SelfKind::No, &SelfStatic) => true, + (&SelfKind::Ref, &SelfValue(_)) | (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), _ => false, } @@ -878,11 +877,11 @@ impl SelfKind { fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool { match (self, &ty.node) { - (&SelfKind::Value, &TyPath(..)) => true, - (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true, - (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, - (&SelfKind::Ref, &TyPath(..)) => allow_value_for_ref, - (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, + (&SelfKind::Value, &TyPath(..)) | + (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) | + (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, + (&SelfKind::Ref, &TyPath(..)) | + (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, _ => false, } } diff --git a/src/misc.rs b/src/misc.rs index f570c18b742..076e6e385c2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -421,8 +421,7 @@ impl LateLintPass for UsedUnderscoreBinding { fn is_used(cx: &LateContext, expr: &Expr) -> bool { if let Some(ref parent) = get_parent_expr(cx, expr) { match parent.node { - ExprAssign(_, ref rhs) => **rhs == *expr, - ExprAssignOp(_, _, ref rhs) => **rhs == *expr, + ExprAssign(_, ref rhs) | ExprAssignOp(_, _, ref rhs) => **rhs == *expr, _ => is_used(cx, &parent), } } else { diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 1ccb411b775..f8695956f09 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -38,8 +38,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { false } } - (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) => self.eq_expr(l, r), - (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), + (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | + (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), _ => false, } } diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 5bdca7f3629..3a4a83af5c6 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -138,15 +138,15 @@ fn bloo() { #[cyclomatic_complexity = "0"] fn baa() { //~ ERROR: the function has a cyclomatic complexity of 2 let x = || match 99 { - 0 => true, - 1 => false, - 2 => true, - 4 => true, - 6 => true, - 9 => true, - _ => false, + 0 => 0, + 1 => 1, + 2 => 2, + 4 => 4, + 6 => 6, + 9 => 9, + _ => 42, }; - if x() { + if x() == 42 { println!("x"); } else { println!("not x"); diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 71cc7c59f8f..46d3ff8d5fb 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -101,8 +101,8 @@ fn match_bool() { let test: bool = true; match test { //~ ERROR you seem to be trying to match on a boolean expression - true => (), - false => (), + true => 0, + false => 42, }; let option = 1; @@ -128,9 +128,9 @@ fn match_bool() { // Not linted match option { - 1 ... 10 => (), - 11 ... 20 => (), - _ => (), + 1 ... 10 => 1, + 11 ... 20 => 2, + _ => 3, }; } -- cgit 1.4.1-3-g733a5 From f309dc3c0fae39b993f95058a619f8591e9935df Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 10 Feb 2016 01:22:53 +0100 Subject: Add the MATCH_SAME_ARMS lint --- README.md | 3 +- src/copies.rs | 126 +++++++++++++++++++++++++++++++++++++------ src/lib.rs | 1 + tests/compile-fail/copies.rs | 71 ++++++++++++++++-------- 4 files changed, 162 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 6bb7a2e230e..c2d3b16074c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 119 lints included in this crate: +There are 120 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -65,6 +65,7 @@ name [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead +[match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/copies.rs b/src/copies.rs index 5f7e7a2a643..aea17c3132d 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,7 +1,9 @@ use rustc::lint::*; +use rustc::middle::ty; use rustc_front::hir::*; use std::collections::HashMap; use std::collections::hash_map::Entry; +use syntax::parse::token::InternedString; use utils::{SpanlessEq, SpanlessHash}; use utils::{get_parent_expr, in_macro, span_note_and_lint}; @@ -33,6 +35,25 @@ declare_lint! { "if with the same *then* and *else* blocks" } +/// **What it does:** This lint checks for `match` with identical arm bodies. +/// +/// **Why is this bad?** This is probably a copy & paste error. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// ```rust,ignore +/// match foo { +/// Bar => bar(), +/// Quz => quz(), +/// Baz => bar(), // <= oups +/// ``` +declare_lint! { + pub MATCH_SAME_ARMS, + Warn, + "`match` with identical arm bodies" +} + #[derive(Copy, Clone, Debug)] pub struct CopyAndPaste; @@ -40,7 +61,8 @@ impl LintPass for CopyAndPaste { fn get_lints(&self) -> LintArray { lint_array![ IFS_SAME_COND, - IF_SAME_THEN_ELSE + IF_SAME_THEN_ELSE, + MATCH_SAME_ARMS ] } } @@ -58,39 +80,63 @@ impl LateLintPass for CopyAndPaste { let (conds, blocks) = if_sequence(expr); lint_same_then_else(cx, &blocks); lint_same_cond(cx, &conds); + lint_match_arms(cx, expr); } } } /// Implementation of `IF_SAME_THEN_ELSE`. fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { - let hash = |block| -> u64 { + let hash : &Fn(&&Block) -> u64 = &|block| -> u64 { let mut h = SpanlessHash::new(cx); h.hash_block(block); h.finish() }; - let eq = |lhs, rhs| -> bool { + + let eq : &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same(blocks, hash, eq) { - span_note_and_lint(cx, IF_SAME_THEN_ELSE, j.span, "this if has identical blocks", i.span, "same as this"); + span_note_and_lint(cx, IF_SAME_THEN_ELSE, j.span, "this `if` has identical blocks", i.span, "same as this"); } } /// Implementation of `IFS_SAME_COND`. fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { - let hash = |expr| -> u64 { + let hash : &Fn(&&Expr) -> u64 = &|expr| -> u64 { let mut h = SpanlessHash::new(cx); h.hash_expr(expr); h.finish() }; - let eq = |lhs, rhs| -> bool { + + let eq : &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; if let Some((i, j)) = search_same(conds, hash, eq) { - span_note_and_lint(cx, IFS_SAME_COND, j.span, "this if has the same condition as a previous if", i.span, "same as this"); + span_note_and_lint(cx, IFS_SAME_COND, j.span, "this `if` has the same condition as a previous if", i.span, "same as this"); + } +} + +/// Implementation if `MATCH_SAME_ARMS`. +fn lint_match_arms(cx: &LateContext, expr: &Expr) { + let hash = |arm: &Arm| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_expr(&arm.body); + h.finish() + }; + + let eq = |lhs: &Arm, rhs: &Arm| -> bool { + SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && + // all patterns should have the same bindings + bindings(cx, &lhs.pats[0]) == bindings(cx, &rhs.pats[0]) + }; + + if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { + if let Some((i, j)) = search_same(&**arms, hash, eq) { + span_note_and_lint(cx, MATCH_SAME_ARMS, j.body.span, "this `match` has identical arm bodies", i.body.span, "same as this"); + } } } @@ -123,11 +169,59 @@ fn if_sequence(mut expr: &Expr) -> (Vec<&Expr>, Vec<&Block>) { (conds, blocks) } -fn search_same<'a, T, Hash, Eq>(exprs: &[&'a T], - hash: Hash, - eq: Eq) -> Option<(&'a T, &'a T)> -where Hash: Fn(&'a T) -> u64, - Eq: Fn(&'a T, &'a T) -> bool { +/// Return the list of bindings in a pattern. +fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> { + fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) { + match pat.node { + PatBox(ref pat) | PatRegion(ref pat, _) => bindings_impl(cx, pat, map), + PatEnum(_, Some(ref pats)) => { + for pat in pats { + bindings_impl(cx, pat, map); + } + } + PatIdent(_, ref ident, ref as_pat) => { + if let Entry::Vacant(v) = map.entry(ident.node.name.as_str()) { + v.insert(cx.tcx.pat_ty(pat)); + } + if let Some(ref as_pat) = *as_pat { + bindings_impl(cx, as_pat, map); + } + }, + PatStruct(_, ref fields, _) => { + for pat in fields { + bindings_impl(cx, &pat.node.pat, map); + } + } + PatTup(ref fields) => { + for pat in fields { + bindings_impl(cx, pat, map); + } + } + PatVec(ref lhs, ref mid, ref rhs) => { + for pat in lhs { + bindings_impl(cx, pat, map); + } + if let Some(ref mid) = *mid { + bindings_impl(cx, mid, map); + } + for pat in rhs { + bindings_impl(cx, pat, map); + } + } + PatEnum(..) | PatLit(..) | PatQPath(..) | PatRange(..) | PatWild => (), + } + } + + let mut result = HashMap::new(); + bindings_impl(cx, pat, &mut result); + result +} + +fn search_same<T, Hash, Eq>(exprs: &[T], + hash: Hash, + eq: Eq) -> Option<(&T, &T)> +where Hash: Fn(&T) -> u64, + Eq: Fn(&T, &T) -> bool { // common cases if exprs.len() < 2 { return None; @@ -141,14 +235,14 @@ where Hash: Fn(&'a T) -> u64, } } - let mut map : HashMap<_, Vec<&'a _>> = HashMap::with_capacity(exprs.len()); + let mut map : HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); - for &expr in exprs { + for expr in exprs { match map.entry(hash(expr)) { Entry::Occupied(o) => { for o in o.get() { - if eq(o, expr) { - return Some((o, expr)) + if eq(&o, expr) { + return Some((&o, expr)) } } } diff --git a/src/lib.rs b/src/lib.rs index 775b9830750..675dbdd2dd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,6 +196,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, copies::IF_SAME_THEN_ELSE, copies::IFS_SAME_COND, + copies::MATCH_SAME_ARMS, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_NOT_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index f465141248a..623f9967bd4 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -5,15 +5,18 @@ #![allow(let_and_return)] #![allow(needless_return)] #![allow(unused_variables)] +#![allow(cyclomatic_complexity)] +fn bar<T>(_: T) {} fn foo() -> bool { unimplemented!() } #[deny(if_same_then_else)] +#[deny(match_same_arms)] fn if_same_then_else() -> &'static str { if true { foo(); } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks foo(); } @@ -29,7 +32,7 @@ fn if_same_then_else() -> &'static str { foo(); 42 } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks foo(); 42 }; @@ -41,7 +44,7 @@ fn if_same_then_else() -> &'static str { let _ = if true { 42 } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks 42 }; @@ -56,7 +59,7 @@ fn if_same_then_else() -> &'static str { while foo() { break; } bar + 1; } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks let bar = if true { 42 } @@ -69,29 +72,29 @@ fn if_same_then_else() -> &'static str { } if true { - match 42 { - 42 => (), - a if a > 0 => (), - 10...15 => (), - _ => (), - } + let _ = match 42 { + 42 => 1, + a if a > 0 => 2, + 10...15 => 3, + _ => 4, + }; } else if false { foo(); } - else if foo() { //~ERROR this if has identical blocks - match 42 { - 42 => (), - a if a > 0 => (), - 10...15 => (), - _ => (), - } + else if foo() { //~ERROR this `if` has identical blocks + let _ = match 42 { + 42 => 1, + a if a > 0 => 2, + 10...15 => 3, + _ => 4, + }; } if true { if let Some(a) = Some(42) {} } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks if let Some(a) = Some(42) {} } @@ -102,6 +105,30 @@ fn if_same_then_else() -> &'static str { if let Some(a) = Some(43) {} } + let _ = match 42 { + 42 => foo(), + 51 => foo(), //~ERROR this `match` has identical arm bodies + _ => true, + }; + + let _ = match Some(42) { + Some(42) => 24, + Some(a) => 24, // bindings are different + None => 0, + }; + + match (Some(42), Some(42)) { + (Some(a), None) => bar(a), + (None, Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies + _ => (), + } + + match (Some(42), Some("")) { + (Some(a), None) => bar(a), + (None, Some(a)) => bar(a), // bindings have different types + _ => (), + } + if true { let foo = ""; return &foo[0..]; @@ -110,7 +137,7 @@ fn if_same_then_else() -> &'static str { let foo = "bar"; return &foo[0..]; } - else { //~ERROR this if has identical blocks + else { //~ERROR this `if` has identical blocks let foo = ""; return &foo[0..]; } @@ -124,19 +151,19 @@ fn ifs_same_cond() { if b { } - else if b { //~ERROR this if has the same condition as a previous if + else if b { //~ERROR this `if` has the same condition as a previous if } if a == 1 { } - else if a == 1 { //~ERROR this if has the same condition as a previous if + else if a == 1 { //~ERROR this `if` has the same condition as a previous if } if 2*a == 1 { } else if 2*a == 2 { } - else if 2*a == 1 { //~ERROR this if has the same condition as a previous if + else if 2*a == 1 { //~ERROR this `if` has the same condition as a previous if } else if a == 1 { } -- cgit 1.4.1-3-g733a5 From 68ecd06f4cf67a996af348a5ccc90d6a0f25589f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 11 Feb 2016 23:49:35 +0100 Subject: Small optimisation of most common cases --- src/copies.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index aea17c3132d..e2defe8f364 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -4,6 +4,7 @@ use rustc_front::hir::*; use std::collections::HashMap; use std::collections::hash_map::Entry; use syntax::parse::token::InternedString; +use syntax::util::small_vector::SmallVector; use utils::{SpanlessEq, SpanlessHash}; use utils::{get_parent_expr, in_macro, span_note_and_lint}; @@ -78,8 +79,8 @@ impl LateLintPass for CopyAndPaste { } let (conds, blocks) = if_sequence(expr); - lint_same_then_else(cx, &blocks); - lint_same_cond(cx, &conds); + lint_same_then_else(cx, blocks.as_slice()); + lint_same_cond(cx, conds.as_slice()); lint_match_arms(cx, expr); } } @@ -143,9 +144,9 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { /// Return the list of condition expressions and the list of blocks in a sequence of `if/else`. /// Eg. would return `([a, b], [c, d, e])` for the expression /// `if a { c } else if b { d } else { e }`. -fn if_sequence(mut expr: &Expr) -> (Vec<&Expr>, Vec<&Block>) { - let mut conds = vec![]; - let mut blocks = vec![]; +fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { + let mut conds = SmallVector::zero(); + let mut blocks = SmallVector::zero(); while let ExprIf(ref cond, ref then_block, ref else_expr) = expr.node { conds.push(&**cond); -- cgit 1.4.1-3-g733a5 From 07228a104109b00ad3ec553a33eb6b496fc97451 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 12 Feb 2016 15:51:55 +0100 Subject: Fix `Hash` implementation for `Constant` --- src/consts.rs | 93 ++++++++++++++++++++++++++++++++++++--------------------- tests/consts.rs | 10 ++++++- 2 files changed, 68 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 4469853ddf9..416ec82799c 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -2,22 +2,21 @@ use rustc::lint::LateContext; use rustc::middle::const_eval::lookup_const_by_id; -use rustc::middle::def::PathResolution; -use rustc::middle::def::Def; +use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; -use syntax::ptr::P; -use std::cmp::PartialOrd; use std::cmp::Ordering::{self, Greater, Less, Equal}; -use std::rc::Rc; +use std::cmp::PartialOrd; +use std::hash::{Hash, Hasher}; +use std::mem; use std::ops::Deref; - -use syntax::ast::Lit_; -use syntax::ast::LitIntType; -use syntax::ast::{UintTy, FloatTy, StrStyle}; +use std::rc::Rc; +use syntax::ast::{LitIntType, Lit_}; use syntax::ast::Sign::{self, Plus, Minus}; +use syntax::ast::{UintTy, FloatTy, StrStyle}; +use syntax::ptr::P; -#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)] +#[derive(Debug, Copy, Clone)] pub enum FloatWidth { Fw32, Fw64, @@ -34,7 +33,7 @@ impl From<FloatTy> for FloatWidth { } /// a Lit_-like enum to fold constant `Expr`s into -#[derive(Eq, Debug, Clone, Hash)] +#[derive(Debug, Clone)] pub enum Constant { /// a String "abc" Str(String, StrStyle), @@ -100,18 +99,12 @@ impl PartialEq for Constant { (&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => { lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)) } - (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { - use self::FloatWidth::*; - if match (lw, rw) { - (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, + (&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::<f64>(), rs.parse::<f64>()) { + (Ok(l), Ok(r)) => l.eq(&r), _ => false, - } { - match (ls.parse::<f64>(), rs.parse::<f64>()) { - (Ok(l), Ok(r)) => l.eq(&r), - _ => false, - } - } else { - false } } (&Constant::Bool(l), &Constant::Bool(r)) => l == r, @@ -123,6 +116,46 @@ impl PartialEq for Constant { } } +impl Hash for Constant { + fn hash<H>(&self, state: &mut H) where H: Hasher { + match *self { + Constant::Str(ref s, ref k) => { + s.hash(state); + k.hash(state); + } + Constant::Binary(ref b) => { + b.hash(state); + } + Constant::Byte(u) => { + u.hash(state); + } + Constant::Char(c) => { + c.hash(state); + } + Constant::Int(u, t) => { + u.hash(state); + t.hash(state); + } + Constant::Float(ref f, _) => { + // don’t use the width here because of PartialEq implementation + if let Ok(f) = f.parse::<f64>() { + unsafe { mem::transmute::<f64, u64>(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); + } + } + } +} + impl PartialOrd for Constant { fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { @@ -143,18 +176,10 @@ impl PartialOrd for Constant { (false, true) => Greater, }) } - (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { - use self::FloatWidth::*; - if match (lw, rw) { - (FwAny, _) | (_, FwAny) | (Fw32, Fw32) | (Fw64, Fw64) => true, - _ => false, - } { - match (ls.parse::<f64>(), rs.parse::<f64>()) { - (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), - _ => None, - } - } else { - None + (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { + match (ls.parse::<f64>(), rs.parse::<f64>()) { + (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), + _ => None, } } (&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)), diff --git a/tests/consts.rs b/tests/consts.rs index 75082e646a0..ab8636b8131 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -17,7 +17,7 @@ use syntax::ast::LitIntType::*; use syntax::ast::StrStyle::*; use syntax::ast::Sign::*; -use clippy::consts::{constant_simple, Constant}; +use clippy::consts::{constant_simple, Constant, FloatWidth}; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } @@ -78,4 +78,12 @@ fn test_ops() { check(ONE, &binop(BiSub, litone.clone(), litzero.clone())); check(ONE, &binop(BiMul, litone.clone(), litone.clone())); check(ONE, &binop(BiDiv, litone.clone(), litone.clone())); + + let half_any = Constant::Float("0.5".into(), FloatWidth::FwAny); + let half32 = Constant::Float("0.5".into(), FloatWidth::Fw32); + let half64 = Constant::Float("0.5".into(), FloatWidth::Fw64); + + assert_eq!(half_any, half32); + assert_eq!(half_any, half64); + assert_eq!(half32, half64); // for transitivity } -- cgit 1.4.1-3-g733a5 From 3f34b65747546aefeceb2edc4e8e4dc03c82e7f7 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 12 Feb 2016 18:35:44 +0100 Subject: fix nightly breakage --- Cargo.toml | 2 +- src/approx_const.rs | 8 +- src/attrs.rs | 12 +-- src/bit_mask.rs | 4 +- src/consts.rs | 233 ++++++++++++++++-------------------------- src/derive.rs | 4 +- src/enum_variants.rs | 2 +- src/identity_op.rs | 8 +- src/items_after_statements.rs | 8 +- src/len_zero.rs | 4 +- src/matches.rs | 6 +- src/mutex_atomic.rs | 4 +- src/needless_bool.rs | 4 +- src/open_options.rs | 4 +- src/panic.rs | 4 +- src/precedence.rs | 22 ++-- src/regex.rs | 8 +- src/returns.rs | 18 ++-- src/strings.rs | 4 +- src/types.rs | 54 +++++----- src/unicode.rs | 4 +- src/utils.rs | 9 +- tests/consts.rs | 36 +++---- 23 files changed, 202 insertions(+), 260 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index c0d600e418c..9a0b0b37bae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ regex-syntax = "0.2.2" [dev-dependencies] compiletest_rs = "0.0.11" regex = "0.1.47" -regex_macros = "0.1.27" +regex_macros = "0.1.28" lazy_static = "0.1.15" rustc-serialize = "0.3" diff --git a/src/approx_const.rs b/src/approx_const.rs index d18785ab818..b1a33584442 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use std::f64::consts as f64; use utils::span_lint; -use syntax::ast::{Lit, Lit_, FloatTy}; +use syntax::ast::{Lit, LitKind, FloatTy}; /// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. /// @@ -55,9 +55,9 @@ impl LateLintPass for ApproxConstant { fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { match lit.node { - Lit_::LitFloat(ref s, FloatTy::TyF32) => check_known_consts(cx, e, s, "f32"), - Lit_::LitFloat(ref s, FloatTy::TyF64) => check_known_consts(cx, e, s, "f64"), - Lit_::LitFloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), + LitKind::Float(ref s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"), + LitKind::Float(ref s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"), + LitKind::FloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), _ => (), } } diff --git a/src/attrs.rs b/src/attrs.rs index 231a08779cc..fda46724862 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use reexport::*; use semver::Version; use syntax::codemap::Span; use syntax::attr::*; -use syntax::ast::{Attribute, Lit, Lit_, MetaList, MetaWord, MetaNameValue}; +use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. @@ -54,12 +54,12 @@ impl LintPass for AttrPass { impl LateLintPass for AttrPass { fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) { - if let MetaList(ref name, ref items) = attr.node.value.node { + if let MetaItemKind::List(ref name, ref items) = attr.node.value.node { if items.is_empty() || name != &"deprecated" { return; } for ref item in items { - if let MetaNameValue(ref name, ref lit) = item.node { + if let MetaItemKind::NameValue(ref name, ref lit) = item.node { if name == &"since" { check_semver(cx, item.span, lit); } @@ -144,11 +144,11 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { } for attr in attrs { - if let MetaList(ref inline, ref values) = attr.node.value.node { + if let MetaItemKind::List(ref inline, ref values) = attr.node.value.node { if values.len() != 1 || inline != &"inline" { continue; } - if let MetaWord(ref always) = values[0].node { + if let MetaItemKind::Word(ref always) = values[0].node { if always != &"always" { continue; } @@ -163,7 +163,7 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { } fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { - if let Lit_::LitStr(ref is, _) = lit.node { + if let LitKind::Str(ref is, _) = lit.node { if Version::parse(&*is).is_ok() { return; } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 6de00167571..e1366924e1d 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -4,7 +4,7 @@ use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; use syntax::codemap::Span; -use syntax::ast::Lit_; +use syntax::ast::LitKind; use utils::span_lint; @@ -254,7 +254,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { match lit.node { ExprLit(ref lit_ptr) => { - if let Lit_::LitInt(value, _) = lit_ptr.node { + if let LitKind::Int(value, _) = lit_ptr.node { Some(value) //TODO: Handle sign } else { None diff --git a/src/consts.rs b/src/consts.rs index ddc8560c9b3..5ff0591e02d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -11,10 +11,9 @@ use std::cmp::Ordering::{self, Greater, Less, Equal}; use std::rc::Rc; use std::ops::Deref; -use syntax::ast::Lit_; +use syntax::ast::LitKind; use syntax::ast::LitIntType; use syntax::ast::{UintTy, FloatTy, StrStyle}; -use syntax::ast::Sign::{self, Plus, Minus}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] @@ -27,12 +26,18 @@ pub enum FloatWidth { impl From<FloatTy> for FloatWidth { fn from(ty: FloatTy) -> FloatWidth { match ty { - FloatTy::TyF32 => FloatWidth::Fw32, - FloatTy::TyF64 => FloatWidth::Fw64, + FloatTy::F32 => FloatWidth::Fw32, + FloatTy::F64 => FloatWidth::Fw64, } } } +#[derive(Copy, Eq, Debug, Clone, PartialEq)] +pub enum Sign { + Plus, + Minus, +} + /// a Lit_-like enum to fold constant `Expr`s into #[derive(Eq, Debug, Clone)] pub enum Constant { @@ -44,8 +49,8 @@ pub enum Constant { Byte(u8), /// a single char 'a' Char(char), - /// an integer - Int(u64, LitIntType), + /// an integer, third argument is whether the value is negated + Int(u64, LitIntType, Sign), /// a float with given type Float(String, FloatWidth), /// true or false @@ -65,7 +70,7 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let Constant::Int(val, _) = *self { + if let Constant::Int(val, _, _) = *self { val // TODO we may want to check the sign if any } else { panic!("Could not convert a {:?} to u64", self); @@ -78,13 +83,8 @@ impl Constant { match *self { Constant::Byte(b) => Some(b as f64), Constant::Float(ref s, _) => s.parse().ok(), - Constant::Int(i, ty) => { - Some(if is_negative(ty) { - -(i as f64) - } else { - i as f64 - }) - } + Constant::Int(i, _, Sign::Minus) => Some(-(i as f64)), + Constant::Int(i, _, Sign::Plus) => Some(i as f64), _ => None, } } @@ -97,8 +97,9 @@ impl PartialEq for Constant { (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, (&Constant::Byte(l), &Constant::Byte(r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r, - (&Constant::Int(lv, lty), &Constant::Int(rv, rty)) => { - lv == rv && (is_negative(lty) & (lv != 0)) == (is_negative(rty) & (rv != 0)) + (&Constant::Int(0, _, _), &Constant::Int(0, _, _)) => true, + (&Constant::Int(lv, _, lneg), &Constant::Int(rv, _, rneg)) => { + lv == rv && lneg == rneg } (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { use self::FloatWidth::*; @@ -135,14 +136,11 @@ impl PartialOrd for Constant { } (&Constant::Byte(ref l), &Constant::Byte(ref r)) => Some(l.cmp(r)), (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), - (&Constant::Int(ref lv, lty), &Constant::Int(ref rv, rty)) => { - Some(match (is_negative(lty) && *lv != 0, is_negative(rty) && *rv != 0) { - (true, true) => rv.cmp(lv), - (false, false) => lv.cmp(rv), - (true, false) => Less, - (false, true) => Greater, - }) - } + (&Constant::Int(0, _, _), &Constant::Int(0, _, _)) => Some(Equal), + (&Constant::Int(ref lv, _, Sign::Plus), &Constant::Int(ref rv, _, Sign::Plus)) => Some(lv.cmp(rv)), + (&Constant::Int(ref lv, _, Sign::Minus), &Constant::Int(ref rv, _, Sign::Minus)) => Some(rv.cmp(lv)), + (&Constant::Int(_, _, Sign::Minus), &Constant::Int(_, _, Sign::Plus)) => Some(Less), + (&Constant::Int(_, _, Sign::Plus), &Constant::Int(_, _, Sign::Minus)) => Some(Greater), (&Constant::Float(ref ls, lw), &Constant::Float(ref rs, rw)) => { use self::FloatWidth::*; if match (lw, rw) { @@ -171,16 +169,16 @@ impl PartialOrd for Constant { } } -fn lit_to_constant(lit: &Lit_) -> Constant { +fn lit_to_constant(lit: &LitKind) -> Constant { match *lit { - Lit_::LitStr(ref is, style) => Constant::Str(is.to_string(), style), - Lit_::LitByte(b) => Constant::Byte(b), - Lit_::LitByteStr(ref s) => Constant::Binary(s.clone()), - Lit_::LitChar(c) => Constant::Char(c), - Lit_::LitInt(value, ty) => Constant::Int(value, ty), - Lit_::LitFloat(ref is, ty) => Constant::Float(is.to_string(), ty.into()), - Lit_::LitFloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::FwAny), - Lit_::LitBool(b) => Constant::Bool(b), + LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), + LitKind::Byte(b) => Constant::Byte(b), + LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), + LitKind::Char(c) => Constant::Char(c), + LitKind::Int(value, ty) => Constant::Int(value, ty, Sign::Plus), + LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), + LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::FwAny), + LitKind::Bool(b) => Constant::Bool(b), } } @@ -189,21 +187,21 @@ fn constant_not(o: Constant) -> Option<Constant> { use self::Constant::*; match o { Bool(b) => Some(Bool(!b)), - Int(::std::u64::MAX, SignedIntLit(_, Plus)) => None, - Int(value, SignedIntLit(ity, Plus)) => Some(Int(value + 1, SignedIntLit(ity, Minus))), - Int(0, SignedIntLit(ity, Minus)) => Some(Int(1, SignedIntLit(ity, Minus))), - Int(value, SignedIntLit(ity, Minus)) => Some(Int(value - 1, SignedIntLit(ity, Plus))), - Int(value, UnsignedIntLit(ity)) => { + Int(::std::u64::MAX, LitIntType::Signed(_), Sign::Plus) => None, + Int(value, LitIntType::Signed(ity), Sign::Plus) => Some(Int(value + 1, LitIntType::Signed(ity), Sign::Minus)), + Int(0, LitIntType::Signed(ity), Sign::Minus) => Some(Int(1, LitIntType::Signed(ity), Sign::Minus)), + Int(value, LitIntType::Signed(ity), Sign::Minus) => Some(Int(value - 1, LitIntType::Signed(ity), Sign::Plus)), + Int(value, LitIntType::Unsigned(ity), Sign::Plus) => { let mask = match ity { - UintTy::TyU8 => ::std::u8::MAX as u64, - UintTy::TyU16 => ::std::u16::MAX as u64, - UintTy::TyU32 => ::std::u32::MAX as u64, - UintTy::TyU64 => ::std::u64::MAX, - UintTy::TyUs => { + UintTy::U8 => ::std::u8::MAX as u64, + UintTy::U16 => ::std::u16::MAX as u64, + UintTy::U32 => ::std::u32::MAX as u64, + UintTy::U64 => ::std::u64::MAX, + UintTy::Us => { return None; } // refuse to guess }; - Some(Int(!value & mask, UnsignedIntLit(ity))) + Some(Int(!value & mask, LitIntType::Unsigned(ity), Sign::Plus)) }, _ => None, } @@ -213,8 +211,8 @@ fn constant_negate(o: Constant) -> Option<Constant> { use syntax::ast::LitIntType::*; use self::Constant::*; match o { - Int(value, SignedIntLit(ity, sign)) => Some(Int(value, SignedIntLit(ity, neg_sign(sign)))), - Int(value, UnsuffixedIntLit(sign)) => Some(Int(value, UnsuffixedIntLit(neg_sign(sign)))), + Int(value, LitIntType::Signed(ity), sign) => Some(Int(value, LitIntType::Signed(ity), neg_sign(sign))), + Int(value, LitIntType::Unsuffixed, sign) => Some(Int(value, LitIntType::Unsuffixed, neg_sign(sign))), Float(is, ty) => Some(Float(neg_float_str(is), ty)), _ => None, } @@ -235,78 +233,32 @@ fn neg_float_str(s: String) -> String { } } -/// is the given LitIntType negative? -/// -/// Examples -/// -/// ``` -/// assert!(is_negative(UnsuffixedIntLit(Minus))); -/// ``` -pub fn is_negative(ty: LitIntType) -> bool { - match ty { - LitIntType::SignedIntLit(_, sign) | LitIntType::UnsuffixedIntLit(sign) => sign == Minus, - LitIntType::UnsignedIntLit(_) => false, - } -} - -fn unify_int_type(l: LitIntType, r: LitIntType, s: Sign) -> Option<LitIntType> { +fn unify_int_type(l: LitIntType, r: LitIntType) -> Option<LitIntType> { use syntax::ast::LitIntType::*; match (l, r) { - (SignedIntLit(lty, _), SignedIntLit(rty, _)) => { + (Signed(lty), Signed(rty)) => { if lty == rty { - Some(SignedIntLit(lty, s)) + Some(LitIntType::Signed(lty)) } else { None } } - (UnsignedIntLit(lty), UnsignedIntLit(rty)) => { - if s == Plus && lty == rty { - Some(UnsignedIntLit(lty)) - } else { - None - } - } - (UnsuffixedIntLit(_), UnsuffixedIntLit(_)) => Some(UnsuffixedIntLit(s)), - (SignedIntLit(lty, _), UnsuffixedIntLit(_)) => Some(SignedIntLit(lty, s)), - (UnsignedIntLit(lty), UnsuffixedIntLit(rs)) => { - if rs == Plus { - Some(UnsignedIntLit(lty)) - } else { - None - } - } - (UnsuffixedIntLit(_), SignedIntLit(rty, _)) => Some(SignedIntLit(rty, s)), - (UnsuffixedIntLit(ls), UnsignedIntLit(rty)) => { - if ls == Plus { - Some(UnsignedIntLit(rty)) + (Unsigned(lty), Unsigned(rty)) => { + if lty == rty { + Some(LitIntType::Unsigned(lty)) } else { None } } + (Unsuffixed, Unsuffixed) => Some(Unsuffixed), + (Signed(lty), Unsuffixed) => Some(Signed(lty)), + (Unsigned(lty), Unsuffixed) => Some(Unsigned(lty)), + (Unsuffixed, Signed(rty)) => Some(Signed(rty)), + (Unsuffixed, Unsigned(rty)) => Some(Unsigned(rty)), _ => None, } } -fn add_neg_int(pos: u64, pty: LitIntType, neg: u64, nty: LitIntType) -> Option<Constant> { - if neg > pos { - unify_int_type(nty, pty, Minus).map(|ty| Constant::Int(neg - pos, ty)) - } else { - unify_int_type(nty, pty, Plus).map(|ty| Constant::Int(pos - neg, ty)) - } -} - -fn sub_int(l: u64, lty: LitIntType, r: u64, rty: LitIntType, neg: bool) -> Option<Constant> { - unify_int_type(lty, - rty, - if neg { - Minus - } else { - Plus - }) - .and_then(|ty| l.checked_sub(r).map(|v| Constant::Int(v, ty))) -} - - pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { let mut cx = ConstEvalLateContext { lcx: Some(lcx), @@ -412,23 +364,9 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { self.binop_apply(left, right, |l, r| { match (l, r) { (Constant::Byte(l8), Constant::Byte(r8)) => l8.checked_add(r8).map(Constant::Byte), - (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { - let (ln, rn) = (is_negative(lty), is_negative(rty)); - if ln == rn { - unify_int_type(lty, - rty, - if ln { - Minus - } else { - Plus - }) - .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) - } else if ln { - add_neg_int(r64, rty, l64, lty) - } else { - add_neg_int(l64, lty, r64, rty) - } - } + (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { + add_ints(l64, r64, lty, rty, lsign, rsign) + }, // TODO: float (would need bignum library?) _ => None, } @@ -444,20 +382,9 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { Some(Constant::Byte(l8 - r8)) } } - (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { - match (is_negative(lty), is_negative(rty)) { - (false, false) => sub_int(l64, lty, r64, rty, r64 > l64), - (true, true) => sub_int(l64, lty, r64, rty, l64 > r64), - (true, false) => { - unify_int_type(lty, rty, Minus) - .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) - } - (false, true) => { - unify_int_type(lty, rty, Plus) - .and_then(|ty| l64.checked_add(r64).map(|v| Constant::Int(v, ty))) - } - } - } + (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { + add_ints(l64, r64, lty, rty, lsign, neg_sign(rsign)) + }, _ => None, } }) @@ -487,16 +414,10 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { { self.binop_apply(left, right, |l, r| { match (l, r) { - (Constant::Int(l64, lty), Constant::Int(r64, rty)) => { + (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { f(l64, r64).and_then(|value| { - unify_int_type(lty, - rty, - if is_negative(lty) == is_negative(rty) { - Plus - } else { - Minus - }) - .map(|ty| Constant::Int(value, ty)) + let sign = if lsign == rsign { Sign::Plus } else { Sign::Minus }; + unify_int_type(lty, rty).map(|ty| Constant::Int(value, ty, sign)) }) } _ => None, @@ -511,8 +432,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { match (l, r) { (Constant::Bool(l), Constant::Bool(r)) => Some(Constant::Bool(f(l as u64, r as u64) != 0)), (Constant::Byte(l8), Constant::Byte(r8)) => Some(Constant::Byte(f(l8 as u64, r8 as u64) as u8)), - (Constant::Int(l, lty), Constant::Int(r, rty)) => { - unify_int_type(lty, rty, Plus).map(|ty| Constant::Int(f(l, r), ty)) + (Constant::Int(l, lty, lsign), Constant::Int(r, rty, rsign)) => { + if lsign == Sign::Plus && rsign == Sign::Plus { + unify_int_type(lty, rty).map(|ty| Constant::Int(f(l, r), ty, Sign::Plus)) + } else { + None + } } _ => None, } @@ -555,3 +480,21 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { }) } } + +fn add_ints(l64: u64, r64: u64, lty: LitIntType, rty: LitIntType, lsign: Sign, rsign: Sign) -> Option<Constant> { + let ty = if let Some(ty) = unify_int_type(lty, rty) { ty } else { return None; }; + match (lsign, rsign) { + (Sign::Plus, Sign::Plus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Plus)), + (Sign::Plus, Sign::Minus) => if r64 > l64 { + Some(Constant::Int(r64 - l64, ty, Sign::Minus)) + } else { + Some(Constant::Int(l64 - r64, ty, Sign::Plus)) + }, + (Sign::Minus, Sign::Minus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Minus)), + (Sign::Minus, Sign::Plus) => if l64 > r64 { + Some(Constant::Int(l64 - r64, ty, Sign::Minus)) + } else { + Some(Constant::Int(r64 - l64, ty, Sign::Plus)) + }, + } +} diff --git a/src/derive.rs b/src/derive.rs index d8f331ef5ff..e9eef824713 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc::middle::ty::fast_reject::simplify_type; use rustc::middle::ty; use rustc_front::hir::*; -use syntax::ast::{Attribute, MetaItem_}; +use syntax::ast::{Attribute, MetaItemKind}; use syntax::codemap::Span; use utils::{CLONE_TRAIT_PATH, HASH_PATH}; use utils::{match_path, span_lint_and_then}; @@ -170,7 +170,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have. fn is_automatically_derived(attr: &Attribute) -> bool { - if let MetaItem_::MetaWord(ref word) = attr.node.value.node { + if let MetaItemKind::Word(ref word) = attr.node.value.node { word == &"automatically_derived" } else { false diff --git a/src/enum_variants.rs b/src/enum_variants.rs index 8ceaca1bbf3..c77e42e69c9 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -41,7 +41,7 @@ fn partial_rmatch(left: &str, right: &str) -> usize { impl EarlyLintPass for EnumVariantNames { fn check_item(&mut self, cx: &EarlyContext, item: &Item) { - if let ItemEnum(ref def, _) = item.node { + if let ItemKind::Enum(ref def, _) = item.node { if def.variants.len() < 2 { return; } diff --git a/src/identity_op.rs b/src/identity_op.rs index 1a62ffb4ae0..b033b234122 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use consts::{constant_simple, is_negative, Constant}; +use consts::{constant_simple, Constant, Sign}; use utils::{span_lint, snippet, in_macro}; /// **What it does:** This lint checks for identity operations, e.g. `x + 0`. @@ -55,11 +55,11 @@ impl LateLintPass for IdentityOp { fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(Constant::Int(v, ty)) = constant_simple(e) { + if let Some(Constant::Int(v, _, sign)) = constant_simple(e) { if match m { 0 => v == 0, - -1 => is_negative(ty) && v == 1, - 1 => !is_negative(ty) && v == 1, + -1 => sign == Sign::Minus && v == 1, + 1 => sign == Sign::Plus && v == 1, _ => unreachable!(), } { span_lint(cx, diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 2aa2fc6da34..9bfb3b87ed1 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -47,15 +47,15 @@ impl EarlyLintPass for ItemsAfterStatemets { } let mut stmts = item.stmts.iter().map(|stmt| &stmt.node); // skip initial items - while let Some(&StmtDecl(ref decl, _)) = stmts.next() { - if let DeclLocal(_) = decl.node { + while let Some(&StmtKind::Decl(ref decl, _)) = stmts.next() { + if let DeclKind::Local(_) = decl.node { break; } } // lint on all further items for stmt in stmts { - if let StmtDecl(ref decl, _) = *stmt { - if let DeclItem(ref it) = decl.node { + if let StmtKind::Decl(ref decl, _) = *stmt { + if let DeclKind::Item(ref it) = decl.node { if in_macro(cx, it.span) { return; } diff --git a/src/len_zero.rs b/src/len_zero.rs index ea0c873cb54..4f3c2367370 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -6,7 +6,7 @@ use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use syntax::ast::{Lit, Lit_}; +use syntax::ast::{Lit, LitKind}; use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; @@ -151,7 +151,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { - if let Spanned{node: Lit_::LitInt(0, _), ..} = *lit { + if let Spanned{node: LitKind::Int(0, _), ..} = *lit { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint(cx, LEN_ZERO, diff --git a/src/matches.rs b/src/matches.rs index 6be5d0bf24f..ca410a413bd 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -5,7 +5,7 @@ use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::ty; use rustc_front::hir::*; use std::cmp::Ordering; -use syntax::ast::Lit_::LitBool; +use syntax::ast::LitKind; use syntax::codemap::Span; use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; @@ -238,8 +238,8 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { match lit.node { - LitBool(true) => Some((&*arms[0].body, &*arms[1].body)), - LitBool(false) => Some((&*arms[1].body, &*arms[0].body)), + LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), + LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), _ => None, } } else { diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index cf1c347750c..8a51ba27b8e 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -56,8 +56,8 @@ impl LateLintPass for MutexAtomic { behaviour and not the internal type, consider using Mutex<()>.", atomic_name); match *mutex_param { - ty::TyUint(t) if t != ast::TyUs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::TyInt(t) if t != ast::TyIs => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + ty::TyUint(t) if t != ast::UintTy::Us => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + ty::TyInt(t) if t != ast::IntTy::Is => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), }; } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 4ddd8f2f3c5..fe46988dccb 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -5,7 +5,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::ast::Lit_; +use syntax::ast::LitKind; use syntax::codemap::Spanned; use utils::{span_lint, span_lint_and_then, snippet}; @@ -164,7 +164,7 @@ fn fetch_bool_expr(expr: &Expr) -> Option<bool> { match expr.node { ExprBlock(ref block) => fetch_bool_block(block), ExprLit(ref lit_ptr) => { - if let Lit_::LitBool(value) = lit_ptr.node { + if let LitKind::Bool(value) = lit_ptr.node { Some(value) } else { None diff --git a/src/open_options.rs b/src/open_options.rs index 77e9a300335..8b1c4a90fdf 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::{Expr, ExprMethodCall, ExprLit}; use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; use syntax::codemap::{Span, Spanned}; -use syntax::ast::Lit_::LitBool; +use syntax::ast::LitKind; /// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. /// @@ -65,7 +65,7 @@ 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: LitBool(lit), ..} = **span { + if let Spanned {node: LitKind::Bool(lit), ..} = **span { if lit { Argument::True } else { diff --git a/src/panic.rs b/src/panic.rs index 5337942b4e0..b76def8d2f3 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::ast::Lit_::LitStr; +use syntax::ast::LitKind; use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; @@ -37,7 +37,7 @@ impl LateLintPass for PanicPass { let ExprPath(None, ref path) = fun.node, match_path(path, &BEGIN_UNWIND), let ExprLit(ref lit) = params[0].node, - let LitStr(ref string, _) = lit.node, + let LitKind::Str(ref string, _) = lit.node, string.contains('{'), let Some(sp) = cx.sess().codemap() .with_expn_info(expr.span.expn_id, diff --git a/src/precedence.rs b/src/precedence.rs index 009a79b1673..d498510f97a 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -32,7 +32,7 @@ impl LintPass for Precedence { impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { - if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node { + if let ExprKind::Binary(Spanned { node: op, ..}, ref left, ref right) = expr.node { if !is_bit_op(op) { return; } @@ -71,12 +71,12 @@ impl EarlyLintPass for Precedence { } } - if let ExprUnary(UnNeg, ref rhs) = expr.node { - if let ExprMethodCall(_, _, ref args) = rhs.node { + if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.node { + if let ExprKind::MethodCall(_, _, ref args) = rhs.node { if let Some(slf) = args.first() { - if let ExprLit(ref lit) = slf.node { + if let ExprKind::Lit(ref lit) = slf.node { match lit.node { - LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) => { + LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { span_lint(cx, PRECEDENCE, expr.span, @@ -95,21 +95,23 @@ impl EarlyLintPass for Precedence { fn is_arith_expr(expr: &Expr) -> bool { match expr.node { - ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op), + ExprKind::Binary(Spanned { node: op, ..}, _, _) => is_arith_op(op), _ => false, } } -fn is_bit_op(op: BinOp_) -> bool { +fn is_bit_op(op: BinOpKind) -> bool { + use syntax::ast::BinOpKind::*; match op { - BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true, + BitXor | BitAnd | BitOr | Shl | Shr => true, _ => false, } } -fn is_arith_op(op: BinOp_) -> bool { +fn is_arith_op(op: BinOpKind) -> bool { + use syntax::ast::BinOpKind::*; match op { - BiAdd | BiSub | BiMul | BiDiv | BiRem => true, + Add | Sub | Mul | Div | Rem => true, _ => false, } } diff --git a/src/regex.rs b/src/regex.rs index cf938dcf4b3..5103391e9dd 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,7 +1,7 @@ use regex_syntax; use std::error::Error; use std::collections::HashSet; -use syntax::ast::Lit_::LitStr; +use syntax::ast::LitKind; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; @@ -75,7 +75,7 @@ impl LateLintPass for RegexPass { match_path(path, ®EX_NEW_PATH) && args.len() == 1 ], { if let ExprLit(ref lit) = args[0].node { - if let LitStr(ref r, _) = lit.node { + if let LitKind::Str(ref r, _) = lit.node { match regex_syntax::Expr::parse(r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { @@ -176,8 +176,8 @@ impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { if self.spans.contains(&span) { return; } - span_lint(self.cx, - REGEX_MACRO, + span_lint(self.cx, + REGEX_MACRO, span, "`regex!(_)` found. \ Please use `Regex::new(_)`, which is faster for now."); diff --git a/src/returns.rs b/src/returns.rs index 3d830e9e372..63864eafcd2 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -40,8 +40,8 @@ impl ReturnPass { if let Some(ref expr) = block.expr { self.check_final_expr(cx, expr); } else if let Some(stmt) = block.stmts.last() { - if let StmtSemi(ref expr, _) = stmt.node { - if let ExprRet(Some(ref inner)) = expr.node { + if let StmtKind::Semi(ref expr, _) = stmt.node { + if let ExprKind::Ret(Some(ref inner)) = expr.node { self.emit_return_lint(cx, (stmt.span, inner.span)); } } @@ -52,22 +52,22 @@ impl ReturnPass { fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) { match expr.node { // simple return is always "bad" - ExprRet(Some(ref inner)) => { + ExprKind::Ret(Some(ref inner)) => { self.emit_return_lint(cx, (expr.span, inner.span)); } // a whole block? check it! - ExprBlock(ref block) => { + 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 - ExprIf(_, ref ifblock, Some(ref elsexpr)) => { + ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { self.check_block_return(cx, ifblock); self.check_final_expr(cx, elsexpr); } // a match expr, check all arms - ExprMatch(_, ref arms) => { + ExprKind::Match(_, ref arms) => { for arm in arms { self.check_final_expr(cx, &arm.body); } @@ -94,11 +94,11 @@ impl ReturnPass { [ let Some(stmt) = block.stmts.last(), let Some(ref retexpr) = block.expr, - let StmtDecl(ref decl, _) = stmt.node, - let DeclLocal(ref local) = decl.node, + let StmtKind::Decl(ref decl, _) = stmt.node, + let DeclKind::Local(ref local) = decl.node, let Some(ref initexpr) = local.init, let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, - let ExprPath(_, ref path) = retexpr.node, + let ExprKind::Path(_, ref path) = retexpr.node, match_path_ast(path, &[&id.name.as_str()]) ], { self.emit_let_lint(cx, retexpr.span, initexpr.span); diff --git a/src/strings.rs b/src/strings.rs index b78db7f4b77..7b4b2e2c5ec 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -133,13 +133,13 @@ impl LintPass for StringLitAsBytes { impl LateLintPass for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { use std::ascii::AsciiExt; - use syntax::ast::Lit_::LitStr; + use syntax::ast::LitKind; use utils::{snippet, in_macro}; if let ExprMethodCall(ref name, _, ref args) = e.node { if name.node.as_str() == "as_bytes" { if let ExprLit(ref lit) = args[0].node { - if let LitStr(ref lit_content, _) = lit.node { + if let LitKind::Str(ref lit_content, _) = lit.node { if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, e.span) { let msg = format!("calling `as_bytes()` on a string literal. \ Consider using a byte string literal instead: \ diff --git a/src/types.rs b/src/types.rs index a48172c5980..7cfcc76193d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -235,7 +235,7 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize { fn is_isize_or_usize(typ: &ty::TyS) -> bool { match typ.sty { - ty::TyInt(IntTy::TyIs) | ty::TyUint(UintTy::TyUs) => true, + ty::TyInt(IntTy::Is) | ty::TyUint(UintTy::Us) => true, _ => false, } } @@ -360,7 +360,7 @@ impl LateLintPass for CastPass { match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = if let ty::TyFloat(FloatTy::TyF32) = cast_to.sty { + let to_nbits = if let ty::TyFloat(FloatTy::F32) = cast_to.sty { 32 } else { 64 @@ -391,7 +391,7 @@ impl LateLintPass for CastPass { check_truncation_and_wrapping(cx, expr, cast_from, cast_to); } (false, false) => { - if let (&ty::TyFloat(FloatTy::TyF64), &ty::TyFloat(FloatTy::TyF32)) = (&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, @@ -560,12 +560,12 @@ impl LintPass for CharLitAsU8 { impl LateLintPass for CharLitAsU8 { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - use syntax::ast::{Lit_, UintTy}; + use syntax::ast::{LitKind, UintTy}; if let ExprCast(ref e, _) = expr.node { if let ExprLit(ref l) = e.node { - if let Lit_::LitChar(_) = l.node { - if ty::TyUint(UintTy::TyU8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { + if let LitKind::Char(_) = l.node { + if ty::TyUint(UintTy::U8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { let msg = "casting character literal to u8. `char`s \ are 4 bytes wide in rust, so casting to u8 \ truncates them"; @@ -676,31 +676,31 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx let which = match (ty, cv) { (&ty::TyBool, Bool(false)) => Minimum, - (&ty::TyInt(IntTy::TyIs), Int(x)) if x == ::std::isize::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::TyI8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::TyI16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::TyI32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::TyI64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum, + (&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MIN as i64 => Minimum, + (&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum, + (&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum, + (&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum, + (&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum, - (&ty::TyUint(UintTy::TyUs), Uint(x)) if x == ::std::usize::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::TyU8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::TyU16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::TyU32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::TyU64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum, + (&ty::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MIN as u64 => Minimum, + (&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum, + (&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum, + (&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum, + (&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum, (&ty::TyBool, Bool(true)) => Maximum, - (&ty::TyInt(IntTy::TyIs), Int(x)) if x == ::std::isize::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::TyI8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::TyI16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::TyI32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::TyI64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum, - - (&ty::TyUint(UintTy::TyUs), Uint(x)) if x == ::std::usize::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::TyU8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::TyU16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::TyU32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::TyU64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum, + (&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MAX as i64 => Maximum, + (&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum, + (&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum, + (&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum, + (&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum, + + (&ty::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MAX as u64 => Maximum, + (&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum, + (&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum, + (&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum, + (&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum, _ => return None, }; diff --git a/src/unicode.rs b/src/unicode.rs index f363eace713..c8d810b9e71 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; -use syntax::ast::Lit_; +use syntax::ast::LitKind; use unicode_normalization::UnicodeNormalization; @@ -59,7 +59,7 @@ impl LintPass for Unicode { impl LateLintPass for Unicode { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprLit(ref lit) = expr.node { - if let Lit_::LitStr(_, _) = lit.node { + if let LitKind::Str(_, _) = lit.node { check_str(cx, lit.span) } } diff --git a/src/utils.rs b/src/utils.rs index 4c89b7f113d..cd4a34d95b3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,8 +10,7 @@ use std::borrow::Cow; use std::mem; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use syntax::ast::Lit_; -use syntax::ast; +use syntax::ast::{LitKind, self}; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; @@ -531,7 +530,7 @@ pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { // FIXME: use constant folding if let ExprLit(ref spanned) = expr.node { - if let Lit_::LitInt(v, _) = spanned.node { + if let LitKind::Int(v, _) = spanned.node { return v == value; } } @@ -575,9 +574,9 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' if attr.is_sugared_doc { continue; } - if let ast::MetaNameValue(ref key, ref value) = attr.value.node { + if let ast::MetaItemKind::NameValue(ref key, ref value) = attr.value.node { if *key == name { - if let Lit_::LitStr(ref s, _) = value.node { + if let LitKind::Str(ref s, _) = value.node { if let Ok(value) = FromStr::from_str(s) { f(value) } else { diff --git a/tests/consts.rs b/tests/consts.rs index 75082e646a0..1d639c8092b 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -11,13 +11,11 @@ use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; -use syntax::ast::Lit_::*; -use syntax::ast::Lit_; -use syntax::ast::LitIntType::*; -use syntax::ast::StrStyle::*; -use syntax::ast::Sign::*; +use syntax::ast::LitKind; +use syntax::ast::LitIntType; +use syntax::ast::StrStyle; -use clippy::consts::{constant_simple, Constant}; +use clippy::consts::{constant_simple, Constant, Sign}; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } @@ -32,7 +30,7 @@ fn expr(n: Expr_) -> Expr { } } -fn lit(l: Lit_) -> Expr { +fn lit(l: LitKind) -> Expr { expr(ExprLit(P(spanned(l)))) } @@ -46,26 +44,26 @@ fn check(expect: Constant, expr: &Expr) { const TRUE : Constant = Constant::Bool(true); const FALSE : Constant = Constant::Bool(false); -const ZERO : Constant = Constant::Int(0, UnsuffixedIntLit(Plus)); -const ONE : Constant = Constant::Int(1, UnsuffixedIntLit(Plus)); -const TWO : Constant = Constant::Int(2, UnsuffixedIntLit(Plus)); +const ZERO : Constant = Constant::Int(0, LitIntType::Unsuffixed, Sign::Plus); +const ONE : Constant = Constant::Int(1, LitIntType::Unsuffixed, Sign::Plus); +const TWO : Constant = Constant::Int(2, LitIntType::Unsuffixed, Sign::Plus); #[test] fn test_lit() { - check(TRUE, &lit(LitBool(true))); - check(FALSE, &lit(LitBool(false))); - check(ZERO, &lit(LitInt(0, UnsuffixedIntLit(Plus)))); - check(Constant::Str("cool!".into(), CookedStr), &lit(LitStr( - InternedString::new("cool!"), CookedStr))); + check(TRUE, &lit(LitKind::Bool(true))); + check(FALSE, &lit(LitKind::Bool(false))); + check(ZERO, &lit(LitKind::Int(0, LitIntType::Unsuffixed))); + check(Constant::Str("cool!".into(), StrStyle::Cooked), &lit(LitKind::Str( + InternedString::new("cool!"), StrStyle::Cooked))); } #[test] fn test_ops() { - check(TRUE, &binop(BiOr, lit(LitBool(false)), lit(LitBool(true)))); - check(FALSE, &binop(BiAnd, lit(LitBool(false)), lit(LitBool(true)))); + check(TRUE, &binop(BiOr, lit(LitKind::Bool(false)), lit(LitKind::Bool(true)))); + check(FALSE, &binop(BiAnd, lit(LitKind::Bool(false)), lit(LitKind::Bool(true)))); - let litzero = lit(LitInt(0, UnsuffixedIntLit(Plus))); - let litone = lit(LitInt(1, UnsuffixedIntLit(Plus))); + let litzero = lit(LitKind::Int(0, LitIntType::Unsuffixed)); + let litone = lit(LitKind::Int(1, LitIntType::Unsuffixed)); check(TRUE, &binop(BiEq, litzero.clone(), litzero.clone())); check(TRUE, &binop(BiGe, litzero.clone(), litzero.clone())); check(TRUE, &binop(BiLe, litzero.clone(), litzero.clone())); -- cgit 1.4.1-3-g733a5 From 7f567ce1d18a3d4579567fae33bfceaa0b18a9ff Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 01:38:55 +0100 Subject: Fix false negative with OK_EXPECT --- src/methods.rs | 25 +++++-------------------- tests/compile-fail/methods.rs | 4 +--- 2 files changed, 6 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 9263d657371..175e3b5c033 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -274,7 +274,6 @@ declare_lint! { /// println!("{:p} {:p}",*y, z); // prints out the same pointer /// } /// ``` -/// declare_lint! { pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`" } @@ -789,26 +788,12 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { None } -/// This checks whether a given type is known to implement Debug. It's -/// conservative, i.e. it should not return false positives, but will return -/// false negatives. +/// This checks whether a given type is known to implement Debug. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { - let no_ref_ty = walk_ptrs_ty(ty); - let debug = match cx.tcx.lang_items.debug_trait() { - Some(debug) => debug, - None => return false, - }; - let debug_def = cx.tcx.lookup_trait_def(debug); - let mut debug_impl_exists = false; - debug_def.for_each_relevant_impl(cx.tcx, no_ref_ty, |d| { - let self_ty = &cx.tcx.impl_trait_ref(d).and_then(|im| im.substs.self_ty()); - if let Some(self_ty) = *self_ty { - if !self_ty.flags.get().contains(ty::TypeFlags::HAS_PARAMS) { - debug_impl_exists = true; - } - } - }); - debug_impl_exists + match cx.tcx.lang_items.debug_trait() { + Some(debug) => implements_trait(cx, ty, debug, Some(vec![])), + None => false, + } } #[cfg_attr(rustfmt, rustfmt_skip)] diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 4e515c2aa12..043f9e7bcac 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -274,10 +274,8 @@ fn main() { // the error type implements `Debug` let res2: Result<i32, MyError> = Ok(0); res2.ok().expect("oh noes!"); - // we currently don't warn if the error type has a type parameter - // (but it would be nice if we did) let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0); - res3.ok().expect("whoof"); + res3.ok().expect("whoof"); //~ERROR called `ok().expect()` let res4: Result<u32, io::Error> = Ok(0); res4.ok().expect("argh"); //~ERROR called `ok().expect()` let res5: io::Result<u32> = Ok(0); -- cgit 1.4.1-3-g733a5 From edc0d19a3f1f32dc16dc307e30dd2637f5a5fb04 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 01:42:46 +0100 Subject: Add `new` to WRONG_SELF_CONVENTION --- src/methods.rs | 93 +++++++++++++++++++++++++++---------------- tests/compile-fail/methods.rs | 2 + 2 files changed, 61 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 175e3b5c033..3787474e28c 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,11 +1,11 @@ -use rustc_front::hir::*; use rustc::lint::*; -use rustc::middle::ty; use rustc::middle::subst::{Subst, TypeSpace}; -use std::iter; +use rustc::middle::ty; +use rustc_front::hir::*; use std::borrow::Cow; -use syntax::ptr::P; +use std::{fmt, iter}; use syntax::codemap::Span; +use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, match_type, method_chain_args, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, @@ -367,10 +367,11 @@ impl LateLintPass for MethodsPass { } } } + // check conventions w.r.t. conversion method names and predicates let is_copy = is_copy(cx, &ty, &item); - for &(prefix, self_kinds) in &CONVENTIONS { - if name.as_str().starts_with(prefix) && + for &(ref conv, self_kinds) in &CONVENTIONS { + if conv.check(&name.as_str()) && !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { let lint = if item.vis == Visibility::Public { WRONG_PUB_SELF_CONVENTION @@ -380,9 +381,9 @@ impl LateLintPass for MethodsPass { span_lint(cx, lint, sig.explicit_self.span, - &format!("methods called `{}*` usually take {}; consider choosing a less \ + &format!("methods called `{}` usually take {}; consider choosing a less \ ambiguous name", - prefix, + conv, &self_kinds.iter() .map(|k| k.description()) .collect::<Vec<_>>() @@ -796,47 +797,53 @@ fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { } } +enum Convention { + Eq(&'static str), + StartsWith(&'static str), +} + #[cfg_attr(rustfmt, rustfmt_skip)] -const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [ - ("into_", &[SelfKind::Value]), - ("to_", &[SelfKind::Ref]), - ("as_", &[SelfKind::Ref, SelfKind::RefMut]), - ("is_", &[SelfKind::Ref, SelfKind::No]), - ("from_", &[SelfKind::No]), +const CONVENTIONS: [(Convention, &'static [SelfKind]); 6] = [ + (Convention::Eq("new"), &[SelfKind::No]), + (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), + (Convention::StartsWith("from_"), &[SelfKind::No]), + (Convention::StartsWith("into_"), &[SelfKind::Value]), + (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), + (Convention::StartsWith("to_"), &[SelfKind::Ref]), ]; #[cfg_attr(rustfmt, rustfmt_skip)] const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"), - ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), - ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"), - ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"), - ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"), - ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"), - ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"), + ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), + ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"), ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"), - ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"), - ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"), - ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), - ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"), - ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), - ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), - ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), - ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"), ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), - ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), - ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), - ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), + ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"), ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"), - ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), - ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), - ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), + ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), + ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), + ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"), + ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), + ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"), ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"), + ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), + ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"), + ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), + ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), + ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"), + ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"), + ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), + ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"), + ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"), + ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"), + ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"), + ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), ]; #[derive(Clone, Copy)] @@ -881,6 +888,24 @@ impl SelfKind { } } +impl Convention { + fn check(&self, other: &str) -> bool { + match *self { + Convention::Eq(this) => this == other, + Convention::StartsWith(this) => other.starts_with(this), + } + } +} + +impl fmt::Display for Convention { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Convention::Eq(this) => this.fmt(f), + Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), + } + } +} + #[derive(Clone, Copy)] enum OutType { Unit, diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 043f9e7bcac..9a10b336e0e 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -22,6 +22,8 @@ impl T { fn into_u16(&self) -> u16 { 0 } //~ERROR methods called `into_*` usually take self by value fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference + + fn new(self) {} //~ERROR methods called `new` usually take no self } #[derive(Clone,Copy)] -- cgit 1.4.1-3-g733a5 From e8c2aa2997861c745c01c837aa14eec24627f584 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 02:20:22 +0100 Subject: Lint about `new` methods not returning `Self` --- README.md | 3 ++- src/lib.rs | 1 + src/methods.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/methods.rs | 13 ++++++++++++- 4 files changed, 57 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index c2d3b16074c..5a405c6d4ca 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 120 lints included in this crate: +There are 121 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -76,6 +76,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file diff --git a/src/lib.rs b/src/lib.rs index 675dbdd2dd7..8d29d6ab68a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,6 +234,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::CLONE_ON_COPY, methods::EXTEND_FROM_SLICE, methods::FILTER_NEXT, + methods::NEW_RET_NO_SELF, methods::OK_EXPECT, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, diff --git a/src/methods.rs b/src/methods.rs index 3787474e28c..ed3f61e4a72 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -278,6 +278,23 @@ declare_lint! { pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`" } +/// **What it does:** This lint warns about `new` not returning `Self`. +/// +/// **Why is this bad?** As a convention, `new` methods are used to make a new instance of a type. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// impl Foo { +/// fn new(..) -> NotAFoo { +/// } +/// } +/// ``` +declare_lint! { + pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method" +} + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(EXTEND_FROM_SLICE, @@ -294,7 +311,8 @@ impl LintPass for MethodsPass { OR_FUN_CALL, CHARS_NEXT_CMP, CLONE_ON_COPY, - CLONE_DOUBLE_REF) + CLONE_DOUBLE_REF, + NEW_RET_NO_SELF) } } @@ -390,6 +408,29 @@ impl LateLintPass for MethodsPass { .join(" or "))); } } + + if &name.as_str() == &"new" { + let returns_self = if let FunctionRetTy::Return(ref ret_ty) = sig.decl.output { + let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + let ty = ast_ty_to_ty_cache.get(&ty.id); + let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id); + + match (ty, ret_ty) { + (Some(&ty), Some(&ret_ty)) => ret_ty.walk().any(|t| t == ty), + _ => false, + } + } + else { + false + }; + + if !returns_self { + span_lint(cx, + NEW_RET_NO_SELF, + sig.explicit_self.span, + "methods called `new` usually return `Self`"); + } + } } } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 9a10b336e0e..afe056e3d05 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -23,16 +23,27 @@ impl T { fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference - fn new(self) {} //~ERROR methods called `new` usually take no self + fn new(self) {} + //~^ ERROR methods called `new` usually take no self + //~| ERROR methods called `new` usually return `Self` } #[derive(Clone,Copy)] struct U; impl U { + fn new() -> Self { U } fn to_something(self) -> u32 { 0 } // ok because U is Copy } +struct V<T> { + _dummy: T +} + +impl<T> V<T> { + fn new() -> Option<V<T>> { None } +} + impl Mul<T> for T { type Output = T; fn mul(self, other: T) -> T { self } // no error, obviously -- cgit 1.4.1-3-g733a5 From 1efc88f10a182d263baa4f267be756b1fb01492a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 13:17:48 +0100 Subject: Rustup to 1.8.0-nightly (ce4b75f25 2016-02-12) --- src/enum_variants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/enum_variants.rs b/src/enum_variants.rs index c77e42e69c9..1dab2c40891 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -45,7 +45,7 @@ impl EarlyLintPass for EnumVariantNames { if def.variants.len() < 2 { return; } - let first = var2str(&*def.variants[0]); + let first = var2str(&def.variants[0]); let mut pre = first.to_string(); let mut post = pre.clone(); for var in &def.variants[1..] { -- cgit 1.4.1-3-g733a5 From 49e2501c633d519d56352609afda8103dbe8a2e8 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 15:36:57 +0100 Subject: Fix false positive for `ifs_same_cond` and `cfg!` --- src/utils/hir.rs | 5 +++++ tests/compile-fail/copies.rs | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/utils/hir.rs b/src/utils/hir.rs index f8695956f09..e527f63ebbd 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -4,6 +4,7 @@ use rustc_front::hir::*; use std::hash::{Hash, Hasher, SipHasher}; use syntax::ast::Name; use syntax::ptr::P; +use utils::differing_macro_contexts; /// Type used to check whether two ast are the same. This is different from the operator /// `==` on ast types as this operator would compare true equality with ID and span. @@ -53,6 +54,10 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { // ok, it’s a big function, but mostly one big match with simples cases #[allow(cyclomatic_complexity)] pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { + if self.ignore_fn && differing_macro_contexts(left.span, right.span) { + return false; + } + if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) { if l == r { return true; diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 623f9967bd4..7a17b345fa8 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -12,7 +12,7 @@ fn foo() -> bool { unimplemented!() } #[deny(if_same_then_else)] #[deny(match_same_arms)] -fn if_same_then_else() -> &'static str { +fn if_same_then_else() -> Result<&'static str, ()> { if true { foo(); } @@ -129,17 +129,24 @@ fn if_same_then_else() -> &'static str { _ => (), } + if true { + try!(Ok("foo")); + } + else { //~ERROR this `if` has identical blocks + try!(Ok("foo")); + } + if true { let foo = ""; - return &foo[0..]; + return Ok(&foo[0..]); } else if false { let foo = "bar"; - return &foo[0..]; + return Ok(&foo[0..]); } else { //~ERROR this `if` has identical blocks let foo = ""; - return &foo[0..]; + return Ok(&foo[0..]); } } @@ -168,6 +175,15 @@ fn ifs_same_cond() { else if a == 1 { } + // See #659 + if cfg!(feature = "feature1-659") { + 1 + } else if cfg!(feature = "feature2-659") { + 2 + } else { + 3 + }; + let mut v = vec![1]; if v.pop() == None { // ok, functions } -- cgit 1.4.1-3-g733a5 From d589a2d516a4b35af22dee60f9e7ae57622cea00 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 22:08:15 +0100 Subject: Fix comment --- src/copies.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index e2defe8f364..b975aefe125 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -48,6 +48,7 @@ declare_lint! { /// Bar => bar(), /// Quz => quz(), /// Baz => bar(), // <= oups +/// } /// ``` declare_lint! { pub MATCH_SAME_ARMS, -- cgit 1.4.1-3-g733a5 From 4562040d6b640fa448fedcb7db9124b6abcaba5b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 13 Feb 2016 22:09:17 +0100 Subject: Fix false positive in `NEEDLESS_RANGE_LOOP` --- src/loops.rs | 23 ++++++++++++++++++----- tests/compile-fail/for_loop.rs | 6 ++++++ 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index cecf47daf55..bbbff676350 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -4,6 +4,7 @@ use rustc::lint::*; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; use rustc::middle::def::Def; +use rustc::middle::region::CodeExtent; use rustc::middle::ty; use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; @@ -338,20 +339,28 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex if let ExprRange(Some(ref l), ref r) = arg.node { // the var must be a single name if let PatIdent(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { cx: cx, var: ident.node.name, - indexed: HashSet::new(), + indexed: HashMap::new(), nonindex: false, }; walk_expr(&mut visitor, body); + // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let indexed = visitor.indexed + let (indexed, indexed_extent) = visitor.indexed .into_iter() .next() .expect("Len was nonzero, but no contents found"); + // ensure that the indexed variable was declared before the loop, see #601 + let pat_extent = cx.tcx.region_maps.var_scope(pat.id); + if cx.tcx.region_maps.is_subscope_of(indexed_extent, pat_extent) { + return; + } + let starts_at_zero = is_integer_literal(l, 0); let skip: Cow<_> = if starts_at_zero { @@ -673,7 +682,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference var: Name, // var name to look for as index - indexed: HashSet<Name>, // indexed variables + indexed: HashMap<Name, CodeExtent>, // indexed variables nonindex: bool, // has the var been used otherwise? } @@ -689,8 +698,12 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { let ExprPath(None, ref seqvar) = seqexpr.node, seqvar.segments.len() == 1 ], { - self.indexed.insert(seqvar.segments[0].identifier.name); - return; // no need to walk further + let def_map = self.cx.tcx.def_map.borrow(); + if let Some(def) = def_map.get(&seqexpr.id) { + let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); + self.indexed.insert(seqvar.segments[0].identifier.name, extent); + return; // no need to walk further + } } } // we are not indexing anything, record that diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 4609c840836..b805963a03a 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -192,6 +192,12 @@ fn main() { println!("{}", i); } + // See #601 + for i in 0..10 { // no error, id_col does not exist outside the loop + let mut id_col = vec![0f64; 10]; + id_col[i] = 1f64; + } + /* for i in (10..0).map(|x| x * 2) { println!("{}", i); -- cgit 1.4.1-3-g733a5 From cbe2de7fd273d25e6fc37abb4094a3ecfabbe359 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 14 Feb 2016 12:07:56 +0100 Subject: Address small nit --- src/loops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index bbbff676350..2754f743caa 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -9,7 +9,7 @@ use rustc::middle::ty; use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; -use std::collections::{HashSet, HashMap}; +use std::collections::HashMap; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty}; @@ -353,7 +353,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex let (indexed, indexed_extent) = visitor.indexed .into_iter() .next() - .expect("Len was nonzero, but no contents found"); + .unwrap_or_else(|| unreachable!() /* len == 1 */); // ensure that the indexed variable was declared before the loop, see #601 let pat_extent = cx.tcx.region_maps.var_scope(pat.id); -- cgit 1.4.1-3-g733a5 From 30a8dfb31ae401a104bfbb870a528225b4d6b2e0 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 14 Feb 2016 16:55:02 +0100 Subject: remove Visitor from regex_macro --- src/lib.rs | 2 +- src/regex.rs | 66 +++++++++++++++++++++++++++++------------------------------- 2 files changed, 33 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8d29d6ab68a..cb3d3d5392b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,7 +158,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box vec::UselessVec); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); - reg.register_late_lint_pass(box regex::RegexPass); + reg.register_late_lint_pass(box regex::RegexPass::default()); reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_lint_group("clippy_pedantic", vec![ diff --git a/src/regex.rs b/src/regex.rs index 5103391e9dd..25c7260abec 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,11 +1,10 @@ use regex_syntax; use std::error::Error; use std::collections::HashSet; -use syntax::ast::LitKind; +use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_block}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; @@ -52,8 +51,11 @@ declare_lint! { "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" } -#[derive(Copy,Clone)] -pub struct RegexPass; +#[derive(Clone, Default)] +pub struct RegexPass { + spans: HashSet<Span>, + last: Option<NodeId> +} impl LintPass for RegexPass { fn get_lints(&self) -> LintArray { @@ -62,11 +64,34 @@ impl LintPass for RegexPass { } impl LateLintPass for RegexPass { - fn check_crate(&mut self, cx: &LateContext, krate: &Crate) { - let mut visitor = RegexVisitor { cx: cx, spans: HashSet::new() }; - krate.visit_all_items(&mut visitor); + fn check_crate(&mut self, _: &LateContext, _: &Crate) { + self.spans.clear(); } + fn check_block(&mut self, cx: &LateContext, block: &Block) { + if_let_chain!{[ + self.last.is_none(), + let Some(ref expr) = block.expr, + match_type(cx, cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), + let Some(span) = is_expn_of(cx, expr.span, "regex") + ], { + if !self.spans.contains(&span) { + span_lint(cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now."); + self.spans.insert(span); + } + self.last = Some(block.id); + }} + } + + fn check_block_post(&mut self, _: &LateContext, block: &Block) { + if self.last.map_or(false, |id| block.id == id) { + self.last = None; + } + } fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain!{[ @@ -160,30 +185,3 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { _ => None, } } - -struct RegexVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, - spans: HashSet<Span>, -} - -impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { - fn visit_block(&mut self, block: &'v Block) { - if_let_chain!{[ - let Some(ref expr) = block.expr, - match_type(self.cx, self.cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), - let Some(span) = is_expn_of(self.cx, expr.span, "regex") - ], { - if self.spans.contains(&span) { - return; - } - span_lint(self.cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); - self.spans.insert(span); - return; - }} - walk_block(self, block); - } -} -- cgit 1.4.1-3-g733a5 From 1b93d716459346eb0c6de654c5771d95ecf6aaa4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 14 Feb 2016 20:29:32 +0100 Subject: Fix ICE in `EXPL_IMPL_CLONE_ON_COPY` --- src/derive.rs | 20 +++++++++++--------- tests/ice-666.rs | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 tests/ice-666.rs (limited to 'src') diff --git a/src/derive.rs b/src/derive.rs index e9eef824713..467d55feafd 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,4 +1,5 @@ use rustc::lint::*; +use rustc::middle::ty::TypeVariants; use rustc::middle::ty::fast_reject::simplify_type; use rustc::middle::ty; use rustc_front::hir::*; @@ -6,7 +7,6 @@ use syntax::ast::{Attribute, MetaItemKind}; use syntax::codemap::Span; use utils::{CLONE_TRAIT_PATH, HASH_PATH}; use utils::{match_path, span_lint_and_then}; -use rustc::middle::ty::TypeVariants; /// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` /// explicitly. @@ -73,14 +73,14 @@ impl LateLintPass for Derive { let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); if_let_chain! {[ - let ItemImpl(_, _, _, Some(ref trait_ref), ref ast_ty, _) = item.node, + let ItemImpl(_, _, ref ast_generics, Some(ref trait_ref), ref ast_ty, _) = item.node, let Some(&ty) = ast_ty_to_ty_cache.get(&ast_ty.id) ], { if item.attrs.iter().any(is_automatically_derived) { check_hash_peq(cx, item.span, trait_ref, ty); } - else { - check_copy_clone(cx, item.span, trait_ref, ty); + else if !ast_generics.is_lt_parameterized() { + check_copy_clone(cx, item, trait_ref, ty); } }} } @@ -127,11 +127,13 @@ fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty } /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. -fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { +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, &CLONE_TRAIT_PATH) { - let parameter_environment = cx.tcx.empty_parameter_environment(); + let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - if ty.moves_by_default(¶meter_environment, span) { + if ty.moves_by_default(¶meter_environment, item.span) { return; // ty is not Copy } @@ -160,10 +162,10 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: span_lint_and_then(cx, DERIVE_HASH_NOT_EQ, - span, + item.span, "you are implementing `Clone` explicitly on a `Copy` type", |db| { - db.span_note(span, "consider deriving `Clone` or removing `Copy`"); + db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); }); } } diff --git a/tests/ice-666.rs b/tests/ice-666.rs new file mode 100644 index 00000000000..b681f4b2c58 --- /dev/null +++ b/tests/ice-666.rs @@ -0,0 +1,24 @@ +#![feature(plugin)] +#![plugin(clippy)] + +pub struct Lt<'a> { + _foo: &'a u8, +} + +impl<'a> Copy for Lt<'a> {} +impl<'a> Clone for Lt<'a> { + fn clone(&self) -> Lt<'a> { + unimplemented!(); + } +} + +pub struct Ty<A> { + _foo: A, +} + +impl<A: Copy> Copy for Ty<A> {} +impl<A> Clone for Ty<A> { + fn clone(&self) -> Ty<A> { + unimplemented!(); + } +} -- cgit 1.4.1-3-g733a5 From 7eea67605a92864530600bde3776c80ce08e790e Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Sun, 14 Feb 2016 22:40:43 -0500 Subject: Lint single-character strings as P: Pattern args Fixes #650 --- README.md | 3 +- src/lib.rs | 1 + src/methods.rs | 62 ++++++++++++++++++++++++++++- src/misc_early.rs | 2 +- tests/compile-fail/methods.rs | 91 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 155 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 483182a68f6..ae5b42e45b3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 121 lints included in this crate: +There are 122 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -104,6 +104,7 @@ name [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` [shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value [should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")` [single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead [single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead [str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` diff --git a/src/lib.rs b/src/lib.rs index 8d29d6ab68a..7233eab2921 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OR_FUN_CALL, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, + methods::SINGLE_CHAR_PATTERN, methods::STR_TO_STRING, methods::STRING_TO_STRING, methods::WRONG_SELF_CONVENTION, diff --git a/src/methods.rs b/src/methods.rs index ed3f61e4a72..c8c3160ccaa 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,4 +1,6 @@ use rustc::lint::*; +use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::subst::{Subst, TypeSpace}; use rustc::middle::ty; use rustc_front::hir::*; @@ -295,6 +297,20 @@ declare_lint! { pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method" } +/// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")` +/// +/// **Why is this bad?** Performing these methods using a `str` may be slower than using a `char` +/// +/// **Known problems:** Does not catch multi-byte unicode characters +/// +/// **Example:** `_.split("x")` could be `_.split('x')` +declare_lint! { + pub SINGLE_CHAR_PATTERN, + Warn, + "using a single-character str where a char could be used, e.g. \ + `_.split(\"x\")`" +} + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(EXTEND_FROM_SLICE, @@ -312,7 +328,8 @@ impl LintPass for MethodsPass { CHARS_NEXT_CMP, CLONE_ON_COPY, CLONE_DOUBLE_REF, - NEW_RET_NO_SELF) + NEW_RET_NO_SELF, + SINGLE_CHAR_PATTERN) } } @@ -351,6 +368,11 @@ impl LateLintPass for MethodsPass { lint_clone_on_copy(cx, expr); lint_clone_double_ref(cx, expr, &args[0]); } + for &(method, pos) in &PATTERN_METHODS { + if name.node.as_str() == method && args.len() > pos { + lint_single_char_pattern(cx, expr, &args[pos]); + } + } } ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { if !lint_chars_next(cx, expr, lhs, rhs, op.node == BiEq) { @@ -817,6 +839,22 @@ fn lint_chars_next(cx: &LateContext, expr: &Expr, chain: &Expr, other: &Expr, eq false } +/// lint for length-1 `str`s for methods in `PATTERN_METHODS` +fn lint_single_char_pattern(cx: &LateContext, expr: &Expr, arg: &Expr) { + if let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, arg, ExprTypeChecked, None) { + if r.len() == 1 { + let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); + span_lint_and_then(cx, + SINGLE_CHAR_PATTERN, + expr.span, + "single-character string constant used as pattern", + |db| { + db.span_suggestion(expr.span, "try using a char instead:", hint); + }); + } + } +} + /// Given a `Result<T, E>` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { if !match_type(cx, ty, &RESULT_PATH) { @@ -887,6 +925,28 @@ const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30 ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), ]; +#[cfg_attr(rustfmt, rustfmt_skip)] +const PATTERN_METHODS: [(&'static str, usize); 17] = [ + ("contains", 1), + ("starts_with", 1), + ("ends_with", 1), + ("find", 1), + ("rfind", 1), + ("split", 1), + ("rsplit", 1), + ("split_terminator", 1), + ("rsplit_terminator", 1), + ("splitn", 2), + ("rsplitn", 2), + ("matches", 1), + ("rmatches", 1), + ("match_indices", 1), + ("rmatch_indices", 1), + ("trim_left_matches", 1), + ("trim_right_matches", 1), +]; + + #[derive(Clone, Copy)] enum SelfKind { Value, diff --git a/src/misc_early.rs b/src/misc_early.rs index 59a0102aacf..1999d911804 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -104,7 +104,7 @@ impl EarlyLintPass for MiscEarly { if let PatIdent(_, sp_ident, None) = arg.pat.node { let arg_name = sp_ident.node.to_string(); - if arg_name.starts_with("_") { + if arg_name.starts_with('_') { if let Some(correspondance) = registered_names.get(&arg_name[1..]) { span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index afe056e3d05..06dd161ba9e 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(unused, print_stdout)] +#![allow(unused, print_stdout, non_ascii_literal)] use std::collections::BTreeMap; use std::collections::HashMap; @@ -355,3 +355,92 @@ fn clone_on_double_ref() { //~^^^ERROR using `clone` on a `Copy` type println!("{:p} {:p}",*y, z); } + +fn single_char_pattern() { + let x = "foo"; + x.split("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.split('x'); + + x.split("xx"); + + x.split('x'); + + let y = "x"; + x.split(y); + + // Not yet testing for multi-byte characters + // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_single_char_pattern` + // should have done this but produced an ICE + x.split("ß"); + x.split("ℝ"); + x.split("💣"); + // Can't use this lint for unicode code points which don't fit in a char + x.split("❤️"); + + x.contains("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.contains('x'); + x.starts_with("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.starts_with('x'); + x.ends_with("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.ends_with('x'); + x.find("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.find('x'); + x.rfind("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rfind('x'); + x.rsplit("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rsplit('x'); + x.split_terminator("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.split_terminator('x'); + x.rsplit_terminator("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rsplit_terminator('x'); + x.splitn(0, "x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.splitn(0, 'x'); + x.rsplitn(0, "x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rsplitn(0, 'x'); + x.matches("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.matches('x'); + x.rmatches("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rmatches('x'); + x.match_indices("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.match_indices('x'); + x.rmatch_indices("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.rmatch_indices('x'); + x.trim_left_matches("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.trim_left_matches('x'); + x.trim_right_matches("x"); + //~^ ERROR single-character string constant used as pattern + //~| HELP try using a char instead: + //~| SUGGESTION x.trim_right_matches('x'); +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 1ca59031389ef3ebd029faf889c5eaae2a169438 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 15 Feb 2016 10:20:26 +0530 Subject: Make derive lint handle generics correctly --- src/derive.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/derive.rs b/src/derive.rs index 467d55feafd..7cb85b8c97b 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,4 +1,5 @@ use rustc::lint::*; +use rustc::middle::subst::Subst; use rustc::middle::ty::TypeVariants; use rustc::middle::ty::fast_reject::simplify_type; use rustc::middle::ty; @@ -70,16 +71,17 @@ impl LintPass for Derive { impl LateLintPass for Derive { fn check_item(&mut self, cx: &LateContext, item: &Item) { - let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + if_let_chain! {[ - let ItemImpl(_, _, ref ast_generics, Some(ref trait_ref), ref ast_ty, _) = item.node, - let Some(&ty) = ast_ty_to_ty_cache.get(&ast_ty.id) + let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node ], { + + let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; if item.attrs.iter().any(is_automatically_derived) { check_hash_peq(cx, item.span, trait_ref, ty); } - else if !ast_generics.is_lt_parameterized() { + else { check_copy_clone(cx, item, trait_ref, ty); } }} @@ -132,8 +134,9 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) { let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); + let subst_ty = ty.subst(cx.tcx, ¶meter_environment.free_substs); - if ty.moves_by_default(¶meter_environment, item.span) { + if subst_ty.moves_by_default(¶meter_environment, item.span) { return; // ty is not Copy } -- cgit 1.4.1-3-g733a5 From d755b1ebe2204b93c8ab82c6c04699a9e20921f5 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 15 Feb 2016 13:25:29 +0100 Subject: Cleanup --- src/derive.rs | 3 --- tests/compile-fail/derive.rs | 11 +++++++++++ tests/ice-666.rs | 24 ------------------------ 3 files changed, 11 insertions(+), 27 deletions(-) delete mode 100644 tests/ice-666.rs (limited to 'src') diff --git a/src/derive.rs b/src/derive.rs index 7cb85b8c97b..7110cf71424 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -71,12 +71,9 @@ impl LintPass for Derive { impl LateLintPass for Derive { fn check_item(&mut self, cx: &LateContext, item: &Item) { - - if_let_chain! {[ let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node ], { - let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; if item.attrs.iter().any(is_automatically_derived) { check_hash_peq(cx, item.span, trait_ref, ty); diff --git a/tests/compile-fail/derive.rs b/tests/compile-fail/derive.rs index 66b04a66d0f..14b1106add5 100755 --- a/tests/compile-fail/derive.rs +++ b/tests/compile-fail/derive.rs @@ -35,6 +35,17 @@ impl Clone for Qux { fn clone(&self) -> Self { Qux } } +// See #666 +#[derive(Copy)] +struct Lt<'a> { + a: &'a u8, +} + +impl<'a> Clone for Lt<'a> { +//~^ ERROR you are implementing `Clone` explicitly on a `Copy` type + fn clone(&self) -> Self { unimplemented!() } +} + // Ok, `Clone` cannot be derived because of the big array #[derive(Copy)] struct BigArray { diff --git a/tests/ice-666.rs b/tests/ice-666.rs deleted file mode 100644 index b681f4b2c58..00000000000 --- a/tests/ice-666.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -pub struct Lt<'a> { - _foo: &'a u8, -} - -impl<'a> Copy for Lt<'a> {} -impl<'a> Clone for Lt<'a> { - fn clone(&self) -> Lt<'a> { - unimplemented!(); - } -} - -pub struct Ty<A> { - _foo: A, -} - -impl<A: Copy> Copy for Ty<A> {} -impl<A> Clone for Ty<A> { - fn clone(&self) -> Ty<A> { - unimplemented!(); - } -} -- cgit 1.4.1-3-g733a5 From 570b9635354c8d41711f464bcaeb6a7128d1cc2a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 15 Feb 2016 13:44:59 +0100 Subject: Replace potentially ICEgen ast_ty_to_ty_cache --- src/methods.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index ed3f61e4a72..b71d2ffd7a2 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -366,7 +366,7 @@ impl LateLintPass for MethodsPass { return; } - if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node { + if let ItemImpl(_, _, _, None, _, ref items) = item.node { for implitem in items { let name = implitem.name; if let ImplItemKind::Method(ref sig, _) = implitem.node { @@ -387,6 +387,7 @@ impl LateLintPass for MethodsPass { } // check conventions w.r.t. conversion method names and predicates + let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; let is_copy = is_copy(cx, &ty, &item); for &(ref conv, self_kinds) in &CONVENTIONS { if conv.check(&name.as_str()) && @@ -412,12 +413,13 @@ impl LateLintPass for MethodsPass { if &name.as_str() == &"new" { let returns_self = if let FunctionRetTy::Return(ref ret_ty) = sig.decl.output { let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); - let ty = ast_ty_to_ty_cache.get(&ty.id); let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id); - match (ty, ret_ty) { - (Some(&ty), Some(&ret_ty)) => ret_ty.walk().any(|t| t == ty), - _ => false, + if let Some(&ret_ty) = ret_ty { + ret_ty.walk().any(|t| t == ty) + } + else { + false } } else { @@ -983,12 +985,7 @@ fn is_bool(ty: &Ty) -> bool { false } -fn is_copy(cx: &LateContext, ast_ty: &Ty, item: &Item) -> bool { - match cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { - None => false, - Some(ty) => { - let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - !ty.subst(cx.tcx, &env.free_substs).moves_by_default(&env, ast_ty.span) - } - } +fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &Item) -> bool { + let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); + !ty.subst(cx.tcx, &env.free_substs).moves_by_default(&env, item.span) } -- cgit 1.4.1-3-g733a5 From 643a223f7123ee832d67732370faffb023ab3ed9 Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Mon, 15 Feb 2016 09:10:31 -0500 Subject: Address nits --- src/methods.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index c8c3160ccaa..f1aaaf633dd 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -297,11 +297,11 @@ declare_lint! { pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method" } -/// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")` +/// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")`. /// -/// **Why is this bad?** Performing these methods using a `str` may be slower than using a `char` +/// **Why is this bad?** Performing these methods using a `str` may be slower than using a `char`. /// -/// **Known problems:** Does not catch multi-byte unicode characters +/// **Known problems:** Does not catch multi-byte unicode characters. /// /// **Example:** `_.split("x")` could be `_.split('x')` declare_lint! { @@ -846,7 +846,7 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &Expr, arg: &Expr) { let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); span_lint_and_then(cx, SINGLE_CHAR_PATTERN, - expr.span, + arg.span, "single-character string constant used as pattern", |db| { db.span_suggestion(expr.span, "try using a char instead:", hint); -- cgit 1.4.1-3-g733a5 From c22ded11e57ece41455e18e11eba8f64606c8860 Mon Sep 17 00:00:00 2001 From: Joshua Holmer <holmerj@uindy.edu> Date: Mon, 15 Feb 2016 10:32:04 -0500 Subject: Reword lint documentation char is faster, proven by benchmark. --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index f1aaaf633dd..c8d5fa08ff1 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -299,7 +299,7 @@ declare_lint! { /// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")`. /// -/// **Why is this bad?** Performing these methods using a `str` may be slower than using a `char`. +/// **Why is this bad?** Performing these methods using a `char` is faster than using a `str`. /// /// **Known problems:** Does not catch multi-byte unicode characters. /// -- cgit 1.4.1-3-g733a5 From 00b27bf7becf26f3be918f2558e56f617fd716ec Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 15 Feb 2016 17:43:16 +0100 Subject: Fix suggestion in `COLLAPSIBLE_IF` lint --- src/collapsible_if.rs | 4 +--- tests/compile-fail/collapsible_if.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 03c43ef5dc8..e5ad94fc639 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -66,9 +66,7 @@ fn check_if(cx: &LateContext, e: &Expr) { COLLAPSIBLE_IF, block.span, "this `else { if .. }` block can be collapsed", |db| { - db.span_suggestion(block.span, "try", - format!("else {}", - snippet_block(cx, else_.span, ".."))); + db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned()); }); }} } else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = diff --git a/tests/compile-fail/collapsible_if.rs b/tests/compile-fail/collapsible_if.rs index 85eac28dc38..3bf4128347a 100644 --- a/tests/compile-fail/collapsible_if.rs +++ b/tests/compile-fail/collapsible_if.rs @@ -22,7 +22,7 @@ fn main() { print!("Hello "); } else { //~ERROR: this `else { if .. }` //~| HELP try - //~| SUGGESTION else if y == "world" + //~| SUGGESTION } else if y == "world" if y == "world" { println!("world!") } @@ -32,7 +32,7 @@ fn main() { print!("Hello "); } else { //~ERROR this `else { if .. }` //~| HELP try - //~| SUGGESTION else if y == "world" + //~| SUGGESTION } else if y == "world" if y == "world" { println!("world") } -- cgit 1.4.1-3-g733a5 From cd35b9e38d3520b59eb5ef219cec0f17f7d12f91 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 15 Feb 2016 22:26:20 +0100 Subject: Fix wrong reported lint for EXPL_IMPL_CLONE_ON_COPY --- src/derive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/derive.rs b/src/derive.rs index 467d55feafd..30ef2be9384 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -16,7 +16,7 @@ use utils::{match_path, span_lint_and_then}; /// an explicitely defined `PartialEq`. In particular, the following must hold for any type: /// /// ```rust -/// k1 == k2 -> hash(k1) == hash(k2) +/// k1 == k2 ⇒ hash(k1) == hash(k2) /// ``` /// /// **Known problems:** None. @@ -161,7 +161,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, } span_lint_and_then(cx, - DERIVE_HASH_NOT_EQ, + EXPL_IMPL_CLONE_ON_COPY, item.span, "you are implementing `Clone` explicitly on a `Copy` type", |db| { -- cgit 1.4.1-3-g733a5 From b5ba621f61a07193d3f7b0e7bd04204cc0dec4b4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 15 Feb 2016 23:38:09 +0100 Subject: Make DERIVE_HASH_NOT_EQ symmetric --- README.md | 2 +- src/derive.rs | 43 ++++++++++++++++++++++++++++++------------- src/lib.rs | 2 +- tests/compile-fail/derive.rs | 10 ++++++++++ 4 files changed, 42 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 483182a68f6..05737f142fa 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ name [collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to `else if` [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver -[derive_hash_not_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_not_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly +[derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected diff --git a/src/derive.rs b/src/derive.rs index e8816731219..084d00d409f 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -32,7 +32,7 @@ use utils::{match_path, span_lint_and_then}; /// } /// ``` declare_lint! { - pub DERIVE_HASH_NOT_EQ, + pub DERIVE_HASH_XOR_EQ, Warn, "deriving `Hash` but implementing `PartialEq` explicitly" } @@ -65,7 +65,7 @@ pub struct Derive; impl LintPass for Derive { fn get_lints(&self) -> LintArray { - lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_NOT_EQ) + lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ) } } @@ -75,19 +75,25 @@ impl LateLintPass for Derive { let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node ], { let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; - if item.attrs.iter().any(is_automatically_derived) { - check_hash_peq(cx, item.span, trait_ref, ty); - } - else { + let is_automatically_derived = item.attrs.iter().any(is_automatically_derived); + + check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); + + if !is_automatically_derived { check_copy_clone(cx, item, trait_ref, ty); } }} } } -/// Implementation of the `DERIVE_HASH_NOT_EQ` lint. -fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty) { - // If `item` is an automatically derived `Hash` implementation +/// Implementation of the `DERIVE_HASH_XOR_EQ` lint. +fn check_hash_peq( + cx: &LateContext, + span: Span, + trait_ref: &TraitRef, + ty: ty::Ty, + hash_is_automatically_derived: bool +) { if_let_chain! {[ match_path(&trait_ref.path, &HASH_PATH), let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() @@ -103,14 +109,25 @@ fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty let Some(impl_ids) = peq_impls.get(&simpl_ty) ], { for &impl_id in impl_ids { + let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); + + if peq_is_automatically_derived == hash_is_automatically_derived { + return; + } + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); // Only care about `impl PartialEq<Foo> for Foo` - if trait_ref.input_types()[0] == ty && - !cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived) { + if trait_ref.input_types()[0] == ty { + let mess = if peq_is_automatically_derived { + "you are implementing `Hash` explicitly but have derived `PartialEq`" + } else { + "you are deriving `Hash` but have implemented `PartialEq` explicitly" + }; + span_lint_and_then( - cx, DERIVE_HASH_NOT_EQ, span, - "you are deriving `Hash` but have implemented `PartialEq` explicitly", + cx, DERIVE_HASH_XOR_EQ, span, + mess, |db| { if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { db.span_note( diff --git a/src/lib.rs b/src/lib.rs index 8d29d6ab68a..bd13190f859 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,7 +198,7 @@ pub fn plugin_registrar(reg: &mut Registry) { copies::IFS_SAME_COND, copies::MATCH_SAME_ARMS, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, - derive::DERIVE_HASH_NOT_EQ, + derive::DERIVE_HASH_XOR_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, drop_ref::DROP_REF, entry::MAP_ENTRY, diff --git a/tests/compile-fail/derive.rs b/tests/compile-fail/derive.rs index 14b1106add5..06f1388dc05 100755 --- a/tests/compile-fail/derive.rs +++ b/tests/compile-fail/derive.rs @@ -4,6 +4,8 @@ #![deny(warnings)] #![allow(dead_code)] +use std::hash::{Hash, Hasher}; + #[derive(PartialEq, Hash)] struct Foo; @@ -27,6 +29,14 @@ impl PartialEq<Baz> for Baz { fn eq(&self, _: &Baz) -> bool { true } } +#[derive(PartialEq)] +struct Bah; + +impl Hash for Bah { +//~^ ERROR you are implementing `Hash` explicitly but have derived `PartialEq` + fn hash<H: Hasher>(&self, _: &mut H) {} +} + #[derive(Copy)] struct Qux; -- cgit 1.4.1-3-g733a5 From e809eb61d7b150dac9b9810b4d62f31b11db15d1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 15 Feb 2016 16:59:56 +0100 Subject: fix enum_variant_names linting on all caps enum variants --- src/enum_variants.rs | 70 ++++++++++++++++++++++-------------- src/utils/mod.rs | 62 ++++++++++++++++++++++++++++++++ tests/camel_case.rs | 51 ++++++++++++++++++++++++++ tests/compile-fail/enum_variants.rs | 71 +++++++++++++++++++++++++++++++++++++ 4 files changed, 227 insertions(+), 27 deletions(-) create mode 100644 tests/camel_case.rs create mode 100644 tests/compile-fail/enum_variants.rs (limited to 'src') diff --git a/src/enum_variants.rs b/src/enum_variants.rs index 1dab2c40891..8ad7adf0077 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -6,6 +6,7 @@ use syntax::ast::*; use syntax::parse::token::InternedString; use utils::span_help_and_lint; +use utils::{camel_case_from, camel_case_until}; /// **What it does:** Warns on enum variants that are prefixed or suffixed by the same characters /// @@ -31,48 +32,63 @@ fn var2str(var: &Variant) -> InternedString { var.node.name.name.as_str() } -fn partial_match(left: &str, right: &str) -> usize { - left.chars().zip(right.chars()).take_while(|&(l, r)| l == r).count() +/* +FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 +fn partial_match(pre: &str, name: &str) -> usize { + // skip(1) to ensure that the prefix never takes the whole variant name + pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() } -fn partial_rmatch(left: &str, right: &str) -> usize { - left.chars().rev().zip(right.chars().rev()).take_while(|&(l, r)| l == r).count() +fn partial_rmatch(post: &str, name: &str) -> usize { + // skip(1) to ensure that the postfix never takes the whole variant name + post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() +}*/ + +fn partial_match(pre: &str, name: &str) -> usize { + let mut name_iter = name.chars(); + let _ = name_iter.next_back(); // make sure the name is never fully matched + pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() +} + +fn partial_rmatch(post: &str, name: &str) -> usize { + let mut name_iter = name.chars(); + let _ = name_iter.next(); // make sure the name is never fully matched + post.chars().rev().zip(name_iter.rev()).take_while(|&(l, r)| l == r).count() } impl EarlyLintPass for EnumVariantNames { + // FIXME: #600 + #[allow(while_let_on_iterator)] fn check_item(&mut self, cx: &EarlyContext, item: &Item) { if let ItemKind::Enum(ref def, _) = item.node { if def.variants.len() < 2 { return; } let first = var2str(&def.variants[0]); - let mut pre = first.to_string(); - let mut post = pre.clone(); - for var in &def.variants[1..] { + let mut pre = &first[..camel_case_until(&*first)]; + let mut post = &first[camel_case_from(&*first)..]; + for var in &def.variants { let name = var2str(var); + let pre_match = partial_match(&pre, &name); - let post_match = partial_rmatch(&post, &name); - pre.truncate(pre_match); - let post_end = post.len() - post_match; - post.drain(..post_end); - } - if let Some(c) = first[pre.len()..].chars().next() { - if !c.is_uppercase() { - // non camel case prefix - pre.clear() - } - } - if let Some(c) = first[..(first.len() - post.len())].chars().rev().next() { - if let Some(c1) = post.chars().next() { - if !c.is_lowercase() || !c1.is_uppercase() { - // non camel case postfix - post.clear() + pre = &pre[..pre_match]; + let pre_camel = camel_case_until(&pre); + pre = &pre[..pre_camel]; + while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { + if next.is_lowercase() { + let last = pre.len() - last.len_utf8(); + let last_camel = camel_case_until(&pre[..last]); + pre = &pre[..last_camel]; + } else { + break; } } - } - if pre == "_" { - // don't lint on underscores which are meant to allow dead code - pre.clear(); + + let post_match = partial_rmatch(&post, &name); + let post_end = post.len() - post_match; + post = &post[post_end..]; + let post_camel = camel_case_from(&post); + post = &post[post_camel..]; } let (what, value) = if !pre.is_empty() { ("pre", pre) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 9fd52ff0e98..3a7c6c90d51 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -607,3 +607,65 @@ pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> } } } + +/// Returns index of character after first CamelCase component of `s` +pub fn camel_case_until(s: &str) -> usize { + let mut iter = s.char_indices(); + if let Some((_, first)) = iter.next() { + if !first.is_uppercase() { + return 0; + } + } else { + return 0; + } + let mut up = true; + let mut last_i = 0; + for (i, c) in iter { + if up { + if c.is_lowercase() { + up = false; + } else { + return last_i; + } + } else if c.is_uppercase() { + up = true; + last_i = i; + } else if !c.is_lowercase() { + return i; + } + } + if up { + last_i + } else { + s.len() + } +} + +/// Returns index of last CamelCase component of `s`. +pub fn camel_case_from(s: &str) -> usize { + let mut iter = s.char_indices().rev(); + if let Some((_, first)) = iter.next() { + if !first.is_lowercase() { + return s.len(); + } + } else { + return s.len(); + } + let mut down = true; + let mut last_i = s.len(); + for (i, c) in iter { + if down { + if c.is_uppercase() { + down = false; + last_i = i; + } else if !c.is_lowercase() { + return last_i; + } + } else if c.is_lowercase() { + down = true; + } else { + return last_i; + } + } + last_i +} diff --git a/tests/camel_case.rs b/tests/camel_case.rs new file mode 100644 index 00000000000..201b796af1c --- /dev/null +++ b/tests/camel_case.rs @@ -0,0 +1,51 @@ +#[allow(plugin_as_library)] +extern crate clippy; + +use clippy::utils::{camel_case_from, camel_case_until}; + +#[test] +fn from_full() { + assert_eq!(camel_case_from("AbcDef"), 0); + assert_eq!(camel_case_from("Abc"), 0); +} + +#[test] +fn from_partial() { + assert_eq!(camel_case_from("abcDef"), 3); + assert_eq!(camel_case_from("aDbc"), 1); +} + +#[test] +fn from_not() { + assert_eq!(camel_case_from("AbcDef_"), 7); + assert_eq!(camel_case_from("AbcDD"), 5); +} + +#[test] +fn from_caps() { + assert_eq!(camel_case_from("ABCD"), 4); +} + +#[test] +fn until_full() { + assert_eq!(camel_case_until("AbcDef"), 6); + assert_eq!(camel_case_until("Abc"), 3); +} + +#[test] +fn until_not() { + assert_eq!(camel_case_until("abcDef"), 0); + assert_eq!(camel_case_until("aDbc"), 0); +} + +#[test] +fn until_partial() { + assert_eq!(camel_case_until("AbcDef_"), 6); + assert_eq!(camel_case_until("CallTypeC"), 8); + assert_eq!(camel_case_until("AbcDD"), 3); +} + +#[test] +fn until_caps() { + assert_eq!(camel_case_until("ABCD"), 0); +} diff --git a/tests/compile-fail/enum_variants.rs b/tests/compile-fail/enum_variants.rs new file mode 100644 index 00000000000..6589bd35fd3 --- /dev/null +++ b/tests/compile-fail/enum_variants.rs @@ -0,0 +1,71 @@ +#![feature(plugin, non_ascii_idents)] +#![plugin(clippy)] +#![deny(clippy)] + +enum FakeCallType { + CALL, CREATE +} + +enum FakeCallType2 { + CALL, CREATELL +} + +enum Foo { + cFoo, cBar, +} + +enum BadCallType { //~ ERROR: All variants have the same prefix: `CallType` + CallTypeCall, + CallTypeCreate, + CallTypeDestroy, +} + +enum TwoCallType { //~ ERROR: All variants have the same prefix: `CallType` + CallTypeCall, + CallTypeCreate, +} + +enum Consts { //~ ERROR: All variants have the same prefix: `Constant` + ConstantInt, + ConstantCake, + ConstantLie, +} + +enum Two { //~ ERROR: All variants have the same prefix: `Constant` + ConstantInt, + ConstantInfer, +} + +enum Something { + CCall, + CCreate, + CCryogenize, +} + +enum Seal { + With, + Without, +} + +enum Seall { + With, + WithOut, + Withbroken, +} + +enum Sealll { + With, + WithOut, +} + +enum Seallll { //~ ERROR: All variants have the same prefix: `With` + WithOutCake, + WithOut, +} + +enum NonCaps { //~ ERROR: All variants have the same prefix: `Prefix` + Prefix的, + PrefixCake, +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From cf536d7a4fbb82595f439eb812d469eda766bf42 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 15 Feb 2016 17:00:06 +0100 Subject: fallout --- src/consts.rs | 12 ++++++------ src/zero_div_zero.rs | 4 ++-- tests/consts.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 7cb0683711a..37322aeffc8 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -15,16 +15,16 @@ use syntax::ptr::P; #[derive(Debug, Copy, Clone)] pub enum FloatWidth { - Fw32, - Fw64, - FwAny, + F32, + F64, + Any, } impl From<FloatTy> for FloatWidth { fn from(ty: FloatTy) -> FloatWidth { match ty { - FloatTy::F32 => FloatWidth::Fw32, - FloatTy::F64 => FloatWidth::Fw64, + FloatTy::F32 => FloatWidth::F32, + FloatTy::F64 => FloatWidth::F64, } } } @@ -200,7 +200,7 @@ fn lit_to_constant(lit: &LitKind) -> Constant { LitKind::Char(c) => Constant::Char(c), LitKind::Int(value, ty) => Constant::Int(value, ty, Sign::Plus), LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), - LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::FwAny), + LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), LitKind::Bool(b) => Constant::Bool(b), } } diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 1576d699a4a..dbfa2744189 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -47,8 +47,8 @@ impl LateLintPass for ZeroDivZeroPass { // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, // match the precision of the literals that are given. let float_type = match (lhs_width, rhs_width) { - (FloatWidth::Fw64, _) - | (_, FloatWidth::Fw64) => "f64", + (FloatWidth::F64, _) + | (_, FloatWidth::F64) => "f64", _ => "f32" }; span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span, diff --git a/tests/consts.rs b/tests/consts.rs index 67be4243335..5c6088d0554 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -77,9 +77,9 @@ fn test_ops() { check(ONE, &binop(BiMul, litone.clone(), litone.clone())); check(ONE, &binop(BiDiv, litone.clone(), litone.clone())); - let half_any = Constant::Float("0.5".into(), FloatWidth::FwAny); - let half32 = Constant::Float("0.5".into(), FloatWidth::Fw32); - let half64 = Constant::Float("0.5".into(), FloatWidth::Fw64); + let half_any = Constant::Float("0.5".into(), FloatWidth::Any); + let half32 = Constant::Float("0.5".into(), FloatWidth::F32); + let half64 = Constant::Float("0.5".into(), FloatWidth::F64); assert_eq!(half_any, half32); assert_eq!(half_any, half64); -- cgit 1.4.1-3-g733a5 From 227ff8c4ad881b99222d1f3feda559a8db95a8d3 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 17 Feb 2016 13:38:44 +0100 Subject: Rustup to 1.8.0-nightly (57c357d89 2016-02-16) --- src/misc_early.rs | 10 +++++----- src/returns.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/misc_early.rs b/src/misc_early.rs index 59a0102aacf..cdc95c9924e 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -43,7 +43,7 @@ impl LintPass for MiscEarly { impl EarlyLintPass for MiscEarly { fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { - if let PatStruct(ref npat, ref pfields, _) = pat.node { + if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { let mut wilds = 0; let type_name = match npat.segments.last() { Some(elem) => format!("{}", elem.identifier.name), @@ -51,7 +51,7 @@ impl EarlyLintPass for MiscEarly { }; for field in pfields { - if field.node.pat.node == PatWild { + if field.node.pat.node == PatKind::Wild { wilds += 1; } } @@ -67,14 +67,14 @@ impl EarlyLintPass for MiscEarly { let mut normal = vec![]; for field in pfields { - if field.node.pat.node != PatWild { + if field.node.pat.node != PatKind::Wild { if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) { normal.push(n); } } } for field in pfields { - if field.node.pat.node == PatWild { + if field.node.pat.node == PatKind::Wild { wilds -= 1; if wilds > 0 { span_lint(cx, @@ -101,7 +101,7 @@ impl EarlyLintPass for MiscEarly { let mut registered_names: HashMap<String, Span> = HashMap::new(); for ref arg in &decl.inputs { - if let PatIdent(_, sp_ident, None) = arg.pat.node { + if let PatKind::Ident(_, sp_ident, None) = arg.pat.node { let arg_name = sp_ident.node.to_string(); if arg_name.starts_with("_") { diff --git a/src/returns.rs b/src/returns.rs index 63864eafcd2..bfddee797b8 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -97,7 +97,7 @@ impl ReturnPass { let StmtKind::Decl(ref decl, _) = stmt.node, let DeclKind::Local(ref local) = decl.node, let Some(ref initexpr) = local.init, - let PatIdent(_, Spanned { node: id, .. }, _) = local.pat.node, + let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node, let ExprKind::Path(_, ref path) = retexpr.node, match_path_ast(path, &[&id.name.as_str()]) ], { -- cgit 1.4.1-3-g733a5 From add483afedc86aa56913de6debadfa4f867675ad Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 18 Feb 2016 16:08:45 +0100 Subject: fix enum glob use (again) --- src/enum_glob_use.rs | 8 +++++--- tests/compile-fail/enum_glob_use.rs | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index c6561461e04..f8afdf627e2 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -44,9 +44,11 @@ impl EnumGlobUse { if let ItemUse(ref item_use) = item.node { if let ViewPath_::ViewPathGlob(_) = item_use.node { let def = cx.tcx.def_map.borrow()[&item.id]; - if let Some(NodeItem(it)) = cx.tcx.map.get_if_local(def.def_id()) { - if let ItemEnum(..) = it.node { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + if let Some(node_id) = cx.tcx.map.as_local_node_id(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 { if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() { diff --git a/tests/compile-fail/enum_glob_use.rs b/tests/compile-fail/enum_glob_use.rs index fc5f531ba90..27f0ff24579 100644 --- a/tests/compile-fail/enum_glob_use.rs +++ b/tests/compile-fail/enum_glob_use.rs @@ -17,4 +17,8 @@ mod blurg { pub use std::cmp::Ordering::*; // ok, re-export } +mod tests { + use super::*; +} + fn main() {} -- cgit 1.4.1-3-g733a5 From 1fd0676fa3c859ec9f0e83fc7266189ea62b4635 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Thu, 18 Feb 2016 20:12:33 +0100 Subject: improve str_add_assign lint description --- src/strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index 14c2e877919..a7dca02c967 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -13,9 +13,9 @@ use utils::STRING_PATH; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). /// -/// **Why is this bad?** Because this expression needs another copy as opposed to `x.push_str(y)` (in practice LLVM will usually elide it, though). Despite [llogiq](https://github.com/llogiq)'s reservations, this lint also is `allow` by default, as some people opine that it's more readable. +/// **Why is this bad?** It's not really bad, but some people think that the `.push_str(_)` method is more readable. /// -/// **Known problems:** None. Well apart from the lint being `allow` by default. :smile: +/// **Known problems:** None. /// /// **Example:** /// -- cgit 1.4.1-3-g733a5 From aa1df8e9fff6db1aec49e1d01f5495fce1c653ac Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 18 Feb 2016 20:19:16 +0100 Subject: Improve the `MAP_ENTRY` lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t span a suggestion when not appropriate but use a note and don’t force it to be `if !cond`. --- src/entry.rs | 140 ++++++++++++++++++++++++++++---------------- tests/compile-fail/entry.rs | 24 +++++--- 2 files changed, 104 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/entry.rs b/src/entry.rs index c2f2e956e5e..6242b44dd6e 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,5 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; +use rustc_front::intravisit::{Visitor, walk_expr, walk_block}; use syntax::codemap::Span; use utils::SpanlessEq; use utils::{BTREEMAP_PATH, HASHMAP_PATH}; @@ -41,73 +42,108 @@ impl LintPass for HashMapLint { impl LateLintPass for HashMapLint { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if_let_chain! { - [ - let ExprIf(ref check, ref then, _) = expr.node, - let ExprUnary(UnOp::UnNot, ref check) = check.node, - let ExprMethodCall(ref name, _, ref params) = check.node, - params.len() >= 2, - name.node.as_str() == "contains_key" - ], { - let key = match params[1].node { - ExprAddrOf(_, ref key) => key, - _ => return - }; - - let map = ¶ms[0]; - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); - - let kind = if match_type(cx, obj_ty, &BTREEMAP_PATH) { - "BTreeMap" - } - else if match_type(cx, obj_ty, &HASHMAP_PATH) { - "HashMap" - } - else { - return - }; + 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) { + // in case of `if !m.contains_key(&k) { m.insert(k, v); }` + // we can give a better error message + let sole_expr = else_block.is_none() && + if then_block.expr.is_some() { 1 } else { 0 } + then_block.stmts.len() == 1; - let sole_expr = if then.expr.is_some() { 1 } else { 0 } + then.stmts.len() == 1; + let mut visitor = InsertVisitor { + cx: cx, + span: expr.span, + ty: ty, + map: map, + key: key, + sole_expr: sole_expr, + }; - if let Some(ref then) = then.expr { - check_for_insert(cx, expr.span, map, key, then, sole_expr, kind); + walk_block(&mut visitor, then_block); } + } else if let Some(ref else_block) = *else_block { + if let Some((ty, map, key)) = check_cond(cx, check) { + let mut visitor = InsertVisitor { + cx: cx, + span: expr.span, + ty: ty, + map: map, + key: key, + sole_expr: false, + }; - for stmt in &then.stmts { - if let StmtSemi(ref stmt, _) = stmt.node { - check_for_insert(cx, expr.span, map, key, stmt, sole_expr, kind); - } + walk_expr(&mut visitor, else_block); } } } } } -fn check_for_insert(cx: &LateContext, span: Span, map: &Expr, key: &Expr, expr: &Expr, sole_expr: bool, kind: &str) { - if_let_chain! { - [ +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, + name.node.as_str() == "contains_key", + let ExprAddrOf(_, ref key) = params[1].node + ], { + let map = ¶ms[0]; + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); + + return if match_type(cx, obj_ty, &BTREEMAP_PATH) { + Some(("BTreeMap", map, key)) + } + else if match_type(cx, obj_ty, &HASHMAP_PATH) { + Some(("HashMap", map, key)) + } + else { + None + }; + }} + + None +} + +struct InsertVisitor<'a, 'tcx: 'a, 'b> { + cx: &'a LateContext<'a, 'tcx>, + span: Span, + ty: &'static str, + map: &'b Expr, + key: &'b Expr, + sole_expr: bool, +} + +impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> { + fn visit_expr(&mut self, expr: &'v Expr) { + if_let_chain! {[ let ExprMethodCall(ref name, _, ref params) = expr.node, params.len() == 3, name.node.as_str() == "insert", - get_item_name(cx, map) == get_item_name(cx, &*params[0]), - SpanlessEq::new(cx).eq_expr(key, ¶ms[1]) + get_item_name(self.cx, self.map) == get_item_name(self.cx, &*params[0]), + SpanlessEq::new(self.cx).eq_expr(self.key, ¶ms[1]) ], { - let help = if sole_expr { - format!("{}.entry({}).or_insert({})", - snippet(cx, map.span, "map"), - snippet(cx, params[1].span, ".."), - snippet(cx, params[2].span, "..")) - } - else { - format!("{}.entry({})", - snippet(cx, map.span, "map"), - snippet(cx, params[1].span, "..")) - }; - - span_lint_and_then(cx, MAP_ENTRY, span, - &format!("usage of `contains_key` followed by `insert` on `{}`", kind), |db| { - db.span_suggestion(span, "Consider using", help); + + span_lint_and_then(self.cx, MAP_ENTRY, self.span, + &format!("usage of `contains_key` followed by `insert` on `{}`", self.ty), |db| { + if self.sole_expr { + let help = format!("{}.entry({}).or_insert({})", + snippet(self.cx, self.map.span, "map"), + snippet(self.cx, params[1].span, ".."), + snippet(self.cx, params[2].span, "..")); + + db.span_suggestion(self.span, "Consider using", help); + } + else { + let help = format!("Consider using `{}.entry({})`", + snippet(self.cx, self.map.span, "map"), + snippet(self.cx, params[1].span, "..")); + + db.span_note(self.span, &help); + } }); + }} + + if !self.sole_expr { + walk_expr(self, expr); } } } diff --git a/tests/compile-fail/entry.rs b/tests/compile-fail/entry.rs index a7460282007..7dc4054ec5b 100644 --- a/tests/compile-fail/entry.rs +++ b/tests/compile-fail/entry.rs @@ -19,29 +19,37 @@ fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v); } //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` - //~| HELP Consider - //~| SUGGESTION m.entry(k) + //~| NOTE Consider using `m.entry(k)` } fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { m.insert(k, v) } else { None }; //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` - //~| HELP Consider - //~| SUGGESTION m.entry(k).or_insert(v) + //~| NOTE Consider using `m.entry(k)` +} + +fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if m.contains_key(&k) { None } else { m.insert(k, v) }; + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| NOTE Consider using `m.entry(k)` } fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` - //~| HELP Consider - //~| SUGGESTION m.entry(k) + //~| NOTE Consider using `m.entry(k)` +} + +fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) { + if m.contains_key(&k) { None } else { foo(); m.insert(k, v) }; + //~^ ERROR usage of `contains_key` followed by `insert` on `HashMap` + //~| NOTE Consider using `m.entry(k)` } fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) { if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; //~^ ERROR usage of `contains_key` followed by `insert` on `BTreeMap` - //~| HELP Consider - //~| SUGGESTION m.entry(k) + //~| NOTE Consider using `m.entry(k)` } fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) { -- cgit 1.4.1-3-g733a5 From 35a48bf5120d5a92723896982c16d793cd680e82 Mon Sep 17 00:00:00 2001 From: quininer kel <quininer@live.com> Date: Fri, 19 Feb 2016 04:16:39 +0800 Subject: fix nightly https://github.com/rust-lang/rust/commit/9b40e1e5b3d75c101b1ad78a1e2160962e955174 --- src/copies.rs | 14 +++++++------- src/eta_reduction.rs | 2 +- src/loops.rs | 16 ++++++++-------- src/map_clone.rs | 4 ++-- src/matches.rs | 20 ++++++++++---------- src/misc.rs | 8 ++++---- src/shadow.rs | 12 ++++++------ src/utils/hir.rs | 20 ++++++++++---------- 8 files changed, 48 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index b975aefe125..d97745203f0 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -175,13 +175,13 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> { fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) { match pat.node { - PatBox(ref pat) | PatRegion(ref pat, _) => bindings_impl(cx, pat, map), - PatEnum(_, Some(ref pats)) => { + PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), + PatKind::TupleStruct(_, Some(ref pats)) => { for pat in pats { bindings_impl(cx, pat, map); } } - PatIdent(_, ref ident, ref as_pat) => { + PatKind::Ident(_, ref ident, ref as_pat) => { if let Entry::Vacant(v) = map.entry(ident.node.name.as_str()) { v.insert(cx.tcx.pat_ty(pat)); } @@ -189,17 +189,17 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned bindings_impl(cx, as_pat, map); } }, - PatStruct(_, ref fields, _) => { + PatKind::Struct(_, ref fields, _) => { for pat in fields { bindings_impl(cx, &pat.node.pat, map); } } - PatTup(ref fields) => { + PatKind::Tup(ref fields) => { for pat in fields { bindings_impl(cx, pat, map); } } - PatVec(ref lhs, ref mid, ref rhs) => { + PatKind::Vec(ref lhs, ref mid, ref rhs) => { for pat in lhs { bindings_impl(cx, pat, map); } @@ -210,7 +210,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned bindings_impl(cx, pat, map); } } - PatEnum(..) | PatLit(..) | PatQPath(..) | PatRange(..) | PatWild => (), + PatKind::TupleStruct(..) | PatKind::Lit(..) | PatKind::QPath(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (), } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 280392a50b1..2522b1517a6 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -67,7 +67,7 @@ fn check_closure(cx: &LateContext, expr: &Expr) { } } for (ref a1, ref a2) in decl.inputs.iter().zip(args) { - if let PatIdent(_, ident, _) = a1.pat.node { + if let PatKind::Ident(_, ident, _) = a1.pat.node { // XXXManishearth Should I be checking the binding mode here? if let ExprPath(None, ref p) = a2.node { if p.segments.len() != 1 { diff --git a/src/loops.rs b/src/loops.rs index 2754f743caa..f88c12b4056 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -288,7 +288,7 @@ impl LateLintPass for LoopsPass { } if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node { let pat = &arms[0].pats[0].node; - if let (&PatEnum(ref path, Some(ref pat_args)), + if let (&PatKind::TupleStruct(ref path, Some(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() { @@ -338,7 +338,7 @@ fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &E fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { if let ExprRange(Some(ref l), ref r) = arg.node { // the var must be a single name - if let PatIdent(_, ref ident, _) = pat.node { + if let PatKind::Ident(_, ref ident, _) = pat.node { let mut visitor = VarVisitor { cx: cx, @@ -584,7 +584,7 @@ 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) { - if let PatTup(ref pat) = pat.node { + if let PatKind::Tup(ref pat) = pat.node { if pat.len() == 2 { let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { @@ -622,10 +622,10 @@ 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: &Pat_, body: &Expr) -> bool { +fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { match *pat { - PatWild => true, - PatIdent(_, ident, None) if ident.node.name.as_str().starts_with('_') => { + PatKind::Wild => true, + PatKind::Ident(_, ident, None) if ident.node.name.as_str().starts_with('_') => { let mut visitor = UsedVisitor { var: ident.node, used: false, @@ -668,7 +668,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { let Some(ref loopexpr) = block.expr, let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, innerarms.len() == 2 && innerarms[0].pats.len() == 1, - let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node, + let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, somepats.len() == 1 ], { return Some((&somepats[0], @@ -909,7 +909,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { // Look for declarations of the variable if let DeclLocal(ref local) = decl.node { if local.pat.id == self.var_id { - if let PatIdent(_, ref ident, _) = local.pat.node { + if let PatKind::Ident(_, ref ident, _) = local.pat.node { self.name = Some(ident.node.name); self.state = if let Some(ref init) = local.init { diff --git a/src/map_clone.rs b/src/map_clone.rs index e0255c52fb5..c83e4ca64ff 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -108,8 +108,8 @@ fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static s fn get_arg_name(pat: &Pat) -> Option<Ident> { match pat.node { - PatIdent(_, ident, None) => Some(ident.node), - PatRegion(ref subpat, _) => get_arg_name(subpat), + PatKind::Ident(_, ident, None) => Some(ident.node), + PatKind::Ref(ref subpat, _) => get_arg_name(subpat), _ => None, } } diff --git a/src/matches.rs b/src/matches.rs index ca410a413bd..b8ea4f2b1b0 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -157,7 +157,7 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { - if arms[1].pats[0].node == PatWild { + if arms[1].pats[0].node == PatKind::Wild { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { @@ -192,15 +192,15 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: ]; let path = match arms[1].pats[0].node { - PatEnum(ref path, Some(ref inner)) => { + PatKind::TupleStruct(ref path, Some(ref inner)) => { // contains any non wildcard patterns? e.g. Err(err) - if inner.iter().any(|pat| if let PatWild = pat.node { false } else { true }) { + if inner.iter().any(|pat| if let PatKind::Wild = pat.node { false } else { true }) { return; } path.to_string() }, - PatEnum(ref path, None) => path.to_string(), - PatIdent(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), + PatKind::TupleStruct(ref path, None) => path.to_string(), + PatKind::Ident(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), _ => return, }; @@ -235,7 +235,7 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if cx.tcx.expr_ty(ex).sty == ty::TyBool { let sugg = if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards - let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node { + let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pats[0].node { if let ExprLit(ref lit) = arm_bool.node { match lit.node { LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), @@ -334,7 +334,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { if let Arm { ref pats, guard: None, .. } = *arm { Some(pats.iter().filter_map(|pat| { if_let_chain! {[ - let PatRange(ref lhs, ref rhs) = pat.node, + 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) ], { @@ -342,7 +342,7 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { }} if_let_chain! {[ - let PatLit(ref value) = pat.node, + 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) }); @@ -424,8 +424,8 @@ fn has_only_ref_pats(arms: &[Arm]) -> bool { .flat_map(|a| &a.pats) .map(|p| { match p.node { - PatRegion(..) => Some(true), // &-patterns - PatWild => Some(false), // an "anything" wildcard is also fine + PatKind::Ref(..) => Some(true), // &-patterns + PatKind::Wild => Some(false), // an "anything" wildcard is also fine _ => None, // any other pattern is not fine } }) diff --git a/src/misc.rs b/src/misc.rs index 076e6e385c2..5c154dc59e2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -45,7 +45,7 @@ impl LateLintPass for TopLevelRefPass { return; } for ref arg in &decl.inputs { - if let PatIdent(BindByRef(_), _, _) = arg.pat.node { + if let PatKind::Ident(BindByRef(_), _, _) = arg.pat.node { span_lint(cx, TOPLEVEL_REF_ARG, arg.pat.span, @@ -58,7 +58,7 @@ impl LateLintPass for TopLevelRefPass { [ let StmtDecl(ref d, _) = s.node, let DeclLocal(ref l) = d.node, - let PatIdent(BindByRef(_), i, None) = l.pat.node, + let PatKind::Ident(BindByRef(_), i, None) = l.pat.node, let Some(ref init) = l.init ], { let tyopt = if let Some(ref ty) = l.ty { @@ -345,8 +345,8 @@ impl LintPass for PatternPass { impl LateLintPass for PatternPass { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { - if let PatIdent(_, ref ident, Some(ref right)) = pat.node { - if right.node == PatWild { + if let PatKind::Ident(_, ref ident, Some(ref right)) = pat.node { + if right.node == PatKind::Wild { cx.span_lint(REDUNDANT_PATTERN, pat.span, &format!("the `{} @ _` pattern can be written as just `{}`", diff --git a/src/shadow.rs b/src/shadow.rs index ff9ea47f065..206fa492419 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -67,7 +67,7 @@ impl LateLintPass for ShadowPass { fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { let mut bindings = Vec::new(); for arg in &decl.inputs { - if let PatIdent(_, ident, _) = arg.pat.node { + if let PatKind::Ident(_, ident, _) = arg.pat.node { bindings.push((ident.node.unhygienic_name, ident.span)) } } @@ -119,7 +119,7 @@ fn is_binding(cx: &LateContext, pat: &Pat) -> bool { fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { // TODO: match more stuff / destructuring match pat.node { - PatIdent(_, ref ident, ref inner) => { + PatKind::Ident(_, ref ident, ref inner) => { let name = ident.node.unhygienic_name; if is_binding(cx, pat) { let mut new_binding = true; @@ -140,7 +140,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } // PatEnum(Path, Option<Vec<P<Pat>>>), - PatStruct(_, ref pfields, _) => { + PatKind::Struct(_, ref pfields, _) => { if let Some(ref init_struct) = *init { if let ExprStruct(_, ref efields, _) = init_struct.node { for field in pfields { @@ -161,7 +161,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } } - PatTup(ref inner) => { + PatKind::Tup(ref inner) => { if let Some(ref init_tup) = *init { if let ExprTup(ref tup) = init_tup.node { for (i, p) in inner.iter().enumerate() { @@ -178,7 +178,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } } - PatBox(ref inner) => { + PatKind::Box(ref inner) => { if let Some(ref initp) = *init { if let ExprBox(ref inner_init) = initp.node { check_pat(cx, inner, &Some(&**inner_init), span, bindings); @@ -189,7 +189,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind check_pat(cx, inner, init, span, bindings); } } - PatRegion(ref inner, _) => check_pat(cx, inner, init, span, bindings), + PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings), // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), _ => (), } diff --git a/src/utils/hir.rs b/src/utils/hir.rs index e527f63ebbd..631bcb1b100 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -168,41 +168,41 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { /// Check whether two patterns are the same. pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { match (&left.node, &right.node) { - (&PatBox(ref l), &PatBox(ref r)) => { + (&PatKind::Box(ref l), &PatKind::Box(ref r)) => { self.eq_pat(l, r) } - (&PatEnum(ref lp, ref la), &PatEnum(ref rp, ref ra)) => { + (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => { self.eq_path(lp, rp) && both(la, ra, |l, r| { over(l, r, |l, r| self.eq_pat(l, r)) }) } - (&PatIdent(ref lb, ref li, ref lp), &PatIdent(ref rb, ref ri, ref rp)) => { + (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => { lb == rb && li.node.name.as_str() == ri.node.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) } - (&PatLit(ref l), &PatLit(ref r)) => { + (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => { self.eq_expr(l, r) } - (&PatQPath(ref ls, ref lp), &PatQPath(ref rs, ref rp)) => { + (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { self.eq_qself(ls, rs) && self.eq_path(lp, rp) } - (&PatTup(ref l), &PatTup(ref r)) => { + (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => { over(l, r, |l, r| self.eq_pat(l, r)) } - (&PatRange(ref ls, ref le), &PatRange(ref rs, ref re)) => { + (&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => { self.eq_expr(ls, rs) && self.eq_expr(le, re) } - (&PatRegion(ref le, ref lm), &PatRegion(ref re, ref rm)) => { + (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => { lm == rm && self.eq_pat(le, re) } - (&PatVec(ref ls, ref li, ref le), &PatVec(ref rs, ref ri, ref re)) => { + (&PatKind::Vec(ref ls, ref li, ref le), &PatKind::Vec(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)) } - (&PatWild, &PatWild) => true, + (&PatKind::Wild, &PatKind::Wild) => true, _ => false, } } -- cgit 1.4.1-3-g733a5 From 5fe6e9f911f69cdef209c20b2024c33b19bf3993 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 17:00:36 +0100 Subject: Build the import lint in update_lints.py --- src/lib.rs | 69 +++++++++++++++++++++++++++------------------------- util/update_lints.py | 13 ++++++++++ 2 files changed, 49 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 106d63aa0da..23accd2ebaa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,59 +35,62 @@ extern crate rustc_plugin; use rustc_plugin::Registry; +pub mod consts; #[macro_use] pub mod utils; + +// begin lints modules, do not remove this comment, it’s used in `update_lints` +pub mod approx_const; +pub mod array_indexing; +pub mod attrs; +pub mod bit_mask; +pub mod block_in_if_condition; +pub mod collapsible_if; pub mod copies; -pub mod consts; -pub mod types; -pub mod misc; +pub mod cyclomatic_complexity; +pub mod derive; +pub mod drop_ref; +pub mod entry; pub mod enum_glob_use; +pub mod enum_variants; pub mod eq_op; -pub mod bit_mask; -pub mod ptr_arg; -pub mod needless_bool; -pub mod approx_const; +pub mod escape; pub mod eta_reduction; -pub mod enum_variants; pub mod identity_op; pub mod items_after_statements; -pub mod minmax; -pub mod mut_mut; -pub mod mut_reference; pub mod len_zero; -pub mod attrs; -pub mod collapsible_if; -pub mod block_in_if_condition; -pub mod unicode; -pub mod shadow; -pub mod strings; -pub mod methods; -pub mod returns; pub mod lifetimes; pub mod loops; -pub mod ranges; pub mod map_clone; pub mod matches; -pub mod precedence; +pub mod methods; +pub mod minmax; +pub mod misc; +pub mod misc_early; +pub mod mut_mut; +pub mod mut_reference; pub mod mutex_atomic; -pub mod zero_div_zero; -pub mod open_options; +pub mod needless_bool; pub mod needless_features; pub mod needless_update; pub mod no_effect; -pub mod temporary_assignment; -pub mod transmute; -pub mod cyclomatic_complexity; -pub mod escape; -pub mod entry; -pub mod misc_early; -pub mod array_indexing; +pub mod open_options; pub mod panic; -pub mod derive; +pub mod precedence; pub mod print; -pub mod vec; -pub mod drop_ref; +pub mod ptr_arg; +pub mod ranges; pub mod regex; +pub mod returns; +pub mod shadow; +pub mod strings; +pub mod temporary_assignment; +pub mod transmute; +pub mod types; +pub mod unicode; +pub mod vec; +pub mod zero_div_zero; +// end lints modules, do not remove this comment, it’s used in `update_lints` mod reexport { pub use syntax::ast::{Name, NodeId}; diff --git a/util/update_lints.py b/util/update_lints.py index 9f105a2699c..2eaa6ab6211 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -60,6 +60,13 @@ def gen_group(lints, levels=None): yield ' %s::%s,\n' % (module, name.upper()) +def gen_mods(lints): + """Declare modules""" + + for module in sorted(set(lint[0] for lint in lints)): + yield 'pub mod %s;\n' % module + + def replace_region(fn, region_start, region_end, callback, replace_start=True, write_back=True): """Replace a region in a file delimited by two lines matching regexes. @@ -128,6 +135,12 @@ def main(print_only=False, check=False): lambda: ['There are %d lints included in this crate:\n' % len(lints)], write_back=not check) + # update the `pub mod` list + changed |= replace_region( + 'src/lib.rs', r'begin lints modules', r'end lints modules', + lambda: gen_mods(lints), + replace_start=False, write_back=not check) + # same for "clippy" lint collection changed |= replace_region( 'src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', -- cgit 1.4.1-3-g733a5 From 222086d62b2c22e59eab82f03f4d08e3cb9bd6ae Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 17:33:53 +0100 Subject: Remove all use of `format!("string literal")` --- src/loops.rs | 4 ++-- src/methods.rs | 2 +- src/types.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 2754f743caa..9e5745950dd 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -317,8 +317,8 @@ impl LateLintPass for LoopsPass { span_lint(cx, UNUSED_COLLECT, expr.span, - &format!("you are collect()ing an iterator and throwing away the result. Consider \ - using an explicit for loop to exhaust the iterator")); + &"you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator"); } } } diff --git a/src/methods.rs b/src/methods.rs index 39f69f63d7b..f776d5890b7 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -589,7 +589,7 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { span_lint(cx, EXTEND_FROM_SLICE, expr.span, - &format!("use of `extend` to extend a Vec by a slice")) + &"use of `extend` to extend a Vec by a slice") .span_suggestion(expr.span, "try this", format!("{}.extend_from_slice({}{})", diff --git a/src/types.rs b/src/types.rs index 7cfcc76193d..7521bc48046 100644 --- a/src/types.rs +++ b/src/types.rs @@ -491,12 +491,12 @@ fn check_type(cx: &LateContext, ty: &Ty) { visitor.visit_ty(ty); visitor.score }; - // println!("{:?} --> {}", ty, score); + if score > 250 { span_lint(cx, TYPE_COMPLEXITY, ty.span, - &format!("very complex type used. Consider factoring parts into `type` definitions")); + &"very complex type used. Consider factoring parts into `type` definitions"); } } -- cgit 1.4.1-3-g733a5 From ef4401d4acf2eb1e125b9dd01d1baef195e2f53b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 17:35:07 +0100 Subject: Lint about usage of `format!("string literal")` --- README.md | 3 ++- src/format.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ tests/compile-fail/format.rs | 11 +++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/format.rs create mode 100755 tests/compile-fail/format.rs (limited to 'src') diff --git a/README.md b/README.md index 7fa0a15715f..62d6695b24d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 122 lints included in this crate: +There are 123 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -126,6 +126,7 @@ name [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore +[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` [while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop diff --git a/src/format.rs b/src/format.rs new file mode 100644 index 00000000000..ad72b38e110 --- /dev/null +++ b/src/format.rs @@ -0,0 +1,40 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::{is_expn_of, span_lint}; + +/// **What it does:** This lints about use of `format!("string literal with no argument")`. +/// +/// **Why is this bad?** There is no point of doing that. If you want a `String` you can use +/// `to_owned` on the string literal. The even worst `&format!("foo")` is often encountered in the +/// wild. +/// +/// **Known problems:** None. +/// +/// **Example:** `format!("foo")` +declare_lint! { + pub USELESS_FORMAT, + Warn, + "useless use of `format!`" +} + +#[derive(Copy, Clone, Debug)] +pub struct FormatMacLint; + +impl LintPass for FormatMacLint { + fn get_lints(&self) -> LintArray { + lint_array![USELESS_FORMAT] + } +} + +impl LateLintPass for FormatMacLint { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + // `format!("foo")` expansion contains `match () { () => [], }` + if let ExprMatch(ref matchee, _, _) = expr.node { + if let ExprTup(ref tup) = matchee.node { + if tup.is_empty() && is_expn_of(cx, expr.span, "format").is_some() { + span_lint(cx, USELESS_FORMAT, expr.span, &"useless use of `format!`"); + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 23accd2ebaa..b690a5cf45e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,6 +163,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); reg.register_late_lint_pass(box regex::RegexPass::default()); reg.register_late_lint_pass(box copies::CopyAndPaste); + reg.register_late_lint_pass(box format::FormatMacLint); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -209,6 +210,7 @@ pub fn plugin_registrar(reg: &mut Registry) { eq_op::EQ_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, + format::USELESS_FORMAT, identity_op::IDENTITY_OP, items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/tests/compile-fail/format.rs b/tests/compile-fail/format.rs new file mode 100755 index 00000000000..6cdceefd063 --- /dev/null +++ b/tests/compile-fail/format.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(useless_format)] + +fn main() { + format!("foo"); //~ERROR useless use of `format!` + format!("foo {}", 42); + + println!("foo"); + println!("foo {}", 42); +} -- cgit 1.4.1-3-g733a5 From b6443b992898eebf465470c2dcdb93fdbd87d381 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 21:03:45 +0100 Subject: Replace all `format!("{}", foo)` calls --- src/collapsible_if.rs | 7 ++++--- src/loops.rs | 6 +++--- src/methods.rs | 8 ++++---- src/misc_early.rs | 5 +---- src/mut_reference.rs | 4 ++-- 5 files changed, 14 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index e5ad94fc639..663d39cdbb2 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -14,6 +14,7 @@ use rustc::lint::*; use rustc_front::hir::*; +use std::borrow::Cow; use syntax::codemap::Spanned; use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; @@ -95,11 +96,11 @@ fn requires_brackets(e: &Expr) -> bool { } } -fn check_to_string(cx: &LateContext, e: &Expr) -> String { +fn check_to_string(cx: &LateContext, e: &Expr) -> Cow<'static, str> { if requires_brackets(e) { - format!("({})", snippet(cx, e.span, "..")) + format!("({})", snippet(cx, e.span, "..")).into() } else { - format!("{}", snippet(cx, e.span, "..")) + snippet(cx, e.span, "..") } } diff --git a/src/loops.rs b/src/loops.rs index 9e5745950dd..fff73f907f0 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -245,13 +245,13 @@ impl LateLintPass for LoopsPass { let mut other_stuff = block.stmts .iter() .skip(1) - .map(|stmt| format!("{}", snippet(cx, stmt.span, ".."))) - .collect::<Vec<String>>(); + .map(|stmt| snippet(cx, stmt.span, "..")) + .collect::<Vec<Cow<_>>>(); if inner_stmt_expr.is_some() { // if we have a statement which has a match, if let Some(ref expr) = block.expr { // then collect the expression (without semicolon) below it - other_stuff.push(format!("{}", snippet(cx, expr.span, ".."))); + other_stuff.push(snippet(cx, expr.span, "..")); } } diff --git a/src/methods.rs b/src/methods.rs index f776d5890b7..1d529e175db 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -530,10 +530,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) return; } - let sugg = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")), - (false, false) => format!("|| {}", snippet(cx, arg.span, "..")), - (false, true) => format!("{}", snippet(cx, fun.span, "..")), + let sugg: Cow<_> = match (fn_has_arguments, !or_has_args) { + (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(), + (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(), + (false, true) => snippet(cx, fun.span, ".."), }; span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name)) diff --git a/src/misc_early.rs b/src/misc_early.rs index 28d5fb65f36..bbed9ad4996 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -45,10 +45,7 @@ impl EarlyLintPass for MiscEarly { fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { let mut wilds = 0; - let type_name = match npat.segments.last() { - Some(elem) => format!("{}", elem.identifier.name), - None => String::new(), - }; + let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name; for field in pfields { if field.node.pat.node == PatKind::Wild { diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 35904533719..ea2c00bab94 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -39,13 +39,13 @@ impl LateLintPass for UnnecessaryMutPassed { 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, &format!("{}", path)); + 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, &format!("{}", name.node.as_str())) + check_arguments(cx, &arguments, method_type.ty, &name.node.as_str()) } _ => {} } -- cgit 1.4.1-3-g733a5 From ba3be834881a5a62c00cb49ac09b2d1b9f35fe5f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 21:15:05 +0100 Subject: Lint about `format!("{}", foo)` --- src/format.rs | 86 ++++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 1 + src/utils/mod.rs | 2 ++ tests/compile-fail/format.rs | 4 +++ 4 files changed, 86 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/format.rs b/src/format.rs index ad72b38e110..704b4e8e8fa 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,11 +1,14 @@ +use rustc::front::map::Node::NodeItem; use rustc::lint::*; use rustc_front::hir::*; -use utils::{is_expn_of, span_lint}; +use syntax::ast::LitKind; +use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH}; +use utils::{is_expn_of, match_path, span_lint}; /// **What it does:** This lints about use of `format!("string literal with no argument")`. /// /// **Why is this bad?** There is no point of doing that. If you want a `String` you can use -/// `to_owned` on the string literal. The even worst `&format!("foo")` is often encountered in the +/// `to_owned` on the string literal. The even worse `&format!("foo")` is often encountered in the /// wild. /// /// **Known problems:** None. @@ -28,13 +31,82 @@ impl LintPass for FormatMacLint { impl LateLintPass for FormatMacLint { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - // `format!("foo")` expansion contains `match () { () => [], }` - if let ExprMatch(ref matchee, _, _) = expr.node { - if let ExprTup(ref tup) = matchee.node { - if tup.is_empty() && is_expn_of(cx, expr.span, "format").is_some() { - span_lint(cx, USELESS_FORMAT, expr.span, &"useless use of `format!`"); + 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(_, ref path) = fun.node, + args.len() == 2, + match_path(path, &FMT_ARGUMENTS_NEWV1_PATH), + // 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 + check_arg_is_display(&args[1]) + ], { + 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 { + if tup.is_empty() { + span_lint(cx, USELESS_FORMAT, span, &"useless use of `format!`"); + } + } + } + _ => (), } } } } + +/// Checks if the expressions matches +/// ``` +/// { static __STATIC_FMTSTR: &[""] = _; __STATIC_FMTSTR } +/// ``` +fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { + if_let_chain! {[ + let ExprBlock(ref block) = expr.node, + block.stmts.len() == 1, + let StmtDecl(ref decl, _) = block.stmts[0].node, + let DeclItem(ref decl) = decl.node, + let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id), + decl.name.as_str() == "__STATIC_FMTSTR", + let ItemStatic(_, _, ref expr) = decl.node, + let ExprAddrOf(_, ref expr) = expr.node, // &[""] + let ExprVec(ref expr) = expr.node, + expr.len() == 1, + let ExprLit(ref lit) = expr[0].node, + let LitKind::Str(ref lit, _) = lit.node, + lit.is_empty() + ], { + return true; + }} + + false +} + +/// Checks if the expressions matches +/// ``` +/// &match (&42,) { +/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)], +/// }) +/// ``` +fn check_arg_is_display(expr: &Expr) -> bool { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, + let ExprMatch(_, ref arms, _) = expr.node, + arms.len() == 1, + let ExprVec(ref exprs) = arms[0].body.node, + exprs.len() == 1, + let ExprCall(_, ref args) = exprs[0].node, + args.len() == 2, + let ExprPath(None, ref path) = args[1].node, + match_path(path, &DISPLAY_FMT_METHOD_PATH) + ], { + return true; + }} + + false +} diff --git a/src/lib.rs b/src/lib.rs index b690a5cf45e..8348eb09834 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ pub mod enum_variants; pub mod eq_op; pub mod escape; pub mod eta_reduction; +pub mod format; pub mod identity_op; pub mod items_after_statements; pub mod len_zero; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3a7c6c90d51..68137fbbf2a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -28,7 +28,9 @@ pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; +pub const DISPLAY_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; +pub const FMT_ARGUMENTS_NEWV1_PATH: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; diff --git a/tests/compile-fail/format.rs b/tests/compile-fail/format.rs index 6cdceefd063..0219771e09e 100755 --- a/tests/compile-fail/format.rs +++ b/tests/compile-fail/format.rs @@ -4,7 +4,11 @@ fn main() { format!("foo"); //~ERROR useless use of `format!` + format!("{}", 42); //~ERROR useless use of `format!` + format!("{:?}", 42); // we only want to warn about `{}` + format!("{:+}", 42); // we only want to warn about `{}` format!("foo {}", 42); + format!("{} bar", 42); println!("foo"); println!("foo {}", 42); -- cgit 1.4.1-3-g733a5 From 1a64a4890c56f23039fbb5df3c643d6c060d7660 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 20 Feb 2016 21:20:56 +0100 Subject: Small cleanup --- src/format.rs | 4 ++-- src/loops.rs | 4 ++-- src/methods.rs | 2 +- src/regex.rs | 4 ++-- src/types.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/format.rs b/src/format.rs index 704b4e8e8fa..901cd3f7a9b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -44,14 +44,14 @@ impl LateLintPass for FormatMacLint { // ensure the format argument is `{}` ie. Display with no fancy option check_arg_is_display(&args[1]) ], { - span_lint(cx, USELESS_FORMAT, span, &"useless use of `format!`"); + 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 { if tup.is_empty() { - span_lint(cx, USELESS_FORMAT, span, &"useless use of `format!`"); + span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); } } } diff --git a/src/loops.rs b/src/loops.rs index fff73f907f0..15f0e51f36c 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -317,8 +317,8 @@ impl LateLintPass for LoopsPass { span_lint(cx, UNUSED_COLLECT, expr.span, - &"you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator"); + "you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator"); } } } diff --git a/src/methods.rs b/src/methods.rs index 1d529e175db..c67e2eade14 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -589,7 +589,7 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { span_lint(cx, EXTEND_FROM_SLICE, expr.span, - &"use of `extend` to extend a Vec by a slice") + "use of `extend` to extend a Vec by a slice") .span_suggestion(expr.span, "try this", format!("{}.extend_from_slice({}{})", diff --git a/src/regex.rs b/src/regex.rs index 25c7260abec..745d685ec80 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -105,7 +105,7 @@ impl LateLintPass for RegexPass { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - &"trivial regex", + "trivial regex", &format!("consider using {}", repl)); } } @@ -123,7 +123,7 @@ impl LateLintPass for RegexPass { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - &"trivial regex", + "trivial regex", &format!("consider using {}", repl)); } } diff --git a/src/types.rs b/src/types.rs index 7521bc48046..eec8bd63eb7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -496,7 +496,7 @@ fn check_type(cx: &LateContext, ty: &Ty) { span_lint(cx, TYPE_COMPLEXITY, ty.span, - &"very complex type used. Consider factoring parts into `type` definitions"); + "very complex type used. Consider factoring parts into `type` definitions"); } } -- cgit 1.4.1-3-g733a5 From d77ccdc33870e89c7fba9a55aea876f14754b94d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 21 Feb 2016 13:21:04 +0100 Subject: Fix `USELESS_FORMAT` wiki --- src/format.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/format.rs b/src/format.rs index 901cd3f7a9b..e161d6fce3b 100644 --- a/src/format.rs +++ b/src/format.rs @@ -5,15 +5,16 @@ use syntax::ast::LitKind; use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH}; use utils::{is_expn_of, match_path, span_lint}; -/// **What it does:** This lints about use of `format!("string literal with no argument")`. +/// **What it does:** This lints about use of `format!("string literal with no argument")` and +/// `format!("{}", foo)`. /// /// **Why is this bad?** There is no point of doing that. If you want a `String` you can use -/// `to_owned` on the string literal. The even worse `&format!("foo")` is often encountered in the -/// wild. +/// `to_owned` on the string literal or expression. The even worse `&format!("foo")` is often +/// encountered in the wild. /// /// **Known problems:** None. /// -/// **Example:** `format!("foo")` +/// **Examples:** `format!("foo")` and `format!("{}", foo)` declare_lint! { pub USELESS_FORMAT, Warn, -- cgit 1.4.1-3-g733a5 From 2a0fb1fb440fda9267a7d57961d16da25b03005a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 22 Feb 2016 17:54:46 +0100 Subject: Limit `USELESS_FORMAT` with args to string args --- src/format.rs | 24 +++++++++++++++--------- tests/compile-fail/format.rs | 25 ++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/format.rs b/src/format.rs index e161d6fce3b..f0b8485b4a4 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,16 +1,17 @@ use rustc::front::map::Node::NodeItem; use rustc::lint::*; +use rustc::middle::ty::TypeVariants; use rustc_front::hir::*; use syntax::ast::LitKind; -use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH}; -use utils::{is_expn_of, match_path, span_lint}; +use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH, STRING_PATH}; +use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty}; /// **What it does:** This lints about use of `format!("string literal with no argument")` and -/// `format!("{}", foo)`. +/// `format!("{}", foo)` where `foo` is a string. /// -/// **Why is this bad?** There is no point of doing that. If you want a `String` you can use -/// `to_owned` on the string literal or expression. The even worse `&format!("foo")` is often -/// encountered in the wild. +/// **Why is this bad?** There is no point of doing that. `format!("too")` can be replaced by `"foo".to_owned()` if you really need a `String`. The even worse `&format!("foo")` is often +/// encountered in the wild. `format!("{}", foo)` can be replaced by `foo.clone()` if `foo: String` +/// or `foo.to_owned()` is `foo: &str`. /// /// **Known problems:** None. /// @@ -43,7 +44,7 @@ impl LateLintPass for FormatMacLint { // 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 - check_arg_is_display(&args[1]) + check_arg_is_display(cx, &args[1]) ], { span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); }} @@ -94,11 +95,14 @@ fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { /// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)], /// }) /// ``` -fn check_arg_is_display(expr: &Expr) -> bool { +fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { if_let_chain! {[ let ExprAddrOf(_, ref expr) = expr.node, let ExprMatch(_, ref arms, _) = expr.node, arms.len() == 1, + arms[0].pats.len() == 1, + let PatKind::Tup(ref pat) = arms[0].pats[0].node, + pat.len() == 1, let ExprVec(ref exprs) = arms[0].body.node, exprs.len() == 1, let ExprCall(_, ref args) = exprs[0].node, @@ -106,7 +110,9 @@ fn check_arg_is_display(expr: &Expr) -> bool { let ExprPath(None, ref path) = args[1].node, match_path(path, &DISPLAY_FMT_METHOD_PATH) ], { - return true; + let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0])); + + return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &STRING_PATH); }} false diff --git a/tests/compile-fail/format.rs b/tests/compile-fail/format.rs index 0219771e09e..4fff131f6e7 100755 --- a/tests/compile-fail/format.rs +++ b/tests/compile-fail/format.rs @@ -4,12 +4,31 @@ fn main() { format!("foo"); //~ERROR useless use of `format!` - format!("{}", 42); //~ERROR useless use of `format!` - format!("{:?}", 42); // we only want to warn about `{}` - format!("{:+}", 42); // we only want to warn about `{}` + + format!("{}", "foo"); //~ERROR useless use of `format!` + format!("{:?}", "foo"); // we only want to warn about `{}` + format!("{:+}", "foo"); // we only want to warn about `{}` + format!("foo {}", "bar"); + format!("{} bar", "foo"); + + let arg: String = "".to_owned(); + format!("{}", arg); //~ERROR useless use of `format!` + format!("{:?}", arg); // we only want to warn about `{}` + format!("{:+}", arg); // we only want to warn about `{}` + format!("foo {}", arg); + format!("{} bar", arg); + + // we don’t want to warn for non-string args, see #697 + format!("{}", 42); + format!("{:?}", 42); + format!("{:+}", 42); format!("foo {}", 42); format!("{} bar", 42); + // we only want to warn about `format!` itself println!("foo"); + println!("{}", "foo"); + println!("foo {}", "foo"); + println!("{}", 42); println!("foo {}", 42); } -- cgit 1.4.1-3-g733a5 From 3b783152ccff54f3bf1e54db424dc476e36b1b31 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 22 Feb 2016 20:00:51 +0100 Subject: Fix ICE with match_def_path --- src/utils/mod.rs | 6 +++++- tests/run-pass/ice-700.rs | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100755 tests/run-pass/ice-700.rs (limited to 'src') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 68137fbbf2a..b9dd9359c66 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -133,8 +133,12 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { /// ``` pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { cx.tcx.with_path(def_id, |iter| { - iter.zip(path) + let mut len = 0; + + iter.inspect(|_| len += 1) + .zip(path) .all(|(nm, p)| nm.name().as_str() == *p) + && len == path.len() }) } diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs new file mode 100755 index 00000000000..a7ff78eac14 --- /dev/null +++ b/tests/run-pass/ice-700.rs @@ -0,0 +1,9 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy)] + +fn core() {} + +fn main() { + core(); +} -- cgit 1.4.1-3-g733a5 From b753e77cbe175fc6e336387029290e9d19f1243a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 24 Feb 2016 17:38:57 +0100 Subject: Rustfmt and sort all `use` items --- src/approx_const.rs | 2 +- src/attrs.rs | 6 +-- src/bit_mask.rs | 2 +- src/block_in_if_condition.rs | 2 +- src/consts.rs | 59 ++++++++++++++++++----------- src/copies.rs | 74 +++++++++++++++++++++--------------- src/cyclomatic_complexity.rs | 8 ++-- src/drop_ref.rs | 3 +- src/enum_glob_use.rs | 8 ++-- src/enum_variants.rs | 5 +-- src/eq_op.rs | 1 - src/escape.rs | 10 ++--- src/eta_reduction.rs | 4 +- src/identity_op.rs | 3 +- src/items_after_statements.rs | 2 +- src/len_zero.rs | 11 ++---- src/lifetimes.rs | 7 ++-- src/loops.rs | 87 ++++++++++++++++++++++--------------------- src/map_clone.rs | 6 ++- src/matches.rs | 33 ++++++++-------- src/methods.rs | 25 ++++++------- src/minmax.rs | 12 +++--- src/misc.rs | 15 ++++---- src/misc_early.rs | 3 -- src/mut_mut.rs | 3 +- src/mut_reference.rs | 4 +- src/mutex_atomic.rs | 6 +-- src/needless_bool.rs | 2 - src/needless_features.rs | 1 - src/needless_update.rs | 1 - src/no_effect.rs | 7 +--- src/open_options.rs | 4 +- src/panic.rs | 1 - src/precedence.rs | 3 +- src/print.rs | 2 +- src/ptr_arg.rs | 7 ++-- src/regex.rs | 39 +++++++++---------- src/returns.rs | 1 - src/shadow.rs | 10 ++--- src/strings.rs | 5 +-- src/temporary_assignment.rs | 1 - src/types.rs | 32 +++++++++------- src/unicode.rs | 5 +-- src/utils/hir.rs | 29 +++++++++------ src/utils/mod.rs | 2 +- src/zero_div_zero.rs | 3 +- 46 files changed, 279 insertions(+), 277 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index b1a33584442..822fbd16c32 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,8 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; use std::f64::consts as f64; -use utils::span_lint; use syntax::ast::{Lit, LitKind, FloatTy}; +use utils::span_lint; /// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. /// diff --git a/src/attrs.rs b/src/attrs.rs index fda46724862..363809c37bb 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,12 +1,12 @@ //! checks for attributes +use reexport::*; use rustc::lint::*; use rustc_front::hir::*; -use reexport::*; use semver::Version; -use syntax::codemap::Span; -use syntax::attr::*; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; +use syntax::attr::*; +use syntax::codemap::Span; use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. diff --git a/src/bit_mask.rs b/src/bit_mask.rs index e1366924e1d..0e09122bcc6 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -3,8 +3,8 @@ use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; -use syntax::codemap::Span; use syntax::ast::LitKind; +use syntax::codemap::Span; use utils::span_lint; diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 65fbce640cf..6db77a5ce93 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -1,5 +1,5 @@ -use rustc_front::hir::*; use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; +use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr}; use utils::*; diff --git a/src/consts.rs b/src/consts.rs index 37322aeffc8..cf32a9a2c82 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -95,9 +95,7 @@ impl PartialEq for Constant { (&Constant::Byte(l), &Constant::Byte(r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r, (&Constant::Int(0, _, _), &Constant::Int(0, _, _)) => true, - (&Constant::Int(lv, _, lneg), &Constant::Int(rv, _, rneg)) => { - lv == rv && lneg == rneg - } + (&Constant::Int(lv, _, lneg), &Constant::Int(rv, _, rneg)) => lv == rv && lneg == rneg, (&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 @@ -116,7 +114,9 @@ impl PartialEq for Constant { } impl Hash for Constant { - fn hash<H>(&self, state: &mut H) where H: Hasher { + fn hash<H>(&self, state: &mut H) + where H: Hasher + { match *self { Constant::Str(ref s, ref k) => { s.hash(state); @@ -144,7 +144,7 @@ impl Hash for Constant { Constant::Bool(b) => { b.hash(state); } - Constant::Vec(ref v) | Constant::Tuple(ref v)=> { + Constant::Vec(ref v) | Constant::Tuple(ref v) => { v.hash(state); } Constant::Repeat(ref c, l) => { @@ -210,7 +210,9 @@ fn constant_not(o: Constant) -> Option<Constant> { use self::Constant::*; match o { Bool(b) => Some(Bool(!b)), - Int(value, LitIntType::Signed(ity), Sign::Plus) if value != ::std::u64::MAX => Some(Int(value + 1, LitIntType::Signed(ity), Sign::Minus)), + Int(value, LitIntType::Signed(ity), Sign::Plus) if value != ::std::u64::MAX => { + Some(Int(value + 1, LitIntType::Signed(ity), Sign::Minus)) + } Int(0, LitIntType::Signed(ity), Sign::Minus) => Some(Int(1, LitIntType::Signed(ity), Sign::Minus)), Int(value, LitIntType::Signed(ity), Sign::Minus) => Some(Int(value - 1, LitIntType::Signed(ity), Sign::Plus)), Int(value, LitIntType::Unsigned(ity), Sign::Plus) => { @@ -224,7 +226,7 @@ fn constant_not(o: Constant) -> Option<Constant> { } // refuse to guess }; Some(Int(!value & mask, LitIntType::Unsigned(ity), Sign::Plus)) - }, + } _ => None, } } @@ -388,7 +390,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { (Constant::Byte(l8), Constant::Byte(r8)) => l8.checked_add(r8).map(Constant::Byte), (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { add_ints(l64, r64, lty, rty, lsign, rsign) - }, + } // TODO: float (would need bignum library?) _ => None, } @@ -406,7 +408,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { add_ints(l64, r64, lty, rty, lsign, neg_sign(rsign)) - }, + } _ => None, } }) @@ -438,7 +440,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { match (l, r) { (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { f(l64, r64).and_then(|value| { - let sign = if lsign == rsign { Sign::Plus } else { Sign::Minus }; + let sign = if lsign == rsign { + Sign::Plus + } else { + Sign::Minus + }; unify_int_type(lty, rty).map(|ty| Constant::Int(value, ty, sign)) }) } @@ -504,19 +510,28 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn add_ints(l64: u64, r64: u64, lty: LitIntType, rty: LitIntType, lsign: Sign, rsign: Sign) -> Option<Constant> { - let ty = if let Some(ty) = unify_int_type(lty, rty) { ty } else { return None; }; + let ty = if let Some(ty) = unify_int_type(lty, rty) { + ty + } else { + return None; + }; + match (lsign, rsign) { (Sign::Plus, Sign::Plus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Plus)), - (Sign::Plus, Sign::Minus) => if r64 > l64 { - Some(Constant::Int(r64 - l64, ty, Sign::Minus)) - } else { - Some(Constant::Int(l64 - r64, ty, Sign::Plus)) - }, - (Sign::Minus, Sign::Minus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Minus)), - (Sign::Minus, Sign::Plus) => if l64 > r64 { - Some(Constant::Int(l64 - r64, ty, Sign::Minus)) - } else { - Some(Constant::Int(r64 - l64, ty, Sign::Plus)) - }, + (Sign::Plus, Sign::Minus) => { + if r64 > l64 { + Some(Constant::Int(r64 - l64, ty, Sign::Minus)) + } else { + Some(Constant::Int(l64 - r64, ty, Sign::Plus)) + } + } + (Sign::Minus, Sign::Minus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Minus)), + (Sign::Minus, Sign::Plus) => { + if l64 > r64 { + Some(Constant::Int(l64 - r64, ty, Sign::Minus)) + } else { + Some(Constant::Int(r64 - l64, ty, Sign::Plus)) + } + } } } diff --git a/src/copies.rs b/src/copies.rs index d97745203f0..1995e2901ad 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -61,11 +61,7 @@ pub struct CopyAndPaste; impl LintPass for CopyAndPaste { fn get_lints(&self) -> LintArray { - lint_array![ - IFS_SAME_COND, - IF_SAME_THEN_ELSE, - MATCH_SAME_ARMS - ] + lint_array![IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS] } } @@ -89,35 +85,43 @@ impl LateLintPass for CopyAndPaste { /// Implementation of `IF_SAME_THEN_ELSE`. fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { - let hash : &Fn(&&Block) -> u64 = &|block| -> u64 { + let hash: &Fn(&&Block) -> u64 = &|block| -> u64 { let mut h = SpanlessHash::new(cx); h.hash_block(block); h.finish() }; - let eq : &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { + let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same(blocks, hash, eq) { - span_note_and_lint(cx, IF_SAME_THEN_ELSE, j.span, "this `if` has identical blocks", i.span, "same as this"); + span_note_and_lint(cx, + IF_SAME_THEN_ELSE, + j.span, + "this `if` has identical blocks", + i.span, + "same as this"); } } /// Implementation of `IFS_SAME_COND`. fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { - let hash : &Fn(&&Expr) -> u64 = &|expr| -> u64 { + let hash: &Fn(&&Expr) -> u64 = &|expr| -> u64 { let mut h = SpanlessHash::new(cx); h.hash_expr(expr); h.finish() }; - let eq : &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { - SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) - }; + let eq: &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; if let Some((i, j)) = search_same(conds, hash, eq) { - span_note_and_lint(cx, IFS_SAME_COND, j.span, "this `if` has the same condition as a previous if", i.span, "same as this"); + span_note_and_lint(cx, + IFS_SAME_COND, + j.span, + "this `if` has the same condition as a previous if", + i.span, + "same as this"); } } @@ -137,7 +141,12 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { if let Some((i, j)) = search_same(&**arms, hash, eq) { - span_note_and_lint(cx, MATCH_SAME_ARMS, j.body.span, "this `match` has identical arm bodies", i.body.span, "same as this"); + span_note_and_lint(cx, + MATCH_SAME_ARMS, + j.body.span, + "this `match` has identical arm bodies", + i.body.span, + "same as this"); } } } @@ -155,8 +164,7 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { if let Some(ref else_expr) = *else_expr { expr = else_expr; - } - else { + } else { break; } } @@ -188,7 +196,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned 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); @@ -210,7 +218,12 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned bindings_impl(cx, pat, map); } } - PatKind::TupleStruct(..) | PatKind::Lit(..) | PatKind::QPath(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (), + PatKind::TupleStruct(..) | + PatKind::Lit(..) | + PatKind::QPath(..) | + PatKind::Range(..) | + PatKind::Wild | + PatKind::Path(..) => (), } } @@ -219,36 +232,35 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned result } -fn search_same<T, Hash, Eq>(exprs: &[T], - hash: Hash, - eq: Eq) -> Option<(&T, &T)> -where Hash: Fn(&T) -> u64, - Eq: Fn(&T, &T) -> bool { +fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> + where Hash: Fn(&T) -> u64, + Eq: Fn(&T, &T) -> bool +{ // common cases if exprs.len() < 2 { return None; - } - else if exprs.len() == 2 { + } else if exprs.len() == 2 { return if eq(&exprs[0], &exprs[1]) { Some((&exprs[0], &exprs[1])) - } - else { + } else { None - } + }; } - let mut map : HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); + let mut map: HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); for expr in exprs { match map.entry(hash(expr)) { Entry::Occupied(o) => { for o in o.get() { if eq(&o, expr) { - return Some((&o, expr)) + return Some((&o, expr)); } } } - Entry::Vacant(v) => { v.insert(vec![expr]); } + Entry::Vacant(v) => { + v.insert(vec![expr]); + } } } diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 99157e76969..3f956f1fc41 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -1,13 +1,13 @@ //! calculate cyclomatic complexity and warn about overly complex functions use rustc::lint::*; -use rustc_front::hir::*; use rustc::middle::cfg::CFG; use rustc::middle::ty; -use syntax::codemap::Span; -use syntax::attr::*; -use syntax::ast::Attribute; +use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr}; +use syntax::ast::Attribute; +use syntax::attr::*; +use syntax::codemap::Span; use utils::{in_macro, LimitStack, span_help_and_lint}; diff --git a/src/drop_ref.rs b/src/drop_ref.rs index 6dc3d734196..5f7e67925bd 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -1,8 +1,7 @@ use rustc::lint::*; -use rustc_front::hir::*; use rustc::middle::ty; +use rustc_front::hir::*; use syntax::codemap::Span; - use utils::DROP_PATH; use utils::{match_def_path, span_note_and_lint}; diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index f8afdf627e2..5b542a7d67b 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -1,13 +1,13 @@ //! lint on `use`ing all variants of an enum -use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; -use rustc_front::hir::*; use rustc::front::map::Node::NodeItem; use rustc::front::map::definitions::DefPathData; +use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; use rustc::middle::ty::TyEnum; -use utils::span_lint; -use syntax::codemap::Span; +use rustc_front::hir::*; use syntax::ast::NodeId; +use syntax::codemap::Span; +use utils::span_lint; /// **What it does:** Warns when `use`ing all variants of an enum /// diff --git a/src/enum_variants.rs b/src/enum_variants.rs index 8ad7adf0077..a95fca8c6c4 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -1,10 +1,9 @@ //! lint on enum variants that are prefixed or suffixed by the same characters use rustc::lint::*; -use syntax::attr::*; use syntax::ast::*; +use syntax::attr::*; use syntax::parse::token::InternedString; - use utils::span_help_and_lint; use utils::{camel_case_from, camel_case_until}; @@ -95,7 +94,7 @@ impl EarlyLintPass for EnumVariantNames { } else if !post.is_empty() { ("post", post) } else { - return + return; }; span_help_and_lint(cx, ENUM_VARIANT_NAMES, diff --git a/src/eq_op.rs b/src/eq_op.rs index fc1cab2cd71..09ac6325f96 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc_front::util as ast_util; - use utils::{SpanlessEq, span_lint}; /// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, diff --git a/src/escape.rs b/src/escape.rs index 60bfbbc59c3..bcc1cb16870 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,13 +1,13 @@ -use rustc::lint::*; use rustc::front::map::Node::{NodeExpr, NodeStmt}; -use rustc_front::hir::*; -use rustc_front::intravisit as visit; -use rustc::middle::ty; -use rustc::middle::ty::adjustment::AutoAdjustment; +use rustc::lint::*; use rustc::middle::expr_use_visitor::*; use rustc::middle::infer; use rustc::middle::mem_categorization::{cmt, Categorization}; +use rustc::middle::ty::adjustment::AutoAdjustment; +use rustc::middle::ty; use rustc::util::nodemap::NodeSet; +use rustc_front::hir::*; +use rustc_front::intravisit as visit; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::span_lint; diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 2522b1517a6..e28411cc79c 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,10 +1,8 @@ use rustc::lint::*; -use rustc_front::hir::*; use rustc::middle::ty; - +use rustc_front::hir::*; use utils::{snippet_opt, span_lint_and_then, is_adjusted}; - #[allow(missing_copy_implementations)] pub struct EtaPass; diff --git a/src/identity_op.rs b/src/identity_op.rs index b033b234122..8a0da7bcd9f 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,8 +1,7 @@ +use consts::{constant_simple, Constant, Sign}; use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; - -use consts::{constant_simple, Constant, Sign}; use utils::{span_lint, snippet, in_macro}; /// **What it does:** This lint checks for identity operations, e.g. `x + 0`. diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 9bfb3b87ed1..a2ab7246942 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -1,8 +1,8 @@ //! lint when items are used after statements use rustc::lint::*; -use syntax::attr::*; use syntax::ast::*; +use syntax::attr::*; use utils::in_macro; /// **What it does:** This lints checks for items declared after some statement in a block diff --git a/src/len_zero.rs b/src/len_zero.rs index 222de03f006..6963592592d 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,13 +1,10 @@ use rustc::lint::*; -use rustc_front::hir::*; -use syntax::ast::Name; -use syntax::ptr::P; -use syntax::codemap::{Span, Spanned}; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; - -use syntax::ast::{Lit, LitKind}; - +use rustc_front::hir::*; +use syntax::ast::{Lit, LitKind, Name}; +use syntax::codemap::{Span, Spanned}; +use syntax::ptr::P; use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; /// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. diff --git a/src/lifetimes.rs b/src/lifetimes.rs index f30163f4656..72fdba07d32 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -1,11 +1,10 @@ -use rustc_front::hir::*; use reexport::*; use rustc::lint::*; -use syntax::codemap::Span; -use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; use rustc::middle::def::Def; +use rustc_front::hir::*; +use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; use std::collections::{HashSet, HashMap}; - +use syntax::codemap::Span; use utils::{in_external_macro, span_lint}; /// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. diff --git a/src/loops.rs b/src/loops.rs index acfb6c150d5..ce2ae94cd30 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -351,9 +351,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 let pat_extent = cx.tcx.region_maps.var_scope(pat.id); @@ -438,8 +438,12 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // who think that this will iterate from the larger value to the // smaller value. let (sup, eq) = match (start_idx, stop_idx) { - (ConstVal::Int(start_idx), ConstVal::Int(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), - (ConstVal::Uint(start_idx), ConstVal::Uint(stop_idx)) => (start_idx > stop_idx, start_idx == stop_idx), + (ConstVal::Int(start_idx), ConstVal::Int(stop_idx)) => { + (start_idx > stop_idx, start_idx == stop_idx) + } + (ConstVal::Uint(start_idx), ConstVal::Uint(stop_idx)) => { + (start_idx > stop_idx, start_idx == stop_idx) + } _ => (false, false), }; @@ -515,26 +519,25 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { let ty = cx.tcx.expr_ty(arg); if match_type(cx, ty, &OPTION_PATH) { - span_help_and_lint( - cx, - FOR_LOOP_OVER_OPTION, - arg.span, - &format!("for loop over `{0}`, which is an `Option`. This is more readably written as \ - an `if let` statement.", snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", - snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_")) - ); - } - else if match_type(cx, ty, &RESULT_PATH) { - span_help_and_lint( - cx, - FOR_LOOP_OVER_RESULT, - arg.span, - &format!("for loop over `{0}`, which is a `Result`. This is more readably written as \ - an `if let` statement.", snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", - snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_")) - ); + span_help_and_lint(cx, + FOR_LOOP_OVER_OPTION, + arg.span, + &format!("for loop over `{0}`, which is an `Option`. This is more readably written as an \ + `if let` statement.", + snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_"))); + } else if match_type(cx, ty, &RESULT_PATH) { + span_help_and_lint(cx, + FOR_LOOP_OVER_RESULT, + arg.span, + &format!("for loop over `{0}`, which is a `Result`. This is more readably written as an \ + `if let` statement.", + snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_"))); } } @@ -590,31 +593,29 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), - _ => return + _ => return, }; let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); let arg_span = if let ExprAddrOf(_, ref expr) = arg.node { expr.span - } - else { + } else { arg.span }; - if match_type(cx, ty, &HASHMAP_PATH) || - match_type(cx, ty, &BTREEMAP_PATH) { + if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) { span_lint_and_then(cx, - FOR_KV_MAP, - expr.span, - &format!("you seem to want to iterate on a map's {}", kind), - |db| { - db.span_suggestion(expr.span, - "use the corresponding method", - format!("for {} in {}.{}() {{...}}", - snippet(cx, *pat_span, ".."), - snippet(cx, arg_span, ".."), - kind)); - }); + FOR_KV_MAP, + expr.span, + &format!("you seem to want to iterate on a map's {}", kind), + |db| { + db.span_suggestion(expr.span, + "use the corresponding method", + format!("for {} in {}.{}() {{...}}", + snippet(cx, *pat_span, ".."), + snippet(cx, arg_span, ".."), + kind)); + }); } } } @@ -632,7 +633,7 @@ fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { }; walk_expr(&mut visitor, body); !visitor.used - }, + } _ => false, } } @@ -647,7 +648,7 @@ impl<'a> Visitor<'a> for UsedVisitor { if let ExprPath(None, ref path) = expr.node { if path.segments.len() == 1 && path.segments[0].identifier == self.var { self.used = true; - return + return; } } diff --git a/src/map_clone.rs b/src/map_clone.rs index c83e4ca64ff..8a4e1d770dc 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,8 +1,10 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::{CLONE_PATH, OPTION_PATH}; -use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint}; -use utils::{walk_ptrs_ty, walk_ptrs_ty_depth}; +use utils::{ + is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, + walk_ptrs_ty, walk_ptrs_ty_depth +}; /// **What it does:** This lint checks for mapping clone() over an iterator. /// diff --git a/src/matches.rs b/src/matches.rs index b8ea4f2b1b0..35c0dbb3950 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -7,7 +7,6 @@ use rustc_front::hir::*; use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; - use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; use utils::{match_type, snippet, span_lint, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; @@ -139,20 +138,20 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && arms[1].guard.is_none() { - let els = if is_unit_expr(&arms[1].body) { - None - } else if let ExprBlock(_) = arms[1].body.node { - // matches with blocks that contain statements are prettier as `if let + else` - Some(&*arms[1].body) - } else { - // allow match arms with just expressions - return; - }; - let ty = cx.tcx.expr_ty(ex); - if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { - check_single_match_single_pattern(cx, ex, arms, expr, els); - check_single_match_opt_like(cx, ex, arms, expr, ty, els); - } + let els = if is_unit_expr(&arms[1].body) { + None + } else if let ExprBlock(_) = arms[1].body.node { + // matches with blocks that contain statements are prettier as `if let + else` + Some(&*arms[1].body) + } else { + // allow match arms with just expressions + return; + }; + let ty = cx.tcx.expr_ty(ex); + if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { + check_single_match_single_pattern(cx, ex, arms, expr, els); + check_single_match_opt_like(cx, ex, arms, expr, ty, els); + } } } @@ -194,11 +193,11 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: let path = match arms[1].pats[0].node { PatKind::TupleStruct(ref path, Some(ref inner)) => { // contains any non wildcard patterns? e.g. Err(err) - if inner.iter().any(|pat| if let PatKind::Wild = pat.node { false } else { true }) { + if inner.iter().any(|pat| pat.node != PatKind::Wild) { return; } path.to_string() - }, + } PatKind::TupleStruct(ref path, None) => path.to_string(), PatKind::Ident(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), _ => return, diff --git a/src/methods.rs b/src/methods.rs index c67e2eade14..6ef779cd79e 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,6 +1,7 @@ use rustc::lint::*; -use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; +use rustc::middle::cstore::CrateStore; use rustc::middle::subst::{Subst, TypeSpace}; use rustc::middle::ty; use rustc_front::hir::*; @@ -8,14 +9,12 @@ use std::borrow::Cow; use std::{fmt, iter}; use syntax::codemap::Span; use syntax::ptr::P; - use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, match_type, method_chain_args, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, - VEC_PATH,}; + VEC_PATH}; use utils::MethodArgs; -use rustc::middle::cstore::CrateStore; #[derive(Clone)] pub struct MethodsPass; @@ -439,12 +438,10 @@ impl LateLintPass for MethodsPass { if let Some(&ret_ty) = ret_ty { ret_ty.walk().any(|t| t == ty) - } - else { + } else { false } - } - else { + } else { false }; @@ -961,9 +958,9 @@ impl SelfKind { fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool { match (self, slf) { (&SelfKind::Value, &SelfValue(_)) | - (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) | - (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) | - (&SelfKind::No, &SelfStatic) => true, + (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) | + (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) | + (&SelfKind::No, &SelfStatic) => true, (&SelfKind::Ref, &SelfValue(_)) | (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), _ => false, @@ -973,10 +970,10 @@ impl SelfKind { fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool { match (self, &ty.node) { (&SelfKind::Value, &TyPath(..)) | - (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) | - (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, + (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) | + (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, (&SelfKind::Ref, &TyPath(..)) | - (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, + (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, _ => false, } } diff --git a/src/minmax.rs b/src/minmax.rs index 03e2d0a4ec3..0560bf15604 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,11 +1,9 @@ +use consts::{Constant, constant_simple}; use rustc::lint::*; use rustc_front::hir::*; -use syntax::ptr::P; use std::cmp::{PartialOrd, Ordering}; - -use consts::{Constant, constant_simple}; +use syntax::ptr::P; use utils::{match_def_path, span_lint}; -use self::MinMax::{Min, Max}; /// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. /// @@ -36,7 +34,7 @@ impl LateLintPass for MinMaxPass { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { - (_, None) | (Max, Some(Ordering::Less)) | (Min, Some(Ordering::Greater)) => (), + (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); } @@ -58,9 +56,9 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &' let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); if match_def_path(cx, def_id, &["core", "cmp", "min"]) { - fetch_const(args, Min) + fetch_const(args, MinMax::Min) } else if match_def_path(cx, def_id, &["core", "cmp", "max"]) { - fetch_const(args, Max) + fetch_const(args, MinMax::Max) } else { None } diff --git a/src/misc.rs b/src/misc.rs index 5c154dc59e2..fae780e4ced 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,15 +1,14 @@ +use reexport::*; use rustc::lint::*; -use syntax::ptr::P; +use rustc::middle::const_eval::ConstVal::Float; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::eval_const_expr_partial; +use rustc::middle::ty; use rustc_front::hir::*; -use reexport::*; +use rustc_front::intravisit::FnKind; use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned, ExpnFormat}; -use rustc_front::intravisit::FnKind; -use rustc::middle::ty; -use rustc::middle::const_eval::ConstVal::Float; -use rustc::middle::const_eval::eval_const_expr_partial; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; - +use syntax::ptr::P; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; use utils::{span_lint_and_then, walk_ptrs_ty, is_integer_literal, implements_trait}; diff --git a/src/misc_early.rs b/src/misc_early.rs index bbed9ad4996..604e6002103 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -1,11 +1,8 @@ use rustc::lint::*; - use std::collections::HashMap; - use syntax::ast::*; use syntax::codemap::Span; use syntax::visit::FnKind; - use utils::{span_lint, span_help_and_lint}; /// **What it does:** This lint checks for structure field patterns bound to wildcards. diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 1759a89242b..c8f86330b93 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,7 +1,6 @@ use rustc::lint::*; -use rustc_front::hir::*; use rustc::middle::ty::{TypeAndMut, TyRef}; - +use rustc_front::hir::*; use utils::{in_external_macro, span_lint}; /// **What it does:** This lint checks for instances of `mut mut` references. diff --git a/src/mut_reference.rs b/src/mut_reference.rs index ea2c00bab94..0e5b038f27d 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -1,8 +1,8 @@ use rustc::lint::*; -use rustc_front::hir::*; -use utils::span_lint; use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; +use rustc_front::hir::*; use syntax::ptr::P; +use utils::span_lint; /// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. /// diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 8a51ba27b8e..c8f5e3c7919 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -3,12 +3,10 @@ //! This lint is **warn** by default use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; +use rustc::middle::subst::ParamSpace; +use rustc::middle::ty; use rustc_front::hir::Expr; - use syntax::ast; -use rustc::middle::ty; -use rustc::middle::subst::ParamSpace; - use utils::{span_lint, MUTEX_PATH, match_type}; /// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do. diff --git a/src/needless_bool.rs b/src/needless_bool.rs index fe46988dccb..625f8b0ca78 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -4,10 +4,8 @@ use rustc::lint::*; use rustc_front::hir::*; - use syntax::ast::LitKind; use syntax::codemap::Spanned; - use utils::{span_lint, span_lint_and_then, snippet}; /// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. diff --git a/src/needless_features.rs b/src/needless_features.rs index 646ebbbd015..f80ac48320e 100644 --- a/src/needless_features.rs +++ b/src/needless_features.rs @@ -4,7 +4,6 @@ use rustc::lint::*; use rustc_front::hir::*; - use utils::span_lint; use utils; diff --git a/src/needless_update.rs b/src/needless_update.rs index d18930c8ccc..e3359469150 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -1,7 +1,6 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::middle::ty::TyStruct; use rustc_front::hir::{Expr, ExprStruct}; - use utils::span_lint; /// **What it does:** This lint warns on needlessly including a base struct on update when all fields are changed anyway. diff --git a/src/no_effect.rs b/src/no_effect.rs index 0df5ede82da..65dfeb0d4be 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,10 +1,7 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::middle::def::Def; -use rustc_front::hir::{Expr, Expr_}; -use rustc_front::hir::{Stmt, StmtSemi}; - -use utils::in_macro; -use utils::span_lint; +use rustc_front::hir::{Expr, Expr_, Stmt, StmtSemi}; +use utils::{in_macro, span_lint}; /// **What it does:** This lint checks for statements which have no effect. /// diff --git a/src/open_options.rs b/src/open_options.rs index 8b1c4a90fdf..e3f61afcf1c 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -1,8 +1,8 @@ use rustc::lint::*; use rustc_front::hir::{Expr, ExprMethodCall, ExprLit}; -use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; -use syntax::codemap::{Span, Spanned}; use syntax::ast::LitKind; +use syntax::codemap::{Span, Spanned}; +use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; /// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. /// diff --git a/src/panic.rs b/src/panic.rs index b76def8d2f3..60a3ce1a461 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::LitKind; - use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; /// **What it does:** This lint checks for missing parameters in `panic!`. diff --git a/src/precedence.rs b/src/precedence.rs index d498510f97a..7e24f55d1b4 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,7 +1,6 @@ use rustc::lint::*; -use syntax::codemap::Spanned; use syntax::ast::*; - +use syntax::codemap::Spanned; use utils::{span_lint, snippet}; /// **What it does:** This lint checks for operations where precedence may be unclear and suggests to add parentheses. Currently it catches the following: diff --git a/src/print.rs b/src/print.rs index 3c10b4bed13..d7d83bfb437 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,6 +1,6 @@ +use rustc::front::map::Node::{NodeItem, NodeImplItem}; use rustc::lint::*; use rustc_front::hir::*; -use rustc::front::map::Node::{NodeItem, NodeImplItem}; use utils::{FMT_ARGUMENTV1_NEW_PATH, DEBUG_FMT_METHOD_PATH, IO_PRINT_PATH}; use utils::{is_expn_of, match_path, span_lint}; diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 707adcfeb07..c02e5609b8c 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -2,13 +2,12 @@ //! //! This lint is **warn** by default -use rustc::lint::*; -use rustc_front::hir::*; use rustc::front::map::NodeItem; +use rustc::lint::*; use rustc::middle::ty; - -use utils::{span_lint, match_type}; +use rustc_front::hir::*; use utils::{STRING_PATH, VEC_PATH}; +use utils::{span_lint, match_type}; /// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. /// diff --git a/src/regex.rs b/src/regex.rs index 745d685ec80..f58b6319d57 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,13 +1,13 @@ use regex_syntax; -use std::error::Error; +use rustc::lint::*; +use rustc::middle::const_eval::EvalHint::ExprTypeChecked; +use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc_front::hir::*; use std::collections::HashSet; +use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; -use rustc_front::hir::*; -use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::lint::*; use utils::{is_expn_of, match_path, match_type, REGEX_NEW_PATH, span_lint, span_help_and_lint}; @@ -54,7 +54,7 @@ declare_lint! { #[derive(Clone, Default)] pub struct RegexPass { spans: HashSet<Span>, - last: Option<NodeId> + last: Option<NodeId>, } impl LintPass for RegexPass { @@ -86,10 +86,10 @@ impl LateLintPass for RegexPass { self.last = Some(block.id); }} } - + fn check_block_post(&mut self, _: &LateContext, block: &Block) { if self.last.map_or(false, |id| block.id == id) { - self.last = None; + self.last = None; } } @@ -145,7 +145,7 @@ impl LateLintPass for RegexPass { fn str_span(base: Span, s: &str, c: usize) -> Span { let lo = match s.char_indices().nth(c) { Some((b, _)) => base.lo + BytePos(b as u32), - _ => base.hi + _ => base.hi, }; Span{ lo: lo, hi: lo, ..base } } @@ -153,7 +153,7 @@ fn str_span(base: Span, s: &str, c: usize) -> Span { fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { match eval_const_expr_partial(cx.tcx, e, ExprTypeChecked, None) { Ok(ConstVal::Str(r)) => Some(r), - _ => None + _ => None, } } @@ -165,20 +165,21 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { Expr::Literal {..} => Some("consider using `str::contains`"), Expr::Concat(ref exprs) => { match exprs.len() { - 2 => match (&exprs[0], &exprs[1]) { - (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), - (&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"), - (&Expr::Literal {..}, &Expr::EndText) => Some("consider using `str::ends_with`"), - _ => None, - }, + 2 => { + match (&exprs[0], &exprs[1]) { + (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), + (&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"), + (&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]) { Some("consider using `==` on `str`s") - } - else { + } else { None } - }, + } _ => None, } } diff --git a/src/returns.rs b/src/returns.rs index bfddee797b8..43ea3780173 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -1,6 +1,5 @@ use rustc::lint::*; use syntax::ast::*; -// use reexport::*; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; diff --git a/src/shadow.rs b/src/shadow.rs index 206fa492419..baf5c9b8872 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -1,12 +1,10 @@ -use std::ops::Deref; -use rustc_front::hir::*; use reexport::*; -use syntax::codemap::Span; -use rustc_front::intravisit::{Visitor, FnKind}; - use rustc::lint::*; use rustc::middle::def::Def; - +use rustc_front::hir::*; +use rustc_front::intravisit::{Visitor, FnKind}; +use std::ops::Deref; +use syntax::codemap::Span; use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; /// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. diff --git a/src/strings.rs b/src/strings.rs index a7dca02c967..fdba6302a46 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -6,10 +6,9 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; - -use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; -use utils::SpanlessEq; use utils::STRING_PATH; +use utils::SpanlessEq; +use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). /// diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs index 417ec540856..c945fd7148e 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -1,6 +1,5 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; - use utils::is_adjusted; use utils::span_lint; diff --git a/src/types.rs b/src/types.rs index eec8bd63eb7..248aab32baa 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,13 +1,12 @@ +use reexport::*; use rustc::lint::*; +use rustc::middle::const_eval; +use rustc::middle::ty; use rustc_front::hir::*; -use reexport::*; -use rustc_front::util::{is_comparison_binop, binop_to_string}; -use syntax::codemap::Span; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; -use rustc::middle::ty; -use rustc::middle::const_eval; +use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::ast::{IntTy, UintTy, FloatTy}; - +use syntax::codemap::Span; use utils::*; /// Handles all the linting of funky types @@ -618,7 +617,7 @@ enum AbsurdComparisonResult { } fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) - -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { + -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { use types::ExtremeType::*; use types::AbsurdComparisonResult::*; type Extr<'a> = ExtremeExpr<'a>; @@ -704,7 +703,10 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx _ => return None, }; - Some(ExtremeExpr { which: which, expr: expr }) + Some(ExtremeExpr { + which: which, + expr: expr, + }) } impl LateLintPass for AbsurdExtremeComparisons { @@ -721,16 +723,20 @@ impl LateLintPass for AbsurdExtremeComparisons { let conclusion = match result { AlwaysFalse => "this comparison is always false".to_owned(), AlwaysTrue => "this comparison is always true".to_owned(), - InequalityImpossible => - format!("the case where the two sides are not equal never occurs, \ - consider using {} == {} instead", + InequalityImpossible => { + format!("the case where the two sides are not equal never occurs, consider using {} == {} \ + instead", snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs")), + snippet(cx, rhs.span, "rhs")) + } }; let help = format!("because {} is the {} value for this type, {}", snippet(cx, culprit.expr.span, "x"), - match culprit.which { Minimum => "minimum", Maximum => "maximum" }, + match culprit.which { + Minimum => "minimum", + Maximum => "maximum", + }, conclusion); span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); diff --git a/src/unicode.rs b/src/unicode.rs index c8d810b9e71..0f21822ea08 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,11 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; -use syntax::codemap::Span; - use syntax::ast::LitKind; - +use syntax::codemap::Span; use unicode_normalization::UnicodeNormalization; - use utils::{snippet, span_help_and_lint}; /// **What it does:** This lint checks for the unicode zero-width space in the code. diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 631bcb1b100..faa2082b7d0 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -19,11 +19,17 @@ pub struct SpanlessEq<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { - SpanlessEq { cx: cx, ignore_fn: false } + SpanlessEq { + cx: cx, + ignore_fn: false, + } } pub fn ignore_fn(self) -> Self { - SpanlessEq { cx: self.cx, ignore_fn: true } + SpanlessEq { + cx: self.cx, + ignore_fn: true, + } } /// Check whether two statements are the same. @@ -40,7 +46,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } } (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | - (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), + (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), _ => false, } } @@ -48,7 +54,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { /// Check whether two blocks are the same. pub fn eq_block(&self, left: &Block, right: &Block) -> bool { over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && - both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) + both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) } // ok, it’s a big function, but mostly one big match with simples cases @@ -77,9 +83,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&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) - } + (&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r), (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) } @@ -267,7 +271,10 @@ pub struct SpanlessHash<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { - SpanlessHash { cx: cx, s: SipHasher::new() } + SpanlessHash { + cx: cx, + s: SipHasher::new(), + } } pub fn finish(&self) -> u64 { @@ -389,7 +396,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { let c: fn(_) -> _ = ExprLit; c.hash(&mut self.s); l.hash(&mut self.s); - }, + } ExprLoop(ref b, ref i) => { let c: fn(_, _) -> _ = ExprLoop; c.hash(&mut self.s); @@ -466,7 +473,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { 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); @@ -491,7 +498,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { c.hash(&mut self.s); self.hash_exprs(v); - }, + } ExprWhile(ref cond, ref b, l) => { let c: fn(_, _, _) -> _ = ExprWhile; c.hash(&mut self.s); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index b9dd9359c66..a8708eb8f7f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,7 +9,7 @@ use std::borrow::Cow; use std::mem; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use syntax::ast::{LitKind, self}; +use syntax::ast::{self, LitKind}; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index dbfa2744189..1d119b05176 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -1,8 +1,7 @@ +use consts::{Constant, constant_simple, FloatWidth}; use rustc::lint::*; use rustc_front::hir::*; - use utils::span_help_and_lint; -use consts::{Constant, constant_simple, FloatWidth}; /// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists /// `of 0.0/0.0`, which is always NaN. It is more clear to replace instances of -- cgit 1.4.1-3-g733a5 From c1b2fe31b70e2b7293b3aea7cfb8b1ed084b9334 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 24 Feb 2016 20:52:47 +0100 Subject: Use `span_suggestion` in `len_zero` --- src/len_zero.rs | 20 ++++++++++++-------- tests/compile-fail/len_zero.rs | 25 ++++++++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 222de03f006..f99ea1e6fd5 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -8,7 +8,7 @@ use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; use syntax::ast::{Lit, LitKind}; -use utils::{get_item_name, snippet, span_lint, walk_ptrs_ty}; +use utils::{get_item_name, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; /// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. /// @@ -80,7 +80,6 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { } if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - // span_lint(cx, LEN_WITHOUT_IS_EMPTY, item.span, &format!("trait {}", item.ident)); for i in trait_items { if is_named_self(i, "len") { span_lint(cx, @@ -151,12 +150,17 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitKind::Int(0, _), ..} = *lit { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { - span_lint(cx, - LEN_ZERO, - span, - &format!("consider replacing the len comparison with `{}{}.is_empty()`", - op, - snippet(cx, args[0].span, "_"))); + span_lint_and_then(cx, + LEN_ZERO, + span, + "length comparison to zero", + |db| { + db.span_suggestion(span, + "consider using `is_empty`", + format!("{}{}.is_empty()", + op, + snippet(cx, args[0].span, "_"))); + }); } } } diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 626e5557fb6..9814a1c2d7d 100644 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -69,7 +69,10 @@ impl HasWrongIsEmpty { #[deny(len_zero)] fn main() { let x = [1, 2]; - if x.len() == 0 { //~ERROR consider replacing the len comparison + if x.len() == 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION x.is_empty() println!("This should not happen!"); } @@ -84,19 +87,31 @@ fn main() { } let hie = HasIsEmpty; - if hie.len() == 0 { //~ERROR consider replacing the len comparison + if hie.len() == 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION hie.is_empty() println!("Or this!"); } - if hie.len() != 0 { //~ERROR consider replacing the len comparison + if hie.len() != 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION !hie.is_empty() println!("Or this!"); } - if hie.len() > 0 { //~ERROR consider replacing the len comparison + if hie.len() > 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION !hie.is_empty() println!("Or this!"); } assert!(!hie.is_empty()); let wie : &WithIsEmpty = &Wither; - if wie.len() == 0 { //~ERROR consider replacing the len comparison + if wie.len() == 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION wie.is_empty() println!("Or this!"); } assert!(!wie.is_empty()); -- cgit 1.4.1-3-g733a5 From 7b1a0a94348bd429b863ac16dfa0cc9c79e73c90 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 24 Feb 2016 20:53:15 +0100 Subject: Macro check `len_zero` --- src/len_zero.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index f99ea1e6fd5..f63e733d65b 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -8,7 +8,7 @@ use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; use syntax::ast::{Lit, LitKind}; -use utils::{get_item_name, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; +use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; /// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. /// @@ -51,6 +51,10 @@ impl LintPass for LenZero { impl LateLintPass for LenZero { fn check_item(&mut self, cx: &LateContext, item: &Item) { + if in_macro(cx, item.span) { + return; + } + match item.node { ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), ItemImpl(_, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items), @@ -59,6 +63,10 @@ impl LateLintPass for LenZero { } fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_macro(cx, expr.span) { + return; + } + if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = expr.node { match cmp { BiEq => check_cmp(cx, expr.span, left, right, ""), -- cgit 1.4.1-3-g733a5 From 783437eef0380dff8e1a6a4d049366aa54011f48 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 24 Feb 2016 20:54:35 +0100 Subject: Use `span_suggestion` in loops lints --- src/loops.rs | 13 ++++++++----- tests/compile-fail/while_loop.rs | 20 ++++++++++++++++---- 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index acfb6c150d5..602de0eebcb 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -271,14 +271,17 @@ impl LateLintPass for LoopsPass { } else { expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") }; - span_help_and_lint(cx, + span_lint_and_then(cx, WHILE_LET_LOOP, expr.span, "this loop could be written as a `while let` loop", - &format!("try\nwhile let {} = {} {}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, ".."), - loop_body)); + |db| { + let sug = format!("while let {} = {} {}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, ".."), + loop_body); + db.span_suggestion(expr.span, "try", sug); + }); } } _ => (), diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index ee8e4622e0e..bbb76cfbfaf 100644 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -6,7 +6,10 @@ fn main() { let y = Some(true); - loop { //~ERROR + loop { + //~^ERROR this loop could be written as a `while let` loop + //~|HELP try + //~|SUGGESTION while let Some(_x) = y { if let Some(_x) = y { let _v = 1; } else { @@ -19,13 +22,19 @@ fn main() { } break; } - loop { //~ERROR + loop { + //~^ERROR this loop could be written as a `while let` loop + //~|HELP try + //~|SUGGESTION while let Some(_x) = y { match y { Some(_x) => true, None => break }; } - loop { //~ERROR + loop { + //~^ERROR this loop could be written as a `while let` loop + //~|HELP try + //~|SUGGESTION while let Some(x) = y { let x = match y { Some(x) => x, None => break @@ -33,7 +42,10 @@ fn main() { let _x = x; let _str = "foo"; } - loop { //~ERROR + loop { + //~^ERROR this loop could be written as a `while let` loop + //~|HELP try + //~|SUGGESTION while let Some(x) = y { let x = match y { Some(x) => x, None => break, -- cgit 1.4.1-3-g733a5 From 62cbd877281a9d8dd8b4948dd73799319eb16846 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 26 Feb 2016 12:45:55 +0100 Subject: Fix false positive in `FOR_KV_MAP` and `&mut` refs --- src/loops.rs | 19 +++++++++---------- tests/compile-fail/for_loop.rs | 7 +++++++ 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index a4c0e349495..3eb013da6d9 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -588,24 +588,23 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex } } -// Check for the FOR_KV_MAP lint. +/// Check for the FOR_KV_MAP lint. fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { if let PatKind::Tup(ref pat) = pat.node { if pat.len() == 2 { - let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), _ => return, }; - let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); - let arg_span = if let ExprAddrOf(_, ref expr) = arg.node { - expr.span - } else { - arg.span + let arg_span = match arg.node { + ExprAddrOf(MutImmutable, ref expr) => expr.span, + ExprAddrOf(MutMutable, _) => return, // for _ in &mut _, there is no {values,keys}_mut method + _ => arg.span, }; + let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) { span_lint_and_then(cx, FOR_KV_MAP, @@ -625,7 +624,7 @@ 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 '_'. +/// Return true if the pattern is a `PatWild` or an ident prefixed with '_'. fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { match *pat { PatKind::Wild => true, @@ -845,7 +844,7 @@ enum VarState { DontWarn, } -// Scan a for loop for variables that are incremented exactly once. +/// Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference states: HashMap<NodeId, VarState>, // incremented variables @@ -897,7 +896,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { } } -// Check whether a variable is initialized to zero at the start of a loop. +/// 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. diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index b805963a03a..69ce68b17db 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -311,6 +311,13 @@ fn main() { let _v = v; } + let mut m : HashMap<u64, u64> = HashMap::new(); + for (_, v) in &mut m { + // Ok, there is no values_mut method or equivalent + let _v = v; + } + + let rm = &m; for (k, _value) in rm { //~^ you seem to want to iterate on a map's keys -- cgit 1.4.1-3-g733a5 From 810de56079b678caf72e9fa712798da61f11fe77 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 27 Feb 2016 17:57:36 +0100 Subject: Add a lint about suspiciously formatted `=@` ops For `@` in {`*`, `!`, `-`}. --- README.md | 255 ++++++++++++++++++++------------------- src/formatting.rs | 66 ++++++++++ src/lib.rs | 3 + tests/compile-fail/formatting.rs | 28 +++++ 4 files changed, 225 insertions(+), 127 deletions(-) create mode 100644 src/formatting.rs create mode 100755 tests/compile-fail/formatting.rs (limited to 'src') diff --git a/README.md b/README.md index 62d6695b24d..9156db1cbdb 100644 --- a/README.md +++ b/README.md @@ -8,133 +8,134 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 123 lints included in this crate: - -name | default | meaning ----------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false -[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant -[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) -[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` -[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` -[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true` -[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap -[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary -[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` -[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` -[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` -[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` -[char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | Casting a character literal to u8 -[chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char -[clone_double_ref](https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref) | warn | using `clone` on `&&T` -[clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type -[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) -[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` -[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to `else if` -[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions -[deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver -[derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly -[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value -[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore -[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected -[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | finds use items that import all variants of an enum -[enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix -[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) -[expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types -[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do -[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do -[extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice -[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` -[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) -[for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do -[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` -[for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` -[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` -[if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks -[ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition -[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` -[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases -[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations -[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement -[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended -[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` -[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead -[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block -[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards -[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque -[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) -[map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap` -[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead -[match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms -[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead -[match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies -[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant -[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 -[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) -[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead -[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type -[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` -[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them -[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do -[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice -[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields -[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method -[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect -[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file -[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result -[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` -[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` -[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` -[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method when the `*or_else` would do -[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing -[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` -[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught -[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout -[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 -[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) -[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern -[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | warn | finds use of `regex!(_)`, suggests `Regex::new(_)` instead -[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled -[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` -[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` -[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` -[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` -[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value -[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait -[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")` -[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead -[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead -[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` -[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead -[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead -[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient -[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries -[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. -[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations -[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions -[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) -[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) -[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference -[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` -[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 -[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 -[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop -[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions -[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting -[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore -[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` -[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types -[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` -[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop -[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator -[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention -[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention -[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN -[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing +There are 125 lints included in this crate: + +name | default | meaning +---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false +[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` +[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` +[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true` +[box_vec](https://github.com/Manishearth/rust-clippy/wiki#box_vec) | warn | usage of `Box<Vec<T>>`, vector elements are already on the heap +[boxed_local](https://github.com/Manishearth/rust-clippy/wiki#boxed_local) | warn | using Box<T> where unnecessary +[cast_possible_truncation](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_truncation) | allow | casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32` +[cast_possible_wrap](https://github.com/Manishearth/rust-clippy/wiki#cast_possible_wrap) | allow | casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX` +[cast_precision_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_precision_loss) | allow | casts that cause loss of precision, e.g `x as f32` where `x: u64` +[cast_sign_loss](https://github.com/Manishearth/rust-clippy/wiki#cast_sign_loss) | allow | casts from signed types to unsigned types, e.g `x as u32` where `x: i32` +[char_lit_as_u8](https://github.com/Manishearth/rust-clippy/wiki#char_lit_as_u8) | warn | Casting a character literal to u8 +[chars_next_cmp](https://github.com/Manishearth/rust-clippy/wiki#chars_next_cmp) | warn | using `.chars().next()` to check if a string starts with a char +[clone_double_ref](https://github.com/Manishearth/rust-clippy/wiki#clone_double_ref) | warn | using `clone` on `&&T` +[clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#clone_on_copy) | warn | using `clone` on a `Copy` type +[cmp_nan](https://github.com/Manishearth/rust-clippy/wiki#cmp_nan) | deny | comparisons to NAN (which will always return false, which is probably not intended) +[cmp_owned](https://github.com/Manishearth/rust-clippy/wiki#cmp_owned) | warn | creating owned instances for comparing with others, e.g. `x == "foo".to_string()` +[collapsible_if](https://github.com/Manishearth/rust-clippy/wiki#collapsible_if) | warn | two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to `else if` +[cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions +[deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver +[derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly +[drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value +[duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore +[empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | finds use items that import all variants of an enum +[enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix +[eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) +[expl_impl_clone_on_copy](https://github.com/Manishearth/rust-clippy/wiki#expl_impl_clone_on_copy) | warn | implementing `Clone` explicitly on `Copy` types +[explicit_counter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop) | warn | for-looping with an explicit counter when `_.enumerate()` would do +[explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do +[extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice +[filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` +[float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) +[for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do +[for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` +[for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` +[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks +[ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition +[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` +[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations +[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement +[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended +[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` +[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead +[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block +[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards +[linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) +[map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap` +[match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead +[match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms +[match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead +[match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies +[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant +[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 +[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) +[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead +[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type +[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them +[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do +[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice +[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method +[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect +[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file +[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result +[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` +[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)` +[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` +[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method when the `*or_else` would do +[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing +[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` +[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught +[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout +[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 +[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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern +[regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | warn | finds use of `regex!(_)`, suggests `Regex::new(_)` instead +[result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled +[reverse_range_loop](https://github.com/Manishearth/rust-clippy/wiki#reverse_range_loop) | warn | Iterating over an empty range, such as `10..0` or `5..5` +[search_is_some](https://github.com/Manishearth/rust-clippy/wiki#search_is_some) | warn | using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()` +[shadow_reuse](https://github.com/Manishearth/rust-clippy/wiki#shadow_reuse) | allow | rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1` +[shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` +[shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value +[should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")` +[single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead +[single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead +[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` +[string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead +[string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead +[string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead +[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient +[suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` +[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries +[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. +[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations +[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions +[unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) +[unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) +[unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference +[unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` +[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 +[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 +[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions +[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting +[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore +[useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` +[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types +[useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` +[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop +[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator +[wrong_pub_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_pub_self_convention) | allow | defining a public method named with an established prefix (like "into_") that takes `self` with the wrong convention +[wrong_self_convention](https://github.com/Manishearth/rust-clippy/wiki#wrong_self_convention) | warn | defining a method named with an established prefix (like "into_") that takes `self` with the wrong convention +[zero_divided_by_zero](https://github.com/Manishearth/rust-clippy/wiki#zero_divided_by_zero) | warn | usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN +[zero_width_space](https://github.com/Manishearth/rust-clippy/wiki#zero_width_space) | deny | using a zero-width space in a string literal, which is confusing More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/src/formatting.rs b/src/formatting.rs new file mode 100644 index 00000000000..ce3c6f45a22 --- /dev/null +++ b/src/formatting.rs @@ -0,0 +1,66 @@ +use rustc::lint::*; +use syntax::codemap::mk_sp; +use syntax::ast; +use utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; +use syntax::ptr::P; + +/// **What it does:** This lint looks for use of the non-existent `=*`, `=!` and `=-` operators. +/// +/// **Why is this bad?** This either a typo of `*=`, `!=` or `-=` or confusing. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? +/// ``` +declare_lint! { + pub SUSPICIOUS_ASSIGNMENT_FORMATTING, + Warn, + "suspicious formatting of `*=`, `-=` or `!=`" +} + +#[derive(Copy,Clone)] +pub struct Formatting; + +impl LintPass for Formatting { + fn get_lints(&self) -> LintArray { + lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING] + } +} + +impl EarlyLintPass for Formatting { + fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { + check_assign(cx, expr); + } +} + +/// Implementation of the SUSPICIOUS_ASSIGNMENT_FORMATTING lint. +fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { + if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { + if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(cx, lhs.span) { + let eq_span = mk_sp(lhs.span.hi, rhs.span.lo); + + if let Some((sub_rhs, op)) = check_unop(rhs) { + if let Some(eq_snippet) = snippet_opt(cx, eq_span) { + let eqop_span = mk_sp(lhs.span.hi, sub_rhs.span.lo); + if eq_snippet.ends_with('=') { + span_note_and_lint(cx, + SUSPICIOUS_ASSIGNMENT_FORMATTING, + eqop_span, + &format!("this looks like you are trying to use `.. {op}= ..`, but you really are doing `.. = ({op} ..)`", op=op), + eqop_span, + &format!("to remove this lint, use either `{op}=` or `= {op}`", op=op)); + } + } + } + } + } +} + +fn check_unop(expr: &ast::Expr) -> Option<(&P<ast::Expr>, &'static str)> { + match expr.node { + ast::ExprKind::Unary(op, ref expr) => Some((expr, ast::UnOp::to_string(op))), + _ => None, + } +} diff --git a/src/lib.rs b/src/lib.rs index 8348eb09834..61029138fc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ pub mod eq_op; pub mod escape; pub mod eta_reduction; pub mod format; +pub mod formatting; pub mod identity_op; pub mod items_after_statements; pub mod len_zero; @@ -165,6 +166,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box regex::RegexPass::default()); reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_late_lint_pass(box format::FormatMacLint); + reg.register_early_lint_pass(box formatting::Formatting); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -212,6 +214,7 @@ pub fn plugin_registrar(reg: &mut Registry) { escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, format::USELESS_FORMAT, + formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, identity_op::IDENTITY_OP, items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/tests/compile-fail/formatting.rs b/tests/compile-fail/formatting.rs new file mode 100755 index 00000000000..c2d0f54f906 --- /dev/null +++ b/tests/compile-fail/formatting.rs @@ -0,0 +1,28 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(clippy)] +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(if_same_then_else)] + +fn main() { + // weird op_eq formatting: + let mut a = 42; + a =- 35; + //~^ ERROR this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` + //~| NOTE to remove this lint, use either `-=` or `= -` + a =* &191; + //~^ ERROR this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` + //~| NOTE to remove this lint, use either `*=` or `= *` + + let mut b = true; + b =! false; + //~^ ERROR this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` + //~| NOTE to remove this lint, use either `!=` or `= !` + + // those are ok: + a = -35; + a = *&191; + b = !false; +} -- cgit 1.4.1-3-g733a5 From 1c3cce8ba586c634d70a304d7e1a0da58b35bbea Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 27 Feb 2016 17:59:04 +0100 Subject: Add a lint about suspiciously formatted `else if` --- README.md | 1 + src/formatting.rs | 110 ++++++++++++++++++++++++++++++++++++++- src/lib.rs | 1 + tests/compile-fail/formatting.rs | 48 +++++++++++++++++ 4 files changed, 158 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 9156db1cbdb..c9730c4c58b 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ name [string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` +[suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations diff --git a/src/formatting.rs b/src/formatting.rs index ce3c6f45a22..f82aa7d8188 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -6,7 +6,7 @@ use syntax::ptr::P; /// **What it does:** This lint looks for use of the non-existent `=*`, `=!` and `=-` operators. /// -/// **Why is this bad?** This either a typo of `*=`, `!=` or `-=` or confusing. +/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or confusing. /// /// **Known problems:** None. /// @@ -20,18 +20,65 @@ declare_lint! { "suspicious formatting of `*=`, `-=` or `!=`" } +/// **What it does:** This lint checks for formatting of `else if`. It lints if the `else` and `if` +/// are not on the same line or the `else` seems to be missing. +/// +/// **Why is this bad?** This is probably some refactoring remnant, even if the code is correct, it +/// might look confusing. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// if foo { +/// } if bar { // looks like an `else` is missing here +/// } +/// +/// if foo { +/// } else +/// +/// if bar { // this is the `else` block of the previous `if`, but should it be? +/// } +/// ``` +declare_lint! { + pub SUSPICIOUS_ELSE_FORMATTING, + Warn, + "suspicious formatting of `else if`" +} + #[derive(Copy,Clone)] pub struct Formatting; impl LintPass for Formatting { fn get_lints(&self) -> LintArray { - lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING] + lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING, SUSPICIOUS_ELSE_FORMATTING] } } impl EarlyLintPass for Formatting { + fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { + for w in block.stmts.windows(2) { + match (&w[0].node, &w[1].node) { + (&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); + } + _ => (), + } + } + + if let Some(ref expr) = block.expr { + if let Some(ref stmt) = block.stmts.iter().last() { + if let ast::StmtKind::Expr(ref first, _) = stmt.node { + check_consecutive_ifs(cx, first, expr); + } + } + } + } + fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { check_assign(cx, expr); + check_else_if(cx, expr); } } @@ -64,3 +111,62 @@ fn check_unop(expr: &ast::Expr) -> Option<(&P<ast::Expr>, &'static str)> { _ => None, } } + +/// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`. +fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { + if let Some((then, &Some(ref else_))) = unsugar_if(expr) { + if unsugar_if(else_).is_some() && + !differing_macro_contexts(then.span, else_.span) && + !in_macro(cx, then.span) { + // this will be a span from the closing ‘}’ of the “then” block (excluding) to the + // “if” of the “else if” block (excluding) + let else_span = mk_sp(then.span.hi, else_.span.lo); + + // the snippet should look like " else \n " with maybe comments anywhere + // it’s bad when there is a ‘\n’ after the “else” + if let Some(else_snippet) = snippet_opt(cx, else_span) { + let else_pos = else_snippet.find("else").expect("there must be a `else` here"); + + if else_snippet[else_pos..].contains('\n') { + span_note_and_lint(cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this is an `else if` but the formatting might hide it", + else_span, + "to remove this lint, remove the `else` or remove the new line between `else` and `if`"); + } + } + } + } +} + +/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. +fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { + if !differing_macro_contexts(first.span, second.span) && + !in_macro(cx, first.span) && + unsugar_if(first).is_some() && + unsugar_if(second).is_some() { + // where the else would be + let else_span = mk_sp(first.span.hi, second.span.lo); + + if let Some(else_snippet) = snippet_opt(cx, else_span) { + if !else_snippet.contains('\n') { + span_note_and_lint(cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this looks like an `else if` but the `else` is missing", + else_span, + "to remove this lint, add the missing `else` or add a new line before the second `if`"); + } + } + } +} + +/// Match `if` or `else if` expressions and return the `then` and `else` block. +fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)>{ + match expr.node { + ast::ExprKind::If(_, ref then, ref else_) | + ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), + _ => None, + } +} diff --git a/src/lib.rs b/src/lib.rs index 61029138fc7..47d9fc6f24c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,6 +215,7 @@ pub fn plugin_registrar(reg: &mut Registry) { eta_reduction::REDUNDANT_CLOSURE, format::USELESS_FORMAT, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + formatting::SUSPICIOUS_ELSE_FORMATTING, identity_op::IDENTITY_OP, items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/tests/compile-fail/formatting.rs b/tests/compile-fail/formatting.rs index c2d0f54f906..14a23111ec7 100755 --- a/tests/compile-fail/formatting.rs +++ b/tests/compile-fail/formatting.rs @@ -6,7 +6,55 @@ #![allow(unused_assignments)] #![allow(if_same_then_else)] +fn foo() -> bool { true } + fn main() { + // weird `else if` formatting: + if foo() { + } if foo() { //~ERROR this looks like an `else if` but the `else` is missing + } + + let _ = { + if foo() { + } if foo() { //~ERROR this looks like an `else if` but the `else` is missing + } + else { + } + }; + + if foo() { + } else //~ERROR this is an `else if` but the formatting might hide it + if foo() { // the span of the above error should continue here + } + + if foo() { + } //~ERROR this is an `else if` but the formatting might hide it + else + if foo() { // the span of the above error should continue here + } + + // those are ok: + if foo() { + } + if foo() { + } + + if foo() { + } else if foo() { + } + + if foo() { + } + else if foo() { + } + + if foo() { + } + + else if + + foo() {} + // weird op_eq formatting: let mut a = 42; a =- 35; -- cgit 1.4.1-3-g733a5 From 3a5b9a707c786bf02ed05d65ca8394d77df601fb Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 27 Feb 2016 18:05:50 +0100 Subject: Fix (new?) rustc warnings --- src/consts.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index cf32a9a2c82..64f45d72c12 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -206,7 +206,6 @@ fn lit_to_constant(lit: &LitKind) -> Constant { } fn constant_not(o: Constant) -> Option<Constant> { - use syntax::ast::LitIntType::*; use self::Constant::*; match o { Bool(b) => Some(Bool(!b)), @@ -232,7 +231,6 @@ fn constant_not(o: Constant) -> Option<Constant> { } fn constant_negate(o: Constant) -> Option<Constant> { - use syntax::ast::LitIntType::*; use self::Constant::*; match o { Int(value, LitIntType::Signed(ity), sign) => Some(Int(value, LitIntType::Signed(ity), neg_sign(sign))), -- cgit 1.4.1-3-g733a5 From 05178c92b900caeee17bfc4acbaf6baf6600f089 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 27 Feb 2016 18:14:37 +0100 Subject: Cleanup --- src/formatting.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/formatting.rs b/src/formatting.rs index f82aa7d8188..efcb222ebed 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -88,8 +88,9 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(cx, lhs.span) { let eq_span = mk_sp(lhs.span.hi, rhs.span.lo); - if let Some((sub_rhs, op)) = check_unop(rhs) { + if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { + let op = ast::UnOp::to_string(op); let eqop_span = mk_sp(lhs.span.hi, sub_rhs.span.lo); if eq_snippet.ends_with('=') { span_note_and_lint(cx, @@ -105,13 +106,6 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { } } -fn check_unop(expr: &ast::Expr) -> Option<(&P<ast::Expr>, &'static str)> { - match expr.node { - ast::ExprKind::Unary(op, ref expr) => Some((expr, ast::UnOp::to_string(op))), - _ => None, - } -} - /// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`. fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) { -- cgit 1.4.1-3-g733a5 From 72ef26272d9718f5495b3a143010e031ba898e5a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 28 Feb 2016 00:01:15 +0100 Subject: Lint `foo = bar; bar = foo` sequences --- README.md | 3 ++- src/lib.rs | 3 +++ src/swap.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/swap.rs | 17 ++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/swap.rs create mode 100755 tests/compile-fail/swap.rs (limited to 'src') diff --git a/README.md b/README.md index c9730c4c58b..f7527372585 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 125 lints included in this crate: +There are 126 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -114,6 +114,7 @@ name [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` [suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` +[suspicious_swap](https://github.com/Manishearth/rust-clippy/wiki#suspicious_swap) | warn | `foo = bar; bar = foo` sequence [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations diff --git a/src/lib.rs b/src/lib.rs index 47d9fc6f24c..217110e2bd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,6 +86,7 @@ pub mod regex; pub mod returns; pub mod shadow; pub mod strings; +pub mod swap; pub mod temporary_assignment; pub mod transmute; pub mod types; @@ -167,6 +168,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_late_lint_pass(box format::FormatMacLint); reg.register_early_lint_pass(box formatting::Formatting); + reg.register_late_lint_pass(box swap::Swap); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -285,6 +287,7 @@ pub fn plugin_registrar(reg: &mut Registry) { returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, strings::STRING_LIT_AS_BYTES, + swap::SUSPICIOUS_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, diff --git a/src/swap.rs b/src/swap.rs new file mode 100644 index 00000000000..8e1b1e781f4 --- /dev/null +++ b/src/swap.rs @@ -0,0 +1,66 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; +use syntax::codemap::mk_sp; + +/// **What it does:** This lints `foo = bar; bar = foo` sequences. +/// +/// **Why is this bad?** This looks like a failed attempt to swap. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// a = b; +/// b = a; +/// ``` +declare_lint! { + pub SUSPICIOUS_SWAP, + Warn, + "`foo = bar; bar = foo` sequence" +} + +#[derive(Copy,Clone)] +pub struct Swap; + +impl LintPass for Swap { + fn get_lints(&self) -> LintArray { + lint_array![SUSPICIOUS_SWAP] + } +} + +impl LateLintPass for Swap { + fn check_block(&mut self, cx: &LateContext, block: &Block) { + for w in block.stmts.windows(2) { + if_let_chain!{[ + let StmtSemi(ref first, _) = w[0].node, + let StmtSemi(ref second, _) = w[1].node, + !differing_macro_contexts(first.span, second.span), + let ExprAssign(ref lhs0, ref rhs0) = first.node, + let ExprAssign(ref lhs1, ref rhs1) = second.node, + 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)) = (snippet_opt(cx, lhs0.span), snippet_opt(cx, rhs0.span)) { + (format!(" `{}` and `{}`", first, second), first, second) + } else { + ("".to_owned(), "".to_owned(), "".to_owned()) + }; + + let span = mk_sp(first.span.lo, second.span.hi); + + span_lint_and_then(cx, + SUSPICIOUS_SWAP, + span, + &format!("this looks like you are trying to swap{}", what), + |db| { + if !what.is_empty() { + db.span_suggestion(span, "try", + format!("std::mem::swap({}, {})", lhs, rhs)); + db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); + } + }); + }} + } + } +} diff --git a/tests/compile-fail/swap.rs b/tests/compile-fail/swap.rs new file mode 100755 index 00000000000..be2c785eb41 --- /dev/null +++ b/tests/compile-fail/swap.rs @@ -0,0 +1,17 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(clippy)] +#![allow(unused_assignments)] + +fn main() { + let mut a = 42; + let mut b = 1337; + + a = b; + b = a; + //~^^ ERROR this looks like you are trying to swap `a` and `b` + //~| HELP try + //~| SUGGESTION std::mem::swap(a, b); + //~| NOTE or maybe you should use `std::mem::replace`? +} -- cgit 1.4.1-3-g733a5 From 5fadfb3ea6a89512959b0bfa1261ed92bcf47964 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 27 Feb 2016 22:59:15 +0100 Subject: Fix wrong suggestion in `WHILE_LET_LOOP` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ok, I lied in the title. This basically *removes* the problematic part but: 1) it was ugly with big bodies; 2) it was not indented properly; 3) it wasn’t very smart (see #675). --- src/loops.rs | 34 +++++++++------------------------- tests/compile-fail/while_loop.rs | 13 +++++++++++++ 2 files changed, 22 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 3eb013da6d9..e6b28d20e83 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -11,7 +11,7 @@ use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; use std::collections::HashMap; -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block, +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty}; use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; @@ -241,20 +241,6 @@ impl LateLintPass for LoopsPass { // or extract the first expression (if any) from the block if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(block)) { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { - // collect the remaining statements below the match - let mut other_stuff = block.stmts - .iter() - .skip(1) - .map(|stmt| snippet(cx, stmt.span, "..")) - .collect::<Vec<Cow<_>>>(); - if inner_stmt_expr.is_some() { - // if we have a statement which has a match, - if let Some(ref expr) = block.expr { - // then collect the expression (without semicolon) below it - other_stuff.push(snippet(cx, expr.span, "..")); - } - } - // ensure "if let" compatible match structure match *source { MatchSource::Normal | MatchSource::IfLetDesugar{..} => { @@ -264,22 +250,20 @@ impl LateLintPass for LoopsPass { if in_external_macro(cx, expr.span) { return; } - let loop_body = if inner_stmt_expr.is_some() { - // FIXME: should probably be an ellipsis - // tabbing and newline is probably a bad idea, especially for large blocks - Cow::Owned(format!("{{\n {}\n}}", other_stuff.join("\n "))) - } else { - expr_block(cx, &arms[0].body, Some(other_stuff.join("\n ")), "..") - }; + + // NOTE: we used to make build a body here instead of using + // ellipsis, this was removed because: + // 1) it was ugly with big bodies; + // 2) it was not indented properly; + // 3) it wasn’t very smart (see #675). span_lint_and_then(cx, WHILE_LET_LOOP, expr.span, "this loop could be written as a `while let` loop", |db| { - let sug = format!("while let {} = {} {}", + let sug = format!("while let {} = {} {{ .. }}", snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, ".."), - loop_body); + snippet(cx, matchexpr.span, "..")); db.span_suggestion(expr.span, "try", sug); }); } diff --git a/tests/compile-fail/while_loop.rs b/tests/compile-fail/while_loop.rs index bbb76cfbfaf..7c5582ba9bf 100644 --- a/tests/compile-fail/while_loop.rs +++ b/tests/compile-fail/while_loop.rs @@ -66,6 +66,19 @@ fn main() { println!("{}", x); } + // #675, this used to have a wrong suggestion + loop { + //~^ERROR this loop could be written as a `while let` loop + //~|HELP try + //~|SUGGESTION while let Some(word) = "".split_whitespace().next() { .. } + let (e, l) = match "".split_whitespace().next() { + Some(word) => (word.is_empty(), word.len()), + None => break + }; + + let _ = (e, l); + } + let mut iter = 1..20; while let Option::Some(x) = iter.next() { //~ERROR this loop could be written as a `for` loop println!("{}", x); -- cgit 1.4.1-3-g733a5 From 76004306ccf3e3069bdf0928a70895916bea00ff Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 28 Feb 2016 00:46:02 +0100 Subject: Lint manual swaps --- README.md | 5 +- src/lib.rs | 3 +- src/swap.rs | 136 ++++++++++++++++++++++++++++++++++----------- tests/compile-fail/swap.rs | 29 +++++++++- 4 files changed, 137 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index f7527372585..f421cbdb7c9 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,12 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 126 lints included in this crate: +There are 127 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false +[almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` @@ -62,6 +63,7 @@ name [let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[manual_swap](https://github.com/Manishearth/rust-clippy/wiki#manual_swap) | warn | manual swap [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) [map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap` [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead @@ -114,7 +116,6 @@ name [string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` [suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` -[suspicious_swap](https://github.com/Manishearth/rust-clippy/wiki#suspicious_swap) | warn | `foo = bar; bar = foo` sequence [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations diff --git a/src/lib.rs b/src/lib.rs index 217110e2bd8..5debe2ed50c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -287,7 +287,8 @@ pub fn plugin_registrar(reg: &mut Registry) { returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, strings::STRING_LIT_AS_BYTES, - swap::SUSPICIOUS_SWAP, + swap::ALMOST_SWAPPED, + swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, diff --git a/src/swap.rs b/src/swap.rs index 8e1b1e781f4..6d7212233fb 100644 --- a/src/swap.rs +++ b/src/swap.rs @@ -1,7 +1,26 @@ use rustc::lint::*; use rustc_front::hir::*; -use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; use syntax::codemap::mk_sp; +use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; + +/// **What it does:** This lints manual swapping. +/// +/// **Why is this bad?** The `std::mem::swap` function exposes the intent better without +/// deinitializing or copying either variable. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// let t = b; +/// b = a; +/// a = t; +/// ``` +declare_lint! { + pub MANUAL_SWAP, + Warn, + "manual swap" +} /// **What it does:** This lints `foo = bar; bar = foo` sequences. /// @@ -15,7 +34,7 @@ use syntax::codemap::mk_sp; /// b = a; /// ``` declare_lint! { - pub SUSPICIOUS_SWAP, + pub ALMOST_SWAPPED, Warn, "`foo = bar; bar = foo` sequence" } @@ -25,42 +44,95 @@ pub struct Swap; impl LintPass for Swap { fn get_lints(&self) -> LintArray { - lint_array![SUSPICIOUS_SWAP] + lint_array![MANUAL_SWAP, ALMOST_SWAPPED] } } impl LateLintPass for Swap { fn check_block(&mut self, cx: &LateContext, block: &Block) { - for w in block.stmts.windows(2) { - if_let_chain!{[ - let StmtSemi(ref first, _) = w[0].node, - let StmtSemi(ref second, _) = w[1].node, - !differing_macro_contexts(first.span, second.span), - let ExprAssign(ref lhs0, ref rhs0) = first.node, - let ExprAssign(ref lhs1, ref rhs1) = second.node, - 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)) = (snippet_opt(cx, lhs0.span), snippet_opt(cx, rhs0.span)) { - (format!(" `{}` and `{}`", first, second), first, second) - } else { - ("".to_owned(), "".to_owned(), "".to_owned()) - }; + check_manual_swap(cx, block); + check_suspicious_swap(cx, block); + } +} + +/// Implementation of the `MANUAL_SWAP` lint. +fn check_manual_swap(cx: &LateContext, block: &Block) { + for w in block.stmts.windows(3) { + if_let_chain!{[ + // let t = foo(); + let StmtDecl(ref tmp, _) = w[0].node, + let DeclLocal(ref tmp) = tmp.node, + let Some(ref tmp_init) = tmp.init, + let PatKind::Ident(_, ref tmp_name, None) = tmp.pat.node, + + // foo() = bar(); + let StmtSemi(ref first, _) = w[1].node, + let ExprAssign(ref lhs1, ref rhs1) = first.node, + + // bar() = t; + let StmtSemi(ref second, _) = w[2].node, + let ExprAssign(ref lhs2, ref rhs2) = second.node, + let ExprPath(None, ref rhs2) = rhs2.node, + rhs2.segments.len() == 1, + + tmp_name.node.name.as_str() == rhs2.segments[0].identifier.name.as_str(), + SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1), + SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2) + ], { + let (what, lhs, rhs) = if let (Some(first), Some(second)) = (snippet_opt(cx, lhs1.span), snippet_opt(cx, rhs1.span)) { + (format!(" `{}` and `{}`", first, second), first, second) + } else { + ("".to_owned(), "".to_owned(), "".to_owned()) + }; + + let span = mk_sp(tmp.span.lo, second.span.hi); + + span_lint_and_then(cx, + MANUAL_SWAP, + span, + &format!("this looks like you are swapping{} manually", what), + |db| { + if !what.is_empty() { + db.span_suggestion(span, "try", + format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); + db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); + } + }); + }} + } +} + +/// Implementation of the `ALMOST_SWAPPED` lint. +fn check_suspicious_swap(cx: &LateContext, block: &Block) { + for w in block.stmts.windows(2) { + if_let_chain!{[ + let StmtSemi(ref first, _) = w[0].node, + let StmtSemi(ref second, _) = w[1].node, + !differing_macro_contexts(first.span, second.span), + let ExprAssign(ref lhs0, ref rhs0) = first.node, + let ExprAssign(ref lhs1, ref rhs1) = second.node, + 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)) = (snippet_opt(cx, lhs0.span), snippet_opt(cx, rhs0.span)) { + (format!(" `{}` and `{}`", first, second), first, second) + } else { + ("".to_owned(), "".to_owned(), "".to_owned()) + }; - let span = mk_sp(first.span.lo, second.span.hi); + let span = mk_sp(first.span.lo, second.span.hi); - span_lint_and_then(cx, - SUSPICIOUS_SWAP, - span, - &format!("this looks like you are trying to swap{}", what), - |db| { - if !what.is_empty() { - db.span_suggestion(span, "try", - format!("std::mem::swap({}, {})", lhs, rhs)); - db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); - } - }); - }} - } + span_lint_and_then(cx, + ALMOST_SWAPPED, + span, + &format!("this looks like you are trying to swap{}", what), + |db| { + if !what.is_empty() { + db.span_suggestion(span, "try", + format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); + db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); + } + }); + }} } } diff --git a/tests/compile-fail/swap.rs b/tests/compile-fail/swap.rs index be2c785eb41..cc0570e6c63 100755 --- a/tests/compile-fail/swap.rs +++ b/tests/compile-fail/swap.rs @@ -4,6 +4,8 @@ #![deny(clippy)] #![allow(unused_assignments)] +struct Foo(u32); + fn main() { let mut a = 42; let mut b = 1337; @@ -12,6 +14,31 @@ fn main() { b = a; //~^^ ERROR this looks like you are trying to swap `a` and `b` //~| HELP try - //~| SUGGESTION std::mem::swap(a, b); + //~| SUGGESTION std::mem::swap(&mut a, &mut b); + //~| NOTE or maybe you should use `std::mem::replace`? + + let t = a; + a = b; + b = t; + //~^^^ ERROR this looks like you are swapping `a` and `b` manually + //~| HELP try + //~| SUGGESTION std::mem::swap(&mut a, &mut b); + //~| NOTE or maybe you should use `std::mem::replace`? + + let mut c = Foo(42); + + c.0 = a; + a = c.0; + //~^^ ERROR this looks like you are trying to swap `c.0` and `a` + //~| HELP try + //~| SUGGESTION std::mem::swap(&mut c.0, &mut a); + //~| NOTE or maybe you should use `std::mem::replace`? + + let t = c.0; + c.0 = a; + a = t; + //~^^^ ERROR this looks like you are swapping `c.0` and `a` manually + //~| HELP try + //~| SUGGESTION std::mem::swap(&mut c.0, &mut a); //~| NOTE or maybe you should use `std::mem::replace`? } -- cgit 1.4.1-3-g733a5 From 67213c9be408fbfb8b1015d00b1b72a4f3742c75 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 29 Feb 2016 09:36:13 +0100 Subject: lint unportable clike enum discriminants --- README.md | 3 ++- src/enum_clike.rs | 56 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ tests/compile-fail/enums_clike.rs | 53 ++++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/enum_clike.rs create mode 100644 tests/compile-fail/enums_clike.rs (limited to 'src') diff --git a/README.md b/README.md index f421cbdb7c9..d424aca9faa 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 127 lints included in this crate: +There are 128 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -38,6 +38,7 @@ name [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected +[enum_clike_unportable_variant](https://github.com/Manishearth/rust-clippy/wiki#enum_clike_unportable_variant) | warn | finds C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` [enum_glob_use](https://github.com/Manishearth/rust-clippy/wiki#enum_glob_use) | allow | finds use items that import all variants of an enum [enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#enum_variant_names) | warn | finds enums where all variants share a prefix/postfix [eq_op](https://github.com/Manishearth/rust-clippy/wiki#eq_op) | warn | equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`) diff --git a/src/enum_clike.rs b/src/enum_clike.rs new file mode 100644 index 00000000000..7ee71f41f29 --- /dev/null +++ b/src/enum_clike.rs @@ -0,0 +1,56 @@ +//! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` + +use rustc::lint::*; +use syntax::ast::{IntTy, UintTy}; +use syntax::attr::*; +use rustc_front::hir::*; +use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial}; +use rustc::middle::ty; +use utils::span_lint; + +/// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. +/// +/// **Why is this bad?** This will truncate the variant value on 32bit architectures, but works fine on 64 bit. +/// +/// **Known problems:** None +/// +/// **Example:** `#[repr(usize)] enum NonPortable { X = 0x1_0000_0000, Y = 0 }` +declare_lint! { + pub ENUM_CLIKE_UNPORTABLE_VARIANT, Warn, + "finds C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`" +} + +pub struct EnumClikeUnportableVariant; + +impl LintPass for EnumClikeUnportableVariant { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT) + } +} + +impl LateLintPass for EnumClikeUnportableVariant { + #[allow(cast_possible_truncation, cast_sign_loss)] + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemEnum(ref def, _) = item.node { + for var in &def.variants { + let variant = &var.node; + if let Some(ref disr) = variant.disr_expr { + let cv = eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None); + let bad = match (cv, &cx.tcx.expr_ty(&**disr).sty) { + (Ok(ConstVal::Int(i)), &ty::TyInt(IntTy::Is)) => i as i32 as i64 != i, + (Ok(ConstVal::Uint(i)), &ty::TyInt(IntTy::Is)) => i as i32 as u64 != i, + (Ok(ConstVal::Int(i)), &ty::TyUint(UintTy::Us)) => (i < 0) || (i as u32 as i64 != i), + (Ok(ConstVal::Uint(i)), &ty::TyUint(UintTy::Us)) => i as u32 as u64 != i, + _ => false, + }; + if bad { + span_lint(cx, + ENUM_CLIKE_UNPORTABLE_VARIANT, + var.span, + "Clike enum variant discriminant is not portable to 32-bit targets"); + } + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5debe2ed50c..50ea765f85d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ pub mod cyclomatic_complexity; pub mod derive; pub mod drop_ref; pub mod entry; +pub mod enum_clike; pub mod enum_glob_use; pub mod enum_variants; pub mod eq_op; @@ -108,6 +109,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box eq_op::EqOp); reg.register_early_lint_pass(box enum_variants::EnumVariantNames); reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); + reg.register_late_lint_pass(box enum_clike::EnumClikeUnportableVariant); reg.register_late_lint_pass(box bit_mask::BitMask); reg.register_late_lint_pass(box ptr_arg::PtrArg); reg.register_late_lint_pass(box needless_bool::NeedlessBool); @@ -211,6 +213,7 @@ pub fn plugin_registrar(reg: &mut Registry) { derive::EXPL_IMPL_CLONE_ON_COPY, drop_ref::DROP_REF, entry::MAP_ENTRY, + enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, enum_variants::ENUM_VARIANT_NAMES, eq_op::EQ_OP, escape::BOXED_LOCAL, diff --git a/tests/compile-fail/enums_clike.rs b/tests/compile-fail/enums_clike.rs new file mode 100644 index 00000000000..f48f9b13de4 --- /dev/null +++ b/tests/compile-fail/enums_clike.rs @@ -0,0 +1,53 @@ +#![feature(plugin, associated_consts)] +#![plugin(clippy)] +#![deny(clippy)] + +#![allow(unused)] + +#[repr(usize)] +enum NonPortable { + X = 0x1_0000_0000, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets + Y = 0, + Z = 0x7FFF_FFFF, + A = 0xFFFF_FFFF, +} + +enum NonPortableNoHint { + X = 0x1_0000_0000, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets + Y = 0, + Z = 0x7FFF_FFFF, + A = 0xFFFF_FFFF, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets +} + +#[repr(isize)] +enum NonPortableSigned { + X = -1, + Y = 0x7FFF_FFFF, + Z = 0xFFFF_FFFF, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets + A = 0x1_0000_0000, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets + B = std::i32::MIN as isize, + C = (std::i32::MIN as isize) - 1, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets +} + +enum NonPortableSignedNoHint { + X = -1, + Y = 0x7FFF_FFFF, + Z = 0xFFFF_FFFF, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets + A = 0x1_0000_0000, //~ ERROR: Clike enum variant discriminant is not portable to 32-bit targets +} + +/* +FIXME: uncomment once https://github.com/rust-lang/rust/issues/31910 is fixed +#[repr(usize)] +enum NonPortable2<T: Trait> { + X = Trait::Number, + Y = 0, +} + +trait Trait { + const Number: usize = 0x1_0000_0000; +} +*/ + +fn main() { +} -- cgit 1.4.1-3-g733a5 From 3b7720f992a5bc03027e64450ba51a58a5a971ae Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 29 Feb 2016 09:45:36 +0100 Subject: lint ! and != in if expressions with else branches --- README.md | 3 ++- src/block_in_if_condition.rs | 6 ++--- src/consts.rs | 6 ++--- src/enum_variants.rs | 10 +++----- src/if_not_else.rs | 53 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ src/loops.rs | 6 ++--- src/matches.rs | 22 ++++++++-------- tests/compile-fail/entry.rs | 2 +- tests/compile-fail/if_not_else.rs | 18 +++++++++++++ 10 files changed, 100 insertions(+), 29 deletions(-) create mode 100644 src/if_not_else.rs create mode 100644 tests/compile-fail/if_not_else.rs (limited to 'src') diff --git a/README.md b/README.md index d424aca9faa..3a957a7e4c9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 128 lints included in this crate: +There are 129 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -52,6 +52,7 @@ name [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` [for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` +[if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | warn | finds if branches that could be swapped so no negation operation is necessary on the condition [if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks [ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 6db77a5ce93..7004910dfc7 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -45,9 +45,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { fn visit_expr(&mut self, expr: &'v Expr) { if let ExprClosure(_, _, ref block) = expr.node { let complex = { - if !block.stmts.is_empty() { - true - } else { + if block.stmts.is_empty() { if let Some(ref ex) = block.expr { match ex.node { ExprBlock(_) => true, @@ -56,6 +54,8 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { } else { false } + } else { + true } }; if complex { diff --git a/src/consts.rs b/src/consts.rs index 64f45d72c12..6dd5651e7ef 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -159,10 +159,10 @@ impl PartialOrd for Constant { fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => { - if lsty != rsty { - None - } else { + if lsty == rsty { Some(ls.cmp(rs)) + } else { + None } } (&Constant::Byte(ref l), &Constant::Byte(ref r)) => Some(l.cmp(r)), diff --git a/src/enum_variants.rs b/src/enum_variants.rs index a95fca8c6c4..179ce24cfa7 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -89,12 +89,10 @@ impl EarlyLintPass for EnumVariantNames { let post_camel = camel_case_from(&post); post = &post[post_camel..]; } - let (what, value) = if !pre.is_empty() { - ("pre", pre) - } else if !post.is_empty() { - ("post", post) - } else { - return; + let (what, value) = match (pre.is_empty(), post.is_empty()) { + (true, true) => return, + (false, _) => ("pre", pre), + (true, false) => ("post", post), }; span_help_and_lint(cx, ENUM_VARIANT_NAMES, diff --git a/src/if_not_else.rs b/src/if_not_else.rs new file mode 100644 index 00000000000..1a074a723a9 --- /dev/null +++ b/src/if_not_else.rs @@ -0,0 +1,53 @@ +//! lint on if branches that could be swapped so no `!` operation is necessary on the condition + +use rustc::lint::*; +use syntax::attr::*; +use syntax::ast::*; + +use utils::span_help_and_lint; + +/// **What it does:** Warns on the use of `!` or `!=` in an if condition with an else branch +/// +/// **Why is this bad?** Negations reduce the readability of statements +/// +/// **Known problems:** None +/// +/// **Example:** if !v.is_empty() { a() } else { b() } +declare_lint! { + pub IF_NOT_ELSE, Warn, + "finds if branches that could be swapped so no negation operation is necessary on the condition" +} + +pub struct IfNotElse; + +impl LintPass for IfNotElse { + fn get_lints(&self) -> LintArray { + lint_array!(IF_NOT_ELSE) + } +} + +impl EarlyLintPass for IfNotElse { + fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { + if let ExprKind::If(ref cond, _, Some(ref els)) = item.node { + if let ExprKind::Block(..) = els.node { + match cond.node { + ExprKind::Unary(UnOp::Not, _) => { + span_help_and_lint(cx, + IF_NOT_ELSE, + 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/src/lib.rs b/src/lib.rs index 50ea765f85d..7436dada020 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,7 @@ pub mod eta_reduction; pub mod format; pub mod formatting; pub mod identity_op; +pub mod if_not_else; pub mod items_after_statements; pub mod len_zero; pub mod lifetimes; @@ -171,6 +172,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box format::FormatMacLint); reg.register_early_lint_pass(box formatting::Formatting); reg.register_late_lint_pass(box swap::Swap); + reg.register_early_lint_pass(box if_not_else::IfNotElse); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -222,6 +224,7 @@ pub fn plugin_registrar(reg: &mut Registry) { formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, identity_op::IDENTITY_OP, + if_not_else::IF_NOT_ELSE, items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, diff --git a/src/loops.rs b/src/loops.rs index e6b28d20e83..5e862382742 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -357,10 +357,10 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex }; let take: Cow<_> = if let Some(ref r) = *r { - if !is_len_call(&r, &indexed) { - format!(".take({})", snippet(cx, r.span, "..")).into() - } else { + if is_len_call(&r, &indexed) { "".into() + } else { + format!(".take({})", snippet(cx, r.span, "..")).into() } } else { "".into() diff --git a/src/matches.rs b/src/matches.rs index 35c0dbb3950..d832888606a 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -249,23 +249,21 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { }; if let Some((ref true_expr, ref false_expr)) = exprs { - if !is_unit_expr(true_expr) { - if !is_unit_expr(false_expr) { + match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => Some(format!("if {} {} else {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, ".."), - expr_block(cx, false_expr, None, ".."))) - } else { + expr_block(cx, false_expr, None, ".."))), + (false, true) => Some(format!("if {} {}", snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, ".."))) - } - } else if !is_unit_expr(false_expr) { - Some(format!("try\nif !{} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))) - } else { - None + expr_block(cx, true_expr, None, ".."))), + (true, false) => + Some(format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))), + (true, true) => None, } } else { None diff --git a/tests/compile-fail/entry.rs b/tests/compile-fail/entry.rs index 7dc4054ec5b..e65ef503ba5 100644 --- a/tests/compile-fail/entry.rs +++ b/tests/compile-fail/entry.rs @@ -1,6 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused)] +#![allow(unused, if_not_else)] #![deny(map_entry)] diff --git a/tests/compile-fail/if_not_else.rs b/tests/compile-fail/if_not_else.rs new file mode 100644 index 00000000000..eb716e4599a --- /dev/null +++ b/tests/compile-fail/if_not_else.rs @@ -0,0 +1,18 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy)] + +fn bla() -> bool { unimplemented!() } + +fn main() { + if !bla() { //~ ERROR: Unnecessary boolean `not` operation + println!("Bugs"); + } else { + println!("Bunny"); + } + if 4 != 5 { //~ ERROR: Unnecessary `!=` operation + println!("Bugs"); + } else { + println!("Bunny"); + } +} -- cgit 1.4.1-3-g733a5 From bd45cfd2739babc9350760cc4b5989a729fe447e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 29 Feb 2016 16:49:32 +0530 Subject: rustfmt --- src/block_in_if_condition.rs | 3 +- src/collapsible_if.rs | 10 ++-- src/copies.rs | 4 +- src/derive.rs | 12 +---- src/entry.rs | 2 +- src/enum_variants.rs | 24 ++++----- src/formatting.rs | 24 ++++----- src/len_zero.rs | 16 ++---- src/loops.rs | 27 +++++----- src/map_clone.rs | 6 +-- src/matches.rs | 39 +++++++------- src/methods.rs | 9 ++-- src/print.rs | 11 ++-- src/regex.rs | 6 ++- src/strings.rs | 2 +- src/types.rs | 10 ++-- src/utils/hir.rs | 125 +++++++++++++------------------------------ src/utils/mod.rs | 12 ++--- 18 files changed, 138 insertions(+), 204 deletions(-) (limited to 'src') diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 7004910dfc7..9cb11968abc 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -92,8 +92,7 @@ impl LateLintPass for BlockInIfCondition { snippet_block(cx, then.span, ".."))); } } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, - |e| e.span); + let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); if in_macro(cx, span) || differing_macro_contexts(expr.span, span) { return; } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 663d39cdbb2..74397304eda 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -71,15 +71,13 @@ fn check_if(cx: &LateContext, e: &Expr) { }); }} } else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = - single_stmt_of_block(then) { + single_stmt_of_block(then) { if e.span.expn_id != sp.expn_id { return; } - span_lint_and_then(cx, - COLLAPSIBLE_IF, - e.span, - "this if statement can be collapsed", |db| { - db.span_suggestion(e.span, "try", + span_lint_and_then(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", |db| { + db.span_suggestion(e.span, + "try", format!("if {} && {} {}", check_to_string(cx, check), check_to_string(cx, check_inner), diff --git a/src/copies.rs b/src/copies.rs index 1995e2901ad..691acad6e92 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -91,9 +91,7 @@ fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { h.finish() }; - let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { - SpanlessEq::new(cx).eq_block(lhs, rhs) - }; + let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same(blocks, hash, eq) { span_note_and_lint(cx, diff --git a/src/derive.rs b/src/derive.rs index 084d00d409f..8bdcb4b0167 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -87,13 +87,7 @@ impl LateLintPass for Derive { } /// Implementation of the `DERIVE_HASH_XOR_EQ` lint. -fn check_hash_peq( - cx: &LateContext, - span: Span, - trait_ref: &TraitRef, - ty: ty::Ty, - hash_is_automatically_derived: bool -) { +fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty, hash_is_automatically_derived: bool) { if_let_chain! {[ match_path(&trait_ref.path, &HASH_PATH), let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() @@ -143,9 +137,7 @@ fn check_hash_peq( } /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. -fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, - item: &Item, - trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { +fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) { if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) { let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); let subst_ty = ty.subst(cx.tcx, ¶meter_environment.free_substs); diff --git a/src/entry.rs b/src/entry.rs index 6242b44dd6e..8a4cf37c0ac 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -48,7 +48,7 @@ impl LateLintPass for HashMapLint { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message let sole_expr = else_block.is_none() && - if then_block.expr.is_some() { 1 } else { 0 } + then_block.stmts.len() == 1; + ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1); let mut visitor = InsertVisitor { cx: cx, diff --git a/src/enum_variants.rs b/src/enum_variants.rs index 179ce24cfa7..d7bd4742ebb 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -31,17 +31,16 @@ fn var2str(var: &Variant) -> InternedString { var.node.name.name.as_str() } -/* -FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 -fn partial_match(pre: &str, name: &str) -> usize { - // skip(1) to ensure that the prefix never takes the whole variant name - pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() -} - -fn partial_rmatch(post: &str, name: &str) -> usize { - // skip(1) to ensure that the postfix never takes the whole variant name - post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() -}*/ +// FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 +// fn partial_match(pre: &str, name: &str) -> usize { +// // skip(1) to ensure that the prefix never takes the whole variant name +// pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() +// } +// +// fn partial_rmatch(post: &str, name: &str) -> usize { +// // skip(1) to ensure that the postfix never takes the whole variant name +// post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() +// } fn partial_match(pre: &str, name: &str) -> usize { let mut name_iter = name.chars(); @@ -99,7 +98,8 @@ impl EarlyLintPass for EnumVariantNames { item.span, &format!("All variants have the same {}fix: `{}`", what, value), &format!("remove the {}fixes and use full paths to \ - the variants instead of glob imports", what)); + the variants instead of glob imports", + what)); } } } diff --git a/src/formatting.rs b/src/formatting.rs index efcb222ebed..091280de28d 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -96,9 +96,11 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { span_note_and_lint(cx, SUSPICIOUS_ASSIGNMENT_FORMATTING, eqop_span, - &format!("this looks like you are trying to use `.. {op}= ..`, but you really are doing `.. = ({op} ..)`", op=op), + &format!("this looks like you are trying to use `.. {op}= ..`, but you \ + really are doing `.. = ({op} ..)`", + op = op), eqop_span, - &format!("to remove this lint, use either `{op}=` or `= {op}`", op=op)); + &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op)); } } } @@ -109,9 +111,7 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { /// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`. fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) { - if unsugar_if(else_).is_some() && - !differing_macro_contexts(then.span, else_.span) && - !in_macro(cx, then.span) { + if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(cx, then.span) { // this will be a span from the closing ‘}’ of the “then” block (excluding) to the // “if” of the “else if” block (excluding) let else_span = mk_sp(then.span.hi, else_.span.lo); @@ -127,7 +127,8 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { else_span, "this is an `else if` but the formatting might hide it", else_span, - "to remove this lint, remove the `else` or remove the new line between `else` and `if`"); + "to remove this lint, remove the `else` or remove the new line between `else` \ + and `if`"); } } } @@ -136,10 +137,8 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { - if !differing_macro_contexts(first.span, second.span) && - !in_macro(cx, first.span) && - unsugar_if(first).is_some() && - unsugar_if(second).is_some() { + if !differing_macro_contexts(first.span, second.span) && !in_macro(cx, first.span) && + unsugar_if(first).is_some() && unsugar_if(second).is_some() { // where the else would be let else_span = mk_sp(first.span.hi, second.span.lo); @@ -150,14 +149,15 @@ fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Exp else_span, "this looks like an `else if` but the `else` is missing", else_span, - "to remove this lint, add the missing `else` or add a new line before the second `if`"); + "to remove this lint, add the missing `else` or add a new line before the second \ + `if`"); } } } } /// Match `if` or `else if` expressions and return the `then` and `else` block. -fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)>{ +fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> { match expr.node { ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), diff --git a/src/len_zero.rs b/src/len_zero.rs index adf42b43383..548a3d92c2c 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -155,17 +155,11 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { if let Spanned{node: LitKind::Int(0, _), ..} = *lit { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { - span_lint_and_then(cx, - LEN_ZERO, - span, - "length comparison to zero", - |db| { - db.span_suggestion(span, - "consider using `is_empty`", - format!("{}{}.is_empty()", - op, - snippet(cx, args[0].span, "_"))); - }); + span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| { + db.span_suggestion(span, + "consider using `is_empty`", + format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_"))); + }); } } } diff --git a/src/loops.rs b/src/loops.rs index 5e862382742..600f22ea001 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -370,14 +370,14 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, - &format!("the loop variable `{}` is used to index `{}`. \ - Consider using `for ({}, item) in {}.iter().enumerate(){}{}` or similar iterators", - ident.node.name, - indexed, - ident.node.name, - indexed, - take, - skip)); + &format!("the loop variable `{}` is used to index `{}`. Consider using `for ({}, \ + item) in {}.iter().enumerate(){}{}` or similar iterators", + ident.node.name, + indexed, + ident.node.name, + indexed, + take, + skip)); } else { let repl = if starts_at_zero && take.is_empty() { format!("&{}", indexed) @@ -390,9 +390,9 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex expr.span, &format!("the loop variable `{}` is only used to index `{}`. \ Consider using `for item in {}` or similar iterators", - ident.node.name, - indexed, - repl)); + ident.node.name, + indexed, + repl)); } } } @@ -447,9 +447,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { "consider using the following if \ you are attempting to iterate \ over this range in reverse", - format!("({}..{}).rev()` ", - stop_snippet, - start_snippet)); + format!("({}..{}).rev()` ", stop_snippet, start_snippet)); }); } else if eq { // if they are equal, it's also problematic - this loop @@ -744,6 +742,7 @@ impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { /// Return true if the type of expr is one that provides IntoIterator impls /// for &T and &mut T, such as Vec. +#[cfg_attr(rustfmt, rustfmt_skip)] fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards diff --git a/src/map_clone.rs b/src/map_clone.rs index 8a4e1d770dc..4eac4dc6113 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,10 +1,8 @@ use rustc::lint::*; use rustc_front::hir::*; use utils::{CLONE_PATH, OPTION_PATH}; -use utils::{ - is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, - walk_ptrs_ty, walk_ptrs_ty_depth -}; +use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty, + walk_ptrs_ty_depth}; /// **What it does:** This lint checks for mapping clone() over an iterator. /// diff --git a/src/matches.rs b/src/matches.rs index d832888606a..1b05162c86a 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -134,10 +134,11 @@ impl LateLintPass for MatchPass { } } +#[cfg_attr(rustfmt, rustfmt_skip)] fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms.len() == 2 && - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() { + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() { let els = if is_unit_expr(&arms[1].body) { None } else if let ExprBlock(_) = arms[1].body.node { @@ -167,28 +168,28 @@ fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], lint, expr.span, "you seem to be trying to use match for destructuring a single pattern. \ - Consider using `if let`", |db| { - db.span_suggestion(expr.span, "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + Consider using `if let`", + |db| { + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); } } 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 = &[ - (&COW_PATH, "Borrowed"), - (&COW_PATH, "Cow::Borrowed"), - (&COW_PATH, "Cow::Owned"), - (&COW_PATH, "Owned"), - (&OPTION_PATH, "None"), - (&RESULT_PATH, "Err"), - (&RESULT_PATH, "Ok"), - ]; + let candidates = &[(&COW_PATH, "Borrowed"), + (&COW_PATH, "Cow::Borrowed"), + (&COW_PATH, "Cow::Owned"), + (&COW_PATH, "Owned"), + (&OPTION_PATH, "None"), + (&RESULT_PATH, "Err"), + (&RESULT_PATH, "Ok")]; let path = match arms[1].pats[0].node { PatKind::TupleStruct(ref path, Some(ref inner)) => { diff --git a/src/methods.rs b/src/methods.rs index 6ef779cd79e..94548cf9672 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -565,7 +565,9 @@ fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) { let ty = cx.tcx.expr_ty(arg); if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { if let ty::TyRef(..) = inner.sty { - let mut db = span_lint(cx, CLONE_DOUBLE_REF, expr.span, + let mut db = span_lint(cx, + CLONE_DOUBLE_REF, + expr.span, "using `clone` on a double-reference; \ this will copy the reference instead of cloning \ the inner type"); @@ -583,10 +585,7 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } let arg_ty = cx.tcx.expr_ty(&args[1]); if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { - span_lint(cx, - EXTEND_FROM_SLICE, - expr.span, - "use of `extend` to extend a Vec by a slice") + span_lint(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice") .span_suggestion(expr.span, "try this", format!("{}.extend_from_slice({}{})", diff --git a/src/print.rs b/src/print.rs index d7d83bfb437..ffe20d13cea 100644 --- a/src/print.rs +++ b/src/print.rs @@ -60,9 +60,8 @@ impl LateLintPass for PrintLint { // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) { if let ExprPath(None, ref path) = args[1].node { - if match_path(path, &DEBUG_FMT_METHOD_PATH) && - !is_in_debug_impl(cx, expr) && - is_expn_of(cx, expr.span, "panic").is_none() { + if match_path(path, &DEBUG_FMT_METHOD_PATH) && !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"); } } @@ -75,8 +74,10 @@ impl LateLintPass for PrintLint { fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { let map = &cx.tcx.map; - if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { // `fmt` method - if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) { // `Debug` impl + // `fmt` method + if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { + // `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"]); } diff --git a/src/regex.rs b/src/regex.rs index f58b6319d57..e8a71a2cb5a 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -147,7 +147,11 @@ fn str_span(base: Span, s: &str, c: usize) -> Span { Some((b, _)) => base.lo + BytePos(b as u32), _ => base.hi, }; - Span{ lo: lo, hi: lo, ..base } + Span { + lo: lo, + hi: lo, + ..base + } } fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { diff --git a/src/strings.rs b/src/strings.rs index fdba6302a46..f4318fc261a 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -144,7 +144,7 @@ impl LateLintPass for StringLitAsBytes { let msg = format!("calling `as_bytes()` on a string literal. \ Consider using a byte string literal instead: \ `b{}`", - snippet(cx, args[0].span, r#""foo""#)); + snippet(cx, args[0].span, r#""foo""#)); span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg); } } diff --git a/src/types.rs b/src/types.rs index 248aab32baa..27c67e78e03 100644 --- a/src/types.rs +++ b/src/types.rs @@ -390,7 +390,8 @@ impl LateLintPass for CastPass { 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, @@ -570,7 +571,7 @@ impl LateLintPass for CharLitAsU8 { truncates them"; let help = format!("Consider using a byte literal \ instead:\nb{}", - snippet(cx, e.span, "'x'")); + snippet(cx, e.span, "'x'")); span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); } } @@ -623,7 +624,10 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs type Extr<'a> = ExtremeExpr<'a>; // Put the expression in the form lhs < rhs or lhs <= rhs. - enum Rel { Lt, Le }; + enum Rel { + Lt, + Le, + }; let (rel, lhs2, rhs2) = match op { BiLt => (Rel::Lt, lhs, rhs), BiLe => (Rel::Le, lhs, rhs), diff --git a/src/utils/hir.rs b/src/utils/hir.rs index faa2082b7d0..6231970a0cc 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -38,10 +38,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { // TODO: tys - l.ty.is_none() && r.ty.is_none() && - both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) - } - else { + l.ty.is_none() && r.ty.is_none() && both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) + } else { false } } @@ -71,15 +69,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } match (&left.node, &right.node) { - (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => { - lmut == rmut && self.eq_expr(le, re) - } - (&ExprAgain(li), &ExprAgain(ri)) => { - both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) - } - (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => { - self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - } + (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => lmut == rmut && self.eq_expr(le, re), + (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.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) } @@ -87,79 +79,50 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) } - (&ExprBreak(li), &ExprBreak(ri)) => { - both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) - } - (&ExprBox(ref l), &ExprBox(ref r)) => { - self.eq_expr(l, r) - } + (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), + (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { - !self.ignore_fn && - self.eq_expr(lfun, rfun) && - self.eq_exprs(largs, rargs) - } - (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => { - self.eq_expr(lx, rx) && self.eq_ty(lt, rt) + !self.ignore_fn && self.eq_expr(lfun, rfun) && self.eq_exprs(largs, rargs) } + (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt), (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { lfident.node == rfident.node && self.eq_expr(lfexp, rfexp) } - (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { - self.eq_expr(la, ra) && self.eq_expr(li, ri) - } + (&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)) + 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), &ExprLoop(ref rb, ref rl)) => { - self.eq_block(lb, rb) && - both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) - + self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.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 lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { + 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 lname, ref ltys, ref largs), + &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { // TODO: tys - !self.ignore_fn && - lname.node == rname.node && - ltys.is_empty() && - rtys.is_empty() && - self.eq_exprs(largs, rargs) + !self.ignore_fn && lname.node == rname.node && ltys.is_empty() && rtys.is_empty() && + self.eq_exprs(largs, rargs) } (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { - both(lb, rb, |l, r| self.eq_expr(l, r)) && - both(le, re, |l, r| self.eq_expr(l, r)) - } - (&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)) + both(lb, rb, |l, r| self.eq_expr(l, r)) && both(le, re, |l, r| self.eq_expr(l, r)) } + (&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 lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath) } (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup), - (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { - li.node == ri.node && self.eq_expr(le, re) - } - (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => { - lop == rop && self.eq_expr(le, re) - } + (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re), + (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => lop == rop && self.eq_expr(le, re), (&ExprVec(ref l), &ExprVec(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.name.as_str() == r.name.as_str()) + self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) } _ => false, } @@ -172,39 +135,25 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { /// Check whether two patterns are the same. pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { match (&left.node, &right.node) { - (&PatKind::Box(ref l), &PatKind::Box(ref r)) => { - self.eq_pat(l, r) - } + (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => { - self.eq_path(lp, rp) && - both(la, ra, |l, r| { - over(l, r, |l, r| self.eq_pat(l, r)) - }) + self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r))) } (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => { - lb == rb && li.node.name.as_str() == ri.node.name.as_str() && - both(lp, rp, |l, r| self.eq_pat(l, r)) - } - (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => { - self.eq_expr(l, r) + lb == rb && li.node.name.as_str() == ri.node.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) } + (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { self.eq_qself(ls, rs) && self.eq_path(lp, rp) } - (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => { - over(l, r, |l, r| self.eq_pat(l, r)) - } + (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => 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) + 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::Vec(ref ls, ref li, ref le), &PatKind::Vec(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)) + 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, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index a8708eb8f7f..f2b0c1f4db1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -137,8 +137,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { iter.inspect(|_| len += 1) .zip(path) - .all(|(nm, p)| nm.name().as_str() == *p) - && len == path.len() + .all(|(nm, p)| nm.name().as_str() == *p) && len == path.len() }) } @@ -600,11 +599,10 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' /// Return the pre-expansion span if is this comes from an expansion of the macro `name`. pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { 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) - }) - }); + let span_name_span = cx.tcx + .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.as_str() == name => return Some(new_span), -- cgit 1.4.1-3-g733a5 From 100ca337421f57c4db57d5e3270c0ce1dbe86765 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 3 Mar 2016 01:24:20 +0530 Subject: Rust upgrade to 2016-03-02 nightly --- src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 27c67e78e03..cf90155b1fa 100644 --- a/src/types.rs +++ b/src/types.rs @@ -432,7 +432,7 @@ impl LateLintPass for TypeComplexityPass { fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { // enum variants are also struct fields now - check_type(cx, &field.node.ty); + check_type(cx, &field.ty); } fn check_item(&mut self, cx: &LateContext, item: &Item) { -- cgit 1.4.1-3-g733a5 From 79b0ad7441970dee66ebbdec9271ed8a6ea07944 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 3 Mar 2016 20:09:31 +0100 Subject: `vec!` now uses `box` --- src/vec.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/vec.rs b/src/vec.rs index fe3c1f90199..dda552bc8f9 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -3,7 +3,7 @@ use rustc::middle::ty::TypeVariants; use rustc_front::hir::*; use syntax::codemap::Span; use syntax::ptr::P; -use utils::{BOX_NEW_PATH, VEC_FROM_ELEM_PATH}; +use utils::VEC_FROM_ELEM_PATH; use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. @@ -33,9 +33,7 @@ impl LintPass for UselessVec { impl LateLintPass for UselessVec { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - unexpand_vec(cx, expr); - - // search for `&!vec[_]` expressions where the adjusted type is `&[_]` + // search for `&vec![_]` expressions where the adjusted type is `&[_]` if_let_chain!{[ let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, let TypeVariants::TySlice(..) = ty.ty.sty, @@ -71,7 +69,7 @@ impl LateLintPass for UselessVec { /// Represent the pre-expansion arguments of a `vec!` invocation. pub enum VecArgs<'a> { - /// `vec![elem, len]` + /// `vec![elem; len]` Repeat(&'a P<Expr>, &'a P<Expr>), /// `vec![a, b, c]` Vec(&'a [P<Expr>]), @@ -91,10 +89,8 @@ pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>> else if match_path(path, &["into_vec"]) && args.len() == 1 { // `vec![a, b, c]` case if_let_chain!{[ - let ExprCall(ref fun, ref args) = args[0].node, - let ExprPath(_, ref path) = fun.node, - match_path(path, &BOX_NEW_PATH) && args.len() == 1, - let ExprVec(ref args) = args[0].node + let ExprBox(ref boxed) = args[0].node, + let ExprVec(ref args) = boxed.node ], { return Some(VecArgs::Vec(&*args)); }} -- cgit 1.4.1-3-g733a5 From c7bf0681210bdf2e504f08967568fc7d807afea1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 4 Mar 2016 14:25:34 +0100 Subject: s/ctxt/TyCtxt --- src/cyclomatic_complexity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 3f956f1fc41..7034f87f59f 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -116,7 +116,7 @@ impl<'a> Visitor<'a> for MatchArmCounter { } } -struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::ctxt<'tcx>); +struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::TyCtxt<'tcx>); impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> { fn visit_expr(&mut self, e: &'a Expr) { -- cgit 1.4.1-3-g733a5 From e7fa117ff8d9c9f6b82aa94dcfbef3ac05cbe68a Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 4 Mar 2016 16:27:03 +0100 Subject: simplify cyclomatic complexity auxiliarly value computation previously the HIR was unnecessarily traversed twice --- src/cyclomatic_complexity.rs | 51 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 7034f87f59f..05f633ee0e4 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -48,18 +48,22 @@ impl CyclomaticComplexity { let n = cfg.graph.len_nodes() as u64; let e = cfg.graph.len_edges() as u64; let cc = e + 2 - n; - let mut arm_counter = MatchArmCounter(0); - arm_counter.visit_block(block); - let narms = arm_counter.0; - - let mut diverge_counter = DivergenceCounter(0, &cx.tcx); - diverge_counter.visit_block(block); - let divergence = diverge_counter.0; - - if cc + divergence < narms { - report_cc_bug(cx, cc, narms, divergence, span); + let mut helper = CCHelper { + match_arms: 0, + divergence: 0, + tcx: &cx.tcx, + }; + helper.visit_block(block); + let CCHelper { + match_arms, + divergence, + .. + } = helper; + + if cc + divergence < match_arms { + report_cc_bug(cx, cc, match_arms, divergence, span); } else { - let rust_cc = cc + divergence - narms; + let rust_cc = cc + divergence - match_arms; if rust_cc > self.limit.limit() { span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, @@ -98,35 +102,28 @@ impl LateLintPass for CyclomaticComplexity { } } -struct MatchArmCounter(u64); +struct CCHelper<'a, 'tcx: 'a> { + match_arms: u64, + divergence: u64, + tcx: &'a ty::TyCtxt<'tcx>, +} -impl<'a> Visitor<'a> for MatchArmCounter { +impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { fn visit_expr(&mut self, e: &'a Expr) { match e.node { ExprMatch(_, ref arms, _) => { walk_expr(self, e); let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum(); if arms_n > 1 { - self.0 += arms_n - 2; + self.match_arms += arms_n - 2; } } - ExprClosure(..) => {} - _ => walk_expr(self, e), - } - } -} - -struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::TyCtxt<'tcx>); - -impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> { - fn visit_expr(&mut self, e: &'a Expr) { - match e.node { ExprCall(ref callee, _) => { walk_expr(self, e); - let ty = self.1.node_id_to_type(callee.id); + let ty = self.tcx.node_id_to_type(callee.id); if let ty::TyBareFn(_, ty) = ty.sty { if ty.sig.skip_binder().output.diverges() { - self.0 += 1; + self.divergence += 1; } } } -- cgit 1.4.1-3-g733a5 From e421a0f8a3aa8a28ef06d5b8892c5c32e7d39f89 Mon Sep 17 00:00:00 2001 From: KALPESH KRISHNA <kalpeshk2011@gmail.com> Date: Fri, 4 Mar 2016 00:44:49 +0530 Subject: Warn about calling a closure in the same expression where it's defined. --- README.md | 3 +- src/lib.rs | 1 + src/misc_early.rs | 58 ++++++++++++++++++++++++++-- tests/compile-fail/eta.rs | 2 +- tests/compile-fail/redundant_closure_call.rs | 25 ++++++++++++ 5 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/redundant_closure_call.rs (limited to 'src') diff --git a/README.md b/README.md index 3a957a7e4c9..ff875085da2 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 129 lints included in this crate: +There are 130 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -99,6 +99,7 @@ name [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 | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`) +[redundant_closure_call](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call) | warn | Closures should not be called in the expression they are defined [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern) | warn | using `name @ _` in a pattern [regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro) | warn | finds use of `regex!(_)`, suggests `Regex::new(_)` instead [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used) | allow | using `Result.unwrap()`, which might be better handled diff --git a/src/lib.rs b/src/lib.rs index 7436dada020..803a4c2345c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,6 +272,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::TOPLEVEL_REF_ARG, misc::USED_UNDERSCORE_BINDING, misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::REDUNDANT_CLOSURE_CALL, misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, diff --git a/src/misc_early.rs b/src/misc_early.rs index 604e6002103..89a0763e2e3 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -3,8 +3,7 @@ use std::collections::HashMap; use syntax::ast::*; use syntax::codemap::Span; use syntax::visit::FnKind; -use utils::{span_lint, span_help_and_lint}; - +use utils::{span_lint, span_help_and_lint, snippet, span_lint_and_then}; /// **What it does:** This lint checks for structure field patterns bound to wildcards. /// /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. @@ -29,12 +28,24 @@ declare_lint! { "Function arguments having names which only differ by an underscore" } +/// **What it does:** This lint detects closures called in the same expression where they are defined. +/// +/// **Why is this bad?** It is unnecessarily adding to the expression's complexity. +/// +/// **Known problems:** None. +/// +/// **Example:** `(|| 42)()` +declare_lint! { + pub REDUNDANT_CLOSURE_CALL, Warn, + "Closures should not be called in the expression they are defined" +} + #[derive(Copy, Clone)] pub struct MiscEarly; impl LintPass for MiscEarly { fn get_lints(&self) -> LintArray { - lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT) + lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL) } } @@ -105,7 +116,7 @@ impl EarlyLintPass for MiscEarly { *correspondance, &format!("`{}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult", - arg_name[1..].to_owned())); + arg_name[1..].to_owned()));; } } else { registered_names.insert(arg_name, arg.pat.span); @@ -113,4 +124,43 @@ impl EarlyLintPass for MiscEarly { } } } + + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + if let ExprKind::Call(ref paren, _) = expr.node { + if let ExprKind::Paren(ref closure) = paren.node { + if let ExprKind::Closure(_, ref decl, ref block) = closure.node { + span_lint_and_then(cx, + REDUNDANT_CLOSURE_CALL, + expr.span, + "Try not to call a closure in the expression where it is declared.", + |db| { + if decl.inputs.len() == 0 { + let hint = format!("{}", snippet(cx, block.span, "..")); + db.span_suggestion(expr.span, "Try doing something like: ", hint); + } + }); + } + } + } + } + + fn check_block(&mut self, cx: &EarlyContext, block: &Block) { + for w in block.stmts.windows(2) { + if_let_chain! {[ + let StmtKind::Decl(ref first, _) = w[0].node, + let DeclKind::Local(ref local) = first.node, + let Option::Some(ref t) = local.init, + let ExprKind::Closure(_,_,_) = t.node, + let PatKind::Ident(_,sp_ident,_) = local.pat.node, + let StmtKind::Semi(ref second,_) = w[1].node, + let ExprKind::Assign(_,ref call) = second.node, + let ExprKind::Call(ref closure,_) = call.node, + 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"); + } + }} + } + } } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index 46680f2b8d8..0e72efe654e 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -1,6 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unknown_lints, unused, no_effect)] +#![allow(unknown_lints, unused, no_effect, redundant_closure_call)] #![deny(redundant_closure)] fn main() { diff --git a/tests/compile-fail/redundant_closure_call.rs b/tests/compile-fail/redundant_closure_call.rs new file mode 100644 index 00000000000..73830ecc9f1 --- /dev/null +++ b/tests/compile-fail/redundant_closure_call.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(redundant_closure_call)] + +fn main() { + let a = (|| 42)(); + //~^ ERROR Try not to call a closure in the expression where it is declared. + //~| HELP Try doing something like: + //~| SUGGESTION let a = 42; + + let mut i = 1; + let k = (|m| m+1)(i); //~ERROR Try not to call a closure in the expression where it is declared. + + k = (|a,b| a*b)(1,5); //~ERROR Try not to call a closure in the expression where it is declared. + + let closure = || 32; + i = closure(); //~ERROR Closure called just once immediately after it was declared + + let closure = |i| i+1; + i = closure(3); //~ERROR Closure called just once immediately after it was declared + + i = closure(4); +} + -- cgit 1.4.1-3-g733a5 From 2abb775de5bed06722ef0d9d14488d6e8777842f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 6 Mar 2016 14:10:04 +0100 Subject: Fix dogfood --- src/misc_early.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/misc_early.rs b/src/misc_early.rs index 89a0763e2e3..60e175d6382 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -134,7 +134,7 @@ impl EarlyLintPass for MiscEarly { expr.span, "Try not to call a closure in the expression where it is declared.", |db| { - if decl.inputs.len() == 0 { + if decl.inputs.is_empty() { let hint = format!("{}", snippet(cx, block.span, "..")); db.span_suggestion(expr.span, "Try doing something like: ", hint); } -- cgit 1.4.1-3-g733a5 From eb0a4934422941385a490ae9273ce8f6f05698e2 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 7 Mar 2016 16:30:02 +0100 Subject: Implement struct literal equality --- src/utils/hir.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 6231970a0cc..6b745c15e6f 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -117,6 +117,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath) } + (&ExprStruct(ref lpath, ref lf, ref lo), &ExprStruct(ref rpath, ref rf, ref ro)) => { + self.eq_path(lpath, rpath) && + both(lo, ro, |l, r| self.eq_expr(l, r)) && + over(lf, rf, |l, r| self.eq_field(l, r)) + } (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup), (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re), (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => lop == rop && self.eq_expr(le, re), @@ -132,6 +137,10 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { over(left, right, |l, r| self.eq_expr(l, r)) } + fn eq_field(&self, left: &Field, right: &Field) -> bool { + left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr) + } + /// Check whether two patterns are the same. pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { match (&left.node, &right.node) { -- cgit 1.4.1-3-g733a5 From 13bb22a68b1170a9e75fba0d1ded528fd7fe5139 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 7 Mar 2016 16:31:38 +0100 Subject: Remove all ExprRange Rustup to rustc 1.9.0-nightly (998a6720b 2016-03-07) --- src/loops.rs | 41 ++++++++++++++-------------- src/no_effect.rs | 11 +++++--- src/ranges.rs | 10 +++---- src/utils/hir.rs | 13 --------- src/utils/mod.rs | 60 ++++++++++++++++++++++++++++++++++++++++- tests/compile-fail/copies.rs | 32 +++++++++++++++++++++- tests/compile-fail/no_effect.rs | 3 ++- 7 files changed, 125 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 600f22ea001..723236c7ed7 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -12,8 +12,10 @@ use std::borrow::Cow; use std::collections::HashMap; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, - span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty}; + span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, + unsugar_range, walk_ptrs_ty}; use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; +use utils::UnsugaredRange; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. /// @@ -323,10 +325,9 @@ 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) { - if let ExprRange(Some(ref l), ref r) = arg.node { + if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(&arg) { // the var must be a single name if let PatKind::Ident(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { cx: cx, var: ident.node.name, @@ -348,19 +349,19 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex return; } - let starts_at_zero = is_integer_literal(l, 0); + let starts_at_zero = is_integer_literal(start, 0); let skip: Cow<_> = if starts_at_zero { "".into() } else { - format!(".skip({})", snippet(cx, l.span, "..")).into() + format!(".skip({})", snippet(cx, start.span, "..")).into() }; - let take: Cow<_> = if let Some(ref r) = *r { - if is_len_call(&r, &indexed) { + let take: Cow<_> = if let Some(ref end) = *end { + if is_len_call(&end, &indexed) { "".into() } else { - format!(".take({})", snippet(cx, r.span, "..")).into() + format!(".take({})", snippet(cx, end.span, "..")).into() } } else { "".into() @@ -416,27 +417,27 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... - if let ExprRange(Some(ref start_expr), Some(ref stop_expr)) = arg.node { + if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(&arg) { // ...and both sides are compile-time constant integers... - if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start_expr, ExprTypeChecked, None) { - if let Ok(stop_idx) = eval_const_expr_partial(&cx.tcx, stop_expr, ExprTypeChecked, None) { - // ...and the start index is greater than the stop index, + if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start, ExprTypeChecked, None) { + if let Ok(end_idx) = eval_const_expr_partial(&cx.tcx, end, ExprTypeChecked, None) { + // ...and the start index is greater than the end index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the // smaller value. - let (sup, eq) = match (start_idx, stop_idx) { - (ConstVal::Int(start_idx), ConstVal::Int(stop_idx)) => { - (start_idx > stop_idx, start_idx == stop_idx) + let (sup, eq) = match (start_idx, end_idx) { + (ConstVal::Int(start_idx), ConstVal::Int(end_idx)) => { + (start_idx > end_idx, start_idx == end_idx) } - (ConstVal::Uint(start_idx), ConstVal::Uint(stop_idx)) => { - (start_idx > stop_idx, start_idx == stop_idx) + (ConstVal::Uint(start_idx), ConstVal::Uint(end_idx)) => { + (start_idx > end_idx, start_idx == end_idx) } _ => (false, false), }; if sup { - let start_snippet = snippet(cx, start_expr.span, "_"); - let stop_snippet = snippet(cx, stop_expr.span, "_"); + let start_snippet = snippet(cx, start.span, "_"); + let end_snippet = snippet(cx, end.span, "_"); span_lint_and_then(cx, REVERSE_RANGE_LOOP, @@ -447,7 +448,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { "consider using the following if \ you are attempting to iterate \ over this range in reverse", - format!("({}..{}).rev()` ", stop_snippet, start_snippet)); + format!("({}..{}).rev()` ", end_snippet, start_snippet)); }); } else if eq { // if they are equal, it's also problematic - this loop diff --git a/src/no_effect.rs b/src/no_effect.rs index 65dfeb0d4be..59f7be94c23 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -23,15 +23,11 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { match expr.node { Expr_::ExprLit(..) | Expr_::ExprClosure(..) | - Expr_::ExprRange(None, None) | Expr_::ExprPath(..) => true, Expr_::ExprIndex(ref a, ref b) | - Expr_::ExprRange(Some(ref a), Some(ref b)) | Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b), Expr_::ExprVec(ref v) | Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), - Expr_::ExprRange(Some(ref inner), None) | - Expr_::ExprRange(None, Some(ref inner)) | Expr_::ExprRepeat(ref inner, _) | Expr_::ExprCast(ref inner, _) | Expr_::ExprType(ref inner, _) | @@ -55,6 +51,13 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { _ => false, } } + Expr_::ExprBlock(ref block) => { + block.stmts.is_empty() && if let Some(ref expr) = block.expr { + has_no_effect(cx, expr) + } else { + false + } + } _ => false, } } diff --git a/src/ranges.rs b/src/ranges.rs index 895bd180168..766d98b4e0b 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::{is_integer_literal, match_type, snippet}; +use utils::{is_integer_literal, match_type, snippet, unsugar_range, UnsugaredRange}; /// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. /// @@ -47,17 +47,17 @@ impl LateLintPass for StepByZero { instead") } else if name.as_str() == "zip" && args.len() == 2 { let iter = &args[0].node; - let zip_arg = &args[1].node; + let zip_arg = &args[1]; if_let_chain! { [ // .iter() call let ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = *iter, iter_name.as_str() == "iter", // range expression in .zip() call: 0..x.len() - let ExprRange(Some(ref from), Some(ref to)) = *zip_arg, - is_integer_literal(from, 0), + let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(zip_arg), + is_integer_literal(start, 0), // .len() call - let ExprMethodCall(Spanned { node: ref len_name, .. }, _, ref len_args) = to.node, + 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, diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 6b745c15e6f..0bd054a839a 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -109,9 +109,6 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { !self.ignore_fn && lname.node == rname.node && ltys.is_empty() && rtys.is_empty() && self.eq_exprs(largs, rargs) } - (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { - both(lb, rb, |l, r| self.eq_expr(l, r)) && both(le, re, |l, r| self.eq_expr(l, r)) - } (&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 lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { @@ -384,16 +381,6 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { self.hash_name(&name.node); self.hash_exprs(args); } - ExprRange(ref b, ref e) => { - let c: fn(_, _) -> _ = ExprRange; - c.hash(&mut self.s); - if let Some(ref b) = *b { - self.hash_expr(b); - } - if let Some(ref e) = *e { - self.hash_expr(e); - } - } ExprRepeat(ref e, ref l) => { let c: fn(_, _) -> _ = ExprRepeat; c.hash(&mut self.s); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index f2b0c1f4db1..b001d9530ed 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,7 +9,7 @@ use std::borrow::Cow; use std::mem; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use syntax::ast::{self, LitKind}; +use syntax::ast::{self, LitKind, RangeLimits}; use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; @@ -40,6 +40,12 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedLis pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; +pub const RANGE_FROM_PATH: [&'static str; 3] = ["std", "ops", "RangeFrom"]; +pub const RANGE_FULL_PATH: [&'static str; 3] = ["std", "ops", "RangeFull"]; +pub const RANGE_INCLUSIVE_NON_EMPTY_PATH: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE_PATH: [&'static str; 3] = ["std", "ops", "Range"]; +pub const RANGE_TO_INCLUSIVE_PATH: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; +pub const RANGE_TO_PATH: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; @@ -673,3 +679,55 @@ pub fn camel_case_from(s: &str) -> usize { } last_i } + +/// Represents a range akin to `ast::ExprKind::Range`. +pub struct UnsugaredRange<'a> { + pub start: Option<&'a Expr>, + pub end: Option<&'a Expr>, + pub limits: RangeLimits, +} + +/// Unsugar a `hir` range. +pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { + // To be removed when ranges get stable. + fn unwrap_unstable(expr: &Expr) -> &Expr { + if let ExprBlock(ref block) = expr.node { + if block.rules == BlockCheckMode::PushUnstableBlock || block.rules == BlockCheckMode::PopUnstableBlock { + if let Some(ref expr) = block.expr { + return expr; + } + } + } + + expr + } + + fn get_field<'a>(name: &str, fields: &'a [Field]) -> Option<&'a Expr> { + let expr = &fields.iter() + .find(|field| field.name.node.as_str() == name) + .unwrap_or_else(|| panic!("missing {} field for range", name)) + .expr; + + Some(unwrap_unstable(expr)) + } + + if let ExprStruct(ref path, ref fields, None) = unwrap_unstable(&expr).node { + if match_path(path, &RANGE_FROM_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen }) + } else if match_path(path, &RANGE_FULL_PATH) { + Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen }) + } else if match_path(path, &RANGE_INCLUSIVE_NON_EMPTY_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed }) + } else if match_path(path, &RANGE_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + } else if match_path(path, &RANGE_TO_INCLUSIVE_PATH) { + Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed }) + } else if match_path(path, &RANGE_TO_PATH) { + Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + } else { + None + } + } else { + None + } +} diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 7a17b345fa8..c1e1ba68b3e 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -1,4 +1,4 @@ -#![feature(plugin)] +#![feature(plugin, inclusive_range_syntax)] #![plugin(clippy)] #![allow(dead_code, no_effect)] @@ -10,16 +10,46 @@ fn bar<T>(_: T) {} fn foo() -> bool { unimplemented!() } +struct Foo { + bar: u8, +} + #[deny(if_same_then_else)] #[deny(match_same_arms)] fn if_same_then_else() -> Result<&'static str, ()> { if true { + Foo { bar: 42 }; + 0..10; + ..; + 0..; + ..10; + 0...10; foo(); } else { //~ERROR this `if` has identical blocks + Foo { bar: 42 }; + 0..10; + ..; + 0..; + ..10; + 0...10; foo(); } + if true { + Foo { bar: 42 }; + } + else { + Foo { bar: 43 }; + } + + if true { + 0..10; + } + else { + 0...10; + } + if true { foo(); foo(); diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index 52ea423a57d..344c82f3307 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -1,4 +1,4 @@ -#![feature(plugin, box_syntax)] +#![feature(plugin, box_syntax, inclusive_range_syntax)] #![plugin(clippy)] #![deny(no_effect)] @@ -39,6 +39,7 @@ fn main() { 5..; //~ERROR statement with no effect ..5; //~ERROR statement with no effect 5..6; //~ERROR statement with no effect + 5...6; //~ERROR statement with no effect [42, 55]; //~ERROR statement with no effect [42, 55][1]; //~ERROR statement with no effect (42, 55).1; //~ERROR statement with no effect -- cgit 1.4.1-3-g733a5 From 3c3a4549a8df25e9fcdd2e41a50311124cc0906c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 7 Mar 2016 16:55:12 +0100 Subject: Fix tests with inclusive ranges --- src/loops.rs | 5 +++-- tests/compile-fail/for_loop.rs | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 723236c7ed7..e41402ef85a 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -10,6 +10,7 @@ use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; use std::collections::HashMap; +use syntax::ast; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, @@ -417,7 +418,7 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... - if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(&arg) { + if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(&arg) { // ...and both sides are compile-time constant integers... if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start, ExprTypeChecked, None) { if let Ok(end_idx) = eval_const_expr_partial(&cx.tcx, end, ExprTypeChecked, None) { @@ -450,7 +451,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { over this range in reverse", format!("({}..{}).rev()` ", end_snippet, start_snippet)); }); - } else if eq { + } else if eq && limits != ast::RangeLimits::Closed { // if they are equal, it's also problematic - this loop // will never run. span_lint(cx, diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 8d483ccde7a..0853ae83cd7 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -1,4 +1,4 @@ -#![feature(plugin, step_by)] +#![feature(plugin, step_by, inclusive_range_syntax)] #![plugin(clippy)] use std::collections::*; @@ -118,11 +118,21 @@ fn main() { println!("{}", vec[i]); } + for i in 0...MAX_LEN { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(MAX_LEN)` + println!("{}", vec[i]); + } + for i in 5..10 { //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)` println!("{}", vec[i]); } + for i in 5...10 { + //~^ ERROR `i` is only used to index `vec`. Consider using `for item in vec.iter().take(10).skip(5)` + println!("{}", vec[i]); + } + for i in 5..vec.len() { //~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate().skip(5)` println!("{} {}", vec[i], i); @@ -140,6 +150,13 @@ fn main() { println!("{}", i); } + for i in 10...0 { + //~^ERROR this range is empty so this for loop will never run + //~|HELP consider + //~|SUGGESTION (0..10).rev() + println!("{}", i); + } + for i in MAX_LEN..0 { //~ERROR this range is empty so this for loop will never run //~|HELP consider //~|SUGGESTION (0..MAX_LEN).rev() @@ -150,6 +167,10 @@ fn main() { println!("{}", i); } + for i in 5...5 { // not an error, this is the range with only one element “5” + println!("{}", i); + } + for i in 0..10 { // not an error, the start index is less than the end index println!("{}", i); } -- cgit 1.4.1-3-g733a5 From 55fbf59f3bec1425e03b56516050912ed02147c9 Mon Sep 17 00:00:00 2001 From: KALPESH KRISHNA <kalpeshk2011@gmail.com> Date: Sun, 6 Mar 2016 20:31:17 +0530 Subject: Linting classical overflow checks. --- README.md | 3 +- src/lib.rs | 3 ++ src/overflow_check_conditional.rs | 41 ++++++++++++++++++++++++ tests/compile-fail/overflow_check_conditional.rs | 25 +++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/overflow_check_conditional.rs create mode 100644 tests/compile-fail/overflow_check_conditional.rs (limited to 'src') diff --git a/README.md b/README.md index ff875085da2..77518df6b39 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 130 lints included in this crate: +There are 131 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -92,6 +92,7 @@ name [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method when the `*or_else` would do [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing +[overflow_check_conditional](https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional) | warn | Using overflow checks which are likely to panic [panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout diff --git a/src/lib.rs b/src/lib.rs index 803a4c2345c..51292bea8b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,7 @@ pub mod needless_features; pub mod needless_update; pub mod no_effect; pub mod open_options; +pub mod overflow_check_conditional; pub mod panic; pub mod precedence; pub mod print; @@ -173,6 +174,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box formatting::Formatting); reg.register_late_lint_pass(box swap::Swap); reg.register_early_lint_pass(box if_not_else::IfNotElse); + reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -283,6 +285,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, + overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, panic::PANIC_PARAMS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs new file mode 100644 index 00000000000..7f4f4b3597c --- /dev/null +++ b/src/overflow_check_conditional.rs @@ -0,0 +1,41 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::{span_lint}; + +/// **What it does:** This lint finds classic overflow checks. +/// +/// **Why is this bad?** Most classic C overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. +/// +/// **Known problems:** None. +/// +/// **Example:** `a + b < a` +declare_lint!(pub OVERFLOW_CHECK_CONDITIONAL, Warn, + "Using overflow checks which are likely to panic"); + +#[derive(Copy, Clone)] +pub struct OverflowCheckConditional; + +impl LintPass for OverflowCheckConditional { + fn get_lints(&self) -> LintArray { + lint_array!(OVERFLOW_CHECK_CONDITIONAL) + } +} + +impl LateLintPass for OverflowCheckConditional { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! {[ + let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, + let BinOp_::BiLt = op.node, + let Expr_::ExprBinary(ref op2, ref add1, ref add2) = first.node, + let BinOp_::BiAdd = op2.node, + let Expr_::ExprPath(_,ref path1) = add1.node, + let Expr_::ExprPath(_, ref path2) = add2.node, + let Expr_::ExprPath(_, ref path3) = second.node, + (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, + cx.tcx.expr_ty(add1).is_integral(), + cx.tcx.expr_ty(add2).is_integral() + ], { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditons that will fail in Rust."); + }} + } +} diff --git a/tests/compile-fail/overflow_check_conditional.rs b/tests/compile-fail/overflow_check_conditional.rs new file mode 100644 index 00000000000..0b5e486df46 --- /dev/null +++ b/tests/compile-fail/overflow_check_conditional.rs @@ -0,0 +1,25 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(overflow_check_conditional)] + +fn main() { + let a: u32 = 1; + let b: u32 = 2; + let c: u32 = 3; + if a + b < a { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + + } + if a + b < b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + + } + if a + b < c { + + } + let i = 1.1; + let j = 2.2; + if i + j < i { + + } +} + -- cgit 1.4.1-3-g733a5 From d6d409414ea82866bac7f4c7698c16f9884a1b9b Mon Sep 17 00:00:00 2001 From: KALPESH KRISHNA <kalpeshk2011@gmail.com> Date: Tue, 8 Mar 2016 02:57:45 +0530 Subject: Adding underflow checks and tests --- src/overflow_check_conditional.rs | 15 +++++++++++++++ tests/compile-fail/overflow_check_conditional.rs | 12 ++++++++++++ 2 files changed, 27 insertions(+) (limited to 'src') diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index 7f4f4b3597c..c89a3dd2732 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -37,5 +37,20 @@ impl LateLintPass for OverflowCheckConditional { ], { span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditons that will fail in Rust."); }} + + if_let_chain! {[ + let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, + let BinOp_::BiGt = op.node, + let Expr_::ExprBinary(ref op2, ref sub1, ref sub2) = first.node, + let BinOp_::BiSub = op2.node, + let Expr_::ExprPath(_,ref path1) = sub1.node, + let Expr_::ExprPath(_, ref path2) = sub2.node, + let Expr_::ExprPath(_, ref path3) = second.node, + (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, + cx.tcx.expr_ty(sub1).is_integral(), + cx.tcx.expr_ty(sub2).is_integral() + ], { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditons that will fail in Rust."); + }} } } diff --git a/tests/compile-fail/overflow_check_conditional.rs b/tests/compile-fail/overflow_check_conditional.rs index 0b5e486df46..a59fa2a444a 100644 --- a/tests/compile-fail/overflow_check_conditional.rs +++ b/tests/compile-fail/overflow_check_conditional.rs @@ -12,14 +12,26 @@ fn main() { } if a + b < b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + } + if a - b > b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + + } + if a - b > a { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + } if a + b < c { + } + if a - b < c { + } let i = 1.1; let j = 2.2; if i + j < i { + } + if i - j < i { + } } -- cgit 1.4.1-3-g733a5 From 8bbd8b0b9263718b4c0c6c86b5ab2fb038aa3f5b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 7 Mar 2016 23:24:11 +0100 Subject: Fix ICE in for_loop with globals --- src/loops.rs | 25 ++++++++++++++++++------- tests/compile-fail/for_loop.rs | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index e41402ef85a..462ca7c49f6 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -345,9 +345,11 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex .unwrap_or_else(|| unreachable!() /* len == 1 */); // ensure that the indexed variable was declared before the loop, see #601 - let pat_extent = cx.tcx.region_maps.var_scope(pat.id); - if cx.tcx.region_maps.is_subscope_of(indexed_extent, pat_extent) { - return; + if let Some(indexed_extent) = indexed_extent { + let pat_extent = cx.tcx.region_maps.var_scope(pat.id); + if cx.tcx.region_maps.is_subscope_of(indexed_extent, pat_extent) { + return; + } } let starts_at_zero = is_integer_literal(start, 0); @@ -669,7 +671,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference var: Name, // var name to look for as index - indexed: HashMap<Name, CodeExtent>, // indexed variables + indexed: HashMap<Name, Option<CodeExtent>>, // indexed variables, the extent is None for global nonindex: bool, // has the var been used otherwise? } @@ -687,9 +689,18 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { ], { let def_map = self.cx.tcx.def_map.borrow(); if let Some(def) = def_map.get(&seqexpr.id) { - let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); - self.indexed.insert(seqvar.segments[0].identifier.name, extent); - return; // no need to walk further + match def.base_def { + Def::Local(..) | Def::Upvar(..) => { + let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); + self.indexed.insert(seqvar.segments[0].identifier.name, Some(extent)); + return; // no need to walk further + } + Def::Static(..) | Def::Const(..) => { + self.indexed.insert(seqvar.segments[0].identifier.name, None); + return; // no need to walk further + } + _ => (), + } } } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 0853ae83cd7..bbdf9d8f1b5 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -3,6 +3,9 @@ use std::collections::*; +static STATIC: [usize; 4] = [ 0, 1, 8, 16 ]; +const CONST: [usize; 4] = [ 0, 1, 8, 16 ]; + #[deny(clippy)] fn for_loop_over_option_and_result() { let option = Some(1); @@ -95,6 +98,18 @@ fn main() { //~^ ERROR `i` is only used to index `vec`. Consider using `for item in &vec` println!("{}", vec[i]); } + + // ICE #746 + for j in 0..4 { + //~^ ERROR `j` is only used to index `STATIC` + println!("{:?}", STATIC[j]); + } + + for j in 0..4 { + //~^ ERROR `j` is only used to index `CONST` + println!("{:?}", CONST[j]); + } + for i in 0..vec.len() { //~^ ERROR `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate()` println!("{} {}", vec[i], i); -- cgit 1.4.1-3-g733a5 From 9faffd28705b39c37526f964b637bb405e348f35 Mon Sep 17 00:00:00 2001 From: KALPESH KRISHNA <kalpeshk2011@gmail.com> Date: Tue, 8 Mar 2016 11:03:30 +0530 Subject: Adding symmetric lints and test cases --- src/overflow_check_conditional.rs | 55 ++++++++++++++++-------- tests/compile-fail/overflow_check_conditional.rs | 24 +++++++++++ 2 files changed, 60 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index c89a3dd2732..2dccbfdb26a 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -1,14 +1,16 @@ +#![allow(cyclomatic_complexity)] use rustc::lint::*; use rustc_front::hir::*; use utils::{span_lint}; -/// **What it does:** This lint finds classic overflow checks. +/// **What it does:** This lint finds classic underflow / overflow checks. /// -/// **Why is this bad?** Most classic C overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. +/// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. /// /// **Known problems:** None. /// /// **Example:** `a + b < a` + declare_lint!(pub OVERFLOW_CHECK_CONDITIONAL, Warn, "Using overflow checks which are likely to panic"); @@ -22,35 +24,50 @@ impl LintPass for OverflowCheckConditional { } impl LateLintPass for OverflowCheckConditional { + // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain! {[ let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, - let BinOp_::BiLt = op.node, - let Expr_::ExprBinary(ref op2, ref add1, ref add2) = first.node, - let BinOp_::BiAdd = op2.node, - let Expr_::ExprPath(_,ref path1) = add1.node, - let Expr_::ExprPath(_, ref path2) = add2.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, (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, - cx.tcx.expr_ty(add1).is_integral(), - cx.tcx.expr_ty(add2).is_integral() + cx.tcx.expr_ty(ident1).is_integral(), + cx.tcx.expr_ty(ident2).is_integral() ], { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditons that will fail in Rust."); + 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 conditons 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 conditons that will fail in Rust."); + } + } }} if_let_chain! {[ let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node, - let BinOp_::BiGt = op.node, - let Expr_::ExprBinary(ref op2, ref sub1, ref sub2) = first.node, - let BinOp_::BiSub = op2.node, - let Expr_::ExprPath(_,ref path1) = sub1.node, - let Expr_::ExprPath(_, ref path2) = sub2.node, - let Expr_::ExprPath(_, ref path3) = second.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, (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, - cx.tcx.expr_ty(sub1).is_integral(), - cx.tcx.expr_ty(sub2).is_integral() + cx.tcx.expr_ty(ident1).is_integral(), + cx.tcx.expr_ty(ident2).is_integral() ], { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditons that will fail in Rust."); + 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 conditons 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 conditons that will fail in Rust."); + } + } }} } } diff --git a/tests/compile-fail/overflow_check_conditional.rs b/tests/compile-fail/overflow_check_conditional.rs index a59fa2a444a..df629146dee 100644 --- a/tests/compile-fail/overflow_check_conditional.rs +++ b/tests/compile-fail/overflow_check_conditional.rs @@ -9,21 +9,39 @@ fn main() { let c: u32 = 3; if a + b < a { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + } + if a > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + } if a + b < b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + } + if b > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + } if a - b > b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + } + if b < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + } if a - b > a { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + } + if a < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + } if a + b < c { + } + if c > a + b { + } if a - b < c { + } + if c > a - b { + } let i = 1.1; let j = 2.2; @@ -32,6 +50,12 @@ fn main() { } if i - j < i { + } + if i > i + j { + + } + if i - j < i { + } } -- cgit 1.4.1-3-g733a5 From bf20b40664d699954599d4e7e333b756cec0ad59 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 8 Mar 2016 15:10:02 +0100 Subject: fix cyclomatic complexity lint triggering because of short circuit operations --- src/cyclomatic_complexity.rs | 30 +++++++++++++++++------- src/overflow_check_conditional.rs | 9 ++++--- src/utils/hir.rs | 2 -- tests/compile-fail/cyclomatic_complexity.rs | 14 +++++++++-- tests/compile-fail/overflow_check_conditional.rs | 17 +++++++------- 5 files changed, 45 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 05f633ee0e4..b1b578af759 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -51,19 +51,21 @@ impl CyclomaticComplexity { let mut helper = CCHelper { match_arms: 0, divergence: 0, + short_circuits: 0, tcx: &cx.tcx, }; helper.visit_block(block); let CCHelper { match_arms, divergence, + short_circuits, .. } = helper; - if cc + divergence < match_arms { - report_cc_bug(cx, cc, match_arms, divergence, span); + if cc + divergence < match_arms + short_circuits { + report_cc_bug(cx, cc, match_arms, divergence, short_circuits, span); } else { - let rust_cc = cc + divergence - match_arms; + let rust_cc = cc + divergence - match_arms - short_circuits; if rust_cc > self.limit.limit() { span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, @@ -105,6 +107,7 @@ impl LateLintPass for CyclomaticComplexity { struct CCHelper<'a, 'tcx: 'a> { match_arms: u64, divergence: u64, + short_circuits: u64, // && and || tcx: &'a ty::TyCtxt<'tcx>, } @@ -128,29 +131,38 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { } } ExprClosure(..) => {} + ExprBinary(op, _, _) => { + walk_expr(self, e); + match op.node { + BiAnd | BiOr => self.short_circuits += 1, + _ => {}, + } + } _ => walk_expr(self, e), } } } #[cfg(feature="debugging")] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { cx.sess().span_bug(span, &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ - div = {}. Please file a bug report.", + div = {}, shorts = {}. Please file a bug report.", cc, narms, - div));; + div, + shorts));; } #[cfg(not(feature="debugging"))] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) { +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { cx.sess().span_note_without_error(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ - = {}, arms = {}, div = {}. Please file a bug report.", + = {}, arms = {}, div = {}, shorts = {}. Please file a bug report.", cc, narms, - div)); + div, + shorts)); } } diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index 2dccbfdb26a..823cb696901 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -1,4 +1,3 @@ -#![allow(cyclomatic_complexity)] use rustc::lint::*; use rustc_front::hir::*; use utils::{span_lint}; @@ -38,12 +37,12 @@ impl LateLintPass for OverflowCheckConditional { ], { 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 conditons 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 conditons 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."); } } }} @@ -60,12 +59,12 @@ impl LateLintPass for OverflowCheckConditional { ], { 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 conditons 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 conditons 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/src/utils/hir.rs b/src/utils/hir.rs index 0bd054a839a..b4b786f9743 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -55,8 +55,6 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) } - // ok, it’s a big function, but mostly one big match with simples cases - #[allow(cyclomatic_complexity)] pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { if self.ignore_fn && differing_macro_contexts(left.span, right.span) { return false; diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 3a4a83af5c6..30a05c3f87d 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -1,6 +1,6 @@ #![feature(plugin, custom_attribute)] #![plugin(clippy)] -#![deny(clippy)] +#![allow(clippy)] #![deny(cyclomatic_complexity)] #![allow(unused)] @@ -90,7 +90,7 @@ fn main() { //~ERROR the function has a cyclomatic complexity of 28 } #[cyclomatic_complexity = "0"] -fn kaboom() { //~ ERROR: the function has a cyclomatic complexity of 8 +fn kaboom() { //~ ERROR: the function has a cyclomatic complexity of 7 let n = 0; 'a: for i in 0..20 { 'b: for j in i..20 { @@ -135,6 +135,16 @@ fn bloo() { } } +#[cyclomatic_complexity = "0"] +fn lots_of_short_circuits() -> bool { //~ ERROR: the function has a cyclomatic complexity of 1 + true && false && true && false && true && false && true +} + +#[cyclomatic_complexity = "0"] +fn lots_of_short_circuits2() -> bool { //~ ERROR: the function has a cyclomatic complexity of 1 + true || false || true || false || true || false || true +} + #[cyclomatic_complexity = "0"] fn baa() { //~ ERROR: the function has a cyclomatic complexity of 2 let x = || match 99 { diff --git a/tests/compile-fail/overflow_check_conditional.rs b/tests/compile-fail/overflow_check_conditional.rs index df629146dee..db7b2792484 100644 --- a/tests/compile-fail/overflow_check_conditional.rs +++ b/tests/compile-fail/overflow_check_conditional.rs @@ -7,28 +7,28 @@ fn main() { let a: u32 = 1; let b: u32 = 2; let c: u32 = 3; - if a + b < a { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + if a + b < a { //~ERROR You are trying to use classic C overflow conditions that will fail in Rust. } - if a > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + if a > a + b { //~ERROR You are trying to use classic C overflow conditions that will fail in Rust. } - if a + b < b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + if a + b < b { //~ERROR You are trying to use classic C overflow conditions that will fail in Rust. } - if b > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust. + if b > a + b { //~ERROR You are trying to use classic C overflow conditions that will fail in Rust. } - if a - b > b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + if a - b > b { //~ERROR You are trying to use classic C underflow conditions that will fail in Rust. } - if b < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + if b < a - b { //~ERROR You are trying to use classic C underflow conditions that will fail in Rust. } - if a - b > a { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + if a - b > a { //~ERROR You are trying to use classic C underflow conditions that will fail in Rust. } - if a < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust. + if a < a - b { //~ERROR You are trying to use classic C underflow conditions that will fail in Rust. } if a + b < c { @@ -58,4 +58,3 @@ fn main() { } } - -- cgit 1.4.1-3-g733a5 From 204c12c99ea1d3266bf067700351e8e6468a35d2 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 1 Mar 2016 15:15:39 +0100 Subject: Lint unused labels --- README.md | 3 +- src/lib.rs | 3 ++ src/unused_label.rs | 78 +++++++++++++++++++++++++++++++++++++ tests/compile-fail/unused_labels.rs | 35 +++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/unused_label.rs create mode 100755 tests/compile-fail/unused_labels.rs (limited to 'src') diff --git a/README.md b/README.md index 77518df6b39..3b0a4f8820c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 131 lints included in this crate: +There are 132 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -131,6 +131,7 @@ name [unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 [unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop +[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore diff --git a/src/lib.rs b/src/lib.rs index 51292bea8b2..bb9d9b620ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod types; pub mod unicode; +pub mod unused_label; pub mod vec; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -175,6 +176,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box swap::Swap); reg.register_early_lint_pass(box if_not_else::IfNotElse); reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); + reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -309,6 +311,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, + unused_label::UNUSED_LABEL, vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/src/unused_label.rs b/src/unused_label.rs new file mode 100644 index 00000000000..f2ecad7cc82 --- /dev/null +++ b/src/unused_label.rs @@ -0,0 +1,78 @@ +use rustc::lint::*; +use rustc_front::hir; +use rustc_front::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; +use std::collections::HashMap; +use syntax::ast; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::{in_macro, span_lint}; + +/// **What it does:** This lint checks for unused labels. +/// +/// **Why is this bad?** Maybe the label should be used in which case there is an error in the +/// code or it should be removed. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// ```rust,ignore +/// fn unused_label() { +/// 'label: for i in 1..2 { +/// if i > 4 { continue } +/// } +/// ``` +declare_lint! { + pub UNUSED_LABEL, + Warn, + "unused label" +} + +pub struct UnusedLabel; + +#[derive(Default)] +struct UnusedLabelVisitor { + labels: HashMap<InternedString, Span>, +} + +impl UnusedLabelVisitor { + pub fn new() -> UnusedLabelVisitor { + ::std::default::Default::default() + } +} + +impl LintPass for UnusedLabel { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_LABEL) + } +} + +impl LateLintPass for UnusedLabel { + fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Block, span: Span, _: ast::NodeId) { + if in_macro(cx, span) { + return; + } + + let mut v = UnusedLabelVisitor::new(); + walk_fn(&mut v, kind, decl, body, span); + + for (label, span) in v.labels { + span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); + } + } +} + +impl<'v> Visitor<'v> for UnusedLabelVisitor { + fn visit_expr(&mut self, expr: &hir::Expr) { + match expr.node { + hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { + self.labels.remove(&label.node.name.as_str()); + } + hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { + self.labels.insert(label.name.as_str(), expr.span); + } + _ => (), + } + + walk_expr(self, expr); + } +} diff --git a/tests/compile-fail/unused_labels.rs b/tests/compile-fail/unused_labels.rs new file mode 100755 index 00000000000..26b4d4a2f3b --- /dev/null +++ b/tests/compile-fail/unused_labels.rs @@ -0,0 +1,35 @@ +#![plugin(clippy)] +#![feature(plugin)] + +#![allow(dead_code, items_after_statements)] +#![deny(unused_label)] + +fn unused_label() { + 'label: for i in 1..2 { //~ERROR: unused label `'label` + if i > 4 { continue } + } +} + +fn foo() { + 'same_label_in_two_fns: loop { + break 'same_label_in_two_fns; + } +} + + +fn bla() { + 'a: loop { break } //~ERROR: unused label `'a` + fn blub() {} +} + +fn main() { + 'a: for _ in 0..10 { + while let Some(42) = None { + continue 'a; + } + } + + 'same_label_in_two_fns: loop { //~ERROR: unused label `'same_label_in_two_fns` + let _ = 1; + } +} -- cgit 1.4.1-3-g733a5 From d7129f560d4a47d95a0b2f84ebf3b15a9b9f79c6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 1 Mar 2016 16:25:15 +0100 Subject: Lint types with `fn new() -> Self` and no `Default` impl --- README.md | 3 +- src/lib.rs | 3 ++ src/methods.rs | 33 +++++----------- src/misc.rs | 2 +- src/new_without_default.rs | 63 +++++++++++++++++++++++++++++++ src/utils/mod.rs | 20 +++++++++- tests/compile-fail/methods.rs | 2 +- tests/compile-fail/new_without_default.rs | 35 +++++++++++++++++ 8 files changed, 132 insertions(+), 29 deletions(-) create mode 100644 src/new_without_default.rs create mode 100755 tests/compile-fail/new_without_default.rs (limited to 'src') diff --git a/README.md b/README.md index 3b0a4f8820c..9f3c30d39b3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 132 lints included in this crate: +There are 133 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -83,6 +83,7 @@ name [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields [new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method +[new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file diff --git a/src/lib.rs b/src/lib.rs index bb9d9b620ab..8c619a1eaf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,6 +77,7 @@ pub mod mutex_atomic; pub mod needless_bool; pub mod needless_features; pub mod needless_update; +pub mod new_without_default; pub mod no_effect; pub mod open_options; pub mod overflow_check_conditional; @@ -177,6 +178,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box if_not_else::IfNotElse); reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_late_lint_pass(box unused_label::UnusedLabel); + reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -285,6 +287,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, + new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, diff --git a/src/methods.rs b/src/methods.rs index 94548cf9672..663c7dd1bc4 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -10,8 +10,8 @@ use std::{fmt, iter}; use syntax::codemap::Span; use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, - match_type, method_chain_args, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, - walk_ptrs_ty, walk_ptrs_ty_depth}; + match_type, method_chain_args, returns_self, snippet, snippet_opt, span_lint, + span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, VEC_PATH}; use utils::MethodArgs; @@ -431,26 +431,11 @@ impl LateLintPass for MethodsPass { } } - if &name.as_str() == &"new" { - let returns_self = if let FunctionRetTy::Return(ref ret_ty) = sig.decl.output { - let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); - let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id); - - if let Some(&ret_ty) = ret_ty { - ret_ty.walk().any(|t| t == ty) - } else { - false - } - } else { - false - }; - - if !returns_self { - span_lint(cx, - NEW_RET_NO_SELF, - sig.explicit_self.span, - "methods called `new` usually return `Self`"); - } + if &name.as_str() == &"new" && !returns_self(cx, &sig.decl.output, ty) { + span_lint(cx, + NEW_RET_NO_SELF, + sig.explicit_self.span, + "methods called `new` usually return `Self`"); } } } @@ -485,7 +470,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) return false; }; - if implements_trait(cx, arg_ty, default_trait_id, None) { + if implements_trait(cx, arg_ty, default_trait_id, Vec::new()) { span_lint(cx, OR_FUN_CALL, span, @@ -869,7 +854,7 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { /// This checks whether a given type is known to implement Debug. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { match cx.tcx.lang_items.debug_trait() { - Some(debug) => implements_trait(cx, ty, debug, Some(vec![])), + Some(debug) => implements_trait(cx, ty, debug, Vec::new()), None => false, } } diff --git a/src/misc.rs b/src/misc.rs index fae780e4ced..c7aeb7f9a2f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -253,7 +253,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S None => return, }; - if !implements_trait(cx, arg_ty, partial_eq_trait_id, Some(vec![other_ty])) { + if !implements_trait(cx, arg_ty, partial_eq_trait_id, vec![other_ty]) { return; } diff --git a/src/new_without_default.rs b/src/new_without_default.rs new file mode 100644 index 00000000000..4666336495c --- /dev/null +++ b/src/new_without_default.rs @@ -0,0 +1,63 @@ +use rustc::lint::*; +use rustc_front::hir; +use rustc_front::intravisit::FnKind; +use syntax::ast; +use syntax::codemap::Span; +use utils::{get_trait_def_id, implements_trait, in_external_macro, returns_self, span_lint, DEFAULT_TRAIT_PATH}; + +/// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` +/// implementation. +/// +/// **Why is this bad?** User might expect to be able to use `Default` is the type can be +/// constructed without arguments. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ```rust,ignore +/// struct Foo; +/// +/// impl Foo { +/// fn new() -> Self { +/// Foo +/// } +/// } +/// ``` +declare_lint! { + pub NEW_WITHOUT_DEFAULT, + Warn, + "`fn new() -> Self` method without `Default` implementation" +} + +#[derive(Copy,Clone)] +pub struct NewWithoutDefault; + +impl LintPass for NewWithoutDefault { + fn get_lints(&self) -> LintArray { + lint_array!(NEW_WITHOUT_DEFAULT) + } +} + +impl LateLintPass for NewWithoutDefault { + fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, id: ast::NodeId) { + if in_external_macro(cx, span) { + return; + } + + if let FnKind::Method(name, _, _) = kind { + if decl.inputs.is_empty() && name.as_str() == "new" { + let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; + + if returns_self(cx, &decl.output, ty) { + if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { + if !implements_trait(cx, ty, default_trait_id, Vec::new()) { + span_lint(cx, NEW_WITHOUT_DEFAULT, span, + &format!("you should consider adding a `Default` implementation for `{}`", ty)); + } + } + } + } + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index b001d9530ed..46feafb1de4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -264,7 +264,7 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { /// 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: Option<Vec<ty::Ty<'tcx>>>) + ty_params: Vec<ty::Ty<'tcx>>) -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); @@ -274,7 +274,7 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id, 0, ty, - ty_params.unwrap_or_default()); + ty_params); traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) } @@ -731,3 +731,19 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { None } } + +/// Return whether a method returns `Self`. +pub fn returns_self(cx: &LateContext, ret: &FunctionRetTy, ty: ty::Ty) -> bool { + if let FunctionRetTy::Return(ref ret_ty) = *ret { + let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); + let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id); + + if let Some(&ret_ty) = ret_ty { + ret_ty.walk().any(|t| t == ty) + } else { + false + } + } else { + false + } +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index c450c953284..0acab8be4fb 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(unused, print_stdout, non_ascii_literal)] +#![allow(unused, print_stdout, non_ascii_literal, new_without_default)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/compile-fail/new_without_default.rs b/tests/compile-fail/new_without_default.rs new file mode 100755 index 00000000000..5f00179a9a2 --- /dev/null +++ b/tests/compile-fail/new_without_default.rs @@ -0,0 +1,35 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(dead_code)] +#![deny(new_without_default)] + +struct Foo; + +impl Foo { + fn new() -> Foo { Foo } //~ERROR: you should consider adding a `Default` implementation for `Foo` +} + +struct Bar; + +impl Bar { + fn new() -> Self { Bar } //~ERROR: you should consider adding a `Default` implementation for `Bar` +} + +struct Ok; + +impl Ok { + fn new() -> Self { Ok } +} + +impl Default for Ok { + fn default() -> Self { Ok } +} + +struct Params; + +impl Params { + fn new(_: u32) -> Self { Params } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 8e9e858b786c262185b279be2d78e9eea0a81ed8 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 1 Mar 2016 20:38:21 +0100 Subject: Remove uses of `ast_ty_to_ty_cache` --- src/methods.rs | 5 +++-- src/new_without_default.rs | 12 +++++++----- src/ptr_arg.rs | 41 +++++++++++++++++++++-------------------- src/utils/mod.rs | 17 +++++------------ 4 files changed, 36 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 663c7dd1bc4..3ed75fdffeb 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -10,7 +10,7 @@ use std::{fmt, iter}; use syntax::codemap::Span; use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, - match_type, method_chain_args, returns_self, snippet, snippet_opt, span_lint, + match_type, method_chain_args, return_ty, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, VEC_PATH}; @@ -431,7 +431,8 @@ impl LateLintPass for MethodsPass { } } - if &name.as_str() == &"new" && !returns_self(cx, &sig.decl.output, ty) { + let ret_ty = return_ty(cx.tcx.node_id_to_type(implitem.id)); + if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| t == ty)) { span_lint(cx, NEW_RET_NO_SELF, sig.explicit_self.span, diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 4666336495c..89467f1dc55 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -3,7 +3,7 @@ use rustc_front::hir; use rustc_front::intravisit::FnKind; use syntax::ast; use syntax::codemap::Span; -use utils::{get_trait_def_id, implements_trait, in_external_macro, returns_self, span_lint, DEFAULT_TRAIT_PATH}; +use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, span_lint, DEFAULT_TRAIT_PATH}; /// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` /// implementation. @@ -47,13 +47,15 @@ impl LateLintPass for NewWithoutDefault { if let FnKind::Method(name, _, _) = kind { if decl.inputs.is_empty() && name.as_str() == "new" { - let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; + let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; - if returns_self(cx, &decl.output, ty) { + let ret_ty = return_ty(cx.tcx.node_id_to_type(id)); + + if Some(self_ty) == ret_ty { if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { - if !implements_trait(cx, ty, default_trait_id, Vec::new()) { + if !implements_trait(cx, self_ty, default_trait_id, Vec::new()) { span_lint(cx, NEW_WITHOUT_DEFAULT, span, - &format!("you should consider adding a `Default` implementation for `{}`", ty)); + &format!("you should consider adding a `Default` implementation for `{}`", self_ty)); } } } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index c02e5609b8c..85baf3310c3 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -6,6 +6,7 @@ use rustc::front::map::NodeItem; use rustc::lint::*; use rustc::middle::ty; use rustc_front::hir::*; +use syntax::ast::NodeId; use utils::{STRING_PATH, VEC_PATH}; use utils::{span_lint, match_type}; @@ -35,7 +36,7 @@ impl LintPass for PtrArg { impl LateLintPass for PtrArg { fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemFn(ref decl, _, _, _, _, _) = item.node { - check_fn(cx, decl); + check_fn(cx, decl, item.id); } } @@ -46,34 +47,34 @@ impl LateLintPass for PtrArg { return; // ignore trait impls } } - check_fn(cx, &sig.decl); + check_fn(cx, &sig.decl, item.id); } } fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { - check_fn(cx, &sig.decl); + check_fn(cx, &sig.decl, item.id); } } } -fn check_fn(cx: &LateContext, decl: &FnDecl) { - for arg in &decl.inputs { - if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&arg.ty.id) { - if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { - if match_type(cx, ty, &VEC_PATH) { - span_lint(cx, - PTR_ARG, - arg.ty.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices. Consider changing the type to `&[...]`"); - } else if match_type(cx, ty, &STRING_PATH) { - span_lint(cx, - PTR_ARG, - arg.ty.span, - "writing `&String` instead of `&str` involves a new object where a slice will do. \ - Consider changing the type to `&str`"); - } +fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { + let fn_ty = cx.tcx.node_id_to_type(fn_id).fn_sig().skip_binder(); + + 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, &VEC_PATH) { + span_lint(cx, + PTR_ARG, + arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ + with non-Vec-based slices. Consider changing the type to `&[...]`"); + } else if match_type(cx, ty, &STRING_PATH) { + span_lint(cx, + PTR_ARG, + arg.ty.span, + "writing `&String` instead of `&str` involves a new object where a slice will do. \ + Consider changing the type to `&str`"); } } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 46feafb1de4..bef4baea67e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -732,18 +732,11 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { } } -/// Return whether a method returns `Self`. -pub fn returns_self(cx: &LateContext, ret: &FunctionRetTy, ty: ty::Ty) -> bool { - if let FunctionRetTy::Return(ref ret_ty) = *ret { - let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow(); - let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id); - - if let Some(&ret_ty) = ret_ty { - ret_ty.walk().any(|t| t == ty) - } else { - false - } +/// Convenience function to get the return type of a function or `None` if the function diverges. +pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> { + if let ty::FnConverging(ret_ty) = fun.fn_sig().skip_binder().output { + Some(ret_ty) } else { - false + None } } -- cgit 1.4.1-3-g733a5 From 052f5984e772513654be815a1eac08997db6839c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 3 Mar 2016 19:46:10 +0100 Subject: Fix types comparison --- src/methods.rs | 4 ++-- src/new_without_default.rs | 22 +++++++++++----------- src/utils/mod.rs | 8 ++++++++ tests/compile-fail/methods.rs | 19 +++++++++++++++++++ tests/compile-fail/new_without_default.rs | 9 +++++++++ 5 files changed, 49 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 3ed75fdffeb..6d33f31d45c 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -10,7 +10,7 @@ use std::{fmt, iter}; use syntax::codemap::Span; use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, - match_type, method_chain_args, return_ty, snippet, snippet_opt, span_lint, + match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, VEC_PATH}; @@ -432,7 +432,7 @@ impl LateLintPass for MethodsPass { } let ret_ty = return_ty(cx.tcx.node_id_to_type(implitem.id)); - if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| t == ty)) { + if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty))) { span_lint(cx, NEW_RET_NO_SELF, sig.explicit_self.span, diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 89467f1dc55..d341afb4d92 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -3,7 +3,8 @@ use rustc_front::hir; use rustc_front::intravisit::FnKind; use syntax::ast; use syntax::codemap::Span; -use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, span_lint, DEFAULT_TRAIT_PATH}; +use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint, + DEFAULT_TRAIT_PATH}; /// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` /// implementation. @@ -49,16 +50,15 @@ impl LateLintPass for NewWithoutDefault { if decl.inputs.is_empty() && name.as_str() == "new" { let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; - let ret_ty = return_ty(cx.tcx.node_id_to_type(id)); - - if Some(self_ty) == ret_ty { - if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { - if !implements_trait(cx, self_ty, default_trait_id, Vec::new()) { - span_lint(cx, NEW_WITHOUT_DEFAULT, span, - &format!("you should consider adding a `Default` implementation for `{}`", self_ty)); - } - } - } + if_let_chain!{[ + let Some(ret_ty) = return_ty(cx.tcx.node_id_to_type(id)), + same_tys(cx, self_ty, ret_ty), + let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH), + !implements_trait(cx, self_ty, default_trait_id, Vec::new()) + ], { + span_lint(cx, NEW_WITHOUT_DEFAULT, span, + &format!("you should consider adding a `Default` implementation for `{}`", self_ty)); + }} } } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index bef4baea67e..c626fcb8930 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -740,3 +740,11 @@ pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> { None } } + +/// 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>) -> bool { + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); + infcx.can_equate(&cx.tcx.erase_regions(&a), &cx.tcx.erase_regions(&b)).is_ok() +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 0acab8be4fb..46f14d5d921 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -28,6 +28,25 @@ impl T { //~| ERROR methods called `new` usually return `Self` } +struct Lt<'a> { + foo: &'a u32, +} + +impl<'a> Lt<'a> { + // The lifetime is different, but that’s irrelevant, see #734 + #[allow(needless_lifetimes)] + pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() } +} + +struct Lt2<'a> { + foo: &'a u32, +} + +impl<'a> Lt2<'a> { + // The lifetime is different, but that’s irrelevant, see #734 + pub fn new(s: &str) -> Lt2 { unimplemented!() } +} + #[derive(Clone,Copy)] struct U; diff --git a/tests/compile-fail/new_without_default.rs b/tests/compile-fail/new_without_default.rs index 5f00179a9a2..cc033043bc5 100755 --- a/tests/compile-fail/new_without_default.rs +++ b/tests/compile-fail/new_without_default.rs @@ -32,4 +32,13 @@ impl Params { fn new(_: u32) -> Self { Params } } +struct Generics<'a, T> { + foo: &'a bool, + bar: T, +} + +impl<'c, V> Generics<'c, V> { + fn new<'b>() -> Generics<'b, V> { unimplemented!() } //~ERROR: you should consider adding a `Default` implementation for +} + fn main() {} -- cgit 1.4.1-3-g733a5 From 3ab4914a29a24684f0b384133b80e522fb95310b Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 9 Mar 2016 16:10:24 +0100 Subject: Handle the new TryDesugar variant --- src/matches.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 1b05162c86a..85a8a4b005d 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -439,6 +439,7 @@ fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, e MatchSource::IfLetDesugar { .. } => format!("if let ... = {}{} {{", op, expr_snippet), MatchSource::WhileLetDesugar => format!("while let ... = {}{} {{", op, expr_snippet), MatchSource::ForLoopDesugar => cx.sess().span_bug(span, "for loop desugared to match with &-patterns!"), + MatchSource::TryDesugar => cx.sess().span_bug(span, "`?` operator desugared to match with &-patterns!") } } -- cgit 1.4.1-3-g733a5 From 9cfc6124a3e09276c75d8998b5a93a29e82213a4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 9 Mar 2016 16:22:31 +0100 Subject: Improve the MATCH_REF_PATS suggestions --- src/matches.rs | 36 ++++++++++++++++++++++-------------- tests/compile-fail/matches.rs | 25 ++++++++++++++++++++----- 2 files changed, 42 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/matches.rs b/src/matches.rs index 85a8a4b005d..4c60ea89b34 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -8,7 +8,7 @@ use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; -use utils::{match_type, snippet, span_lint, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; +use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; /// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. /// @@ -309,18 +309,26 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match if has_only_ref_pats(arms) { if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { let template = match_template(cx, expr.span, source, "", inner); - span_lint(cx, - MATCH_REF_PATS, - expr.span, - &format!("you don't need to add `&` to both the expression and the patterns: use `{}`", - template)); + span_lint_and_then(cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to both the expression and the patterns", + |db| { + db.span_suggestion(expr.span, + "try", + template); + }); } else { let template = match_template(cx, expr.span, source, "*", ex); - span_lint(cx, - MATCH_REF_PATS, - expr.span, - &format!("instead of prefixing all patterns with `&`, you can dereference the expression: `{}`", - template)); + span_lint_and_then(cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to all patterns", + |db| { + db.span_suggestion(expr.span, + "instead of prefixing all patterns with `&`, you can dereference the expression", + template); + }); } } } @@ -435,9 +443,9 @@ fn has_only_ref_pats(arms: &[Arm]) -> bool { fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, expr: &Expr) -> String { let expr_snippet = snippet(cx, expr.span, ".."); match source { - MatchSource::Normal => format!("match {}{} {{ ...", op, expr_snippet), - MatchSource::IfLetDesugar { .. } => format!("if let ... = {}{} {{", op, expr_snippet), - MatchSource::WhileLetDesugar => format!("while let ... = {}{} {{", op, expr_snippet), + MatchSource::Normal => format!("match {}{} {{ .. }}", op, expr_snippet), + MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet), + MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet), MatchSource::ForLoopDesugar => cx.sess().span_bug(span, "for loop desugared to match with &-patterns!"), MatchSource::TryDesugar => cx.sess().span_bug(span, "`?` operator desugared to match with &-patterns!") } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index 46d3ff8d5fb..f5f830fed51 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -137,7 +137,10 @@ fn match_bool() { fn ref_pats() { { let v = &Some(0); - match v { //~ERROR dereference the expression: `match *v { ...` + match v { + //~^ERROR add `&` to all patterns + //~|HELP instead of + //~|SUGGESTION `match *v { .. }` &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -147,13 +150,19 @@ fn ref_pats() { } } let tup =& (1, 2); - match tup { //~ERROR dereference the expression: `match *tup { ...` + match tup { + //~^ERROR add `&` to all patterns + //~|HELP instead of + //~|SUGGESTION `match *tup { .. }` &(v, 1) => println!("{}", v), _ => println!("none"), } // special case: using & both in expr and pats let w = Some(0); - match &w { //~ERROR use `match w { ...` + match &w { + //~^ERROR add `&` to both + //~|HELP try + //~|SUGGESTION `match w { .. }` &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -164,12 +173,18 @@ fn ref_pats() { } let a = &Some(0); - if let &None = a { //~ERROR dereference the expression: `if let ... = *a {` + if let &None = a { + //~^ERROR add `&` to all patterns + //~|HELP instead of + //~|SUGGESTION `if let ... = *a { .. }` println!("none"); } let b = Some(0); - if let &None = &b { //~ERROR use `if let ... = b {` + if let &None = &b { + //~^ERROR add `&` to both + //~|HELP try + //~|SUGGESTION `if let ... = b { .. }` println!("none"); } } -- cgit 1.4.1-3-g733a5 From c6316df19f14702a16c7be3685547def9ff21b21 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 10 Mar 2016 18:13:49 +0100 Subject: Rustup to 1.9.0-nightly (c9629d61c 2016-03-10) --- src/cyclomatic_complexity.rs | 7 ++++--- src/derive.rs | 2 +- src/eta_reduction.rs | 9 ++++++--- src/mut_reference.rs | 27 +++++++++++++++------------ tests/compile-fail/mut_reference.rs | 25 ++++++++++++++----------- 5 files changed, 40 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index b1b578af759..bc13576fe3b 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -124,13 +124,14 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { ExprCall(ref callee, _) => { walk_expr(self, e); let ty = self.tcx.node_id_to_type(callee.id); - if let ty::TyBareFn(_, ty) = ty.sty { - if ty.sig.skip_binder().output.diverges() { + match ty.sty { + ty::TyFnDef(_, _, ty) | ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => { self.divergence += 1; } + _ => (), } } - ExprClosure(..) => {} + ExprClosure(..) => (), ExprBinary(op, _, _) => { walk_expr(self, e); match op.node { diff --git a/src/derive.rs b/src/derive.rs index 8bdcb4b0167..380ff0a30f9 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -155,7 +155,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref TypeVariants::TyArray(_, size) if size > 32 => { return; } - TypeVariants::TyBareFn(..) => { + TypeVariants::TyFnPtr(..) => { return; } TypeVariants::TyTuple(ref tys) if tys.len() > 12 => { diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index e28411cc79c..6335f3f1398 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -58,11 +58,14 @@ fn check_closure(cx: &LateContext, expr: &Expr) { return; } let fn_ty = cx.tcx.expr_ty(caller); - if let ty::TyBareFn(_, fn_ty) = fn_ty.sty { + match fn_ty.sty { // Is it an unsafe function? They don't implement the closure traits - if fn_ty.unsafety == Unsafety::Unsafe { - return; + ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) => { + if fn_ty.unsafety == Unsafety::Unsafe { + return; + } } + _ => (), } for (ref a1, ref a2) in decl.inputs.iter().zip(args) { if let PatKind::Ident(_, ident, _) = a1.pat.node { diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 0e5b038f27d..707ce8efaeb 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -53,21 +53,24 @@ impl LateLintPass for UnnecessaryMutPassed { } fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) { - if let TypeVariants::TyBareFn(_, ref fn_type) = type_definition.sty { - 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, ..}) | - TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { - if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, - UNNECESSARY_MUT_PASSED, - argument.span, - &format!("The function/method \"{}\" doesn't need a mutable reference", name)); + match type_definition.sty { + TypeVariants::TyFnDef(_, _, ref fn_type) | TypeVariants::TyFnPtr(ref fn_type) => { + 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, ..}) | + TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { + if let ExprAddrOf(MutMutable, _) = argument.node { + span_lint(cx, + UNNECESSARY_MUT_PASSED, + argument.span, + &format!("The function/method \"{}\" doesn't need a mutable reference", name)); + } } + _ => {} } - _ => {} } } + _ => (), } } diff --git a/tests/compile-fail/mut_reference.rs b/tests/compile-fail/mut_reference.rs index 7480add8e68..1d81ed14e4e 100644 --- a/tests/compile-fail/mut_reference.rs +++ b/tests/compile-fail/mut_reference.rs @@ -3,12 +3,8 @@ #![allow(unused_variables)] -fn takes_an_immutable_reference(a: &i32) { -} - - -fn takes_a_mutable_reference(a: &mut i32) { -} +fn takes_an_immutable_reference(a: &i32) {} +fn takes_a_mutable_reference(a: &mut i32) {} struct MyStruct; @@ -24,23 +20,30 @@ impl MyStruct { fn main() { // Functions takes_an_immutable_reference(&mut 42); //~ERROR The function/method "takes_an_immutable_reference" doesn't need a mutable reference - + let foo: fn(&i32) = takes_an_immutable_reference; + foo(&mut 42); //~ERROR The function/method "foo" doesn't need a mutable reference + // Methods let my_struct = MyStruct; my_struct.takes_an_immutable_reference(&mut 42); //~ERROR The function/method "takes_an_immutable_reference" doesn't need a mutable reference - + // No error - + // Functions takes_an_immutable_reference(&42); + let foo: fn(&i32) = takes_an_immutable_reference; + foo(&42); + takes_a_mutable_reference(&mut 42); + let foo: fn(&mut i32) = takes_a_mutable_reference; + foo(&mut 42); + let a = &mut 42; takes_an_immutable_reference(a); - + // Methods my_struct.takes_an_immutable_reference(&42); my_struct.takes_a_mutable_reference(&mut 42); my_struct.takes_an_immutable_reference(a); - } -- cgit 1.4.1-3-g733a5 From a38958b8d94984ef15f27d808ac82279191ca19e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 11 Mar 2016 20:27:33 +0100 Subject: Fix `unsugar_range` with `..` --- src/utils/mod.rs | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c626fcb8930..625e8da197d 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -681,6 +681,7 @@ pub fn camel_case_from(s: &str) -> usize { } /// Represents a range akin to `ast::ExprKind::Range`. +#[derive(Debug, Copy, Clone)] pub struct UnsugaredRange<'a> { pub start: Option<&'a Expr>, pub end: Option<&'a Expr>, @@ -711,24 +712,30 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { Some(unwrap_unstable(expr)) } - if let ExprStruct(ref path, ref fields, None) = unwrap_unstable(&expr).node { - if match_path(path, &RANGE_FROM_PATH) { - Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen }) - } else if match_path(path, &RANGE_FULL_PATH) { - Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen }) - } else if match_path(path, &RANGE_INCLUSIVE_NON_EMPTY_PATH) { - Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed }) - } else if match_path(path, &RANGE_PATH) { - Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen }) - } else if match_path(path, &RANGE_TO_INCLUSIVE_PATH) { - Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed }) - } else if match_path(path, &RANGE_TO_PATH) { - Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen }) - } else { - None + match unwrap_unstable(&expr).node { + ExprPath(None, ref path) => { + if match_path(path, &RANGE_FULL_PATH) { + Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen }) + } else { + None + } } - } else { - None + ExprStruct(ref path, ref fields, None) => { + if match_path(path, &RANGE_FROM_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen }) + } else if match_path(path, &RANGE_INCLUSIVE_NON_EMPTY_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed }) + } else if match_path(path, &RANGE_PATH) { + Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + } else if match_path(path, &RANGE_TO_INCLUSIVE_PATH) { + Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed }) + } else if match_path(path, &RANGE_TO_PATH) { + Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + } else { + None + } + } + _ => None, } } -- cgit 1.4.1-3-g733a5 From 87ef5f4d3b300c893cb404ab1f62816b34e0ea4d Mon Sep 17 00:00:00 2001 From: Adolfo Ochagavía <aochagavia92@gmail.com> Date: Fri, 11 Mar 2016 10:51:16 +0100 Subject: Lint against indexing and slicing This can be useful to prevent panics in a codebase. ATM it is a pedantic lint, but in the future it should be added to the restricions group. --- README.md | 3 +- src/array_indexing.rs | 110 ++++++++++++++++++++++++++++++++--- src/lib.rs | 1 + tests/compile-fail/array_indexing.rs | 25 +++++++- 4 files changed, 128 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 556bfcf7eb2..48a106e3591 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to link with clippy-service](#link-with-clippy-service) ##Lints -There are 133 lints included in this crate: +There are 134 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -58,6 +58,7 @@ name [if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | warn | finds if branches that could be swapped so no negation operation is necessary on the condition [if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks [ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition +[indexing_slicing](https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing) | allow | indexing/slicing usage [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations diff --git a/src/array_indexing.rs b/src/array_indexing.rs index cfa52f390d2..abce04f0b77 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -3,7 +3,8 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::ty::TyArray; use rustc_front::hir::*; -use utils::span_lint; +use syntax::ast::RangeLimits; +use utils; /// **What it does:** Check for out of bounds array indexing with a constant index. /// @@ -17,6 +18,7 @@ use utils::span_lint; /// let x = [1,2,3,4]; /// ... /// x[9]; +/// &x[2..9]; /// ``` declare_lint! { pub OUT_OF_BOUNDS_INDEXING, @@ -24,28 +26,122 @@ declare_lint! { "out of bound constant indexing" } +/// **What it does:** Check for usage of indexing or slicing. +/// +/// **Why is this bad?** Usually, this can be safely allowed. However, +/// in some domains such as kernel development, a panic can cause the +/// whole operating system to crash. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// ... +/// x[2]; +/// &x[0..2]; +/// ``` +declare_lint! { + pub INDEXING_SLICING, + Allow, + "indexing/slicing usage" +} + #[derive(Copy,Clone)] pub struct ArrayIndexing; impl LintPass for ArrayIndexing { fn get_lints(&self) -> LintArray { - lint_array!(OUT_OF_BOUNDS_INDEXING) + lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING) } } impl LateLintPass for ArrayIndexing { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprIndex(ref array, ref index) = e.node { + // Array with known size can be checked statically let ty = cx.tcx.expr_ty(array); - if let TyArray(_, size) = ty.sty { - let index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); - if let Ok(ConstVal::Uint(index)) = index { - if size as u64 <= index { - span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index-expr is out of bounds"); + let size = size as u64; + + // Index is a constant uint + let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); + if let Ok(ConstVal::Uint(const_index)) = const_index { + if size <= const_index { + utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); + utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic"); + } else { + // Index is within bounds + return; } } + + // Index is a constant range + if let Some(range) = utils::unsugar_range(index) { + let start = range.start.map(|start| + eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)); + let end = range.end.map(|end| + eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)); + + if let Some((start, end)) = to_const_range(start, end, range.limits, size) { + if start >= size && end >= size { + utils::span_lint(cx, + OUT_OF_BOUNDS_INDEXING, + e.span, + "range is out of bounds"); + utils::span_lint(cx, + INDEXING_SLICING, + e.span, + "slicing may panic"); + } else { + // Range is within bounds + return; + } + } + } + } + + if let Some(range) = utils::unsugar_range(index) { + // Full ranges are always valid + if range.start.is_none() && range.end.is_none() { + return; + } + + // Impossible to know if indexing or slicing is correct + utils::span_lint(cx, INDEXING_SLICING, e.span, "slicing may panic"); + } else { + utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic"); } } } } + +/// Returns an option containing a tuple with the start and end (exclusive) of the range +/// +/// Note: we assume the start and the end of the range are unsigned, since array slicing +/// works only on usize +fn to_const_range<T>(start: Option<Result<ConstVal, T>>, + end: Option<Result<ConstVal, T>>, + limits: RangeLimits, + array_size: u64) + -> Option<(u64, u64)> { + let start = match start { + Some(Ok(ConstVal::Uint(x))) => x, + Some(_) => return None, + None => 0, + }; + + let end = match end { + Some(Ok(ConstVal::Uint(x))) => { + if limits == RangeLimits::Closed { + x + } else { + x - 1 + } + } + Some(_) => return None, + None => array_size - 1, + }; + + Some((start, end)) +} diff --git a/src/lib.rs b/src/lib.rs index 8c619a1eaf7..664819b97ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,6 +181,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_lint_group("clippy_pedantic", vec![ + array_indexing::INDEXING_SLICING, enum_glob_use::ENUM_GLOB_USE, matches::SINGLE_MATCH_ELSE, methods::OPTION_UNWRAP_USED, diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs index 1d9492bc0ab..bcd25f5bf06 100644 --- a/tests/compile-fail/array_indexing.rs +++ b/tests/compile-fail/array_indexing.rs @@ -1,6 +1,7 @@ -#![feature(plugin)] +#![feature(inclusive_range_syntax, plugin)] #![plugin(clippy)] +#![deny(indexing_slicing)] #![deny(out_of_bounds_indexing)] #![allow(no_effect)] @@ -8,6 +9,24 @@ fn main() { let x = [1,2,3,4]; x[0]; x[3]; - x[4]; //~ERROR: const index-expr is out of bounds - x[1 << 3]; //~ERROR: const index-expr is out of bounds + x[4]; //~ERROR: indexing may panic + //~^ ERROR: const index is out of bounds + x[1 << 3]; //~ERROR: indexing may panic + //~^ ERROR: const index is out of bounds + &x[1..5]; //~ERROR: slicing may panic + //~^ ERROR: range is out of bounds + &x[0..3]; + &x[0...4]; //~ERROR: slicing may panic + //~^ ERROR: range is out of bounds + &x[..]; + &x[1..]; + &x[..4]; + &x[..5]; //~ERROR: slicing may panic + //~^ ERROR: range is out of bounds + + let y = &x; + y[0]; //~ERROR: indexing may panic + &y[1..2]; //~ERROR: slicing may panic + &y[..]; + &y[0...4]; //~ERROR: slicing may panic } -- cgit 1.4.1-3-g733a5 From 2f13c3bdefefb7947049ed51edde8db341994164 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 11 Mar 2016 22:10:40 +0100 Subject: Small nits on INDEXING_SLICING --- src/array_indexing.rs | 28 ++++++++++------------------ src/lib.rs | 2 +- tests/compile-fail/array_indexing.rs | 15 +++++---------- 3 files changed, 16 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index abce04f0b77..274491b7c96 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -69,34 +69,26 @@ impl LateLintPass for ArrayIndexing { if let Ok(ConstVal::Uint(const_index)) = const_index { if size <= const_index { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); - utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic"); - } else { - // Index is within bounds - return; } + + return; } // Index is a constant range if let Some(range) = utils::unsugar_range(index) { let start = range.start.map(|start| - eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)); + eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)).map(|v| v.ok()); let end = range.end.map(|end| - eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)); + eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)).map(|v| v.ok()); if let Some((start, end)) = to_const_range(start, end, range.limits, size) { - if start >= size && end >= size { + if start >= size || end >= size { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds"); - utils::span_lint(cx, - INDEXING_SLICING, - e.span, - "slicing may panic"); - } else { - // Range is within bounds - return; } + return; } } } @@ -120,19 +112,19 @@ impl LateLintPass for ArrayIndexing { /// /// Note: we assume the start and the end of the range are unsigned, since array slicing /// works only on usize -fn to_const_range<T>(start: Option<Result<ConstVal, T>>, - end: Option<Result<ConstVal, T>>, +fn to_const_range(start: Option<Option<ConstVal>>, + end: Option<Option<ConstVal>>, limits: RangeLimits, array_size: u64) -> Option<(u64, u64)> { let start = match start { - Some(Ok(ConstVal::Uint(x))) => x, + Some(Some(ConstVal::Uint(x))) => x, Some(_) => return None, None => 0, }; let end = match end { - Some(Ok(ConstVal::Uint(x))) => { + Some(Some(ConstVal::Uint(x))) => { if limits == RangeLimits::Closed { x } else { diff --git a/src/lib.rs b/src/lib.rs index 664819b97ec..4b9d5d8c9c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![feature(rustc_private, collections)] #![feature(iter_arith)] #![feature(custom_attribute)] -#![allow(unknown_lints)] +#![allow(indexing_slicing, shadow_reuse, unknown_lints)] // this only exists to allow the "dogfood" integration test to work #[allow(dead_code)] diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs index bcd25f5bf06..14f3448a9f6 100644 --- a/tests/compile-fail/array_indexing.rs +++ b/tests/compile-fail/array_indexing.rs @@ -9,20 +9,15 @@ fn main() { let x = [1,2,3,4]; x[0]; x[3]; - x[4]; //~ERROR: indexing may panic - //~^ ERROR: const index is out of bounds - x[1 << 3]; //~ERROR: indexing may panic - //~^ ERROR: const index is out of bounds - &x[1..5]; //~ERROR: slicing may panic - //~^ ERROR: range is out of bounds + x[4]; //~ERROR: const index is out of bounds + x[1 << 3]; //~ERROR: const index is out of bounds + &x[1..5]; //~ERROR: range is out of bounds &x[0..3]; - &x[0...4]; //~ERROR: slicing may panic - //~^ ERROR: range is out of bounds + &x[0...4]; //~ERROR: range is out of bounds &x[..]; &x[1..]; &x[..4]; - &x[..5]; //~ERROR: slicing may panic - //~^ ERROR: range is out of bounds + &x[..5]; //~ERROR: range is out of bounds let y = &x; y[0]; //~ERROR: indexing may panic -- cgit 1.4.1-3-g733a5 From 29c0c2bb09b9b33f1e4e81db0e46bdd089dc2847 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 21 Feb 2016 20:11:32 +0100 Subject: Start implementing a configuration file --- Cargo.toml | 1 + src/conf.rs | 184 +++++++++++++++++++++++++++++++ src/lib.rs | 26 ++++- tests/compile-fail/conf_bad_arg.rs | 6 + tests/compile-fail/conf_non_existant.rs | 6 + tests/compile-fail/conf_unknown_key.rs | 6 + tests/compile-fail/conf_unknown_key.toml | 1 + 7 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/conf.rs create mode 100644 tests/compile-fail/conf_bad_arg.rs create mode 100644 tests/compile-fail/conf_non_existant.rs create mode 100644 tests/compile-fail/conf_unknown_key.rs create mode 100644 tests/compile-fail/conf_unknown_key.toml (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 853815e049f..a10164b5fcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ plugin = true regex-syntax = "0.2.2" regex_macros = { version = "0.1.28", optional = true } semver = "0.2.1" +toml = "0.1" unicode-normalization = "0.1" [dev-dependencies] diff --git a/src/conf.rs b/src/conf.rs new file mode 100644 index 00000000000..e275bd701bd --- /dev/null +++ b/src/conf.rs @@ -0,0 +1,184 @@ +use std::{fmt, fs, io}; +use std::io::Read; +use syntax::{ast, codemap, ptr}; +use syntax::parse::token; +use toml; + +/// Get the configuration file from arguments. +pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { + for arg in args { + match arg.node { + ast::MetaItemKind::Word(ref name) | ast::MetaItemKind::List(ref name, _) => { + if name == &"conf_file" { + return Err(("`conf_file` must be a named value", arg.span)); + } + } + ast::MetaItemKind::NameValue(ref name, ref value) => { + if name == &"conf_file" { + return if let ast::LitKind::Str(ref file, _) = value.node { + Ok(Some(file.clone())) + } else { + Err(("`conf_file` value must be a string", value.span)) + } + } + } + } + } + + Ok(None) +} + +/// Error from reading a configuration file. +#[derive(Debug)] +pub enum ConfError { + IoError(io::Error), + TomlError(Vec<toml::ParserError>), + TypeError(&'static str, &'static str, &'static str), + UnknownKey(String), +} + +impl fmt::Display for ConfError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + ConfError::IoError(ref err) => { + err.fmt(f) + } + ConfError::TomlError(ref errs) => { + let mut first = true; + for err in errs { + if !first { + try!(", ".fmt(f)); + first = false; + } + + try!(err.fmt(f)); + } + + Ok(()) + } + ConfError::TypeError(ref key, ref expected, ref got) => { + write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) + } + ConfError::UnknownKey(ref key) => { + write!(f, "unknown key `{}`", key) + } + } + } +} + +impl From<io::Error> for ConfError { + fn from(e: io::Error) -> Self { + ConfError::IoError(e) + } +} + +macro_rules! define_Conf { + ($(($toml_name: tt, $rust_name: ident, $default: expr, $ty: ident),)+) => { + /// Type used to store lint configuration. + pub struct Conf { + $(pub $rust_name: $ty,)+ + } + + impl Default for Conf { + fn default() -> Conf { + Conf { + $($rust_name: $default,)+ + } + } + } + + impl Conf { + /// Set the property `name` (which must be the `toml` name) to the given value + #[allow(cast_sign_loss)] + fn set(&mut self, name: String, value: toml::Value) -> Result<(), ConfError> { + match name.as_str() { + $( + define_Conf!(PAT $toml_name) => { + if let Some(value) = define_Conf!(CONV $ty, value) { + self.$rust_name = value; + } + else { + return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), + stringify!($ty), + value.type_str())); + } + }, + )+ + _ => { + return Err(ConfError::UnknownKey(name)); + } + } + + Ok(()) + } + } + }; + + // hack to convert tts + (PAT $pat: pat) => { $pat }; + (EXPR $e: expr) => { $e }; + + // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; + (CONV StringVec, $value: expr) => {{ + let slice = $value.as_slice(); + + 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().unwrap_or_else(|| unreachable!()).to_owned()).collect()) + } + } + else { + None + } + }}; +} + +/// To keep the `define_Conf!` macro simple +pub type StringVec = Vec<String>; + +define_Conf! { + ("blacklisted-names", blacklisted_names, vec!["foo".to_owned(), "bar".to_owned(), "baz".to_owned()], StringVec), + ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25, u64), + ("too-many-arguments-threshold", too_many_arguments_threshold, 6, u64), + ("type-complexity-threshold", type_complexity_threshold, 250, u64), +} + +/// Read the `toml` configuration file. The function will ignore “File not found” errors iif +/// `!must_exist`, in which case, it will return the default configuration. +pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { + let mut conf = Conf::default(); + + let file = match fs::File::open(path) { + Ok(mut file) => { + let mut buf = String::new(); + try!(file.read_to_string(&mut buf)); + buf + } + Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { + return Ok(conf); + } + Err(err) => { + return Err(err.into()); + } + }; + + let mut parser = toml::Parser::new(&file); + let toml = if let Some(toml) = parser.parse() { + toml + } + else { + return Err(ConfError::TomlError(parser.errors)); + }; + + for (key, value) in toml { + try!(conf.set(key, value)); + } + + Ok(conf) +} diff --git a/src/lib.rs b/src/lib.rs index 4b9d5d8c9c4..f3c3564796a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ extern crate rustc; #[macro_use] extern crate rustc_front; +extern crate toml; + // Only for the compile time checking of paths extern crate core; extern crate collections; @@ -35,6 +37,7 @@ extern crate rustc_plugin; use rustc_plugin::Registry; +mod conf; pub mod consts; #[macro_use] pub mod utils; @@ -107,6 +110,27 @@ mod reexport { #[plugin_registrar] #[cfg_attr(rustfmt, rustfmt_skip)] pub fn plugin_registrar(reg: &mut Registry) { + let conferr = match conf::conf_file(reg.args()) { + Ok(Some(file_name)) => { + conf::read_conf(&file_name, true) + } + Ok(None) => { + conf::read_conf("Clippy.toml", false) + } + Err((err, span)) => { + reg.sess.struct_span_err(span, err).emit(); + return; + } + }; + + let conf = match conferr { + Ok(conf) => conf, + Err(err) => { + reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", err)).emit(); + return; + } + }; + reg.register_late_lint_pass(box types::TypePass); reg.register_late_lint_pass(box misc::TopLevelRefPass); reg.register_late_lint_pass(box misc::CmpNan); @@ -157,7 +181,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); reg.register_late_lint_pass(box transmute::UselessTransmute); - reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25)); + reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold)); reg.register_late_lint_pass(box escape::EscapePass); reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); diff --git a/tests/compile-fail/conf_bad_arg.rs b/tests/compile-fail/conf_bad_arg.rs new file mode 100644 index 00000000000..68b902719f6 --- /dev/null +++ b/tests/compile-fail/conf_bad_arg.rs @@ -0,0 +1,6 @@ +// error-pattern: `conf_file` must be a named value + +#![feature(plugin)] +#![plugin(clippy(conf_file))] + +fn main() {} diff --git a/tests/compile-fail/conf_non_existant.rs b/tests/compile-fail/conf_non_existant.rs new file mode 100644 index 00000000000..13ab7f6cebf --- /dev/null +++ b/tests/compile-fail/conf_non_existant.rs @@ -0,0 +1,6 @@ +// error-pattern: error reading Clippy's configuration file: No such file or directory + +#![feature(plugin)] +#![plugin(clippy(conf_file="./tests/compile-fail/non_existant_conf.toml"))] + +fn main() {} diff --git a/tests/compile-fail/conf_unknown_key.rs b/tests/compile-fail/conf_unknown_key.rs new file mode 100644 index 00000000000..02131d94d52 --- /dev/null +++ b/tests/compile-fail/conf_unknown_key.rs @@ -0,0 +1,6 @@ +// error-pattern: error reading Clippy's configuration file: unknown key `foobar` + +#![feature(plugin)] +#![plugin(clippy(conf_file="./tests/compile-fail/conf_unknown_key.toml"))] + +fn main() {} diff --git a/tests/compile-fail/conf_unknown_key.toml b/tests/compile-fail/conf_unknown_key.toml new file mode 100644 index 00000000000..df298ea78d4 --- /dev/null +++ b/tests/compile-fail/conf_unknown_key.toml @@ -0,0 +1 @@ +foobar = 42 -- cgit 1.4.1-3-g733a5 From 1841804d43b1ef3e919a3e9cb7fdb4e166f8fd64 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 21 Feb 2016 21:01:30 +0100 Subject: Use configuration in the `TYPE_COMPLEXITY` lint --- src/lib.rs | 2 +- src/types.rs | 78 +++++++++++++++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f3c3564796a..4c0a069a090 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,7 +168,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box entry::HashMapLint); reg.register_late_lint_pass(box ranges::StepByZero); reg.register_late_lint_pass(box types::CastPass); - reg.register_late_lint_pass(box types::TypeComplexityPass); + reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold)); reg.register_late_lint_pass(box matches::MatchPass); reg.register_late_lint_pass(box misc::PatternPass); reg.register_late_lint_pass(box minmax::MinMaxPass); diff --git a/src/types.rs b/src/types.rs index cf90155b1fa..1aefe5a4d27 100644 --- a/src/types.rs +++ b/src/types.rs @@ -417,7 +417,17 @@ declare_lint! { } #[allow(missing_copy_implementations)] -pub struct TypeComplexityPass; +pub struct TypeComplexityPass { + threshold: u64, +} + +impl TypeComplexityPass { + pub fn new(threshold: u64) -> Self { + TypeComplexityPass { + threshold: threshold + } + } +} impl LintPass for TypeComplexityPass { fn get_lints(&self) -> LintArray { @@ -427,18 +437,18 @@ impl LintPass for TypeComplexityPass { impl LateLintPass for TypeComplexityPass { fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - check_fndecl(cx, decl); + self.check_fndecl(cx, decl); } fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { // enum variants are also struct fields now - check_type(cx, &field.ty); + self.check_type(cx, &field.ty); } fn check_item(&mut self, cx: &LateContext, item: &Item) { match item.node { ItemStatic(ref ty, _, _) | - ItemConst(ref ty, _) => check_type(cx, ty), + ItemConst(ref ty, _) => self.check_type(cx, ty), // functions, enums, structs, impls and traits are covered _ => (), } @@ -447,8 +457,8 @@ impl LateLintPass for TypeComplexityPass { fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { match item.node { ConstTraitItem(ref ty, _) | - TypeTraitItem(_, Some(ref ty)) => check_type(cx, ty), - MethodTraitItem(MethodSig { ref decl, .. }, None) => check_fndecl(cx, decl), + TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty), + MethodTraitItem(MethodSig { ref decl, .. }, None) => self.check_fndecl(cx, decl), // methods with default impl are covered by check_fn _ => (), } @@ -457,7 +467,7 @@ impl LateLintPass for TypeComplexityPass { fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { match item.node { ImplItemKind::Const(ref ty, _) | - ImplItemKind::Type(ref ty) => check_type(cx, ty), + ImplItemKind::Type(ref ty) => self.check_type(cx, ty), // methods are covered by check_fn _ => (), } @@ -465,47 +475,49 @@ impl LateLintPass for TypeComplexityPass { fn check_local(&mut self, cx: &LateContext, local: &Local) { if let Some(ref ty) = local.ty { - check_type(cx, ty); + self.check_type(cx, ty); } } } -fn check_fndecl(cx: &LateContext, decl: &FnDecl) { - for arg in &decl.inputs { - check_type(cx, &arg.ty); - } - if let Return(ref ty) = decl.output { - check_type(cx, ty); +impl TypeComplexityPass { + fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) { + for arg in &decl.inputs { + self.check_type(cx, &arg.ty); + } + if let Return(ref ty) = decl.output { + self.check_type(cx, ty); + } } -} -fn check_type(cx: &LateContext, ty: &Ty) { - if in_macro(cx, ty.span) { - return; - } - let score = { - let mut visitor = TypeComplexityVisitor { - score: 0, - nest: 1, + fn check_type(&self, cx: &LateContext, ty: &Ty) { + if in_macro(cx, ty.span) { + return; + } + let score = { + let mut visitor = TypeComplexityVisitor { + score: 0, + nest: 1, + }; + visitor.visit_ty(ty); + visitor.score }; - visitor.visit_ty(ty); - visitor.score - }; - if score > 250 { - span_lint(cx, - TYPE_COMPLEXITY, - ty.span, - "very complex type used. Consider factoring parts into `type` definitions"); + if score > self.threshold { + span_lint(cx, + TYPE_COMPLEXITY, + ty.span, + "very complex type used. Consider factoring parts into `type` definitions"); + } } } /// Walks a type and assigns a complexity score to it. struct TypeComplexityVisitor { /// total complexity score of the type - score: u32, + score: u64, /// current nesting level - nest: u32, + nest: u64, } impl<'v> Visitor<'v> for TypeComplexityVisitor { -- cgit 1.4.1-3-g733a5 From 232710cd4312abce7476de2baa21b943a9763eb4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 22 Feb 2016 14:25:51 +0100 Subject: Add configuration variables to wiki --- src/conf.rs | 32 +++++++++++++++++++------------- src/lib.rs | 1 + util/update_wiki.py | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/conf.rs b/src/conf.rs index e275bd701bd..3b2a1dafad4 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -73,16 +73,16 @@ impl From<io::Error> for ConfError { } macro_rules! define_Conf { - ($(($toml_name: tt, $rust_name: ident, $default: expr, $ty: ident),)+) => { + ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { /// Type used to store lint configuration. pub struct Conf { - $(pub $rust_name: $ty,)+ + $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ } impl Default for Conf { fn default() -> Conf { Conf { - $($rust_name: $default,)+ + $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ } } } @@ -94,12 +94,12 @@ macro_rules! define_Conf { match name.as_str() { $( define_Conf!(PAT $toml_name) => { - if let Some(value) = define_Conf!(CONV $ty, value) { + if let Some(value) = define_Conf!(CONV $($ty)+, value) { self.$rust_name = value; } else { return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), - stringify!($ty), + stringify!($($ty)+), value.type_str())); } }, @@ -117,12 +117,13 @@ macro_rules! define_Conf { // hack to convert tts (PAT $pat: pat) => { $pat }; (EXPR $e: expr) => { $e }; + (TY $ty: ty) => { $ty }; // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; - (CONV StringVec, $value: expr) => {{ + (CONV Vec<String>, $value: expr) => {{ let slice = $value.as_slice(); if let Some(slice) = slice { @@ -137,16 +138,21 @@ macro_rules! define_Conf { None } }}; -} -/// To keep the `define_Conf!` macro simple -pub type StringVec = Vec<String>; + // provide a nicer syntax to declare the default value of `Vec<String>` variables + (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; + (DEFAULT $ty: ty, $e: expr) => { $e }; +} define_Conf! { - ("blacklisted-names", blacklisted_names, vec!["foo".to_owned(), "bar".to_owned(), "baz".to_owned()], StringVec), - ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25, u64), - ("too-many-arguments-threshold", too_many_arguments_threshold, 6, u64), - ("type-complexity-threshold", type_complexity_threshold, 250, u64), + /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about + ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), + /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have + ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), + /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have + ("too-many-arguments-threshold", too_many_arguments_threshold, 6 => u64), + /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have + ("type-complexity-threshold", type_complexity_threshold, 250 => u64), } /// Read the `toml` configuration file. The function will ignore “File not found” errors iif diff --git a/src/lib.rs b/src/lib.rs index 4c0a069a090..b69fdf70c99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(type_macros)] #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] #![feature(iter_arith)] diff --git a/util/update_wiki.py b/util/update_wiki.py index d3467a41012..a10b3549a22 100755 --- a/util/update_wiki.py +++ b/util/update_wiki.py @@ -9,6 +9,8 @@ import sys level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''') +conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE) +confvar_re = re.compile(r'''/// Lint: (\w+). (.*).*\n *\("([^"]*)", (?:[^,]*), (.*) => (.*)\),''') def parse_path(p="src"): @@ -16,10 +18,23 @@ def parse_path(p="src"): for f in os.listdir(p): if f.endswith(".rs"): parse_file(d, os.path.join(p, f)) - return d + return (d, parse_conf(p)) -START = 0 -LINT = 1 + +def parse_conf(p): + c = {} + with open(p + '/conf.rs') as f: + f = f.read() + + m = re.search(conf_re, f) + m = m.groups()[0] + + m = re.findall(confvar_re, m) + + for (lint, doc, name, default, ty) in m: + c[lint.lower()] = (name, ty, doc, default) + + return c def parse_file(d, f): @@ -85,8 +100,14 @@ template = """\n# `%s` %s""" +conf_template = """ +**Configuration:** This lint has the following configuration variables: -def write_wiki_page(d, f): +* `%s: %s`: %s (defaults to `%s`). +""" + + +def write_wiki_page(d, c, f): keys = list(d.keys()) keys.sort() with open(f, "w") as w: @@ -102,8 +123,11 @@ def write_wiki_page(d, f): for k in keys: w.write(template % (k, d[k][0], "".join(d[k][1]))) + if k in c: + w.write(conf_template % c[k]) + -def check_wiki_page(d, f): +def check_wiki_page(d, c, f): errors = [] with open(f) as w: for line in w: @@ -122,11 +146,11 @@ def check_wiki_page(d, f): def main(): - d = parse_path() + (d, c) = parse_path() if "-c" in sys.argv: - check_wiki_page(d, "../rust-clippy.wiki/Home.md") + check_wiki_page(d, c, "../rust-clippy.wiki/Home.md") else: - write_wiki_page(d, "../rust-clippy.wiki/Home.md") + write_wiki_page(d, c, "../rust-clippy.wiki/Home.md") if __name__ == "__main__": main() -- cgit 1.4.1-3-g733a5 From a3031e34f9db46f172d955cec607c6f4ef226ab4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 22 Feb 2016 15:42:24 +0100 Subject: Add a `BLACKLISTED_NAME` lint --- README.md | 3 +- src/blacklisted_name.rs | 45 ++++++++++++++++++++++ src/lib.rs | 3 ++ tests/compile-fail/blacklisted_name.rs | 26 +++++++++++++ tests/compile-fail/box_vec.rs | 1 + tests/compile-fail/conf_french_blacklisted_name.rs | 26 +++++++++++++ .../compile-fail/conf_french_blacklisted_name.toml | 1 + tests/compile-fail/copies.rs | 1 + tests/compile-fail/dlist.rs | 3 +- tests/compile-fail/methods.rs | 2 +- tests/compile-fail/mut_reference.rs | 12 +++--- tests/compile-fail/used_underscore_binding.rs | 2 + 12 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 src/blacklisted_name.rs create mode 100755 tests/compile-fail/blacklisted_name.rs create mode 100755 tests/compile-fail/conf_french_blacklisted_name.rs create mode 100644 tests/compile-fail/conf_french_blacklisted_name.toml (limited to 'src') diff --git a/README.md b/README.md index 48a106e3591..1b18a62f7a4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to link with clippy-service](#link-with-clippy-service) ##Lints -There are 134 lints included in this crate: +There are 135 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -19,6 +19,7 @@ name [almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) +[blacklisted_name](https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name) | warn | usage of a blacklisted/placeholder name [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` [block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...` [bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true` diff --git a/src/blacklisted_name.rs b/src/blacklisted_name.rs new file mode 100644 index 00000000000..2d62cc44d26 --- /dev/null +++ b/src/blacklisted_name.rs @@ -0,0 +1,45 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use utils::span_lint; + +/// **What it does:** This lints about usage of blacklisted names. +/// +/// **Why is this bad?** These names are usually placeholder names and should be avoided. +/// +/// **Known problems:** None. +/// +/// **Example:** `let foo = 3.14;` +declare_lint! { + pub BLACKLISTED_NAME, + Warn, + "usage of a blacklisted/placeholder name" +} + +#[derive(Clone, Debug)] +pub struct BlackListedName { + blacklist: Vec<String>, +} + +impl BlackListedName { + pub fn new(blacklist: Vec<String>) -> BlackListedName { + BlackListedName { + blacklist: blacklist + } + } +} + +impl LintPass for BlackListedName { + fn get_lints(&self) -> LintArray { + lint_array!(BLACKLISTED_NAME) + } +} + +impl LateLintPass for BlackListedName { + fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { + if let PatKind::Ident(_, ref ident, _) = pat.node { + if self.blacklist.iter().any(|s| s == &*ident.node.name.as_str()) { + span_lint(cx, BLACKLISTED_NAME, pat.span, &format!("use of a blacklisted/placeholder name `{}`", ident.node.name)); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b69fdf70c99..66ae815d7e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,7 @@ pub mod approx_const; pub mod array_indexing; pub mod attrs; pub mod bit_mask; +pub mod blacklisted_name; pub mod block_in_if_condition; pub mod collapsible_if; pub mod copies; @@ -204,6 +205,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); + reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -236,6 +238,7 @@ pub fn plugin_registrar(reg: &mut Registry) { attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, + blacklisted_name::BLACKLISTED_NAME, block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, diff --git a/tests/compile-fail/blacklisted_name.rs b/tests/compile-fail/blacklisted_name.rs new file mode 100755 index 00000000000..efcb810a30e --- /dev/null +++ b/tests/compile-fail/blacklisted_name.rs @@ -0,0 +1,26 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(dead_code)] +#![allow(single_match)] +#![allow(unused_variables)] +#![deny(blacklisted_name)] + +fn test(foo: ()) {} //~ERROR use of a blacklisted/placeholder name `foo` + +fn main() { + let foo = 42; //~ERROR use of a blacklisted/placeholder name `foo` + let bar = 42; //~ERROR use of a blacklisted/placeholder name `bar` + let baz = 42; //~ERROR use of a blacklisted/placeholder name `baz` + + let barb = 42; + let barbaric = 42; + + match (42, Some(1337), Some(0)) { + (foo, Some(bar), baz @ Some(_)) => (), + //~^ ERROR use of a blacklisted/placeholder name `foo` + //~| ERROR use of a blacklisted/placeholder name `bar` + //~| ERROR use of a blacklisted/placeholder name `baz` + _ => (), + } +} diff --git a/tests/compile-fail/box_vec.rs b/tests/compile-fail/box_vec.rs index 044e7dffa79..071945a81b2 100644 --- a/tests/compile-fail/box_vec.rs +++ b/tests/compile-fail/box_vec.rs @@ -3,6 +3,7 @@ #![deny(clippy)] #![allow(boxed_local)] +#![allow(blacklisted_name)] macro_rules! boxit { ($init:expr, $x:ty) => { diff --git a/tests/compile-fail/conf_french_blacklisted_name.rs b/tests/compile-fail/conf_french_blacklisted_name.rs new file mode 100755 index 00000000000..b7e29eeef1f --- /dev/null +++ b/tests/compile-fail/conf_french_blacklisted_name.rs @@ -0,0 +1,26 @@ +#![feature(plugin)] +#![plugin(clippy(conf_file="./tests/compile-fail/conf_french_blacklisted_name.toml"))] + +#![allow(dead_code)] +#![allow(single_match)] +#![allow(unused_variables)] +#![deny(blacklisted_name)] + +fn test(toto: ()) {} //~ERROR use of a blacklisted/placeholder name `toto` + +fn main() { + let toto = 42; //~ERROR use of a blacklisted/placeholder name `toto` + let tata = 42; //~ERROR use of a blacklisted/placeholder name `tata` + let titi = 42; //~ERROR use of a blacklisted/placeholder name `titi` + + let tatab = 42; + let tatatataic = 42; + + match (42, Some(1337), Some(0)) { + (toto, Some(tata), titi @ Some(_)) => (), + //~^ ERROR use of a blacklisted/placeholder name `toto` + //~| ERROR use of a blacklisted/placeholder name `tata` + //~| ERROR use of a blacklisted/placeholder name `titi` + _ => (), + } +} diff --git a/tests/compile-fail/conf_french_blacklisted_name.toml b/tests/compile-fail/conf_french_blacklisted_name.toml new file mode 100644 index 00000000000..6abe5a3bbc2 --- /dev/null +++ b/tests/compile-fail/conf_french_blacklisted_name.toml @@ -0,0 +1 @@ +blacklisted-names = ["toto", "tata", "titi"] diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index c1e1ba68b3e..66457e77f47 100755 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -6,6 +6,7 @@ #![allow(needless_return)] #![allow(unused_variables)] #![allow(cyclomatic_complexity)] +#![allow(blacklisted_name)] fn bar<T>(_: T) {} fn foo() -> bool { unimplemented!() } diff --git a/tests/compile-fail/dlist.rs b/tests/compile-fail/dlist.rs index a800c045a50..e7919619121 100644 --- a/tests/compile-fail/dlist.rs +++ b/tests/compile-fail/dlist.rs @@ -6,8 +6,7 @@ extern crate collections; use collections::linked_list::LinkedList; -pub fn test(foo: LinkedList<u8>) { //~ ERROR I see you're using a LinkedList! - println!("{:?}", foo) +pub fn test(_: LinkedList<u8>) { //~ ERROR I see you're using a LinkedList! } fn main(){ diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 46f14d5d921..344016a3b90 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(unused, print_stdout, non_ascii_literal, new_without_default)] +#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/compile-fail/mut_reference.rs b/tests/compile-fail/mut_reference.rs index 1d81ed14e4e..0bb59a318b8 100644 --- a/tests/compile-fail/mut_reference.rs +++ b/tests/compile-fail/mut_reference.rs @@ -20,8 +20,8 @@ impl MyStruct { fn main() { // Functions takes_an_immutable_reference(&mut 42); //~ERROR The function/method "takes_an_immutable_reference" doesn't need a mutable reference - let foo: fn(&i32) = takes_an_immutable_reference; - foo(&mut 42); //~ERROR The function/method "foo" doesn't need a mutable reference + let as_ptr: fn(&i32) = takes_an_immutable_reference; + as_ptr(&mut 42); //~ERROR The function/method "as_ptr" doesn't need a mutable reference // Methods let my_struct = MyStruct; @@ -32,12 +32,12 @@ fn main() { // Functions takes_an_immutable_reference(&42); - let foo: fn(&i32) = takes_an_immutable_reference; - foo(&42); + let as_ptr: fn(&i32) = takes_an_immutable_reference; + as_ptr(&42); takes_a_mutable_reference(&mut 42); - let foo: fn(&mut i32) = takes_a_mutable_reference; - foo(&mut 42); + let as_ptr: fn(&mut i32) = takes_a_mutable_reference; + as_ptr(&mut 42); let a = &mut 42; takes_an_immutable_reference(a); diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 281d92c46df..6bf4324e623 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -2,6 +2,8 @@ #![plugin(clippy)] #![deny(clippy)] +#![allow(blacklisted_name)] + /// Test that we lint if we use a binding with a single leading underscore fn prefix_underscore(_foo: u32) -> u32 { _foo + 1 //~ ERROR used binding which is prefixed with an underscore -- cgit 1.4.1-3-g733a5 From c7db94aee6996b0b707cb8c0b912056c1ede6011 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 29 Feb 2016 17:48:20 +0100 Subject: Rustfmt --- src/blacklisted_name.rs | 9 +++++---- src/conf.rs | 13 ++++--------- src/types.rs | 4 +--- 3 files changed, 10 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/blacklisted_name.rs b/src/blacklisted_name.rs index 2d62cc44d26..25c0bac2c37 100644 --- a/src/blacklisted_name.rs +++ b/src/blacklisted_name.rs @@ -22,9 +22,7 @@ pub struct BlackListedName { impl BlackListedName { pub fn new(blacklist: Vec<String>) -> BlackListedName { - BlackListedName { - blacklist: blacklist - } + BlackListedName { blacklist: blacklist } } } @@ -38,7 +36,10 @@ impl LateLintPass for BlackListedName { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatKind::Ident(_, ref ident, _) = pat.node { if self.blacklist.iter().any(|s| s == &*ident.node.name.as_str()) { - span_lint(cx, BLACKLISTED_NAME, pat.span, &format!("use of a blacklisted/placeholder name `{}`", ident.node.name)); + span_lint(cx, + BLACKLISTED_NAME, + pat.span, + &format!("use of a blacklisted/placeholder name `{}`", ident.node.name)); } } } diff --git a/src/conf.rs b/src/conf.rs index 3b2a1dafad4..0ceede3b5b8 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -19,7 +19,7 @@ pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::Interne Ok(Some(file.clone())) } else { Err(("`conf_file` value must be a string", value.span)) - } + }; } } } @@ -40,9 +40,7 @@ pub enum ConfError { impl fmt::Display for ConfError { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { - ConfError::IoError(ref err) => { - err.fmt(f) - } + ConfError::IoError(ref err) => err.fmt(f), ConfError::TomlError(ref errs) => { let mut first = true; for err in errs { @@ -59,9 +57,7 @@ impl fmt::Display for ConfError { ConfError::TypeError(ref key, ref expected, ref got) => { write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) } - ConfError::UnknownKey(ref key) => { - write!(f, "unknown key `{}`", key) - } + ConfError::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), } } } @@ -177,8 +173,7 @@ pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { let mut parser = toml::Parser::new(&file); let toml = if let Some(toml) = parser.parse() { toml - } - else { + } else { return Err(ConfError::TomlError(parser.errors)); }; diff --git a/src/types.rs b/src/types.rs index 1aefe5a4d27..e64bf010549 100644 --- a/src/types.rs +++ b/src/types.rs @@ -423,9 +423,7 @@ pub struct TypeComplexityPass { impl TypeComplexityPass { pub fn new(threshold: u64) -> Self { - TypeComplexityPass { - threshold: threshold - } + TypeComplexityPass { threshold: threshold } } } -- cgit 1.4.1-3-g733a5 From 403c54ec5bfa6f2d944dff5a1b34fda3344dec66 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 6 Mar 2016 14:40:25 +0100 Subject: White-list `third-party` in conf files --- src/conf.rs | 4 ++++ tests/compile-fail/conf_unknown_key.toml | 5 +++++ tests/run-pass/conf_unknown_key.rs | 4 ++++ tests/run-pass/conf_unknown_key.toml | 3 +++ 4 files changed, 16 insertions(+) create mode 100644 tests/run-pass/conf_unknown_key.rs create mode 100644 tests/run-pass/conf_unknown_key.toml (limited to 'src') diff --git a/src/conf.rs b/src/conf.rs index 0ceede3b5b8..93caa1edca3 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -100,6 +100,10 @@ macro_rules! define_Conf { } }, )+ + "third-party" => { + // for external tools such as clippy-service + return Ok(()); + } _ => { return Err(ConfError::UnknownKey(name)); } diff --git a/tests/compile-fail/conf_unknown_key.toml b/tests/compile-fail/conf_unknown_key.toml index df298ea78d4..554b87cc50b 100644 --- a/tests/compile-fail/conf_unknown_key.toml +++ b/tests/compile-fail/conf_unknown_key.toml @@ -1 +1,6 @@ +# that one is an error foobar = 42 + +# that one is white-listed +[third-party] +clippy-feature = "nightly" diff --git a/tests/run-pass/conf_unknown_key.rs b/tests/run-pass/conf_unknown_key.rs new file mode 100644 index 00000000000..bb186d47630 --- /dev/null +++ b/tests/run-pass/conf_unknown_key.rs @@ -0,0 +1,4 @@ +#![feature(plugin)] +#![plugin(clippy(conf_file="./tests/run-pass/conf_unknown_key.toml"))] + +fn main() {} diff --git a/tests/run-pass/conf_unknown_key.toml b/tests/run-pass/conf_unknown_key.toml new file mode 100644 index 00000000000..9f87de20baf --- /dev/null +++ b/tests/run-pass/conf_unknown_key.toml @@ -0,0 +1,3 @@ +# this is ignored by Clippy, but allowed for other tools like clippy-service +[third-party] +clippy-feature = "nightly" -- cgit 1.4.1-3-g733a5 From d118b27abb50fef41f7a9510aa9e3741ac036370 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 6 Mar 2016 15:17:51 +0100 Subject: mv src/conf.rs src/utils --- src/conf.rs | 189 ------------------------------------------------------ src/lib.rs | 7 +- src/utils/conf.rs | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 1 + 4 files changed, 193 insertions(+), 193 deletions(-) delete mode 100644 src/conf.rs create mode 100644 src/utils/conf.rs (limited to 'src') diff --git a/src/conf.rs b/src/conf.rs deleted file mode 100644 index 93caa1edca3..00000000000 --- a/src/conf.rs +++ /dev/null @@ -1,189 +0,0 @@ -use std::{fmt, fs, io}; -use std::io::Read; -use syntax::{ast, codemap, ptr}; -use syntax::parse::token; -use toml; - -/// Get the configuration file from arguments. -pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { - for arg in args { - match arg.node { - ast::MetaItemKind::Word(ref name) | ast::MetaItemKind::List(ref name, _) => { - if name == &"conf_file" { - return Err(("`conf_file` must be a named value", arg.span)); - } - } - ast::MetaItemKind::NameValue(ref name, ref value) => { - if name == &"conf_file" { - return if let ast::LitKind::Str(ref file, _) = value.node { - Ok(Some(file.clone())) - } else { - Err(("`conf_file` value must be a string", value.span)) - }; - } - } - } - } - - Ok(None) -} - -/// Error from reading a configuration file. -#[derive(Debug)] -pub enum ConfError { - IoError(io::Error), - TomlError(Vec<toml::ParserError>), - TypeError(&'static str, &'static str, &'static str), - UnknownKey(String), -} - -impl fmt::Display for ConfError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ConfError::IoError(ref err) => err.fmt(f), - ConfError::TomlError(ref errs) => { - let mut first = true; - for err in errs { - if !first { - try!(", ".fmt(f)); - first = false; - } - - try!(err.fmt(f)); - } - - Ok(()) - } - ConfError::TypeError(ref key, ref expected, ref got) => { - write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) - } - ConfError::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), - } - } -} - -impl From<io::Error> for ConfError { - fn from(e: io::Error) -> Self { - ConfError::IoError(e) - } -} - -macro_rules! define_Conf { - ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { - /// Type used to store lint configuration. - pub struct Conf { - $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ - } - - impl Default for Conf { - fn default() -> Conf { - Conf { - $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ - } - } - } - - impl Conf { - /// Set the property `name` (which must be the `toml` name) to the given value - #[allow(cast_sign_loss)] - fn set(&mut self, name: String, value: toml::Value) -> Result<(), ConfError> { - match name.as_str() { - $( - define_Conf!(PAT $toml_name) => { - if let Some(value) = define_Conf!(CONV $($ty)+, value) { - self.$rust_name = value; - } - else { - return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), - stringify!($($ty)+), - value.type_str())); - } - }, - )+ - "third-party" => { - // for external tools such as clippy-service - return Ok(()); - } - _ => { - return Err(ConfError::UnknownKey(name)); - } - } - - Ok(()) - } - } - }; - - // hack to convert tts - (PAT $pat: pat) => { $pat }; - (EXPR $e: expr) => { $e }; - (TY $ty: ty) => { $ty }; - - // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; - (CONV Vec<String>, $value: expr) => {{ - let slice = $value.as_slice(); - - 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().unwrap_or_else(|| unreachable!()).to_owned()).collect()) - } - } - else { - None - } - }}; - - // provide a nicer syntax to declare the default value of `Vec<String>` variables - (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; - (DEFAULT $ty: ty, $e: expr) => { $e }; -} - -define_Conf! { - /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about - ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), - /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have - ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), - /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have - ("too-many-arguments-threshold", too_many_arguments_threshold, 6 => u64), - /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have - ("type-complexity-threshold", type_complexity_threshold, 250 => u64), -} - -/// Read the `toml` configuration file. The function will ignore “File not found” errors iif -/// `!must_exist`, in which case, it will return the default configuration. -pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { - let mut conf = Conf::default(); - - let file = match fs::File::open(path) { - Ok(mut file) => { - let mut buf = String::new(); - try!(file.read_to_string(&mut buf)); - buf - } - Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { - return Ok(conf); - } - Err(err) => { - return Err(err.into()); - } - }; - - let mut parser = toml::Parser::new(&file); - let toml = if let Some(toml) = parser.parse() { - toml - } else { - return Err(ConfError::TomlError(parser.errors)); - }; - - for (key, value) in toml { - try!(conf.set(key, value)); - } - - Ok(conf) -} diff --git a/src/lib.rs b/src/lib.rs index 66ae815d7e0..a7fe2c1aab3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,6 @@ extern crate rustc_plugin; use rustc_plugin::Registry; -mod conf; pub mod consts; #[macro_use] pub mod utils; @@ -112,12 +111,12 @@ mod reexport { #[plugin_registrar] #[cfg_attr(rustfmt, rustfmt_skip)] pub fn plugin_registrar(reg: &mut Registry) { - let conferr = match conf::conf_file(reg.args()) { + let conferr = match utils::conf::conf_file(reg.args()) { Ok(Some(file_name)) => { - conf::read_conf(&file_name, true) + utils::conf::read_conf(&file_name, true) } Ok(None) => { - conf::read_conf("Clippy.toml", false) + utils::conf::read_conf("Clippy.toml", false) } Err((err, span)) => { reg.sess.struct_span_err(span, err).emit(); diff --git a/src/utils/conf.rs b/src/utils/conf.rs new file mode 100644 index 00000000000..93caa1edca3 --- /dev/null +++ b/src/utils/conf.rs @@ -0,0 +1,189 @@ +use std::{fmt, fs, io}; +use std::io::Read; +use syntax::{ast, codemap, ptr}; +use syntax::parse::token; +use toml; + +/// Get the configuration file from arguments. +pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { + for arg in args { + match arg.node { + ast::MetaItemKind::Word(ref name) | ast::MetaItemKind::List(ref name, _) => { + if name == &"conf_file" { + return Err(("`conf_file` must be a named value", arg.span)); + } + } + ast::MetaItemKind::NameValue(ref name, ref value) => { + if name == &"conf_file" { + return if let ast::LitKind::Str(ref file, _) = value.node { + Ok(Some(file.clone())) + } else { + Err(("`conf_file` value must be a string", value.span)) + }; + } + } + } + } + + Ok(None) +} + +/// Error from reading a configuration file. +#[derive(Debug)] +pub enum ConfError { + IoError(io::Error), + TomlError(Vec<toml::ParserError>), + TypeError(&'static str, &'static str, &'static str), + UnknownKey(String), +} + +impl fmt::Display for ConfError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + ConfError::IoError(ref err) => err.fmt(f), + ConfError::TomlError(ref errs) => { + let mut first = true; + for err in errs { + if !first { + try!(", ".fmt(f)); + first = false; + } + + try!(err.fmt(f)); + } + + Ok(()) + } + ConfError::TypeError(ref key, ref expected, ref got) => { + write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) + } + ConfError::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), + } + } +} + +impl From<io::Error> for ConfError { + fn from(e: io::Error) -> Self { + ConfError::IoError(e) + } +} + +macro_rules! define_Conf { + ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { + /// Type used to store lint configuration. + pub struct Conf { + $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ + } + + impl Default for Conf { + fn default() -> Conf { + Conf { + $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ + } + } + } + + impl Conf { + /// Set the property `name` (which must be the `toml` name) to the given value + #[allow(cast_sign_loss)] + fn set(&mut self, name: String, value: toml::Value) -> Result<(), ConfError> { + match name.as_str() { + $( + define_Conf!(PAT $toml_name) => { + if let Some(value) = define_Conf!(CONV $($ty)+, value) { + self.$rust_name = value; + } + else { + return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), + stringify!($($ty)+), + value.type_str())); + } + }, + )+ + "third-party" => { + // for external tools such as clippy-service + return Ok(()); + } + _ => { + return Err(ConfError::UnknownKey(name)); + } + } + + Ok(()) + } + } + }; + + // hack to convert tts + (PAT $pat: pat) => { $pat }; + (EXPR $e: expr) => { $e }; + (TY $ty: ty) => { $ty }; + + // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; + (CONV Vec<String>, $value: expr) => {{ + let slice = $value.as_slice(); + + 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().unwrap_or_else(|| unreachable!()).to_owned()).collect()) + } + } + else { + None + } + }}; + + // provide a nicer syntax to declare the default value of `Vec<String>` variables + (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; + (DEFAULT $ty: ty, $e: expr) => { $e }; +} + +define_Conf! { + /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about + ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), + /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have + ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), + /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have + ("too-many-arguments-threshold", too_many_arguments_threshold, 6 => u64), + /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have + ("type-complexity-threshold", type_complexity_threshold, 250 => u64), +} + +/// Read the `toml` configuration file. The function will ignore “File not found” errors iif +/// `!must_exist`, in which case, it will return the default configuration. +pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { + let mut conf = Conf::default(); + + let file = match fs::File::open(path) { + Ok(mut file) => { + let mut buf = String::new(); + try!(file.read_to_string(&mut buf)); + buf + } + Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { + return Ok(conf); + } + Err(err) => { + return Err(err.into()); + } + }; + + let mut parser = toml::Parser::new(&file); + let toml = if let Some(toml) = parser.parse() { + toml + } else { + return Err(ConfError::TomlError(parser.errors)); + }; + + for (key, value) in toml { + try!(conf.set(key, value)); + } + + Ok(conf) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 625e8da197d..feeb70126ea 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -14,6 +14,7 @@ use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; +pub mod conf; mod hir; pub use self::hir::{SpanlessEq, SpanlessHash}; pub type MethodArgs = HirVec<P<Expr>>; -- cgit 1.4.1-3-g733a5 From 95e582a338068a840d0d5a9be6ae4b2b9c93c053 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 6 Mar 2016 15:48:56 +0100 Subject: Don’t make conf errors fatal errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 38 ++++++++++++++++++++++---------------- src/utils/conf.rs | 25 ++++++++++++++++++------- 2 files changed, 40 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a7fe2c1aab3..1088e4bc139 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,24 +111,30 @@ mod reexport { #[plugin_registrar] #[cfg_attr(rustfmt, rustfmt_skip)] pub fn plugin_registrar(reg: &mut Registry) { - let conferr = match utils::conf::conf_file(reg.args()) { - Ok(Some(file_name)) => { - utils::conf::read_conf(&file_name, true) - } - Ok(None) => { - utils::conf::read_conf("Clippy.toml", false) + let conf = match utils::conf::conf_file(reg.args()) { + Ok(file_name) => { + // if the user specified a file, it must exist, otherwise default to `Clippy.toml` but + // do not require the file to exist + let (ref file_name, must_exist) = if let Some(ref file_name) = file_name { + (&**file_name, true) + } else { + ("Clippy.toml", false) + }; + + let (conf, errors) = utils::conf::read_conf(&file_name, must_exist); + + // all conf errors are non-fatal, we just use the default conf in case of error + for error in errors { + reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit(); + } + + conf } Err((err, span)) => { - reg.sess.struct_span_err(span, err).emit(); - return; - } - }; - - let conf = match conferr { - Ok(conf) => conf, - Err(err) => { - reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", err)).emit(); - return; + reg.sess.struct_span_err(span, err) + .span_note(span, "Clippy will use defaulf configuration") + .emit(); + utils::conf::Conf::default() } }; diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 93caa1edca3..8c36570c833 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -157,20 +157,28 @@ define_Conf! { /// Read the `toml` configuration file. The function will ignore “File not found” errors iif /// `!must_exist`, in which case, it will return the default configuration. -pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { +/// In case of error, the function tries to continue as much as possible. +pub fn read_conf(path: &str, must_exist: bool) -> (Conf, Vec<ConfError>) { let mut conf = Conf::default(); + let mut errors = Vec::new(); let file = match fs::File::open(path) { Ok(mut file) => { let mut buf = String::new(); - try!(file.read_to_string(&mut buf)); + + if let Err(err) = file.read_to_string(&mut buf) { + errors.push(err.into()); + return (conf, errors); + } + buf } Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { - return Ok(conf); + return (conf, errors); } Err(err) => { - return Err(err.into()); + errors.push(err.into()); + return (conf, errors); } }; @@ -178,12 +186,15 @@ pub fn read_conf(path: &str, must_exist: bool) -> Result<Conf, ConfError> { let toml = if let Some(toml) = parser.parse() { toml } else { - return Err(ConfError::TomlError(parser.errors)); + errors.push(ConfError::TomlError(parser.errors)); + return (conf, errors); }; for (key, value) in toml { - try!(conf.set(key, value)); + if let Err(err) = conf.set(key, value) { + errors.push(err); + } } - Ok(conf) + (conf, errors) } -- cgit 1.4.1-3-g733a5 From aa4daea3646f1ff34362f6f52a6881fab91190a6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 9 Mar 2016 00:48:10 +0100 Subject: Lint function with too many arguments --- README.md | 3 +- src/functions.rs | 75 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/utils/conf.rs | 2 +- tests/compile-fail/functions.rs | 33 ++++++++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 src/functions.rs create mode 100755 tests/compile-fail/functions.rs (limited to 'src') diff --git a/README.md b/README.md index 97e0a075dd2..93edf4a81fa 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 135 lints included in this crate: +There are 136 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -130,6 +130,7 @@ name [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` [suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries +[too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions diff --git a/src/functions.rs b/src/functions.rs new file mode 100644 index 00000000000..5ac5aae51a4 --- /dev/null +++ b/src/functions.rs @@ -0,0 +1,75 @@ +use rustc::lint::*; +use rustc_front::hir; +use rustc_front::intravisit; +use syntax::ast; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** Check for functions with too many parameters. +/// +/// **Why is this bad?** Functions with lots of parameters are considered bad style and reduce +/// readability (“what does the 5th parameter means?”). Consider grouping some parameters into a +/// new type. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// +/// ``` +/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. } +/// ``` +declare_lint! { + pub TOO_MANY_ARGUMENTS, + Warn, + "functions with too many arguments" +} + +#[derive(Copy,Clone)] +pub struct Functions { + threshold: u64, +} + +impl Functions { + pub fn new(threshold: u64) -> Functions { + Functions { + threshold: threshold + } + } +} + +impl LintPass for Functions { + fn get_lints(&self) -> LintArray { + lint_array!(TOO_MANY_ARGUMENTS) + } +} + +impl LateLintPass for Functions { + fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) { + use rustc::front::map::Node::*; + + if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { + match item.node { + hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..) => return, + _ => (), + } + } + + self.check_arg_number(cx, decl, span); + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { + if let hir::MethodTraitItem(ref sig, _) = item.node { + self.check_arg_number(cx, &sig.decl, item.span); + } + } +} + +impl Functions { + fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { + let args = decl.inputs.len() as u64; + if args > self.threshold { + span_lint(cx, TOO_MANY_ARGUMENTS, span, + &format!("this function has to many arguments ({}/{})", args, self.threshold)); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 1088e4bc139..d65294b56b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ pub mod escape; pub mod eta_reduction; pub mod format; pub mod formatting; +pub mod functions; pub mod identity_op; pub mod if_not_else; pub mod items_after_statements; @@ -211,6 +212,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); + reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -263,6 +265,7 @@ pub fn plugin_registrar(reg: &mut Registry) { format::USELESS_FORMAT, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, + functions::TOO_MANY_ARGUMENTS, identity_op::IDENTITY_OP, if_not_else::IF_NOT_ELSE, items_after_statements::ITEMS_AFTER_STATEMENTS, diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 8c36570c833..6636e30ab38 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -150,7 +150,7 @@ define_Conf! { /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64), /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have - ("too-many-arguments-threshold", too_many_arguments_threshold, 6 => u64), + ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64), /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have ("type-complexity-threshold", type_complexity_threshold, 250 => u64), } diff --git a/tests/compile-fail/functions.rs b/tests/compile-fail/functions.rs new file mode 100755 index 00000000000..d3d5eee335a --- /dev/null +++ b/tests/compile-fail/functions.rs @@ -0,0 +1,33 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(clippy)] +#![allow(dead_code)] + +fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} + +fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) { + //~^ ERROR: this function has to many arguments (8/7) +} + +trait Foo { + fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool); + fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); + //~^ ERROR: this function has to many arguments (8/7) +} + +struct Bar; + +impl Bar { + fn good_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} + fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} + //~^ ERROR: this function has to many arguments (8/7) +} + +// ok, we don’t want to warn implementations +impl Foo for Bar { + fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} + fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 14dcb60bf8c68dda34bb22894534f4d9b83e60df Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 9 Mar 2016 11:48:55 +0100 Subject: s/Clippy.toml/clippy.toml --- README.md | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 93edf4a81fa..52223ef097b 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ And, in your `main.rs` or `lib.rs`: ``` ## Configuration -Some lints can be configured in a `Clippy.toml` file. It contains basic `variable = value` mapping eg. +Some lints can be configured in a `clippy.toml` file. It contains basic `variable = value` mapping eg. ```toml blacklisted-names = ["toto", "tata", "titi"] diff --git a/src/lib.rs b/src/lib.rs index d65294b56b8..f5a3598a1ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,12 +114,12 @@ mod reexport { pub fn plugin_registrar(reg: &mut Registry) { let conf = match utils::conf::conf_file(reg.args()) { Ok(file_name) => { - // if the user specified a file, it must exist, otherwise default to `Clippy.toml` but + // if the user specified a file, it must exist, otherwise default to `clippy.toml` but // do not require the file to exist let (ref file_name, must_exist) = if let Some(ref file_name) = file_name { (&**file_name, true) } else { - ("Clippy.toml", false) + ("clippy.toml", false) }; let (conf, errors) = utils::conf::read_conf(&file_name, must_exist); -- cgit 1.4.1-3-g733a5 From 04d81799a22f7a3e8138fae806502b830b647628 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 12 Mar 2016 21:23:35 +0100 Subject: Dogfood --- src/utils/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 625e8da197d..ee2e2d7206f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -383,14 +383,14 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { let x = s.lines() .skip(ignore_first as usize) .filter_map(|l| { - if l.len() > 0 { + if l.is_empty() { + None + } else { // ignore empty lines Some(l.char_indices() .find(|&(_, x)| x != ch) .unwrap_or((l.len(), ch)) .0) - } else { - None } }) .min() @@ -399,7 +399,7 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { Cow::Owned(s.lines() .enumerate() .map(|(i, l)| { - if (ignore_first && i == 0) || l.len() == 0 { + if (ignore_first && i == 0) || l.is_empty() { l } else { l.split_at(x).1 -- cgit 1.4.1-3-g733a5 From 7eef989ff4859f9b551b3905f2bf30c6ff113872 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 12 Mar 2016 21:12:35 +0100 Subject: Add `str` to types considered by `len_zero` --- src/len_zero.rs | 2 +- tests/compile-fail/len_zero.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 548a3d92c2c..e61c77adf24 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -198,7 +198,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { } ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), - ty::TyArray(..) => true, + ty::TyArray(..) | ty::TyStr => true, _ => false, } } diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 9814a1c2d7d..5168f80b856 100644 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -76,6 +76,12 @@ fn main() { println!("This should not happen!"); } + if "".len() == 0 { + //~^ERROR length comparison to zero + //~|HELP consider using `is_empty` + //~|SUGGESTION "".is_empty() + } + let y = One; if y.len() == 0 { //no error because One does not have .is_empty() println!("This should not happen either!"); -- cgit 1.4.1-3-g733a5 From 0774b203f4a9a46d91ea4edfab89e7552382c2c6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 12 Mar 2016 21:23:01 +0100 Subject: Fix false-positive in `panic_params` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It might still have false positives, but it’s even less likely. --- src/panic.rs | 3 ++- tests/compile-fail/panic.rs | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/panic.rs b/src/panic.rs index 60a3ce1a461..7dbcf2a5b30 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -37,7 +37,8 @@ impl LateLintPass for PanicPass { match_path(path, &BEGIN_UNWIND), let ExprLit(ref lit) = params[0].node, let LitKind::Str(ref string, _) = lit.node, - string.contains('{'), + let Some(par) = string.find('{'), + string[par..].contains('}'), let Some(sp) = cx.sess().codemap() .with_expn_info(expr.span.expn_id, |info| info.map(|i| i.call_site)) diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 36427f4330b..38fe5aa2c0f 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -4,10 +4,14 @@ #[deny(panic_params)] fn missing() { - panic!("{}"); //~ERROR: You probably are missing some parameter + if true { + panic!("{}"); //~ERROR: You probably are missing some parameter + } else { + panic!("{:?}"); //~ERROR: You probably are missing some parameter + } } -fn ok_sigle() { +fn ok_single() { panic!("foo bar"); } @@ -15,8 +19,18 @@ fn ok_multiple() { panic!("{}", "This is {ok}"); } +fn ok_bracket() { + // the match is just here because of #759, it serves no other purpose for the lint + match 42 { + 1337 => panic!("{so is this"), + 666 => panic!("so is this}"), + _ => panic!("}so is that{"), + } +} + fn main() { missing(); - ok_sigle(); + ok_single(); ok_multiple(); + ok_bracket(); } -- cgit 1.4.1-3-g733a5 From d5a01e8789ff46e4f35bf48273c274b5c5effd31 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 17:24:55 +0100 Subject: prevent cc lint from panicking on unreachable code --- src/cyclomatic_complexity.rs | 4 ++++ tests/compile-fail/cyclomatic_complexity.rs | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index bc13576fe3b..a03a42f2bc0 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -47,6 +47,10 @@ impl CyclomaticComplexity { let cfg = CFG::new(cx.tcx, block); let n = cfg.graph.len_nodes() as u64; let e = cfg.graph.len_edges() as u64; + if e + 2 < n { + // the function has unreachable code, other lints should catch this + return; + } let cc = e + 2 - n; let mut helper = CCHelper { match_arms: 0, diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 30a05c3f87d..f744d60440f 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -298,3 +298,9 @@ fn void(void: Void) { //~ ERROR: the function has a cyclomatic complexity of 1 } } } + +#[cyclomatic_complexity = "0"] +fn mcarton_sees_all() { + panic!("meh"); + panic!("möh"); +} -- cgit 1.4.1-3-g733a5 From 20123eef982d3bd26fb30df8ead2f386d0daad7b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 15 Mar 2016 21:03:08 +0530 Subject: Update to rustc 1.9.0-nightly (6d215fe04 2016-03-14) --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 0bf83ab872a..115ca4ede32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ plugin = true [dependencies] regex-syntax = "0.3.0" -regex_macros = { version = "0.1.28", optional = true } +regex_macros = { version = "0.1.33", optional = true } semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" diff --git a/src/lib.rs b/src/lib.rs index f5a3598a1ba..17f35e07537 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ extern crate semver; extern crate regex_syntax; extern crate rustc_plugin; - +extern crate rustc_const_eval; use rustc_plugin::Registry; pub mod consts; -- cgit 1.4.1-3-g733a5 From d65953330b45672b61a321add42056376b3c2342 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 15 Mar 2016 20:09:53 +0100 Subject: rustup const eval changes --- src/array_indexing.rs | 19 +++++++------ src/bit_mask.rs | 2 +- src/consts.rs | 2 +- src/enum_clike.rs | 12 +++----- src/loops.rs | 5 +--- src/matches.rs | 76 +++++++++++++++------------------------------------ src/types.rs | 59 +++++++++++++++++++++------------------ 7 files changed, 71 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index 274491b7c96..3c6acb93284 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -3,6 +3,7 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::ty::TyArray; use rustc_front::hir::*; +use rustc_const_eval::ConstInt; use syntax::ast::RangeLimits; use utils; @@ -62,11 +63,11 @@ impl LateLintPass for ArrayIndexing { // Array with known size can be checked statically let ty = cx.tcx.expr_ty(array); if let TyArray(_, size) = ty.sty { - let size = size as u64; + let size = ConstInt::Infer(size as u64); // Index is a constant uint let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); - if let Ok(ConstVal::Uint(const_index)) = const_index { + if let Ok(ConstVal::Integral(const_index)) = const_index { if size <= const_index { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); } @@ -115,24 +116,24 @@ impl LateLintPass for ArrayIndexing { fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, - array_size: u64) - -> Option<(u64, u64)> { + array_size: ConstInt) + -> Option<(ConstInt, ConstInt)> { let start = match start { - Some(Some(ConstVal::Uint(x))) => x, + Some(Some(ConstVal::Integral(x))) => x, Some(_) => return None, - None => 0, + None => ConstInt::Infer(0), }; let end = match end { - Some(Some(ConstVal::Uint(x))) => { + Some(Some(ConstVal::Integral(x))) => { if limits == RangeLimits::Closed { x } else { - x - 1 + (x - ConstInt::Infer(1)).expect("x > 0") } } Some(_) => return None, - None => array_size - 1, + None => (array_size - ConstInt::Infer(1)).expect("array_size > 0"), }; Some((start, end)) diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 0e09122bcc6..02d428e834d 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -271,7 +271,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { } } .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None, None)) - .and_then(|l| fetch_int_literal(cx, l)) + .and_then(|(l, _ty)| fetch_int_literal(cx, l)) } _ => None, } diff --git a/src/consts.rs b/src/consts.rs index 6dd5651e7ef..eae9747d6e0 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -347,7 +347,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } // separate if lets to avoid double borrowing the def_map if let Some(id) = maybe_id { - if let Some(const_expr) = lookup_const_by_id(lcx.tcx, id, None, None) { + if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None, None) { let ret = self.expr(const_expr); if ret.is_some() { self.needed_resolution = true; diff --git a/src/enum_clike.rs b/src/enum_clike.rs index 7ee71f41f29..85fa418f278 100644 --- a/src/enum_clike.rs +++ b/src/enum_clike.rs @@ -1,11 +1,9 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` use rustc::lint::*; -use syntax::ast::{IntTy, UintTy}; use syntax::attr::*; use rustc_front::hir::*; use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial}; -use rustc::middle::ty; use utils::span_lint; /// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. @@ -35,12 +33,10 @@ impl LateLintPass for EnumClikeUnportableVariant { for var in &def.variants { let variant = &var.node; if let Some(ref disr) = variant.disr_expr { - let cv = eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None); - let bad = match (cv, &cx.tcx.expr_ty(&**disr).sty) { - (Ok(ConstVal::Int(i)), &ty::TyInt(IntTy::Is)) => i as i32 as i64 != i, - (Ok(ConstVal::Uint(i)), &ty::TyInt(IntTy::Is)) => i as i32 as u64 != i, - (Ok(ConstVal::Int(i)), &ty::TyUint(UintTy::Us)) => (i < 0) || (i as u32 as i64 != i), - (Ok(ConstVal::Uint(i)), &ty::TyUint(UintTy::Us)) => i as u32 as u64 != i, + use rustc_const_eval::*; + let bad = match eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None) { + Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i, + Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i, _ => false, }; if bad { diff --git a/src/loops.rs b/src/loops.rs index 462ca7c49f6..7987c70d027 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -429,10 +429,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // who think that this will iterate from the larger value to the // smaller value. let (sup, eq) = match (start_idx, end_idx) { - (ConstVal::Int(start_idx), ConstVal::Int(end_idx)) => { - (start_idx > end_idx, start_idx == end_idx) - } - (ConstVal::Uint(start_idx), ConstVal::Uint(end_idx)) => { + (ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => { (start_idx > end_idx, start_idx == end_idx) } _ => (false, false), diff --git a/src/matches.rs b/src/matches.rs index 4c60ea89b34..a456a816f62 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,9 +1,9 @@ use rustc::lint::*; -use rustc::middle::const_eval::ConstVal::{Int, Uint}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::ty; use rustc_front::hir::*; +use rustc_const_eval::ConstInt; use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; @@ -288,19 +288,16 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms); - let overlap = match type_ranges(&ranges) { - TypedRanges::IntRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), - TypedRanges::UintRanges(ranges) => overlapping(&ranges).map(|(start, end)| (start.span, end.span)), - TypedRanges::None => None, - }; - - if let Some((start, end)) = overlap { - span_note_and_lint(cx, - MATCH_OVERLAPPING_ARM, - start, - "some ranges overlap", - end, - "overlaps with this"); + let type_ranges = type_ranges(&ranges); + if !type_ranges.is_empty() { + if let Some((start, end)) = overlapping(&type_ranges) { + span_note_and_lint(cx, + MATCH_OVERLAPPING_ARM, + start.span, + "some ranges overlap", + end.span, + "overlaps with this"); + } } } } @@ -370,51 +367,22 @@ pub struct SpannedRange<T> { pub node: (T, T), } -#[derive(Debug)] -enum TypedRanges { - IntRanges(Vec<SpannedRange<i64>>), - UintRanges(Vec<SpannedRange<u64>>), - None, -} +type TypedRanges = Vec<SpannedRange<ConstInt>>; /// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than /// `Uint` and `Int` probably don't make sense. fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { - if ranges.is_empty() { - TypedRanges::None - } else { - match ranges[0].node { - (Int(_), Int(_)) => { - TypedRanges::IntRanges(ranges.iter() - .filter_map(|range| { - if let (Int(start), Int(end)) = range.node { - Some(SpannedRange { - span: range.span, - node: (start, end), - }) - } else { - None - } - }) - .collect()) - } - (Uint(_), Uint(_)) => { - TypedRanges::UintRanges(ranges.iter() - .filter_map(|range| { - if let (Uint(start), Uint(end)) = range.node { - Some(SpannedRange { - span: range.span, - node: (start, end), - }) - } else { - None - } - }) - .collect()) - } - _ => TypedRanges::None, + 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() } fn is_unit_expr(expr: &Expr) -> bool { diff --git a/src/types.rs b/src/types.rs index e64bf010549..c5acbb41ea1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -673,6 +673,7 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use types::ExtremeType::*; use rustc::middle::const_eval::ConstVal::*; + use rustc_const_eval::*; let ty = &cx.tcx.expr_ty(expr).sty; @@ -687,33 +688,37 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx }; let which = match (ty, cv) { - (&ty::TyBool, Bool(false)) => Minimum, - - (&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MIN as i64 => Minimum, - (&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MIN as i64 => Minimum, - - (&ty::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MIN as u64 => Minimum, - (&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MIN as u64 => Minimum, - - (&ty::TyBool, Bool(true)) => Maximum, - - (&ty::TyInt(IntTy::Is), Int(x)) if x == ::std::isize::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::I8), Int(x)) if x == ::std::i8::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::I16), Int(x)) if x == ::std::i16::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::I32), Int(x)) if x == ::std::i32::MAX as i64 => Maximum, - (&ty::TyInt(IntTy::I64), Int(x)) if x == ::std::i64::MAX as i64 => Maximum, - - (&ty::TyUint(UintTy::Us), Uint(x)) if x == ::std::usize::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::U8), Uint(x)) if x == ::std::u8::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::U16), Uint(x)) if x == ::std::u16::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::U32), Uint(x)) if x == ::std::u32::MAX as u64 => Maximum, - (&ty::TyUint(UintTy::U64), Uint(x)) if x == ::std::u64::MAX as u64 => Maximum, + (&ty::TyBool, Bool(false)) | + + (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) | + (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) | + (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) | + (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) | + (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) | + + (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) | + (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) | + (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) | + (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MIN))) | + (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum, + + (&ty::TyBool, Bool(true)) | + + (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) | + (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) | + (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) | + (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) | + (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) | + + (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) | + (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) | + (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) | + (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) | + (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) => Maximum, _ => return None, }; -- cgit 1.4.1-3-g733a5 From 1546cc47988129cd41b4531f4670f49937162b4c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 14 Mar 2016 21:48:24 +0100 Subject: Fix ICE in `OUT_OF_BOUNDS_INDEXING` with ranges --- src/array_indexing.rs | 19 ++++++++----------- tests/compile-fail/array_indexing.rs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index 3c6acb93284..ece66ae20a2 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -83,7 +83,7 @@ impl LateLintPass for ArrayIndexing { eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)).map(|v| v.ok()); if let Some((start, end)) = to_const_range(start, end, range.limits, size) { - if start >= size || end >= size { + if start > size || end > size { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, @@ -109,14 +109,11 @@ impl LateLintPass for ArrayIndexing { } } -/// Returns an option containing a tuple with the start and end (exclusive) of the range -/// -/// Note: we assume the start and the end of the range are unsigned, since array slicing -/// works only on usize +/// Returns an option containing a tuple with the start and end (exclusive) of the range. fn to_const_range(start: Option<Option<ConstVal>>, - end: Option<Option<ConstVal>>, - limits: RangeLimits, - array_size: ConstInt) + end: Option<Option<ConstVal>>, + limits: RangeLimits, + array_size: ConstInt) -> Option<(ConstInt, ConstInt)> { let start = match start { Some(Some(ConstVal::Integral(x))) => x, @@ -127,13 +124,13 @@ fn to_const_range(start: Option<Option<ConstVal>>, let end = match end { Some(Some(ConstVal::Integral(x))) => { if limits == RangeLimits::Closed { - x + (x + ConstInt::Infer(1)).expect("such a big array is not realistic") } else { - (x - ConstInt::Infer(1)).expect("x > 0") + x } } Some(_) => return None, - None => (array_size - ConstInt::Infer(1)).expect("array_size > 0"), + None => array_size }; Some((start, end)) diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs index 14f3448a9f6..35fadf8c1e4 100644 --- a/tests/compile-fail/array_indexing.rs +++ b/tests/compile-fail/array_indexing.rs @@ -16,6 +16,8 @@ fn main() { &x[0...4]; //~ERROR: range is out of bounds &x[..]; &x[1..]; + &x[4..]; + &x[5..]; //~ERROR: range is out of bounds &x[..4]; &x[..5]; //~ERROR: range is out of bounds @@ -24,4 +26,16 @@ fn main() { &y[1..2]; //~ERROR: slicing may panic &y[..]; &y[0...4]; //~ERROR: slicing may panic + + let empty: [i8; 0] = []; + empty[0]; //~ERROR: const index is out of bounds + &empty[1..5]; //~ERROR: range is out of bounds + &empty[0...4]; //~ERROR: range is out of bounds + &empty[..]; + &empty[0..]; + &empty[0..0]; + &empty[0...0]; //~ERROR: range is out of bounds + &empty[..0]; + &empty[1..]; //~ERROR: range is out of bounds + &empty[..4]; //~ERROR: range is out of bounds } -- cgit 1.4.1-3-g733a5 From 6d4e1bd73d080476a371b904d99827f2a056c6d2 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 14 Mar 2016 22:00:01 +0100 Subject: Fix false positive with STRING_LIT_AS_BYTES and stringify! --- src/strings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index f4318fc261a..dac5ac9f6bd 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -140,7 +140,7 @@ impl LateLintPass for StringLitAsBytes { if name.node.as_str() == "as_bytes" { if let ExprLit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { - if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, e.span) { + if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, args[0].span) { let msg = format!("calling `as_bytes()` on a string literal. \ Consider using a byte string literal instead: \ `b{}`", -- cgit 1.4.1-3-g733a5 From 251c3eefd15bb35cad053e9526768ca949f6efea Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 14 Mar 2016 22:03:30 +0100 Subject: Use `span_suggestion` in `STRING_LIT_AS_BYTES` --- src/strings.rs | 19 +++++++++++++------ tests/compile-fail/strings.rs | 8 +++++++- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/strings.rs b/src/strings.rs index dac5ac9f6bd..aa9cdcce50c 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -8,7 +8,7 @@ use rustc_front::hir::*; use syntax::codemap::Spanned; use utils::STRING_PATH; use utils::SpanlessEq; -use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr}; +use utils::{match_type, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr}; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). /// @@ -141,11 +141,18 @@ impl LateLintPass for StringLitAsBytes { if let ExprLit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, args[0].span) { - let msg = format!("calling `as_bytes()` on a string literal. \ - Consider using a byte string literal instead: \ - `b{}`", - snippet(cx, args[0].span, r#""foo""#)); - span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg); + span_lint_and_then(cx, + STRING_LIT_AS_BYTES, + 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); + }); + } } } diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 7ed93737ffa..656349ba621 100644 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -47,9 +47,15 @@ fn both() { #[allow(dead_code, unused_variables)] #[deny(string_lit_as_bytes)] fn str_lit_as_bytes() { - let bs = "hello there".as_bytes(); //~ERROR calling `as_bytes()` + let bs = "hello there".as_bytes(); + //~^ERROR calling `as_bytes()` + //~|HELP byte string literal + //~|SUGGESTION b"hello there" + // no warning, because this cannot be written as a byte string literal: let ubs = "☃".as_bytes(); + + let strify = stringify!(foobar).as_bytes(); } fn main() { -- cgit 1.4.1-3-g733a5 From 8282a3a426690b8dddf7b275621090402b254444 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 15 Mar 2016 21:02:08 +0100 Subject: Fix problem in PANIC_PARAMS with inner `format!` --- src/panic.rs | 14 +++++--------- src/utils/mod.rs | 20 ++++++++++++++++++++ tests/compile-fail/panic.rs | 15 +++++++++++---- 3 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/panic.rs b/src/panic.rs index 7dbcf2a5b30..8b9bf9f1f19 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::LitKind; -use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; +use utils::{span_lint, is_direct_expn_of, match_path, BEGIN_UNWIND}; /// **What it does:** This lint checks for missing parameters in `panic!`. /// @@ -28,7 +28,6 @@ impl LintPass for PanicPass { impl LateLintPass for PanicPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain! {[ - in_external_macro(cx, expr.span), let ExprBlock(ref block) = expr.node, let Some(ref ex) = block.expr, let ExprCall(ref fun, ref params) = ex.node, @@ -36,16 +35,13 @@ impl LateLintPass for PanicPass { let ExprPath(None, ref path) = fun.node, match_path(path, &BEGIN_UNWIND), 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, let Some(par) = string.find('{'), - string[par..].contains('}'), - let Some(sp) = cx.sess().codemap() - .with_expn_info(expr.span.expn_id, - |info| info.map(|i| i.call_site)) + string[par..].contains('}') ], { - - span_lint(cx, PANIC_PARAMS, sp, - "You probably are missing some parameter in your `panic!` call"); + span_lint(cx, PANIC_PARAMS, params[0].span, + "you probably are missing some parameter in your format string"); }} } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 86a5e24efc2..3fb52318b6f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -604,6 +604,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } /// Return the pre-expansion span if is this comes from an expansion of the macro `name`. +/// See also `is_direct_expn_of`. pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { loop { let span_name_span = cx.tcx @@ -619,6 +620,25 @@ pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> } } +/// Return the pre-expansion span if is this directly comes from an expansion of the macro `name`. +/// The difference with `is_expn_of` is that in +/// ```rust,ignore +/// foo!(bar!(42)); +/// ``` +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by +/// `is_direct_expn_of`. +pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option<Span> { + let span_name_span = cx.tcx + .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.as_str() == name => Some(new_span), + _ => None, + } +} + /// Returns index of character after first CamelCase component of `s` pub fn camel_case_until(s: &str) -> usize { let mut iter = s.char_indices(); diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 38fe5aa2c0f..7e535d69b69 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,13 +1,15 @@ #![feature(plugin)] #![plugin(clippy)] -#[deny(panic_params)] +#![deny(panic_params)] fn missing() { if true { - panic!("{}"); //~ERROR: You probably are missing some parameter + panic!("{}"); //~ERROR: you probably are missing some parameter + } else if false { + panic!("{:?}"); //~ERROR: you probably are missing some parameter } else { - panic!("{:?}"); //~ERROR: You probably are missing some parameter + assert!(true, "here be missing values: {}"); //~ERROR you probably are missing some parameter } } @@ -15,12 +17,16 @@ fn ok_single() { panic!("foo bar"); } +fn ok_inner() { + // Test for #768 + assert!("foo bar".contains(&format!("foo {}", "bar"))); +} + fn ok_multiple() { panic!("{}", "This is {ok}"); } fn ok_bracket() { - // the match is just here because of #759, it serves no other purpose for the lint match 42 { 1337 => panic!("{so is this"), 666 => panic!("so is this}"), @@ -33,4 +39,5 @@ fn main() { ok_single(); ok_multiple(); ok_bracket(); + ok_inner(); } -- cgit 1.4.1-3-g733a5 From 1ac6efedd1f462d02de09a3cea0f94037fbd162d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 16 Mar 2016 16:57:11 +0100 Subject: Rustup to *1.9.0-nightly (c66d2380a 2016-03-15)* --- src/escape.rs | 3 ++- src/utils/mod.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index bcc1cb16870..f81a05d43d5 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -3,6 +3,7 @@ use rustc::lint::*; use rustc::middle::expr_use_visitor::*; use rustc::middle::infer; use rustc::middle::mem_categorization::{cmt, Categorization}; +use rustc::middle::traits::ProjectionMode; use rustc::middle::ty::adjustment::AutoAdjustment; use rustc::middle::ty; use rustc::util::nodemap::NodeSet; @@ -54,7 +55,7 @@ impl LintPass for EscapePass { impl LateLintPass for EscapePass { fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env)); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), ProjectionMode::Any); let mut v = EscapeDelegate { cx: cx, set: NodeSet(), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 86a5e24efc2..cacc9f8e51b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,6 +2,7 @@ use reexport::*; use rustc::front::map::Node; use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::middle::def_id::DefId; +use rustc::middle::traits::ProjectionMode; use rustc::middle::{cstore, def, infer, ty, traits}; use rustc::session::Session; use rustc_front::hir::*; @@ -269,7 +270,7 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any); let obligation = traits::predicate_for_trait_def(cx.tcx, traits::ObligationCause::dummy(), trait_id, @@ -753,6 +754,6 @@ pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> { // 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>) -> bool { - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any); infcx.can_equate(&cx.tcx.erase_regions(&a), &cx.tcx.erase_regions(&b)).is_ok() } -- cgit 1.4.1-3-g733a5 From 432d9fec38be7b8b5abe57f002dc3f71d84e63c3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 16 Mar 2016 12:38:26 +0100 Subject: refactor clippy-consts to use ConstInt --- src/consts.rs | 278 +++++++++++------------------------------------------ src/identity_op.rs | 11 ++- tests/consts.rs | 10 +- 3 files changed, 66 insertions(+), 233 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index eae9747d6e0..06f790d8308 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -4,13 +4,14 @@ use rustc::lint::LateContext; use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::{Def, PathResolution}; use rustc_front::hir::*; -use std::cmp::Ordering::{self, Greater, Less, Equal}; +use rustc_const_eval::{ConstInt, ConstUsize, ConstIsize}; +use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::rc::Rc; -use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy}; +use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy}; use syntax::ptr::P; #[derive(Debug, Copy, Clone)] @@ -29,12 +30,6 @@ impl From<FloatTy> for FloatWidth { } } -#[derive(Copy, Eq, Debug, Clone, PartialEq, Hash)] -pub enum Sign { - Plus, - Minus, -} - /// a Lit_-like enum to fold constant `Expr`s into #[derive(Debug, Clone)] pub enum Constant { @@ -42,12 +37,10 @@ pub enum Constant { Str(String, StrStyle), /// a Binary String b"abc" Binary(Rc<Vec<u8>>), - /// a single byte b'a' - Byte(u8), /// a single char 'a' Char(char), /// an integer, third argument is whether the value is negated - Int(u64, LitIntType, Sign), + Int(ConstInt), /// a float with given type Float(String, FloatWidth), /// true or false @@ -67,21 +60,20 @@ impl Constant { /// /// if the constant could not be converted to u64 losslessly fn as_u64(&self) -> u64 { - if let Constant::Int(val, _, _) = *self { - val // TODO we may want to check the sign if any + if let Constant::Int(val) = *self { + val.to_u64().expect("negative constant can't be casted to u64") } else { panic!("Could not convert a {:?} to u64", self); } } /// convert this constant to a f64, if possible - #[allow(cast_precision_loss)] + #[allow(cast_precision_loss, cast_possible_wrap)] pub fn as_float(&self) -> Option<f64> { match *self { - Constant::Byte(b) => Some(b as f64), Constant::Float(ref s, _) => s.parse().ok(), - Constant::Int(i, _, Sign::Minus) => Some(-(i as f64)), - Constant::Int(i, _, Sign::Plus) => Some(i as f64), + Constant::Int(i) if i.is_negative() => Some(i.to_u64_unchecked() as i64 as f64), + Constant::Int(i) => Some(i.to_u64_unchecked() as f64), _ => None, } } @@ -92,10 +84,8 @@ impl PartialEq for Constant { match (self, other) { (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => ls == rs && lsty == rsty, (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, - (&Constant::Byte(l), &Constant::Byte(r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r, - (&Constant::Int(0, _, _), &Constant::Int(0, _, _)) => true, - (&Constant::Int(lv, _, lneg), &Constant::Int(rv, _, rneg)) => lv == rv && lneg == rneg, + (&Constant::Int(l), &Constant::Int(r)) => l == r, (&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 @@ -125,15 +115,11 @@ impl Hash for Constant { Constant::Binary(ref b) => { b.hash(state); } - Constant::Byte(u) => { - u.hash(state); - } Constant::Char(c) => { c.hash(state); } - Constant::Int(u, _, t) => { - u.hash(state); - t.hash(state); + Constant::Int(i) => { + i.hash(state); } Constant::Float(ref f, _) => { // don’t use the width here because of PartialEq implementation @@ -165,13 +151,8 @@ impl PartialOrd for Constant { None } } - (&Constant::Byte(ref l), &Constant::Byte(ref r)) => Some(l.cmp(r)), (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), - (&Constant::Int(0, _, _), &Constant::Int(0, _, _)) => Some(Equal), - (&Constant::Int(ref lv, _, Sign::Plus), &Constant::Int(ref rv, _, Sign::Plus)) => Some(lv.cmp(rv)), - (&Constant::Int(ref lv, _, Sign::Minus), &Constant::Int(ref rv, _, Sign::Minus)) => Some(rv.cmp(lv)), - (&Constant::Int(_, _, Sign::Minus), &Constant::Int(_, _, Sign::Plus)) => Some(Less), - (&Constant::Int(_, _, Sign::Plus), &Constant::Int(_, _, Sign::Minus)) => Some(Greater), + (&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)), (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { match (ls.parse::<f64>(), rs.parse::<f64>()) { (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), @@ -192,13 +173,24 @@ impl PartialOrd for Constant { } } +#[allow(cast_possible_wrap)] fn lit_to_constant(lit: &LitKind) -> Constant { match *lit { LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), - LitKind::Byte(b) => Constant::Byte(b), + LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), LitKind::Char(c) => Constant::Char(c), - LitKind::Int(value, ty) => Constant::Int(value, ty, Sign::Plus), + LitKind::Int(value, LitIntType::Unsuffixed) => Constant::Int(ConstInt::Infer(value)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U8)) => Constant::Int(ConstInt::U8(value as u8)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)), + 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), @@ -209,23 +201,7 @@ fn constant_not(o: Constant) -> Option<Constant> { use self::Constant::*; match o { Bool(b) => Some(Bool(!b)), - Int(value, LitIntType::Signed(ity), Sign::Plus) if value != ::std::u64::MAX => { - Some(Int(value + 1, LitIntType::Signed(ity), Sign::Minus)) - } - Int(0, LitIntType::Signed(ity), Sign::Minus) => Some(Int(1, LitIntType::Signed(ity), Sign::Minus)), - Int(value, LitIntType::Signed(ity), Sign::Minus) => Some(Int(value - 1, LitIntType::Signed(ity), Sign::Plus)), - Int(value, LitIntType::Unsigned(ity), Sign::Plus) => { - let mask = match ity { - UintTy::U8 => ::std::u8::MAX as u64, - UintTy::U16 => ::std::u16::MAX as u64, - UintTy::U32 => ::std::u32::MAX as u64, - UintTy::U64 => ::std::u64::MAX, - UintTy::Us => { - return None; - } // refuse to guess - }; - Some(Int(!value & mask, LitIntType::Unsigned(ity), Sign::Plus)) - } + Int(value) => (!value).ok().map(Int), _ => None, } } @@ -233,20 +209,12 @@ fn constant_not(o: Constant) -> Option<Constant> { fn constant_negate(o: Constant) -> Option<Constant> { use self::Constant::*; match o { - Int(value, LitIntType::Signed(ity), sign) => Some(Int(value, LitIntType::Signed(ity), neg_sign(sign))), - Int(value, LitIntType::Unsuffixed, sign) => Some(Int(value, LitIntType::Unsuffixed, neg_sign(sign))), + Int(value) => (-value).ok().map(Int), Float(is, ty) => Some(Float(neg_float_str(is), ty)), _ => None, } } -fn neg_sign(s: Sign) -> Sign { - match s { - Sign::Plus => Sign::Minus, - Sign::Minus => Sign::Plus, - } -} - fn neg_float_str(s: String) -> String { if s.starts_with('-') { s[1..].to_owned() @@ -255,32 +223,6 @@ fn neg_float_str(s: String) -> String { } } -fn unify_int_type(l: LitIntType, r: LitIntType) -> Option<LitIntType> { - use syntax::ast::LitIntType::*; - match (l, r) { - (Signed(lty), Signed(rty)) => { - if lty == rty { - Some(LitIntType::Signed(lty)) - } else { - None - } - } - (Unsigned(lty), Unsigned(rty)) => { - if lty == rty { - Some(LitIntType::Unsigned(lty)) - } else { - None - } - } - (Unsuffixed, Unsuffixed) => Some(Unsuffixed), - (Signed(lty), Unsuffixed) => Some(Signed(lty)), - (Unsigned(lty), Unsuffixed) => Some(Unsigned(lty)), - (Unsuffixed, Signed(rty)) => Some(Signed(rty)), - (Unsuffixed, Unsigned(rty)) => Some(Unsigned(rty)), - _ => None, - } -} - pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { let mut cx = ConstEvalLateContext { lcx: Some(lcx), @@ -381,101 +323,36 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { - match op.node { - BiAdd => { - self.binop_apply(left, right, |l, r| { - match (l, r) { - (Constant::Byte(l8), Constant::Byte(r8)) => l8.checked_add(r8).map(Constant::Byte), - (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { - add_ints(l64, r64, lty, rty, lsign, rsign) - } - // TODO: float (would need bignum library?) - _ => None, - } - }) - } - BiSub => { - self.binop_apply(left, right, |l, r| { - match (l, r) { - (Constant::Byte(l8), Constant::Byte(r8)) => { - if r8 > l8 { - None - } else { - Some(Constant::Byte(l8 - r8)) - } - } - (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { - add_ints(l64, r64, lty, rty, lsign, neg_sign(rsign)) - } - _ => None, - } - }) - } - BiMul => self.divmul(left, right, u64::checked_mul), - BiDiv => self.divmul(left, right, u64::checked_div), - // BiRem, - BiAnd => self.short_circuit(left, right, false), - BiOr => self.short_circuit(left, right, true), - BiBitXor => self.bitop(left, right, |x, y| x ^ y), - BiBitAnd => self.bitop(left, right, |x, y| x & y), - BiBitOr => self.bitop(left, right, |x, y| (x | y)), - BiShl => self.bitop(left, right, |x, y| x << y), - BiShr => self.bitop(left, right, |x, y| x >> y), - BiEq => self.binop_apply(left, right, |l, r| Some(Constant::Bool(l == r))), - BiNe => self.binop_apply(left, right, |l, r| Some(Constant::Bool(l != r))), - BiLt => self.cmp(left, right, Less, true), - BiLe => self.cmp(left, right, Greater, false), - BiGe => self.cmp(left, right, Less, false), - BiGt => self.cmp(left, right, Greater, true), + let l = if let Some(l) = self.expr(left) { l } else { return None; }; + let r = self.expr(right); + match (op.node, l, r) { + (BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int), + (BiSub, Constant::Int(l), Some(Constant::Int(r))) => (l - r).ok().map(Constant::Int), + (BiMul, Constant::Int(l), Some(Constant::Int(r))) => (l * r).ok().map(Constant::Int), + (BiDiv, Constant::Int(l), Some(Constant::Int(r))) => (l / r).ok().map(Constant::Int), + (BiRem, Constant::Int(l), Some(Constant::Int(r))) => (l % r).ok().map(Constant::Int), + (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), + (BiAnd, Constant::Bool(true), Some(r)) => Some(r), + (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), + (BiOr, Constant::Bool(false), Some(r)) => Some(r), + (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), + (BiBitXor, Constant::Int(l), Some(Constant::Int(r))) => (l ^ r).ok().map(Constant::Int), + (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), + (BiBitAnd, Constant::Int(l), Some(Constant::Int(r))) => (l & r).ok().map(Constant::Int), + (BiBitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), + (BiBitOr, Constant::Int(l), Some(Constant::Int(r))) => (l | r).ok().map(Constant::Int), + (BiShl, Constant::Int(l), Some(Constant::Int(r))) => (l << r).ok().map(Constant::Int), + (BiShr, Constant::Int(l), Some(Constant::Int(r))) => (l >> r).ok().map(Constant::Int), + (BiEq, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l == r)), + (BiNe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l != r)), + (BiLt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l < r)), + (BiLe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l <= r)), + (BiGe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l >= r)), + (BiGt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l > r)), _ => None, } } - fn divmul<F>(&mut self, left: &Expr, right: &Expr, f: F) -> Option<Constant> - where F: Fn(u64, u64) -> Option<u64> - { - self.binop_apply(left, right, |l, r| { - match (l, r) { - (Constant::Int(l64, lty, lsign), Constant::Int(r64, rty, rsign)) => { - f(l64, r64).and_then(|value| { - let sign = if lsign == rsign { - Sign::Plus - } else { - Sign::Minus - }; - unify_int_type(lty, rty).map(|ty| Constant::Int(value, ty, sign)) - }) - } - _ => None, - } - }) - } - - fn bitop<F>(&mut self, left: &Expr, right: &Expr, f: F) -> Option<Constant> - where F: Fn(u64, u64) -> u64 - { - self.binop_apply(left, right, |l, r| { - match (l, r) { - (Constant::Bool(l), Constant::Bool(r)) => Some(Constant::Bool(f(l as u64, r as u64) != 0)), - (Constant::Byte(l8), Constant::Byte(r8)) => Some(Constant::Byte(f(l8 as u64, r8 as u64) as u8)), - (Constant::Int(l, lty, lsign), Constant::Int(r, rty, rsign)) => { - if lsign == Sign::Plus && rsign == Sign::Plus { - unify_int_type(lty, rty).map(|ty| Constant::Int(f(l, r), ty, Sign::Plus)) - } else { - None - } - } - _ => None, - } - }) - } - - fn cmp(&mut self, left: &Expr, right: &Expr, ordering: Ordering, b: bool) -> Option<Constant> { - self.binop_apply(left, - right, - |l, r| l.partial_cmp(&r).map(|o| Constant::Bool(b == (o == ordering)))) - } - fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> where F: Fn(Constant, Constant) -> Option<Constant> { @@ -485,51 +362,4 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { None } } - - fn short_circuit(&mut self, left: &Expr, right: &Expr, b: bool) -> Option<Constant> { - self.expr(left).and_then(|left| { - if let Constant::Bool(lbool) = left { - if lbool == b { - Some(left) - } else { - self.expr(right).and_then(|right| { - if let Constant::Bool(_) = right { - Some(right) - } else { - None - } - }) - } - } else { - None - } - }) - } -} - -fn add_ints(l64: u64, r64: u64, lty: LitIntType, rty: LitIntType, lsign: Sign, rsign: Sign) -> Option<Constant> { - let ty = if let Some(ty) = unify_int_type(lty, rty) { - ty - } else { - return None; - }; - - match (lsign, rsign) { - (Sign::Plus, Sign::Plus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Plus)), - (Sign::Plus, Sign::Minus) => { - if r64 > l64 { - Some(Constant::Int(r64 - l64, ty, Sign::Minus)) - } else { - Some(Constant::Int(l64 - r64, ty, Sign::Plus)) - } - } - (Sign::Minus, Sign::Minus) => l64.checked_add(r64).map(|v| Constant::Int(v, ty, Sign::Minus)), - (Sign::Minus, Sign::Plus) => { - if l64 > r64 { - Some(Constant::Int(l64 - r64, ty, Sign::Minus)) - } else { - Some(Constant::Int(r64 - l64, ty, Sign::Plus)) - } - } - } } diff --git a/src/identity_op.rs b/src/identity_op.rs index 8a0da7bcd9f..21167ce768d 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,8 +1,9 @@ -use consts::{constant_simple, Constant, Sign}; +use consts::{constant_simple, Constant}; use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; use utils::{span_lint, snippet, in_macro}; +use rustc_const_eval::ConstInt; /// **What it does:** This lint checks for identity operations, e.g. `x + 0`. /// @@ -54,11 +55,11 @@ impl LateLintPass for IdentityOp { fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(Constant::Int(v, _, sign)) = constant_simple(e) { + if let Some(Constant::Int(v)) = constant_simple(e) { if match m { - 0 => v == 0, - -1 => sign == Sign::Minus && v == 1, - 1 => sign == Sign::Plus && v == 1, + 0 => v == ConstInt::Infer(0), + -1 => v == ConstInt::InferSigned(-1), + 1 => v == ConstInt::Infer(1), _ => unreachable!(), } { span_lint(cx, diff --git a/tests/consts.rs b/tests/consts.rs index 5c6088d0554..78853f7c1e5 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -5,8 +5,10 @@ extern crate clippy; extern crate syntax; extern crate rustc; extern crate rustc_front; +extern crate rustc_const_eval; use rustc_front::hir::*; +use rustc_const_eval::ConstInt; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; @@ -15,7 +17,7 @@ use syntax::ast::LitKind; use syntax::ast::LitIntType; use syntax::ast::StrStyle; -use clippy::consts::{constant_simple, Constant, FloatWidth, Sign}; +use clippy::consts::{constant_simple, Constant, FloatWidth}; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } @@ -44,9 +46,9 @@ fn check(expect: Constant, expr: &Expr) { const TRUE : Constant = Constant::Bool(true); const FALSE : Constant = Constant::Bool(false); -const ZERO : Constant = Constant::Int(0, LitIntType::Unsuffixed, Sign::Plus); -const ONE : Constant = Constant::Int(1, LitIntType::Unsuffixed, Sign::Plus); -const TWO : Constant = Constant::Int(2, LitIntType::Unsuffixed, Sign::Plus); +const ZERO : Constant = Constant::Int(ConstInt::Infer(0)); +const ONE : Constant = Constant::Int(ConstInt::Infer(1)); +const TWO : Constant = Constant::Int(ConstInt::Infer(2)); #[test] fn test_lit() { -- cgit 1.4.1-3-g733a5 From 64110f16dd5fc8b28bcee3f4291f8c4ffb6162aa Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 16 Mar 2016 16:28:31 +0100 Subject: fix `Eq`+`Hash` for `Constant` --- src/consts.rs | 5 +++-- src/identity_op.rs | 8 ++++---- tests/consts.rs | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 06f790d8308..3e08f1b74ff 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -85,7 +85,7 @@ impl PartialEq for Constant { (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => ls == rs && lsty == rsty, (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r, - (&Constant::Int(l), &Constant::Int(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 @@ -119,7 +119,8 @@ impl Hash for Constant { c.hash(state); } Constant::Int(i) => { - i.hash(state); + 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 diff --git a/src/identity_op.rs b/src/identity_op.rs index 21167ce768d..9ade801abb3 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -55,11 +55,11 @@ impl LateLintPass for IdentityOp { fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(Constant::Int(v)) = constant_simple(e) { + if let Some(v @ Constant::Int(_)) = constant_simple(e) { if match m { - 0 => v == ConstInt::Infer(0), - -1 => v == ConstInt::InferSigned(-1), - 1 => v == ConstInt::Infer(1), + 0 => v == Constant::Int(ConstInt::Infer(0)), + -1 => v == Constant::Int(ConstInt::InferSigned(-1)), + 1 => v == Constant::Int(ConstInt::Infer(1)), _ => unreachable!(), } { span_lint(cx, diff --git a/tests/consts.rs b/tests/consts.rs index 78853f7c1e5..3a774f67473 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -86,4 +86,8 @@ fn test_ops() { assert_eq!(half_any, half32); assert_eq!(half_any, half64); assert_eq!(half32, half64); // for transitivity + + assert_eq!(Constant::Int(ConstInt::Infer(0)), Constant::Int(ConstInt::U8(0))); + assert_eq!(Constant::Int(ConstInt::Infer(0)), Constant::Int(ConstInt::I8(0))); + assert_eq!(Constant::Int(ConstInt::InferSigned(-1)), Constant::Int(ConstInt::I8(-1))); } -- cgit 1.4.1-3-g733a5 From 06ca1fc0a6d88ff5fbe0dabcc595687861c8c9b1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 1 Mar 2016 10:13:54 +0100 Subject: lint on binding-names that are too similar --- Cargo.toml | 1 + README.md | 1 + src/consts.rs | 7 +- src/lib.rs | 6 ++ src/non_expressive_names.rs | 150 +++++++++++++++++++++++++++++ src/types.rs | 6 +- src/utils/hir.rs | 46 ++++----- src/utils/mod.rs | 4 +- tests/compile-fail/approx_const.rs | 2 +- tests/compile-fail/drop_ref.rs | 2 +- tests/compile-fail/for_loop.rs | 2 +- tests/compile-fail/len_zero.rs | 28 +++--- tests/compile-fail/methods.rs | 1 + tests/compile-fail/non_expressive_names.rs | 37 +++++++ 14 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 src/non_expressive_names.rs create mode 100644 tests/compile-fail/non_expressive_names.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index dd675981fae..844408df23c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ regex_macros = { version = "0.1.33", optional = true } semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" +strsim = "0.4.0" [dev-dependencies] compiletest_rs = "0.1.0" diff --git a/README.md b/README.md index 52223ef097b..2ee4dfc5e6c 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ name [shadow_same](https://github.com/Manishearth/rust-clippy/wiki#shadow_same) | allow | rebinding a name to itself, e.g. `let mut x = &mut x` [shadow_unrelated](https://github.com/Manishearth/rust-clippy/wiki#shadow_unrelated) | allow | The name is re-bound without even using the original value [should_implement_trait](https://github.com/Manishearth/rust-clippy/wiki#should_implement_trait) | warn | defining a method that should be implementing a std trait +[similar_names](https://github.com/Manishearth/rust-clippy/wiki#similar_names) | warn | similarly named items and bindings [single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")` [single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead [single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead diff --git a/src/consts.rs b/src/consts.rs index 3e08f1b74ff..f04ad1d214a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -82,7 +82,7 @@ impl Constant { impl PartialEq for Constant { fn eq(&self, other: &Constant) -> bool { match (self, other) { - (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => ls == rs && lsty == rsty, + (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty, (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, (&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(), @@ -145,8 +145,8 @@ impl Hash for Constant { impl PartialOrd for Constant { fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { match (self, other) { - (&Constant::Str(ref ls, ref lsty), &Constant::Str(ref rs, ref rsty)) => { - if lsty == rsty { + (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => { + if l_sty == r_sty { Some(ls.cmp(rs)) } else { None @@ -354,6 +354,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } } + fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> where F: Fn(Constant, Constant) -> Option<Constant> { diff --git a/src/lib.rs b/src/lib.rs index 17f35e07537..ef6b1f3a2b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,9 @@ extern crate unicode_normalization; // for semver check in attrs.rs extern crate semver; +// for levensthein distance +extern crate strsim; + // for regex checking extern crate regex_syntax; @@ -84,6 +87,7 @@ pub mod needless_features; pub mod needless_update; pub mod new_without_default; pub mod no_effect; +pub mod non_expressive_names; pub mod open_options; pub mod overflow_check_conditional; pub mod panic; @@ -200,6 +204,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); + reg.register_early_lint_pass(box non_expressive_names::SimilarNames(1)); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); reg.register_late_lint_pass(box regex::RegexPass::default()); @@ -326,6 +331,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, + non_expressive_names::SIMILAR_NAMES, open_options::NONSENSICAL_OPEN_OPTIONS, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, panic::PANIC_PARAMS, diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs new file mode 100644 index 00000000000..944dcaeb006 --- /dev/null +++ b/src/non_expressive_names.rs @@ -0,0 +1,150 @@ +use rustc::lint::*; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use syntax::ast::*; +use syntax::visit::{self, FnKind}; +use utils::{span_note_and_lint, in_macro}; +use strsim::levenshtein; + +/// **What it does:** This lint warns about names that are very similar and thus confusing +/// +/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character +/// +/// **Known problems:** None? +/// +/// **Example:** `checked_exp` and `checked_expr` +declare_lint! { + pub SIMILAR_NAMES, + Warn, + "similarly named items and bindings" +} + +pub struct SimilarNames(pub usize); + +impl LintPass for SimilarNames { + fn get_lints(&self) -> LintArray { + lint_array!(SIMILAR_NAMES) + } +} + +struct SimilarNamesLocalVisitor<'a, 'b: 'a> { + names: Vec<(InternedString, Span)>, + cx: &'a EarlyContext<'b>, + limit: usize, +} + +const WHITELIST: &'static [&'static str] = &[ + "lhs", "rhs", +]; + +struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); + +impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { + fn visit_pat(&mut self, pat: &'v Pat) { + if let PatKind::Ident(_, id, _) = pat.node { + self.check_name(id.span, id.node.name); + } + visit::walk_pat(self, pat); + } +} + +impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { + fn check_name(&mut self, span: Span, name: Name) { + if in_macro(self.0.cx, span) { + return; + } + let interned_name = name.as_str(); + if interned_name.chars().any(char::is_uppercase) { + return; + } + if interned_name.chars().count() < 3 { + return; + } + for &allow in WHITELIST { + if interned_name == allow { + return; + } + if interned_name.len() <= allow.len() { + continue; + } + // allow_* + let allow_start = allow.chars().chain(Some('_')); + if interned_name.chars().zip(allow_start).all(|(l, r)| l == r) { + return; + } + // *_allow + let allow_end = Some('_').into_iter().chain(allow.chars()); + if interned_name.chars().rev().zip(allow_end.rev()).all(|(l, r)| l == r) { + return; + } + } + for &(ref existing_name, sp) in &self.0.names { + let dist = levenshtein(&interned_name, &existing_name); + // equality is caught by shadow lints + if dist == 0 { + continue; + } + // if they differ enough it's all good + if dist > self.0.limit { + continue; + } + // are we doing stuff like `for item in items`? + if interned_name.starts_with(&**existing_name) || + existing_name.starts_with(&*interned_name) || + interned_name.ends_with(&**existing_name) || + existing_name.ends_with(&*interned_name) { + continue; + } + if dist == 1 { + // are we doing stuff like a_bar, b_bar, c_bar? + if interned_name.chars().next() != existing_name.chars().next() && interned_name.chars().nth(1) == Some('_') { + continue; + } + // are we doing stuff like foo_x, foo_y, foo_z? + if interned_name.chars().rev().next() != existing_name.chars().rev().next() && interned_name.chars().rev().nth(1) == Some('_') { + continue; + } + } + span_note_and_lint(self.0.cx, SIMILAR_NAMES, span, "binding's name is too similar to existing binding", sp, "existing binding defined here"); + return; + } + self.0.names.push((interned_name, span)); + } +} + +impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { + fn visit_local(&mut self, local: &'v Local) { + SimilarNamesNameVisitor(self).visit_local(local) + } + fn visit_block(&mut self, blk: &'v Block) { + // ensure scoping rules work + let n = self.names.len(); + visit::walk_block(self, blk); + self.names.truncate(n); + } + fn visit_arm(&mut self, arm: &'v Arm) { + let n = self.names.len(); + // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier + SimilarNamesNameVisitor(self).visit_pat(&arm.pats[0]); + self.names.truncate(n); + } + fn visit_item(&mut self, _: &'v Item) { + // do nothing + } +} + +impl EarlyLintPass for SimilarNames { + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, blk: &Block, _: Span, _: NodeId) { + let mut visitor = SimilarNamesLocalVisitor { + names: Vec::new(), + cx: cx, + limit: self.0, + }; + // initialize with function arguments + for arg in &decl.inputs { + visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat); + } + // walk all other bindings + visit::walk_block(&mut visitor, blk); + } +} diff --git a/src/types.rs b/src/types.rs index c5acbb41ea1..1dc1f55b773 100644 --- a/src/types.rs +++ b/src/types.rs @@ -638,7 +638,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs Lt, Le, }; - let (rel, lhs2, rhs2) = match op { + let (rel, normalized_lhs, normalized_rhs) = match op { BiLt => (Rel::Lt, lhs, rhs), BiLe => (Rel::Le, lhs, rhs), BiGt => (Rel::Lt, rhs, lhs), @@ -646,8 +646,8 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs _ => return None, }; - let lx = detect_extreme_expr(cx, lhs2); - let rx = detect_extreme_expr(cx, rhs2); + let lx = detect_extreme_expr(cx, normalized_lhs); + let rx = detect_extreme_expr(cx, normalized_rhs); Some(match rel { Rel::Lt => { diff --git a/src/utils/hir.rs b/src/utils/hir.rs index b4b786f9743..bc7bc358a9c 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -67,24 +67,24 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } match (&left.node, &right.node) { - (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => lmut == rmut && self.eq_expr(le, re), + (&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.name.as_str() == r.node.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(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { - lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) + (&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) } (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), - (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { - !self.ignore_fn && self.eq_expr(lfun, rfun) && self.eq_exprs(largs, rargs) + (&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)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt), - (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { - lfident.node == rfident.node && self.eq_expr(lfexp, rfexp) + (&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)) => { @@ -101,25 +101,25 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r)) }) } - (&ExprMethodCall(ref lname, ref ltys, ref largs), - &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { + (&ExprMethodCall(ref l_name, ref l_tys, ref l_args), + &ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => { // TODO: tys - !self.ignore_fn && lname.node == rname.node && ltys.is_empty() && rtys.is_empty() && - self.eq_exprs(largs, rargs) + !self.ignore_fn && l_name.node == r_name.node && l_tys.is_empty() && r_tys.is_empty() && + 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 lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { - both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath) + (&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) } - (&ExprStruct(ref lpath, ref lf, ref lo), &ExprStruct(ref rpath, ref rf, ref ro)) => { - self.eq_path(lpath, rpath) && + (&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)) && over(lf, rf, |l, r| self.eq_field(l, r)) } - (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup), + (&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(lop, ref le), &ExprUnary(rop, ref re)) => lop == rop && self.eq_expr(le, re), + (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), (&ExprVec(ref l), &ExprVec(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.name.as_str() == r.name.as_str()) @@ -179,16 +179,16 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { match (&left.node, &right.node) { - (&TyVec(ref lvec), &TyVec(ref rvec)) => self.eq_ty(lvec, rvec), + (&TyVec(ref l_vec), &TyVec(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(ref rt, ref rl)) => { self.eq_ty(lt, rt) && self.eq_expr(ll, rl) } - (&TyPtr(ref lmut), &TyPtr(ref rmut)) => lmut.mutbl == rmut.mutbl && self.eq_ty(&*lmut.ty, &*rmut.ty), - (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) => { - lrmut.mutbl == rrmut.mutbl && self.eq_ty(&*lrmut.ty, &*rrmut.ty) + (&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 lpath), &TyPath(ref rq, ref rpath)) => { - both(lq, rq, |l, r| self.eq_qself(l, r)) && self.eq_path(lpath, rpath) + (&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) } (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyInfer, &TyInfer) => true, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2934f1c4fba..de303a35f17 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -102,8 +102,8 @@ macro_rules! if_let_chain { /// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one /// isn't). -pub fn differing_macro_contexts(sp1: Span, sp2: Span) -> bool { - sp1.expn_id != sp2.expn_id +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { + rhs.expn_id != lhs.expn_id } /// Returns true if this `expn_info` was expanded by any macro. pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { diff --git a/tests/compile-fail/approx_const.rs b/tests/compile-fail/approx_const.rs index 148746bfa94..3660fb41919 100644 --- a/tests/compile-fail/approx_const.rs +++ b/tests/compile-fail/approx_const.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(approx_constant)] -#[allow(unused, shadow_unrelated)] +#[allow(unused, shadow_unrelated, similar_names)] fn main() { let my_e = 2.7182; //~ERROR approximate value of `f{32, 64}::E` found let almost_e = 2.718; //~ERROR approximate value of `f{32, 64}::E` found diff --git a/tests/compile-fail/drop_ref.rs b/tests/compile-fail/drop_ref.rs index 3e4c0a9d8ec..8454a471513 100644 --- a/tests/compile-fail/drop_ref.rs +++ b/tests/compile-fail/drop_ref.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(drop_ref)] -#![allow(toplevel_ref_arg)] +#![allow(toplevel_ref_arg, similar_names)] use std::mem::drop; diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index bbdf9d8f1b5..b111439ba51 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -88,7 +88,7 @@ impl Unrelated { #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] -#[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity)] +#[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity, similar_names)] fn main() { const MAX_LEN: usize = 42; diff --git a/tests/compile-fail/len_zero.rs b/tests/compile-fail/len_zero.rs index 5168f80b856..4fd0203b912 100644 --- a/tests/compile-fail/len_zero.rs +++ b/tests/compile-fail/len_zero.rs @@ -92,38 +92,38 @@ fn main() { println!("Nor should this!"); } - let hie = HasIsEmpty; - if hie.len() == 0 { + let has_is_empty = HasIsEmpty; + if has_is_empty.len() == 0 { //~^ERROR length comparison to zero //~|HELP consider using `is_empty` - //~|SUGGESTION hie.is_empty() + //~|SUGGESTION has_is_empty.is_empty() println!("Or this!"); } - if hie.len() != 0 { + if has_is_empty.len() != 0 { //~^ERROR length comparison to zero //~|HELP consider using `is_empty` - //~|SUGGESTION !hie.is_empty() + //~|SUGGESTION !has_is_empty.is_empty() println!("Or this!"); } - if hie.len() > 0 { + if has_is_empty.len() > 0 { //~^ERROR length comparison to zero //~|HELP consider using `is_empty` - //~|SUGGESTION !hie.is_empty() + //~|SUGGESTION !has_is_empty.is_empty() println!("Or this!"); } - assert!(!hie.is_empty()); + assert!(!has_is_empty.is_empty()); - let wie : &WithIsEmpty = &Wither; - if wie.len() == 0 { + let with_is_empty: &WithIsEmpty = &Wither; + if with_is_empty.len() == 0 { //~^ERROR length comparison to zero //~|HELP consider using `is_empty` - //~|SUGGESTION wie.is_empty() + //~|SUGGESTION with_is_empty.is_empty() println!("Or this!"); } - assert!(!wie.is_empty()); + assert!(!with_is_empty.is_empty()); - let hwie = HasWrongIsEmpty; - if hwie.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty() + let has_wrong_is_empty = HasWrongIsEmpty; + if has_wrong_is_empty.len() == 0 { //no error as HasWrongIsEmpty does not have .is_empty() println!("Or this!"); } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 344016a3b90..b1a8f6cf776 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -286,6 +286,7 @@ fn or_fun_call() { //~|SUGGESTION btree.entry(42).or_insert_with(String::new); } +#[allow(similar_names)] fn main() { use std::io; diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs new file mode 100644 index 00000000000..a9a06f4234f --- /dev/null +++ b/tests/compile-fail/non_expressive_names.rs @@ -0,0 +1,37 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy)] +#![allow(unused)] + +fn main() { + let specter: i32; + let spectre: i32; + + let apple: i32; //~ NOTE: existing binding defined here + let bpple: i32; //~ ERROR: name is too similar + let cpple: i32; //~ ERROR: name is too similar + + let a_bar: i32; + let b_bar: i32; + let c_bar: i32; + + let foo_x: i32; + let foo_y: i32; + + let rhs: i32; + let lhs: i32; + + let bla_rhs: i32; + let bla_lhs: i32; + + let blubrhs: i32; //~ NOTE: existing binding defined here + let blublhs: i32; //~ ERROR: name is too similar + + let blubx: i32; //~ NOTE: existing binding defined here + let bluby: i32; //~ ERROR: name is too similar + + let cake: i32; //~ NOTE: existing binding defined here + let caked: i32; //~ NOTE: existing binding defined here + let cakes: i32; //~ ERROR: name is too similar + let coke: i32; //~ ERROR: name is too similar +} -- cgit 1.4.1-3-g733a5 From 5373ffdeb85d55b39671b31fc15a8183d86ff662 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 1 Mar 2016 10:34:45 +0100 Subject: suggest inserting underscores for simple cases --- src/non_expressive_names.rs | 30 ++++++++++++++++++++++++------ tests/compile-fail/non_expressive_names.rs | 4 ++-- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 944dcaeb006..fc8bb69c5bc 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -3,7 +3,7 @@ use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ast::*; use syntax::visit::{self, FnKind}; -use utils::{span_note_and_lint, in_macro}; +use utils::{span_lint_and_then, in_macro}; use strsim::levenshtein; /// **What it does:** This lint warns about names that are very similar and thus confusing @@ -95,17 +95,35 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { existing_name.ends_with(&*interned_name) { continue; } + let mut split_at = None; if dist == 1 { // are we doing stuff like a_bar, b_bar, c_bar? - if interned_name.chars().next() != existing_name.chars().next() && interned_name.chars().nth(1) == Some('_') { - continue; + if interned_name.chars().next() != existing_name.chars().next() { + if interned_name.chars().nth(1) == Some('_') { + continue; + } + split_at = interned_name.chars().next().map(|c| c.len_utf8()); } // are we doing stuff like foo_x, foo_y, foo_z? - if interned_name.chars().rev().next() != existing_name.chars().rev().next() && interned_name.chars().rev().nth(1) == Some('_') { - continue; + if interned_name.chars().rev().next() != existing_name.chars().rev().next() { + if interned_name.chars().rev().nth(1) == Some('_') { + continue; + } + split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); } } - span_note_and_lint(self.0.cx, SIMILAR_NAMES, span, "binding's name is too similar to existing binding", sp, "existing binding defined here"); + span_lint_and_then(self.0.cx, + SIMILAR_NAMES, + span, + "binding's name is too similar to existing binding", + |diag| { + diag.span_note(sp, "existing binding defined here"); + if let Some(split) = split_at { + diag.span_help(span, &format!("separate the discriminating character by an underscore like: `{}_{}`", + &interned_name[..split], + &interned_name[split..])); + } + }); return; } self.0.names.push((interned_name, span)); diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index a9a06f4234f..35dba1a82ca 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -29,9 +29,9 @@ fn main() { let blubx: i32; //~ NOTE: existing binding defined here let bluby: i32; //~ ERROR: name is too similar + //~| HELP: separate the discriminating character by an underscore like: `blub_y` let cake: i32; //~ NOTE: existing binding defined here - let caked: i32; //~ NOTE: existing binding defined here - let cakes: i32; //~ ERROR: name is too similar + let cakes: i32; let coke: i32; //~ ERROR: name is too similar } -- cgit 1.4.1-3-g733a5 From 463897fd399482bd99fa80871269139f13d740c8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 1 Mar 2016 13:05:39 +0100 Subject: lint on too many single character bindings --- README.md | 1 + src/lib.rs | 6 ++- src/non_expressive_names.rs | 66 +++++++++++++++++++++++++----- tests/compile-fail/eta.rs | 2 +- tests/compile-fail/for_loop.rs | 1 + tests/compile-fail/non_expressive_names.rs | 27 ++++++++++++ 6 files changed, 91 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 2ee4dfc5e6c..65fc097af71 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ name [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque [manual_swap](https://github.com/Manishearth/rust-clippy/wiki#manual_swap) | warn | manual swap +[many_single_char_names](https://github.com/Manishearth/rust-clippy/wiki#many_single_char_names) | warn | too many single character bindings [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) [map_entry](https://github.com/Manishearth/rust-clippy/wiki#map_entry) | warn | use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap` [match_bool](https://github.com/Manishearth/rust-clippy/wiki#match_bool) | warn | a match on boolean expression; recommends `if..else` block instead diff --git a/src/lib.rs b/src/lib.rs index ef6b1f3a2b9..82383e2b7a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -204,7 +204,10 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); - reg.register_early_lint_pass(box non_expressive_names::SimilarNames(1)); + reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { + similarity_threshold: 1, + max_single_char_names: 5, + }); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); reg.register_late_lint_pass(box regex::RegexPass::default()); @@ -331,6 +334,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, + non_expressive_names::MANY_SINGLE_CHAR_NAMES, non_expressive_names::SIMILAR_NAMES, open_options::NONSENSICAL_OPEN_OPTIONS, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index fc8bb69c5bc..7f2fc618ed6 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -3,7 +3,7 @@ use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ast::*; use syntax::visit::{self, FnKind}; -use utils::{span_lint_and_then, in_macro}; +use utils::{span_lint_and_then, in_macro, span_lint}; use strsim::levenshtein; /// **What it does:** This lint warns about names that are very similar and thus confusing @@ -19,18 +19,35 @@ declare_lint! { "similarly named items and bindings" } -pub struct SimilarNames(pub usize); +/// **What it does:** This lint warns about having too many variables whose name consists of a single character +/// +/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name. +/// +/// **Known problems:** None? +/// +/// **Example:** let (a, b, c, d, e, f, g) = (...); +declare_lint! { + pub MANY_SINGLE_CHAR_NAMES, + Warn, + "too many single character bindings" +} + +pub struct NonExpressiveNames { + pub similarity_threshold: usize, + pub max_single_char_names: usize, +} -impl LintPass for SimilarNames { +impl LintPass for NonExpressiveNames { fn get_lints(&self) -> LintArray { - lint_array!(SIMILAR_NAMES) + lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES) } } struct SimilarNamesLocalVisitor<'a, 'b: 'a> { names: Vec<(InternedString, Span)>, cx: &'a EarlyContext<'b>, - limit: usize, + lint: &'a NonExpressiveNames, + single_char_names: Vec<char>, } const WHITELIST: &'static [&'static str] = &[ @@ -57,7 +74,15 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { if interned_name.chars().any(char::is_uppercase) { return; } - if interned_name.chars().count() < 3 { + let count = interned_name.chars().count(); + if count < 3 { + if count == 1 { + let c = interned_name.chars().next().expect("already checked"); + // make sure we ignore shadowing + if !self.0.single_char_names.contains(&c) { + self.0.single_char_names.push(c); + } + } return; } for &allow in WHITELIST { @@ -85,7 +110,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { continue; } // if they differ enough it's all good - if dist > self.0.limit { + if dist > self.0.lint.similarity_threshold { continue; } // are we doing stuff like `for item in items`? @@ -119,7 +144,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { |diag| { diag.span_note(sp, "existing binding defined here"); if let Some(split) = split_at { - diag.span_help(span, &format!("separate the discriminating character by an underscore like: `{}_{}`", + diag.span_help(span, &format!("separate the discriminating character \ + by an underscore like: `{}_{}`", &interned_name[..split], &interned_name[split..])); } @@ -130,6 +156,19 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } } +impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { + fn check_single_char_count(&self, span: Span) { + if self.single_char_names.len() < self.lint.max_single_char_names { + return; + } + span_lint(self.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("scope contains {} bindings whose name are just one char", + self.single_char_names.len())); + } +} + impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { fn visit_local(&mut self, local: &'v Local) { SimilarNamesNameVisitor(self).visit_local(local) @@ -137,26 +176,33 @@ impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { fn visit_block(&mut self, blk: &'v Block) { // ensure scoping rules work let n = self.names.len(); + let single_char_count = self.single_char_names.len(); visit::walk_block(self, blk); self.names.truncate(n); + self.check_single_char_count(blk.span); + self.single_char_names.truncate(single_char_count); } fn visit_arm(&mut self, arm: &'v Arm) { let n = self.names.len(); + let single_char_count = self.single_char_names.len(); // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier SimilarNamesNameVisitor(self).visit_pat(&arm.pats[0]); self.names.truncate(n); + self.check_single_char_count(arm.body.span); + self.single_char_names.truncate(single_char_count); } fn visit_item(&mut self, _: &'v Item) { // do nothing } } -impl EarlyLintPass for SimilarNames { +impl EarlyLintPass for NonExpressiveNames { fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, blk: &Block, _: Span, _: NodeId) { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), cx: cx, - limit: self.0, + lint: &self, + single_char_names: Vec::new(), }; // initialize with function arguments for arg in &decl.inputs { diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index 0e72efe654e..3fd089bf588 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -1,6 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unknown_lints, unused, no_effect, redundant_closure_call)] +#![allow(unknown_lints, unused, no_effect, redundant_closure_call, many_single_char_names)] #![deny(redundant_closure)] fn main() { diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index b111439ba51..064f66537eb 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -89,6 +89,7 @@ impl Unrelated { #[deny(needless_range_loop, explicit_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(unused_collect)] #[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity, similar_names)] +#[allow(many_single_char_names)] fn main() { const MAX_LEN: usize = 42; diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index 35dba1a82ca..9c75b07356e 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -35,3 +35,30 @@ fn main() { let cakes: i32; let coke: i32; //~ ERROR: name is too similar } + + +fn bla() { + let a: i32; + let (b, c, d): (i32, i64, i16); + { + { + let cdefg: i32; + let blar: i32; + } + { //~ ERROR: scope contains 5 bindings whose name are just one char + let e: i32; + } + { //~ ERROR: scope contains 6 bindings whose name are just one char + let e: i32; + let f: i32; + } + match 5 { + 1 => println!(""), + e => panic!(), //~ ERROR: scope contains 5 bindings whose name are just one char + } + match 5 { + 1 => println!(""), + _ => panic!(), + } + } +} -- cgit 1.4.1-3-g733a5 From 077481053cb28050d7c50e7db93d22eb332181cb Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 8 Mar 2016 14:36:21 +0100 Subject: refactoring and bugfix --- README.md | 2 +- src/non_expressive_names.rs | 64 +++++++++++++----------- tests/compile-fail/non_expressive_names.rs | 44 +++++++++++++--- tests/compile-fail/overflow_check_conditional.rs | 1 + 4 files changed, 74 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 65fc097af71..57dedbdb39e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 136 lints included in this crate: +There are 138 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 7f2fc618ed6..f8f2c4fb9a6 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -76,13 +76,23 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } let count = interned_name.chars().count(); if count < 3 { - if count == 1 { - let c = interned_name.chars().next().expect("already checked"); - // make sure we ignore shadowing - if !self.0.single_char_names.contains(&c) { - self.0.single_char_names.push(c); - } + if count != 1 { + return; + } + let c = interned_name.chars().next().expect("already checked"); + // make sure we ignore shadowing + if self.0.single_char_names.contains(&c) { + return; + } + self.0.single_char_names.push(c); + if self.0.single_char_names.len() < self.0.lint.max_single_char_names { + return; } + span_lint(self.0.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("{}th binding whose name is just one char", + self.0.single_char_names.len())); return; } for &allow in WHITELIST { @@ -157,39 +167,33 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { - fn check_single_char_count(&self, span: Span) { - if self.single_char_names.len() < self.lint.max_single_char_names { - return; - } - span_lint(self.cx, - MANY_SINGLE_CHAR_NAMES, - span, - &format!("scope contains {} bindings whose name are just one char", - self.single_char_names.len())); + /// ensure scoping rules work + fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) { + let n = self.names.len(); + let single_char_count = self.single_char_names.len(); + f(self); + self.names.truncate(n); + self.single_char_names.truncate(single_char_count); } } impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { fn visit_local(&mut self, local: &'v Local) { - SimilarNamesNameVisitor(self).visit_local(local) + if let Some(ref init) = local.init { + self.apply(|this| visit::walk_expr(this, &**init)); + } + // add the pattern after the expression because the bindings aren't available yet in the init expression + SimilarNamesNameVisitor(self).visit_pat(&*local.pat); } fn visit_block(&mut self, blk: &'v Block) { - // ensure scoping rules work - let n = self.names.len(); - let single_char_count = self.single_char_names.len(); - visit::walk_block(self, blk); - self.names.truncate(n); - self.check_single_char_count(blk.span); - self.single_char_names.truncate(single_char_count); + self.apply(|this| visit::walk_block(this, blk)); } fn visit_arm(&mut self, arm: &'v Arm) { - let n = self.names.len(); - let single_char_count = self.single_char_names.len(); - // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier - SimilarNamesNameVisitor(self).visit_pat(&arm.pats[0]); - self.names.truncate(n); - self.check_single_char_count(arm.body.span); - self.single_char_names.truncate(single_char_count); + self.apply(|this| { + // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier + SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); + this.apply(|this| visit::walk_expr(this, &arm.body)); + }); } fn visit_item(&mut self, _: &'v Item) { // do nothing diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index 9c75b07356e..2e3c60cf66a 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -34,8 +34,40 @@ fn main() { let cake: i32; //~ NOTE: existing binding defined here let cakes: i32; let coke: i32; //~ ERROR: name is too similar + + match 5 { + cheese @ 1 => {}, + rabbit => panic!(), + } + let cheese: i32; + match (42, 43) { + (cheese1, 1) => {}, + (cheese2, 2) => panic!(), + _ => println!(""), + } } +#[derive(Clone, Debug)] +enum MaybeInst { + Split, + Split1(usize), + Split2(usize), +} + +struct InstSplit { + uiae: usize, +} + +impl MaybeInst { + fn fill(&mut self) { + let filled = match *self { + MaybeInst::Split1(goto1) => panic!(1), + MaybeInst::Split2(goto2) => panic!(2), + _ => unimplemented!(), + }; + unimplemented!() + } +} fn bla() { let a: i32; @@ -45,16 +77,16 @@ fn bla() { let cdefg: i32; let blar: i32; } - { //~ ERROR: scope contains 5 bindings whose name are just one char - let e: i32; + { + let e: i32; //~ ERROR: 5th binding whose name is just one char } - { //~ ERROR: scope contains 6 bindings whose name are just one char - let e: i32; - let f: i32; + { + let e: i32; //~ ERROR: 5th binding whose name is just one char + let f: i32; //~ ERROR: 6th binding whose name is just one char } match 5 { 1 => println!(""), - e => panic!(), //~ ERROR: scope contains 5 bindings whose name are just one char + e => panic!(), //~ ERROR: 5th binding whose name is just one char } match 5 { 1 => println!(""), diff --git a/tests/compile-fail/overflow_check_conditional.rs b/tests/compile-fail/overflow_check_conditional.rs index db7b2792484..24310eb81da 100644 --- a/tests/compile-fail/overflow_check_conditional.rs +++ b/tests/compile-fail/overflow_check_conditional.rs @@ -1,6 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(many_single_char_names)] #![deny(overflow_check_conditional)] fn main() { -- cgit 1.4.1-3-g733a5 From aa1ecb6fce5b6e44f5a7e8c8ca2e15391dd64489 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 10:18:09 +0100 Subject: fix and rebase --- src/non_expressive_names.rs | 13 ++++++------- tests/compile-fail/blacklisted_name.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index f8f2c4fb9a6..294af274beb 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -85,14 +85,13 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { return; } self.0.single_char_names.push(c); - if self.0.single_char_names.len() < self.0.lint.max_single_char_names { - return; + if self.0.single_char_names.len() >= self.0.lint.max_single_char_names { + span_lint(self.0.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("{}th binding whose name is just one char", + self.0.single_char_names.len())); } - span_lint(self.0.cx, - MANY_SINGLE_CHAR_NAMES, - span, - &format!("{}th binding whose name is just one char", - self.0.single_char_names.len())); return; } for &allow in WHITELIST { diff --git a/tests/compile-fail/blacklisted_name.rs b/tests/compile-fail/blacklisted_name.rs index efcb810a30e..1afcd94a0b1 100755 --- a/tests/compile-fail/blacklisted_name.rs +++ b/tests/compile-fail/blacklisted_name.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] #![allow(single_match)] -#![allow(unused_variables)] +#![allow(unused_variables, similar_names)] #![deny(blacklisted_name)] fn test(foo: ()) {} //~ERROR use of a blacklisted/placeholder name `foo` -- cgit 1.4.1-3-g733a5 From 24cdb14d5a99e3a12250f449b16d05cdd4a7d53c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 14:34:47 +0100 Subject: refactor for speed --- Cargo.toml | 1 - src/lib.rs | 4 - src/non_expressive_names.rs | 178 +++++++++++++++++++---------- tests/compile-fail/non_expressive_names.rs | 5 + 4 files changed, 125 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 844408df23c..dd675981fae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ regex_macros = { version = "0.1.33", optional = true } semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" -strsim = "0.4.0" [dev-dependencies] compiletest_rs = "0.1.0" diff --git a/src/lib.rs b/src/lib.rs index 82383e2b7a9..a42db8d1fcb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,9 +31,6 @@ extern crate unicode_normalization; // for semver check in attrs.rs extern crate semver; -// for levensthein distance -extern crate strsim; - // for regex checking extern crate regex_syntax; @@ -205,7 +202,6 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { - similarity_threshold: 1, max_single_char_names: 5, }); reg.register_late_lint_pass(box drop_ref::DropRefPass); diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 294af274beb..0c7c97ce474 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -4,7 +4,6 @@ use syntax::parse::token::InternedString; use syntax::ast::*; use syntax::visit::{self, FnKind}; use utils::{span_lint_and_then, in_macro, span_lint}; -use strsim::levenshtein; /// **What it does:** This lint warns about names that are very similar and thus confusing /// @@ -33,7 +32,6 @@ declare_lint! { } pub struct NonExpressiveNames { - pub similarity_threshold: usize, pub max_single_char_names: usize, } @@ -44,7 +42,7 @@ impl LintPass for NonExpressiveNames { } struct SimilarNamesLocalVisitor<'a, 'b: 'a> { - names: Vec<(InternedString, Span)>, + names: Vec<(InternedString, Span, usize)>, cx: &'a EarlyContext<'b>, lint: &'a NonExpressiveNames, single_char_names: Vec<char>, @@ -65,7 +63,43 @@ impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> } } +fn whitelisted(interned_name: &str) -> bool { + for &allow in WHITELIST { + if interned_name == allow { + return true; + } + if interned_name.len() <= allow.len() { + continue; + } + // allow_* + let allow_start = allow.chars().chain(Some('_')); + if interned_name.chars().zip(allow_start).all(|(l, r)| l == r) { + return true; + } + // *_allow + let allow_end = Some('_').into_iter().chain(allow.chars()); + if interned_name.chars().rev().zip(allow_end.rev()).all(|(l, r)| l == r) { + return true; + } + } + false +} + impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { + fn check_short_name(&mut self, c: char, span: Span) { + // make sure we ignore shadowing + if self.0.single_char_names.contains(&c) { + return; + } + self.0.single_char_names.push(c); + if self.0.single_char_names.len() >= self.0.lint.max_single_char_names { + span_lint(self.0.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("{}th binding whose name is just one char", + self.0.single_char_names.len())); + } + } fn check_name(&mut self, span: Span, name: Name) { if in_macro(self.0.cx, span) { return; @@ -80,67 +114,68 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { return; } let c = interned_name.chars().next().expect("already checked"); - // make sure we ignore shadowing - if self.0.single_char_names.contains(&c) { - return; - } - self.0.single_char_names.push(c); - if self.0.single_char_names.len() >= self.0.lint.max_single_char_names { - span_lint(self.0.cx, - MANY_SINGLE_CHAR_NAMES, - span, - &format!("{}th binding whose name is just one char", - self.0.single_char_names.len())); - } + self.check_short_name(c, span); return; } - for &allow in WHITELIST { - if interned_name == allow { - return; - } - if interned_name.len() <= allow.len() { - continue; - } - // allow_* - let allow_start = allow.chars().chain(Some('_')); - if interned_name.chars().zip(allow_start).all(|(l, r)| l == r) { - return; - } - // *_allow - let allow_end = Some('_').into_iter().chain(allow.chars()); - if interned_name.chars().rev().zip(allow_end.rev()).all(|(l, r)| l == r) { - return; - } + if whitelisted(&interned_name) { + return; } - for &(ref existing_name, sp) in &self.0.names { - let dist = levenshtein(&interned_name, &existing_name); - // equality is caught by shadow lints - if dist == 0 { - continue; - } - // if they differ enough it's all good - if dist > self.0.lint.similarity_threshold { - continue; - } - // are we doing stuff like `for item in items`? - if interned_name.starts_with(&**existing_name) || - existing_name.starts_with(&*interned_name) || - interned_name.ends_with(&**existing_name) || - existing_name.ends_with(&*interned_name) { - continue; - } + for &(ref existing_name, sp, existing_len) in &self.0.names { let mut split_at = None; - if dist == 1 { - // are we doing stuff like a_bar, b_bar, c_bar? - if interned_name.chars().next() != existing_name.chars().next() { - if interned_name.chars().nth(1) == Some('_') { + if existing_len > count { + if existing_len - count != 1 { + continue; + } + if levenstein_not_1(&interned_name, &existing_name) { + continue; + } + } else if existing_len < count { + if count - existing_len != 1 { + continue; + } + if levenstein_not_1(&existing_name, &interned_name) { + continue; + } + } else { + let mut interned_chars = interned_name.chars(); + let mut existing_chars = existing_name.chars(); + + if interned_chars.next() != existing_chars.next() { + let i = interned_chars.next().expect("we know we have more than 1 char"); + let e = existing_chars.next().expect("we know we have more than 1 char"); + if i == e { + if i == '_' { + // allowed similarity x_foo, y_foo + // or too many chars differ (x_foo, y_boo) + continue; + } else if interned_chars.ne(existing_chars) { + // too many chars differ + continue + } + } else { + // too many chars differ continue; } split_at = interned_name.chars().next().map(|c| c.len_utf8()); - } - // are we doing stuff like foo_x, foo_y, foo_z? - if interned_name.chars().rev().next() != existing_name.chars().rev().next() { - if interned_name.chars().rev().nth(1) == Some('_') { + } else if interned_chars.next_back() == existing_chars.next_back() { + if interned_chars.zip(existing_chars).filter(|&(i, e)| i != e).count() != 1 { + // too many chars differ, or none differ (aka shadowing) + continue; + } + } else { + let i = interned_chars.next_back().expect("we know we have more than 2 chars"); + let e = existing_chars.next_back().expect("we know we have more than 2 chars"); + if i == e { + if i == '_' { + // allowed similarity foo_x, foo_x + // or too many chars differ (foo_x, boo_x) + continue; + } else if interned_chars.ne(existing_chars) { + // too many chars differ + continue + } + } else { + // too many chars differ continue; } split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); @@ -161,7 +196,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { }); return; } - self.0.names.push((interned_name, span)); + self.0.names.push((interned_name, span, count)); } } @@ -215,3 +250,30 @@ impl EarlyLintPass for NonExpressiveNames { visit::walk_block(&mut visitor, blk); } } + +/// precondition: a_name.chars().count() < b_name.chars().count() +fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { + debug_assert!(a_name.chars().count() < b_name.chars().count()); + let mut a_chars = a_name.chars(); + let mut b_chars = b_name.chars(); + while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) { + if a == b { + continue; + } + if let Some(b2) = b_chars.next() { + // check if there's just one character inserted + if a == b2 && a_chars.eq(b_chars) { + return false; + } else { + // two charaters don't match + return true; + } + } else { + // tuple + // ntuple + return true; + } + } + // for item in items + true +} diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index 2e3c60cf66a..c374c3c4331 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -15,6 +15,11 @@ fn main() { let b_bar: i32; let c_bar: i32; + let items = [5]; + for item in &items { + loop {} + } + let foo_x: i32; let foo_y: i32; -- cgit 1.4.1-3-g733a5 From ea1c2406cc2711ac19bc651b665ab081cfac987f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 14:56:44 +0100 Subject: make single char names threshold configurable --- src/lib.rs | 2 +- src/non_expressive_names.rs | 4 ++-- src/utils/conf.rs | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a42db8d1fcb..8bbaff65361 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,7 +202,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box print::PrintLint); reg.register_late_lint_pass(box vec::UselessVec); reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { - max_single_char_names: 5, + max_single_char_names: conf.max_single_char_names, }); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 0c7c97ce474..9ad91b421dd 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -32,7 +32,7 @@ declare_lint! { } pub struct NonExpressiveNames { - pub max_single_char_names: usize, + pub max_single_char_names: u64, } impl LintPass for NonExpressiveNames { @@ -92,7 +92,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { return; } self.0.single_char_names.push(c); - if self.0.single_char_names.len() >= self.0.lint.max_single_char_names { + if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names { span_lint(self.0.cx, MANY_SINGLE_CHAR_NAMES, span, diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 6636e30ab38..2411e48997b 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -153,6 +153,8 @@ define_Conf! { ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64), /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have ("type-complexity-threshold", type_complexity_threshold, 250 => u64), + /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have + ("single-char-binding-names-threshold", max_single_char_names, 5 => u64), } /// Read the `toml` configuration file. The function will ignore “File not found” errors iif -- cgit 1.4.1-3-g733a5 From 9dc282e31db5c70ca9583152557ebbf87df8ee95 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 16:41:41 +0100 Subject: improve needless_bool to catch odd construct in non_expressive_names --- src/lib.rs | 1 + src/needless_bool.rs | 94 +++++++++++++++++++++---------------- src/non_expressive_names.rs | 7 +-- tests/compile-fail/needless_bool.rs | 26 ++++++++++ 4 files changed, 82 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8bbaff65361..f6179f4f993 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(rustc_private, collections)] #![feature(iter_arith)] #![feature(custom_attribute)] +#![feature(slice_patterns)] #![allow(indexing_slicing, shadow_reuse, unknown_lints)] // this only exists to allow the "dogfood" integration test to work diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 625f8b0ca78..58afc86b82c 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -47,44 +47,39 @@ impl LintPass for NeedlessBool { impl LateLintPass for NeedlessBool { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + use self::Expression::*; if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { + let reduce = |hint: &str, not| { + let pred_snip = snippet(cx, pred.span, ".."); + let hint = if pred_snip == ".." { + hint.into() + } else { + format!("`{}{}`", not, pred_snip) + }; + span_lint(cx, + NEEDLESS_BOOL, + e.span, + &format!("you can reduce this if-then-else expression to just {}", hint)); + }; match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (Some(true), Some(true)) => { + (RetBool(true), RetBool(true)) | + (Bool(true), Bool(true)) => { span_lint(cx, NEEDLESS_BOOL, e.span, "this if-then-else expression will always return true"); } - (Some(false), Some(false)) => { + (RetBool(false), RetBool(false)) | + (Bool(false), Bool(false)) => { span_lint(cx, NEEDLESS_BOOL, e.span, "this if-then-else expression will always return false"); } - (Some(true), Some(false)) => { - let pred_snip = snippet(cx, pred.span, ".."); - let hint = if pred_snip == ".." { - "its predicate".into() - } else { - format!("`{}`", pred_snip) - }; - span_lint(cx, - NEEDLESS_BOOL, - e.span, - &format!("you can reduce this if-then-else expression to just {}", hint)); - } - (Some(false), Some(true)) => { - let pred_snip = snippet(cx, pred.span, ".."); - let hint = if pred_snip == ".." { - "`!` and its predicate".into() - } else { - format!("`!{}`", pred_snip) - }; - span_lint(cx, - NEEDLESS_BOOL, - e.span, - &format!("you can reduce this if-then-else expression to just {}", hint)); - } + (RetBool(true), RetBool(false)) => reduce("its predicate", "return "), + (Bool(true), Bool(false)) => reduce("its predicate", ""), + (RetBool(false), RetBool(true)) => reduce("`!` and its predicate", "return !"), + (Bool(false), Bool(true)) => reduce("`!` and its predicate", "!"), _ => (), } } @@ -102,9 +97,10 @@ impl LintPass for BoolComparison { impl LateLintPass for BoolComparison { fn check_expr(&mut self, cx: &LateContext, e: &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)) { - (Some(true), None) => { + (Bool(true), Other) => { let hint = snippet(cx, right_side.span, "..").into_owned(); span_lint_and_then(cx, BOOL_COMPARISON, @@ -114,7 +110,7 @@ impl LateLintPass for BoolComparison { db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } - (None, Some(true)) => { + (Other, Bool(true)) => { let hint = snippet(cx, left_side.span, "..").into_owned(); span_lint_and_then(cx, BOOL_COMPARISON, @@ -124,7 +120,7 @@ impl LateLintPass for BoolComparison { db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } - (Some(false), None) => { + (Bool(false), Other) => { let hint = format!("!{}", snippet(cx, right_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, @@ -134,7 +130,7 @@ impl LateLintPass for BoolComparison { db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); } - (None, Some(false)) => { + (Other, Bool(false)) => { let hint = format!("!{}", snippet(cx, left_side.span, "..")); span_lint_and_then(cx, BOOL_COMPARISON, @@ -150,24 +146,42 @@ impl LateLintPass for BoolComparison { } } -fn fetch_bool_block(block: &Block) -> Option<bool> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|e| fetch_bool_expr(e)) - } else { - None +enum Expression { + Bool(bool), + RetBool(bool), + Other, +} + +fn fetch_bool_block(block: &Block) -> Expression { + match (&*block.stmts, block.expr.as_ref()) { + ([], Some(e)) => fetch_bool_expr(&**e), + ([ref e], None) => if let StmtSemi(ref e, _) = e.node { + if let ExprRet(_) = e.node { + fetch_bool_expr(&**e) + } else { + Expression::Other + } + } else { + Expression::Other + }, + _ => Expression::Other, } } -fn fetch_bool_expr(expr: &Expr) -> Option<bool> { +fn fetch_bool_expr(expr: &Expr) -> Expression { match expr.node { ExprBlock(ref block) => fetch_bool_block(block), ExprLit(ref lit_ptr) => { if let LitKind::Bool(value) = lit_ptr.node { - Some(value) + Expression::Bool(value) } else { - None + Expression::Other } - } - _ => None, + }, + ExprRet(Some(ref expr)) => match fetch_bool_expr(expr) { + Expression::Bool(value) => Expression::RetBool(value), + _ => Expression::Other, + }, + _ => Expression::Other, } } diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 9ad91b421dd..b7d2ac80a10 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -262,12 +262,7 @@ fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { } if let Some(b2) = b_chars.next() { // check if there's just one character inserted - if a == b2 && a_chars.eq(b_chars) { - return false; - } else { - // two charaters don't match - return true; - } + return !(a == b2 && a_chars.eq(b_chars)); } else { // tuple // ntuple diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index c2ad24bc4ee..eff2bdc9b28 100644 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -10,4 +10,30 @@ fn main() { if x { true } else { false }; //~ERROR you can reduce this if-then-else expression to just `x` if x { false } else { true }; //~ERROR you can reduce this if-then-else expression to just `!x` if x { x } else { false }; // would also be questionable, but we don't catch this yet + bool_ret(x); + bool_ret2(x); + bool_ret3(x); + bool_ret4(x); +} + +#[deny(needless_bool)] +#[allow(if_same_then_else)] +fn bool_ret(x: bool) -> bool { + if x { return true } else { return true }; //~ERROR this if-then-else expression will always return true +} + +#[deny(needless_bool)] +#[allow(if_same_then_else)] +fn bool_ret2(x: bool) -> bool { + if x { return false } else { return false }; //~ERROR this if-then-else expression will always return false +} + +#[deny(needless_bool)] +fn bool_ret3(x: bool) -> bool { + if x { return true } else { return false }; //~ERROR you can reduce this if-then-else expression to just `return x` +} + +#[deny(needless_bool)] +fn bool_ret4(x: bool) -> bool { + if x { return false } else { return true }; //~ERROR you can reduce this if-then-else expression to just `return !x` } -- cgit 1.4.1-3-g733a5 From 6a566a1009fefdbfe30e8475836f6b06fed81b3c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Mar 2016 17:13:10 +0100 Subject: use snippet_opt and span_suggestion --- src/needless_bool.rs | 20 ++++++++++---------- tests/compile-fail/needless_bool.rs | 20 ++++++++++++++++---- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 58afc86b82c..43e7cfddadd 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -6,7 +6,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::ast::LitKind; use syntax::codemap::Spanned; -use utils::{span_lint, span_lint_and_then, snippet}; +use utils::{span_lint, span_lint_and_then, snippet, snippet_opt}; /// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. /// @@ -50,16 +50,16 @@ impl LateLintPass for NeedlessBool { use self::Expression::*; if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { let reduce = |hint: &str, not| { - let pred_snip = snippet(cx, pred.span, ".."); - let hint = if pred_snip == ".." { - hint.into() - } else { - format!("`{}{}`", not, pred_snip) + let hint = match snippet_opt(cx, pred.span) { + Some(pred_snip) => format!("`{}{}`", not, pred_snip), + None => hint.into(), }; - span_lint(cx, - NEEDLESS_BOOL, - e.span, - &format!("you can reduce this if-then-else expression to just {}", hint)); + span_lint_and_then(cx, + NEEDLESS_BOOL, + e.span, + "this if-then-else expression returns a bool literal", |db| { + 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)) | diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index eff2bdc9b28..7f2d7754bda 100644 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -7,8 +7,14 @@ fn main() { let x = true; if x { true } else { true }; //~ERROR this if-then-else expression will always return true if x { false } else { false }; //~ERROR this if-then-else expression will always return false - if x { true } else { false }; //~ERROR you can reduce this if-then-else expression to just `x` - if x { false } else { true }; //~ERROR you can reduce this if-then-else expression to just `!x` + if x { true } else { false }; + //~^ ERROR this if-then-else expression returns a bool literal + //~| HELP you can reduce it to + //~| SUGGESTION `x` + if x { false } else { true }; + //~^ ERROR this if-then-else expression returns a bool literal + //~| HELP you can reduce it to + //~| SUGGESTION `!x` if x { x } else { false }; // would also be questionable, but we don't catch this yet bool_ret(x); bool_ret2(x); @@ -30,10 +36,16 @@ fn bool_ret2(x: bool) -> bool { #[deny(needless_bool)] fn bool_ret3(x: bool) -> bool { - if x { return true } else { return false }; //~ERROR you can reduce this if-then-else expression to just `return x` + if x { return true } else { return false }; + //~^ ERROR this if-then-else expression returns a bool literal + //~| HELP you can reduce it to + //~| SUGGESTION `return x` } #[deny(needless_bool)] fn bool_ret4(x: bool) -> bool { - if x { return false } else { return true }; //~ERROR you can reduce this if-then-else expression to just `return !x` + if x { return false } else { return true }; + //~^ ERROR this if-then-else expression returns a bool literal + //~| HELP you can reduce it to + //~| SUGGESTION `return !x` } -- cgit 1.4.1-3-g733a5 From ef721106840325a1113225489ca3be2735a00d38 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 18 Mar 2016 19:12:32 +0100 Subject: Fix `new_without_default` with lts and generics --- src/new_without_default.rs | 1 + src/utils/mod.rs | 1 + tests/compile-fail/new_without_default.rs | 31 +++++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/new_without_default.rs b/src/new_without_default.rs index d341afb4d92..461d1f5bebd 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -51,6 +51,7 @@ impl LateLintPass for NewWithoutDefault { let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; if_let_chain!{[ + self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics let Some(ret_ty) = return_ty(cx.tcx.node_id_to_type(id)), same_tys(cx, self_ty, ret_ty), let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2934f1c4fba..16174e434d4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -270,6 +270,7 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); + let ty = cx.tcx.erase_regions(&ty); let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any); let obligation = traits::predicate_for_trait_def(cx.tcx, traits::ObligationCause::dummy(), diff --git a/tests/compile-fail/new_without_default.rs b/tests/compile-fail/new_without_default.rs index cc033043bc5..30015f6c9e8 100755 --- a/tests/compile-fail/new_without_default.rs +++ b/tests/compile-fail/new_without_default.rs @@ -32,13 +32,36 @@ impl Params { fn new(_: u32) -> Self { Params } } -struct Generics<'a, T> { - foo: &'a bool, +struct GenericsOk<T> { bar: T, } -impl<'c, V> Generics<'c, V> { - fn new<'b>() -> Generics<'b, V> { unimplemented!() } //~ERROR: you should consider adding a `Default` implementation for +impl<U> Default for GenericsOk<U> { + fn default() -> Self { unimplemented!(); } +} + +impl<'c, V> GenericsOk<V> { + fn new() -> GenericsOk<V> { unimplemented!() } +} + +struct LtOk<'a> { + foo: &'a bool, +} + +impl<'b> Default for LtOk<'b> { + fn default() -> Self { unimplemented!(); } +} + +impl<'c> LtOk<'c> { + fn new() -> LtOk<'c> { unimplemented!() } +} + +struct LtKo<'a> { + foo: &'a bool, +} + +impl<'c> LtKo<'c> { + fn new() -> LtKo<'c> { unimplemented!() } //~ERROR: you should consider adding a `Default` implementation for } fn main() {} -- cgit 1.4.1-3-g733a5 From 7d3e6da3cba392e5c39fc37908bc0a635ca7c96d Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger <badboy@archlinux.us> Date: Sun, 20 Mar 2016 20:32:22 +0100 Subject: Fix typo in new_without_default docu --- src/new_without_default.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 461d1f5bebd..ff5c09e3911 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -9,7 +9,7 @@ use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, sa /// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` /// implementation. /// -/// **Why is this bad?** User might expect to be able to use `Default` is the type can be +/// **Why is this bad?** User might expect to be able to use `Default` as the type can be /// constructed without arguments. /// /// **Known problems:** Hopefully none. -- cgit 1.4.1-3-g733a5 From 6164eabc3c17ab5094c5962c44b4bf7473240b19 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 20 Mar 2016 21:24:18 +0100 Subject: fixed the build --- src/bit_mask.rs | 2 +- src/consts.rs | 2 +- src/utils/hir.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 02d428e834d..f96927f1548 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -270,7 +270,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { _ => None, } } - .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, None, 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/src/consts.rs b/src/consts.rs index 3e08f1b74ff..e6bda7df8de 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -290,7 +290,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } // 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, None) { + 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; diff --git a/src/utils/hir.rs b/src/utils/hir.rs index b4b786f9743..fd8dc046eb5 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -332,8 +332,8 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { self.hash_expr(a); self.hash_expr(i); } - ExprInlineAsm(_) => { - let c: fn(_) -> _ = ExprInlineAsm; + ExprInlineAsm(..) => { + let c: fn(_, _, _) -> _ = ExprInlineAsm; c.hash(&mut self.s); } ExprIf(ref cond, ref t, ref e) => { -- cgit 1.4.1-3-g733a5 From a7f662d8f291ebfdd5cbb46a9c96e28f49200d7f Mon Sep 17 00:00:00 2001 From: Jascha <Jascha-N@users.noreply.github.com> Date: Wed, 23 Mar 2016 16:11:24 +0100 Subject: Match attributes in FnKind patterns --- src/misc.rs | 2 +- src/new_without_default.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index c7aeb7f9a2f..66771e9a690 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -39,7 +39,7 @@ impl LintPass for TopLevelRefPass { impl LateLintPass for TopLevelRefPass { fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - if let FnKind::Closure = k { + if let FnKind::Closure(_) = k { // Does not apply to closures return; } diff --git a/src/new_without_default.rs b/src/new_without_default.rs index ff5c09e3911..d9b11cc49b6 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -46,7 +46,7 @@ impl LateLintPass for NewWithoutDefault { return; } - if let FnKind::Method(name, _, _) = kind { + if let FnKind::Method(name, _, _, _) = kind { if decl.inputs.is_empty() && name.as_str() == "new" { let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; -- cgit 1.4.1-3-g733a5 From 341b7d3f6b5c1b36d8fb3c12a808572b94ccae41 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet <vincent@wearewizards.io> Date: Thu, 24 Mar 2016 17:07:55 +0000 Subject: Update float_cmp message --- src/misc.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 66771e9a690..55439e6a78b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -167,8 +167,9 @@ impl LateLintPass for FloatCmp { span_lint(cx, FLOAT_CMP, expr.span, - &format!("{}-comparison of f32 or f64 detected. Consider changing this to `abs({} - {}) < \ - epsilon` for some suitable value of epsilon", + &format!("{}-comparison of f32 or f64 detected. Consider changing this to `({} - {}).abs() < \ + epsilon` for some suitable value of epsilon. \ + std::f32::EPSILON and std::f64::EPSILON are available.", binop_to_string(op), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); -- cgit 1.4.1-3-g733a5 From 15e55f5df5e13dd7867d86df6bc26c49b7d77944 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 24 Mar 2016 19:25:59 +0100 Subject: Deprecates 4 lints Namely STR_TO_STRING, STRING_TO_STRING, UNSTABLE_AS_SLICE and UNSTABLE_AS_MUT_SLICE. --- README.md | 6 +-- src/deprecated_lints.rs | 44 +++++++++++++++++++++ src/lib.rs | 13 ++++--- src/methods.rs | 53 +------------------------ src/needless_features.rs | 68 --------------------------------- tests/compile-fail/cmp_owned.rs | 1 - tests/compile-fail/methods.rs | 6 --- tests/compile-fail/needless_features.rs | 28 -------------- tests/run-pass/deprecated.rs | 12 ++++++ util/update_lints.py | 34 +++++++++++++++-- util/update_wiki.py | 21 ++++++++-- 11 files changed, 115 insertions(+), 171 deletions(-) create mode 100644 src/deprecated_lints.rs delete mode 100644 src/needless_features.rs delete mode 100644 tests/compile-fail/needless_features.rs create mode 100644 tests/run-pass/deprecated.rs (limited to 'src') diff --git a/README.md b/README.md index 57dedbdb39e..b3e6937604d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 138 lints included in this crate: +There are 134 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -124,11 +124,9 @@ name [single_char_pattern](https://github.com/Manishearth/rust-clippy/wiki#single_char_pattern) | warn | using a single-character str where a char could be used, e.g. `_.split("x")` [single_match](https://github.com/Manishearth/rust-clippy/wiki#single_match) | warn | a match statement with a single nontrivial arm (i.e, where the other arm is `_ => {}`) is used; recommends `if let` instead [single_match_else](https://github.com/Manishearth/rust-clippy/wiki#single_match_else) | allow | a match statement with a two arms where the second arm's pattern is a wildcard; recommends `if let` instead -[str_to_string](https://github.com/Manishearth/rust-clippy/wiki#str_to_string) | warn | using `to_string()` on a str, which should be `to_owned()` [string_add](https://github.com/Manishearth/rust-clippy/wiki#string_add) | allow | using `x + ..` where x is a `String`; suggests using `push_str()` instead [string_add_assign](https://github.com/Manishearth/rust-clippy/wiki#string_add_assign) | allow | using `x = x + ..` where x is a `String`; suggests using `push_str()` instead [string_lit_as_bytes](https://github.com/Manishearth/rust-clippy/wiki#string_lit_as_bytes) | warn | calling `as_bytes` on a string literal; suggests using a byte string literal instead -[string_to_string](https://github.com/Manishearth/rust-clippy/wiki#string_to_string) | warn | calling `String::to_string` which is inefficient [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` [suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries @@ -140,8 +138,6 @@ name [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference [unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` -[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729 -[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729 [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions diff --git a/src/deprecated_lints.rs b/src/deprecated_lints.rs new file mode 100644 index 00000000000..abdb6297b9e --- /dev/null +++ b/src/deprecated_lints.rs @@ -0,0 +1,44 @@ +macro_rules! declare_deprecated_lint { + (pub $name: ident, $_reason: expr) => { + declare_lint!(pub $name, Allow, "deprecated lint") + } +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good +/// stable alternatives. `Vec::as_slice` has now been stabilized. +declare_deprecated_lint! { + pub UNSTABLE_AS_SLICE, + "`Vec::as_slice` has been stabilized in 1.7" +} + + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good +/// stable alternatives. `Vec::as_mut_slice` has now been stabilized. +declare_deprecated_lint! { + pub UNSTABLE_AS_MUT_SLICE, + "`Vec::as_mut_slice` has been stabilized in 1.7" +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `.to_string()` method calls on values +/// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be +/// specialized to be as efficient as `to_owned`. +declare_deprecated_lint! { + pub STR_TO_STRING, + "using `str::to_string` is common even today and specialization will likely happen soon" +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `.to_string()` method calls on values +/// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be +/// specialized to be as efficient as `clone`. +declare_deprecated_lint! { + pub STRING_TO_STRING, + "using `string::to_string` is common even today and specialization will likely happen soon" +} diff --git a/src/lib.rs b/src/lib.rs index f6179f4f993..ffa66fd581b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,6 @@ pub mod mut_mut; pub mod mut_reference; pub mod mutex_atomic; pub mod needless_bool; -pub mod needless_features; pub mod needless_update; pub mod new_without_default; pub mod no_effect; @@ -141,6 +140,13 @@ pub fn plugin_registrar(reg: &mut 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"); + // end deprecated lints, do not remove this comment, it’s used in `update_lints` + reg.register_late_lint_pass(box types::TypePass); reg.register_late_lint_pass(box misc::TopLevelRefPass); reg.register_late_lint_pass(box misc::CmpNan); @@ -185,7 +191,6 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions); reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); - reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); @@ -308,8 +313,6 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, methods::SINGLE_CHAR_PATTERN, - methods::STR_TO_STRING, - methods::STRING_TO_STRING, methods::WRONG_SELF_CONVENTION, minmax::MIN_MAX, misc::CMP_NAN, @@ -326,8 +329,6 @@ pub fn plugin_registrar(reg: &mut Registry) { mutex_atomic::MUTEX_ATOMIC, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, - needless_features::UNSTABLE_AS_MUT_SLICE, - needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, diff --git a/src/methods.rs b/src/methods.rs index 6d33f31d45c..95bbdd441c9 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -6,13 +6,13 @@ use rustc::middle::subst::{Subst, TypeSpace}; use rustc::middle::ty; use rustc_front::hir::*; use std::borrow::Cow; -use std::{fmt, iter}; +use std::fmt; use syntax::codemap::Span; use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; -use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH, +use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; use utils::MethodArgs; @@ -45,31 +45,6 @@ declare_lint! { "using `Result.unwrap()`, which might be better handled" } -/// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. -/// -/// **Why is this bad?** This uses the whole formatting machinery just to clone a string. Using `.to_owned()` is lighter on resources. You can also consider using a [`Cow<'a, str>`](http://doc.rust-lang.org/std/borrow/enum.Cow.html) instead in some cases. -/// -/// **Known problems:** None -/// -/// **Example:** `s.to_string()` where `s: &str` -declare_lint! { - pub STR_TO_STRING, Warn, - "using `to_string()` on a str, which should be `to_owned()`" -} - -/// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. -/// -/// **Why is this bad?** This is an non-efficient way to clone a `String`, `.clone()` should be used -/// instead. `String` implements `ToString` mostly for generics. -/// -/// **Known problems:** None -/// -/// **Example:** `s.to_string()` where `s: String` -declare_lint! { - pub STRING_TO_STRING, Warn, - "calling `String::to_string` which is inefficient" -} - /// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. /// /// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. @@ -315,8 +290,6 @@ impl LintPass for MethodsPass { lint_array!(EXTEND_FROM_SLICE, OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, - STR_TO_STRING, - STRING_TO_STRING, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, WRONG_PUB_SELF_CONVENTION, @@ -343,8 +316,6 @@ impl LateLintPass for MethodsPass { // Chain calls if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { lint_unwrap(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["to_string"]) { - lint_to_string(cx, expr, arglists[0]); } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { lint_ok_expect(cx, expr, arglists[0]); } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { @@ -640,26 +611,6 @@ fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { } } -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `to_string()` for `&str`s and `String`s -fn lint_to_string(cx: &LateContext, expr: &Expr, to_string_args: &MethodArgs) { - let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&to_string_args[0])); - - if obj_ty.sty == ty::TyStr { - let mut arg_str = snippet(cx, to_string_args[0].span, "_"); - if ptr_depth > 1 { - arg_str = Cow::Owned(format!("({}{})", iter::repeat('*').take(ptr_depth - 1).collect::<String>(), arg_str)); - } - span_lint(cx, STR_TO_STRING, expr.span, &format!("`{}.to_owned()` is faster", arg_str)); - } else if match_type(cx, obj_ty, &STRING_PATH) { - span_lint(cx, - STRING_TO_STRING, - expr.span, - "`String::to_string` is an inefficient way to clone a `String`; use `clone()` instead"); - } -} - #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `ok().expect()` for `Result`s diff --git a/src/needless_features.rs b/src/needless_features.rs deleted file mode 100644 index f80ac48320e..00000000000 --- a/src/needless_features.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Checks for usage of nightly features that have simple stable equivalents -//! -//! This lint is **warn** by default - -use rustc::lint::*; -use rustc_front::hir::*; -use utils::span_lint; -use utils; - -/// **What it does:** This lint checks for usage of the `as_slice(..)` function, which is unstable. -/// -/// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. -/// -/// **Known problems:** None. -/// -/// **Example:** `x.as_slice(..)` -declare_lint! { - pub UNSTABLE_AS_SLICE, - Warn, - "as_slice is not stable and can be replaced by & v[..]\ -see https://github.com/rust-lang/rust/issues/27729" -} - -/// **What it does:** This lint checks for usage of the `as_mut_slice(..)` function, which is unstable. -/// -/// **Why is this bad?** Using this function doesn't make your code better, but it will preclude it from building with stable Rust. -/// -/// **Known problems:** None. -/// -/// **Example:** `x.as_mut_slice(..)` -declare_lint! { - pub UNSTABLE_AS_MUT_SLICE, - Warn, - "as_mut_slice is not stable and can be replaced by &mut v[..]\ -see https://github.com/rust-lang/rust/issues/27729" -} - -#[derive(Copy,Clone)] -pub struct NeedlessFeaturesPass; - -impl LintPass for NeedlessFeaturesPass { - fn get_lints(&self) -> LintArray { - lint_array!(UNSTABLE_AS_SLICE, UNSTABLE_AS_MUT_SLICE) - } -} - -impl LateLintPass for NeedlessFeaturesPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(ref name, _, _) = expr.node { - if name.node.as_str() == "as_slice" && check_paths(cx, expr) { - span_lint(cx, - UNSTABLE_AS_SLICE, - expr.span, - "used as_slice() from the 'convert' nightly feature. Use &[..] instead"); - } - if name.node.as_str() == "as_mut_slice" && check_paths(cx, expr) { - span_lint(cx, - UNSTABLE_AS_MUT_SLICE, - expr.span, - "used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] instead"); - } - } - } -} - -fn check_paths(cx: &LateContext, expr: &Expr) -> bool { - utils::match_impl_method(cx, expr, &["collections", "vec", "Vec<T>"]) -} diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index c06949eb01a..eb4070d8fd6 100644 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -3,7 +3,6 @@ #[deny(cmp_owned)] fn main() { - #[allow(str_to_string)] fn with_to_string(x : &str) { x != "foo".to_string(); //~^ ERROR this creates an owned instance just for comparison. Consider using `x != "foo"` to compare without allocation diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index b1a8f6cf776..edbdeb2e55a 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -296,12 +296,6 @@ fn main() { let res: Result<i32, ()> = Ok(0); let _ = res.unwrap(); //~ERROR used unwrap() on a Result - let _ = "str".to_string(); //~ERROR `"str".to_owned()` is faster - - let v = &"str"; - let string = v.to_string(); //~ERROR `(*v).to_owned()` is faster - let _again = string.to_string(); //~ERROR `String::to_string` is an inefficient way to clone a `String`; use `clone()` instead - res.ok().expect("disaster!"); //~ERROR called `ok().expect()` // the following should not warn, since `expect` isn't implemented unless // the error type implements `Debug` diff --git a/tests/compile-fail/needless_features.rs b/tests/compile-fail/needless_features.rs deleted file mode 100644 index c5c82c7072b..00000000000 --- a/tests/compile-fail/needless_features.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -#![deny(clippy)] - -fn test_as_slice() { - let v = vec![1]; - v.as_slice(); //~ERROR used as_slice() from the 'convert' nightly feature. Use &[..] - - let mut v2 = vec![1]; - v2.as_mut_slice(); //~ERROR used as_mut_slice() from the 'convert' nightly feature. Use &mut [..] -} - -struct ShouldWork; - -impl ShouldWork { - fn as_slice(&self) -> &ShouldWork { self } -} - -fn test_should_work() { - let sw = ShouldWork; - sw.as_slice(); -} - -fn main() { - test_as_slice(); - test_should_work(); -} diff --git a/tests/run-pass/deprecated.rs b/tests/run-pass/deprecated.rs new file mode 100644 index 00000000000..70223bfd867 --- /dev/null +++ b/tests/run-pass/deprecated.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[warn(str_to_string)] +//~^WARNING: warning: lint str_to_string has been removed: using `str::to_string` +#[warn(string_to_string)] +//~^WARNING: warning: lint string_to_string has been removed: using `string::to_string` +#[warn(unstable_as_slice)] +//~^WARNING: warning: lint unstable_as_slice has been removed: `Vec::as_slice` has been stabilized +#[warn(unstable_as_mut_slice)] +//~^WARNING: warning: lint unstable_as_mut_slice has been removed: `Vec::as_mut_slice` has been stabilized +fn main() {} diff --git a/util/update_lints.py b/util/update_lints.py index 2eaa6ab6211..b16b4b67fad 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -13,14 +13,20 @@ declare_lint_re = re.compile(r''' pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s* (?P<level>Forbid|Deny|Warn|Allow) \s*,\s* " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] -''', re.X | re.S) +''', re.VERBOSE | re.DOTALL) + +declare_deprecated_lint_re = re.compile(r''' + declare_deprecated_lint! \s* [{(] \s* + pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s* + " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] +''', re.VERBOSE | re.DOTALL) nl_escape_re = re.compile(r'\\\n\s*') wiki_link = 'https://github.com/Manishearth/rust-clippy/wiki' -def collect(lints, fn): +def collect(lints, deprecated_lints, fn): """Collect all lints from a file. Adds entries to the lints list as `(module, name, level, desc)`. @@ -35,6 +41,13 @@ def collect(lints, fn): match.group('level').lower(), desc.replace('\\"', '"'))) + for match in declare_deprecated_lint_re.finditer(code): + # remove \-newline escapes from description string + desc = nl_escape_re.sub('', match.group('desc')) + deprecated_lints.append((os.path.splitext(os.path.basename(fn))[0], + match.group('name').lower(), + desc.replace('\\"', '"'))) + def gen_table(lints, link=None): """Write lint table in Markdown format.""" @@ -67,6 +80,13 @@ def gen_mods(lints): yield 'pub mod %s;\n' % module +def gen_deprecated(lints): + """Declare deprecated lints""" + + for lint in lints: + yield ' store.register_removed("%s", "%s");\n' % (lint[1], lint[2]) + + def replace_region(fn, region_start, region_end, callback, replace_start=True, write_back=True): """Replace a region in a file delimited by two lines matching regexes. @@ -107,6 +127,7 @@ def replace_region(fn, region_start, region_end, callback, def main(print_only=False, check=False): lints = [] + deprecated_lints = [] # check directory if not os.path.isfile('src/lib.rs'): @@ -117,7 +138,7 @@ def main(print_only=False, check=False): for root, dirs, files in os.walk('src'): for fn in files: if fn.endswith('.rs'): - collect(lints, os.path.join(root, fn)) + collect(lints, deprecated_lints, os.path.join(root, fn)) if print_only: sys.stdout.writelines(gen_table(lints)) @@ -147,6 +168,13 @@ def main(print_only=False, check=False): lambda: gen_group(lints, levels=('warn', 'deny')), replace_start=False, write_back=not check) + # same for "deprecated" lint collection + changed |= replace_region( + 'src/lib.rs', r'let mut store', r'end deprecated lints', + lambda: gen_deprecated(deprecated_lints), + replace_start=False, + write_back=not check) + # same for "clippy_pedantic" lint collection changed |= replace_region( 'src/lib.rs', r'reg.register_lint_group\("clippy_pedantic"', r'\]\);', diff --git a/util/update_wiki.py b/util/update_wiki.py index cf3421a8228..5040a28bca0 100755 --- a/util/update_wiki.py +++ b/util/update_wiki.py @@ -51,6 +51,10 @@ def parse_file(d, f): last_comment.append(line[3:]) elif line.startswith("declare_lint!"): comment = False + deprecated = False + elif line.startswith("declare_deprecated_lint!"): + comment = False + deprecated = True else: last_comment = [] if not comment: @@ -60,7 +64,8 @@ def parse_file(d, f): if m: name = m.group(1).lower() - while True: + # Intentionally either a never looping or infinite loop + while not deprecated: m = re.search(level_re, line) if m: level = m.group(0) @@ -68,6 +73,9 @@ def parse_file(d, f): line = next(rs) + if deprecated: + level = "Deprecated" + print("found %s with level %s in %s" % (name, level, f)) d[name] = (level, last_comment) last_comment = [] @@ -107,14 +115,21 @@ conf_template = """ """ +def level_message(level): + if level == "Deprecated": + return "\n**Those lints are deprecated**:\n\n" + else: + return "\n**Those lints are %s by default**:\n\n" % level + + def write_wiki_page(d, c, f): keys = list(d.keys()) keys.sort() with open(f, "w") as w: w.write(PREFIX) - for level in ('Deny', 'Warn', 'Allow'): - w.write("\n**Those lints are %s by default**:\n\n" % level) + for level in ('Deny', 'Warn', 'Allow', 'Deprecated'): + w.write(level_message(level)) for k in keys: if d[k][0] == level: w.write("[`%s`](#%s)\n" % (k, k)) -- cgit 1.4.1-3-g733a5 From 6adb9cb53f5d3ee899398603c6de628ec55f99fe Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Thu, 24 Mar 2016 15:48:38 -0700 Subject: Added crosspointer transmute error and tests --- src/lib.rs | 2 ++ src/transmute.rs | 58 +++++++++++++++++++++++++++++++++++++++++ tests/compile-fail/transmute.rs | 31 ++++++++++++++++++++-- 3 files changed, 89 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index ffa66fd581b..8a4a84f5dde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,6 +195,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); + reg.register_late_lint_pass(box transmute::CrosspointerTransmute); reg.register_late_lint_pass(box transmute::UselessTransmute); reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold)); reg.register_late_lint_pass(box escape::EscapePass); @@ -350,6 +351,7 @@ pub fn plugin_registrar(reg: &mut Registry) { swap::ALMOST_SWAPPED, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, + transmute::CROSSPOINTER_TRANSMUTE, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, types::BOX_VEC, diff --git a/src/transmute.rs b/src/transmute.rs index 0dd5b60e77a..daefbaf07ad 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -1,5 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; +use rustc::middle::ty::TyS; +use rustc::middle::ty::TypeVariants::TyRawPtr; use utils; /// **What it does:** This lint checks for transmutes to the original type of the object. @@ -15,6 +17,19 @@ declare_lint! { "transmutes that have the same to and from types" } +/// **What it does:*** This lint checks for transmutes between a type T and *T. +/// +/// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type. +/// +/// **Known problems:** None. +/// +/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `*t` or `&t`'s. +declare_lint! { + pub CROSSPOINTER_TRANSMUTE, + Warn, + "transmutes that have to or from types that are a pointer to the other" +} + pub struct UselessTransmute; impl LintPass for UselessTransmute { @@ -43,3 +58,46 @@ impl LateLintPass for UselessTransmute { } } } + +pub struct CrosspointerTransmute; + +impl LintPass for CrosspointerTransmute { + fn get_lints(&self) -> LintArray { + lint_array!(CROSSPOINTER_TRANSMUTE) + } +} + +fn is_ptr_to(from: &TyS, to: &TyS) -> bool { + if let TyRawPtr(from_ptr) = from.sty { + from_ptr.ty == to + } else { + false + } +} + +impl LateLintPass for CrosspointerTransmute { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, ref args) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + + if utils::match_def_path(cx, def_id, &["core", "intrinsics", "transmute"]) { + let from_ty = cx.tcx.expr_ty(&args[0]); + let to_ty = cx.tcx.expr_ty(e); + + if is_ptr_to(to_ty, from_ty) { + cx.span_lint(CROSSPOINTER_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty)); + } + + if is_ptr_to(from_ty, to_ty) { + cx.span_lint(CROSSPOINTER_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty)); + } + } + } + } + } +} diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs index 94dd3a18549..b8755008086 100644 --- a/tests/compile-fail/transmute.rs +++ b/tests/compile-fail/transmute.rs @@ -1,6 +1,5 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(useless_transmute)] extern crate core; @@ -12,6 +11,7 @@ fn my_vec() -> MyVec<i32> { } #[allow(needless_lifetimes)] +#[deny(useless_transmute)] unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { let _: &'a T = core::intrinsics::transmute(t); //~^ ERROR transmute from a type (`&'a T`) to itself @@ -19,7 +19,8 @@ unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { let _: &'a U = core::intrinsics::transmute(t); } -fn main() { +#[deny(useless_transmute)] +fn useless() { unsafe { let _: Vec<i32> = core::intrinsics::transmute(my_vec()); //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself @@ -43,3 +44,29 @@ fn main() { let _: Vec<u32> = my_transmute(my_vec()); } } + +#[deny(crosspointer_transmute)] +fn crosspointer() { + let mut vec: Vec<i32> = vec![]; + let vec_const_ptr: *const Vec<i32> = &vec as *const Vec<i32>; + let vec_mut_ptr: *mut Vec<i32> = &mut vec as *mut Vec<i32>; + + unsafe { + let _: Vec<i32> = core::intrinsics::transmute(vec_const_ptr); + //~^ ERROR transmute from a type (`*const collections::vec::Vec<i32>`) to the type that it points to (`collections::vec::Vec<i32>`) + + let _: Vec<i32> = core::intrinsics::transmute(vec_mut_ptr); + //~^ ERROR transmute from a type (`*mut collections::vec::Vec<i32>`) to the type that it points to (`collections::vec::Vec<i32>`) + + let _: *const Vec<i32> = core::intrinsics::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to a pointer to that type (`*const collections::vec::Vec<i32>`) + + let _: *mut Vec<i32> = core::intrinsics::transmute(my_vec()); + //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to a pointer to that type (`*mut collections::vec::Vec<i32>`) + } +} + +fn main() { + useless(); + crosspointer(); +} -- cgit 1.4.1-3-g733a5 From b07360eb2852953fcb07da738da0e2266058b2c0 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Thu, 24 Mar 2016 16:38:16 -0700 Subject: Cleanup and added transmute to ugly path list --- src/transmute.rs | 11 +++++------ src/utils/mod.rs | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/transmute.rs b/src/transmute.rs index daefbaf07ad..488d214b21f 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -3,6 +3,7 @@ use rustc_front::hir::*; use rustc::middle::ty::TyS; use rustc::middle::ty::TypeVariants::TyRawPtr; use utils; +use utils::TRANSMUTE_PATH; /// **What it does:** This lint checks for transmutes to the original type of the object. /// @@ -17,7 +18,7 @@ declare_lint! { "transmutes that have the same to and from types" } -/// **What it does:*** This lint checks for transmutes between a type T and *T. +/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`. /// /// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type. /// @@ -44,7 +45,7 @@ impl LateLintPass for UselessTransmute { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if utils::match_def_path(cx, def_id, &["core", "intrinsics", "transmute"]) { + if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) { let from_ty = cx.tcx.expr_ty(&args[0]); let to_ty = cx.tcx.expr_ty(e); @@ -81,7 +82,7 @@ impl LateLintPass for CrosspointerTransmute { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if utils::match_def_path(cx, def_id, &["core", "intrinsics", "transmute"]) { + if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) { let from_ty = cx.tcx.expr_ty(&args[0]); let to_ty = cx.tcx.expr_ty(e); @@ -89,9 +90,7 @@ impl LateLintPass for CrosspointerTransmute { cx.span_lint(CROSSPOINTER_TRANSMUTE, e.span, &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty)); - } - - if is_ptr_to(from_ty, to_ty) { + } else if is_ptr_to(from_ty, to_ty) { cx.span_lint(CROSSPOINTER_TRANSMUTE, e.span, &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty)); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 050aec0e430..e7b2a9d5210 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -51,6 +51,7 @@ pub const RANGE_TO_PATH: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; +pub const TRANSMUTE_PATH: [&'static str; 3] = ["core", "intrinsics", "transmute"]; pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -- cgit 1.4.1-3-g733a5 From e37ff5a5c739d4852761daa42272e0ff69772a4f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 27 Mar 2016 02:44:25 +0530 Subject: Fix ICE with relating late bound regions --- src/methods.rs | 4 ++-- src/new_without_default.rs | 4 ++-- src/utils/mod.rs | 19 ++++++++++++++----- 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 95bbdd441c9..81761695eb8 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -402,8 +402,8 @@ impl LateLintPass for MethodsPass { } } - let ret_ty = return_ty(cx.tcx.node_id_to_type(implitem.id)); - if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty))) { + let ret_ty = return_ty(cx, implitem.id); + if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { span_lint(cx, NEW_RET_NO_SELF, sig.explicit_self.span, diff --git a/src/new_without_default.rs b/src/new_without_default.rs index d9b11cc49b6..395d69138e1 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -52,8 +52,8 @@ impl LateLintPass for NewWithoutDefault { if_let_chain!{[ self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics - let Some(ret_ty) = return_ty(cx.tcx.node_id_to_type(id)), - same_tys(cx, self_ty, ret_ty), + let Some(ret_ty) = return_ty(cx, id), + same_tys(cx, self_ty, ret_ty, id), let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH), !implements_trait(cx, self_ty, default_trait_id, Vec::new()) ], { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index e7b2a9d5210..09fb1475b0c 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,6 +4,7 @@ use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::middle::def_id::DefId; use rustc::middle::traits::ProjectionMode; use rustc::middle::{cstore, def, infer, ty, traits}; +use rustc::middle::subst::Subst; use rustc::session::Session; use rustc_front::hir::*; use std::borrow::Cow; @@ -764,8 +765,13 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { } /// Convenience function to get the return type of a function or `None` if the function diverges. -pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> { - if let ty::FnConverging(ret_ty) = fun.fn_sig().skip_binder().output { +pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> { + let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any); + + let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(infcx.tcx, &infcx.parameter_environment.free_substs); + let fn_sig = infcx.tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive, &fn_sig); + if let ty::FnConverging(ret_ty) = fn_sig.output { Some(ret_ty) } else { None @@ -775,7 +781,10 @@ pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> { /// 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>) -> bool { - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any); - infcx.can_equate(&cx.tcx.erase_regions(&a), &cx.tcx.erase_regions(&b)).is_ok() +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); + let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any); + let new_a = a.subst(infcx.tcx, &infcx.parameter_environment.free_substs); + let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs); + infcx.can_equate(&new_a, &new_b).is_ok() } -- cgit 1.4.1-3-g733a5 From f3fdbd0d89f2ce785c7dfb43b9776f1073dd4189 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 27 Mar 2016 02:45:14 +0530 Subject: Fix ICE with unknown defids --- src/enum_glob_use.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index 5b542a7d67b..7924623c189 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -43,20 +43,21 @@ impl EnumGlobUse { } if let ItemUse(ref item_use) = item.node { if let ViewPath_::ViewPathGlob(_) = item_use.node { - let def = cx.tcx.def_map.borrow()[&item.id]; - if let Some(node_id) = cx.tcx.map.as_local_node_id(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 { - if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() { - if let DefPathData::Type(_) = dp.data { - if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { + 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.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 { + if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() { + if let DefPathData::Type(_) = dp.data { + if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + } + } + } } } } -- cgit 1.4.1-3-g733a5 From 07dc709ba4099bf0c6738f18c2d975c7b893435c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 27 Mar 2016 04:24:42 +0530 Subject: Allow trailing commas in if_let_chain --- src/utils/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 09fb1475b0c..0389c3d56c0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -55,6 +55,7 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const TRANSMUTE_PATH: [&'static str; 3] = ["core", "intrinsics", "transmute"]; pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// @@ -90,6 +91,11 @@ macro_rules! if_let_chain { $block } }; + ([let $pat:pat = $expr:expr,], $block:block) => { + if let $pat = $expr { + $block + } + }; ([$expr:expr, $($tt:tt)+], $block:block) => { if $expr { if_let_chain!{ [$($tt)+], $block } @@ -100,6 +106,11 @@ macro_rules! if_let_chain { $block } }; + ([$expr:expr,], $block:block) => { + if $expr { + $block + } + }; } /// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one -- cgit 1.4.1-3-g733a5 From fcfda681e51ec538fd117d906b95606fd3c3198d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 27 Mar 2016 04:24:55 +0530 Subject: Stop using ast_ty_to_ty_cache It's not reliable and gets cleared` --- src/types.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 1dc1f55b773..742298622fc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,6 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::const_eval; -use rustc::middle::ty; +use rustc::middle::{const_eval, def, ty}; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc_front::util::{is_comparison_binop, binop_to_string}; @@ -53,21 +52,34 @@ impl LateLintPass for TypePass { if in_macro(cx, ast_ty.span) { return; } - if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { - if let ty::TyBox(ref inner) = ty.sty { - if match_type(cx, inner, &VEC_PATH) { + if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) { + if let def::Def::Struct(..) = did.full_def() { + if Some(did.def_id()) == cx.tcx.lang_items.owned_box() { + 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.def_id(), &VEC_PATH), + ], + { + span_help_and_lint(cx, + BOX_VEC, + ast_ty.span, + "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); + } + } + } else if match_def_path(cx, did.def_id(), &LL_PATH) { span_help_and_lint(cx, - BOX_VEC, + LINKEDLIST, ast_ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); + "I see you're using a LinkedList! Perhaps you meant some other data structure?", + "a VecDeque might work"); } - } else if match_type(cx, ty, &LL_PATH) { - 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"); } } } -- cgit 1.4.1-3-g733a5 From f51293c399eda07678ea74cc6f5a83c557011c63 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 27 Mar 2016 04:57:25 +0530 Subject: Rm extraneous infcx --- src/utils/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 0389c3d56c0..6ef0853fdd7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -778,10 +778,8 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { /// Convenience function to get the return type of a function or `None` if the function diverges. pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> { let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any); - - let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(infcx.tcx, &infcx.parameter_environment.free_substs); - let fn_sig = infcx.tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive, &fn_sig); + let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(cx.tcx, ¶meter_env.free_substs); + let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, &fn_sig); if let ty::FnConverging(ret_ty) = fn_sig.output { Some(ret_ty) } else { -- cgit 1.4.1-3-g733a5 From aa819b7748b8aa6ae03ddcdc993b6dff1ba26912 Mon Sep 17 00:00:00 2001 From: josephDunne <jd@lambda.tech> Date: Sun, 27 Mar 2016 19:59:02 +0100 Subject: Update rust-clippy to rustc 1.9.0-nightly (d5a91e695 2016-03-26) move cfg, infer, traits and ty from middle to top-level move middle::subst into middle::ty track the extern-crate def-id rather than path (rustc ab9b844) --- CONTRIBUTING.md | 2 +- src/array_indexing.rs | 2 +- src/copies.rs | 2 +- src/cyclomatic_complexity.rs | 4 ++-- src/derive.rs | 8 ++++---- src/drop_ref.rs | 2 +- src/enum_glob_use.rs | 7 ++++--- src/escape.rs | 8 ++++---- src/eta_reduction.rs | 2 +- src/format.rs | 2 +- src/len_zero.rs | 2 +- src/loops.rs | 2 +- src/matches.rs | 2 +- src/methods.rs | 4 ++-- src/misc.rs | 2 +- src/mut_mut.rs | 2 +- src/mut_reference.rs | 2 +- src/mutex_atomic.rs | 4 ++-- src/needless_update.rs | 2 +- src/ptr_arg.rs | 2 +- src/transmute.rs | 4 ++-- src/types.rs | 3 ++- src/utils/mod.rs | 9 ++++++--- src/vec.rs | 2 +- 24 files changed, 43 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac094d1c828..d7b181c8bdb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ the lint will end up to be a nested series of matches and ifs, [like so](https://github.com/Manishearth/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34). T-middle issues can be more involved and require verifying types. The -[`middle::ty`](http://manishearth.github.io/rust-internals-docs/rustc/middle/ty) module contains a +[`ty`](http://manishearth.github.io/rust-internals-docs/rustc/middle/ty) module contains a lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful. diff --git a/src/array_indexing.rs b/src/array_indexing.rs index ece66ae20a2..344a8b8c34e 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; -use rustc::middle::ty::TyArray; +use rustc::ty::TyArray; use rustc_front::hir::*; use rustc_const_eval::ConstInt; use syntax::ast::RangeLimits; diff --git a/src/copies.rs b/src/copies.rs index 691acad6e92..789f852c6c3 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use std::collections::HashMap; use std::collections::hash_map::Entry; diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index a03a42f2bc0..3db080f970e 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -1,8 +1,8 @@ //! calculate cyclomatic complexity and warn about overly complex functions use rustc::lint::*; -use rustc::middle::cfg::CFG; -use rustc::middle::ty; +use rustc::cfg::CFG; +use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr}; use syntax::ast::Attribute; diff --git a/src/derive.rs b/src/derive.rs index 380ff0a30f9..4a20d8018de 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,8 +1,8 @@ use rustc::lint::*; -use rustc::middle::subst::Subst; -use rustc::middle::ty::TypeVariants; -use rustc::middle::ty::fast_reject::simplify_type; -use rustc::middle::ty; +use rustc::ty::subst::Subst; +use rustc::ty::TypeVariants; +use rustc::ty::fast_reject::simplify_type; +use rustc::ty; use rustc_front::hir::*; use syntax::ast::{Attribute, MetaItemKind}; use syntax::codemap::Span; diff --git a/src/drop_ref.rs b/src/drop_ref.rs index 5f7e67925bd..7536fb1b63b 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use syntax::codemap::Span; use utils::DROP_PATH; diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index 7924623c189..63f5886fec8 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -3,7 +3,7 @@ use rustc::front::map::Node::NodeItem; use rustc::front::map::definitions::DefPathData; use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; -use rustc::middle::ty::TyEnum; +use rustc::ty::TyEnum; use rustc_front::hir::*; use syntax::ast::NodeId; use syntax::codemap::Span; @@ -51,8 +51,9 @@ impl EnumGlobUse { } } } else { - if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() { - if let DefPathData::Type(_) = dp.data { + let dp = cx.sess().cstore.relative_def_path(def.def_id()); + if let Some(dpa) = dp.data.last() { + if let DefPathData::TypeNs(_) = dpa.data { if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } diff --git a/src/escape.rs b/src/escape.rs index f81a05d43d5..51c4c7b6f5d 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,11 +1,11 @@ use rustc::front::map::Node::{NodeExpr, NodeStmt}; use rustc::lint::*; use rustc::middle::expr_use_visitor::*; -use rustc::middle::infer; +use rustc::infer; use rustc::middle::mem_categorization::{cmt, Categorization}; -use rustc::middle::traits::ProjectionMode; -use rustc::middle::ty::adjustment::AutoAdjustment; -use rustc::middle::ty; +use rustc::traits::ProjectionMode; +use rustc::ty::adjustment::AutoAdjustment; +use rustc::ty; use rustc::util::nodemap::NodeSet; use rustc_front::hir::*; use rustc_front::intravisit as visit; diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 6335f3f1398..bae971f46ac 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use utils::{snippet_opt, span_lint_and_then, is_adjusted}; diff --git a/src/format.rs b/src/format.rs index f0b8485b4a4..300b3d17b39 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,6 +1,6 @@ use rustc::front::map::Node::NodeItem; use rustc::lint::*; -use rustc::middle::ty::TypeVariants; +use rustc::ty::TypeVariants; use rustc_front::hir::*; use syntax::ast::LitKind; use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH, STRING_PATH}; diff --git a/src/len_zero.rs b/src/len_zero.rs index e61c77adf24..6dad8684354 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::middle::def_id::DefId; -use rustc::middle::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; +use rustc::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; use rustc_front::hir::*; use syntax::ast::{Lit, LitKind, Name}; use syntax::codemap::{Span, Spanned}; diff --git a/src/loops.rs b/src/loops.rs index 7987c70d027..c0d3993746a 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -5,7 +5,7 @@ use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; use rustc::middle::def::Def; use rustc::middle::region::CodeExtent; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; diff --git a/src/matches.rs b/src/matches.rs index a456a816f62..bc3b45b32ef 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use rustc_const_eval::ConstInt; use std::cmp::Ordering; diff --git a/src/methods.rs b/src/methods.rs index 81761695eb8..b8bbc0e9068 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -2,8 +2,8 @@ use rustc::lint::*; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; use rustc::middle::cstore::CrateStore; -use rustc::middle::subst::{Subst, TypeSpace}; -use rustc::middle::ty; +use rustc::ty::subst::{Subst, TypeSpace}; +use rustc::ty; use rustc_front::hir::*; use std::borrow::Cow; use std::fmt; diff --git a/src/misc.rs b/src/misc.rs index 55439e6a78b..49426d5d5de 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc::middle::const_eval::ConstVal::Float; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::middle::const_eval::eval_const_expr_partial; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::FnKind; use rustc_front::util::{is_comparison_binop, binop_to_string}; diff --git a/src/mut_mut.rs b/src/mut_mut.rs index c8f86330b93..a5ed233241d 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty::{TypeAndMut, TyRef}; +use rustc::ty::{TypeAndMut, TyRef}; use rustc_front::hir::*; use utils::{in_external_macro, span_lint}; diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 707ce8efaeb..95ed1092eb5 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; +use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; use rustc_front::hir::*; use syntax::ptr::P; use utils::span_lint; diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index c8f5e3c7919..0593438cfc1 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -3,8 +3,8 @@ //! This lint is **warn** by default use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; -use rustc::middle::subst::ParamSpace; -use rustc::middle::ty; +use rustc::ty::subst::ParamSpace; +use rustc::ty; use rustc_front::hir::Expr; use syntax::ast; use utils::{span_lint, MUTEX_PATH, match_type}; diff --git a/src/needless_update.rs b/src/needless_update.rs index e3359469150..d25f66ca434 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -1,5 +1,5 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::middle::ty::TyStruct; +use rustc::ty::TyStruct; use rustc_front::hir::{Expr, ExprStruct}; use utils::span_lint; diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 85baf3310c3..b7882bfda16 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -4,7 +4,7 @@ use rustc::front::map::NodeItem; use rustc::lint::*; -use rustc::middle::ty; +use rustc::ty; use rustc_front::hir::*; use syntax::ast::NodeId; use utils::{STRING_PATH, VEC_PATH}; diff --git a/src/transmute.rs b/src/transmute.rs index 488d214b21f..8689a7e3668 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; -use rustc::middle::ty::TyS; -use rustc::middle::ty::TypeVariants::TyRawPtr; +use rustc::ty::TyS; +use rustc::ty::TypeVariants::TyRawPtr; use utils; use utils::TRANSMUTE_PATH; diff --git a/src/types.rs b/src/types.rs index 742298622fc..c2fc242ec53 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,7 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::{const_eval, def, ty}; +use rustc::middle::{const_eval, def}; +use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc_front::util::{is_comparison_binop, binop_to_string}; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 6ef0853fdd7..017890dc461 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,9 +2,12 @@ use reexport::*; use rustc::front::map::Node; use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::middle::def_id::DefId; -use rustc::middle::traits::ProjectionMode; -use rustc::middle::{cstore, def, infer, ty, traits}; -use rustc::middle::subst::Subst; +use rustc::traits; +use rustc::traits::ProjectionMode; +use rustc::middle::{cstore, def}; +use rustc::infer; +use rustc::ty; +use rustc::ty::subst::Subst; use rustc::session::Session; use rustc_front::hir::*; use std::borrow::Cow; diff --git a/src/vec.rs b/src/vec.rs index dda552bc8f9..481c84079f2 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc::middle::ty::TypeVariants; +use rustc::ty::TypeVariants; use rustc_front::hir::*; use syntax::codemap::Span; use syntax::ptr::P; -- cgit 1.4.1-3-g733a5 From 204034e8fa32e488b14131302a77fb2c918d32f0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 28 Mar 2016 01:58:57 +0530 Subject: Fix ICE --- src/enum_glob_use.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index 63f5886fec8..5b29f84ef51 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -1,9 +1,9 @@ //! lint on `use`ing all variants of an enum use rustc::front::map::Node::NodeItem; -use rustc::front::map::definitions::DefPathData; use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; -use rustc::ty::TyEnum; +use rustc::middle::def::Def; +use rustc::middle::cstore::DefLike; use rustc_front::hir::*; use syntax::ast::NodeId; use syntax::codemap::Span; @@ -51,12 +51,10 @@ impl EnumGlobUse { } } } else { - let dp = cx.sess().cstore.relative_def_path(def.def_id()); - if let Some(dpa) = dp.data.last() { - if let DefPathData::TypeNs(_) = dpa.data { - if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } + let child = cx.sess().cstore.item_children(def.def_id()); + if let Some(child) = child.first() { + if let DefLike::DlDef(Def::Variant(..)) = child.def { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } } } -- cgit 1.4.1-3-g733a5 From 2d5e3f311841617eba62089212c1b43120c13921 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 25 Mar 2016 23:22:17 +0100 Subject: Lint transmute from ptr to ref --- README.md | 3 +- src/lib.rs | 4 +- src/transmute.rs | 108 ++++++++++++++++++++++++++-------------- tests/compile-fail/transmute.rs | 39 +++++++++++++++ 4 files changed, 114 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 6199ccd8e8f..95ba6b08539 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 135 lints included in this crate: +There are 136 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -133,6 +133,7 @@ name [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries [too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. +[transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type [trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see http://www.unicode.org/reports/tr15/ for further information) diff --git a/src/lib.rs b/src/lib.rs index 8a4a84f5dde..7d24b2c8924 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,8 +195,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); - reg.register_late_lint_pass(box transmute::CrosspointerTransmute); - reg.register_late_lint_pass(box transmute::UselessTransmute); + 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 escape::EscapePass); reg.register_early_lint_pass(box misc_early::MiscEarly); @@ -352,6 +351,7 @@ pub fn plugin_registrar(reg: &mut Registry) { swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, transmute::CROSSPOINTER_TRANSMUTE, + transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, types::BOX_VEC, diff --git a/src/transmute.rs b/src/transmute.rs index 8689a7e3668..ef049ba4a6d 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -1,9 +1,9 @@ use rustc::lint::*; +use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; +use rustc::ty; use rustc_front::hir::*; -use rustc::ty::TyS; -use rustc::ty::TypeVariants::TyRawPtr; -use utils; use utils::TRANSMUTE_PATH; +use utils::{match_def_path, snippet_opt, span_lint, span_lint_and_then}; /// **What it does:** This lint checks for transmutes to the original type of the object. /// @@ -31,28 +31,63 @@ declare_lint! { "transmutes that have to or from types that are a pointer to the other" } -pub struct UselessTransmute; +/// **What it does:*** This lint checks for transmutes from a pointer to a reference. +/// +/// **Why is this bad?** This can always be rewritten with `&` and `*`. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _: &T = std::mem::transmute(p); // where p: *const T +/// // can be written: +/// let _: &T = &*p; +/// ``` +declare_lint! { + pub TRANSMUTE_PTR_TO_REF, + Warn, + "transmutes from a pointer to a reference type" +} + +pub struct Transmute; -impl LintPass for UselessTransmute { +impl LintPass for Transmute { fn get_lints(&self) -> LintArray { - lint_array!(USELESS_TRANSMUTE) + lint_array! [ + CROSSPOINTER_TRANSMUTE, + TRANSMUTE_PTR_TO_REF, + USELESS_TRANSMUTE + ] } } -impl LateLintPass for UselessTransmute { +impl LateLintPass for Transmute { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprCall(ref path_expr, ref args) = e.node { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) { + if match_def_path(cx, def_id, &TRANSMUTE_PATH) { let from_ty = cx.tcx.expr_ty(&args[0]); let to_ty = cx.tcx.expr_ty(e); if from_ty == to_ty { - cx.span_lint(USELESS_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to itself", from_ty)); + span_lint(cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty)); + } else if is_ptr_to(to_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)); + } else if is_ptr_to(from_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)); + } else { + check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]); } } } @@ -60,15 +95,7 @@ impl LateLintPass for UselessTransmute { } } -pub struct CrosspointerTransmute; - -impl LintPass for CrosspointerTransmute { - fn get_lints(&self) -> LintArray { - lint_array!(CROSSPOINTER_TRANSMUTE) - } -} - -fn is_ptr_to(from: &TyS, to: &TyS) -> bool { +fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool { if let TyRawPtr(from_ptr) = from.sty { from_ptr.ty == to } else { @@ -76,27 +103,34 @@ fn is_ptr_to(from: &TyS, to: &TyS) -> bool { } } -impl LateLintPass for CrosspointerTransmute { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprCall(ref path_expr, ref args) = e.node { - if let ExprPath(None, _) = path_expr.node { - let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); +fn check_ptr_to_ref<'tcx>(cx: &LateContext, + from_ty: ty::Ty<'tcx>, + to_ty: ty::Ty<'tcx>, + e: &Expr, arg: &Expr) { + if let TyRawPtr(ref from_pty) = from_ty.sty { + if let TyRef(_, ref to_rty) = to_ty.sty { + let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)", + from_ty, + to_ty); + span_lint_and_then(cx, TRANSMUTE_PTR_TO_REF, e.span, &mess, |db| { + if let Some(arg) = snippet_opt(cx, arg.span) { + let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable { + ("&mut *", "*mut") + } else { + ("&*", "*const") + }; - if utils::match_def_path(cx, def_id, &TRANSMUTE_PATH) { - let from_ty = cx.tcx.expr_ty(&args[0]); - let to_ty = cx.tcx.expr_ty(e); - if is_ptr_to(to_ty, from_ty) { - cx.span_lint(CROSSPOINTER_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty)); - } else if is_ptr_to(from_ty, to_ty) { - cx.span_lint(CROSSPOINTER_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", from_ty, to_ty)); + let sugg = if from_pty.ty == to_rty.ty { + format!("{}{}", deref, arg) } + else { + format!("{}({} as {} {})", deref, arg, cast, to_rty.ty) + }; + + db.span_suggestion(e.span, "try", sugg); } - } + }); } } } diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs index b8755008086..5bae2c72643 100644 --- a/tests/compile-fail/transmute.rs +++ b/tests/compile-fail/transmute.rs @@ -19,6 +19,45 @@ unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { let _: &'a U = core::intrinsics::transmute(t); } +#[deny(transmute_ptr_to_ref)] +unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { + let _: &T = std::mem::transmute(p); + //~^ ERROR transmute from a pointer type (`*const T`) to a reference type (`&T`) + //~| HELP try + //~| SUGGESTION = &*p; + let _: &T = &*p; + + let _: &mut T = std::mem::transmute(m); + //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) + //~| HELP try + //~| SUGGESTION = &mut *m; + let _: &mut T = &mut *m; + + let _: &T = std::mem::transmute(m); + //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&T`) + //~| HELP try + //~| SUGGESTION = &*m; + let _: &T = &*m; + + let _: &T = std::mem::transmute(o); + //~^ ERROR transmute from a pointer type (`*const U`) to a reference type (`&T`) + //~| HELP try + //~| SUGGESTION = &*(o as *const T); + let _: &T = &*(o as *const T); + + let _: &mut T = std::mem::transmute(om); + //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) + //~| HELP try + //~| SUGGESTION = &mut *(om as *mut T); + let _: &mut T = &mut *(om as *mut T); + + let _: &T = std::mem::transmute(om); + //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&T`) + //~| HELP try + //~| SUGGESTION = &*(om as *const T); + let _: &T = &*(om as *const T); +} + #[deny(useless_transmute)] fn useless() { unsafe { -- cgit 1.4.1-3-g733a5 From e7158dc8f174126780ac6caa864bccede5dda262 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 26 Mar 2016 01:49:45 +0100 Subject: s/cx.span_lint/span_lint(cx, / --- src/misc.rs | 22 ++++++++++++---------- src/ranges.rs | 19 +++++++++++-------- 2 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/misc.rs b/src/misc.rs index 49426d5d5de..5a787ba6dba 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -312,7 +312,7 @@ impl LateLintPass for ModuloOne { if let ExprBinary(ref cmp, _, ref right) = expr.node { if let Spanned {node: BinOp_::BiRem, ..} = *cmp { if is_integer_literal(right, 1) { - cx.span_lint(MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } } } @@ -347,11 +347,12 @@ impl LateLintPass for PatternPass { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatKind::Ident(_, ref ident, Some(ref right)) = pat.node { if right.node == PatKind::Wild { - cx.span_lint(REDUNDANT_PATTERN, - pat.span, - &format!("the `{} @ _` pattern can be written as just `{}`", - ident.node.name, - ident.node.name)); + span_lint(cx, + REDUNDANT_PATTERN, + pat.span, + &format!("the `{} @ _` pattern can be written as just `{}`", + ident.node.name, + ident.node.name)); } } } @@ -408,10 +409,11 @@ impl LateLintPass for UsedUnderscoreBinding { _ => false, }; if needs_lint { - cx.span_lint(USED_UNDERSCORE_BINDING, - expr.span, - "used binding which is prefixed with an underscore. A leading underscore signals that a \ - binding will not be used."); + span_lint(cx, + USED_UNDERSCORE_BINDING, + expr.span, + "used binding which is prefixed with an underscore. A leading underscore signals that a \ + binding will not be used."); } } } diff --git a/src/ranges.rs b/src/ranges.rs index 766d98b4e0b..23bd3d1103c 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Spanned; -use utils::{is_integer_literal, match_type, snippet, unsugar_range, UnsugaredRange}; +use utils::{is_integer_literal, match_type, snippet, span_lint, unsugar_range, UnsugaredRange}; /// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. /// @@ -41,10 +41,11 @@ impl LateLintPass for StepByZero { // Range with step_by(0). if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && is_integer_literal(&args[1], 0) { - cx.span_lint(RANGE_STEP_BY_ZERO, - expr.span, - "Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \ - instead") + span_lint(cx, + RANGE_STEP_BY_ZERO, + expr.span, + "Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \ + instead"); } else if name.as_str() == "zip" && args.len() == 2 { let iter = &args[0].node; let zip_arg = &args[1]; @@ -64,9 +65,11 @@ impl LateLintPass for StepByZero { let ExprPath(_, Path { segments: ref len_path, .. }) = len_args[0].node, iter_path == len_path ], { - cx.span_lint(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, "_"))); } } } -- cgit 1.4.1-3-g733a5 From 7877a42308a05597840f212d10d2abb27086669f Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 19 Mar 2016 15:06:56 +0100 Subject: Fix some spelling mistakes here and there --- src/copies.rs | 2 +- src/derive.rs | 2 +- src/items_after_statements.rs | 6 +++--- src/lib.rs | 4 ++-- src/misc_early.rs | 4 ++-- src/needless_bool.rs | 4 ++-- src/utils/hir.rs | 2 +- tests/compile-fail/bool_comparison.rs | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 789f852c6c3..04f8aaa37e7 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -47,7 +47,7 @@ declare_lint! { /// match foo { /// Bar => bar(), /// Quz => quz(), -/// Baz => bar(), // <= oups +/// Baz => bar(), // <= oops /// } /// ``` declare_lint! { diff --git a/src/derive.rs b/src/derive.rs index 4a20d8018de..ab4f73eafc0 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -14,7 +14,7 @@ use utils::{match_path, span_lint_and_then}; /// /// **Why is this bad?** The implementation of these traits must agree (for example for use with /// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation with -/// an explicitely defined `PartialEq`. In particular, the following must hold for any type: +/// an explicitly defined `PartialEq`. In particular, the following must hold for any type: /// /// ```rust /// k1 == k2 ⇒ hash(k1) == hash(k2) diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index a2ab7246942..952dcb7ed9c 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -32,15 +32,15 @@ declare_lint! { "finds blocks where an item comes after a statement" } -pub struct ItemsAfterStatemets; +pub struct ItemsAfterStatements; -impl LintPass for ItemsAfterStatemets { +impl LintPass for ItemsAfterStatements { fn get_lints(&self) -> LintArray { lint_array!(ITEMS_AFTER_STATEMENTS) } } -impl EarlyLintPass for ItemsAfterStatemets { +impl EarlyLintPass for ItemsAfterStatements { fn check_block(&mut self, cx: &EarlyContext, item: &Block) { if in_macro(cx, item.span) { return; diff --git a/src/lib.rs b/src/lib.rs index 7d24b2c8924..75b5ec4cc23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,7 @@ pub fn plugin_registrar(reg: &mut Registry) { } Err((err, span)) => { reg.sess.struct_span_err(span, err) - .span_note(span, "Clippy will use defaulf configuration") + .span_note(span, "Clippy will use default configuration") .emit(); utils::conf::Conf::default() } @@ -163,7 +163,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box precedence::Precedence); reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box identity_op::IdentityOp); - reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatemets); + reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements); reg.register_late_lint_pass(box mut_mut::MutMut); reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); reg.register_late_lint_pass(box len_zero::LenZero); diff --git a/src/misc_early.rs b/src/misc_early.rs index 60e175d6382..b1c584a4b3e 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -110,10 +110,10 @@ impl EarlyLintPass for MiscEarly { let arg_name = sp_ident.node.to_string(); if arg_name.starts_with('_') { - if let Some(correspondance) = registered_names.get(&arg_name[1..]) { + if let Some(correspondence) = registered_names.get(&arg_name[1..]) { span_lint(cx, DUPLICATE_UNDERSCORE_ARGUMENT, - *correspondance, + *correspondence, &format!("`{}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult", arg_name[1..].to_owned()));; diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 43e7cfddadd..ab5a1e26b20 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -105,7 +105,7 @@ impl LateLintPass for BoolComparison { span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against true are unnecesary", + "equality checks against true are unnecessary", |db| { db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); @@ -115,7 +115,7 @@ impl LateLintPass for BoolComparison { span_lint_and_then(cx, BOOL_COMPARISON, e.span, - "equality checks against true are unnecesary", + "equality checks against true are unnecessary", |db| { db.span_suggestion(e.span, "try simplifying it as shown:", hint); }); diff --git a/src/utils/hir.rs b/src/utils/hir.rs index ed2a49b3caa..20c7e33fbb2 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -13,7 +13,7 @@ use utils::differing_macro_contexts; pub struct SpanlessEq<'a, 'tcx: 'a> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'a, 'tcx>, - /// If is true, never consider as equal expressions containing fonction calls. + /// If is true, never consider as equal expressions containing function calls. ignore_fn: bool, } diff --git a/tests/compile-fail/bool_comparison.rs b/tests/compile-fail/bool_comparison.rs index 8a792931d02..83675945519 100644 --- a/tests/compile-fail/bool_comparison.rs +++ b/tests/compile-fail/bool_comparison.rs @@ -5,7 +5,7 @@ fn main() { let x = true; if x == true { "yes" } else { "no" }; - //~^ ERROR equality checks against true are unnecesary + //~^ ERROR equality checks against true are unnecessary //~| HELP try simplifying it as shown: //~| SUGGESTION if x { "yes" } else { "no" }; if x == false { "yes" } else { "no" }; @@ -13,7 +13,7 @@ fn main() { //~| HELP try simplifying it as shown: //~| SUGGESTION if !x { "yes" } else { "no" }; if true == x { "yes" } else { "no" }; - //~^ ERROR equality checks against true are unnecesary + //~^ ERROR equality checks against true are unnecessary //~| HELP try simplifying it as shown: //~| SUGGESTION if x { "yes" } else { "no" }; if false == x { "yes" } else { "no" }; -- cgit 1.4.1-3-g733a5 From 941ec6e4f5cfc54078f5fe65702ec46b6c59b8d2 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 19 Mar 2016 17:48:29 +0100 Subject: Beautify more docs --- src/bit_mask.rs | 36 +++++++++++++++++----------------- src/consts.rs | 2 +- src/formatting.rs | 4 ++-- src/len_zero.rs | 6 +++--- src/loops.rs | 8 ++++---- src/matches.rs | 2 +- src/non_expressive_names.rs | 2 +- src/ptr_arg.rs | 4 +--- src/strings.rs | 2 +- src/utils/mod.rs | 10 +++++----- src/zero_div_zero.rs | 2 +- tests/compile-fail/methods.rs | 10 +++++----- tests/used_underscore_binding_macro.rs | 2 +- 13 files changed, 44 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/bit_mask.rs b/src/bit_mask.rs index f96927f1548..15fbabf9f0b 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -13,14 +13,14 @@ use utils::span_lint; /// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` /// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: /// -/// |Comparison |Bit-Op|Example |is always|Formula | -/// |------------|------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// |Comparison |Bit Op |Example |is always|Formula | +/// |------------|-------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// /// **Why is this bad?** If the bits that the comparison cares about are always set to zero or one by the bit mask, the comparison is constant `true` or `false` (depending on mask, compared value, and operators). /// @@ -38,7 +38,7 @@ declare_lint! { /// **What it does:** This lint checks for bit masks in comparisons which can be removed without changing the outcome. The basic structure can be seen in the following table: /// -/// |Comparison|Bit-Op |Example |equals | +/// |Comparison| Bit Op |Example |equals | /// |----------|---------|-----------|-------| /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| @@ -61,21 +61,21 @@ declare_lint! { /// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , /// `!=`, `>=`, `>`}) can be determined from the following table: /// -/// |Comparison |Bit-Op|Example |is always|Formula | -/// |------------|------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// |Comparison |Bit Op |Example |is always|Formula | +/// |------------|-------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// /// This lint is **deny** by default /// /// There is also a lint that warns on ineffective masks that is *warn* /// by default. /// -/// |Comparison|Bit-Op |Example |equals |Formula| +/// |Comparison| Bit Op |Example |equals |Formula| /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`| /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` | /// diff --git a/src/consts.rs b/src/consts.rs index 67da1216c42..97a99dda4b5 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -30,7 +30,7 @@ impl From<FloatTy> for FloatWidth { } } -/// a Lit_-like enum to fold constant `Expr`s into +/// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant { /// a String "abc" diff --git a/src/formatting.rs b/src/formatting.rs index 091280de28d..aa6dd46cf0b 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -82,7 +82,7 @@ impl EarlyLintPass for Formatting { } } -/// Implementation of the SUSPICIOUS_ASSIGNMENT_FORMATTING lint. +/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(cx, lhs.span) { @@ -108,7 +108,7 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { } } -/// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`. +/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`. fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) { if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(cx, then.span) { diff --git a/src/len_zero.rs b/src/len_zero.rs index 6dad8684354..1a097820e1e 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -164,9 +164,9 @@ fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], l } } -/// check if this type has an is_empty method +/// Check if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { - /// get a ImplOrTraitItem and return true if it matches is_empty(self) + /// Get an `ImplOrTraitItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { if let MethodTraitItemId(def_id) = *id { if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { @@ -179,7 +179,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { } } - /// check the inherent impl's items for an is_empty(self) method + /// Check the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext, id: &DefId) -> bool { let impl_items = cx.tcx.impl_items.borrow(); cx.tcx.inherent_impls.borrow().get(id).map_or(false, |ids| { diff --git a/src/loops.rs b/src/loops.rs index c0d3993746a..546f07a6507 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -571,7 +571,7 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex } } -/// Check for the FOR_KV_MAP lint. +/// Check for the `FOR_KV_MAP` lint. fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { if let PatKind::Tup(ref pat) = pat.node { if pat.len() == 2 { @@ -607,7 +607,7 @@ 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 '_'. +/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { match *pat { PatKind::Wild => true, @@ -750,8 +750,8 @@ impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> { } -/// Return true if the type of expr is one that provides IntoIterator impls -/// for &T and &mut T, such as Vec. +/// Return true if the type of expr is one that provides `IntoIterator` impls +/// for `&T` and `&mut T`, such as `Vec`. #[cfg_attr(rustfmt, rustfmt_skip)] fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it diff --git a/src/matches.rs b/src/matches.rs index bc3b45b32ef..7bffd445f6b 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -330,7 +330,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match } } -/// Get all arms that are unbounded PatRange-s. +/// Get all arms that are unbounded `PatRange`s. fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { arms.iter() .filter_map(|arm| { diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index b7d2ac80a10..d7cb6fc5d28 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -251,7 +251,7 @@ impl EarlyLintPass for NonExpressiveNames { } } -/// precondition: a_name.chars().count() < b_name.chars().count() +/// Precondition: `a_name.chars().count() < b_name.chars().count()`. fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { debug_assert!(a_name.chars().count() < b_name.chars().count()); let mut a_chars = a_name.chars(); diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index b7882bfda16..6498db66e13 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -1,6 +1,4 @@ -//! Checks for usage of &Vec[_] and &String -//! -//! This lint is **warn** by default +//! Checks for usage of `&Vec[_]` and `&String`. use rustc::front::map::NodeItem; use rustc::lint::*; diff --git a/src/strings.rs b/src/strings.rs index aa9cdcce50c..9f68175b202 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -1,4 +1,4 @@ -//! This LintPass catches both string addition and string addition + assignment +//! This lint catches both string addition and string addition + assignment //! //! Note that since we have two lints where one subsumes the other, we try to //! disable the subsumed lint unless it has a higher level diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 017890dc461..34404f4c2e9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -129,8 +129,8 @@ pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { /// Returns true if the macro that expanded the crate was outside of the current crate or was a /// compiler plugin. pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { - /// Invokes in_macro with the expansion info of the given span slightly heavy, try to use this - /// after other checks have already happened. + /// Invokes `in_macro` with the expansion info of the given span slightly heavy, try to use + /// this after other checks have already happened. fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { // no ExpnInfo = no macro opt_info.map_or(false, |info| { @@ -657,7 +657,7 @@ pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option<Spa } } -/// Returns index of character after first CamelCase component of `s` +/// Return the index of the character after the first camel-case component of `s`. pub fn camel_case_until(s: &str) -> usize { let mut iter = s.char_indices(); if let Some((_, first)) = iter.next() { @@ -690,7 +690,7 @@ pub fn camel_case_until(s: &str) -> usize { } } -/// Returns index of last CamelCase component of `s`. +/// Return index of the last camel-case component of `s`. pub fn camel_case_from(s: &str) -> usize { let mut iter = s.char_indices().rev(); if let Some((_, first)) = iter.next() { @@ -719,7 +719,7 @@ pub fn camel_case_from(s: &str) -> usize { last_i } -/// Represents a range akin to `ast::ExprKind::Range`. +/// Represent a range akin to `ast::ExprKind::Range`. #[derive(Debug, Copy, Clone)] pub struct UnsugaredRange<'a> { pub start: Option<&'a Expr>, diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index 1d119b05176..f58b0e695a9 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -4,7 +4,7 @@ use rustc_front::hir::*; use utils::span_help_and_lint; /// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists -/// `of 0.0/0.0`, which is always NaN. It is more clear to replace instances of +/// `of 0.0/0.0`, which is always `NaN`. It is more clear to replace instances of /// `0.0/0.0` with `std::f32::NaN` or `std::f64::NaN`, depending on the precision. pub struct ZeroDivZeroPass; diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 74f262b05a7..9d938ebb19e 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -85,8 +85,8 @@ macro_rules! opt_map { } /// Checks implementation of the following lints: -/// OPTION_MAP_UNWRAP_OR -/// OPTION_MAP_UNWRAP_OR_ELSE +/// * `OPTION_MAP_UNWRAP_OR` +/// * `OPTION_MAP_UNWRAP_OR_ELSE` fn option_methods() { let opt = Some(1); @@ -154,7 +154,7 @@ impl IteratorFalsePositives { } } -/// Checks implementation of FILTER_NEXT lint +/// Checks implementation of `FILTER_NEXT` lint fn filter_next() { let v = vec![3, 2, 1, 0, -1, -2, -3]; @@ -174,7 +174,7 @@ fn filter_next() { let _ = foo.filter().next(); } -/// Checks implementation of SEARCH_IS_SOME lint +/// Checks implementation of `SEARCH_IS_SOME` lint fn search_is_some() { let v = vec![3, 2, 1, 0, -1, -2, -3]; @@ -218,7 +218,7 @@ fn search_is_some() { let _ = foo.rposition().is_some(); } -/// Checks implementation of the OR_FUN_CALL lint +/// Checks implementation of the `OR_FUN_CALL` lint fn or_fun_call() { struct Foo; diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs index 4170f907b0a..7a8faa62742 100644 --- a/tests/used_underscore_binding_macro.rs +++ b/tests/used_underscore_binding_macro.rs @@ -3,7 +3,7 @@ extern crate rustc_serialize; -/// Test that we do not lint for unused underscores in a MacroAttribute expansion +/// Test that we do not lint for unused underscores in a `MacroAttribute` expansion #[deny(used_underscore_binding)] #[derive(RustcEncodable)] struct MacroAttributesTest { -- cgit 1.4.1-3-g733a5 From 42bf37f49f49829507be4f2dfd6c5db9b8234b66 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 19 Mar 2016 17:59:12 +0100 Subject: Add a lint for bad documentation formatting --- README.md | 1 + src/doc.rs | 112 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ tests/compile-fail/doc.rs | 26 +++++++++++ 4 files changed, 142 insertions(+) create mode 100644 src/doc.rs create mode 100755 tests/compile-fail/doc.rs (limited to 'src') diff --git a/README.md b/README.md index 95ba6b08539..e4d18c28bfe 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ name [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly +[doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | checks for the presence of the `_` character outside ticks in documentation [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected diff --git a/src/doc.rs b/src/doc.rs new file mode 100644 index 00000000000..610aa34ab2c --- /dev/null +++ b/src/doc.rs @@ -0,0 +1,112 @@ +use rustc::lint::*; +use std::borrow::Cow; +use syntax::ast; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** This lint checks for the presence of the `_` character outside ticks in +/// documentation. +/// +/// **Why is this bad?** *Rustdoc* supports markdown formatting, the `_` character probably +/// indicates some code which should be included between ticks. +/// +/// **Known problems:** Lots of bad docs won’t be fixed, the lint only checks for `_`. +/// +/// **Examples:** +/// ```rust +/// /// Do something with the foo_bar parameter. +/// fn doit(foo_bar) { .. } +/// ``` +declare_lint! { + pub DOC_MARKDOWN, Warn, + "checks for the presence of the `_` character outside ticks in documentation" +} + +#[derive(Copy,Clone)] +pub struct Doc; + +impl LintPass for Doc { + fn get_lints(&self) -> LintArray { + lint_array![DOC_MARKDOWN] + } +} + +impl EarlyLintPass for Doc { + fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { + check_attrs(cx, &krate.attrs, krate.span); + } + + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + check_attrs(cx, &item.attrs, item.span); + } +} + +/// Collect all doc attributes. Multiple `///` are represented in different attributes. `rustdoc` +/// has a pass to merge them, but we probably don’t want to invoke that here. +fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { + fn doc_and_span(attr: &ast::Attribute) -> Option<(&str, Span)> { + if attr.node.is_sugared_doc { + if let ast::MetaItemKind::NameValue(_, ref doc) = attr.node.value.node { + if let ast::LitKind::Str(ref doc, _) = doc.node { + return Some((&doc[..], attr.span)); + } + } + } + + None + } + let doc_and_span: fn(_) -> _ = doc_and_span; + + let mut doc_attrs = attrs.iter().filter_map(doc_and_span); + + let count = doc_attrs.clone().take(2).count(); + + match count { + 0 => ("".into(), None), + 1 => { + let (doc, span) = doc_attrs.next().unwrap_or_else(|| unreachable!()); + (doc.into(), Some(span)) + } + _ => (doc_attrs.map(|s| s.0).collect::<String>().into(), None), + } +} + +fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_span: Span) { + let (doc, span) = collect_doc(attrs); + let span = span.unwrap_or(default_span); + + let mut in_ticks = false; + for word in doc.split_whitespace() { + let ticks = word.bytes().filter(|&b| b == b'`').count(); + + if ticks == 2 { // likely to be “`foo`” + continue; + } else if ticks % 2 == 1 { + in_ticks = !in_ticks; + continue; // let’s assume no one will ever write something like “`foo`_bar” + } + + if !in_ticks { + check_word(cx, word, span); + } + } +} + +fn check_word(cx: &EarlyContext, word: &str, span: Span) { + /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is + /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). + fn is_camel_case(s: &str) -> bool { + let s = if s.ends_with('s') { + &s[..s.len()-1] + } else { + s + }; + + s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 && + s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 + } + + if word.contains('_') || is_camel_case(word) { + span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 75b5ec4cc23..0a51385f6f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,7 @@ pub mod collapsible_if; pub mod copies; pub mod cyclomatic_complexity; pub mod derive; +pub mod doc; pub mod drop_ref; pub mod entry; pub mod enum_clike; @@ -223,6 +224,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); + reg.register_early_lint_pass(box doc::Doc); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -265,6 +267,7 @@ pub fn plugin_registrar(reg: &mut Registry) { cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, derive::DERIVE_HASH_XOR_EQ, derive::EXPL_IMPL_CLONE_ON_COPY, + doc::DOC_MARKDOWN, drop_ref::DROP_REF, entry::MAP_ENTRY, enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs new file mode 100755 index 00000000000..9eb949a3b68 --- /dev/null +++ b/tests/compile-fail/doc.rs @@ -0,0 +1,26 @@ +//! This file tests for the DOC_MARKDOWN lint +//~^ ERROR: you should put `DOC_MARKDOWN` between ticks + +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(doc_markdown)] + +/// The foo_bar function does nothing. +//~^ ERROR: you should put `foo_bar` between ticks +fn foo_bar() { +} + +/// That one tests multiline ticks. +/// ```rust +/// foo_bar FOO_BAR +/// ``` +fn multiline_ticks() { +} + +/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and +/// `multiline_ticks` functions. +fn main() { + foo_bar(); + multiline_ticks(); +} -- cgit 1.4.1-3-g733a5 From b1d1f095f12d6640aac2ab7e8ad29fc36de90b39 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 28 Mar 2016 18:00:24 +0200 Subject: Improve the DOC_MARKDOWN lint `_` can be used for emphasize text. `::` is equality as bad outside ticks. --- README.md | 2 +- src/doc.rs | 37 +++++++++++++++++++++++++++++-------- tests/compile-fail/doc.rs | 8 ++++++-- 3 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index e4d18c28bfe..264bc6f010b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ name [cyclomatic_complexity](https://github.com/Manishearth/rust-clippy/wiki#cyclomatic_complexity) | warn | finds functions that should be split up into multiple functions [deprecated_semver](https://github.com/Manishearth/rust-clippy/wiki#deprecated_semver) | warn | `Warn` on `#[deprecated(since = "x")]` where x is not semver [derive_hash_xor_eq](https://github.com/Manishearth/rust-clippy/wiki#derive_hash_xor_eq) | warn | deriving `Hash` but implementing `PartialEq` explicitly -[doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | checks for the presence of the `_` character outside ticks in documentation +[doc_markdown](https://github.com/Manishearth/rust-clippy/wiki#doc_markdown) | warn | checks for the presence of `_`, `::` or camel-case outside ticks in documentation [drop_ref](https://github.com/Manishearth/rust-clippy/wiki#drop_ref) | warn | call to `std::mem::drop` with a reference instead of an owned value, which will not call the `Drop::drop` method on the underlying value [duplicate_underscore_argument](https://github.com/Manishearth/rust-clippy/wiki#duplicate_underscore_argument) | warn | Function arguments having names which only differ by an underscore [empty_loop](https://github.com/Manishearth/rust-clippy/wiki#empty_loop) | warn | empty `loop {}` detected diff --git a/src/doc.rs b/src/doc.rs index 610aa34ab2c..a4a0448c102 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -4,22 +4,23 @@ use syntax::ast; use syntax::codemap::Span; use utils::span_lint; -/// **What it does:** This lint checks for the presence of the `_` character outside ticks in -/// documentation. +/// **What it does:** This lint checks for the presence of `_`, `::` or camel-case words outside +/// ticks in documentation. /// -/// **Why is this bad?** *Rustdoc* supports markdown formatting, the `_` character probably +/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and camel-case probably /// indicates some code which should be included between ticks. /// -/// **Known problems:** Lots of bad docs won’t be fixed, the lint only checks for `_`. +/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks for is limited. /// /// **Examples:** /// ```rust -/// /// Do something with the foo_bar parameter. +/// /// Do something with the foo_bar parameter. See also that::other::module::foo. +/// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar) { .. } /// ``` declare_lint! { pub DOC_MARKDOWN, Warn, - "checks for the presence of the `_` character outside ticks in documentation" + "checks for the presence of `_`, `::` or camel-case outside ticks in documentation" } #[derive(Copy,Clone)] @@ -71,10 +72,21 @@ fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { } } -fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_span: Span) { +pub fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_span: Span) { let (doc, span) = collect_doc(attrs); let span = span.unwrap_or(default_span); + // In markdown, `_` can be used to emphasize something, or, is a raw `_` depending on context. + // There really is no markdown specification that would disambiguate this properly. This is + // what GitHub and Rustdoc do: + // + // foo_bar test_quz → foo_bar test_quz + // foo_bar_baz → foo_bar_baz (note that the “official” spec says this should be emphasized) + // _foo bar_ test_quz_ → <em>foo bar</em> test_quz_ + // \_foo bar\_ → _foo bar_ + // (_baz_) → (<em>baz</em>) + // foo _ bar _ baz → foo _ bar _ baz + let mut in_ticks = false; for word in doc.split_whitespace() { let ticks = word.bytes().filter(|&b| b == b'`').count(); @@ -106,7 +118,16 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 } - if word.contains('_') || is_camel_case(word) { + fn has_underscore(s: &str) -> bool { + s != "_" && !s.contains("\\_") && s.contains('_') + } + + // Trim punctuation as in `some comment (see foo::bar).` + // ^^ + // Or even as `_foo bar_` which is emphasized. + let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + + if has_underscore(word) || word.contains("::") || is_camel_case(word) { span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word)); } } diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 9eb949a3b68..35b5857d937 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -6,9 +6,13 @@ #![deny(doc_markdown)] -/// The foo_bar function does nothing. -//~^ ERROR: you should put `foo_bar` between ticks +/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) +/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun +/// which should be reported only once despite being __doubly bad__. fn foo_bar() { +//~^ ERROR: you should put `foo_bar` between ticks +//~| ERROR: you should put `foo::bar` between ticks +//~| ERROR: you should put `Foo::some_fun` between ticks } /// That one tests multiline ticks. -- cgit 1.4.1-3-g733a5 From 371a5537eb0435fef43763d1bbbc21007ac707e4 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 28 Mar 2016 21:23:21 +0200 Subject: Address nits in DOC_MARKDOWN --- README.md | 2 +- src/bit_mask.rs | 34 +++++++++++++++++----------------- src/doc.rs | 4 +++- tests/compile-fail/doc.rs | 8 ++++++++ 4 files changed, 29 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 264bc6f010b..43caa80543a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 136 lints included in this crate: +There are 137 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 15fbabf9f0b..28fc311507d 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -13,14 +13,14 @@ use utils::span_lint; /// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` /// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: /// -/// |Comparison |Bit Op |Example |is always|Formula | -/// |------------|-------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// |Comparison |Bit Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// /// **Why is this bad?** If the bits that the comparison cares about are always set to zero or one by the bit mask, the comparison is constant `true` or `false` (depending on mask, compared value, and operators). /// @@ -61,21 +61,21 @@ declare_lint! { /// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , /// `!=`, `>=`, `>`}) can be determined from the following table: /// -/// |Comparison |Bit Op |Example |is always|Formula | -/// |------------|-------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// |Comparison |Bit Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | /// /// This lint is **deny** by default /// /// There is also a lint that warns on ineffective masks that is *warn* /// by default. /// -/// |Comparison| Bit Op |Example |equals |Formula| +/// |Comparison|Bit Op |Example |equals |Formula| /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`| /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` | /// diff --git a/src/doc.rs b/src/doc.rs index a4a0448c102..5637fb2cefb 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -8,7 +8,8 @@ use utils::span_lint; /// ticks in documentation. /// /// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and camel-case probably -/// indicates some code which should be included between ticks. +/// indicates some code which should be included between ticks. `_` can also be used for empasis in +/// markdown, this lint tries to consider that. /// /// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks for is limited. /// @@ -114,6 +115,7 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { s }; + 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/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 35b5857d937..eecf5e0b206 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -18,13 +18,21 @@ fn foo_bar() { /// That one tests multiline ticks. /// ```rust /// foo_bar FOO_BAR +/// _foo bar_ /// ``` fn multiline_ticks() { } +/// This _is a test for +/// multiline +/// emphasis_. +fn test_emphasis() { +} + /// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and /// `multiline_ticks` functions. fn main() { foo_bar(); multiline_ticks(); + test_emphasis(); } -- cgit 1.4.1-3-g733a5 From 777e810a394bdf8becc308704f7df5ade9321f79 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 28 Mar 2016 23:32:55 +0200 Subject: Add `for _ in vec![…]` to the `USELESS_VEC` lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/loops.rs | 26 +--------------------- src/utils/mod.rs | 24 ++++++++++++++++++++ src/vec.rs | 56 ++++++++++++++++++++++++++++------------------- tests/compile-fail/vec.rs | 7 ++++++ 4 files changed, 65 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 546f07a6507..10a8a76d7ae 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -14,7 +14,7 @@ use syntax::ast; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, - unsugar_range, walk_ptrs_ty}; + unsugar_range, walk_ptrs_ty, recover_for_loop}; use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; use utils::UnsugaredRange; @@ -641,30 +641,6 @@ impl<'a> Visitor<'a> for UsedVisitor { } } -/// Recover the essential nodes of a desugared for loop: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. -fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { - if_let_chain! { - [ - let ExprMatch(ref iterexpr, ref arms, _) = expr.node, - let ExprCall(_, ref iterargs) = iterexpr.node, - iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), - let ExprLoop(ref block, _) = arms[0].body.node, - block.stmts.is_empty(), - let Some(ref loopexpr) = block.expr, - let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, - innerarms.len() == 2 && innerarms[0].pats.len() == 1, - let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, - somepats.len() == 1 - ], { - return Some((&somepats[0], - &iterargs[0], - &innerarms[0].body)); - } - } - None -} - struct VarVisitor<'v, 't: 'v> { cx: &'v LateContext<'v, 't>, // context reference var: Name, // var name to look for as index diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 34404f4c2e9..300cb8df042 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -800,3 +800,27 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs); infcx.can_equate(&new_a, &new_b).is_ok() } + +/// Recover the essential nodes of a desugared for loop: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. +pub fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { + if_let_chain! { + [ + let ExprMatch(ref iterexpr, ref arms, _) = expr.node, + let ExprCall(_, ref iterargs) = iterexpr.node, + iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), + let ExprLoop(ref block, _) = arms[0].body.node, + block.stmts.is_empty(), + let Some(ref loopexpr) = block.expr, + let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, + innerarms.len() == 2 && innerarms[0].pats.len() == 1, + let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, + somepats.len() == 1 + ], { + return Some((&somepats[0], + &iterargs[0], + &innerarms[0].body)); + } + } + None +} diff --git a/src/vec.rs b/src/vec.rs index 481c84079f2..412ebf396dd 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -4,7 +4,7 @@ use rustc_front::hir::*; use syntax::codemap::Span; use syntax::ptr::P; use utils::VEC_FROM_ELEM_PATH; -use utils::{is_expn_of, match_path, snippet, span_lint_and_then}; +use utils::{is_expn_of, match_path, recover_for_loop, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. /// @@ -38,32 +38,42 @@ impl LateLintPass for UselessVec { let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, let TypeVariants::TySlice(..) = ty.ty.sty, let ExprAddrOf(_, ref addressee) = expr.node, - let Some(vec_args) = unexpand_vec(cx, addressee) ], { - let snippet = match vec_args { - VecArgs::Repeat(elem, len) => { - format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() - } - VecArgs::Vec(args) => { - if let Some(last) = args.iter().last() { - let span = Span { - lo: args[0].span.lo, - hi: last.span.hi, - expn_id: args[0].span.expn_id, - }; + check_vec_macro(cx, expr, addressee); + }} + + // search for `for _ in vec![…]` + if let Some((_, arg, _)) = recover_for_loop(expr) { + check_vec_macro(cx, arg, arg); + } + } +} + +fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) { + if let Some(vec_args) = unexpand_vec(cx, vec) { + let snippet = match vec_args { + VecArgs::Repeat(elem, len) => { + format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() + } + VecArgs::Vec(args) => { + if let Some(last) = args.iter().last() { + let span = Span { + lo: args[0].span.lo, + hi: last.span.hi, + expn_id: args[0].span.expn_id, + }; - format!("&[{}]", snippet(cx, span, "..")).into() - } - else { - "&[]".into() - } + format!("&[{}]", snippet(cx, span, "..")).into() + } + else { + "&[]".into() } - }; + } + }; - span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { - db.span_suggestion(expr.span, "you can use a slice directly", snippet); - }); - }} + span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { + db.span_suggestion(expr.span, "you can use a slice directly", snippet); + }); } } diff --git a/tests/compile-fail/vec.rs b/tests/compile-fail/vec.rs index b4f52ecadc5..eda75a2fe8a 100644 --- a/tests/compile-fail/vec.rs +++ b/tests/compile-fail/vec.rs @@ -41,4 +41,11 @@ fn main() { on_vec(&vec![]); on_vec(&vec![1, 2]); on_vec(&vec![1; 2]); + + for a in vec![1, 2, 3] { + //~^ ERROR useless use of `vec!` + //~| HELP you can use + //~| SUGGESTION for a in &[1, 2, 3] { + println!("{}", a); + } } -- cgit 1.4.1-3-g733a5 From 0939f5a2ec9797c9277b2dabd578429264da0498 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 29 Mar 2016 01:39:35 +0200 Subject: Fix false positive in `MATCH_SAME_ARMS` and guards --- src/copies.rs | 6 ++++-- tests/compile-fail/copies.rs | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 04f8aaa37e7..2de034f83c2 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -132,13 +132,15 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { }; let eq = |lhs: &Arm, rhs: &Arm| -> bool { - SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && + // Arms with a guard are ignored, those can’t always be merged together + lhs.guard.is_none() && rhs.guard.is_none() && + SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && // all patterns should have the same bindings bindings(cx, &lhs.pats[0]) == bindings(cx, &rhs.pats[0]) }; if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { - if let Some((i, j)) = search_same(&**arms, hash, eq) { + if let Some((i, j)) = search_same(&arms, hash, eq) { span_note_and_lint(cx, MATCH_SAME_ARMS, j.body.span, diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 66457e77f47..68756a57cc7 100644 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -142,12 +142,23 @@ fn if_same_then_else() -> Result<&'static str, ()> { _ => true, }; + let _ = match Some(42) { + Some(_) => 24, + None => 24, + }; + let _ = match Some(42) { Some(42) => 24, Some(a) => 24, // bindings are different None => 0, }; + let _ = match Some(42) { + Some(a) if a > 0 => 24, + Some(a) => 24, // one arm has a guard + None => 0, + }; + match (Some(42), Some(42)) { (Some(a), None) => bar(a), (None, Some(a)) => bar(a), //~ERROR this `match` has identical arm bodies -- cgit 1.4.1-3-g733a5 From 93d097eb12fc0b7e34187d2cac19b0059fa18ed4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 12:19:13 +0100 Subject: better simplification --- Cargo.toml | 1 + README.md | 3 +- src/booleans.rs | 155 ++++++++++++++++++++++++++++ src/lib.rs | 8 ++ tests/compile-fail/block_in_if_condition.rs | 2 +- tests/compile-fail/eq_op.rs | 2 + 6 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/booleans.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 3bb7a82f6e2..93886e214e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ regex_macros = { version = "0.1.33", optional = true } semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" +quine-mc_cluskey = "0.2" [dev-dependencies] compiletest_rs = "0.1.0" diff --git a/README.md b/README.md index 43caa80543a..cd8b0257c6e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 137 lints included in this crate: +There are 138 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -97,6 +97,7 @@ name [new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead +[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | warn | checks for boolean expressions that can be written more concisely [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result [option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` diff --git a/src/booleans.rs b/src/booleans.rs new file mode 100644 index 00000000000..90e4dee9769 --- /dev/null +++ b/src/booleans.rs @@ -0,0 +1,155 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use rustc_front::intravisit::*; +use syntax::ast::LitKind; +use utils::{span_lint_and_then, in_macro, snippet_opt}; + +/// **What it does:** This lint checks for boolean expressions that can be written more concisely +/// +/// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication +/// +/// **Known problems:** None +/// +/// **Example:** `if a && b || a` should be `if a` +declare_lint! { + pub NONMINIMAL_BOOL, Warn, + "checks for boolean expressions that can be written more concisely" +} + +#[derive(Copy,Clone)] +pub struct NonminimalBool; + +impl LintPass for NonminimalBool { + fn get_lints(&self) -> LintArray { + lint_array!(NONMINIMAL_BOOL) + } +} + +impl LateLintPass for NonminimalBool { + fn check_crate(&mut self, cx: &LateContext, krate: &Crate) { + krate.visit_all_items(&mut NonminimalBoolVisitor(cx)) + } +} + +struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); + +use quine_mc_cluskey::Bool; +struct Hir2Qmm<'tcx>(Vec<&'tcx Expr>); + +impl<'tcx> Hir2Qmm<'tcx> { + fn extract(&mut self, op: BinOp_, a: &[&'tcx Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> { + for a in a { + if let ExprBinary(binop, ref lhs, ref rhs) = a.node { + if binop.node == op { + v = self.extract(op, &[lhs, rhs], v)?; + continue; + } + } + v.push(self.run(a)?); + } + Ok(v) + } + + fn run(&mut self, e: &'tcx Expr) -> Result<Bool, String> { + match e.node { + ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), + ExprBinary(binop, ref lhs, ref rhs) => { + match binop.node { + BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), + 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), + _ => {}, + } + }, + _ => {}, + } + let n = self.0.len(); + self.0.push(e); + if n < 32 { + #[allow(cast_possible_truncation)] + Ok(Bool::Term(n as u8)) + } else { + Err("too many literals".to_owned()) + } + } +} + +fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { + fn recurse(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { + use quine_mc_cluskey::Bool::*; + match *suggestion { + True => { + s.extend("true".chars()); + s + }, + False => { + s.extend("false".chars()); + s + }, + Not(ref inner) => { + s.push('!'); + recurse(cx, inner, terminals, s) + }, + And(ref v) => { + s = recurse(cx, &v[0], terminals, s); + for inner in &v[1..] { + s.extend(" && ".chars()); + s = recurse(cx, inner, terminals, s); + } + s + }, + Or(ref v) => { + s = recurse(cx, &v[0], terminals, s); + for inner in &v[1..] { + s.extend(" || ".chars()); + s = recurse(cx, inner, terminals, s); + } + s + }, + Term(n) => { + s.extend(snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros").chars()); + s + } + } + } + recurse(cx, suggestion, terminals, String::new()) +} + +impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { + fn bool_expr(&self, e: &Expr) { + let mut h2q = Hir2Qmm(Vec::new()); + if let Ok(expr) = h2q.run(e) { + let simplified = expr.simplify(); + if !simplified.iter().any(|s| *s == expr) { + span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| { + for suggestion in &simplified { + db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.0)); + } + }); + } + } + } +} + +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) { 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.node_types()[&inner.id].is_bool() { + self.bool_expr(e); + } else { + walk_expr(self, e); + } + }, + _ => walk_expr(self, e), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 0a51385f6f2..575e318e7ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ #![feature(iter_arith)] #![feature(custom_attribute)] #![feature(slice_patterns)] +#![feature(question_mark)] +#![feature(stmt_expr_attributes)] #![allow(indexing_slicing, shadow_reuse, unknown_lints)] // this only exists to allow the "dogfood" integration test to work @@ -35,6 +37,9 @@ extern crate semver; // for regex checking extern crate regex_syntax; +// for finding minimal boolean expressions +extern crate quine_mc_cluskey; + extern crate rustc_plugin; extern crate rustc_const_eval; use rustc_plugin::Registry; @@ -50,6 +55,7 @@ pub mod attrs; pub mod bit_mask; pub mod blacklisted_name; pub mod block_in_if_condition; +pub mod booleans; pub mod collapsible_if; pub mod copies; pub mod cyclomatic_complexity; @@ -149,6 +155,7 @@ pub fn plugin_registrar(reg: &mut Registry) { // end deprecated lints, do not remove this comment, it’s used in `update_lints` reg.register_late_lint_pass(box types::TypePass); + reg.register_late_lint_pass(box booleans::NonminimalBool); reg.register_late_lint_pass(box misc::TopLevelRefPass); reg.register_late_lint_pass(box misc::CmpNan); reg.register_late_lint_pass(box eq_op::EqOp); @@ -260,6 +267,7 @@ pub fn plugin_registrar(reg: &mut Registry) { blacklisted_name::BLACKLISTED_NAME, block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, + booleans::NONMINIMAL_BOOL, collapsible_if::COLLAPSIBLE_IF, copies::IF_SAME_THEN_ELSE, copies::IFS_SAME_COND, diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index 5158e74c1e0..19fa949fb84 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -67,7 +67,7 @@ fn pred_test() { fn condition_is_normal() -> i32 { let x = 3; - if true && x == 3 { + if true && x == 3 { //~ WARN this boolean expression can be simplified 6 } else { 10 diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 487185516bf..bd76695e6ad 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -38,7 +38,9 @@ fn main() { 1 - 1; //~ERROR equal expressions 1 / 1; //~ERROR equal expressions true && true; //~ERROR equal expressions + //~|WARN this boolean expression can be simplified true || true; //~ERROR equal expressions + //~|WARN this boolean expression can be simplified let mut a = vec![1]; a == a; //~ERROR equal expressions -- cgit 1.4.1-3-g733a5 From 57faa5a9f58026ab167c1024c5a3b924156522c3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 12:49:16 +0100 Subject: improve bracket display --- src/booleans.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 90e4dee9769..5b29d33e891 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -81,7 +81,7 @@ impl<'tcx> Hir2Qmm<'tcx> { } fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { - fn recurse(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { + fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { use quine_mc_cluskey::Bool::*; match *suggestion { True => { @@ -94,21 +94,33 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { }, Not(ref inner) => { s.push('!'); - recurse(cx, inner, terminals, s) + recurse(true, cx, inner, terminals, s) }, And(ref v) => { - s = recurse(cx, &v[0], terminals, s); + if brackets { + s.push('('); + } + s = recurse(true, cx, &v[0], terminals, s); for inner in &v[1..] { s.extend(" && ".chars()); - s = recurse(cx, inner, terminals, s); + s = recurse(true, cx, inner, terminals, s); + } + if brackets { + s.push(')'); } s }, Or(ref v) => { - s = recurse(cx, &v[0], terminals, s); + if brackets { + s.push('('); + } + s = recurse(true, cx, &v[0], terminals, s); for inner in &v[1..] { s.extend(" || ".chars()); - s = recurse(cx, inner, terminals, s); + s = recurse(true, cx, inner, terminals, s); + } + if brackets { + s.push(')'); } s }, @@ -118,7 +130,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { } } } - recurse(cx, suggestion, terminals, String::new()) + recurse(false, cx, suggestion, terminals, String::new()) } impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { -- cgit 1.4.1-3-g733a5 From 1f1f09ba92b997388d7a653c6515fb4ab4e4a888 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 12:52:17 +0100 Subject: also compute minimal product of sum form --- src/booleans.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 5b29d33e891..178cef3aada 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -133,11 +133,40 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { recurse(false, cx, suggestion, terminals, String::new()) } +fn simple_negate(b: Bool) -> Bool { + use quine_mc_cluskey::Bool::*; + match b { + True => False, + False => True, + t @ Term(_) => Not(Box::new(t)), + And(mut v) => { + for el in &mut v { + *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, + } +} + impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { fn bool_expr(&self, e: &Expr) { let mut h2q = Hir2Qmm(Vec::new()); if let Ok(expr) = h2q.run(e) { - let simplified = expr.simplify(); + let mut simplified = expr.simplify(); + for simple in Bool::Not(Box::new(expr.clone())).simplify() { + let simple_negated = simple_negate(simple); + if simplified.iter().any(|s| *s == simple_negated) { + continue; + } + simplified.push(simple_negated); + } if !simplified.iter().any(|s| *s == expr) { span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| { for suggestion in &simplified { -- cgit 1.4.1-3-g733a5 From 25ed62ff23eca4b6757bbd18f53061feebb09ae4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 14:45:51 +0100 Subject: improve lint attribute detail --- src/booleans.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 178cef3aada..12cec565271 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -26,8 +26,8 @@ impl LintPass for NonminimalBool { } impl LateLintPass for NonminimalBool { - fn check_crate(&mut self, cx: &LateContext, krate: &Crate) { - krate.visit_all_items(&mut NonminimalBoolVisitor(cx)) + fn check_item(&mut self, cx: &LateContext, item: &Item) { + NonminimalBoolVisitor(cx).visit_item(item) } } -- cgit 1.4.1-3-g733a5 From 5911ccaba8ff0a308660c83e4d307609f8236146 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 14:50:08 +0100 Subject: merge multiple equal terminals into one --- src/booleans.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 12cec565271..4369a05d2d8 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -34,10 +34,13 @@ impl LateLintPass for NonminimalBool { struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); use quine_mc_cluskey::Bool; -struct Hir2Qmm<'tcx>(Vec<&'tcx Expr>); +struct Hir2Qmm<'a, 'tcx: 'a, 'v> { + terminals: Vec<&'v Expr>, + cx: &'a LateContext<'a, 'tcx> +} -impl<'tcx> Hir2Qmm<'tcx> { - fn extract(&mut self, op: BinOp_, a: &[&'tcx Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> { +impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { + fn extract(&mut self, op: BinOp_, a: &[&'v Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> { for a in a { if let ExprBinary(binop, ref lhs, ref rhs) = a.node { if binop.node == op { @@ -50,7 +53,7 @@ impl<'tcx> Hir2Qmm<'tcx> { Ok(v) } - fn run(&mut self, e: &'tcx Expr) -> Result<Bool, String> { + fn run(&mut self, e: &'v Expr) -> Result<Bool, String> { match e.node { ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), ExprBinary(binop, ref lhs, ref rhs) => { @@ -69,8 +72,15 @@ impl<'tcx> Hir2Qmm<'tcx> { }, _ => {}, } - let n = self.0.len(); - self.0.push(e); + if let Some((n, _)) = self.terminals + .iter() + .enumerate() + .find(|&(_, expr)| SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr)) { + #[allow(cast_possible_truncation)] + return Ok(Bool::Term(n as u8)); + } + let n = self.terminals.len(); + self.terminals.push(e); if n < 32 { #[allow(cast_possible_truncation)] Ok(Bool::Term(n as u8)) @@ -157,7 +167,10 @@ fn simple_negate(b: Bool) -> Bool { impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { fn bool_expr(&self, e: &Expr) { - let mut h2q = Hir2Qmm(Vec::new()); + let mut h2q = Hir2Qmm { + terminals: Vec::new(), + cx: self.0, + }; if let Ok(expr) = h2q.run(e) { let mut simplified = expr.simplify(); for simple in Bool::Not(Box::new(expr.clone())).simplify() { @@ -170,7 +183,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { if !simplified.iter().any(|s| *s == expr) { span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| { for suggestion in &simplified { - db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.0)); + db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals)); } }); } -- cgit 1.4.1-3-g733a5 From 050d7fd30805dcc995cd99575af2ff4db3ae0b90 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 23 Mar 2016 14:50:47 +0100 Subject: fallout and tests --- src/booleans.rs | 6 +++--- src/non_expressive_names.rs | 2 +- tests/compile-fail/block_in_if_condition.rs | 1 + tests/compile-fail/booleans.rs | 24 ++++++++++++++++++++++++ tests/compile-fail/eq_op.rs | 5 +++-- 5 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/booleans.rs (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 4369a05d2d8..e9197cf85c6 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -2,17 +2,17 @@ use rustc::lint::*; use rustc_front::hir::*; use rustc_front::intravisit::*; use syntax::ast::LitKind; -use utils::{span_lint_and_then, in_macro, snippet_opt}; +use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// **What it does:** This lint checks for boolean expressions that can be written more concisely /// /// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication /// -/// **Known problems:** None +/// **Known problems:** Ignores short circuting behavior, bitwise and/or and xor. Ends up suggesting things like !(a == b) /// /// **Example:** `if a && b || a` should be `if a` declare_lint! { - pub NONMINIMAL_BOOL, Warn, + pub NONMINIMAL_BOOL, Allow, "checks for boolean expressions that can be written more concisely" } diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index d7cb6fc5d28..87373c7a0de 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -262,7 +262,7 @@ fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { } if let Some(b2) = b_chars.next() { // check if there's just one character inserted - return !(a == b2 && a_chars.eq(b_chars)); + return a != b2 || a_chars.ne(b_chars); } else { // tuple // ntuple diff --git a/tests/compile-fail/block_in_if_condition.rs b/tests/compile-fail/block_in_if_condition.rs index 19fa949fb84..3d47fc74a11 100644 --- a/tests/compile-fail/block_in_if_condition.rs +++ b/tests/compile-fail/block_in_if_condition.rs @@ -4,6 +4,7 @@ #![deny(block_in_if_condition_expr)] #![deny(block_in_if_condition_stmt)] #![allow(unused, let_and_return)] +#![warn(nonminimal_bool)] macro_rules! blocky { diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs new file mode 100644 index 00000000000..ed989c0e84b --- /dev/null +++ b/tests/compile-fail/booleans.rs @@ -0,0 +1,24 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(nonminimal_bool)] + +#[allow(unused)] +fn main() { + let a: bool = unimplemented!(); + let b: bool = unimplemented!(); + let _ = a && b || a; //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = a; + let _ = !(a && b); //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = !b || !a; + let _ = !true; //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = false; + let _ = !false; //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = true; + let _ = !!a; //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = a; +} diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index bd76695e6ad..d49dcc6f84b 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -4,6 +4,7 @@ #[deny(eq_op)] #[allow(identity_op)] #[allow(no_effect)] +#[deny(nonminimal_bool)] fn main() { // simple values and comparisons 1 == 1; //~ERROR equal expressions @@ -38,9 +39,9 @@ fn main() { 1 - 1; //~ERROR equal expressions 1 / 1; //~ERROR equal expressions true && true; //~ERROR equal expressions - //~|WARN this boolean expression can be simplified + //~|ERROR this boolean expression can be simplified true || true; //~ERROR equal expressions - //~|WARN this boolean expression can be simplified + //~|ERROR this boolean expression can be simplified let mut a = vec![1]; a == a; //~ERROR equal expressions -- cgit 1.4.1-3-g733a5 From 288ea799637dee4b2250069af41b44a8facaa52f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 09:37:16 +0100 Subject: treat macros as terminals to prevent `cfg!` from giving platform specific hints --- src/booleans.rs | 37 ++++++++++++++++++++----------------- tests/compile-fail/booleans.rs | 3 +++ 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index e9197cf85c6..1b4d661da84 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -54,23 +54,26 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } fn run(&mut self, e: &'v Expr) -> Result<Bool, String> { - match e.node { - ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), - ExprBinary(binop, ref lhs, ref rhs) => { - match binop.node { - BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), - 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), - _ => {}, - } - }, - _ => {}, + // prevent folding of `cfg!` macros and the like + if !in_macro(self.cx, e.span) { + match e.node { + ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), + ExprBinary(binop, ref lhs, ref rhs) => { + match binop.node { + BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), + 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), + _ => {}, + } + }, + _ => {}, + } } if let Some((n, _)) = self.terminals .iter() diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 8130e535773..f9bf1a15f18 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -29,4 +29,7 @@ fn main() { let _ = false || a; //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit //|~ SUGGESTION let _ = a; + + // don't lint on cfgs + let _ = cfg!(you_shall_not_not_pass) && a; } -- cgit 1.4.1-3-g733a5 From 03833f666fccad492746304d818a4afbe679ccf3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 10:45:24 +0100 Subject: differentiate between logic bugs and optimizable expressions --- src/booleans.rs | 71 ++++++++++++++++++++++++++++++++++++++---- tests/compile-fail/booleans.rs | 10 ++++-- 2 files changed, 72 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 1b4d661da84..49371de5c9d 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -10,18 +10,30 @@ use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// /// **Known problems:** Ignores short circuting behavior, bitwise and/or and xor. Ends up suggesting things like !(a == b) /// -/// **Example:** `if a && b || a` should be `if a` +/// **Example:** `if a && true` should be `if a` declare_lint! { pub NONMINIMAL_BOOL, Allow, "checks for boolean expressions that can be written more concisely" } +/// **What it does:** This lint checks for boolean expressions that contain terminals that can be eliminated +/// +/// **Why is this bad?** This is most likely a logic bug +/// +/// **Known problems:** Ignores short circuiting behavior +/// +/// **Example:** The `b` in `if a && b || a` is unnecessary because the expression is equivalent to `if a` +declare_lint! { + pub LOGIC_BUG, Warn, + "checks for boolean expressions that contain terminals which can be eliminated" +} + #[derive(Copy,Clone)] pub struct NonminimalBool; impl LintPass for NonminimalBool { fn get_lints(&self) -> LintArray { - lint_array!(NONMINIMAL_BOOL) + lint_array!(NONMINIMAL_BOOL, LOGIC_BUG) } } @@ -168,6 +180,23 @@ fn simple_negate(b: Bool) -> Bool { } } +fn terminal_stats(b: &Bool) -> [usize; 32] { + fn recurse(b: &Bool, stats: &mut [usize; 32]) { + match *b { + True | False => {}, + Not(ref inner) => recurse(inner, stats), + And(ref v) | Or(ref v) => for inner in v { + recurse(inner, stats) + }, + Term(n) => stats[n as usize] += 1, + } + } + use quine_mc_cluskey::Bool::*; + let mut stats = [0; 32]; + recurse(b, &mut stats); + stats +} + impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { fn bool_expr(&self, e: &Expr) { let mut h2q = Hir2Qmm { @@ -175,6 +204,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { cx: self.0, }; if let Ok(expr) = h2q.run(e) { + let stats = terminal_stats(&expr); let mut simplified = expr.simplify(); for simple in Bool::Not(Box::new(expr.clone())).simplify() { let simple_negated = simple_negate(simple); @@ -184,11 +214,40 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { simplified.push(simple_negated); } if !simplified.iter().any(|s| *s == expr) { - span_lint_and_then(self.0, NONMINIMAL_BOOL, e.span, "this boolean expression can be simplified", |db| { - for suggestion in &simplified { - db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals)); + let mut improvements = Vec::new(); + 'simplified: for suggestion in &simplified { + let simplified_stats = terminal_stats(&suggestion); + let mut improvement = false; + for i in 0..32 { + // ignore any "simplifications" that end up requiring a terminal more often than in the original expression + if stats[i] < simplified_stats[i] { + continue 'simplified; + } + // if the number of occurrences of a terminal decreases, this expression is a candidate for improvement + if stats[i] >= simplified_stats[i] { + improvement = true; + } + if stats[i] != 0 && simplified_stats[i] == 0 { + span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| { + db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression"); + db.span_suggestion(e.span, "it would look like the following", suggest(self.0, suggestion, &h2q.terminals)); + }); + // don't also lint `NONMINIMAL_BOOL` + improvements.clear(); + break 'simplified; + } } - }); + if improvement { + improvements.push(suggestion); + } + } + if !improvements.is_empty() { + span_lint_and_then(self.0, 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)); + } + }); + } } } } diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index f9bf1a15f18..31c160980fc 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -1,13 +1,15 @@ #![feature(plugin)] #![plugin(clippy)] -#![deny(nonminimal_bool)] +#![deny(nonminimal_bool, logic_bug)] #[allow(unused)] fn main() { let a: bool = unimplemented!(); let b: bool = unimplemented!(); - let _ = a && b || a; //~ ERROR this boolean expression can be simplified + let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug //|~ HELP for further information visit + //|~ HELP this expression can be optimized out + //|~ HELP it would look like the following //|~ SUGGESTION let _ = a; let _ = !(a && b); //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit @@ -22,8 +24,10 @@ fn main() { //|~ HELP for further information visit //|~ SUGGESTION let _ = a; - let _ = false && a; //~ ERROR this boolean expression can be simplified + let _ = false && a; //~ ERROR this boolean expression contains a logic bug //|~ HELP for further information visit + //|~ HELP this expression can be optimized out + //|~ HELP it would look like the following //|~ SUGGESTION let _ = false; let _ = false || a; //~ ERROR this boolean expression can be simplified -- cgit 1.4.1-3-g733a5 From 37cee84c44ff2e020504f6ee6e762452b525b8c7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 10:54:48 +0100 Subject: negations around expressions can make things simpler --- src/booleans.rs | 4 ++++ tests/compile-fail/booleans.rs | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 49371de5c9d..e290b896b1d 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -207,6 +207,10 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { let stats = terminal_stats(&expr); let mut simplified = expr.simplify(); for simple in Bool::Not(Box::new(expr.clone())).simplify() { + match simple { + Bool::Not(_) | Bool::True | Bool::False => {}, + _ => simplified.push(Bool::Not(Box::new(simple.clone()))), + } let simple_negated = simple_negate(simple); if simplified.iter().any(|s| *s == simple_negated) { continue; diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 31c160980fc..4630a4635b4 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -6,14 +6,13 @@ fn main() { let a: bool = unimplemented!(); let b: bool = unimplemented!(); + let c: bool = unimplemented!(); let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug //|~ HELP for further information visit //|~ HELP this expression can be optimized out //|~ HELP it would look like the following //|~ SUGGESTION let _ = a; - let _ = !(a && b); //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = !b || !a; + let _ = !(a && b); let _ = !true; //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit //|~ SUGGESTION let _ = false; @@ -36,4 +35,6 @@ fn main() { // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; + + let _ = !(a && b || c); } -- cgit 1.4.1-3-g733a5 From 76ab80100177403a1a860ce4f01c5e791377afb0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 10:58:57 +0100 Subject: if a < b { ... } if a >= b { ... } what am I doing? --- src/booleans.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index e290b896b1d..f4437249b4c 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -227,10 +227,8 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { if stats[i] < simplified_stats[i] { continue 'simplified; } - // if the number of occurrences of a terminal decreases, this expression is a candidate for improvement - if stats[i] >= simplified_stats[i] { - improvement = true; - } + // if the number of occurrences of a terminal doesn't increase, this expression is a candidate for improvement + improvement = true; if stats[i] != 0 && simplified_stats[i] == 0 { span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| { db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression"); -- cgit 1.4.1-3-g733a5 From e7013a3e9c7e8b3cfe2825fe0d3c803b67001b20 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 11:02:28 +0100 Subject: update lints --- README.md | 3 ++- src/booleans.rs | 2 +- src/lib.rs | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index cd8b0257c6e..188e272dc4d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 138 lints included in this crate: +There are 139 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -75,6 +75,7 @@ name [let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block [let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards [linkedlist](https://github.com/Manishearth/rust-clippy/wiki#linkedlist) | warn | usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque +[logic_bug](https://github.com/Manishearth/rust-clippy/wiki#logic_bug) | warn | checks for boolean expressions that contain terminals which can be eliminated [manual_swap](https://github.com/Manishearth/rust-clippy/wiki#manual_swap) | warn | manual swap [many_single_char_names](https://github.com/Manishearth/rust-clippy/wiki#many_single_char_names) | warn | too many single character bindings [map_clone](https://github.com/Manishearth/rust-clippy/wiki#map_clone) | warn | using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends `.cloned()` instead) diff --git a/src/booleans.rs b/src/booleans.rs index f4437249b4c..c156a893c62 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -12,7 +12,7 @@ use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// /// **Example:** `if a && true` should be `if a` declare_lint! { - pub NONMINIMAL_BOOL, Allow, + pub NONMINIMAL_BOOL, Warn, "checks for boolean expressions that can be written more concisely" } diff --git a/src/lib.rs b/src/lib.rs index 575e318e7ad..617d2e24266 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -267,6 +267,7 @@ pub fn plugin_registrar(reg: &mut Registry) { blacklisted_name::BLACKLISTED_NAME, block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, + booleans::LOGIC_BUG, booleans::NONMINIMAL_BOOL, collapsible_if::COLLAPSIBLE_IF, copies::IF_SAME_THEN_ELSE, -- cgit 1.4.1-3-g733a5 From 0f92f84f16778d6921f22079ffd5141cec2dbc6b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 15:36:50 +0100 Subject: String::extend -> String::push_str --- src/booleans.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index c156a893c62..ea05d65ac9c 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -1,4 +1,4 @@ -use rustc::lint::*; +use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; use rustc_front::hir::*; use rustc_front::intravisit::*; use syntax::ast::LitKind; @@ -110,11 +110,11 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { use quine_mc_cluskey::Bool::*; match *suggestion { True => { - s.extend("true".chars()); + s.push_str("true"); s }, False => { - s.extend("false".chars()); + s.push_str("false"); s }, Not(ref inner) => { @@ -127,7 +127,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { } s = recurse(true, cx, &v[0], terminals, s); for inner in &v[1..] { - s.extend(" && ".chars()); + s.push_str(" && "); s = recurse(true, cx, inner, terminals, s); } if brackets { @@ -141,7 +141,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { } s = recurse(true, cx, &v[0], terminals, s); for inner in &v[1..] { - s.extend(" || ".chars()); + s.push_str(" || "); s = recurse(true, cx, inner, terminals, s); } if brackets { @@ -150,7 +150,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s }, Term(n) => { - s.extend(snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros").chars()); + s.push_str(&snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros")); s } } -- cgit 1.4.1-3-g733a5 From dd6bee3b3f653d01415b9be3245654b036390718 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 15:37:17 +0100 Subject: collect stats on bool ops and negations in an expression --- src/booleans.rs | 89 ++++++++++++++++++++++++------------------ tests/compile-fail/booleans.rs | 10 ++++- 2 files changed, 61 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index ea05d65ac9c..9da594424ff 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -180,19 +180,35 @@ fn simple_negate(b: Bool) -> Bool { } } -fn terminal_stats(b: &Bool) -> [usize; 32] { - fn recurse(b: &Bool, stats: &mut [usize; 32]) { +#[derive(Default)] +struct Stats { + terminals: [usize; 32], + negations: usize, + ops: usize, +} + +fn terminal_stats(b: &Bool) -> Stats { + fn recurse(b: &Bool, stats: &mut Stats) { match *b { - True | False => {}, - Not(ref inner) => recurse(inner, stats), - And(ref v) | Or(ref v) => for inner in v { - recurse(inner, stats) + True | False => stats.ops += 1, + Not(ref inner) => { + match **inner { + And(_) | Or(_) => stats.ops += 1, // brackets are also operations + _ => stats.negations += 1, + } + recurse(inner, stats); }, - Term(n) => stats[n as usize] += 1, + 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, } } use quine_mc_cluskey::Bool::*; - let mut stats = [0; 32]; + let mut stats = Stats::default(); recurse(b, &mut stats); stats } @@ -217,40 +233,39 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } simplified.push(simple_negated); } - if !simplified.iter().any(|s| *s == expr) { - let mut improvements = Vec::new(); - 'simplified: for suggestion in &simplified { - let simplified_stats = terminal_stats(&suggestion); - let mut improvement = false; - for i in 0..32 { - // ignore any "simplifications" that end up requiring a terminal more often than in the original expression - if stats[i] < simplified_stats[i] { - continue 'simplified; - } - // if the number of occurrences of a terminal doesn't increase, this expression is a candidate for improvement - improvement = true; - if stats[i] != 0 && simplified_stats[i] == 0 { - span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| { - db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression"); - db.span_suggestion(e.span, "it would look like the following", suggest(self.0, suggestion, &h2q.terminals)); - }); - // don't also lint `NONMINIMAL_BOOL` - improvements.clear(); - break 'simplified; - } + let mut improvements = Vec::new(); + 'simplified: for suggestion in &simplified { + let simplified_stats = terminal_stats(&suggestion); + let mut improvement = false; + for i in 0..32 { + // ignore any "simplifications" that end up requiring a terminal more often than in the original expression + if stats.terminals[i] < simplified_stats.terminals[i] { + continue 'simplified; } - if improvement { - improvements.push(suggestion); + if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { + span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| { + db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression"); + db.span_suggestion(e.span, "it would look like the following", suggest(self.0, suggestion, &h2q.terminals)); + }); + // don't also lint `NONMINIMAL_BOOL` + return; } + // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases + improvement = (stats.terminals[i] > simplified_stats.terminals[i]) || + (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || + (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); } - if !improvements.is_empty() { - span_lint_and_then(self.0, 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)); - } - }); + if improvement { + improvements.push(suggestion); } } + if !improvements.is_empty() { + span_lint_and_then(self.0, 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)); + } + }); + } } } } diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 4630a4635b4..5d39c44e7bf 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -2,11 +2,13 @@ #![plugin(clippy)] #![deny(nonminimal_bool, logic_bug)] -#[allow(unused)] +#[allow(unused, many_single_char_names)] fn main() { let a: bool = unimplemented!(); let b: bool = unimplemented!(); let c: bool = unimplemented!(); + let d: bool = unimplemented!(); + let e: bool = unimplemented!(); let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug //|~ HELP for further information visit //|~ HELP this expression can be optimized out @@ -36,5 +38,11 @@ fn main() { // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; + let _ = a || !b || !c || !d || !e; + let _ = !(a && b || c); + + let _ = !(!a && b); //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = !b || a; } -- cgit 1.4.1-3-g733a5 From 25bbde091a9cf1f903b9dc418de2920c1a099c1f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 16:02:26 +0100 Subject: a small refactoring for readability --- src/booleans.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 9da594424ff..2de59c9bc59 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -87,12 +87,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => {}, } } - if let Some((n, _)) = self.terminals - .iter() - .enumerate() - .find(|&(_, expr)| SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr)) { - #[allow(cast_possible_truncation)] - return Ok(Bool::Term(n as u8)); + for (n, expr) in self.terminals.iter().enumerate() { + if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { + #[allow(cast_possible_truncation)] + return Ok(Bool::Term(n as u8)); + } } let n = self.terminals.len(); self.terminals.push(e); -- cgit 1.4.1-3-g733a5 From 3a0791e68080297fe7b8d622f037037108e67148 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 16:11:38 +0100 Subject: make sure `a < b` and `a >= b` are considered equal by SpanlessEq --- src/utils/hir.rs | 20 +++++++++++++++++++- tests/compile-fail/booleans.rs | 3 +++ tests/compile-fail/eq_op.rs | 14 +++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 20c7e33fbb2..0659e26d0f2 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -75,7 +75,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } (&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) + 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), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), @@ -197,6 +198,23 @@ 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)), + BiLt => Some((BiGt, rhs, lhs)), + BiLe => Some((BiGe, rhs, lhs)), + BiGe => Some((BiLe, rhs, lhs)), + BiGt => Some((BiLt, rhs, lhs)), + BiShl | BiShr | BiRem | BiSub | BiDiv | BiAnd | BiOr => None, + } +} + /// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 61a8edaabbd..43528f5c5df 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -58,6 +58,9 @@ fn equality_stuff() { let _ = a == b && c == 5 && a == b; //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit //|~ SUGGESTION let _ = c == 5 && a == b; + let _ = a == b && c == 5 && b == a; //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = c == 5 && a == b; let _ = a < b && a >= b; let _ = a > b && a <= b; let _ = a > b && a == b; diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index d49dcc6f84b..443bbbaacd3 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -3,7 +3,7 @@ #[deny(eq_op)] #[allow(identity_op)] -#[allow(no_effect)] +#[allow(no_effect, unused_variables)] #[deny(nonminimal_bool)] fn main() { // simple values and comparisons @@ -43,6 +43,18 @@ fn main() { true || true; //~ERROR equal expressions //~|ERROR this boolean expression can be simplified + let a: u32 = unimplemented!(); + let b: u32 = unimplemented!(); + + a == b && b == a; //~ERROR equal expressions + //~|ERROR this boolean expression can be simplified + a != b && b != a; //~ERROR equal expressions + //~|ERROR this boolean expression can be simplified + a < b && b > a; //~ERROR equal expressions + //~|ERROR this boolean expression can be simplified + a <= b && b >= a; //~ERROR equal expressions + //~|ERROR this boolean expression can be simplified + let mut a = vec![1]; a == a; //~ERROR equal expressions 2*a.len() == 2*a.len(); // ok, functions -- cgit 1.4.1-3-g733a5 From 96be287f12ff4199b3b1005a22a2dd7c1f01f5bf Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 24 Mar 2016 16:29:20 +0100 Subject: detect negations of terminals like a != b vs a == b --- src/booleans.rs | 27 ++++++++++++++++++++++++++- tests/compile-fail/booleans.rs | 18 +++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 2de59c9bc59..b43f2297311 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -1,7 +1,8 @@ use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; use rustc_front::hir::*; use rustc_front::intravisit::*; -use syntax::ast::LitKind; +use syntax::ast::{LitKind, DUMMY_NODE_ID}; +use syntax::codemap::{DUMMY_SP, dummy_spanned}; use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// **What it does:** This lint checks for boolean expressions that can be written more concisely @@ -92,6 +93,30 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { #[allow(cast_possible_truncation)] return Ok(Bool::Term(n as u8)); } + let negated = match e.node { + ExprBinary(binop, ref lhs, ref rhs) => { + let mk_expr = |op| Expr { + id: DUMMY_NODE_ID, + span: DUMMY_SP, + attrs: None, + node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), + }; + match binop.node { + BiEq => mk_expr(BiNe), + BiNe => mk_expr(BiEq), + BiGt => mk_expr(BiLe), + BiGe => mk_expr(BiLt), + BiLt => mk_expr(BiGe), + BiLe => mk_expr(BiGt), + _ => continue, + } + }, + _ => continue, + }; + if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { + #[allow(cast_possible_truncation)] + return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); + } } let n = self.terminals.len(); self.terminals.push(e); diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 43528f5c5df..4ad51226d51 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -54,14 +54,26 @@ fn equality_stuff() { let c: i32 = unimplemented!(); let d: i32 = unimplemented!(); let e: i32 = unimplemented!(); - let _ = a == b && a != b; + let _ = a == b && a != b; //~ ERROR this boolean expression contains a logic bug + //|~ HELP for further information visit + //|~ HELP this expression can be optimized out + //|~ HELP it would look like the following + //|~ SUGGESTION let _ = false; let _ = a == b && c == 5 && a == b; //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit //|~ SUGGESTION let _ = c == 5 && a == b; let _ = a == b && c == 5 && b == a; //~ ERROR this boolean expression can be simplified //|~ HELP for further information visit //|~ SUGGESTION let _ = c == 5 && a == b; - let _ = a < b && a >= b; - let _ = a > b && a <= b; + let _ = a < b && a >= b; //~ ERROR this boolean expression contains a logic bug + //|~ HELP for further information visit + //|~ HELP this expression can be optimized out + //|~ HELP it would look like the following + //|~ SUGGESTION let _ = false; + let _ = a > b && a <= b; //~ ERROR this boolean expression contains a logic bug + //|~ HELP for further information visit + //|~ HELP this expression can be optimized out + //|~ HELP it would look like the following + //|~ SUGGESTION let _ = false; let _ = a > b && a == b; } -- cgit 1.4.1-3-g733a5 From 216edbae59463538045f953c21d877b5f906caf2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 29 Mar 2016 16:27:06 +0200 Subject: accidentally forgot about improvements if there were multiplie candidates --- Cargo.toml | 2 +- src/booleans.rs | 2 +- tests/compile-fail/booleans.rs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index c07a0bf5e24..058dc012cfa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ regex_macros = { version = "0.1.33", optional = true } semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" -quine-mc_cluskey = "0.2.1" +quine-mc_cluskey = "0.2.2" [dev-dependencies] compiletest_rs = "0.1.0" diff --git a/src/booleans.rs b/src/booleans.rs index b43f2297311..b603d5188aa 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { return; } // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases - improvement = (stats.terminals[i] > simplified_stats.terminals[i]) || + improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); } diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index ecaa52019c6..008e6dcdda9 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -77,5 +77,8 @@ fn equality_stuff() { //|~ SUGGESTION let _ = false; let _ = a > b && a == b; - let _ = a != b || !(a != b || c == d); + let _ = a != b || !(a != b || c == d); //~ ERROR this boolean expression can be simplified + //|~ HELP for further information visit + //|~ SUGGESTION let _ = !c == d || a != b; + //|~ SUGGESTION let _ = !(!a != b && c == d); } -- cgit 1.4.1-3-g733a5 From b05dd13f2c5199bc2e97a5b5e6910b1cde4be988 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 29 Mar 2016 16:55:38 +0200 Subject: added brackets and fixed compiler comments --- src/booleans.rs | 29 +++++++++++++--- tests/compile-fail/booleans.rs | 77 ++++++++++++++++++++++-------------------- 2 files changed, 64 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index b603d5188aa..0cfab9a5357 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -129,6 +129,15 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } } +macro_rules! brackets { + ($val:expr => $($name:ident),*) => { + match $val { + $($name(_) => true,)* + _ => false, + } + } +} + fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { use quine_mc_cluskey::Bool::*; @@ -143,16 +152,16 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { }, Not(ref inner) => { s.push('!'); - recurse(true, cx, inner, terminals, s) + recurse(brackets!(**inner => And, Or, Term), cx, inner, terminals, s) }, And(ref v) => { if brackets { s.push('('); } - s = recurse(true, cx, &v[0], terminals, s); + s = recurse(brackets!(v[0] => Or), cx, &v[0], terminals, s); for inner in &v[1..] { s.push_str(" && "); - s = recurse(true, cx, inner, terminals, s); + s = recurse(brackets!(*inner => Or), cx, inner, terminals, s); } if brackets { s.push(')'); @@ -163,10 +172,10 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { if brackets { s.push('('); } - s = recurse(true, cx, &v[0], terminals, s); + s = recurse(false, cx, &v[0], terminals, s); for inner in &v[1..] { s.push_str(" || "); - s = recurse(true, cx, inner, terminals, s); + s = recurse(false, cx, inner, terminals, s); } if brackets { s.push(')'); @@ -174,7 +183,17 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s }, Term(n) => { + if brackets { + if let ExprBinary(..) = terminals[n as usize].node { + s.push('('); + } + } s.push_str(&snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros")); + if brackets { + if let ExprBinary(..) = terminals[n as usize].node { + s.push(')'); + } + } s } } diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index 008e6dcdda9..f4760a6fd46 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -10,30 +10,30 @@ fn main() { let d: bool = unimplemented!(); let e: bool = unimplemented!(); let _ = a && b || a; //~ ERROR this boolean expression contains a logic bug - //|~ HELP for further information visit - //|~ HELP this expression can be optimized out - //|~ HELP it would look like the following - //|~ SUGGESTION let _ = a; + //~| HELP for further information visit + //~| HELP this expression can be optimized out + //~| HELP it would look like the following + //~| SUGGESTION let _ = a; let _ = !(a && b); let _ = !true; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = false; + //~| HELP for further information visit + //~| SUGGESTION let _ = false; let _ = !false; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = true; + //~| HELP for further information visit + //~| SUGGESTION let _ = true; let _ = !!a; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = a; + //~| HELP for further information visit + //~| SUGGESTION let _ = a; let _ = false && a; //~ ERROR this boolean expression contains a logic bug - //|~ HELP for further information visit - //|~ HELP this expression can be optimized out - //|~ HELP it would look like the following - //|~ SUGGESTION let _ = false; + //~| HELP for further information visit + //~| HELP this expression can be optimized out + //~| HELP it would look like the following + //~| SUGGESTION let _ = false; let _ = false || a; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = a; + //~| HELP for further information visit + //~| SUGGESTION let _ = a; // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; @@ -43,8 +43,8 @@ fn main() { let _ = !(a && b || c); let _ = !(!a && b); //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = !b || a; + //~| HELP for further information visit + //~| SUGGESTION let _ = !b || a; } #[allow(unused, many_single_char_names)] @@ -55,30 +55,33 @@ fn equality_stuff() { let d: i32 = unimplemented!(); let e: i32 = unimplemented!(); let _ = a == b && a != b; //~ ERROR this boolean expression contains a logic bug - //|~ HELP for further information visit - //|~ HELP this expression can be optimized out - //|~ HELP it would look like the following - //|~ SUGGESTION let _ = false; + //~| HELP for further information visit + //~| HELP this expression can be optimized out + //~| HELP it would look like the following + //~| SUGGESTION let _ = false; let _ = a == b && c == 5 && a == b; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = c == 5 && a == b; + //~| HELP for further information visit + //~| SUGGESTION let _ = a == b && c == 5; let _ = a == b && c == 5 && b == a; //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = c == 5 && a == b; + //~| HELP for further information visit + //~| SUGGESTION let _ = a == b && c == 5; + //~| HELP try + //~| SUGGESTION let _ = !(!(c == 5) || !(a == b)); let _ = a < b && a >= b; //~ ERROR this boolean expression contains a logic bug - //|~ HELP for further information visit - //|~ HELP this expression can be optimized out - //|~ HELP it would look like the following - //|~ SUGGESTION let _ = false; + //~| HELP for further information visit + //~| HELP this expression can be optimized out + //~| HELP it would look like the following + //~| SUGGESTION let _ = false; let _ = a > b && a <= b; //~ ERROR this boolean expression contains a logic bug - //|~ HELP for further information visit - //|~ HELP this expression can be optimized out - //|~ HELP it would look like the following - //|~ SUGGESTION let _ = false; + //~| HELP for further information visit + //~| HELP this expression can be optimized out + //~| HELP it would look like the following + //~| SUGGESTION let _ = false; let _ = a > b && a == b; let _ = a != b || !(a != b || c == d); //~ ERROR this boolean expression can be simplified - //|~ HELP for further information visit - //|~ SUGGESTION let _ = !c == d || a != b; - //|~ SUGGESTION let _ = !(!a != b && c == d); + //~| HELP for further information visit + //~| SUGGESTION let _ = !(c == d) || a != b; + //~| HELP try + //~| SUGGESTION let _ = !(!(a != b) && c == d); } -- cgit 1.4.1-3-g733a5 From e9c87c777c88d36b7ce8aee1ef13d5744f90da3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 29 Mar 2016 17:18:47 +0200 Subject: `!(a == b)` --> `a != b` --- src/booleans.rs | 62 ++++++++++++++++++++++++++++++++---------- tests/compile-fail/booleans.rs | 6 ++-- 2 files changed, 51 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 0cfab9a5357..74a10faa070 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -129,18 +129,10 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } } -macro_rules! brackets { - ($val:expr => $($name:ident),*) => { - match $val { - $($name(_) => true,)* - _ => false, - } - } -} - fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { use quine_mc_cluskey::Bool::*; + let snip = |e: &Expr| snippet_opt(cx, e.span).expect("don't try to improve booleans created by macros"); match *suggestion { True => { s.push_str("true"); @@ -151,17 +143,59 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s }, Not(ref inner) => { - s.push('!'); - recurse(brackets!(**inner => And, Or, Term), cx, inner, terminals, s) + match **inner { + And(_) | Or(_) => { + s.push('!'); + recurse(true, cx, inner, terminals, s) + }, + Term(n) => { + match terminals[n as usize].node { + ExprBinary(binop, ref lhs, ref rhs) => { + let op = match binop.node { + BiEq => " != ", + BiNe => " == ", + BiLt => " >= ", + BiGt => " <= ", + BiLe => " > ", + BiGe => " < ", + _ => { + s.push('!'); + return recurse(true, cx, inner, terminals, s) + }, + }; + s.push_str(&snip(lhs)); + s.push_str(op); + s.push_str(&snip(rhs)); + s + }, + _ => { + s.push('!'); + recurse(false, cx, inner, terminals, s) + }, + } + }, + _ => { + s.push('!'); + recurse(false, cx, inner, terminals, s) + }, + } }, And(ref v) => { if brackets { s.push('('); } - s = recurse(brackets!(v[0] => Or), cx, &v[0], terminals, s); + if let Or(_) = v[0] { + s = recurse(true, cx, &v[0], terminals, s); + } else { + s = recurse(false, cx, &v[0], terminals, s); + } for inner in &v[1..] { s.push_str(" && "); - s = recurse(brackets!(*inner => Or), cx, inner, terminals, s); + if let Or(_) = *inner { + s = recurse(true, cx, inner, terminals, s); + } else { + s = recurse(false, cx, inner, terminals, s); + } } if brackets { s.push(')'); @@ -188,7 +222,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push('('); } } - s.push_str(&snippet_opt(cx, terminals[n as usize].span).expect("don't try to improve booleans created by macros")); + s.push_str(&snip(&terminals[n as usize])); if brackets { if let ExprBinary(..) = terminals[n as usize].node { s.push(')'); diff --git a/tests/compile-fail/booleans.rs b/tests/compile-fail/booleans.rs index f4760a6fd46..aba55f0b8b4 100644 --- a/tests/compile-fail/booleans.rs +++ b/tests/compile-fail/booleans.rs @@ -66,7 +66,7 @@ fn equality_stuff() { //~| HELP for further information visit //~| SUGGESTION let _ = a == b && c == 5; //~| HELP try - //~| SUGGESTION let _ = !(!(c == 5) || !(a == b)); + //~| SUGGESTION let _ = !(c != 5 || a != b); let _ = a < b && a >= b; //~ ERROR this boolean expression contains a logic bug //~| HELP for further information visit //~| HELP this expression can be optimized out @@ -81,7 +81,7 @@ fn equality_stuff() { let _ = a != b || !(a != b || c == d); //~ ERROR this boolean expression can be simplified //~| HELP for further information visit - //~| SUGGESTION let _ = !(c == d) || a != b; + //~| SUGGESTION let _ = c != d || a != b; //~| HELP try - //~| SUGGESTION let _ = !(!(a != b) && c == d); + //~| SUGGESTION let _ = !(a == b && c == d); } -- cgit 1.4.1-3-g733a5 From fa48ee678a8b647f339547d1111dd9064ea9bfbe Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 29 Mar 2016 17:20:30 +0200 Subject: dogfood --- src/booleans.rs | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 74a10faa070..35ea5fe4462 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -149,29 +149,26 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { recurse(true, cx, inner, terminals, s) }, Term(n) => { - match terminals[n as usize].node { - ExprBinary(binop, ref lhs, ref rhs) => { - let op = match binop.node { - BiEq => " != ", - BiNe => " == ", - BiLt => " >= ", - BiGt => " <= ", - BiLe => " > ", - BiGe => " < ", - _ => { - s.push('!'); - return recurse(true, cx, inner, terminals, s) - }, - }; - s.push_str(&snip(lhs)); - s.push_str(op); - s.push_str(&snip(rhs)); - s - }, - _ => { - s.push('!'); - recurse(false, cx, inner, terminals, s) - }, + if let ExprBinary(binop, ref lhs, ref rhs) = terminals[n as usize].node { + let op = match binop.node { + BiEq => " != ", + BiNe => " == ", + BiLt => " >= ", + BiGt => " <= ", + BiLe => " > ", + BiGe => " < ", + _ => { + s.push('!'); + return recurse(true, cx, inner, terminals, s) + }, + }; + s.push_str(&snip(lhs)); + s.push_str(op); + s.push_str(&snip(rhs)); + s + } else { + s.push('!'); + recurse(false, cx, inner, terminals, s) } }, _ => { -- cgit 1.4.1-3-g733a5 From 2917484130db16c4533f0e241dd89352ec3b2ba6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 30 Mar 2016 12:55:59 +0200 Subject: make `nonminimal_bool` allow-by-default --- README.md | 2 +- src/booleans.rs | 6 +++--- src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 188e272dc4d..e59012c8165 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ name [new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead -[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | warn | checks for boolean expressions that can be written more concisely +[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | allow | checks for boolean expressions that can be written more concisely [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result [option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)` diff --git a/src/booleans.rs b/src/booleans.rs index 35ea5fe4462..877a45a355a 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -9,11 +9,11 @@ use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// /// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication /// -/// **Known problems:** Ignores short circuting behavior, bitwise and/or and xor. Ends up suggesting things like !(a == b) +/// **Known problems:** Ignores short circuting behavior of `||` and `&&`. Ignores `|`, `&` and `^`. /// -/// **Example:** `if a && true` should be `if a` +/// **Example:** `if a && true` should be `if a` and `!(a == b)` should be `a != b` declare_lint! { - pub NONMINIMAL_BOOL, Warn, + pub NONMINIMAL_BOOL, Allow, "checks for boolean expressions that can be written more concisely" } diff --git a/src/lib.rs b/src/lib.rs index 617d2e24266..2d12532fcfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,6 +235,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, + booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, matches::SINGLE_MATCH_ELSE, methods::OPTION_UNWRAP_USED, @@ -268,7 +269,6 @@ pub fn plugin_registrar(reg: &mut Registry) { block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, booleans::LOGIC_BUG, - booleans::NONMINIMAL_BOOL, collapsible_if::COLLAPSIBLE_IF, copies::IF_SAME_THEN_ELSE, copies::IFS_SAME_COND, -- cgit 1.4.1-3-g733a5 From 77652243aef0a5848ef2858b26443b9d3943ec83 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 30 Mar 2016 16:39:25 +0200 Subject: minor code readability improvements --- src/non_expressive_names.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 87373c7a0de..4e10d415b66 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -123,17 +123,11 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { for &(ref existing_name, sp, existing_len) in &self.0.names { let mut split_at = None; if existing_len > count { - if existing_len - count != 1 { - continue; - } - if levenstein_not_1(&interned_name, &existing_name) { + if existing_len - count != 1 || levenstein_not_1(&interned_name, &existing_name) { continue; } } else if existing_len < count { - if count - existing_len != 1 { - continue; - } - if levenstein_not_1(&existing_name, &interned_name) { + if count - existing_len != 1 || levenstein_not_1(&existing_name, &interned_name) { continue; } } else { -- cgit 1.4.1-3-g733a5 From d3362a2222481ce93c921bcc2781ffd401551628 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 30 Mar 2016 16:40:21 +0200 Subject: don't lint on binding names where only a numeric char changes to another numeric --- src/non_expressive_names.rs | 54 ++++++++++++------------------ tests/compile-fail/non_expressive_names.rs | 9 +++++ 2 files changed, 31 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 4e10d415b66..394812dc4cb 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -133,46 +133,36 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } else { let mut interned_chars = interned_name.chars(); let mut existing_chars = existing_name.chars(); + let first_i = interned_chars.next().expect("we know we have at least one char"); + let first_e = existing_chars.next().expect("we know we have at least one char"); + let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); - if interned_chars.next() != existing_chars.next() { - let i = interned_chars.next().expect("we know we have more than 1 char"); - let e = existing_chars.next().expect("we know we have more than 1 char"); - if i == e { - if i == '_' { - // allowed similarity x_foo, y_foo - // or too many chars differ (x_foo, y_boo) + if eq_or_numeric(first_i, first_e) { + let last_i = interned_chars.next_back().expect("we know we have at least two chars"); + let last_e = existing_chars.next_back().expect("we know we have at least two chars"); + if eq_or_numeric(last_i, last_e) { + if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 { continue; - } else if interned_chars.ne(existing_chars) { - // too many chars differ - continue } } else { - // too many chars differ - continue; - } - split_at = interned_name.chars().next().map(|c| c.len_utf8()); - } else if interned_chars.next_back() == existing_chars.next_back() { - if interned_chars.zip(existing_chars).filter(|&(i, e)| i != e).count() != 1 { - // too many chars differ, or none differ (aka shadowing) - continue; - } - } else { - let i = interned_chars.next_back().expect("we know we have more than 2 chars"); - let e = existing_chars.next_back().expect("we know we have more than 2 chars"); - if i == e { - if i == '_' { - // allowed similarity foo_x, foo_x - // or too many chars differ (foo_x, boo_x) + let second_last_i = interned_chars.next_back().expect("we know we have at least three chars"); + let second_last_e = existing_chars.next_back().expect("we know we have at least three chars"); + if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + // allowed similarity foo_x, foo_y + // or too many chars differ (foo_x, boo_y) or (foox, booy) continue; - } else if interned_chars.ne(existing_chars) { - // too many chars differ - continue } - } else { - // too many chars differ + split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); + } + } else { + let second_i = interned_chars.next().expect("we know we have at least two chars"); + let second_e = existing_chars.next().expect("we know we have at least two chars"); + if !eq_or_numeric(second_i, second_e) || second_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + // allowed similarity x_foo, y_foo + // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) continue; } - split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); + split_at = interned_name.chars().next().map(|c| c.len_utf8()); } } span_lint_and_then(self.0.cx, diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index ac412fb4475..7d0cea70366 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -10,6 +10,7 @@ //~| NOTE: lint level defined here //~| NOTE: lint level defined here //~| NOTE: lint level defined here +//~| NOTE: lint level defined here #![allow(unused)] fn main() { @@ -67,6 +68,14 @@ fn main() { (cheese2, 2) => panic!(), _ => println!(""), } + let ipv4: i32; + let ipv6: i32; + let abcd1: i32; + let abdc2: i32; + let xyz1abc: i32; //~ NOTE: existing binding defined here + let xyz2abc: i32; + let xyzeabc: i32; //~ ERROR: name is too similar + //~| HELP: for further information visit } #[derive(Clone, Debug)] -- cgit 1.4.1-3-g733a5 From f03d93e05e5e2149a2ae0fd05666da7d18edc993 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 30 Mar 2016 17:05:15 +0200 Subject: better whitelisting of "confusable" binding names --- src/non_expressive_names.rs | 76 +++++++++++++++++++----------- tests/compile-fail/non_expressive_names.rs | 7 +++ 2 files changed, 55 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 394812dc4cb..32118b11c4e 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -41,15 +41,25 @@ impl LintPass for NonExpressiveNames { } } +struct ExistingName { + interned: InternedString, + span: Span, + len: usize, + whitelist: &'static[&'static str], +} + struct SimilarNamesLocalVisitor<'a, 'b: 'a> { - names: Vec<(InternedString, Span, usize)>, + names: Vec<ExistingName>, cx: &'a EarlyContext<'b>, lint: &'a NonExpressiveNames, single_char_names: Vec<char>, } -const WHITELIST: &'static [&'static str] = &[ - "lhs", "rhs", +// this list contains lists of names that are allowed to be similar +// the assumption is that no name is ever contained in multiple lists. +const WHITELIST: &'static [&'static [&'static str]] = &[ + &["parsed", "parser"], + &["lhs", "rhs"], ]; struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); @@ -63,21 +73,27 @@ impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> } } -fn whitelisted(interned_name: &str) -> bool { +fn get_whitelist(interned_name: &str) -> Option<&'static[&'static str]> { for &allow in WHITELIST { - if interned_name == allow { - return true; + if whitelisted(interned_name, allow) { + return Some(allow); } - if interned_name.len() <= allow.len() { - continue; - } - // allow_* - let allow_start = allow.chars().chain(Some('_')); + } + None +} + +fn whitelisted(interned_name: &str, list: &[&str]) -> bool { + if list.iter().any(|&name| interned_name == name) { + return true; + } + for name in list { + // name_* + let allow_start = name.chars().chain(Some('_')); if interned_name.chars().zip(allow_start).all(|(l, r)| l == r) { return true; } - // *_allow - let allow_end = Some('_').into_iter().chain(allow.chars()); + // *_name + let allow_end = Some('_').into_iter().chain(name.chars()); if interned_name.chars().rev().zip(allow_end.rev()).all(|(l, r)| l == r) { return true; } @@ -110,29 +126,28 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } let count = interned_name.chars().count(); if count < 3 { - if count != 1 { - return; + if count == 1 { + let c = interned_name.chars().next().expect("already checked"); + self.check_short_name(c, span); } - let c = interned_name.chars().next().expect("already checked"); - self.check_short_name(c, span); - return; - } - if whitelisted(&interned_name) { return; } - for &(ref existing_name, sp, existing_len) in &self.0.names { + for existing_name in &self.0.names { + if whitelisted(&interned_name, existing_name.whitelist) { + continue; + } let mut split_at = None; - if existing_len > count { - if existing_len - count != 1 || levenstein_not_1(&interned_name, &existing_name) { + if existing_name.len > count { + if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { continue; } - } else if existing_len < count { - if count - existing_len != 1 || levenstein_not_1(&existing_name, &interned_name) { + } else if existing_name.len < count { + if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { continue; } } else { let mut interned_chars = interned_name.chars(); - let mut existing_chars = existing_name.chars(); + let mut existing_chars = existing_name.interned.chars(); let first_i = interned_chars.next().expect("we know we have at least one char"); let first_e = existing_chars.next().expect("we know we have at least one char"); let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); @@ -170,7 +185,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { span, "binding's name is too similar to existing binding", |diag| { - diag.span_note(sp, "existing binding defined here"); + diag.span_note(existing_name.span, "existing binding defined here"); if let Some(split) = split_at { diag.span_help(span, &format!("separate the discriminating character \ by an underscore like: `{}_{}`", @@ -180,7 +195,12 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { }); return; } - self.0.names.push((interned_name, span, count)); + self.0.names.push(ExistingName { + whitelist: get_whitelist(&interned_name).unwrap_or(&[]), + interned: interned_name, + span: span, + len: count, + }); } } diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index 7d0cea70366..aab88f742a6 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -11,6 +11,7 @@ //~| NOTE: lint level defined here //~| NOTE: lint level defined here //~| NOTE: lint level defined here +//~| NOTE: lint level defined here #![allow(unused)] fn main() { @@ -76,6 +77,12 @@ fn main() { let xyz2abc: i32; let xyzeabc: i32; //~ ERROR: name is too similar //~| HELP: for further information visit + + let parser: i32; //~ NOTE: existing binding defined here + let parsed: i32; + let parsee: i32; //~ ERROR: name is too similar + //~| HELP: for further information visit + //~| HELP: separate the discriminating character by an underscore like: `parse_e` } #[derive(Clone, Debug)] -- cgit 1.4.1-3-g733a5 From 7095b5df31dceb27b5ee1d344458cd6d1cd791d0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 30 Mar 2016 23:07:21 +0200 Subject: Fix FP in `REDUNDANT_CLOSURE` with divergent functions --- src/eta_reduction.rs | 3 ++- tests/compile-fail/eta.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index bae971f46ac..c080968ef84 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -61,7 +61,8 @@ fn check_closure(cx: &LateContext, expr: &Expr) { match fn_ty.sty { // 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 { + if fn_ty.unsafety == Unsafety::Unsafe || + fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging { return; } } diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index 3fd089bf588..a744489fa9c 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -22,6 +22,14 @@ fn main() { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } + // See #815 + let e = Some(1u8).map(|a| divergent(a)); + let e = Some(1u8).map(|a| generic(a)); + //~^ ERROR redundant closure found + //~| HELP remove closure as shown + //~| SUGGESTION map(generic); + let e = Some(1u8).map(generic); + // See #515 let a: Option<Box<::std::ops::Deref<Target = [i32]>>> = Some(vec![1i32, 2]).map(|v| -> Box<::std::ops::Deref<Target = [i32]>> { Box::new(v) }); @@ -47,3 +55,11 @@ where F: Fn(&X, &X) -> bool { fn below(x: &u8, y: &u8) -> bool { x < y } unsafe fn unsafe_fn(_: u8) { } + +fn divergent(_: u8) -> ! { + unimplemented!() +} + +fn generic<T>(_: T) -> u8 { + 0 +} -- cgit 1.4.1-3-g733a5 From 9438f4f263e6fa8a53f766069e3522ca12b46ce7 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 31 Mar 2016 17:05:43 +0200 Subject: Rustup to 1.9.0-nightly (30a3849f2 2016-03-30) --- src/array_indexing.rs | 7 ++++--- src/bit_mask.rs | 3 +-- src/consts.rs | 4 ++-- src/enum_clike.rs | 5 +++-- src/identity_op.rs | 2 +- src/lib.rs | 1 + src/loops.rs | 5 +++-- src/matches.rs | 7 ++++--- src/methods.rs | 5 +++-- src/misc.rs | 8 ++++---- src/regex.rs | 5 +++-- src/types.rs | 11 ++++++----- tests/consts.rs | 17 +++++++---------- 13 files changed, 42 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index 344a8b8c34e..e5f54c128ef 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -1,9 +1,10 @@ use rustc::lint::*; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::ty::TyArray; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_math::ConstInt; use rustc_front::hir::*; -use rustc_const_eval::ConstInt; use syntax::ast::RangeLimits; use utils; diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 28fc311507d..cbe601ba1b4 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,11 +1,10 @@ use rustc::lint::*; -use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::{Def, PathResolution}; +use rustc_const_eval::lookup_const_by_id; use rustc_front::hir::*; use rustc_front::util::is_comparison_binop; use syntax::ast::LitKind; use syntax::codemap::Span; - use utils::span_lint; /// **What it does:** This lint checks for incompatible bit masks in comparisons. diff --git a/src/consts.rs b/src/consts.rs index 97a99dda4b5..73f2bc4653a 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,10 +1,10 @@ #![allow(cast_possible_truncation)] use rustc::lint::LateContext; -use rustc::middle::const_eval::lookup_const_by_id; use rustc::middle::def::{Def, PathResolution}; +use rustc_const_eval::lookup_const_by_id; +use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc_front::hir::*; -use rustc_const_eval::{ConstInt, ConstUsize, ConstIsize}; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; diff --git a/src/enum_clike.rs b/src/enum_clike.rs index 85fa418f278..0e2a7a5304f 100644 --- a/src/enum_clike.rs +++ b/src/enum_clike.rs @@ -1,9 +1,10 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` use rustc::lint::*; -use syntax::attr::*; +use rustc::middle::const_val::ConstVal; +use rustc_const_math::*; use rustc_front::hir::*; -use rustc::middle::const_eval::{ConstVal, EvalHint, eval_const_expr_partial}; +use syntax::attr::*; use utils::span_lint; /// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. diff --git a/src/identity_op.rs b/src/identity_op.rs index 9ade801abb3..c25047b87b4 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc_front::hir::*; use syntax::codemap::Span; use utils::{span_lint, snippet, in_macro}; -use rustc_const_eval::ConstInt; +use rustc_const_math::ConstInt; /// **What it does:** This lint checks for identity operations, e.g. `x + 0`. /// diff --git a/src/lib.rs b/src/lib.rs index 2d12532fcfe..75970449582 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ extern crate quine_mc_cluskey; extern crate rustc_plugin; extern crate rustc_const_eval; +extern crate rustc_const_math; use rustc_plugin::Registry; pub mod consts; diff --git a/src/loops.rs b/src/loops.rs index 10a8a76d7ae..20d0fc026d1 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,11 +1,12 @@ use reexport::*; use rustc::front::map::Node::NodeBlock; use rustc::lint::*; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; +use rustc::middle::const_val::ConstVal; use rustc::middle::def::Def; use rustc::middle::region::CodeExtent; use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; use rustc_front::hir::*; use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; diff --git a/src/matches.rs b/src/matches.rs index 7bffd445f6b..40013209e57 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,9 +1,10 @@ use rustc::lint::*; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_math::ConstInt; use rustc_front::hir::*; -use rustc_const_eval::ConstInt; use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; diff --git a/src/methods.rs b/src/methods.rs index b8bbc0e9068..3ba6bfc9b41 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,9 +1,10 @@ use rustc::lint::*; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial}; +use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::CrateStore; use rustc::ty::subst::{Subst, TypeSpace}; use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; use rustc_front::hir::*; use std::borrow::Cow; use std::fmt; diff --git a/src/misc.rs b/src/misc.rs index 5a787ba6dba..a6cfec276e5 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,9 +1,9 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::const_eval::ConstVal::Float; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::eval_const_expr_partial; +use rustc::middle::const_val::ConstVal; use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; use rustc_front::hir::*; use rustc_front::intravisit::FnKind; use rustc_front::util::{is_comparison_binop, binop_to_string}; @@ -180,7 +180,7 @@ impl LateLintPass for FloatCmp { fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None); - if let Ok(Float(val)) = res { + if let Ok(ConstVal::Float(val)) = res { val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY } else { false diff --git a/src/regex.rs b/src/regex.rs index e8a71a2cb5a..46ee7776d66 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,7 +1,8 @@ use regex_syntax; use rustc::lint::*; -use rustc::middle::const_eval::EvalHint::ExprTypeChecked; -use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; +use rustc::middle::const_val::ConstVal; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; use rustc_front::hir::*; use std::collections::HashSet; use std::error::Error; diff --git a/src/types.rs b/src/types.rs index c2fc242ec53..8e9ac1217f0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::{const_eval, def}; +use rustc::middle::def; use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; @@ -683,10 +683,11 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs } fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> { - use rustc::middle::const_eval::EvalHint::ExprTypeChecked; - use types::ExtremeType::*; - use rustc::middle::const_eval::ConstVal::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::*; + use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::*; + use types::ExtremeType::*; let ty = &cx.tcx.expr_ty(expr).sty; @@ -695,7 +696,7 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx _ => return None, }; - let cv = match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + let cv = match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { Ok(val) => val, Err(_) => return None, }; diff --git a/tests/consts.rs b/tests/consts.rs index 3a774f67473..b7b2f6a3f83 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -2,22 +2,19 @@ #![feature(rustc_private)] extern crate clippy; -extern crate syntax; extern crate rustc; -extern crate rustc_front; extern crate rustc_const_eval; +extern crate rustc_const_math; +extern crate rustc_front; +extern crate syntax; +use clippy::consts::{constant_simple, Constant, FloatWidth}; +use rustc_const_math::ConstInt; use rustc_front::hir::*; -use rustc_const_eval::ConstInt; +use syntax::ast::{LitIntType, LitKind, StrStyle}; +use syntax::codemap::{Spanned, COMMAND_LINE_SP}; use syntax::parse::token::InternedString; use syntax::ptr::P; -use syntax::codemap::{Spanned, COMMAND_LINE_SP}; - -use syntax::ast::LitKind; -use syntax::ast::LitIntType; -use syntax::ast::StrStyle; - -use clippy::consts::{constant_simple, Constant, FloatWidth}; fn spanned<T>(t: T) -> Spanned<T> { Spanned{ node: t, span: COMMAND_LINE_SP } -- cgit 1.4.1-3-g733a5 From 73ee3e6f36a73d149f9b7994b9c3c57fa14c93e2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 31 Mar 2016 15:38:43 +0200 Subject: whitelist more non-expressive-name false positives --- src/non_expressive_names.rs | 8 ++++---- tests/compile-fail/non_expressive_names.rs | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 32118b11c4e..36fcc292bfc 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -60,6 +60,8 @@ struct SimilarNamesLocalVisitor<'a, 'b: 'a> { const WHITELIST: &'static [&'static [&'static str]] = &[ &["parsed", "parser"], &["lhs", "rhs"], + &["tx", "rx"], + &["set", "get"], ]; struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); @@ -88,13 +90,11 @@ fn whitelisted(interned_name: &str, list: &[&str]) -> bool { } for name in list { // name_* - let allow_start = name.chars().chain(Some('_')); - if interned_name.chars().zip(allow_start).all(|(l, r)| l == r) { + if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) { return true; } // *_name - let allow_end = Some('_').into_iter().chain(name.chars()); - if interned_name.chars().rev().zip(allow_end.rev()).all(|(l, r)| l == r) { + if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) { return true; } } diff --git a/tests/compile-fail/non_expressive_names.rs b/tests/compile-fail/non_expressive_names.rs index aab88f742a6..b756253e6ad 100644 --- a/tests/compile-fail/non_expressive_names.rs +++ b/tests/compile-fail/non_expressive_names.rs @@ -11,7 +11,6 @@ //~| NOTE: lint level defined here //~| NOTE: lint level defined here //~| NOTE: lint level defined here -//~| NOTE: lint level defined here #![allow(unused)] fn main() { @@ -45,9 +44,8 @@ fn main() { let bla_rhs: i32; let bla_lhs: i32; - let blubrhs: i32; //~ NOTE: existing binding defined here - let blublhs: i32; //~ ERROR: name is too similar - //~| HELP: for further information visit + let blubrhs: i32; + let blublhs: i32; let blubx: i32; //~ NOTE: existing binding defined here let bluby: i32; //~ ERROR: name is too similar @@ -83,6 +81,13 @@ fn main() { let parsee: i32; //~ ERROR: name is too similar //~| HELP: for further information visit //~| HELP: separate the discriminating character by an underscore like: `parse_e` + + let setter: i32; + let getter: i32; + let tx1: i32; + let rx1: i32; + let tx_cake: i32; + let rx_cake: i32; } #[derive(Clone, Debug)] -- cgit 1.4.1-3-g733a5 From 4c6c84e0a19539a4c5e742e02387ec17efe68d0a Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Fri, 1 Apr 2016 10:33:17 +0200 Subject: fix #820 --- src/methods.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 3ba6bfc9b41..646cd319a0c 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -302,7 +302,8 @@ impl LintPass for MethodsPass { CLONE_ON_COPY, CLONE_DOUBLE_REF, NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN) + SINGLE_CHAR_PATTERN, + SEARCH_IS_SOME) } } -- cgit 1.4.1-3-g733a5 From 8bfe38c432694677282f658b48b2a4c86d6a23a5 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 1 Apr 2016 13:14:39 +0200 Subject: Improve the `match_same_arms` doc --- src/copies.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/copies.rs b/src/copies.rs index 2de034f83c2..b8eb97cbeed 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -38,7 +38,9 @@ declare_lint! { /// **What it does:** This lint checks for `match` with identical arm bodies. /// -/// **Why is this bad?** This is probably a copy & paste error. +/// **Why is this bad?** This is probably a copy & paste error. If arm bodies are the same on +/// purpose, you can factor them +/// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). /// /// **Known problems:** Hopefully none. /// -- cgit 1.4.1-3-g733a5 From f16da4fddae85c73f088fdc38151eb69b1caffc3 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 1 Apr 2016 17:24:55 +0200 Subject: Fix false positive with `DOC_MARKDOWN` and links --- src/doc.rs | 9 +++++++-- tests/compile-fail/doc.rs | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 5637fb2cefb..9a6a86d4140 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -69,7 +69,7 @@ fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { let (doc, span) = doc_attrs.next().unwrap_or_else(|| unreachable!()); (doc.into(), Some(span)) } - _ => (doc_attrs.map(|s| s.0).collect::<String>().into(), None), + _ => (doc_attrs.map(|s| format!("{}\n", s.0)).collect::<String>().into(), None), } } @@ -124,9 +124,14 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { s != "_" && !s.contains("\\_") && s.contains('_') } + // Something with a `/` might be a link, don’t warn (see #823): + if word.contains('/') { + return; + } + // Trim punctuation as in `some comment (see foo::bar).` // ^^ - // Or even as `_foo bar_` which is emphasized. + // Or even as in `_foo bar_` which is emphasized. let word = word.trim_matches(|c: char| !c.is_alphanumeric()); if has_underscore(word) || word.contains("::") || is_camel_case(word) { diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index eecf5e0b206..a7b316e1f82 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -29,6 +29,11 @@ fn multiline_ticks() { fn test_emphasis() { } +/// This test has [a link with underscores][chunked-example] inside it. See #823. +/// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). +/// +/// [chunked-example]: http://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example + /// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and /// `multiline_ticks` functions. fn main() { -- cgit 1.4.1-3-g733a5 From 6b0eb107694aa07abf8a85e42b5991e9744b73eb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Fri, 1 Apr 2016 21:24:26 +0530 Subject: Ignore pathological cases in boolean lint (#825) --- src/booleans.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/booleans.rs b/src/booleans.rs index 877a45a355a..37ad927ef92 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -294,6 +294,14 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { cx: self.0, }; if let Ok(expr) = h2q.run(e) { + + if h2q.terminals.len() > 8 { + // QMC has exponentially slow behavior as the number of terminals increases + // 8 is reasonable, it takes approximately 0.2 seconds. + // See #825 + return; + } + let stats = terminal_stats(&expr); let mut simplified = expr.simplify(); for simple in Bool::Not(Box::new(expr.clone())).simplify() { -- cgit 1.4.1-3-g733a5 From 498e0fba7f5d614c8165b41204e05c5ad461d25d Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Fri, 25 Mar 2016 02:42:27 -0700 Subject: Initial attempt at linting invalid upcast comparisons --- src/lib.rs | 2 + src/types.rs | 223 +++++++++++++++++++++-- tests/compile-fail/invalid_upcast_comparisons.rs | 15 ++ 3 files changed, 228 insertions(+), 12 deletions(-) create mode 100644 tests/compile-fail/invalid_upcast_comparisons.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 75970449582..6834753adf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,6 +221,7 @@ pub fn plugin_registrar(reg: &mut Registry) { }); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); + reg.register_late_lint_pass(box types::InvalidUpcastComparisons); reg.register_late_lint_pass(box regex::RegexPass::default()); reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_late_lint_pass(box format::FormatMacLint); @@ -367,6 +368,7 @@ pub fn plugin_registrar(reg: &mut Registry) { transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, + types::INVALID_UPCAST_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, types::LET_UNIT_VALUE, diff --git a/src/types.rs b/src/types.rs index 8e9ac1217f0..6f08b57b55a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,10 @@ use reexport::*; +use rustc_const_eval::*; use rustc::lint::*; use rustc::middle::def; use rustc::ty; +use rustc::middle::const_eval::ConstVal::Integral; +use rustc_const_eval; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc_front::util::{is_comparison_binop, binop_to_string}; @@ -9,6 +12,7 @@ use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; use utils::*; + /// Handles all the linting of funky types #[allow(missing_copy_implementations)] pub struct TypePass; @@ -640,24 +644,32 @@ enum AbsurdComparisonResult { InequalityImpossible, } +enum Rel { + Lt, + Le, +} + +// Put the expression in the form lhs < rhs or lhs <= rhs. +fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) + -> Option<(Rel, &'a Expr, &'a Expr)> { + match op { + BiLt => Some((Rel::Lt, lhs, rhs)), + BiLe => Some((Rel::Le, lhs, rhs)), + BiGt => Some((Rel::Lt, rhs, lhs)), + BiGe => Some((Rel::Le, rhs, lhs)), + _ => return None, + } +} + 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::*; type Extr<'a> = ExtremeExpr<'a>; - // Put the expression in the form lhs < rhs or lhs <= rhs. - enum Rel { - Lt, - Le, - }; - let (rel, normalized_lhs, normalized_rhs) = match op { - BiLt => (Rel::Lt, lhs, rhs), - BiLe => (Rel::Le, lhs, rhs), - BiGt => (Rel::Lt, rhs, lhs), - BiGe => (Rel::Le, rhs, lhs), - _ => return None, - }; + let normalized = normalize_comparison(op, lhs, rhs); + if normalized.is_none() { return None; } // Could be an if let, but this prevents rightward drift + let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap(); let lx = detect_extreme_expr(cx, normalized_lhs); let rx = detect_extreme_expr(cx, normalized_rhs); @@ -778,3 +790,190 @@ impl LateLintPass for AbsurdExtremeComparisons { } } } + +/// **What it does:** This lint checks for comparisons where the relation is always either true or false, but where one side has been upcast so that the comparison is necessary. Only integer types are checked. +/// +/// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` will mistakenly imply that it is possible for `x` to be outside the range of `u8`. +/// +/// **Known problems:** None +/// +/// **Example:** `let x : u8 = ...; (x as u32) > 300` +declare_lint! { + pub INVALID_UPCAST_COMPARISONS, Warn, + "a comparison involving an term's upcasting to be within the range of the other side of the \ + term is always true or false" +} + +pub struct InvalidUpcastComparisons; + +impl LintPass for InvalidUpcastComparisons { + fn get_lints(&self) -> LintArray { + lint_array!(INVALID_UPCAST_COMPARISONS) + } +} + +enum FullInt { + S(i64), + U(u64), +} + +use std; +use self::FullInt::*; +use std::cmp::Ordering::*; + +impl FullInt { + fn cmp_s_u(s: &i64, u: &u64) -> std::cmp::Ordering { + if *s < 0 { + Less + } else if *u > (i64::max_value() as u64) { + Greater + } else { + (*s as u64).cmp(u) + } + } +} + +impl PartialEq for FullInt { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Equal + } +} +impl Eq for FullInt {} + +impl PartialOrd for FullInt { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(match (self, other) { + (&S(ref s), &S(ref o)) => s.cmp(o), + (&U(ref s), &U(ref o)) => s.cmp(o), + (&S(ref s), &U(ref o)) => Self::cmp_s_u(s, o), + (&U(ref s), &S(ref o)) => Self::cmp_s_u(o, s).reverse(), + }) + } +} +impl Ord for FullInt { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } +} + + +fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { + use rustc::middle::const_eval::EvalHint::ExprTypeChecked; + + if let ExprCast(ref cast_exp,_) = expr.node { + let cv = match const_eval::eval_const_expr_partial(cx.tcx, cast_exp, ExprTypeChecked, None) { + Ok(val) => val, + Err(_) => return None, + }; + + if let Integral(const_int) = cv { + Some(match const_int { + I8(_) => (S(i8::min_value() as i64), S(i8::max_value() as i64)), + I16(_) => (S(i16::min_value() as i64), S(i16::max_value() as i64)), + I32(_) => (S(i32::min_value() as i64), S(i32::max_value() as i64)), + Isize(_) | + I64(_) | + InferSigned(_) => (S(i64::max_value()), S(i64::max_value())), + U8(_) => (U(u8::min_value() as u64), U(u8::max_value() as u64)), + U16(_) => (U(u16::min_value() as u64), U(u16::max_value() as u64)), + U32(_) => (U(u32::min_value() as u64), U(u32::max_value() as u64)), + Usize(_) | + U64(_) | + Infer(_) => (U(u64::max_value()), U(u64::max_value())), + }) + } else { + None + } + } else { + None + } +} + +fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { + use rustc::middle::const_eval::EvalHint::ExprTypeChecked; + + match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + Ok(val) => { + if let Integral(const_int) = val { + Some(match const_int { + I8(x) => S(x as i64), + I16(x) => S(x as i64), + I32(x) => S(x as i64), + Isize(x) => S(match x { + Is32(x_) => x_ as i64, + Is64(x_) => x_ + }), + I64(x) => S(x), + InferSigned(x) => S(x as i64), + U8(x) => U(x as u64), + U16(x) => U(x as u64), + U32(x) => U(x as u64), + Usize(x) => U(match x { + Us32(x_) => x_ as u64, + Us64(x_) => x_, + }), + U64(x) => U(x), + Infer(x) => U(x as u64), + }) + } else { + None + } + }, + Err(_) => return None, + } +} + +impl LateLintPass for InvalidUpcastComparisons { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { + let normalized = normalize_comparison(cmp.node, lhs, rhs); + if normalized.is_none() { return; } + let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap(); + + let norm_lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); + let norm_rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); + + if let Some(nlb) = norm_lhs_bounds { + if let Some(norm_rhs_val) = node_as_const_fullint(cx, normalized_rhs) { + if match rel { + Rel::Lt => nlb.1 < norm_rhs_val, + Rel::Le => nlb.1 <= norm_rhs_val, + } { + // Expression is always true + cx.span_lint(INVALID_UPCAST_COMPARISONS, + expr.span, + &format!("")); + } else if match rel { + Rel::Lt => nlb.0 >= norm_rhs_val, + Rel::Le => nlb.0 > norm_rhs_val, + } { + // Expression is always false + cx.span_lint(INVALID_UPCAST_COMPARISONS, + expr.span, + &format!("")); + } + } + } else if let Some(nrb) = norm_rhs_bounds { + if let Some(norm_lhs_val) = node_as_const_fullint(cx, normalized_lhs) { + if match rel { + Rel::Lt => norm_lhs_val < nrb.0, + Rel::Le => norm_lhs_val <= nrb.0, + } { + // Expression is always true + cx.span_lint(INVALID_UPCAST_COMPARISONS, + expr.span, + &format!("")); + } else if match rel { + Rel::Lt => norm_lhs_val >= nrb.1, + Rel::Le => norm_lhs_val > nrb.1, + } { + // Expression is always false + cx.span_lint(INVALID_UPCAST_COMPARISONS, + expr.span, + &format!("")); + } + } + } + } + } +} diff --git a/tests/compile-fail/invalid_upcast_comparisons.rs b/tests/compile-fail/invalid_upcast_comparisons.rs new file mode 100644 index 00000000000..63ccb6efd9d --- /dev/null +++ b/tests/compile-fail/invalid_upcast_comparisons.rs @@ -0,0 +1,15 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(invalid_upcast_comparisons)] +#![allow(unused, eq_op, no_effect)] +fn main() { + let zero: u32 = 0; + let u8_max: u8 = 255; + + (u8_max as u32) > 300; //~ERROR + (u8_max as u32) > 20; + + (zero as i32) < -5; //~ERROR + (zero as i32) < 10; +} -- cgit 1.4.1-3-g733a5 From c81edfc7b904ccab94073a5726fda27c439db010 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Fri, 25 Mar 2016 02:44:45 -0700 Subject: Updated lints with script --- README.md | 3 ++- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index e59012c8165..c81fb9b52c1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 139 lints included in this crate: +There are 140 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -68,6 +68,7 @@ name [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations +[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an term's upcasting to be within the range of the other side of the term is always true or false [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` diff --git a/src/lib.rs b/src/lib.rs index 6834753adf0..f3fc453cf69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -368,9 +368,9 @@ pub fn plugin_registrar(reg: &mut Registry) { transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, types::ABSURD_EXTREME_COMPARISONS, - types::INVALID_UPCAST_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, + types::INVALID_UPCAST_COMPARISONS, types::LET_UNIT_VALUE, types::LINKEDLIST, types::TYPE_COMPLEXITY, -- cgit 1.4.1-3-g733a5 From 8687949a29aaf8e33718a33154f9d9b65d39a6be Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Fri, 25 Mar 2016 15:47:27 -0700 Subject: Tests passing for invalid_upcast_comparisons --- src/types.rs | 115 +++++++++++------------ tests/compile-fail/invalid_upcast_comparisons.rs | 8 +- 2 files changed, 63 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 6f08b57b55a..8fede2593ed 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,4 @@ use reexport::*; -use rustc_const_eval::*; use rustc::lint::*; use rustc::middle::def; use rustc::ty; @@ -657,7 +656,7 @@ fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) BiLe => Some((Rel::Le, lhs, rhs)), BiGt => Some((Rel::Lt, rhs, lhs)), BiGe => Some((Rel::Le, rhs, lhs)), - _ => return None, + _ => None, } } @@ -669,7 +668,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs let normalized = normalize_comparison(op, lhs, rhs); if normalized.is_none() { return None; } // Could be an if let, but this prevents rightward drift - let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap(); + let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above"); let lx = detect_extreme_expr(cx, normalized_lhs); let rx = detect_extreme_expr(cx, normalized_rhs); @@ -818,15 +817,15 @@ enum FullInt { } use std; -use self::FullInt::*; -use std::cmp::Ordering::*; +use std::cmp::Ordering; impl FullInt { + #[allow(cast_sign_loss)] fn cmp_s_u(s: &i64, u: &u64) -> std::cmp::Ordering { if *s < 0 { - Less + Ordering::Less } else if *u > (i64::max_value() as u64) { - Greater + Ordering::Greater } else { (*s as u64).cmp(u) } @@ -835,7 +834,7 @@ impl FullInt { impl PartialEq for FullInt { fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Equal + self.cmp(other) == Ordering::Equal } } impl Eq for FullInt {} @@ -843,46 +842,43 @@ impl Eq for FullInt {} impl PartialOrd for FullInt { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(match (self, other) { - (&S(ref s), &S(ref o)) => s.cmp(o), - (&U(ref s), &U(ref o)) => s.cmp(o), - (&S(ref s), &U(ref o)) => Self::cmp_s_u(s, o), - (&U(ref s), &S(ref o)) => Self::cmp_s_u(o, s).reverse(), + (&FullInt::S(ref s), &FullInt::S(ref o)) => s.cmp(o), + (&FullInt::U(ref s), &FullInt::U(ref o)) => s.cmp(o), + (&FullInt::S(ref s), &FullInt::U(ref o)) => Self::cmp_s_u(s, o), + (&FullInt::U(ref s), &FullInt::S(ref o)) => Self::cmp_s_u(o, s).reverse(), }) } } impl Ord for FullInt { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.partial_cmp(other).unwrap() + self.partial_cmp(other).expect("partial_cmp for FullInt can never return None") } } fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { - use rustc::middle::const_eval::EvalHint::ExprTypeChecked; + use rustc::middle::ty::TypeVariants::{TyInt, TyUint}; + use syntax::ast::UintTy; + use syntax::ast::IntTy; + use std::*; if let ExprCast(ref cast_exp,_) = expr.node { - let cv = match const_eval::eval_const_expr_partial(cx.tcx, cast_exp, ExprTypeChecked, None) { - Ok(val) => val, - Err(_) => return None, - }; - - if let Integral(const_int) = cv { - Some(match const_int { - I8(_) => (S(i8::min_value() as i64), S(i8::max_value() as i64)), - I16(_) => (S(i16::min_value() as i64), S(i16::max_value() as i64)), - I32(_) => (S(i32::min_value() as i64), S(i32::max_value() as i64)), - Isize(_) | - I64(_) | - InferSigned(_) => (S(i64::max_value()), S(i64::max_value())), - U8(_) => (U(u8::min_value() as u64), U(u8::max_value() as u64)), - U16(_) => (U(u16::min_value() as u64), U(u16::max_value() as u64)), - U32(_) => (U(u32::min_value() as u64), U(u32::max_value() as u64)), - Usize(_) | - U64(_) | - Infer(_) => (U(u64::max_value()), U(u64::max_value())), - }) - } else { - None + match cx.tcx.expr_ty(cast_exp).sty { + TyInt(int_ty) => Some(match int_ty { + IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)), + IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)), + IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)), + 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)), + UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)), + UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)), + 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 { None @@ -891,35 +887,36 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { use rustc::middle::const_eval::EvalHint::ExprTypeChecked; + use rustc_const_eval::*; match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { Ok(val) => { if let Integral(const_int) = val { Some(match const_int { - I8(x) => S(x as i64), - I16(x) => S(x as i64), - I32(x) => S(x as i64), - Isize(x) => S(match x { + I8(x) => FullInt::S(x as i64), + I16(x) => FullInt::S(x as i64), + I32(x) => FullInt::S(x as i64), + Isize(x) => FullInt::S(match x { Is32(x_) => x_ as i64, Is64(x_) => x_ }), - I64(x) => S(x), - InferSigned(x) => S(x as i64), - U8(x) => U(x as u64), - U16(x) => U(x as u64), - U32(x) => U(x as u64), - Usize(x) => U(match x { + I64(x) => FullInt::S(x), + InferSigned(x) => FullInt::S(x as i64), + U8(x) => FullInt::U(x as u64), + U16(x) => FullInt::U(x as u64), + U32(x) => FullInt::U(x as u64), + Usize(x) => FullInt::U(match x { Us32(x_) => x_ as u64, Us64(x_) => x_, }), - U64(x) => U(x), - Infer(x) => U(x as u64), + U64(x) => FullInt::U(x), + Infer(x) => FullInt::U(x as u64), }) } else { None } }, - Err(_) => return None, + Err(_) => None, } } @@ -928,12 +925,14 @@ impl LateLintPass for InvalidUpcastComparisons { if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { let normalized = normalize_comparison(cmp.node, lhs, rhs); if normalized.is_none() { return; } - let (rel, normalized_lhs, normalized_rhs) = normalized.unwrap(); + let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above"); + + let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); + let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); - let norm_lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); - let norm_rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); + let msg = "Because of the numeric bounds prior to casting, this expression is always "; - if let Some(nlb) = norm_lhs_bounds { + if let Some(nlb) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, normalized_rhs) { if match rel { Rel::Lt => nlb.1 < norm_rhs_val, @@ -942,7 +941,7 @@ impl LateLintPass for InvalidUpcastComparisons { // Expression is always true cx.span_lint(INVALID_UPCAST_COMPARISONS, expr.span, - &format!("")); + &format!("{}{}.", msg, "true")); } else if match rel { Rel::Lt => nlb.0 >= norm_rhs_val, Rel::Le => nlb.0 > norm_rhs_val, @@ -950,10 +949,10 @@ impl LateLintPass for InvalidUpcastComparisons { // Expression is always false cx.span_lint(INVALID_UPCAST_COMPARISONS, expr.span, - &format!("")); + &format!("{}{}.", msg, "false")); } } - } else if let Some(nrb) = norm_rhs_bounds { + } else if let Some(nrb) = rhs_bounds { if let Some(norm_lhs_val) = node_as_const_fullint(cx, normalized_lhs) { if match rel { Rel::Lt => norm_lhs_val < nrb.0, @@ -962,7 +961,7 @@ impl LateLintPass for InvalidUpcastComparisons { // Expression is always true cx.span_lint(INVALID_UPCAST_COMPARISONS, expr.span, - &format!("")); + &format!("{}{}.", msg, "true")); } else if match rel { Rel::Lt => norm_lhs_val >= nrb.1, Rel::Le => norm_lhs_val > nrb.1, @@ -970,7 +969,7 @@ impl LateLintPass for InvalidUpcastComparisons { // Expression is always false cx.span_lint(INVALID_UPCAST_COMPARISONS, expr.span, - &format!("")); + &format!("{}{}.", msg, "false")); } } } diff --git a/tests/compile-fail/invalid_upcast_comparisons.rs b/tests/compile-fail/invalid_upcast_comparisons.rs index 63ccb6efd9d..d5849420e38 100644 --- a/tests/compile-fail/invalid_upcast_comparisons.rs +++ b/tests/compile-fail/invalid_upcast_comparisons.rs @@ -7,9 +7,13 @@ fn main() { let zero: u32 = 0; let u8_max: u8 = 255; - (u8_max as u32) > 300; //~ERROR + (u8_max as u32) > 300; //~ERROR Because of the numeric bounds prior to casting, this expression is always false. (u8_max as u32) > 20; - (zero as i32) < -5; //~ERROR + (zero as i32) < -5; //~ERROR Because of the numeric bounds prior to casting, this expression is always false. (zero as i32) < 10; + + -5 < (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true. + 0 <= (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true. + 0 < (zero as i32); } -- cgit 1.4.1-3-g733a5 From 106ae7da441c075aa1b83f5c021ea47f25589d05 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Fri, 25 Mar 2016 22:57:03 -0700 Subject: Invalid upcast comparison cleanup --- README.md | 2 +- src/types.rs | 159 ++++++++++------------- src/utils/comparisons.rs | 19 +++ src/utils/mod.rs | 1 + tests/compile-fail/invalid_upcast_comparisons.rs | 8 +- 5 files changed, 93 insertions(+), 96 deletions(-) create mode 100644 src/utils/comparisons.rs (limited to 'src') diff --git a/README.md b/README.md index c81fb9b52c1..fee6d066e7c 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ name [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations -[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an term's upcasting to be within the range of the other side of the term is always true or false +[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an upcast which is always true or false [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` diff --git a/src/types.rs b/src/types.rs index 8fede2593ed..5e4b3e673cd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -643,32 +643,21 @@ enum AbsurdComparisonResult { InequalityImpossible, } -enum Rel { - Lt, - Le, -} -// Put the expression in the form lhs < rhs or lhs <= rhs. -fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) - -> Option<(Rel, &'a Expr, &'a Expr)> { - match op { - BiLt => Some((Rel::Lt, lhs, rhs)), - BiLe => Some((Rel::Le, lhs, rhs)), - BiGt => Some((Rel::Lt, rhs, lhs)), - BiGe => Some((Rel::Le, rhs, lhs)), - _ => None, - } -} 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); - if normalized.is_none() { return None; } // Could be an if let, but this prevents rightward drift - let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above"); + let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { + val + } else { + return None; + }; let lx = detect_extreme_expr(cx, normalized_lhs); let rx = detect_extreme_expr(cx, normalized_rhs); @@ -799,8 +788,7 @@ impl LateLintPass for AbsurdExtremeComparisons { /// **Example:** `let x : u8 = ...; (x as u32) > 300` declare_lint! { pub INVALID_UPCAST_COMPARISONS, Warn, - "a comparison involving an term's upcasting to be within the range of the other side of the \ - term is always true or false" + "a comparison involving an upcast which is always true or false" } pub struct InvalidUpcastComparisons; @@ -811,46 +799,39 @@ impl LintPass for InvalidUpcastComparisons { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] enum FullInt { S(i64), U(u64), } -use std; use std::cmp::Ordering; impl FullInt { #[allow(cast_sign_loss)] - fn cmp_s_u(s: &i64, u: &u64) -> std::cmp::Ordering { - if *s < 0 { + fn cmp_s_u(s: i64, u: u64) -> Ordering { + if s < 0 { Ordering::Less - } else if *u > (i64::max_value() as u64) { + } else if u > (i64::max_value() as u64) { Ordering::Greater } else { - (*s as u64).cmp(u) + (s as u64).cmp(&u) } } } -impl PartialEq for FullInt { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl Eq for FullInt {} - impl PartialOrd for FullInt { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(match (self, other) { - (&FullInt::S(ref s), &FullInt::S(ref o)) => s.cmp(o), - (&FullInt::U(ref s), &FullInt::U(ref o)) => s.cmp(o), - (&FullInt::S(ref s), &FullInt::U(ref o)) => Self::cmp_s_u(s, o), - (&FullInt::U(ref s), &FullInt::S(ref o)) => Self::cmp_s_u(o, s).reverse(), + (&FullInt::S(s), &FullInt::S(o)) => s.cmp(&o), + (&FullInt::U(s), &FullInt::U(o)) => s.cmp(&o), + (&FullInt::S(s), &FullInt::U(o)) => Self::cmp_s_u(s, o), + (&FullInt::U(s), &FullInt::S(o)) => Self::cmp_s_u(o, s).reverse(), }) } } impl Ord for FullInt { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { + fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).expect("partial_cmp for FullInt can never return None") } } @@ -896,19 +877,15 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { I8(x) => FullInt::S(x as i64), I16(x) => FullInt::S(x as i64), I32(x) => FullInt::S(x as i64), - Isize(x) => FullInt::S(match x { - Is32(x_) => x_ as i64, - Is64(x_) => x_ - }), + Isize(Is32(x)) => FullInt::S(x as i64), + Isize(Is64(x)) | I64(x) => FullInt::S(x), InferSigned(x) => FullInt::S(x as i64), U8(x) => FullInt::U(x as u64), U16(x) => FullInt::U(x as u64), U32(x) => FullInt::U(x as u64), - Usize(x) => FullInt::U(match x { - Us32(x_) => x_ as u64, - Us64(x_) => x_, - }), + Usize(Us32(x)) => FullInt::U(x as u64), + Usize(Us64(x)) | U64(x) => FullInt::U(x), Infer(x) => FullInt::U(x as u64), }) @@ -920,59 +897,59 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { } } +fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) { + if let ExprCast(ref cast_val, _) = expr.node { + span_lint( + cx, + INVALID_UPCAST_COMPARISONS, + *span, + &format!( + "because of the numeric bounds on `{}` prior to casting, this expression is always {}", + snippet(cx, cast_val.span, "the expression"), + if always { "true" } else { "false" }, + ) + ); + } +} + +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(nlb) = lhs_bounds { + if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { + if match rel { + Rel::Lt => if invert { norm_rhs_val < nlb.0 } else { nlb.1 < norm_rhs_val }, + Rel::Le => if invert { norm_rhs_val <= nlb.0 } else { nlb.1 <= norm_rhs_val }, + } { + err_upcast_comparison(cx, &span, lhs, true) + } else if match rel { + Rel::Lt => if invert { norm_rhs_val >= nlb.1 } else { nlb.0 >= norm_rhs_val }, + Rel::Le => if invert { norm_rhs_val > nlb.1 } else { nlb.0 > norm_rhs_val }, + } { + err_upcast_comparison(cx, &span, lhs, false) + } + } + } +} + impl LateLintPass for InvalidUpcastComparisons { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { - let normalized = normalize_comparison(cmp.node, lhs, rhs); - if normalized.is_none() { return; } - let (rel, normalized_lhs, normalized_rhs) = normalized.expect("Unreachable-- is none check above"); + + let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); + let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { + val + } else { + return; + }; let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); - let msg = "Because of the numeric bounds prior to casting, this expression is always "; - - if let Some(nlb) = lhs_bounds { - if let Some(norm_rhs_val) = node_as_const_fullint(cx, normalized_rhs) { - if match rel { - Rel::Lt => nlb.1 < norm_rhs_val, - Rel::Le => nlb.1 <= norm_rhs_val, - } { - // Expression is always true - cx.span_lint(INVALID_UPCAST_COMPARISONS, - expr.span, - &format!("{}{}.", msg, "true")); - } else if match rel { - Rel::Lt => nlb.0 >= norm_rhs_val, - Rel::Le => nlb.0 > norm_rhs_val, - } { - // Expression is always false - cx.span_lint(INVALID_UPCAST_COMPARISONS, - expr.span, - &format!("{}{}.", msg, "false")); - } - } - } else if let Some(nrb) = rhs_bounds { - if let Some(norm_lhs_val) = node_as_const_fullint(cx, normalized_lhs) { - if match rel { - Rel::Lt => norm_lhs_val < nrb.0, - Rel::Le => norm_lhs_val <= nrb.0, - } { - // Expression is always true - cx.span_lint(INVALID_UPCAST_COMPARISONS, - expr.span, - &format!("{}{}.", msg, "true")); - } else if match rel { - Rel::Lt => norm_lhs_val >= nrb.1, - Rel::Le => norm_lhs_val > nrb.1, - } { - // Expression is always false - cx.span_lint(INVALID_UPCAST_COMPARISONS, - expr.span, - &format!("{}{}.", msg, "false")); - } - } - } + upcast_comparison_bounds_err(cx, &expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false); + upcast_comparison_bounds_err(cx, &expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true); } } } diff --git a/src/utils/comparisons.rs b/src/utils/comparisons.rs new file mode 100644 index 00000000000..2222c31a4f9 --- /dev/null +++ b/src/utils/comparisons.rs @@ -0,0 +1,19 @@ +use rustc_front::hir::{BinOp_, Expr}; + +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum Rel { + Lt, + Le, +} + +/// Put the expression in the form `lhs < rhs` or `lhs <= rhs`. +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)), + BinOp_::BiGt => Some((Rel::Lt, rhs, lhs)), + BinOp_::BiGe => Some((Rel::Le, rhs, lhs)), + _ => None, + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 300cb8df042..7607ef31486 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -19,6 +19,7 @@ use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; +pub mod comparisons; pub mod conf; mod hir; pub use self::hir::{SpanlessEq, SpanlessHash}; diff --git a/tests/compile-fail/invalid_upcast_comparisons.rs b/tests/compile-fail/invalid_upcast_comparisons.rs index d5849420e38..f94b4959287 100644 --- a/tests/compile-fail/invalid_upcast_comparisons.rs +++ b/tests/compile-fail/invalid_upcast_comparisons.rs @@ -7,13 +7,13 @@ fn main() { let zero: u32 = 0; let u8_max: u8 = 255; - (u8_max as u32) > 300; //~ERROR Because of the numeric bounds prior to casting, this expression is always false. + (u8_max as u32) > 300; //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false (u8_max as u32) > 20; - (zero as i32) < -5; //~ERROR Because of the numeric bounds prior to casting, this expression is always false. + (zero as i32) < -5; //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false (zero as i32) < 10; - -5 < (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true. - 0 <= (zero as i32); //~ERROR Because of the numeric bounds prior to casting, this expression is always true. + -5 < (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true + 0 <= (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true 0 < (zero as i32); } -- cgit 1.4.1-3-g733a5 From d52d23d662683050939669609fd4257ef67cbb4c Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Mon, 28 Mar 2016 21:38:54 -0700 Subject: Erased numeric type to reduce branching --- src/types.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 5e4b3e673cd..e9b8e15303a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -873,21 +873,10 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { Ok(val) => { if let Integral(const_int) = val { - Some(match const_int { - I8(x) => FullInt::S(x as i64), - I16(x) => FullInt::S(x as i64), - I32(x) => FullInt::S(x as i64), - Isize(Is32(x)) => FullInt::S(x as i64), - Isize(Is64(x)) | - I64(x) => FullInt::S(x), + Some(match const_int.erase_type() { InferSigned(x) => FullInt::S(x as i64), - U8(x) => FullInt::U(x as u64), - U16(x) => FullInt::U(x as u64), - U32(x) => FullInt::U(x as u64), - Usize(Us32(x)) => FullInt::U(x as u64), - Usize(Us64(x)) | - U64(x) => FullInt::U(x), Infer(x) => FullInt::U(x as u64), + _ => unreachable!(), }) } else { None -- cgit 1.4.1-3-g733a5 From 90a61177298c9d73e2d3b842c199c36e1dfe77e3 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Mon, 28 Mar 2016 21:52:36 -0700 Subject: Reverted to manual implementation of PartialEq for FullInt --- src/types.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index e9b8e15303a..948e8fd063d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -799,7 +799,7 @@ impl LintPass for InvalidUpcastComparisons { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq)] enum FullInt { S(i64), U(u64), @@ -820,6 +820,12 @@ impl FullInt { } } +impl PartialEq for FullInt { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal + } +} + impl PartialOrd for FullInt { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(match (self, other) { -- cgit 1.4.1-3-g733a5 From d050d601fc1d27f486c8f5313330e75a0954a522 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Mon, 28 Mar 2016 22:06:57 -0700 Subject: Added eq and neq handling to invalid upcast comparisons --- src/types.rs | 9 ++++++++- src/utils/comparisons.rs | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 948e8fd063d..9adc2cc5680 100644 --- a/src/types.rs +++ b/src/types.rs @@ -679,6 +679,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs _ => return None, } } + Rel::Ne | Rel::Eq => return None, }) } @@ -914,14 +915,20 @@ fn upcast_comparison_bounds_err( if let Some(nlb) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { - if match rel { + if rel == Rel::Eq || rel == Rel::Ne { + if norm_rhs_val < nlb.0 || norm_rhs_val > nlb.0 { + err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne); + } + } else if match rel { Rel::Lt => if invert { norm_rhs_val < nlb.0 } else { nlb.1 < norm_rhs_val }, Rel::Le => if invert { norm_rhs_val <= nlb.0 } else { nlb.1 <= norm_rhs_val }, + Rel::Eq | Rel::Ne => unreachable!(), } { err_upcast_comparison(cx, &span, lhs, true) } else if match rel { Rel::Lt => if invert { norm_rhs_val >= nlb.1 } else { nlb.0 >= norm_rhs_val }, Rel::Le => if invert { norm_rhs_val > nlb.1 } else { nlb.0 > norm_rhs_val }, + Rel::Eq | Rel::Ne => unreachable!(), } { err_upcast_comparison(cx, &span, lhs, false) } diff --git a/src/utils/comparisons.rs b/src/utils/comparisons.rs index 2222c31a4f9..a9181b35b38 100644 --- a/src/utils/comparisons.rs +++ b/src/utils/comparisons.rs @@ -4,6 +4,8 @@ use rustc_front::hir::{BinOp_, Expr}; pub enum Rel { Lt, Le, + Eq, + Ne, } /// Put the expression in the form `lhs < rhs` or `lhs <= rhs`. @@ -14,6 +16,8 @@ pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) BinOp_::BiLe => Some((Rel::Le, lhs, rhs)), BinOp_::BiGt => Some((Rel::Lt, rhs, lhs)), BinOp_::BiGe => Some((Rel::Le, rhs, lhs)), + BinOp_::BiEq => Some((Rel::Eq, rhs, lhs)), + BinOp_::BiNe => Some((Rel::Ne, rhs, lhs)), _ => None, } } -- cgit 1.4.1-3-g733a5 From 51e63a1ae2b39cf691340f557fdea6f5d50ace35 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 2 Apr 2016 15:43:58 +0200 Subject: Rustup PR #802 --- src/types.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 9adc2cc5680..7c893ef207c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,8 +2,6 @@ use reexport::*; use rustc::lint::*; use rustc::middle::def; use rustc::ty; -use rustc::middle::const_eval::ConstVal::Integral; -use rustc_const_eval; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc_front::util::{is_comparison_binop, binop_to_string}; @@ -11,7 +9,6 @@ use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; use utils::*; - /// Handles all the linting of funky types #[allow(missing_copy_implementations)] pub struct TypePass; @@ -845,7 +842,7 @@ impl Ord for FullInt { fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { - use rustc::middle::ty::TypeVariants::{TyInt, TyUint}; + use rustc::ty::TypeVariants::{TyInt, TyUint}; use syntax::ast::UintTy; use syntax::ast::IntTy; use std::*; @@ -874,15 +871,17 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( } fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { - use rustc::middle::const_eval::EvalHint::ExprTypeChecked; - use rustc_const_eval::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_eval::EvalHint::ExprTypeChecked; + use rustc_const_eval::eval_const_expr_partial; + use rustc_const_math::ConstInt; - match const_eval::eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { Ok(val) => { if let Integral(const_int) = val { Some(match const_int.erase_type() { - InferSigned(x) => FullInt::S(x as i64), - Infer(x) => FullInt::U(x as u64), + ConstInt::InferSigned(x) => FullInt::S(x as i64), + ConstInt::Infer(x) => FullInt::U(x as u64), _ => unreachable!(), }) } else { -- cgit 1.4.1-3-g733a5 From eada860aa74f9b325342ac533c55593beabcc24c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sat, 2 Apr 2016 15:51:28 +0200 Subject: Small fixes in #802 --- src/types.rs | 18 ++++++++---------- tests/compile-fail/invalid_upcast_comparisons.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/types.rs b/src/types.rs index 7c893ef207c..cc618453132 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,6 +5,7 @@ use rustc::ty; use rustc_front::hir::*; use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; use rustc_front::util::{is_comparison_binop, binop_to_string}; +use std::cmp::Ordering; use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; use utils::*; @@ -803,8 +804,6 @@ enum FullInt { U(u64), } -use std::cmp::Ordering; - impl FullInt { #[allow(cast_sign_loss)] fn cmp_s_u(s: i64, u: u64) -> Ordering { @@ -843,8 +842,7 @@ impl Ord for FullInt { fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { use rustc::ty::TypeVariants::{TyInt, TyUint}; - use syntax::ast::UintTy; - use syntax::ast::IntTy; + use syntax::ast::{IntTy, UintTy}; use std::*; if let ExprCast(ref cast_exp,_) = expr.node { @@ -912,21 +910,21 @@ fn upcast_comparison_bounds_err( lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, invert: bool) { use utils::comparisons::*; - if let Some(nlb) = lhs_bounds { + if let Some((lb, ub)) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { if rel == Rel::Eq || rel == Rel::Ne { - if norm_rhs_val < nlb.0 || norm_rhs_val > nlb.0 { + if norm_rhs_val < lb || norm_rhs_val > ub { err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne); } } else if match rel { - Rel::Lt => if invert { norm_rhs_val < nlb.0 } else { nlb.1 < norm_rhs_val }, - Rel::Le => if invert { norm_rhs_val <= nlb.0 } else { nlb.1 <= norm_rhs_val }, + Rel::Lt => if invert { norm_rhs_val < lb } 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) } else if match rel { - Rel::Lt => if invert { norm_rhs_val >= nlb.1 } else { nlb.0 >= norm_rhs_val }, - Rel::Le => if invert { norm_rhs_val > nlb.1 } else { nlb.0 > norm_rhs_val }, + Rel::Lt => if invert { norm_rhs_val >= ub } 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) diff --git a/tests/compile-fail/invalid_upcast_comparisons.rs b/tests/compile-fail/invalid_upcast_comparisons.rs index 6ccba368e62..443dd89aab9 100644 --- a/tests/compile-fail/invalid_upcast_comparisons.rs +++ b/tests/compile-fail/invalid_upcast_comparisons.rs @@ -19,7 +19,17 @@ fn main() { -5 > (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false -5 >= (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false + 1337 == (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false -5 == (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false -5 != (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always true + + // Those are Ok: + 42 == (u8_max as i32); + 42 != (u8_max as i32); + 42 > (u8_max as i32); + (u8_max as i32) == 42; + (u8_max as i32) != 42; + (u8_max as i32) > 42; + (u8_max as i32) < 42; } -- cgit 1.4.1-3-g733a5 From f46e96405fe990ab15d51a8ee54d349f7e79e3b0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 3 Apr 2016 17:16:53 +0200 Subject: Rustup to 1.9.0-nightly (5ab11d72c 2016-04-02) --- src/cyclomatic_complexity.rs | 16 ++++++++-------- src/escape.rs | 2 +- src/matches.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 3db080f970e..ca5acc6895f 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -149,14 +149,14 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { } #[cfg(feature="debugging")] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { - cx.sess().span_bug(span, - &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ - div = {}, shorts = {}. Please file a bug report.", - cc, - narms, - div, - shorts));; +fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { + span_bug!(span, + "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ + div = {}, shorts = {}. Please file a bug report.", + cc, + narms, + div, + shorts); } #[cfg(not(feature="debugging"))] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { diff --git a/src/escape.rs b/src/escape.rs index 51c4c7b6f5d..98500bf62f0 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { self.set.remove(&lid); // Used without autodereffing (i.e. x.clone()) } } else { - self.cx.sess().span_bug(cmt.span, "Unknown adjusted AutoRef"); + span_bug!(cmt.span, "Unknown adjusted AutoRef"); } } else if LoanCause::AddrOf == loan_cause { // &x diff --git a/src/matches.rs b/src/matches.rs index 40013209e57..f1499f7fb94 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -415,8 +415,8 @@ fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, e MatchSource::Normal => format!("match {}{} {{ .. }}", op, expr_snippet), MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet), MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet), - MatchSource::ForLoopDesugar => cx.sess().span_bug(span, "for loop desugared to match with &-patterns!"), - MatchSource::TryDesugar => cx.sess().span_bug(span, "`?` operator desugared to match with &-patterns!") + MatchSource::ForLoopDesugar => span_bug!(span, "for loop desugared to match with &-patterns!"), + MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!") } } -- cgit 1.4.1-3-g733a5 From ee907b73a4935140c547d3f794e31a13e4f6a75a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 4 Apr 2016 20:18:17 +0200 Subject: Fix false positive with `DOC_MARKDOWN` and `32MiB` --- src/doc.rs | 30 +++++++++++++++++++++++------- src/lib.rs | 2 +- src/utils/conf.rs | 2 ++ tests/compile-fail/doc.rs | 13 +++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 9a6a86d4140..0ad238b5522 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -24,8 +24,16 @@ declare_lint! { "checks for the presence of `_`, `::` or camel-case outside ticks in documentation" } -#[derive(Copy,Clone)] -pub struct Doc; +#[derive(Clone)] +pub struct Doc { + valid_idents: Vec<String>, +} + +impl Doc { + pub fn new(valid_idents: Vec<String>) -> Self { + Doc { valid_idents: valid_idents } + } +} impl LintPass for Doc { fn get_lints(&self) -> LintArray { @@ -35,11 +43,11 @@ impl LintPass for Doc { impl EarlyLintPass for Doc { fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { - check_attrs(cx, &krate.attrs, krate.span); + check_attrs(cx, &self.valid_idents, &krate.attrs, krate.span); } fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { - check_attrs(cx, &item.attrs, item.span); + check_attrs(cx, &self.valid_idents, &item.attrs, item.span); } } @@ -73,7 +81,7 @@ fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { } } -pub fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_span: Span) { +pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute], default_span: Span) { let (doc, span) = collect_doc(attrs); let span = span.unwrap_or(default_span); @@ -100,15 +108,19 @@ pub fn check_attrs<'a>(cx: &EarlyContext, attrs: &'a [ast::Attribute], default_s } if !in_ticks { - check_word(cx, word, span); + check_word(cx, valid_idents, word, span); } } } -fn check_word(cx: &EarlyContext, word: &str, span: Span) { +fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span) { /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). fn is_camel_case(s: &str) -> bool { + if s.starts_with(|c: char| c.is_digit(10)) { + return false; + } + let s = if s.ends_with('s') { &s[..s.len()-1] } else { @@ -134,6 +146,10 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { // Or even as in `_foo bar_` which is emphasized. let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + if valid_idents.iter().any(|i| i == word) { + return; + } + if has_underscore(word) || word.contains("::") || is_camel_case(word) { span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word)); } diff --git a/src/lib.rs b/src/lib.rs index f3fc453cf69..7ab48f46223 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,7 +233,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); - reg.register_early_lint_pass(box doc::Doc); + reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents)); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 2411e48997b..e11a6c0d9c7 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -149,6 +149,8 @@ define_Conf! { ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), /// 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"] => Vec<String>), /// 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 diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index a7b316e1f82..635b33be907 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -29,6 +29,18 @@ fn multiline_ticks() { fn test_emphasis() { } +/// This tests units. See also #835. +/// kiB MiB GiB TiB PiB EiB +/// kib Mib Gib Tib Pib Eib +/// kB MB GB TB PB EB +/// kb Mb Gb Tb Pb Eb +/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB +/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib +/// 32kB 32MB 32GB 32TB 32PB 32EB +/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb +fn test_units() { +} + /// This test has [a link with underscores][chunked-example] inside it. See #823. /// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). /// @@ -40,4 +52,5 @@ fn main() { foo_bar(); multiline_ticks(); test_emphasis(); + test_units(); } -- cgit 1.4.1-3-g733a5 From c24ba91123b1a5413de1c9208c1fdf458e1ab8cd Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 7 Apr 2016 17:46:48 +0200 Subject: Rustup to 1.9.0-nightly (bf5da36f1 2016-04-06) --- src/approx_const.rs | 2 +- src/array_indexing.rs | 2 +- src/attrs.rs | 2 +- src/bit_mask.rs | 7 +++---- src/blacklisted_name.rs | 2 +- src/block_in_if_condition.rs | 4 ++-- src/booleans.rs | 4 ++-- src/collapsible_if.rs | 2 +- src/consts.rs | 4 ++-- src/copies.rs | 2 +- src/cyclomatic_complexity.rs | 4 ++-- src/derive.rs | 2 +- src/drop_ref.rs | 2 +- src/entry.rs | 4 ++-- src/enum_clike.rs | 2 +- src/enum_glob_use.rs | 6 +++--- src/eq_op.rs | 5 ++--- src/escape.rs | 8 ++++---- src/eta_reduction.rs | 2 +- src/format.rs | 4 ++-- src/functions.rs | 6 +++--- src/identity_op.rs | 2 +- src/len_zero.rs | 8 +++++--- src/lib.rs | 2 -- src/lifetimes.rs | 6 +++--- src/loops.rs | 8 ++++---- src/map_clone.rs | 2 +- src/matches.rs | 2 +- src/methods.rs | 2 +- src/minmax.rs | 2 +- src/misc.rs | 11 +++++------ src/mut_mut.rs | 2 +- src/mut_reference.rs | 2 +- src/mutex_atomic.rs | 2 +- src/needless_bool.rs | 2 +- src/needless_update.rs | 2 +- src/new_without_default.rs | 4 ++-- src/no_effect.rs | 4 ++-- src/open_options.rs | 2 +- src/overflow_check_conditional.rs | 2 +- src/panic.rs | 2 +- src/print.rs | 4 ++-- src/ptr_arg.rs | 4 ++-- src/ranges.rs | 2 +- src/regex.rs | 3 +-- src/shadow.rs | 6 +++--- src/strings.rs | 2 +- src/swap.rs | 2 +- src/temporary_assignment.rs | 2 +- src/transmute.rs | 2 +- src/types.rs | 10 ++++------ src/unicode.rs | 2 +- src/unused_label.rs | 4 ++-- src/utils/comparisons.rs | 2 +- src/utils/hir.rs | 2 +- src/utils/mod.rs | 39 ++++++++++++++++++++++++--------------- src/vec.rs | 2 +- src/zero_div_zero.rs | 2 +- tests/compile-fail/transmute.rs | 26 +++++++++++++++----------- tests/consts.rs | 3 +-- 60 files changed, 135 insertions(+), 129 deletions(-) (limited to 'src') diff --git a/src/approx_const.rs b/src/approx_const.rs index 822fbd16c32..731f1a45d09 100644 --- a/src/approx_const.rs +++ b/src/approx_const.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use std::f64::consts as f64; use syntax::ast::{Lit, LitKind, FloatTy}; use utils::span_lint; diff --git a/src/array_indexing.rs b/src/array_indexing.rs index e5f54c128ef..ce5c85500bd 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -4,7 +4,7 @@ use rustc::ty::TyArray; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; use rustc_const_math::ConstInt; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::RangeLimits; use utils; diff --git a/src/attrs.rs b/src/attrs.rs index 363809c37bb..17b8a60bcb9 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -2,7 +2,7 @@ use reexport::*; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; use syntax::attr::*; diff --git a/src/bit_mask.rs b/src/bit_mask.rs index cbe601ba1b4..45f7e5bc938 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -1,8 +1,7 @@ +use rustc::hir::*; +use rustc::hir::def::{Def, PathResolution}; use rustc::lint::*; -use rustc::middle::def::{Def, PathResolution}; use rustc_const_eval::lookup_const_by_id; -use rustc_front::hir::*; -use rustc_front::util::is_comparison_binop; use syntax::ast::LitKind; use syntax::codemap::Span; use utils::span_lint; @@ -91,7 +90,7 @@ impl LintPass for BitMask { impl LateLintPass for BitMask { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = e.node { - if is_comparison_binop(cmp.node) { + if cmp.node.is_comparison() { fetch_int_literal(cx, right).map_or_else(|| { fetch_int_literal(cx, left).map_or((), |cmp_val| { check_compare(cx, diff --git a/src/blacklisted_name.rs b/src/blacklisted_name.rs index 25c0bac2c37..b515da000ee 100644 --- a/src/blacklisted_name.rs +++ b/src/blacklisted_name.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use utils::span_lint; /// **What it does:** This lints about usage of blacklisted names. diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 9cb11968abc..1a2123fe00a 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_expr}; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr}; use utils::*; /// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. diff --git a/src/booleans.rs b/src/booleans.rs index 37ad927ef92..213d12b42ef 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -1,6 +1,6 @@ use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; -use rustc_front::hir::*; -use rustc_front::intravisit::*; +use rustc::hir::*; +use rustc::hir::intravisit::*; use syntax::ast::{LitKind, DUMMY_NODE_ID}; use syntax::codemap::{DUMMY_SP, dummy_spanned}; use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 74397304eda..5674806b175 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -13,7 +13,7 @@ //! This lint is **warn** by default use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use std::borrow::Cow; use syntax::codemap::Spanned; diff --git a/src/consts.rs b/src/consts.rs index 73f2bc4653a..d30392e0586 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,10 +1,10 @@ #![allow(cast_possible_truncation)] use rustc::lint::LateContext; -use rustc::middle::def::{Def, PathResolution}; +use rustc::hir::def::{Def, PathResolution}; use rustc_const_eval::lookup_const_by_id; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; -use rustc_front::hir::*; +use rustc::hir::*; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; diff --git a/src/copies.rs b/src/copies.rs index b8eb97cbeed..5b992cf38ae 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use std::collections::HashMap; use std::collections::hash_map::Entry; use syntax::parse::token::InternedString; diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index ca5acc6895f..fcd89801ecc 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -3,8 +3,8 @@ use rustc::lint::*; use rustc::cfg::CFG; use rustc::ty; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_expr}; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr}; use syntax::ast::Attribute; use syntax::attr::*; use syntax::codemap::Span; diff --git a/src/derive.rs b/src/derive.rs index ab4f73eafc0..593118bef84 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -3,7 +3,7 @@ use rustc::ty::subst::Subst; use rustc::ty::TypeVariants; use rustc::ty::fast_reject::simplify_type; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::{Attribute, MetaItemKind}; use syntax::codemap::Span; use utils::{CLONE_TRAIT_PATH, HASH_PATH}; diff --git a/src/drop_ref.rs b/src/drop_ref.rs index 7536fb1b63b..3448e05dbac 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::Span; use utils::DROP_PATH; use utils::{match_def_path, span_note_and_lint}; diff --git a/src/entry.rs b/src/entry.rs index 8a4cf37c0ac..934400bc122 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,6 +1,6 @@ use rustc::lint::*; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_expr, walk_block}; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block}; use syntax::codemap::Span; use utils::SpanlessEq; use utils::{BTREEMAP_PATH, HASHMAP_PATH}; diff --git a/src/enum_clike.rs b/src/enum_clike.rs index 0e2a7a5304f..e3e8f1e5eb6 100644 --- a/src/enum_clike.rs +++ b/src/enum_clike.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc_const_math::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::attr::*; use utils::span_lint; diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index 5b29f84ef51..671b9bb141c 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -1,10 +1,10 @@ //! lint on `use`ing all variants of an enum -use rustc::front::map::Node::NodeItem; +use rustc::hir::*; +use rustc::hir::def::Def; +use rustc::hir::map::Node::NodeItem; use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray, LintContext}; -use rustc::middle::def::Def; use rustc::middle::cstore::DefLike; -use rustc_front::hir::*; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::span_lint; diff --git a/src/eq_op.rs b/src/eq_op.rs index 09ac6325f96..fb06639853c 100644 --- a/src/eq_op.rs +++ b/src/eq_op.rs @@ -1,6 +1,5 @@ +use rustc::hir::*; use rustc::lint::*; -use rustc_front::hir::*; -use rustc_front::util as ast_util; use utils::{SpanlessEq, span_lint}; /// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, @@ -34,7 +33,7 @@ impl LateLintPass for EqOp { span_lint(cx, EQ_OP, e.span, - &format!("equal expressions as operands to `{}`", ast_util::binop_to_string(op.node))); + &format!("equal expressions as operands to `{}`", op.node.as_str())); } } } diff --git a/src/escape.rs b/src/escape.rs index 98500bf62f0..fa235244884 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,14 +1,14 @@ -use rustc::front::map::Node::{NodeExpr, NodeStmt}; +use rustc::hir::*; +use rustc::hir::intravisit as visit; +use rustc::hir::map::Node::{NodeExpr, NodeStmt}; +use rustc::infer; use rustc::lint::*; use rustc::middle::expr_use_visitor::*; -use rustc::infer; use rustc::middle::mem_categorization::{cmt, Categorization}; use rustc::traits::ProjectionMode; use rustc::ty::adjustment::AutoAdjustment; use rustc::ty; use rustc::util::nodemap::NodeSet; -use rustc_front::hir::*; -use rustc_front::intravisit as visit; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::span_lint; diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index c080968ef84..4519acc39de 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use utils::{snippet_opt, span_lint_and_then, is_adjusted}; #[allow(missing_copy_implementations)] diff --git a/src/format.rs b/src/format.rs index 300b3d17b39..0a349c98e07 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,7 +1,7 @@ -use rustc::front::map::Node::NodeItem; +use rustc::hir::map::Node::NodeItem; use rustc::lint::*; use rustc::ty::TypeVariants; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::LitKind; use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH, STRING_PATH}; use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty}; diff --git a/src/functions.rs b/src/functions.rs index 5ac5aae51a4..ed04473abc3 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -1,6 +1,6 @@ use rustc::lint::*; -use rustc_front::hir; -use rustc_front::intravisit; +use rustc::hir; +use rustc::hir::intravisit; use syntax::ast; use syntax::codemap::Span; use utils::span_lint; @@ -45,7 +45,7 @@ impl LintPass for Functions { impl LateLintPass for Functions { fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) { - use rustc::front::map::Node::*; + use rustc::hir::map::Node::*; if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { match item.node { diff --git a/src/identity_op.rs b/src/identity_op.rs index c25047b87b4..4c1f01b7385 100644 --- a/src/identity_op.rs +++ b/src/identity_op.rs @@ -1,6 +1,6 @@ use consts::{constant_simple, Constant}; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::Span; use utils::{span_lint, snippet, in_macro}; use rustc_const_math::ConstInt; diff --git a/src/len_zero.rs b/src/len_zero.rs index 1a097820e1e..3a376d91c92 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -1,7 +1,7 @@ use rustc::lint::*; -use rustc::middle::def_id::DefId; +use rustc::hir::def_id::DefId; use rustc::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::{Lit, LitKind, Name}; use syntax::codemap::{Span, Spanned}; use syntax::ptr::P; @@ -111,6 +111,8 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { for i in impl_items { if is_named_self(i, "len") { + let ty = cx.tcx.node_id_to_type(item.id); + let s = i.span; span_lint(cx, LEN_WITHOUT_IS_EMPTY, @@ -121,7 +123,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { }, &format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ Consider adding one", - item.name)); + ty)); return; } } diff --git a/src/lib.rs b/src/lib.rs index 7ab48f46223..1b48c7b3dbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,8 +19,6 @@ fn main() { extern crate syntax; #[macro_use] extern crate rustc; -#[macro_use] -extern crate rustc_front; extern crate toml; diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 72fdba07d32..ad42a8568e6 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -1,8 +1,8 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::def::Def; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl, walk_generics}; +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 std::collections::{HashSet, HashMap}; use syntax::codemap::Span; use utils::{in_external_macro, span_lint}; diff --git a/src/loops.rs b/src/loops.rs index 20d0fc026d1..4e7e4bf117d 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -1,14 +1,14 @@ use reexport::*; -use rustc::front::map::Node::NodeBlock; +use rustc::hir::*; +use rustc::hir::def::Def; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; +use rustc::hir::map::Node::NodeBlock; use rustc::lint::*; use rustc::middle::const_val::ConstVal; -use rustc::middle::def::Def; use rustc::middle::region::CodeExtent; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; use std::borrow::Cow; use std::collections::HashMap; use syntax::ast; diff --git a/src/map_clone.rs b/src/map_clone.rs index 4eac4dc6113..eeb3aab4655 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use utils::{CLONE_PATH, OPTION_PATH}; use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; diff --git a/src/matches.rs b/src/matches.rs index f1499f7fb94..d82dad5b065 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -1,10 +1,10 @@ +use rustc::hir::*; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; use rustc_const_math::ConstInt; -use rustc_front::hir::*; use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; diff --git a/src/methods.rs b/src/methods.rs index 646cd319a0c..3fcd472faf5 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,3 +1,4 @@ +use rustc::hir::*; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::CrateStore; @@ -5,7 +6,6 @@ use rustc::ty::subst::{Subst, TypeSpace}; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; -use rustc_front::hir::*; use std::borrow::Cow; use std::fmt; use syntax::codemap::Span; diff --git a/src/minmax.rs b/src/minmax.rs index 0560bf15604..67299bac998 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,6 +1,6 @@ use consts::{Constant, constant_simple}; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use std::cmp::{PartialOrd, Ordering}; use syntax::ptr::P; use utils::{match_def_path, span_lint}; diff --git a/src/misc.rs b/src/misc.rs index a6cfec276e5..654e6244c1b 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,12 +1,11 @@ use reexport::*; +use rustc::hir::*; +use rustc::hir::intravisit::FnKind; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; -use rustc_front::hir::*; -use rustc_front::intravisit::FnKind; -use rustc_front::util::{is_comparison_binop, binop_to_string}; use syntax::codemap::{Span, Spanned, ExpnFormat}; use syntax::ptr::P; use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; @@ -105,7 +104,7 @@ impl LintPass for CmpNan { impl LateLintPass for CmpNan { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if is_comparison_binop(cmp.node) { + if cmp.node.is_comparison() { if let ExprPath(_, ref path) = left.node { check_nan(cx, path, expr.span); } @@ -170,7 +169,7 @@ impl LateLintPass for FloatCmp { &format!("{}-comparison of f32 or f64 detected. Consider changing this to `({} - {}).abs() < \ epsilon` for some suitable value of epsilon. \ std::f32::EPSILON and std::f64::EPSILON are available.", - binop_to_string(op), + op.as_str(), snippet(cx, left.span, ".."), snippet(cx, right.span, ".."))); } @@ -217,7 +216,7 @@ impl LintPass for CmpOwned { impl LateLintPass for CmpOwned { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if is_comparison_binop(cmp.node) { + if cmp.node.is_comparison() { check_to_owned(cx, left, right, true, cmp.span); check_to_owned(cx, right, left, false, cmp.span) } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index a5ed233241d..65e2c3a46a9 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty::{TypeAndMut, TyRef}; -use rustc_front::hir::*; +use rustc::hir::*; use utils::{in_external_macro, span_lint}; /// **What it does:** This lint checks for instances of `mut mut` references. diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 95ed1092eb5..d74c2c41f23 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ptr::P; use utils::span_lint; diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index 0593438cfc1..bae1ae38168 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -5,7 +5,7 @@ use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; use rustc::ty::subst::ParamSpace; use rustc::ty; -use rustc_front::hir::Expr; +use rustc::hir::Expr; use syntax::ast; use utils::{span_lint, MUTEX_PATH, match_type}; diff --git a/src/needless_bool.rs b/src/needless_bool.rs index ab5a1e26b20..07da57c684b 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -3,7 +3,7 @@ //! This lint is **warn** by default use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::LitKind; use syntax::codemap::Spanned; use utils::{span_lint, span_lint_and_then, snippet, snippet_opt}; diff --git a/src/needless_update.rs b/src/needless_update.rs index d25f66ca434..d8ae9dc3471 100644 --- a/src/needless_update.rs +++ b/src/needless_update.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::ty::TyStruct; -use rustc_front::hir::{Expr, ExprStruct}; +use rustc::hir::{Expr, ExprStruct}; use utils::span_lint; /// **What it does:** This lint warns on needlessly including a base struct on update when all fields are changed anyway. diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 395d69138e1..2bcc345fd60 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -1,6 +1,6 @@ use rustc::lint::*; -use rustc_front::hir; -use rustc_front::intravisit::FnKind; +use rustc::hir; +use rustc::hir::intravisit::FnKind; use syntax::ast; use syntax::codemap::Span; use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint, diff --git a/src/no_effect.rs b/src/no_effect.rs index 59f7be94c23..afb49376b3f 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::middle::def::Def; -use rustc_front::hir::{Expr, Expr_, Stmt, StmtSemi}; +use rustc::hir::def::Def; +use rustc::hir::{Expr, Expr_, Stmt, StmtSemi}; use utils::{in_macro, span_lint}; /// **What it does:** This lint checks for statements which have no effect. diff --git a/src/open_options.rs b/src/open_options.rs index e3f61afcf1c..3c1e69a40ea 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::{Expr, ExprMethodCall, ExprLit}; +use rustc::hir::{Expr, ExprMethodCall, ExprLit}; use syntax::ast::LitKind; use syntax::codemap::{Span, Spanned}; use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index 823cb696901..627028ad462 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use utils::{span_lint}; /// **What it does:** This lint finds classic underflow / overflow checks. diff --git a/src/panic.rs b/src/panic.rs index 8b9bf9f1f19..ab03181c2dd 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::LitKind; use utils::{span_lint, is_direct_expn_of, match_path, BEGIN_UNWIND}; diff --git a/src/print.rs b/src/print.rs index ffe20d13cea..a298d162c05 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,6 +1,6 @@ -use rustc::front::map::Node::{NodeItem, NodeImplItem}; +use rustc::hir::map::Node::{NodeItem, NodeImplItem}; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use utils::{FMT_ARGUMENTV1_NEW_PATH, DEBUG_FMT_METHOD_PATH, IO_PRINT_PATH}; use utils::{is_expn_of, match_path, span_lint}; diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 6498db66e13..8720424da86 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -1,9 +1,9 @@ //! Checks for usage of `&Vec[_]` and `&String`. -use rustc::front::map::NodeItem; +use rustc::hir::map::NodeItem; use rustc::lint::*; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::NodeId; use utils::{STRING_PATH, VEC_PATH}; use utils::{span_lint, match_type}; diff --git a/src/ranges.rs b/src/ranges.rs index 23bd3d1103c..c2555da1d0b 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::Spanned; use utils::{is_integer_literal, match_type, snippet, span_lint, unsugar_range, UnsugaredRange}; diff --git a/src/regex.rs b/src/regex.rs index 46ee7776d66..f24639312ed 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,15 +1,14 @@ use regex_syntax; +use rustc::hir::*; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; -use rustc_front::hir::*; use std::collections::HashSet; use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; - use utils::{is_expn_of, match_path, match_type, REGEX_NEW_PATH, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. diff --git a/src/shadow.rs b/src/shadow.rs index baf5c9b8872..928d447974a 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -1,8 +1,8 @@ use reexport::*; use rustc::lint::*; -use rustc::middle::def::Def; -use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, FnKind}; +use rustc::hir::def::Def; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, FnKind}; use std::ops::Deref; use syntax::codemap::Span; use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; diff --git a/src/strings.rs b/src/strings.rs index 9f68175b202..da1456671fd 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -4,7 +4,7 @@ //! disable the subsumed lint unless it has a higher level use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::Spanned; use utils::STRING_PATH; use utils::SpanlessEq; diff --git a/src/swap.rs b/src/swap.rs index 6d7212233fb..29db0da5cf9 100644 --- a/src/swap.rs +++ b/src/swap.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::mk_sp; use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs index c945fd7148e..44796410458 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -1,5 +1,5 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc_front::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; +use rustc::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; use utils::is_adjusted; use utils::span_lint; diff --git a/src/transmute.rs b/src/transmute.rs index ef049ba4a6d..41b92ca6113 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; use rustc::ty; -use rustc_front::hir::*; +use rustc::hir::*; use utils::TRANSMUTE_PATH; use utils::{match_def_path, snippet_opt, span_lint, span_lint_and_then}; diff --git a/src/types.rs b/src/types.rs index cc618453132..281af90736b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,10 +1,8 @@ use reexport::*; +use rustc::hir::*; +use rustc::hir::intravisit::{FnKind, Visitor, walk_ty}; use rustc::lint::*; -use rustc::middle::def; use rustc::ty; -use rustc_front::hir::*; -use rustc_front::intravisit::{FnKind, Visitor, walk_ty}; -use rustc_front::util::{is_comparison_binop, binop_to_string}; use std::cmp::Ordering; use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; @@ -162,7 +160,7 @@ impl LateLintPass for UnitCmp { if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; let sty = &cx.tcx.expr_ty(left).sty; - if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) { + if *sty == ty::TyTuple(vec![]) && op.is_comparison() { let result = match op { BiEq | BiLe | BiGe => "true", _ => "false", @@ -171,7 +169,7 @@ impl LateLintPass for UnitCmp { UNIT_CMP, expr.span, &format!("{}-comparison of unit values detected. This will always be {}", - binop_to_string(op), + op.as_str(), result)); } } diff --git a/src/unicode.rs b/src/unicode.rs index 0f21822ea08..26521017ee5 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -1,5 +1,5 @@ use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::LitKind; use syntax::codemap::Span; use unicode_normalization::UnicodeNormalization; diff --git a/src/unused_label.rs b/src/unused_label.rs index f2ecad7cc82..f6ff3c3d4b4 100644 --- a/src/unused_label.rs +++ b/src/unused_label.rs @@ -1,6 +1,6 @@ use rustc::lint::*; -use rustc_front::hir; -use rustc_front::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; +use rustc::hir; +use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; use std::collections::HashMap; use syntax::ast; use syntax::codemap::Span; diff --git a/src/utils/comparisons.rs b/src/utils/comparisons.rs index a9181b35b38..b890a363fb7 100644 --- a/src/utils/comparisons.rs +++ b/src/utils/comparisons.rs @@ -1,4 +1,4 @@ -use rustc_front::hir::{BinOp_, Expr}; +use rustc::hir::{BinOp_, Expr}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum Rel { diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 0659e26d0f2..f6fa2176941 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -1,6 +1,6 @@ use consts::constant; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use std::hash::{Hash, Hasher, SipHasher}; use syntax::ast::Name; use syntax::ptr::P; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 7607ef31486..761d5d3df9d 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,15 +1,15 @@ use reexport::*; -use rustc::front::map::Node; +use rustc::hir::*; +use rustc::hir::def_id::DefId; +use rustc::hir::map::Node; +use rustc::infer; use rustc::lint::{LintContext, LateContext, Level, Lint}; -use rustc::middle::def_id::DefId; -use rustc::traits; +use rustc::middle::cstore; +use rustc::session::Session; use rustc::traits::ProjectionMode; -use rustc::middle::{cstore, def}; -use rustc::infer; -use rustc::ty; +use rustc::traits; use rustc::ty::subst::Subst; -use rustc::session::Session; -use rustc_front::hir::*; +use rustc::ty; use std::borrow::Cow; use std::mem; use std::ops::{Deref, DerefMut}; @@ -56,7 +56,7 @@ pub const RANGE_TO_PATH: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const TRANSMUTE_PATH: [&'static str; 3] = ["core", "intrinsics", "transmute"]; +pub const TRANSMUTE_PATH: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"]; @@ -157,13 +157,22 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { /// match_def_path(cx, id, &["core", "option", "Option"]) /// ``` pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - cx.tcx.with_path(def_id, |iter| { - let mut len = 0; + let krate = &cx.tcx.crate_name(def_id.krate); + if krate != &path[0] { + return false; + } - iter.inspect(|_| len += 1) - .zip(path) - .all(|(nm, p)| nm.name().as_str() == *p) && len == path.len() - }) + let path = &path[1..]; + let other = cx.tcx.def_path(def_id).data; + + if other.len() != path.len() { + return false; + } + + other.into_iter() + .map(|e| e.data) + .zip(path) + .all(|(nm, p)| nm.as_interned_str() == *p) } /// Check if type is struct or enum type with given def path. diff --git a/src/vec.rs b/src/vec.rs index 412ebf396dd..d27a3320d96 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::ty::TypeVariants; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::codemap::Span; use syntax::ptr::P; use utils::VEC_FROM_ELEM_PATH; diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs index f58b0e695a9..902d84d4dd3 100644 --- a/src/zero_div_zero.rs +++ b/src/zero_div_zero.rs @@ -1,6 +1,6 @@ use consts::{Constant, constant_simple, FloatWidth}; use rustc::lint::*; -use rustc_front::hir::*; +use rustc::hir::*; use utils::span_help_and_lint; /// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists diff --git a/tests/compile-fail/transmute.rs b/tests/compile-fail/transmute.rs index cd86281d8f2..ad97410cf65 100644 --- a/tests/compile-fail/transmute.rs +++ b/tests/compile-fail/transmute.rs @@ -6,6 +6,10 @@ extern crate core; use std::mem::transmute as my_transmute; use std::vec::Vec as MyVec; +fn my_int() -> usize { + 42 +} + fn my_vec() -> MyVec<i32> { vec![] } @@ -86,22 +90,22 @@ fn useless() { #[deny(crosspointer_transmute)] fn crosspointer() { - let mut vec: Vec<i32> = vec![]; - let vec_const_ptr: *const Vec<i32> = &vec as *const Vec<i32>; - let vec_mut_ptr: *mut Vec<i32> = &mut vec as *mut Vec<i32>; + let mut int: usize = 0; + let int_const_ptr: *const usize = &int as *const usize; + let int_mut_ptr: *mut usize = &mut int as *mut usize; unsafe { - let _: Vec<i32> = core::intrinsics::transmute(vec_const_ptr); - //~^ ERROR transmute from a type (`*const std::vec::Vec<i32>`) to the type that it points to (`std::vec::Vec<i32>`) + let _: usize = core::intrinsics::transmute(int_const_ptr); + //~^ ERROR transmute from a type (`*const usize`) to the type that it points to (`usize`) - let _: Vec<i32> = core::intrinsics::transmute(vec_mut_ptr); - //~^ ERROR transmute from a type (`*mut std::vec::Vec<i32>`) to the type that it points to (`std::vec::Vec<i32>`) + let _: usize = core::intrinsics::transmute(int_mut_ptr); + //~^ ERROR transmute from a type (`*mut usize`) to the type that it points to (`usize`) - let _: *const Vec<i32> = core::intrinsics::transmute(my_vec()); - //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to a pointer to that type (`*const std::vec::Vec<i32>`) + let _: *const usize = core::intrinsics::transmute(my_int()); + //~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*const usize`) - let _: *mut Vec<i32> = core::intrinsics::transmute(my_vec()); - //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to a pointer to that type (`*mut std::vec::Vec<i32>`) + let _: *mut usize = core::intrinsics::transmute(my_int()); + //~^ ERROR transmute from a type (`usize`) to a pointer to that type (`*mut usize`) } } diff --git a/tests/consts.rs b/tests/consts.rs index b7b2f6a3f83..4b3aba3f6be 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -5,12 +5,11 @@ extern crate clippy; extern crate rustc; extern crate rustc_const_eval; extern crate rustc_const_math; -extern crate rustc_front; extern crate syntax; use clippy::consts::{constant_simple, Constant, FloatWidth}; use rustc_const_math::ConstInt; -use rustc_front::hir::*; +use rustc::hir::*; use syntax::ast::{LitIntType, LitKind, StrStyle}; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; use syntax::parse::token::InternedString; -- cgit 1.4.1-3-g733a5 From 532446d3f8cc5bb1c01d4cdcced86ef1f3529897 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 8 Apr 2016 17:31:47 +0200 Subject: Rustup to 1.9.0-nightly (7979dd608 2016-04-07) --- src/derive.rs | 65 +++++++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/derive.rs b/src/derive.rs index 593118bef84..4b8446e6201 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -1,7 +1,6 @@ use rustc::lint::*; use rustc::ty::subst::Subst; use rustc::ty::TypeVariants; -use rustc::ty::fast_reject::simplify_type; use rustc::ty; use rustc::hir::*; use syntax::ast::{Attribute, MetaItemKind}; @@ -87,52 +86,44 @@ impl LateLintPass for Derive { } /// Implementation of the `DERIVE_HASH_XOR_EQ` lint. -fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty, 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, &HASH_PATH), 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); - cx.tcx.populate_implementations_for_trait_if_necessary(peq_trait_def.trait_ref.def_id); - let peq_impls = peq_trait_def.borrow_impl_lists(cx.tcx).1; - // Look for the PartialEq implementations for `ty` - if_let_chain! {[ - let Some(simpl_ty) = simplify_type(cx.tcx, ty, false), - let Some(impl_ids) = peq_impls.get(&simpl_ty) - ], { - for &impl_id in impl_ids { - let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); + peq_trait_def.for_each_relevant_impl(&cx.tcx, ty, |impl_id| { + let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); - if peq_is_automatically_derived == hash_is_automatically_derived { - return; - } + if peq_is_automatically_derived == hash_is_automatically_derived { + return; + } - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialEq<Foo> for Foo` - if trait_ref.input_types()[0] == ty { - let mess = if peq_is_automatically_derived { - "you are implementing `Hash` explicitly but have derived `PartialEq`" - } else { - "you are deriving `Hash` but have implemented `PartialEq` explicitly" - }; - - span_lint_and_then( - cx, DERIVE_HASH_XOR_EQ, span, - mess, - |db| { - if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { - db.span_note( - cx.tcx.map.span(node_id), - "`PartialEq` implemented here" - ); - } - }); - } + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialEq<Foo> for Foo` + if trait_ref.input_types()[0] == ty { + let mess = if peq_is_automatically_derived { + "you are implementing `Hash` explicitly but have derived `PartialEq`" + } else { + "you are deriving `Hash` but have implemented `PartialEq` explicitly" + }; + + span_lint_and_then( + cx, DERIVE_HASH_XOR_EQ, span, + mess, + |db| { + if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { + db.span_note( + cx.tcx.map.span(node_id), + "`PartialEq` implemented here" + ); + } + }); } - }} + }); }} } -- cgit 1.4.1-3-g733a5 From 9c4ae9295dbcf16a1cabf351149df0d1c0d100ea Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 11 Apr 2016 23:23:49 +0200 Subject: Markdownify more doc --- src/methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 3fcd472faf5..45f87fba9dd 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -805,7 +805,7 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { None } -/// This checks whether a given type is known to implement Debug. +/// This checks whether a given type is known to implement `Debug`. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { match cx.tcx.lang_items.debug_trait() { Some(debug) => implements_trait(cx, ty, debug, Vec::new()), -- cgit 1.4.1-3-g733a5 From 29c058f0af1306e6c7d7a6b633a758d36dc89fef Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Mon, 11 Apr 2016 23:59:52 +0200 Subject: add a note of rust-lang/rust/#31439 to the wiki text --- src/returns.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/returns.rs b/src/returns.rs index 43ea3780173..bb94b59df7d 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -9,7 +9,7 @@ use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_exter /// /// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty. /// -/// **Known problems:** None +/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. /// /// **Example:** `fn foo(x: usize) { return x; }` declare_lint! { @@ -21,7 +21,7 @@ declare_lint! { /// /// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. /// -/// **Known problems:** None +/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. /// /// **Example:** `{ let x = ..; x }` declare_lint! { -- cgit 1.4.1-3-g733a5 From 6c0a486e8b3f9801a408b89946cb6c8245a88061 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 11 Apr 2016 23:22:30 +0200 Subject: Fix FP with `DOC_MARKDOWN` and reference links --- src/doc.rs | 101 ++++++++++++++++++++++++++++++++++++++-------- tests/compile-fail/doc.rs | 11 +++-- 2 files changed, 93 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 0ad238b5522..da87b104341 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -84,7 +84,32 @@ fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute], default_span: Span) { let (doc, span) = collect_doc(attrs); let span = span.unwrap_or(default_span); + check_doc(cx, valid_idents, &doc, span); +} + +macro_rules! jump_to { + // Get the next character’s first byte UTF-8 friendlyly. + (@next_char, $chars: expr, $len: expr) => {{ + if let Some(&(pos, _)) = $chars.peek() { + pos + } else { + $len + } + }}; + + // Jump to the next `$c`. If no such character is found, give up. + ($chars: expr, $c: expr, $len: expr) => {{ + if $chars.find(|&(_, c)| c == $c).is_some() { + jump_to!(@next_char, $chars, $len) + } + else { + return; + } + }}; +} +#[allow(while_let_loop)] // #362 +pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Span) { // In markdown, `_` can be used to emphasize something, or, is a raw `_` depending on context. // There really is no markdown specification that would disambiguate this properly. This is // what GitHub and Rustdoc do: @@ -96,19 +121,68 @@ pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [a // (_baz_) → (<em>baz</em>) // foo _ bar _ baz → foo _ bar _ baz - let mut in_ticks = false; - for word in doc.split_whitespace() { - let ticks = word.bytes().filter(|&b| b == b'`').count(); - - if ticks == 2 { // likely to be “`foo`” - continue; - } else if ticks % 2 == 1 { - in_ticks = !in_ticks; - continue; // let’s assume no one will ever write something like “`foo`_bar” + /// Character that can appear in a word + fn is_word_char(c: char) -> bool { + match c { + t if t.is_alphanumeric() => true, + ':' | '_' => true, + _ => false, } + } - if !in_ticks { - check_word(cx, valid_idents, word, span); + let len = doc.len(); + let mut chars = doc.char_indices().peekable(); + let mut current_word_begin = 0; + loop { + match chars.next() { + Some((_, c)) => { + match c { + c if c.is_whitespace() => { + current_word_begin = jump_to!(@next_char, chars, len); + } + '`' => { + current_word_begin = jump_to!(chars, '`', len); + }, + '[' => { + let end = jump_to!(chars, ']', len); + let link_text = &doc[current_word_begin+1..end]; + + match chars.peek() { + Some(&(_, c)) => { + // Trying to parse a link. Let’s ignore the link. + + // FIXME: how does markdown handles such link? + // https://en.wikipedia.org/w/index.php?title=) + match c { + '(' => { // inline link + current_word_begin = jump_to!(chars, ')', len); + check_doc(cx, valid_idents, link_text, span); + } + '[' => { // reference link + current_word_begin = jump_to!(chars, ']', len); + check_doc(cx, valid_idents, link_text, span); + } + ':' => { // reference link + current_word_begin = jump_to!(chars, '\n', len); + } + _ => continue, + } + } + None => return, + } + } + _ => { + let end = match chars.find(|&(_, c)| !is_word_char(c)) { + Some((end, _)) => end, + None => len, + }; + + check_word(cx, valid_idents, &doc[current_word_begin..end], span); + current_word_begin = jump_to!(@next_char, chars, len); + } + } + } + None => break, } } } @@ -136,11 +210,6 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span s != "_" && !s.contains("\\_") && s.contains('_') } - // Something with a `/` might be a link, don’t warn (see #823): - if word.contains('/') { - return; - } - // Trim punctuation as in `some comment (see foo::bar).` // ^^ // Or even as in `_foo bar_` which is emphasized. diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 635b33be907..81250b5485a 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -41,14 +41,19 @@ fn test_emphasis() { fn test_units() { } -/// This test has [a link with underscores][chunked-example] inside it. See #823. -/// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). +/// This test has [a link_with_underscores][chunked-example] inside it. See #823. +/// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). And here is another [inline link][inline_link]. /// -/// [chunked-example]: http://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example +/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example +/// [inline_link]: https://foobar /// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and /// `multiline_ticks` functions. +/// +/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , fn main() { +//~^ ERROR: you should put `link_with_underscores` between ticks foo_bar(); multiline_ticks(); test_emphasis(); -- cgit 1.4.1-3-g733a5 From fe6e8dac3592b3e73120ff5ce9569c0f2323dd74 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 13 Apr 2016 16:02:44 +0200 Subject: More tests in `DOC_MARKDOWN` --- src/doc.rs | 5 ++++- src/utils/conf.rs | 2 +- tests/compile-fail/doc.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index da87b104341..f27b4d862f1 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -165,7 +165,10 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp ':' => { // reference link current_word_begin = jump_to!(chars, '\n', len); } - _ => continue, + _ => { // automatic reference link + current_word_begin = jump_to!(@next_char, chars, len); + check_doc(cx, valid_idents, link_text, span); + } } } None => return, diff --git a/src/utils/conf.rs b/src/utils/conf.rs index e11a6c0d9c7..74a68d2d730 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -150,7 +150,7 @@ 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"] => Vec<String>), + ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "GitHub"] => Vec<String>), /// 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 diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 81250b5485a..16e460e5055 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -9,10 +9,12 @@ /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun /// which should be reported only once despite being __doubly bad__. +/// be_sure_we_got_to_the_end_of_it fn foo_bar() { //~^ ERROR: you should put `foo_bar` between ticks //~| ERROR: you should put `foo::bar` between ticks //~| ERROR: you should put `Foo::some_fun` between ticks +//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// That one tests multiline ticks. @@ -20,13 +22,17 @@ fn foo_bar() { /// foo_bar FOO_BAR /// _foo bar_ /// ``` +/// be_sure_we_got_to_the_end_of_it fn multiline_ticks() { +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// This _is a test for /// multiline /// emphasis_. +/// be_sure_we_got_to_the_end_of_it fn test_emphasis() { +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// This tests units. See also #835. @@ -38,22 +44,64 @@ fn test_emphasis() { /// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib /// 32kB 32MB 32GB 32TB 32PB 32EB /// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb +/// be_sure_we_got_to_the_end_of_it fn test_units() { +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +} + +/// This one checks we don’t try to split unicode codepoints +/// `ß` +/// `ℝ` +/// `💣` +/// `❤️` +/// ß_foo +/// ℝ_foo +/// 💣_foo +/// ❤️_foo +/// foo_ß +/// foo_ℝ +/// foo_💣 +/// foo_❤️ +/// [ßdummy textß][foo_ß] +/// [ℝdummy textℝ][foo_ℝ] +/// [💣dummy tex💣t][foo_💣] +/// [❤️dummy text❤️][foo_❤️] +/// [ßdummy textß](foo_ß) +/// [ℝdummy textℝ](foo_ℝ) +/// [💣dummy tex💣t](foo_💣) +/// [❤️dummy text❤️](foo_❤️) +/// [foo_ß]: dummy text +/// [foo_ℝ]: dummy text +/// [foo_💣]: dummy text +/// [foo_❤️]: dummy text +/// be_sure_we_got_to_the_end_of_it +fn test_unicode() { +//~^ ERROR: you should put `ß_foo` between ticks +//~| ERROR: you should put `ℝ_foo` between ticks +//~| ERROR: you should put `foo_ß` between ticks +//~| ERROR: you should put `foo_ℝ` between ticks +//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// This test has [a link_with_underscores][chunked-example] inside it. See #823. -/// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues). And here is another [inline link][inline_link]. +/// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues) +/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. +/// It can also be [inline_link2]. /// /// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example /// [inline_link]: https://foobar +/// [inline_link2]: https://foobar /// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and /// `multiline_ticks` functions. /// /// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` /// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , +/// be_sure_we_got_to_the_end_of_it fn main() { -//~^ ERROR: you should put `link_with_underscores` between ticks +//~^ ERROR: you should put `inline_link2` between ticks +//~| ERROR: you should put `link_with_underscores` between ticks +//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks foo_bar(); multiline_ticks(); test_emphasis(); -- cgit 1.4.1-3-g733a5 From 831b8fc1b5e78673a2dd855556c03b756819e5b3 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 5 Apr 2016 17:29:14 +0200 Subject: Ignore `#[test]` fns in `cyclomatic_complexity` --- src/cyclomatic_complexity.rs | 9 ++++++--- tests/compile-fail/cyclomatic_complexity.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index fcd89801ecc..043504f5a28 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -1,12 +1,12 @@ //! calculate cyclomatic complexity and warn about overly complex functions -use rustc::lint::*; use rustc::cfg::CFG; +use rustc::lint::*; use rustc::ty; use rustc::hir::*; use rustc::hir::intravisit::{Visitor, walk_expr}; use syntax::ast::Attribute; -use syntax::attr::*; +use syntax::attr; use syntax::codemap::Span; use utils::{in_macro, LimitStack, span_help_and_lint}; @@ -44,6 +44,7 @@ impl CyclomaticComplexity { if in_macro(cx, span) { return; } + let cfg = CFG::new(cx.tcx, block); let n = cfg.graph.len_nodes() as u64; let e = cfg.graph.len_edges() as u64; @@ -84,7 +85,9 @@ impl CyclomaticComplexity { impl LateLintPass for CyclomaticComplexity { fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemFn(_, _, _, _, _, ref block) = item.node { - self.check(cx, block, item.span); + if !attr::contains_name(&item.attrs, "test") { + self.check(cx, block, item.span); + } } } diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index f744d60440f..4b24f16eda7 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -171,6 +171,17 @@ fn bar() { //~ ERROR: the function has a cyclomatic complexity of 2 } } +#[test] +#[cyclomatic_complexity = "0"] +/// Tests are usually complex but simple at the same time. `cyclomatic_complexity` used to give +/// lots of false-positives in tests. +fn dont_warn_on_tests() { + match 99 { + 0 => println!("hi"), + _ => println!("bye"), + } +} + #[cyclomatic_complexity = "0"] fn barr() { //~ ERROR: the function has a cyclomatic complexity of 2 match 99 { -- cgit 1.4.1-3-g733a5 From 1789430a49d7ce0f59b76b4f07a2d8ba6be3d03e Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 14 Apr 2016 17:25:31 +0200 Subject: Add a `TEMPORARY_CSTRING_AS_PTR` lint --- README.md | 3 ++- src/lib.rs | 1 + src/methods.rs | 54 ++++++++++++++++++++++++++++++++++++++++--- src/utils/mod.rs | 3 ++- tests/compile-fail/methods.rs | 12 ++++++++++ 5 files changed, 68 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index fee6d066e7c..c7cee794db4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 140 lints included in this crate: +There are 141 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -135,6 +135,7 @@ name [suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=` [suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if` [temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries +[temporary_cstring_as_ptr](https://github.com/Manishearth/rust-clippy/wiki#temporary_cstring_as_ptr) | warn | getting the inner pointer of a temporary `CString` [too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type diff --git a/src/lib.rs b/src/lib.rs index 1b48c7b3dbb..c1a7732e3f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -325,6 +325,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, methods::SINGLE_CHAR_PATTERN, + methods::TEMPORARY_CSTRING_AS_PTR, methods::WRONG_SELF_CONVENTION, minmax::MIN_MAX, misc::CMP_NAN, diff --git a/src/methods.rs b/src/methods.rs index 45f87fba9dd..8a51b576b3d 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -13,8 +13,8 @@ use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; -use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, - VEC_PATH}; +use utils::{CSTRING_NEW_PATH, BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, + OPTION_PATH, RESULT_PATH, VEC_PATH}; use utils::MethodArgs; #[derive(Clone)] @@ -286,6 +286,33 @@ declare_lint! { `_.split(\"x\")`" } +/// **What it does:** This lint checks for getting the inner pointer of a temporary `CString`. +/// +/// **Why is this bad?** The inner pointer of a `CString` is only valid as long as the `CString` is +/// alive. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// let c_str = CString::new("foo").unwrap().as_ptr(); +/// unsafe { +/// call_some_ffi_func(c_str); +/// } +/// ``` +/// Here `c_str` point to a freed address. The correct use would be: +/// ```rust,ignore +/// let c_str = CString::new("foo").unwrap(); +/// unsafe { +/// call_some_ffi_func(c_str.as_ptr()); +/// } +/// ``` +declare_lint! { + pub TEMPORARY_CSTRING_AS_PTR, + Warn, + "getting the inner pointer of a temporary `CString`" +} + impl LintPass for MethodsPass { fn get_lints(&self) -> LintArray { lint_array!(EXTEND_FROM_SLICE, @@ -303,7 +330,8 @@ impl LintPass for MethodsPass { CLONE_DOUBLE_REF, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, - SEARCH_IS_SOME) + SEARCH_IS_SOME, + TEMPORARY_CSTRING_AS_PTR) } } @@ -334,7 +362,11 @@ impl LateLintPass for MethodsPass { lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); } else if let Some(arglists) = method_chain_args(expr, &["extend"]) { lint_extend(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["unwrap", "as_ptr"]) { + lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]); } + + lint_or_fun_call(cx, expr, &name.node.as_str(), &args); if args.len() == 1 && name.node.as_str() == "clone" { lint_clone_on_copy(cx, expr); @@ -554,6 +586,22 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } } +fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) { + if_let_chain!{[ + let ExprCall(ref fun, ref args) = new.node, + args.len() == 1, + let ExprPath(None, ref path) = fun.node, + match_path(path, &CSTRING_NEW_PATH), + ], { + span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, + "you are getting the inner pointer of a temporary `CString`", + |db| { + db.fileline_note(expr.span, "that pointer will be invalid outside this expression"); + db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime"); + }); + }} +} + fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 761d5d3df9d..75637b67d9d 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -28,11 +28,13 @@ pub type MethodArgs = HirVec<P<Expr>>; // module DefPaths for certain structs/enums we check for pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"]; +pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"]; pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const CSTRING_NEW_PATH: [&'static str; 4] = ["std", "ffi", "CString", "new"]; pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; pub const DISPLAY_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; @@ -59,7 +61,6 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; pub const TRANSMUTE_PATH: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; -pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 9d938ebb19e..1869fd12a69 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -470,3 +470,15 @@ fn single_char_pattern() { //~| HELP try using a char instead: //~| SUGGESTION x.trim_right_matches('x'); } + +#[allow(result_unwrap_used)] +fn temporary_cstring() { + use std::ffi::CString; + + ( // extra parenthesis to better test spans + //~^ ERROR you are getting the inner pointer of a temporary `CString` + //~| NOTE that pointer will be invalid outside this expression + CString::new("foo").unwrap() + //~^ HELP assign the `CString` to a variable to extend its lifetime + ).as_ptr(); +} -- cgit 1.4.1-3-g733a5 From 48a672b4eefa1cfe4dad62e37f8768e2f5a0c355 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 14 Apr 2016 18:13:15 +0200 Subject: Move paths to their own module --- src/attrs.rs | 5 +++-- src/derive.rs | 6 +++--- src/drop_ref.rs | 5 ++--- src/entry.rs | 9 ++++---- src/format.rs | 10 ++++----- src/loops.rs | 16 +++++++-------- src/map_clone.rs | 9 ++++---- src/matches.rs | 16 +++++++-------- src/methods.rs | 33 +++++++++++++++--------------- src/mutex_atomic.rs | 4 ++-- src/new_without_default.rs | 10 ++++----- src/open_options.rs | 8 ++++---- src/panic.rs | 6 +++--- src/print.rs | 10 ++++----- src/ptr_arg.rs | 9 ++++---- src/regex.rs | 5 +++-- src/strings.rs | 7 +++---- src/transmute.rs | 5 ++--- src/types.rs | 8 +++++--- src/utils/mod.rs | 51 ++++++++-------------------------------------- src/utils/paths.rs | 37 +++++++++++++++++++++++++++++++++ src/vec.rs | 5 ++--- 22 files changed, 136 insertions(+), 138 deletions(-) create mode 100644 src/utils/paths.rs (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 17b8a60bcb9..a41cd141a12 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -7,7 +7,8 @@ use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; use syntax::attr::*; use syntax::codemap::Span; -use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; +use utils::{in_macro, match_path, span_lint}; +use utils::paths; /// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. /// @@ -129,7 +130,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &BEGIN_UNWIND) + !match_path(path, &paths::BEGIN_UNWIND) } else { true } diff --git a/src/derive.rs b/src/derive.rs index 4b8446e6201..c9ac8f0a948 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::hir::*; use syntax::ast::{Attribute, MetaItemKind}; use syntax::codemap::Span; -use utils::{CLONE_TRAIT_PATH, HASH_PATH}; +use utils::paths; use utils::{match_path, span_lint_and_then}; /// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` @@ -88,7 +88,7 @@ impl LateLintPass for Derive { /// Implementation of the `DERIVE_HASH_XOR_EQ` lint. 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, &HASH_PATH), + match_path(&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); @@ -129,7 +129,7 @@ fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: & /// 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, &CLONE_TRAIT_PATH) { + if match_path(&trait_ref.path, &paths::CLONE_TRAIT) { let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); let subst_ty = ty.subst(cx.tcx, ¶meter_environment.free_substs); diff --git a/src/drop_ref.rs b/src/drop_ref.rs index 3448e05dbac..69156f15f31 100644 --- a/src/drop_ref.rs +++ b/src/drop_ref.rs @@ -2,8 +2,7 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; use syntax::codemap::Span; -use utils::DROP_PATH; -use utils::{match_def_path, span_note_and_lint}; +use utils::{match_def_path, paths, span_note_and_lint}; /// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value. /// @@ -37,7 +36,7 @@ impl LateLintPass for DropRefPass { if let ExprCall(ref path, ref args) = expr.node { if let ExprPath(None, _) = path.node { let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); - if match_def_path(cx, def_id, &DROP_PATH) { + if match_def_path(cx, def_id, &paths::DROP) { if args.len() != 1 { return; } diff --git a/src/entry.rs b/src/entry.rs index 934400bc122..24810e242ad 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,10 +1,9 @@ -use rustc::lint::*; use rustc::hir::*; use rustc::hir::intravisit::{Visitor, walk_expr, walk_block}; +use rustc::lint::*; use syntax::codemap::Span; use utils::SpanlessEq; -use utils::{BTREEMAP_PATH, HASHMAP_PATH}; -use utils::{get_item_name, match_type, snippet, span_lint_and_then, walk_ptrs_ty}; +use utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; /// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or /// `BTreeMap`. @@ -89,10 +88,10 @@ fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr) -> O let map = ¶ms[0]; let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); - return if match_type(cx, obj_ty, &BTREEMAP_PATH) { + return if match_type(cx, obj_ty, &paths::BTREEMAP) { Some(("BTreeMap", map, key)) } - else if match_type(cx, obj_ty, &HASHMAP_PATH) { + else if match_type(cx, obj_ty, &paths::HASHMAP) { Some(("HashMap", map, key)) } else { diff --git a/src/format.rs b/src/format.rs index 0a349c98e07..0726fcaeab7 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,9 +1,9 @@ +use rustc::hir::*; use rustc::hir::map::Node::NodeItem; use rustc::lint::*; use rustc::ty::TypeVariants; -use rustc::hir::*; use syntax::ast::LitKind; -use utils::{DISPLAY_FMT_METHOD_PATH, FMT_ARGUMENTS_NEWV1_PATH, STRING_PATH}; +use utils::paths; use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty}; /// **What it does:** This lints about use of `format!("string literal with no argument")` and @@ -40,7 +40,7 @@ impl LateLintPass for FormatMacLint { if_let_chain!{[ let ExprPath(_, ref path) = fun.node, args.len() == 2, - match_path(path, &FMT_ARGUMENTS_NEWV1_PATH), + match_path(path, &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 @@ -108,11 +108,11 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { let ExprCall(_, ref args) = exprs[0].node, args.len() == 2, let ExprPath(None, ref path) = args[1].node, - match_path(path, &DISPLAY_FMT_METHOD_PATH) + match_path(path, &paths::DISPLAY_FMT_METHOD) ], { let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0])); - return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &STRING_PATH); + return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING); }} false diff --git a/src/loops.rs b/src/loops.rs index 4e7e4bf117d..4fb45e7c198 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -16,7 +16,7 @@ use syntax::ast; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range, walk_ptrs_ty, recover_for_loop}; -use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH}; +use utils::paths; use utils::UnsugaredRange; /// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. @@ -505,7 +505,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { /// Check for `for` loops over `Option`s and `Results` fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { let ty = cx.tcx.expr_ty(arg); - if match_type(cx, ty, &OPTION_PATH) { + if match_type(cx, ty, &paths::OPTION) { span_help_and_lint(cx, FOR_LOOP_OVER_OPTION, arg.span, @@ -515,7 +515,7 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", snippet(cx, pat.span, "_"), snippet(cx, arg.span, "_"))); - } else if match_type(cx, ty, &RESULT_PATH) { + } else if match_type(cx, ty, &paths::RESULT) { span_help_and_lint(cx, FOR_LOOP_OVER_RESULT, arg.span, @@ -589,7 +589,7 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex }; let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); - if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) { + if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) { span_lint_and_then(cx, FOR_KV_MAP, expr.span, @@ -735,13 +735,13 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { // will allow further borrows afterwards let ty = cx.tcx.expr_ty(e); is_iterable_array(ty) || - match_type(cx, ty, &VEC_PATH) || - match_type(cx, ty, &LL_PATH) || - match_type(cx, ty, &HASHMAP_PATH) || + match_type(cx, ty, &paths::VEC) || + match_type(cx, ty, &paths::LL) || + match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || - match_type(cx, ty, &BTREEMAP_PATH) || + match_type(cx, ty, &paths::BTREEMAP) || match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) } diff --git a/src/map_clone.rs b/src/map_clone.rs index eeb3aab4655..caefb64eb5f 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,8 +1,7 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{CLONE_PATH, OPTION_PATH}; -use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty, - walk_ptrs_ty_depth}; +use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet, + span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; /// **What it does:** This lint checks for mapping clone() over an iterator. /// @@ -65,7 +64,7 @@ impl LateLintPass for MapClonePass { } } ExprPath(_, ref path) => { - if match_path(path, &CLONE_PATH) { + if match_path(path, &paths::CLONE) { let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); span_help_and_lint(cx, MAP_CLONE, @@ -99,7 +98,7 @@ fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { Some("iterator") - } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &OPTION_PATH) { + } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &paths::OPTION) { Some("Option") } else { None diff --git a/src/matches.rs b/src/matches.rs index d82dad5b065..c1692ee47d2 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -8,7 +8,7 @@ use rustc_const_math::ConstInt; use std::cmp::Ordering; use syntax::ast::LitKind; use syntax::codemap::Span; -use utils::{COW_PATH, OPTION_PATH, RESULT_PATH}; +use utils::paths; use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; /// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. @@ -184,13 +184,13 @@ 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>) { // list of candidate Enums we know will never get any more members - let candidates = &[(&COW_PATH, "Borrowed"), - (&COW_PATH, "Cow::Borrowed"), - (&COW_PATH, "Cow::Owned"), - (&COW_PATH, "Owned"), - (&OPTION_PATH, "None"), - (&RESULT_PATH, "Err"), - (&RESULT_PATH, "Ok")]; + let candidates = &[(&paths::COW, "Borrowed"), + (&paths::COW, "Cow::Borrowed"), + (&paths::COW, "Cow::Owned"), + (&paths::COW, "Owned"), + (&paths::OPTION, "None"), + (&paths::RESULT, "Err"), + (&paths::RESULT, "Ok")]; let path = match arms[1].pats[0].node { PatKind::TupleStruct(ref path, Some(ref inner)) => { diff --git a/src/methods.rs b/src/methods.rs index 8a51b576b3d..d2a91b615ae 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -13,9 +13,8 @@ use syntax::ptr::P; use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; -use utils::{CSTRING_NEW_PATH, BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, - OPTION_PATH, RESULT_PATH, VEC_PATH}; use utils::MethodArgs; +use utils::paths; #[derive(Clone)] pub struct MethodsPass; @@ -470,7 +469,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) if ["default", "new"].contains(&path) { let arg_ty = cx.tcx.expr_ty(arg); - let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) { + let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { default_trait_id } else { return false; @@ -497,13 +496,13 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) fn check_general_case(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, or_has_args: bool, span: Span) { // (path, fn_has_argument, methods) - let know_types: &[(&[_], _, &[_], _)] = &[(&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"), - (&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"), - (&OPTION_PATH, + 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"), - (&RESULT_PATH, true, &["or", "unwrap_or"], "else")]; + (&paths::RESULT, true, &["or", "unwrap_or"], "else")]; let self_ty = cx.tcx.expr_ty(self_expr); @@ -571,7 +570,7 @@ fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) { fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - if !match_type(cx, obj_ty, &VEC_PATH) { + if !match_type(cx, obj_ty, &paths::VEC) { return; } let arg_ty = cx.tcx.expr_ty(&args[1]); @@ -591,7 +590,7 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) let ExprCall(ref fun, ref args) = new.node, args.len() == 1, let ExprPath(None, ref path) = fun.node, - match_path(path, &CSTRING_NEW_PATH), + match_path(path, &paths::CSTRING_NEW), ], { span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, "you are getting the inner pointer of a temporary `CString`", @@ -606,7 +605,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { ty::TySlice(_) => true, - ty::TyStruct(..) => match_type(cx, ty, &VEC_PATH), + ty::TyStruct(..) => match_type(cx, ty, &paths::VEC), ty::TyArray(_, size) => size < 32, ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | ty::TyBox(ref inner) => may_slice(cx, inner), @@ -641,9 +640,9 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); - let mess = if match_type(cx, obj_ty, &OPTION_PATH) { + let mess = if match_type(cx, obj_ty, &paths::OPTION) { Some((OPTION_UNWRAP_USED, "an Option", "None")) - } else if match_type(cx, obj_ty, &RESULT_PATH) { + } else if match_type(cx, obj_ty, &paths::RESULT) { Some((RESULT_UNWRAP_USED, "a Result", "Err")) } else { None @@ -666,7 +665,7 @@ fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { /// lint use of `ok().expect()` for `Result`s fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { // lint if the caller of `ok()` is a `Result` - if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &RESULT_PATH) { + if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &paths::RESULT) { let result_type = cx.tcx.expr_ty(&ok_args[0]); if let Some(error_type) = get_error_type(cx, result_type) { if has_debug_impl(error_type, cx) { @@ -684,7 +683,7 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { /// lint use of `map().unwrap_or()` for `Option`s fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` - if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { // lint message let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling \ `map_or(a, f)` instead"; @@ -715,7 +714,7 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwr /// lint use of `map().unwrap_or_else()` for `Option`s fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` - if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &OPTION_PATH) { + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { // lint message let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ `map_or_else(g, f)` instead"; @@ -842,7 +841,7 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &Expr, arg: &Expr) { /// Given a `Result<T, E>` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { - if !match_type(cx, ty, &RESULT_PATH) { + if !match_type(cx, ty, &paths::RESULT) { return None; } if let ty::TyEnum(_, substs) = ty.sty { @@ -853,7 +852,7 @@ fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { None } -/// This checks whether a given type is known to implement `Debug`. +/// This checks whether a given type is known to implement Debug. fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { match cx.tcx.lang_items.debug_trait() { Some(debug) => implements_trait(cx, ty, debug, Vec::new()), diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs index bae1ae38168..7d637adb8b8 100644 --- a/src/mutex_atomic.rs +++ b/src/mutex_atomic.rs @@ -7,7 +7,7 @@ use rustc::ty::subst::ParamSpace; use rustc::ty; use rustc::hir::Expr; use syntax::ast; -use utils::{span_lint, MUTEX_PATH, match_type}; +use utils::{match_type, paths, span_lint}; /// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do. /// @@ -47,7 +47,7 @@ impl LateLintPass for MutexAtomic { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { let ty = cx.tcx.expr_ty(expr); if let ty::TyStruct(_, subst) = ty.sty { - if match_type(cx, ty, &MUTEX_PATH) { + if match_type(cx, ty, &paths::MUTEX) { let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \ diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 2bcc345fd60..f42b1d0d74a 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -1,10 +1,10 @@ -use rustc::lint::*; -use rustc::hir; use rustc::hir::intravisit::FnKind; +use rustc::hir; +use rustc::lint::*; use syntax::ast; use syntax::codemap::Span; -use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint, - DEFAULT_TRAIT_PATH}; +use utils::paths; +use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint}; /// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` /// implementation. @@ -54,7 +54,7 @@ impl LateLintPass for NewWithoutDefault { self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics let Some(ret_ty) = return_ty(cx, id), same_tys(cx, self_ty, ret_ty, id), - let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH), + let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), !implements_trait(cx, self_ty, default_trait_id, Vec::new()) ], { span_lint(cx, NEW_WITHOUT_DEFAULT, span, diff --git a/src/open_options.rs b/src/open_options.rs index 3c1e69a40ea..aaaebe5b2f8 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -1,8 +1,8 @@ -use rustc::lint::*; use rustc::hir::{Expr, ExprMethodCall, ExprLit}; +use rustc::lint::*; use syntax::ast::LitKind; use syntax::codemap::{Span, Spanned}; -use utils::{walk_ptrs_ty_depth, match_type, span_lint, OPEN_OPTIONS_PATH}; +use utils::{match_type, paths, span_lint, walk_ptrs_ty_depth}; /// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. /// @@ -31,7 +31,7 @@ impl LateLintPass for NonSensicalOpenOptions { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { if let ExprMethodCall(ref name, _, ref arguments) = e.node { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); - if name.node.as_str() == "open" && match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) { + if name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); get_open_options(cx, &arguments[0], &mut options); check_open_options(cx, &options, e.span); @@ -61,7 +61,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &OPEN_OPTIONS_PATH) && arguments.len() >= 2 { + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { let argument_option = match arguments[1].node { ExprLit(ref span) => { diff --git a/src/panic.rs b/src/panic.rs index ab03181c2dd..78499fa1a1a 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -1,7 +1,7 @@ -use rustc::lint::*; use rustc::hir::*; +use rustc::lint::*; use syntax::ast::LitKind; -use utils::{span_lint, is_direct_expn_of, match_path, BEGIN_UNWIND}; +use utils::{is_direct_expn_of, match_path, paths, span_lint}; /// **What it does:** This lint checks for missing parameters in `panic!`. /// @@ -33,7 +33,7 @@ impl LateLintPass for PanicPass { let ExprCall(ref fun, ref params) = ex.node, params.len() == 2, let ExprPath(None, ref path) = fun.node, - match_path(path, &BEGIN_UNWIND), + match_path(path, &paths::BEGIN_UNWIND), 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/src/print.rs b/src/print.rs index a298d162c05..d426286dba4 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,7 +1,7 @@ +use rustc::hir::*; use rustc::hir::map::Node::{NodeItem, NodeImplItem}; use rustc::lint::*; -use rustc::hir::*; -use utils::{FMT_ARGUMENTV1_NEW_PATH, DEBUG_FMT_METHOD_PATH, IO_PRINT_PATH}; +use utils::paths; use utils::{is_expn_of, match_path, span_lint}; /// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants. @@ -45,7 +45,7 @@ impl LateLintPass for PrintLint { if let ExprPath(_, ref path) = fun.node { // Search for `std::io::_print(..)` which is unique in a // `print!` expansion. - if match_path(path, &IO_PRINT_PATH) { + if match_path(path, &paths::IO_PRINT) { if let Some(span) = is_expn_of(cx, expr.span, "print") { // `println!` uses `print!`. let (span, name) = match is_expn_of(cx, span, "println") { @@ -58,9 +58,9 @@ impl LateLintPass for PrintLint { } // Search for something like // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` - else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) { + else if args.len() == 2 && match_path(path, &paths::FMT_ARGUMENTV1_NEW) { if let ExprPath(None, ref path) = args[1].node { - if match_path(path, &DEBUG_FMT_METHOD_PATH) && !is_in_debug_impl(cx, expr) && + if match_path(path, &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"); } diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs index 8720424da86..addcfc9e84d 100644 --- a/src/ptr_arg.rs +++ b/src/ptr_arg.rs @@ -1,12 +1,11 @@ //! Checks for usage of `&Vec[_]` and `&String`. +use rustc::hir::*; use rustc::hir::map::NodeItem; use rustc::lint::*; use rustc::ty; -use rustc::hir::*; use syntax::ast::NodeId; -use utils::{STRING_PATH, VEC_PATH}; -use utils::{span_lint, match_type}; +use utils::{match_type, paths, span_lint}; /// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. /// @@ -61,13 +60,13 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { 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, &VEC_PATH) { + if match_type(cx, ty, &paths::VEC) { span_lint(cx, PTR_ARG, arg.ty.span, "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ with non-Vec-based slices. Consider changing the type to `&[...]`"); - } else if match_type(cx, ty, &STRING_PATH) { + } else if match_type(cx, ty, &paths::STRING) { span_lint(cx, PTR_ARG, arg.ty.span, diff --git a/src/regex.rs b/src/regex.rs index f24639312ed..177f7a7b045 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -9,7 +9,8 @@ use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; -use utils::{is_expn_of, match_path, match_type, REGEX_NEW_PATH, span_lint, span_help_and_lint}; +use utils::paths; +use utils::{is_expn_of, match_path, match_type, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// @@ -97,7 +98,7 @@ impl LateLintPass for RegexPass { if_let_chain!{[ let ExprCall(ref fun, ref args) = expr.node, let ExprPath(_, ref path) = fun.node, - match_path(path, ®EX_NEW_PATH) && args.len() == 1 + match_path(path, &paths::REGEX_NEW) && args.len() == 1 ], { if let ExprLit(ref lit) = args[0].node { if let LitKind::Str(ref r, _) = lit.node { diff --git a/src/strings.rs b/src/strings.rs index da1456671fd..a6808d2dd42 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -3,12 +3,11 @@ //! Note that since we have two lints where one subsumes the other, we try to //! disable the subsumed lint unless it has a higher level -use rustc::lint::*; use rustc::hir::*; +use rustc::lint::*; use syntax::codemap::Spanned; -use utils::STRING_PATH; use utils::SpanlessEq; -use utils::{match_type, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr}; +use utils::{match_type, paths, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr}; /// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). /// @@ -108,7 +107,7 @@ impl LateLintPass for StringAdd { } fn is_string(cx: &LateContext, e: &Expr) -> bool { - match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH) + match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &paths::STRING) } fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { diff --git a/src/transmute.rs b/src/transmute.rs index 41b92ca6113..8b74b1989db 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -2,8 +2,7 @@ use rustc::lint::*; use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; use rustc::ty; use rustc::hir::*; -use utils::TRANSMUTE_PATH; -use utils::{match_def_path, snippet_opt, span_lint, span_lint_and_then}; +use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; /// **What it does:** This lint checks for transmutes to the original type of the object. /// @@ -67,7 +66,7 @@ impl LateLintPass for Transmute { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if match_def_path(cx, def_id, &TRANSMUTE_PATH) { + if match_def_path(cx, def_id, &paths::TRANSMUTE) { let from_ty = cx.tcx.expr_ty(&args[0]); let to_ty = cx.tcx.expr_ty(e); diff --git a/src/types.rs b/src/types.rs index 281af90736b..00b36f1f5d4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,7 +6,9 @@ use rustc::ty; use std::cmp::Ordering; use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::codemap::Span; -use utils::*; +use utils::{comparisons, in_external_macro, in_macro, is_from_for_desugar, match_def_path, snippet, + span_help_and_lint, span_lint}; +use utils::paths; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -63,7 +65,7 @@ impl LateLintPass for TypePass { 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.def_id(), &VEC_PATH), + match_def_path(cx, did.def_id(), &paths::VEC), ], { span_help_and_lint(cx, @@ -73,7 +75,7 @@ impl LateLintPass for TypePass { "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); } } - } else if match_def_path(cx, did.def_id(), &LL_PATH) { + } else if match_def_path(cx, did.def_id(), &paths::LL) { span_help_and_lint(cx, LINKEDLIST, ast_ty.span, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 75637b67d9d..d01b0698de8 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -22,45 +22,10 @@ use syntax::ptr::P; pub mod comparisons; pub mod conf; mod hir; +pub mod paths; pub use self::hir::{SpanlessEq, SpanlessHash}; -pub type MethodArgs = HirVec<P<Expr>>; -// module DefPaths for certain structs/enums we check for -pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; -pub const BOX_NEW_PATH: [&'static str; 4] = ["std", "boxed", "Box", "new"]; -pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"]; -pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; -pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; -pub const CLONE_PATH: [&'static str; 3] = ["clone", "Clone", "clone"]; -pub const CLONE_TRAIT_PATH: [&'static str; 2] = ["clone", "Clone"]; -pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"]; -pub const CSTRING_NEW_PATH: [&'static str; 4] = ["std", "ffi", "CString", "new"]; -pub const DEBUG_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; -pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"]; -pub const DISPLAY_FMT_METHOD_PATH: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; -pub const DROP_PATH: [&'static str; 3] = ["core", "mem", "drop"]; -pub const FMT_ARGUMENTS_NEWV1_PATH: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; -pub const FMT_ARGUMENTV1_NEW_PATH: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; -pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; -pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; -pub const HASH_PATH: [&'static str; 2] = ["hash", "Hash"]; -pub const IO_PRINT_PATH: [&'static str; 3] = ["std", "io", "_print"]; -pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; -pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"]; -pub const RANGE_FROM_PATH: [&'static str; 3] = ["std", "ops", "RangeFrom"]; -pub const RANGE_FULL_PATH: [&'static str; 3] = ["std", "ops", "RangeFull"]; -pub const RANGE_INCLUSIVE_NON_EMPTY_PATH: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; -pub const RANGE_PATH: [&'static str; 3] = ["std", "ops", "Range"]; -pub const RANGE_TO_INCLUSIVE_PATH: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; -pub const RANGE_TO_PATH: [&'static str; 3] = ["std", "ops", "RangeTo"]; -pub const REGEX_NEW_PATH: [&'static str; 3] = ["regex", "Regex", "new"]; -pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"]; -pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"]; -pub const TRANSMUTE_PATH: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; -pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"]; -pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub type MethodArgs = HirVec<P<Expr>>; /// Produce a nested chain of if-lets and ifs from the patterns: /// @@ -764,22 +729,22 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { match unwrap_unstable(&expr).node { ExprPath(None, ref path) => { - if match_path(path, &RANGE_FULL_PATH) { + if match_path(path, &paths::RANGE_FULL) { Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen }) } else { None } } ExprStruct(ref path, ref fields, None) => { - if match_path(path, &RANGE_FROM_PATH) { + if match_path(path, &paths::RANGE_FROM) { Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen }) - } else if match_path(path, &RANGE_INCLUSIVE_NON_EMPTY_PATH) { + } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed }) - } else if match_path(path, &RANGE_PATH) { + } else if match_path(path, &paths::RANGE) { Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen }) - } else if match_path(path, &RANGE_TO_INCLUSIVE_PATH) { + } else if match_path(path, &paths::RANGE_TO_INCLUSIVE) { Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed }) - } else if match_path(path, &RANGE_TO_PATH) { + } else if match_path(path, &paths::RANGE_TO) { Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen }) } else { None diff --git a/src/utils/paths.rs b/src/utils/paths.rs new file mode 100644 index 00000000000..94f1d17f27a --- /dev/null +++ b/src/utils/paths.rs @@ -0,0 +1,37 @@ +//! This module contains paths to types and functions Clippy needs to know about. + +pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; +pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"]; +pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; +pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; +pub const CLONE: [&'static str; 3] = ["clone", "Clone", "clone"]; +pub const CLONE_TRAIT: [&'static str; 2] = ["clone", "Clone"]; +pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"]; +pub const CSTRING_NEW: [&'static str; 4] = ["std", "ffi", "CString", "new"]; +pub const DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; +pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"]; +pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; +pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; +pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; +pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; +pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; +pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const HASH: [&'static str; 2] = ["hash", "Hash"]; +pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; +pub const LL: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; +pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; +pub const RANGE_FROM: [&'static str; 3] = ["std", "ops", "RangeFrom"]; +pub const RANGE_FULL: [&'static str; 3] = ["std", "ops", "RangeFull"]; +pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE: [&'static str; 3] = ["std", "ops", "Range"]; +pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; +pub const RANGE_TO: [&'static str; 3] = ["std", "ops", "RangeTo"]; +pub const REGEX_NEW: [&'static str; 3] = ["regex", "Regex", "new"]; +pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; +pub const STRING: [&'static str; 3] = ["collections", "string", "String"]; +pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; +pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"]; +pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"]; diff --git a/src/vec.rs b/src/vec.rs index d27a3320d96..513efa1a2a4 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -3,8 +3,7 @@ use rustc::ty::TypeVariants; use rustc::hir::*; use syntax::codemap::Span; use syntax::ptr::P; -use utils::VEC_FROM_ELEM_PATH; -use utils::{is_expn_of, match_path, recover_for_loop, snippet, span_lint_and_then}; +use utils::{is_expn_of, match_path, paths, recover_for_loop, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. /// @@ -92,7 +91,7 @@ pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>> let ExprPath(_, ref path) = fun.node, is_expn_of(cx, fun.span, "vec").is_some() ], { - return if match_path(path, &VEC_FROM_ELEM_PATH) && args.len() == 2 { + return if match_path(path, &paths::VEC_FROM_ELEM) && args.len() == 2 { // `vec![elem; size]` case Some(VecArgs::Repeat(&args[0], &args[1])) } -- cgit 1.4.1-3-g733a5 From cd12a2369a4c3a9b9719a14c7f3f53b6b58b9ebe Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 14 Apr 2016 18:41:38 +0200 Subject: s/paths::LL/paths::LINKED_LIST All other paths had non-abbreviated names. --- src/loops.rs | 2 +- src/types.rs | 2 +- src/utils/paths.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 4fb45e7c198..f376e28c992 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -736,7 +736,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { let ty = cx.tcx.expr_ty(e); is_iterable_array(ty) || match_type(cx, ty, &paths::VEC) || - match_type(cx, ty, &paths::LL) || + match_type(cx, ty, &paths::LINKED_LIST) || match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || diff --git a/src/types.rs b/src/types.rs index 00b36f1f5d4..9d12d7970d1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -75,7 +75,7 @@ impl LateLintPass for TypePass { "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); } } - } else if match_def_path(cx, did.def_id(), &paths::LL) { + } else if match_def_path(cx, did.def_id(), &paths::LINKED_LIST) { span_help_and_lint(cx, LINKEDLIST, ast_ty.span, diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 94f1d17f27a..1777c31ef8c 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -19,7 +19,7 @@ pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASH: [&'static str; 2] = ["hash", "Hash"]; pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; -pub const LL: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; -- cgit 1.4.1-3-g733a5 From a878916ad54eba5e92a3e6f0906e5099b26815d1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 14 Apr 2016 20:14:03 +0200 Subject: rustfmt all the things --- src/array_indexing.rs | 23 ++++---- src/attrs.rs | 3 +- src/bit_mask.rs | 2 +- src/booleans.rs | 99 ++++++++++++++++++++-------------- src/collapsible_if.rs | 4 +- src/consts.rs | 23 +++++--- src/copies.rs | 5 +- src/cyclomatic_complexity.rs | 20 +++---- src/doc.rs | 11 ++-- src/entry.rs | 2 +- src/enum_glob_use.rs | 2 +- src/eta_reduction.rs | 5 +- src/functions.rs | 11 ++-- src/if_not_else.rs | 6 +-- src/len_zero.rs | 7 +-- src/lifetimes.rs | 11 ++-- src/loops.rs | 10 ++-- src/matches.rs | 55 ++++++++++--------- src/methods.rs | 6 ++- src/minmax.rs | 4 +- src/misc.rs | 7 +-- src/misc_early.rs | 10 ++-- src/mut_mut.rs | 4 +- src/mut_reference.rs | 11 ++-- src/needless_bool.rs | 35 ++++++------ src/no_effect.rs | 3 +- src/non_expressive_names.rs | 23 ++++---- src/open_options.rs | 4 +- src/overflow_check_conditional.rs | 2 +- src/precedence.rs | 8 +-- src/regex.rs | 6 +-- src/returns.rs | 2 +- src/shadow.rs | 15 +++--- src/strings.rs | 7 ++- src/temporary_assignment.rs | 6 +-- src/transmute.rs | 22 ++++---- src/types.rs | 108 ++++++++++++++++++++++---------------- src/utils/conf.rs | 3 +- src/utils/hir.rs | 9 ++-- src/utils/mod.rs | 53 ++++++++++++++----- src/vec.rs | 3 +- 41 files changed, 375 insertions(+), 275 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index ce5c85500bd..2295bd7832a 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -78,17 +78,16 @@ impl LateLintPass for ArrayIndexing { // Index is a constant range if let Some(range) = utils::unsugar_range(index) { - let start = range.start.map(|start| - eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)).map(|v| v.ok()); - let end = range.end.map(|end| - eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)).map(|v| v.ok()); + let start = range.start + .map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)) + .map(|v| v.ok()); + let end = range.end + .map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)) + .map(|v| v.ok()); if let Some((start, end)) = to_const_range(start, end, range.limits, size) { if start > size || end > size { - utils::span_lint(cx, - OUT_OF_BOUNDS_INDEXING, - e.span, - "range is out of bounds"); + utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds"); } return; } @@ -111,11 +110,9 @@ 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<Option<ConstVal>>, - end: Option<Option<ConstVal>>, - limits: RangeLimits, +fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, array_size: ConstInt) - -> Option<(ConstInt, ConstInt)> { + -> Option<(ConstInt, ConstInt)> { let start = match start { Some(Some(ConstVal::Integral(x))) => x, Some(_) => return None, @@ -131,7 +128,7 @@ fn to_const_range(start: Option<Option<ConstVal>>, } } Some(_) => return None, - None => array_size + None => array_size, }; Some((start, end)) diff --git a/src/attrs.rs b/src/attrs.rs index a41cd141a12..6106486c71e 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -115,7 +115,8 @@ fn is_relevant_block(block: &Block) -> bool { for stmt in &block.stmts { match stmt.node { StmtDecl(_, _) => return true, - StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => { + StmtExpr(ref expr, _) | + StmtSemi(ref expr, _) => { return is_relevant_expr(expr); } } diff --git a/src/bit_mask.rs b/src/bit_mask.rs index 45f7e5bc938..aec0990dcc6 100644 --- a/src/bit_mask.rs +++ b/src/bit_mask.rs @@ -264,7 +264,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { // 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), + Some(&PathResolution { base_def: Def::Const(def_id), .. }) => Some(def_id), _ => None, } } diff --git a/src/booleans.rs b/src/booleans.rs index 213d12b42ef..908415acc7b 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -49,7 +49,7 @@ struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); use quine_mc_cluskey::Bool; struct Hir2Qmm<'a, 'tcx: 'a, 'v> { terminals: Vec<&'v Expr>, - cx: &'a LateContext<'a, 'tcx> + cx: &'a LateContext<'a, 'tcx>, } impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { @@ -75,17 +75,17 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { match binop.node { BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), 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), - _ => {}, + _ => (), } - }, - _ => {}, + } + _ => (), } } for (n, expr) in self.terminals.iter().enumerate() { @@ -95,11 +95,13 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } let negated = match e.node { ExprBinary(binop, ref lhs, ref rhs) => { - let mk_expr = |op| Expr { - id: DUMMY_NODE_ID, - span: DUMMY_SP, - attrs: None, - node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), + let mk_expr = |op| { + Expr { + id: DUMMY_NODE_ID, + span: DUMMY_SP, + attrs: None, + node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), + } }; match binop.node { BiEq => mk_expr(BiNe), @@ -110,7 +112,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) { @@ -137,17 +139,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 { @@ -159,8 +161,8 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { BiGe => " < ", _ => { s.push('!'); - return recurse(true, cx, inner, terminals, s) - }, + return recurse(true, cx, inner, terminals, s); + } }; s.push_str(&snip(lhs)); s.push_str(op); @@ -170,13 +172,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('('); @@ -198,7 +200,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push(')'); } s - }, + } Or(ref v) => { if brackets { s.push('('); @@ -212,7 +214,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,13 +245,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, } } @@ -271,13 +273,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, } } @@ -306,7 +308,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); @@ -325,28 +327,43 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { continue 'simplified; } if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { - span_lint_and_then(self.0, LOGIC_BUG, e.span, "this boolean expression contains a logic bug", |db| { - db.span_help(h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the outer expression"); - db.span_suggestion(e.span, "it would look like the following", suggest(self.0, suggestion, &h2q.terminals)); - }); + span_lint_and_then(self.0, + LOGIC_BUG, + e.span, + "this boolean expression contains a logic bug", + |db| { + db.span_help(h2q.terminals[i].span, + "this expression can be optimized out by applying \ + boolean operations to the outer expression"); + db.span_suggestion(e.span, + "it would look like the following", + suggest(self.0, suggestion, &h2q.terminals)); + }); // don't also lint `NONMINIMAL_BOOL` return; } // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || - (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || - (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); + (stats.negations > simplified_stats.negations && + stats.ops == simplified_stats.ops) || + (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); } if improvement { improvements.push(suggestion); } } if !improvements.is_empty() { - span_lint_and_then(self.0, 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)); - } - }); + span_lint_and_then(self.0, + 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)); + } + }); } } } @@ -354,7 +371,9 @@ 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) { return } + if in_macro(self.0, e.span) { + return; + } match e.node { ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e), ExprUnary(UnNot, ref inner) => { @@ -363,7 +382,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for NonminimalBoolVisitor<'a, 'tcx> { } else { walk_expr(self, e); } - }, + } _ => walk_expr(self, e), } } diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs index 5674806b175..38e04723e53 100644 --- a/src/collapsible_if.rs +++ b/src/collapsible_if.rs @@ -70,7 +70,7 @@ fn check_if(cx: &LateContext, e: &Expr) { db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned()); }); }} - } else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = + } else if let Some(&Expr { node: ExprIf(ref check_inner, ref content, None), span: sp, .. }) = single_stmt_of_block(then) { if e.span.expn_id != sp.expn_id { return; @@ -89,7 +89,7 @@ fn check_if(cx: &LateContext, e: &Expr) { fn requires_brackets(e: &Expr) -> bool { match e.node { - ExprBinary(Spanned {node: n, ..}, _, _) if n == BiEq => false, + ExprBinary(Spanned { node: n, .. }, _, _) if n == BiEq => false, _ => true, } } diff --git a/src/consts.rs b/src/consts.rs index d30392e0586..0eed34a8055 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -85,7 +85,9 @@ impl PartialEq for Constant { (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty, (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, (&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::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 @@ -131,7 +133,8 @@ impl Hash for Constant { Constant::Bool(b) => { b.hash(state); } - Constant::Vec(ref v) | Constant::Tuple(ref v) => { + Constant::Vec(ref v) | + Constant::Tuple(ref v) => { v.hash(state); } Constant::Repeat(ref c, l) => { @@ -186,12 +189,16 @@ fn lit_to_constant(lit: &LitKind) -> Constant { LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)), LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)), 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::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::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), @@ -285,7 +292,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { if let Some(lcx) = self.lcx { let mut maybe_id = None; - if let Some(&PathResolution { base_def: Def::Const(id), ..}) = lcx.tcx.def_map.borrow().get(&e.id) { + 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 @@ -324,7 +331,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { - let l = if let Some(l) = self.expr(left) { l } else { return None; }; + let l = if let Some(l) = self.expr(left) { + l + } else { + return None; + }; let r = self.expr(right); match (op.node, l, r) { (BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int), diff --git a/src/copies.rs b/src/copies.rs index 5b992cf38ae..aba4638ab8b 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -71,7 +71,7 @@ impl LateLintPass for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext, expr: &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) { + if let Some(&Expr { node: ExprIf(_, _, Some(ref else_expr)), .. }) = get_parent_expr(cx, expr) { if else_expr.id == expr.id { return; } @@ -185,7 +185,8 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> { fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) { match pat.node { - PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), + PatKind::Box(ref pat) | + PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), PatKind::TupleStruct(_, Some(ref pats)) => { for pat in pats { bindings_impl(cx, pat, map); diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 043504f5a28..e8a3a569a14 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -60,12 +60,7 @@ impl CyclomaticComplexity { tcx: &cx.tcx, }; helper.visit_block(block); - let CCHelper { - match_arms, - divergence, - short_circuits, - .. - } = helper; + let CCHelper { match_arms, divergence, short_circuits, .. } = helper; if cc + divergence < match_arms + short_circuits { report_cc_bug(cx, cc, match_arms, divergence, short_circuits, span); @@ -132,7 +127,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { walk_expr(self, e); let ty = self.tcx.node_id_to_type(callee.id); match ty.sty { - ty::TyFnDef(_, _, ty) | ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => { + ty::TyFnDef(_, _, ty) | + ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => { self.divergence += 1; } _ => (), @@ -143,7 +139,7 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { walk_expr(self, e); match op.node { BiAnd | BiOr => self.short_circuits += 1, - _ => {}, + _ => (), } } _ => walk_expr(self, e), @@ -156,10 +152,10 @@ fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, sp span_bug!(span, "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ div = {}, shorts = {}. Please file a bug report.", - cc, - narms, - div, - shorts); + cc, + narms, + div, + shorts); } #[cfg(not(feature="debugging"))] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { diff --git a/src/doc.rs b/src/doc.rs index f27b4d862f1..54d5366729e 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -142,10 +142,10 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp } '`' => { current_word_begin = jump_to!(chars, '`', len); - }, + } '[' => { let end = jump_to!(chars, ']', len); - let link_text = &doc[current_word_begin+1..end]; + let link_text = &doc[current_word_begin + 1..end]; match chars.peek() { Some(&(_, c)) => { @@ -199,7 +199,7 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span } let s = if s.ends_with('s') { - &s[..s.len()-1] + &s[..s.len() - 1] } else { s }; @@ -223,6 +223,9 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span } if has_underscore(word) || word.contains("::") || is_camel_case(word) { - span_lint(cx, DOC_MARKDOWN, span, &format!("you should put `{}` between ticks in the documentation", word)); + span_lint(cx, + DOC_MARKDOWN, + span, + &format!("you should put `{}` between ticks in the documentation", word)); } } diff --git a/src/entry.rs b/src/entry.rs index 24810e242ad..d63d8c67c5d 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -47,7 +47,7 @@ impl LateLintPass for HashMapLint { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message let sole_expr = else_block.is_none() && - ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1); + ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1); let mut visitor = InsertVisitor { cx: cx, diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs index 671b9bb141c..37a89069d19 100644 --- a/src/enum_glob_use.rs +++ b/src/enum_glob_use.rs @@ -54,7 +54,7 @@ impl EnumGlobUse { let child = cx.sess().cstore.item_children(def.def_id()); if let Some(child) = child.first() { if let DefLike::DlDef(Def::Variant(..)) = child.def { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } } } diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 4519acc39de..83abe215aa7 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -60,9 +60,10 @@ fn check_closure(cx: &LateContext, expr: &Expr) { let fn_ty = cx.tcx.expr_ty(caller); match fn_ty.sty { // Is it an unsafe function? They don't implement the closure traits - ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) => { + ty::TyFnDef(_, _, fn_ty) | + ty::TyFnPtr(fn_ty) => { if fn_ty.unsafety == Unsafety::Unsafe || - fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging { + fn_ty.sig.skip_binder().output == ty::FnOutput::FnDiverging { return; } } diff --git a/src/functions.rs b/src/functions.rs index ed04473abc3..37b65e471fa 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -31,9 +31,7 @@ pub struct Functions { impl Functions { pub fn new(threshold: u64) -> Functions { - Functions { - threshold: threshold - } + Functions { threshold: threshold } } } @@ -49,7 +47,8 @@ impl LateLintPass for Functions { if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { match item.node { - hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..) => return, + hir::ItemImpl(_, _, _, Some(_), _, _) | + hir::ItemDefaultImpl(..) => return, _ => (), } } @@ -68,7 +67,9 @@ impl Functions { fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { let args = decl.inputs.len() as u64; if args > self.threshold { - span_lint(cx, TOO_MANY_ARGUMENTS, span, + span_lint(cx, + TOO_MANY_ARGUMENTS, + span, &format!("this function has to many arguments ({}/{})", args, self.threshold)); } } diff --git a/src/if_not_else.rs b/src/if_not_else.rs index 1a074a723a9..ebc2ce76fec 100644 --- a/src/if_not_else.rs +++ b/src/if_not_else.rs @@ -37,15 +37,15 @@ 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/src/len_zero.rs b/src/len_zero.rs index 3a376d91c92..7a7a17bc79d 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -64,7 +64,7 @@ impl LateLintPass for LenZero { return; } - if let ExprBinary(Spanned{node: cmp, ..}, ref left, ref right) = expr.node { + if let ExprBinary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node { match cmp { BiEq => check_cmp(cx, expr.span, left, right, ""), BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), @@ -155,7 +155,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { - if let Spanned{node: LitKind::Int(0, _), ..} = *lit { + if let Spanned { node: LitKind::Int(0, _), .. } = *lit { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| { db.span_suggestion(span, @@ -199,7 +199,8 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { .map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))) } ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), - ty::TyEnum(ref id, _) | ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), + ty::TyEnum(ref id, _) | + ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), ty::TyArray(..) | ty::TyStr => true, _ => false, } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index ad42a8568e6..67dfabe2569 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -127,7 +127,7 @@ fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, fun match slf.node { SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt), SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty), - _ => {} + _ => (), } } // extract lifetimes in input argument types @@ -243,7 +243,8 @@ impl<'v, 't> RefVisitor<'v, 't> { 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) => { + Def::TyAlias(def_id) | + Def::Struct(def_id) => { let type_scheme = self.cx.tcx.lookup_item_type(def_id); for _ in type_scheme.generics.regions.as_slice() { self.record(&None); @@ -255,7 +256,7 @@ impl<'v, 't> RefVisitor<'v, 't> { self.record(&None); } } - _ => {} + _ => (), } } } @@ -277,7 +278,7 @@ impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { TyPath(_, ref path) => { self.collect_anonymous_lifetimes(path, ty); } - _ => {} + _ => (), } walk_ty(self, ty); } @@ -353,7 +354,7 @@ fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics, match slf.node { SelfRegion(Some(ref lt), _, _) => checker.visit_lifetime(lt), SelfExplicit(ref t, _) => walk_ty(&mut checker, t), - _ => {} + _ => (), } } diff --git a/src/loops.rs b/src/loops.rs index f376e28c992..0b341f645df 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -14,8 +14,8 @@ use std::collections::HashMap; use syntax::ast; use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, - span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, - unsugar_range, walk_ptrs_ty, recover_for_loop}; + span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range, + walk_ptrs_ty, recover_for_loop}; use utils::paths; use utils::UnsugaredRange; @@ -247,7 +247,8 @@ impl LateLintPass for LoopsPass { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // ensure "if let" compatible match structure match *source { - MatchSource::Normal | MatchSource::IfLetDesugar{..} => { + MatchSource::Normal | + MatchSource::IfLetDesugar { .. } => { 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) { @@ -779,7 +780,8 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> { Some(ref expr) => 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), _ => None, } } diff --git a/src/matches.rs b/src/matches.rs index c1692ee47d2..bce93b717a3 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -252,19 +252,20 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if let Some((ref true_expr, ref false_expr)) = exprs { match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => + (false, false) => { Some(format!("if {} {} else {}", 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) => + expr_block(cx, false_expr, None, ".."))) + } + (false, true) => { + Some(format!("if {} {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, ".."))) + } + (true, false) => { Some(format!("try\nif !{} {}", snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))), + expr_block(cx, false_expr, None, ".."))) + } (true, true) => None, } } else { @@ -312,9 +313,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match expr.span, "you don't need to add `&` to both the expression and the patterns", |db| { - db.span_suggestion(expr.span, - "try", - template); + db.span_suggestion(expr.span, "try", template); }); } else { let template = match_template(cx, expr.span, source, "*", ex); @@ -324,7 +323,8 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match "you don't need to add `&` to all patterns", |db| { 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); }); } @@ -373,17 +373,18 @@ type TypedRanges = Vec<SpannedRange<ConstInt>>; /// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than /// `Uint` and `Int` probably don't make sense. fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> 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() + 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() } fn is_unit_expr(expr: &Expr) -> bool { @@ -416,7 +417,7 @@ fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, e MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet), MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet), MatchSource::ForLoopDesugar => span_bug!(span, "for loop desugared to match with &-patterns!"), - MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!") + MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!"), } } @@ -432,13 +433,15 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & impl<'a, T: Copy> Kind<'a, T> { fn range(&self) -> &'a SpannedRange<T> { match *self { - Kind::Start(_, r) | Kind::End(_, r) => r, + Kind::Start(_, r) | + Kind::End(_, r) => r, } } fn value(self) -> T { match self { - Kind::Start(t, _) | Kind::End(t, _) => t, + Kind::Start(t, _) | + Kind::End(t, _) => t, } } } diff --git a/src/methods.rs b/src/methods.rs index d2a91b615ae..4a31a564a3e 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -436,7 +436,8 @@ impl LateLintPass for MethodsPass { } let ret_ty = return_ty(cx, implitem.id); - if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { + if &name.as_str() == &"new" && + !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { span_lint(cx, NEW_RET_NO_SELF, sig.explicit_self.span, @@ -946,7 +947,8 @@ impl SelfKind { (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) | (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) | (&SelfKind::No, &SelfStatic) => true, - (&SelfKind::Ref, &SelfValue(_)) | (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, + (&SelfKind::Ref, &SelfValue(_)) | + (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), _ => false, } diff --git a/src/minmax.rs b/src/minmax.rs index 67299bac998..7cd2d33cab9 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -34,7 +34,9 @@ impl LateLintPass for MinMaxPass { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { - (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), + (_, None) | + (MinMax::Max, Some(Ordering::Less)) | + (MinMax::Min, Some(Ordering::Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); } diff --git a/src/misc.rs b/src/misc.rs index 654e6244c1b..7323f18a46e 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -226,7 +226,7 @@ impl LateLintPass for CmpOwned { fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) { let (arg_ty, snip) = match expr.node { - ExprMethodCall(Spanned{node: ref name, ..}, _, ref args) if args.len() == 1 => { + ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) if args.len() == 1 => { if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { (cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { @@ -309,7 +309,7 @@ impl LintPass for ModuloOne { impl LateLintPass for ModuloOne { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprBinary(ref cmp, _, ref right) = expr.node { - if let Spanned {node: BinOp_::BiRem, ..} = *cmp { + if let Spanned { node: BinOp_::BiRem, .. } = *cmp { if is_integer_literal(right, 1) { span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); } @@ -422,7 +422,8 @@ impl LateLintPass for UsedUnderscoreBinding { fn is_used(cx: &LateContext, expr: &Expr) -> bool { if let Some(ref parent) = get_parent_expr(cx, expr) { match parent.node { - ExprAssign(_, ref rhs) | ExprAssignOp(_, _, ref rhs) => **rhs == *expr, + ExprAssign(_, ref rhs) | + ExprAssignOp(_, _, ref rhs) => **rhs == *expr, _ => is_used(cx, &parent), } } else { diff --git a/src/misc_early.rs b/src/misc_early.rs index b1c584a4b3e..b43359f29b9 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -134,11 +134,11 @@ 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 = format!("{}", snippet(cx, block.span, "..")); - db.span_suggestion(expr.span, "Try doing something like: ", hint); - } - }); + if decl.inputs.is_empty() { + let hint = format!("{}", snippet(cx, block.span, "..")); + db.span_suggestion(expr.span, "Try doing something like: ", hint); + } + }); } } } diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 65e2c3a46a9..7b7b5ecdf4e 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -52,7 +52,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { unwrap_addr(expr).map_or((), |e| { unwrap_addr(e).map_or_else(|| { - if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty { + if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { span_lint(cx, MUT_MUT, expr.span, @@ -71,7 +71,7 @@ fn check_expr_mut(cx: &LateContext, expr: &Expr) { fn unwrap_mut(ty: &Ty) -> Option<&Ty> { match ty.node { - TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Some(pty), + TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) => Some(pty), _ => None, } } diff --git a/src/mut_reference.rs b/src/mut_reference.rs index d74c2c41f23..4ac4d83360e 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -47,19 +47,20 @@ impl LateLintPass for UnnecessaryMutPassed { 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()) } - _ => {} + _ => (), } } } fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) { match type_definition.sty { - TypeVariants::TyFnDef(_, _, ref fn_type) | TypeVariants::TyFnPtr(ref fn_type) => { + TypeVariants::TyFnDef(_, _, ref fn_type) | + TypeVariants::TyFnPtr(ref fn_type) => { 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, ..}) | - TypeVariants::TyRawPtr(TypeAndMut {mutbl: MutImmutable, ..}) => { + TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) | + TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => { if let ExprAddrOf(MutMutable, _) = argument.node { span_lint(cx, UNNECESSARY_MUT_PASSED, @@ -67,7 +68,7 @@ fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &Ty &format!("The function/method \"{}\" doesn't need a mutable reference", name)); } } - _ => {} + _ => (), } } } diff --git a/src/needless_bool.rs b/src/needless_bool.rs index 07da57c684b..f95d6f5c9c1 100644 --- a/src/needless_bool.rs +++ b/src/needless_bool.rs @@ -57,9 +57,10 @@ impl LateLintPass for NeedlessBool { span_lint_and_then(cx, NEEDLESS_BOOL, e.span, - "this if-then-else expression returns a bool literal", |db| { - db.span_suggestion(e.span, "you can reduce it to", hint); - }); + "this if-then-else expression returns a bool literal", + |db| { + 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)) | @@ -98,7 +99,7 @@ impl LintPass for BoolComparison { impl LateLintPass for BoolComparison { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { use self::Expression::*; - if let ExprBinary(Spanned{ node: BiEq, .. }, ref left_side, ref right_side) = e.node { + 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)) { (Bool(true), Other) => { let hint = snippet(cx, right_side.span, "..").into_owned(); @@ -155,15 +156,17 @@ enum Expression { fn fetch_bool_block(block: &Block) -> Expression { match (&*block.stmts, block.expr.as_ref()) { ([], Some(e)) => fetch_bool_expr(&**e), - ([ref e], None) => if let StmtSemi(ref e, _) = e.node { - if let ExprRet(_) = e.node { - fetch_bool_expr(&**e) + ([ref e], None) => { + if let StmtSemi(ref e, _) = e.node { + if let ExprRet(_) = e.node { + fetch_bool_expr(&**e) + } else { + Expression::Other + } } else { Expression::Other } - } else { - Expression::Other - }, + } _ => Expression::Other, } } @@ -177,11 +180,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, - }, + } + ExprRet(Some(ref expr)) => { + match fetch_bool_expr(expr) { + Expression::Bool(value) => Expression::RetBool(value), + _ => Expression::Other, + } + } _ => Expression::Other, } } diff --git a/src/no_effect.rs b/src/no_effect.rs index afb49376b3f..d928de41578 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -52,7 +52,8 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { } } Expr_::ExprBlock(ref block) => { - block.stmts.is_empty() && if let Some(ref expr) = block.expr { + block.stmts.is_empty() && + if let Some(ref expr) = block.expr { has_no_effect(cx, expr) } else { false diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 36fcc292bfc..a6f0571c499 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -45,7 +45,7 @@ struct ExistingName { interned: InternedString, span: Span, len: usize, - whitelist: &'static[&'static str], + whitelist: &'static [&'static str], } struct SimilarNamesLocalVisitor<'a, 'b: 'a> { @@ -57,6 +57,7 @@ struct SimilarNamesLocalVisitor<'a, 'b: 'a> { // this list contains lists of names that are allowed to be similar // the assumption is that no name is ever contained in multiple lists. +#[cfg_attr(rustfmt, rustfmt_skip)] const WHITELIST: &'static [&'static [&'static str]] = &[ &["parsed", "parser"], &["lhs", "rhs"], @@ -75,7 +76,7 @@ impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> } } -fn get_whitelist(interned_name: &str) -> Option<&'static[&'static str]> { +fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { for &allow in WHITELIST { if whitelisted(interned_name, allow) { return Some(allow); @@ -112,8 +113,7 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { span_lint(self.0.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!("{}th binding whose name is just one char", - self.0.single_char_names.len())); + &format!("{}th binding whose name is just one char", self.0.single_char_names.len())); } } fn check_name(&mut self, span: Span, name: Name) { @@ -162,7 +162,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } else { let second_last_i = interned_chars.next_back().expect("we know we have at least three chars"); let second_last_e = existing_chars.next_back().expect("we know we have at least three chars"); - if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || + !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { // allowed similarity foo_x, foo_y // or too many chars differ (foo_x, boo_y) or (foox, booy) continue; @@ -172,7 +173,8 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { } else { let second_i = interned_chars.next().expect("we know we have at least two chars"); let second_e = existing_chars.next().expect("we know we have at least two chars"); - if !eq_or_numeric(second_i, second_e) || second_i == '_' || !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + if !eq_or_numeric(second_i, second_e) || second_i == '_' || + !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { // allowed similarity x_foo, y_foo // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) continue; @@ -187,10 +189,11 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { |diag| { diag.span_note(existing_name.span, "existing binding defined here"); if let Some(split) = split_at { - diag.span_help(span, &format!("separate the discriminating character \ - by an underscore like: `{}_{}`", - &interned_name[..split], - &interned_name[split..])); + diag.span_help(span, + &format!("separate the discriminating character by an \ + underscore like: `{}_{}`", + &interned_name[..split], + &interned_name[split..])); } }); return; diff --git a/src/open_options.rs b/src/open_options.rs index aaaebe5b2f8..1d760599e3f 100644 --- a/src/open_options.rs +++ b/src/open_options.rs @@ -65,7 +65,7 @@ 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 let Spanned { node: LitKind::Bool(lit), .. } = **span { if lit { Argument::True } else { @@ -96,7 +96,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp "write" => { options.push((OpenOption::Write, argument_option)); } - _ => {} + _ => (), } get_open_options(cx, &arguments[0], options); diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index 627028ad462..6a8ca368fc1 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{span_lint}; +use utils::span_lint; /// **What it does:** This lint finds classic underflow / overflow checks. /// diff --git a/src/precedence.rs b/src/precedence.rs index 7e24f55d1b4..825a1b84450 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -31,7 +31,7 @@ impl LintPass for Precedence { impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { - if let ExprKind::Binary(Spanned { node: op, ..}, ref left, ref right) = expr.node { + if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { if !is_bit_op(op) { return; } @@ -75,7 +75,9 @@ impl EarlyLintPass for Precedence { if let Some(slf) = args.first() { if let ExprKind::Lit(ref lit) = slf.node { match lit.node { - LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { + LitKind::Int(..) | + LitKind::Float(..) | + LitKind::FloatUnsuffixed(..) => { span_lint(cx, PRECEDENCE, expr.span, @@ -94,7 +96,7 @@ impl EarlyLintPass for Precedence { fn is_arith_expr(expr: &Expr) -> bool { match expr.node { - ExprKind::Binary(Spanned { node: op, ..}, _, _) => is_arith_op(op), + ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op), _ => false, } } diff --git a/src/regex.rs b/src/regex.rs index 177f7a7b045..3bd17a2d365 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -167,14 +167,14 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { match *s { Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), - Expr::Literal {..} => Some("consider using `str::contains`"), + Expr::Literal { .. } => Some("consider using `str::contains`"), Expr::Concat(ref exprs) => { match exprs.len() { 2 => { match (&exprs[0], &exprs[1]) { (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), - (&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"), - (&Expr::Literal {..}, &Expr::EndText) => Some("consider using `str::ends_with`"), + (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), + (&Expr::Literal { .. }, &Expr::EndText) => Some("consider using `str::ends_with`"), _ => None, } } diff --git a/src/returns.rs b/src/returns.rs index bb94b59df7d..d7893821263 100644 --- a/src/returns.rs +++ b/src/returns.rs @@ -71,7 +71,7 @@ impl ReturnPass { self.check_final_expr(cx, &arm.body); } } - _ => {} + _ => (), } } diff --git a/src/shadow.rs b/src/shadow.rs index 928d447974a..bb287f449e3 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -77,7 +77,8 @@ fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)> for stmt in &block.stmts { match stmt.node { StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), - StmtExpr(ref e, _) | StmtSemi(ref e, _) => check_expr(cx, e, bindings), + StmtExpr(ref e, _) | + StmtSemi(ref e, _) => check_expr(cx, e, bindings), } } if let Some(ref o) = block.expr { @@ -94,7 +95,7 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { return; } if let DeclLocal(ref local) = decl.node { - let Local{ ref pat, ref ty, ref init, span, .. } = **local; + let Local { ref pat, ref ty, ref init, span, .. } = **local; if let Some(ref t) = *ty { check_ty(cx, t, bindings) } @@ -109,7 +110,8 @@ fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { 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, + Some(Def::Variant(..)) | + Some(Def::Struct(..)) => false, _ => true, } } @@ -251,7 +253,8 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) => check_expr(cx, e, bindings), - ExprBlock(ref block) | ExprLoop(ref block, _) => check_block(cx, block, bindings), + ExprBlock(ref block) | + ExprLoop(ref block, _) => check_block(cx, block, bindings), // ExprCall // ExprMethodCall ExprVec(ref v) | ExprTup(ref v) => { @@ -297,8 +300,8 @@ fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { 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), + TyPtr(MutTy { ty: ref mty, .. }) | + TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings), TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) diff --git a/src/strings.rs b/src/strings.rs index a6808d2dd42..92bce8d0e42 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -74,7 +74,7 @@ impl LintPass for StringAdd { impl LateLintPass for StringAdd { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = e.node { + if let ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) = e.node { if is_string(cx, left) { if let Allow = cx.current_level(STRING_ADD_ASSIGN) { // the string_add_assign is allow, so no duplicates @@ -112,7 +112,7 @@ fn is_string(cx: &LateContext, e: &Expr) -> bool { fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { - ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), + 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)) } @@ -145,8 +145,7 @@ 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""#)); + 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/src/temporary_assignment.rs b/src/temporary_assignment.rs index 44796410458..1496a45dac2 100644 --- a/src/temporary_assignment.rs +++ b/src/temporary_assignment.rs @@ -18,8 +18,7 @@ declare_lint! { fn is_temporary(expr: &Expr) -> bool { match expr.node { - ExprStruct(..) | - ExprTup(..) => true, + ExprStruct(..) | ExprTup(..) => true, _ => false, } } @@ -37,7 +36,8 @@ impl LateLintPass for TemporaryAssignmentPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprAssign(ref target, _) = expr.node { match target.node { - ExprField(ref base, _) | ExprTupField(ref base, _) => { + ExprField(ref base, _) | + ExprTupField(ref base, _) => { if is_temporary(base) && !is_adjusted(cx, base) { span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } diff --git a/src/transmute.rs b/src/transmute.rs index 8b74b1989db..2217fd59bd9 100644 --- a/src/transmute.rs +++ b/src/transmute.rs @@ -52,11 +52,7 @@ pub struct Transmute; impl LintPass for Transmute { fn get_lints(&self) -> LintArray { - lint_array! [ - CROSSPOINTER_TRANSMUTE, - TRANSMUTE_PTR_TO_REF, - USELESS_TRANSMUTE - ] + lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE] } } @@ -79,12 +75,16 @@ impl LateLintPass for Transmute { span_lint(cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty)); + &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", + from_ty, + to_ty)); } else if is_ptr_to(from_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)); + &format!("transmute from a type (`{}`) to the type that it points to (`{}`)", + from_ty, + to_ty)); } else { check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]); } @@ -102,10 +102,7 @@ fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool { } } -fn check_ptr_to_ref<'tcx>(cx: &LateContext, - from_ty: ty::Ty<'tcx>, - to_ty: ty::Ty<'tcx>, - e: &Expr, arg: &Expr) { +fn check_ptr_to_ref<'tcx>(cx: &LateContext, from_ty: ty::Ty<'tcx>, to_ty: ty::Ty<'tcx>, e: &Expr, arg: &Expr) { if let TyRawPtr(ref from_pty) = from_ty.sty { if let TyRef(_, ref to_rty) = to_ty.sty { let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)", @@ -122,8 +119,7 @@ fn check_ptr_to_ref<'tcx>(cx: &LateContext, let sugg = if from_pty.ty == to_rty.ty { format!("{}{}", deref, arg) - } - else { + } else { format!("{}({} as {} {})", deref, arg, cast, to_rty.ty) }; diff --git a/src/types.rs b/src/types.rs index 9d12d7970d1..43d42cde501 100644 --- a/src/types.rs +++ b/src/types.rs @@ -248,7 +248,8 @@ fn int_ty_to_nbits(typ: &ty::TyS) -> usize { fn is_isize_or_usize(typ: &ty::TyS) -> bool { match typ.sty { - ty::TyInt(IntTy::Is) | ty::TyUint(UintTy::Us) => true, + ty::TyInt(IntTy::Is) | + ty::TyUint(UintTy::Us) => true, _ => false, } } @@ -536,9 +537,7 @@ impl<'v> Visitor<'v> for TypeComplexityVisitor { fn visit_ty(&mut self, ty: &'v 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), + TyInfer | TyPtr(..) | TyRptr(..) => (1, 0), // the "normal" components of a type: named types, arrays/tuples TyPath(..) | @@ -663,17 +662,17 @@ 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 @ Extr { which: Maximum, .. }), _) => (l, AlwaysFalse), // max < x + (_, Some(r @ Extr { 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 @ 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 _ => return None, } } @@ -702,14 +701,12 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx let which = match (ty, cv) { (&ty::TyBool, Bool(false)) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) | (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) | (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) | (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) | (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) | (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) | (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) | (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) | @@ -718,14 +715,12 @@ fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeEx (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum, (&ty::TyBool, Bool(true)) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) | (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) | (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) | (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) | (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) | (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) | (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) | (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) | @@ -845,22 +840,26 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( use syntax::ast::{IntTy, UintTy}; use std::*; - if let ExprCast(ref cast_exp,_) = expr.node { + if let ExprCast(ref cast_exp, _) = expr.node { match cx.tcx.expr_ty(cast_exp).sty { - TyInt(int_ty) => Some(match int_ty { - IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)), - IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)), - IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)), - 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)), - UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)), - UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)), - 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)), - }), + TyInt(int_ty) => { + Some(match int_ty { + IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)), + IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)), + IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)), + 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)), + UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)), + UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)), + 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 { @@ -885,29 +884,26 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { } else { None } - }, + } Err(_) => None, } } fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) { if let ExprCast(ref cast_val, _) = expr.node { - span_lint( - cx, - INVALID_UPCAST_COMPARISONS, - *span, - &format!( + span_lint(cx, + INVALID_UPCAST_COMPARISONS, + *span, + &format!( "because of the numeric bounds on `{}` prior to casting, this expression is always {}", snippet(cx, cast_val.span, "the expression"), if always { "true" } else { "false" }, - ) - ); + )); } } -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 { @@ -917,14 +913,38 @@ fn upcast_comparison_bounds_err( err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne); } } else if match rel { - Rel::Lt => if invert { norm_rhs_val < lb } else { ub < norm_rhs_val }, - Rel::Le => if invert { norm_rhs_val <= lb } else { ub <= norm_rhs_val }, + Rel::Lt => { + if invert { + norm_rhs_val < lb + } 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) } else if match rel { - Rel::Lt => if invert { norm_rhs_val >= ub } else { lb >= norm_rhs_val }, - Rel::Le => if invert { norm_rhs_val > ub } else { lb > norm_rhs_val }, + Rel::Lt => { + if invert { + norm_rhs_val >= ub + } 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) diff --git a/src/utils/conf.rs b/src/utils/conf.rs index 74a68d2d730..e773cc0e025 100644 --- a/src/utils/conf.rs +++ b/src/utils/conf.rs @@ -8,7 +8,8 @@ use toml; pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { for arg in args { match arg.node { - ast::MetaItemKind::Word(ref name) | ast::MetaItemKind::List(ref name, _) => { + ast::MetaItemKind::Word(ref name) | + ast::MetaItemKind::List(ref name, _) => { if name == &"conf_file" { return Err(("`conf_file` must be a named value", arg.span)); } diff --git a/src/utils/hir.rs b/src/utils/hir.rs index f6fa2176941..379812a283d 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -76,7 +76,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&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)) + 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), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), @@ -114,9 +116,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { both(l_qself, r_qself, |l, r| self.eq_qself(l, r)) && self.eq_path(l_subpath, r_subpath) } (&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)) && - over(lf, rf, |l, r| self.eq_field(l, r)) + self.eq_path(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), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d01b0698de8..d8f5a0757b7 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -144,7 +144,8 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { /// Check if type is struct or enum type with given def path. pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { match ty.sty { - ty::TyEnum(ref adt, _) | ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), + ty::TyEnum(ref adt, _) | + ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), _ => false, } } @@ -304,9 +305,9 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.map.get_parent(expr.id); match cx.tcx.map.find(parent_id) { - Some(Node::NodeItem(&Item{ ref name, .. })) | - Some(Node::NodeTraitItem(&TraitItem{ ref name, .. })) | - Some(Node::NodeImplItem(&ImplItem{ ref name, .. })) => Some(*name), + Some(Node::NodeItem(&Item { ref name, .. })) | + Some(Node::NodeTraitItem(&TraitItem { ref name, .. })) | + Some(Node::NodeImplItem(&ImplItem { ref name, .. })) => Some(*name), _ => None, } } @@ -431,7 +432,7 @@ pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c if let Some(node) = enclosing_node { match node { Node::NodeBlock(ref block) => Some(block), - Node::NodeItem(&Item{ node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), + Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), _ => None, } } else { @@ -517,7 +518,8 @@ pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, /// Return the base type for references and raw pointers. pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), + ty::TyRef(_, ref tm) | + ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), _ => ty, } } @@ -526,7 +528,8 @@ pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { match ty.sty { - ty::TyRef(_, ref tm) | ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), + ty::TyRef(_, ref tm) | + ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), _ => (ty, depth), } } @@ -730,22 +733,46 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { match unwrap_unstable(&expr).node { ExprPath(None, ref path) => { if match_path(path, &paths::RANGE_FULL) { - Some(UnsugaredRange { start: None, end: None, limits: RangeLimits::HalfOpen }) + Some(UnsugaredRange { + start: None, + end: None, + limits: RangeLimits::HalfOpen, + }) } else { None } } ExprStruct(ref path, ref fields, None) => { if match_path(path, &paths::RANGE_FROM) { - Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen }) + Some(UnsugaredRange { + start: get_field("start", fields), + end: None, + limits: RangeLimits::HalfOpen, + }) } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { - Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed }) + Some(UnsugaredRange { + start: get_field("start", fields), + end: get_field("end", fields), + limits: RangeLimits::Closed, + }) } else if match_path(path, &paths::RANGE) { - Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + Some(UnsugaredRange { + start: get_field("start", fields), + end: get_field("end", fields), + limits: RangeLimits::HalfOpen, + }) } else if match_path(path, &paths::RANGE_TO_INCLUSIVE) { - Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed }) + Some(UnsugaredRange { + start: None, + end: get_field("end", fields), + limits: RangeLimits::Closed, + }) } else if match_path(path, &paths::RANGE_TO) { - Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::HalfOpen }) + Some(UnsugaredRange { + start: None, + end: get_field("end", fields), + limits: RangeLimits::HalfOpen, + }) } else { None } diff --git a/src/vec.rs b/src/vec.rs index 513efa1a2a4..63b9952c3c8 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -63,8 +63,7 @@ fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) { }; format!("&[{}]", snippet(cx, span, "..")).into() - } - else { + } else { "&[]".into() } } -- cgit 1.4.1-3-g733a5 From 578cc3dc71134594da58a606acce1ef03883fee3 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 15 Apr 2016 00:09:37 +0200 Subject: Fix the `REGEX_MACRO` lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [rust-lang-nursery/regex#183](https://github.com/rust-lang-nursery/regex/pull/183) has made the following change that broke the lint: src/re.rs → src/re_unicode.rs --- src/regex.rs | 7 +++---- src/utils/paths.rs | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/regex.rs b/src/regex.rs index 3bd17a2d365..72a33757027 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -9,8 +9,7 @@ use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; -use utils::paths; -use utils::{is_expn_of, match_path, match_type, span_lint, span_help_and_lint}; +use utils::{is_expn_of, match_path, match_type, paths, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// @@ -73,8 +72,8 @@ impl LateLintPass for RegexPass { if_let_chain!{[ self.last.is_none(), let Some(ref expr) = block.expr, - match_type(cx, cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), - let Some(span) = is_expn_of(cx, expr.span, "regex") + match_type(cx, cx.tcx.expr_ty(expr), &paths::REGEX), + let Some(span) = is_expn_of(cx, expr.span, "regex"), ], { if !self.spans.contains(&span) { span_lint(cx, diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 1777c31ef8c..88d0dd415aa 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -29,6 +29,7 @@ pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["std", "ops", "RangeIn pub const RANGE: [&'static str; 3] = ["std", "ops", "Range"]; pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; pub const RANGE_TO: [&'static str; 3] = ["std", "ops", "RangeTo"]; +pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; pub const REGEX_NEW: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING: [&'static str; 3] = ["collections", "string", "String"]; -- cgit 1.4.1-3-g733a5 From 12b8a0ac148f7fa3120ba99b61b24c5601a7afcf Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Sun, 17 Apr 2016 12:52:38 +0200 Subject: Make if_not_else lint Allow by default (fixes #859) --- README.md | 2 +- src/if_not_else.rs | 2 +- src/lib.rs | 2 +- tests/compile-fail/entry.rs | 2 +- tests/compile-fail/if_not_else.rs | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) mode change 100644 => 100755 tests/compile-fail/entry.rs mode change 100644 => 100755 tests/compile-fail/if_not_else.rs (limited to 'src') diff --git a/README.md b/README.md index c7cee794db4..80d26cdede0 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ name [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` [for_loop_over_result](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_result) | warn | for-looping over a `Result`, which is more clearly expressed as an `if let` [identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1` -[if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | warn | finds if branches that could be swapped so no negation operation is necessary on the condition +[if_not_else](https://github.com/Manishearth/rust-clippy/wiki#if_not_else) | allow | finds if branches that could be swapped so no negation operation is necessary on the condition [if_same_then_else](https://github.com/Manishearth/rust-clippy/wiki#if_same_then_else) | warn | if with the same *then* and *else* blocks [ifs_same_cond](https://github.com/Manishearth/rust-clippy/wiki#ifs_same_cond) | warn | consecutive `ifs` with the same condition [indexing_slicing](https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing) | allow | indexing/slicing usage diff --git a/src/if_not_else.rs b/src/if_not_else.rs index ebc2ce76fec..2fc2cc10e38 100644 --- a/src/if_not_else.rs +++ b/src/if_not_else.rs @@ -14,7 +14,7 @@ use utils::span_help_and_lint; /// /// **Example:** if !v.is_empty() { a() } else { b() } declare_lint! { - pub IF_NOT_ELSE, Warn, + pub IF_NOT_ELSE, Allow, "finds if branches that could be swapped so no negation operation is necessary on the condition" } diff --git a/src/lib.rs b/src/lib.rs index c1a7732e3f5..0f005152239 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -237,6 +237,7 @@ pub fn plugin_registrar(reg: &mut Registry) { array_indexing::INDEXING_SLICING, booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, + if_not_else::IF_NOT_ELSE, matches::SINGLE_MATCH_ELSE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, @@ -289,7 +290,6 @@ pub fn plugin_registrar(reg: &mut Registry) { formatting::SUSPICIOUS_ELSE_FORMATTING, functions::TOO_MANY_ARGUMENTS, identity_op::IDENTITY_OP, - if_not_else::IF_NOT_ELSE, items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, diff --git a/tests/compile-fail/entry.rs b/tests/compile-fail/entry.rs old mode 100644 new mode 100755 index e65ef503ba5..7dc4054ec5b --- a/tests/compile-fail/entry.rs +++ b/tests/compile-fail/entry.rs @@ -1,6 +1,6 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused, if_not_else)] +#![allow(unused)] #![deny(map_entry)] diff --git a/tests/compile-fail/if_not_else.rs b/tests/compile-fail/if_not_else.rs old mode 100644 new mode 100755 index eb716e4599a..a72699adafd --- a/tests/compile-fail/if_not_else.rs +++ b/tests/compile-fail/if_not_else.rs @@ -1,6 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] #![deny(clippy)] +#![deny(if_not_else)] fn bla() -> bool { unimplemented!() } -- cgit 1.4.1-3-g733a5 From 0bc067089eae3011b92aed71191a48bf2b9a0d58 Mon Sep 17 00:00:00 2001 From: llogiq <bogusandre@gmail.com> Date: Sun, 17 Apr 2016 23:33:21 +0200 Subject: add neg_multiply lint (#862) add neg_multiply lint --- CHANGELOG.md | 1 + README.md | 3 +- src/consts.rs | 3 +- src/lib.rs | 3 ++ src/neg_multiply.rs | 57 ++++++++++++++++++++++++++++++++++++++ tests/compile-fail/neg_multiply.rs | 40 ++++++++++++++++++++++++++ 6 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/neg_multiply.rs create mode 100644 tests/compile-fail/neg_multiply.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 2493ae2502d..d02136421ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,6 +145,7 @@ All notable changes to this project will be documented in this file. [`needless_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop [`needless_return`]: https://github.com/Manishearth/rust-clippy/wiki#needless_return [`needless_update`]: https://github.com/Manishearth/rust-clippy/wiki#needless_update +[`neg_multiply`]: https://github.com/Manishearth/rust-clippy/wiki#neg_multiply [`new_ret_no_self`]: https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self [`new_without_default`]: https://github.com/Manishearth/rust-clippy/wiki#new_without_default [`no_effect`]: https://github.com/Manishearth/rust-clippy/wiki#no_effect diff --git a/README.md b/README.md index 80d26cdede0..3951418eade 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 141 lints included in this crate: +There are 142 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -95,6 +95,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[neg_multiply](https://github.com/Manishearth/rust-clippy/wiki#neg_multiply) | warn | Warns on multiplying integers with -1 [new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method [new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect diff --git a/src/consts.rs b/src/consts.rs index 0eed34a8055..4a5f457ed7d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -177,8 +177,9 @@ impl PartialOrd for Constant { } } +/// parse a `LitKind` to a `Constant` #[allow(cast_possible_wrap)] -fn lit_to_constant(lit: &LitKind) -> Constant { +pub fn lit_to_constant(lit: &LitKind) -> Constant { match *lit { LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), diff --git a/src/lib.rs b/src/lib.rs index 0f005152239..6d98cf55f09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,7 @@ pub mod mut_reference; pub mod mutex_atomic; pub mod needless_bool; pub mod needless_update; +pub mod neg_multiply; pub mod new_without_default; pub mod no_effect; pub mod non_expressive_names; @@ -232,6 +233,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); 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_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -343,6 +345,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, needless_update::NEEDLESS_UPDATE, + neg_multiply::NEG_MULTIPLY, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, non_expressive_names::MANY_SINGLE_CHAR_NAMES, diff --git a/src/neg_multiply.rs b/src/neg_multiply.rs new file mode 100644 index 00000000000..fb986409a41 --- /dev/null +++ b/src/neg_multiply.rs @@ -0,0 +1,57 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::codemap::{Span, Spanned}; + +use consts::{self, Constant}; +use utils::span_lint; + +/// **What it does:** Checks for multiplication by -1 as a form of negation. +/// +/// **Why is this bad?** It's more readable to just negate. +/// +/// **Known problems:** This only catches integers (for now) +/// +/// **Example:** `x * -1` +declare_lint! { + pub NEG_MULTIPLY, + Warn, + "Warns on multiplying integers with -1" +} + +#[derive(Copy, Clone)] +pub struct NegMultiply; + +impl LintPass for NegMultiply { + fn get_lints(&self) -> LintArray { + lint_array!(NEG_MULTIPLY) + } +} + +#[allow(match_same_arms)] +impl LateLintPass for NegMultiply { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprBinary(Spanned { node: BiMul, .. }, ref l, ref r) = e.node { + match (&l.node, &r.node) { + (&ExprUnary(..), &ExprUnary(..)) => (), + (&ExprUnary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r), + (_, &ExprUnary(UnNeg, ref lit)) => check_mul(cx, e.span, lit, l), + _ => () + } + } + } +} + +fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { + if_let_chain!([ + let ExprLit(ref l) = lit.node, + let Constant::Int(ref ci) = consts::lit_to_constant(&l.node), + let Some(val) = ci.to_u64(), + val == 1, + cx.tcx.expr_ty(exp).is_integral() + ], { + span_lint(cx, + NEG_MULTIPLY, + span, + "Negation by multiplying with -1"); + }) +} diff --git a/tests/compile-fail/neg_multiply.rs b/tests/compile-fail/neg_multiply.rs new file mode 100644 index 00000000000..9deb38920de --- /dev/null +++ b/tests/compile-fail/neg_multiply.rs @@ -0,0 +1,40 @@ +#![feature(plugin)] + +#![plugin(clippy)] +#![deny(neg_multiply)] +#![allow(no_effect)] + +use std::ops::Mul; + +struct X; + +impl Mul<isize> for X { + type Output = X; + + fn mul(self, _r: isize) -> Self { + self + } +} + +impl Mul<X> for isize { + type Output = X; + + fn mul(self, _r: X) -> X { + X + } +} + +fn main() { + let x = 0; + + x * -1; + //~^ ERROR Negation by multiplying with -1 + + -1 * x; + //~^ ERROR Negation by multiplying with -1 + + -1 * -1; // should be ok + + X * -1; // should be ok + -1 * X; // should also be ok +} -- cgit 1.4.1-3-g733a5 From 038f528f452e35a5d586898c878b3b69fd8ff539 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Tue, 19 Apr 2016 16:27:01 -0700 Subject: Added lint for use imports which remove unsafe from name --- src/lib.rs | 3 + src/unsafe_removed_from_name.rs | 90 ++++++++++++++++++++++++++ tests/compile-fail/unsafe_removed_from_name.rs | 12 ++++ 3 files changed, 105 insertions(+) create mode 100644 src/unsafe_removed_from_name.rs create mode 100644 tests/compile-fail/unsafe_removed_from_name.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 6d98cf55f09..eee091e6195 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,6 +109,7 @@ pub mod transmute; pub mod types; pub mod unicode; pub mod unused_label; +pub mod unsafe_removed_from_name; pub mod vec; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -234,6 +235,7 @@ pub fn plugin_registrar(reg: &mut 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_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -379,6 +381,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, unused_label::UNUSED_LABEL, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/src/unsafe_removed_from_name.rs b/src/unsafe_removed_from_name.rs new file mode 100644 index 00000000000..86860c67cfe --- /dev/null +++ b/src/unsafe_removed_from_name.rs @@ -0,0 +1,90 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::ast::{Name, NodeId}; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::span_lint; + +/// **What it does:** This lint checks for imports that remove "unsafe" from an item's name +/// +/// **Why is this bad?** Renaming makes it less clear which traits and structures are unsafe. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// use std::cell::{UnsafeCell as TotallySafeCell}; +/// +/// extern crate crossbeam; +/// use crossbeam::{spawn_unsafe as spawn}; +/// ``` +declare_lint! { + pub UNSAFE_REMOVED_FROM_NAME, + Warn, + "unsafe removed from name" +} + +pub struct UnsafeNameRemoval; + +impl LintPass for UnsafeNameRemoval { + fn get_lints(&self) -> LintArray { + lint_array!(UNSAFE_REMOVED_FROM_NAME) + } +} + +impl LateLintPass for UnsafeNameRemoval { + fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { + // only check top level `use` statements + for item in &m.item_ids { + self.lint_item(cx, cx.krate.item(item.id)); + } + } +} + +impl UnsafeNameRemoval { + fn lint_item(&self, cx: &LateContext, item: &Item) { + if let ItemUse(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") + .identifier.name, + *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; + if let (Some(name), Some(rename)) = (plid.name(), plid.rename()) { + unsafe_to_safe_check(name, rename, cx, &item.span); + }; + } + }, + 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(); + 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 + )); + } +} + +fn contains_unsafe(name: &InternedString) -> bool { + name.contains("Unsafe") || name.contains("unsafe") +} diff --git a/tests/compile-fail/unsafe_removed_from_name.rs b/tests/compile-fail/unsafe_removed_from_name.rs new file mode 100644 index 00000000000..facdb2c64ed --- /dev/null +++ b/tests/compile-fail/unsafe_removed_from_name.rs @@ -0,0 +1,12 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(unused_imports)] +#![deny(unsafe_removed_from_name)] + +use std::cell::{UnsafeCell as TotallySafeCell}; +//~^ ERROR removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCell` + +use std::cell::UnsafeCell as TotallySafeCellAgain; +//~^ ERROR removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCellAgain` + +fn main() {} -- cgit 1.4.1-3-g733a5 From b793ad7f2f1cb193422094bf23e2ca1fb93335c8 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Tue, 19 Apr 2016 16:32:04 -0700 Subject: Ran update_lints script --- CHANGELOG.md | 1 + README.md | 3 ++- src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index d02136421ec..d15f85251b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -198,6 +198,7 @@ All notable changes to this project will be documented in this file. [`unit_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#unit_cmp [`unnecessary_mut_passed`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed [`unneeded_field_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern +[`unsafe_removed_from_name`]: https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name [`unstable_as_mut_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice [`unstable_as_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice [`unused_collect`]: https://github.com/Manishearth/rust-clippy/wiki#unused_collect diff --git a/README.md b/README.md index 3951418eade..6aa1e1ecf34 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 142 lints included in this crate: +There are 143 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -146,6 +146,7 @@ name [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference [unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` +[unsafe_removed_from_name](https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name) | warn | unsafe removed from name [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop [unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions diff --git a/src/lib.rs b/src/lib.rs index eee091e6195..5774f3bf7af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,8 +108,8 @@ pub mod temporary_assignment; pub mod transmute; pub mod types; pub mod unicode; -pub mod unused_label; pub mod unsafe_removed_from_name; +pub mod unused_label; pub mod vec; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -380,8 +380,8 @@ pub fn plugin_registrar(reg: &mut Registry) { types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, - unused_label::UNUSED_LABEL, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_label::UNUSED_LABEL, vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); -- cgit 1.4.1-3-g733a5 From 4be11e911662706ffa353225434cd8bd05ea9677 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Tue, 19 Apr 2016 21:41:45 -0700 Subject: Removed unnecessary restriction of unsafe_removed_from_name to top-level use statements --- src/unsafe_removed_from_name.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/unsafe_removed_from_name.rs b/src/unsafe_removed_from_name.rs index 86860c67cfe..404d6d93604 100644 --- a/src/unsafe_removed_from_name.rs +++ b/src/unsafe_removed_from_name.rs @@ -1,6 +1,6 @@ use rustc::hir::*; use rustc::lint::*; -use syntax::ast::{Name, NodeId}; +use syntax::ast::Name; use syntax::codemap::Span; use syntax::parse::token::InternedString; use utils::span_lint; @@ -33,16 +33,7 @@ impl LintPass for UnsafeNameRemoval { } impl LateLintPass for UnsafeNameRemoval { - fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { - // only check top level `use` statements - for item in &m.item_ids { - self.lint_item(cx, cx.krate.item(item.id)); - } - } -} - -impl UnsafeNameRemoval { - fn lint_item(&self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemUse(ref item_use) = item.node { match item_use.node { ViewPath_::ViewPathSimple(ref name, ref path) => { -- cgit 1.4.1-3-g733a5 From de9a80cd102021c05ad0352369abe5bdf38ab57d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 20 Apr 2016 21:09:38 +0200 Subject: Check type for `SINGLE_CHAR_PATTERN` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’d be nicer to actually check for `Pattern` bounds but in the meantime this needs to be fixed. --- src/methods.rs | 20 +++++++++++++------- tests/compile-fail/methods.rs | 4 ++++ 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 4a31a564a3e..73f6a7aa4b0 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -365,16 +365,23 @@ impl LateLintPass for MethodsPass { lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]); } - lint_or_fun_call(cx, expr, &name.node.as_str(), &args); + + let self_ty = cx.tcx.expr_ty_adjusted(&args[0]); if args.len() == 1 && name.node.as_str() == "clone" { lint_clone_on_copy(cx, expr); - lint_clone_double_ref(cx, expr, &args[0]); + lint_clone_double_ref(cx, expr, &args[0], self_ty); } - for &(method, pos) in &PATTERN_METHODS { - if name.node.as_str() == method && args.len() > pos { - lint_single_char_pattern(cx, expr, &args[pos]); + + match self_ty.sty { + ty::TyRef(_, ty) if ty.ty.sty == ty::TyStr => { + for &(method, pos) in &PATTERN_METHODS { + if name.node.as_str() == method && args.len() > pos { + lint_single_char_pattern(cx, expr, &args[pos]); + } + } } + _ => (), } } ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { @@ -552,8 +559,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &Expr) { } /// Checks for the `CLONE_DOUBLE_REF` lint. -fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) { - let ty = cx.tcx.expr_ty(arg); +fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr, ty: ty::Ty) { if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { if let ty::TyRef(..) = inner.sty { let mut db = span_lint(cx, diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 1869fd12a69..7503cb50746 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::collections::HashMap; +use std::collections::HashSet; use std::ops::Mul; struct T; @@ -469,6 +470,9 @@ fn single_char_pattern() { //~^ ERROR single-character string constant used as pattern //~| HELP try using a char instead: //~| SUGGESTION x.trim_right_matches('x'); + + let h = HashSet::<String>::new(); + h.contains("X"); // should not warn } #[allow(result_unwrap_used)] -- cgit 1.4.1-3-g733a5 From 447940c889d92b9cfa436a8c7fb964b1e1e4803a Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Wed, 20 Apr 2016 13:10:23 -0700 Subject: Added lint for mem_forget --- src/lib.rs | 3 +++ src/mem_forget.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/utils/paths.rs | 1 + tests/compile-fail/mem_forget.rs | 21 +++++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 src/mem_forget.rs create mode 100644 tests/compile-fail/mem_forget.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 5774f3bf7af..07a142060cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ pub mod len_zero; pub mod lifetimes; pub mod loops; pub mod map_clone; +pub mod mem_forget; pub mod matches; pub mod methods; pub mod minmax; @@ -236,6 +237,7 @@ pub fn plugin_registrar(reg: &mut Registry) { 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_late_lint_pass(box mem_forget::MemForget); reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, @@ -243,6 +245,7 @@ pub fn plugin_registrar(reg: &mut Registry) { enum_glob_use::ENUM_GLOB_USE, if_not_else::IF_NOT_ELSE, matches::SINGLE_MATCH_ELSE, + mem_forget::MEM_FORGET, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, diff --git a/src/mem_forget.rs b/src/mem_forget.rs new file mode 100644 index 00000000000..836c60f84a9 --- /dev/null +++ b/src/mem_forget.rs @@ -0,0 +1,38 @@ +use rustc::lint::*; +use rustc::hir::{Expr, ExprCall, ExprPath}; +use utils::{match_def_path, paths, span_lint}; + +/// **What it does:** This lint checks for usage of `std::mem::forget(_)`. +/// +/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks +/// +/// **Known problems:** None. +/// +/// **Example:** `std::mem::forget(_))` +declare_lint! { + pub MEM_FORGET, + Allow, + "std::mem::forget usage is likely to cause memory leaks" +} + +pub struct MemForget; + +impl LintPass for MemForget { + fn get_lints(&self) -> LintArray { + lint_array![MEM_FORGET] + } +} + +impl LateLintPass for MemForget { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, _) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + + if match_def_path(cx, def_id, &paths::MEM_FORGET) { + span_lint(cx, MEM_FORGET, e.span, "usage of std::mem::forget"); + } + } + } + } +} diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 88d0dd415aa..38985373085 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -20,6 +20,7 @@ pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "Ha pub const HASH: [&'static str; 2] = ["hash", "Hash"]; pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; diff --git a/tests/compile-fail/mem_forget.rs b/tests/compile-fail/mem_forget.rs new file mode 100644 index 00000000000..1b9cc810f96 --- /dev/null +++ b/tests/compile-fail/mem_forget.rs @@ -0,0 +1,21 @@ +#![feature(plugin)] +#![plugin(clippy)] + +use std::sync::Arc; + +use std::mem::forget as forgetSomething; +use std::mem as memstuff; + +#[deny(mem_forget)] +fn main() { + let five: i32 = 5; + forgetSomething(five); + //~^ ERROR usage of std::mem::forget + + let six: Arc<i32> = Arc::new(6); + memstuff::forget(six); + //~^ ERROR usage of std::mem::forget + + std::mem::forget(7); + //~^ ERROR usage of std::mem::forget +} -- cgit 1.4.1-3-g733a5 From 7961f59303a0829f0724b236cad0cbb001930d9c Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Wed, 20 Apr 2016 13:11:55 -0700 Subject: Ran update_lints and updated CHANGELOG.md to reflect addition of mem_forget --- CHANGELOG.md | 3 ++- README.md | 3 ++- src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 272f5d77f35..0ad943c3f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. ## Unreleased -* New lint: [`temporary_cstring_as_ptr`] and [`unsafe_removed_from_name`] +* New lints: [`temporary_cstring_as_ptr`], [`unsafe_removed_from_name`], and [`mem_forget`] ## 0.0.63 — 2016-04-08 * Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)* @@ -135,6 +135,7 @@ All notable changes to this project will be documented in this file. [`match_overlapping_arm`]: https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm [`match_ref_pats`]: https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats [`match_same_arms`]: https://github.com/Manishearth/rust-clippy/wiki#match_same_arms +[`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget [`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max [`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one [`mut_mut`]: https://github.com/Manishearth/rust-clippy/wiki#mut_mut diff --git a/README.md b/README.md index 6aa1e1ecf34..7b7a74cca4c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 143 lints included in this crate: +There are 144 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -85,6 +85,7 @@ name [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead [match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies +[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | std::mem::forget usage is likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/lib.rs b/src/lib.rs index 07a142060cb..5f3b3999f95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,8 +78,8 @@ pub mod len_zero; pub mod lifetimes; pub mod loops; pub mod map_clone; -pub mod mem_forget; pub mod matches; +pub mod mem_forget; pub mod methods; pub mod minmax; pub mod misc; -- cgit 1.4.1-3-g733a5 From 12ae306630f5029d0c3c7b52fa7532f5a2f308da Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Wed, 20 Apr 2016 13:33:05 -0700 Subject: Ticks around std::mem::forget --- README.md | 2 +- src/mem_forget.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 7b7a74cca4c..8e8a2627557 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ name [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead [match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies -[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | std::mem::forget usage is likely to cause memory leaks +[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `std::mem::forget` usage is likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/mem_forget.rs b/src/mem_forget.rs index 836c60f84a9..651e56d709f 100644 --- a/src/mem_forget.rs +++ b/src/mem_forget.rs @@ -12,7 +12,7 @@ use utils::{match_def_path, paths, span_lint}; declare_lint! { pub MEM_FORGET, Allow, - "std::mem::forget usage is likely to cause memory leaks" + "`std::mem::forget` usage is likely to cause memory leaks" } pub struct MemForget; -- cgit 1.4.1-3-g733a5 From 5158a08c5b048a5e9ce094d4999db8cb6f13ab44 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Wed, 20 Apr 2016 18:55:41 -0700 Subject: Changed std::mem::forget errors to mem::forget --- README.md | 2 +- src/mem_forget.rs | 6 +++--- tests/compile-fail/mem_forget.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 8e8a2627557..0a4f83ffee6 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ name [match_overlapping_arm](https://github.com/Manishearth/rust-clippy/wiki#match_overlapping_arm) | warn | a match has overlapping arms [match_ref_pats](https://github.com/Manishearth/rust-clippy/wiki#match_ref_pats) | warn | a match or `if let` has all arms prefixed with `&`; the match expression can be dereferenced instead [match_same_arms](https://github.com/Manishearth/rust-clippy/wiki#match_same_arms) | warn | `match` with identical arm bodies -[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `std::mem::forget` usage is likely to cause memory leaks +[mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage is likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 [mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references) diff --git a/src/mem_forget.rs b/src/mem_forget.rs index 651e56d709f..d857adf10d6 100644 --- a/src/mem_forget.rs +++ b/src/mem_forget.rs @@ -8,11 +8,11 @@ use utils::{match_def_path, paths, span_lint}; /// /// **Known problems:** None. /// -/// **Example:** `std::mem::forget(_))` +/// **Example:** `mem::forget(_))` declare_lint! { pub MEM_FORGET, Allow, - "`std::mem::forget` usage is likely to cause memory leaks" + "`mem::forget` usage is likely to cause memory leaks" } pub struct MemForget; @@ -30,7 +30,7 @@ impl LateLintPass for MemForget { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); if match_def_path(cx, def_id, &paths::MEM_FORGET) { - span_lint(cx, MEM_FORGET, e.span, "usage of std::mem::forget"); + span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget"); } } } diff --git a/tests/compile-fail/mem_forget.rs b/tests/compile-fail/mem_forget.rs index 1b9cc810f96..5198b4ea8d3 100644 --- a/tests/compile-fail/mem_forget.rs +++ b/tests/compile-fail/mem_forget.rs @@ -10,12 +10,12 @@ use std::mem as memstuff; fn main() { let five: i32 = 5; forgetSomething(five); - //~^ ERROR usage of std::mem::forget + //~^ ERROR usage of mem::forget let six: Arc<i32> = Arc::new(6); memstuff::forget(six); - //~^ ERROR usage of std::mem::forget + //~^ ERROR usage of mem::forget std::mem::forget(7); - //~^ ERROR usage of std::mem::forget + //~^ ERROR usage of mem::forget } -- cgit 1.4.1-3-g733a5 From 77427b6ead79c54648c47f5048953590a59615bb Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Wed, 20 Apr 2016 19:24:31 -0700 Subject: Limited mem_forget error to only Drop types (fails) --- src/mem_forget.rs | 19 ++++++++++++------- tests/compile-fail/mem_forget.rs | 13 ++++++++++--- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mem_forget.rs b/src/mem_forget.rs index d857adf10d6..0568e70023a 100644 --- a/src/mem_forget.rs +++ b/src/mem_forget.rs @@ -1,18 +1,18 @@ use rustc::lint::*; use rustc::hir::{Expr, ExprCall, ExprPath}; -use utils::{match_def_path, paths, span_lint}; +use utils::{get_trait_def_id, implements_trait, match_def_path, paths, span_lint}; -/// **What it does:** This lint checks for usage of `std::mem::forget(_)`. +/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`. /// /// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks /// /// **Known problems:** None. /// -/// **Example:** `mem::forget(_))` +/// **Example:** `mem::forget(Rc::new(55)))` declare_lint! { pub MEM_FORGET, Allow, - "`mem::forget` usage is likely to cause memory leaks" + "`mem::forget` usage on `Drop` types is likely to cause memory leaks" } pub struct MemForget; @@ -25,12 +25,17 @@ impl LintPass for MemForget { impl LateLintPass for MemForget { fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprCall(ref path_expr, _) = e.node { + if let ExprCall(ref path_expr, ref args) = e.node { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if match_def_path(cx, def_id, &paths::MEM_FORGET) { - span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget"); + if let Some(drop_trait_id) = get_trait_def_id(cx, &paths::DROP) { + let forgot_ty = cx.tcx.expr_ty(&args[0]); + + if implements_trait(cx, forgot_ty, drop_trait_id, Vec::new()) { + span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); + } + } } } } diff --git a/tests/compile-fail/mem_forget.rs b/tests/compile-fail/mem_forget.rs index 5198b4ea8d3..c8cebcb2a42 100644 --- a/tests/compile-fail/mem_forget.rs +++ b/tests/compile-fail/mem_forget.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] use std::sync::Arc; +use std::rc::Rc; use std::mem::forget as forgetSomething; use std::mem as memstuff; @@ -10,12 +11,18 @@ use std::mem as memstuff; fn main() { let five: i32 = 5; forgetSomething(five); - //~^ ERROR usage of mem::forget let six: Arc<i32> = Arc::new(6); memstuff::forget(six); - //~^ ERROR usage of mem::forget + //~^ ERROR usage of mem::forget on Drop type + + let seven: Rc<i32> = Rc::new(7); + std::mem::forget(seven); + //~^ ERROR usage of mem::forget on Drop type + + let eight: Vec<i32> = vec![8]; + forgetSomething(eight); + //~^ ERROR usage of mem::forget on Drop type std::mem::forget(7); - //~^ ERROR usage of mem::forget } -- cgit 1.4.1-3-g733a5 From 8866ba9e2a744c5f033e7d1f5b0298da77550b91 Mon Sep 17 00:00:00 2001 From: Taylor Cramer <cramertj@cs.washington.edu> Date: Thu, 21 Apr 2016 09:36:39 -0700 Subject: Fixed destructor detection in mem_forget --- src/mem_forget.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mem_forget.rs b/src/mem_forget.rs index 0568e70023a..1f627d614ff 100644 --- a/src/mem_forget.rs +++ b/src/mem_forget.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::{Expr, ExprCall, ExprPath}; -use utils::{get_trait_def_id, implements_trait, match_def_path, paths, span_lint}; +use utils::{match_def_path, paths, span_lint}; /// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`. /// @@ -29,12 +29,13 @@ impl LateLintPass for MemForget { if let ExprPath(None, _) = path_expr.node { let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); if match_def_path(cx, def_id, &paths::MEM_FORGET) { - if let Some(drop_trait_id) = get_trait_def_id(cx, &paths::DROP) { - let forgot_ty = cx.tcx.expr_ty(&args[0]); + let forgot_ty = cx.tcx.expr_ty(&args[0]); - if implements_trait(cx, forgot_ty, drop_trait_id, Vec::new()) { - span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); - } + if match forgot_ty.ty_adt_def() { + Some(def) => def.has_dtor(), + _ => false + } { + span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); } } } -- cgit 1.4.1-3-g733a5 From e3d86800ffae3a88c1284d9bcfd45405f08e807a Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 23 Apr 2016 07:50:46 +0200 Subject: allow items_after_statements by default --- README.md | 2 +- src/items_after_statements.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 80d5c282556..59724457ac1 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ name [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations [invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an upcast which is always true or false -[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement +[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` [len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 952dcb7ed9c..9d8ae2e9913 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -28,7 +28,7 @@ use utils::in_macro; /// ``` declare_lint! { pub ITEMS_AFTER_STATEMENTS, - Warn, + Allow, "finds blocks where an item comes after a statement" } diff --git a/src/lib.rs b/src/lib.rs index 5f3b3999f95..14d1a19f262 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -244,6 +244,7 @@ pub fn plugin_registrar(reg: &mut Registry) { booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, if_not_else::IF_NOT_ELSE, + items_after_statements::ITEMS_AFTER_STATEMENTS, matches::SINGLE_MATCH_ELSE, mem_forget::MEM_FORGET, methods::OPTION_UNWRAP_USED, @@ -297,7 +298,6 @@ pub fn plugin_registrar(reg: &mut Registry) { formatting::SUSPICIOUS_ELSE_FORMATTING, functions::TOO_MANY_ARGUMENTS, identity_op::IDENTITY_OP, - items_after_statements::ITEMS_AFTER_STATEMENTS, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, lifetimes::NEEDLESS_LIFETIMES, -- cgit 1.4.1-3-g733a5 From bf4221c51a54294482e437c803a7b1f9c37dbcd8 Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Sat, 23 Apr 2016 14:30:05 +0200 Subject: cc: early returns are special --- src/cyclomatic_complexity.rs | 37 +++++++++++++------ tests/compile-fail/cyclomatic_complexity.rs | 57 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index e8a3a569a14..9b20cc4a312 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -9,7 +9,7 @@ use syntax::ast::Attribute; use syntax::attr; use syntax::codemap::Span; -use utils::{in_macro, LimitStack, span_help_and_lint}; +use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type}; /// **What it does:** This lint checks for methods with high cyclomatic complexity /// @@ -57,15 +57,26 @@ impl CyclomaticComplexity { match_arms: 0, divergence: 0, short_circuits: 0, + returns: 0, tcx: &cx.tcx, }; helper.visit_block(block); - let CCHelper { match_arms, divergence, short_circuits, .. } = helper; + let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; + let ret_ty = cx.tcx.node_id_to_type(block.id); + let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) { + returns + } else { + returns / 2 + }; - if cc + divergence < match_arms + short_circuits { - report_cc_bug(cx, cc, match_arms, divergence, short_circuits, span); + if cc + divergence < match_arms + short_circuits { + report_cc_bug(cx, cc, match_arms, divergence, short_circuits, ret_adjust, span); } else { - let rust_cc = cc + divergence - match_arms - short_circuits; + let mut rust_cc = cc + divergence - match_arms - short_circuits; + // prevent degenerate cases where unreachable code contains `return` statements + if rust_cc >= ret_adjust { + rust_cc -= ret_adjust; + } if rust_cc > self.limit.limit() { span_help_and_lint(cx, CYCLOMATIC_COMPLEXITY, @@ -109,6 +120,7 @@ impl LateLintPass for CyclomaticComplexity { struct CCHelper<'a, 'tcx: 'a> { match_arms: u64, divergence: u64, + returns: u64, short_circuits: u64, // && and || tcx: &'a ty::TyCtxt<'tcx>, } @@ -142,31 +154,34 @@ impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { _ => (), } } + ExprRet(_) => self.returns += 1, _ => walk_expr(self, e), } } } #[cfg(feature="debugging")] -fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { +fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { span_bug!(span, "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ - div = {}, shorts = {}. Please file a bug report.", + div = {}, shorts = {}, returns = {}. Please file a bug report.", cc, narms, div, - shorts); + shorts, + returns); } #[cfg(not(feature="debugging"))] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, span: Span) { +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { cx.sess().span_note_without_error(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ - = {}, arms = {}, div = {}, shorts = {}. Please file a bug report.", + = {}, arms = {}, div = {}, shorts = {}, returns = {}. Please file a bug report.", cc, narms, div, - shorts)); + shorts, + returns)); } } diff --git a/tests/compile-fail/cyclomatic_complexity.rs b/tests/compile-fail/cyclomatic_complexity.rs index 4b24f16eda7..2160272bf46 100644 --- a/tests/compile-fail/cyclomatic_complexity.rs +++ b/tests/compile-fail/cyclomatic_complexity.rs @@ -315,3 +315,60 @@ fn mcarton_sees_all() { panic!("meh"); panic!("möh"); } + +#[cyclomatic_complexity = "0"] +fn try() -> Result<i32, &'static str> { //~ ERROR: cyclomatic complexity of 1 + match 5 { + 5 => Ok(5), + _ => return Err("bla"), + } +} + +#[cyclomatic_complexity = "0"] +fn try_again() -> Result<i32, &'static str> { //~ ERROR: cyclomatic complexity of 1 + let _ = try!(Ok(42)); + let _ = try!(Ok(43)); + let _ = try!(Ok(44)); + let _ = try!(Ok(45)); + let _ = try!(Ok(46)); + let _ = try!(Ok(47)); + let _ = try!(Ok(48)); + let _ = try!(Ok(49)); + match 5 { + 5 => Ok(5), + _ => return Err("bla"), + } +} + +#[cyclomatic_complexity = "0"] +fn early() -> Result<i32, &'static str> { //~ ERROR: cyclomatic complexity of 1 + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); + return Ok(5); +} + +#[cyclomatic_complexity = "0"] +fn early_ret() -> i32 { //~ ERROR: cyclomatic complexity of 8 + let a = if true { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + let a = if a < 99 { 42 } else { return 0; }; + match 5 { + 5 => 5, + _ => return 6, + } +} -- cgit 1.4.1-3-g733a5 From c3d75ad80d949be1cdb7c5a6c20d9134df677070 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 24 Apr 2016 17:15:54 +0530 Subject: Improve new_without_default docs --- src/new_without_default.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/new_without_default.rs b/src/new_without_default.rs index f42b1d0d74a..46021ec8836 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -6,10 +6,13 @@ use syntax::codemap::Span; use utils::paths; use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint}; -/// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default` -/// implementation. +/// **What it does:** This lints about type with a `fn new() -> Self` method +/// and no implementation of +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) /// -/// **Why is this bad?** User might expect to be able to use `Default` as the type can be +/// **Why is this bad?** User might expect to be able to use +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// as the type can be /// constructed without arguments. /// /// **Known problems:** Hopefully none. @@ -25,6 +28,21 @@ use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, sa /// } /// } /// ``` +/// +/// Instead, use: +/// +/// ```rust +/// struct Foo; +/// +/// impl Default for Foo { +/// fn default() -> Self { +/// Foo +/// } +/// } +/// ``` +/// +/// You can also have `new()` call `Default::default()` +/// declare_lint! { pub NEW_WITHOUT_DEFAULT, Warn, -- cgit 1.4.1-3-g733a5 From 08818de9b7f0a51bf71fc863ae7798be9e19b1c5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 26 Apr 2016 02:01:49 +0530 Subject: Rustup to rustc 1.10.0-nightly (645dd013a 2016-04-24); release 0.0.64 --- Cargo.toml | 2 +- src/block_in_if_condition.rs | 2 +- src/eta_reduction.rs | 2 +- src/map_clone.rs | 2 +- src/misc_early.rs | 4 ++-- src/utils/hir.rs | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index b55ab8d2271..5a8968ac2f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.63" +version = "0.0.64" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index 1a2123fe00a..cdaf53684c5 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -43,7 +43,7 @@ struct ExVisitor<'v> { impl<'v> Visitor<'v> for ExVisitor<'v> { fn visit_expr(&mut self, expr: &'v Expr) { - if let ExprClosure(_, _, ref block) = expr.node { + if let ExprClosure(_, _, ref block, _) = expr.node { let complex = { if block.stmts.is_empty() { if let Some(ref ex) = block.expr { diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index 83abe215aa7..c9a9ef85ede 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -40,7 +40,7 @@ impl LateLintPass for EtaPass { } fn check_closure(cx: &LateContext, expr: &Expr) { - if let ExprClosure(_, ref decl, ref blk) = expr.node { + if let ExprClosure(_, ref decl, ref blk, _) = expr.node { if !blk.stmts.is_empty() { // || {foo(); bar()}; can't be reduced here return; diff --git a/src/map_clone.rs b/src/map_clone.rs index caefb64eb5f..1cfa339d4a0 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -25,7 +25,7 @@ impl LateLintPass for MapClonePass { 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 blk) => { + ExprClosure(_, ref decl, ref blk, _) => { if_let_chain! { [ // just one expression in the closure diff --git a/src/misc_early.rs b/src/misc_early.rs index b43359f29b9..a7ab59497ac 100644 --- a/src/misc_early.rs +++ b/src/misc_early.rs @@ -128,7 +128,7 @@ impl EarlyLintPass for MiscEarly { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { if let ExprKind::Call(ref paren, _) = expr.node { if let ExprKind::Paren(ref closure) = paren.node { - if let ExprKind::Closure(_, ref decl, ref block) = closure.node { + if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node { span_lint_and_then(cx, REDUNDANT_CLOSURE_CALL, expr.span, @@ -150,7 +150,7 @@ impl EarlyLintPass for MiscEarly { let StmtKind::Decl(ref first, _) = w[0].node, let DeclKind::Local(ref local) = first.node, let Option::Some(ref t) = local.init, - let ExprKind::Closure(_,_,_) = t.node, + let ExprKind::Closure(_,_,_,_) = t.node, let PatKind::Ident(_,sp_ident,_) = local.pat.node, let StmtKind::Semi(ref second,_) = w[1].node, let ExprKind::Assign(_,ref call) = second.node, diff --git a/src/utils/hir.rs b/src/utils/hir.rs index 379812a283d..fe4c6d30952 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -333,8 +333,8 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { self.hash_expr(e); // TODO: _ty } - ExprClosure(cap, _, ref b) => { - let c: fn(_, _, _) -> _ = ExprClosure; + ExprClosure(cap, _, ref b, _) => { + let c: fn(_, _, _, _) -> _ = ExprClosure; c.hash(&mut self.s); cap.hash(&mut self.s); self.hash_block(b); -- cgit 1.4.1-3-g733a5 From cf5c1ab0b6ce335525ed5a71af1b8b7df637abe0 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 26 Apr 2016 13:31:52 +0200 Subject: Fix paths resolution Put more paths into the `utils::paths` module. --- src/loops.rs | 14 ++++++------- src/map_clone.rs | 2 +- src/methods.rs | 4 ++-- src/minmax.rs | 6 +++--- src/ranges.rs | 13 +++++++----- src/utils/mod.rs | 49 ++++++++++++++++++++++++++++----------------- src/utils/paths.rs | 37 ++++++++++++++++++++++++---------- tests/compile-fail/range.rs | 2 ++ 8 files changed, 80 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/loops.rs b/src/loops.rs index 0b341f645df..70abb7a1aac 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -285,7 +285,7 @@ impl LateLintPass for LoopsPass { 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, &["core", "iter", "Iterator"]) && + match_trait_method(cx, match_expr, &paths::ITERATOR) && lhs_constructor.identifier.name.as_str() == "Some" && !is_iterator_used_after_while_let(cx, iter_expr) { let iterator = snippet(cx, method_args[0].span, "_"); @@ -305,7 +305,7 @@ impl LateLintPass for LoopsPass { 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" && - match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + match_trait_method(cx, expr, &paths::ITERATOR) { span_lint(cx, UNUSED_COLLECT, expr.span, @@ -488,7 +488,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { object, method_name)); } - } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &["core", "iter", "Iterator"]) { + } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { span_lint(cx, ITER_NEXT_LOOP, expr.span, @@ -739,11 +739,11 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { match_type(cx, ty, &paths::VEC) || match_type(cx, ty, &paths::LINKED_LIST) || match_type(cx, ty, &paths::HASHMAP) || - match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) || - match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) || - match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) || + match_type(cx, ty, &paths::HASHSET) || + match_type(cx, ty, &paths::VEC_DEQUE) || + match_type(cx, ty, &paths::BINARY_HEAP) || match_type(cx, ty, &paths::BTREEMAP) || - match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"]) + match_type(cx, ty, &paths::BTREESET) } fn is_iterable_array(ty: ty::Ty) -> bool { diff --git a/src/map_clone.rs b/src/map_clone.rs index 1cfa339d4a0..1a0620d8834 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -96,7 +96,7 @@ fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { } fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { - if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) { + if match_trait_method(cx, expr, &paths::ITERATOR) { Some("iterator") } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &paths::OPTION) { Some("Option") diff --git a/src/methods.rs b/src/methods.rs index 73f6a7aa4b0..e25154bd38b 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -752,7 +752,7 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, /// lint use of `filter().next() for Iterators` fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { // lint if caller of `.filter().next()` is an Iterator - if match_trait_method(cx, expr, &["core", "iter", "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 filter_snippet = snippet(cx, filter_args[1].span, ".."); @@ -776,7 +776,7 @@ fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, search_args: &MethodArgs, is_some_args: &MethodArgs) { // lint if caller of search is an Iterator - if match_trait_method(cx, &*is_some_args[0], &["core", "iter", "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()`.", search_method); diff --git a/src/minmax.rs b/src/minmax.rs index 7cd2d33cab9..eaba19b08e4 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc::hir::*; use std::cmp::{PartialOrd, Ordering}; use syntax::ptr::P; -use utils::{match_def_path, span_lint}; +use utils::{match_def_path, paths, span_lint}; /// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. /// @@ -57,9 +57,9 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &' if let ExprPath(None, _) = path.node { let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); - if match_def_path(cx, def_id, &["core", "cmp", "min"]) { + if match_def_path(cx, def_id, &paths::CMP_MIN) { fetch_const(args, MinMax::Min) - } else if match_def_path(cx, def_id, &["core", "cmp", "max"]) { + } else if match_def_path(cx, def_id, &paths::CMP_MAX) { fetch_const(args, MinMax::Max) } else { None diff --git a/src/ranges.rs b/src/ranges.rs index c2555da1d0b..e96212a9cef 100644 --- a/src/ranges.rs +++ b/src/ranges.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::hir::*; use syntax::codemap::Spanned; -use utils::{is_integer_literal, match_type, snippet, span_lint, unsugar_range, UnsugaredRange}; +use utils::{is_integer_literal, match_type, paths, snippet, span_lint, unsugar_range, UnsugaredRange}; /// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. /// @@ -39,7 +39,7 @@ impl LateLintPass for StepByZero { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { // Range with step_by(0). - if name.as_str() == "step_by" && args.len() == 2 && is_range(cx, &args[0]) && + if name.as_str() == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && is_integer_literal(&args[1], 0) { span_lint(cx, RANGE_STEP_BY_ZERO, @@ -77,10 +77,13 @@ impl LateLintPass for StepByZero { } } -fn is_range(cx: &LateContext, expr: &Expr) -> bool { +fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { // No need for walk_ptrs_ty here because step_by moves self, so it // can't be called on a borrowed range. let ty = cx.tcx.expr_ty(expr); - // Note: RangeTo and RangeFull don't have step_by - match_type(cx, ty, &["core", "ops", "Range"]) || match_type(cx, ty, &["core", "ops", "RangeFrom"]) + + // 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) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d8f5a0757b7..83247a59174 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -122,23 +122,33 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { /// ``` /// match_def_path(cx, id, &["core", "option", "Option"]) /// ``` +/// +/// See also the `paths` module. pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - let krate = &cx.tcx.crate_name(def_id.krate); - if krate != &path[0] { - return false; + use syntax::parse::token; + + struct AbsolutePathBuffer { + names: Vec<token::InternedString>, } - let path = &path[1..]; - let other = cx.tcx.def_path(def_id).data; + impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { + fn root_mode(&self) -> &ty::item_path::RootMode { + const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute; + ABSOLUTE + } - if other.len() != path.len() { - return false; + fn push(&mut self, text: &str) { + self.names.push(token::intern(text).as_str()); + } } - other.into_iter() - .map(|e| e.data) - .zip(path) - .all(|(nm, p)| nm.as_interned_str() == *p) + let mut apb = AbsolutePathBuffer { + names: vec![], + }; + + cx.tcx.push_item_path(&mut apb, def_id); + + apb.names == path } /// Check if type is struct or enum type with given def path. @@ -730,9 +740,12 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { Some(unwrap_unstable(expr)) } - match unwrap_unstable(&expr).node { + // 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 { ExprPath(None, ref path) => { - if match_path(path, &paths::RANGE_FULL) { + if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) { Some(UnsugaredRange { start: None, end: None, @@ -743,31 +756,31 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { } } ExprStruct(ref path, ref fields, None) => { - if match_path(path, &paths::RANGE_FROM) { + if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) { Some(UnsugaredRange { start: get_field("start", fields), end: None, limits: RangeLimits::HalfOpen, }) - } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { + } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::Closed, }) - } else if match_path(path, &paths::RANGE) { + } else if match_path(path, &paths::RANGE_STD) || match_path(path, &paths::RANGE) { Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), limits: RangeLimits::HalfOpen, }) - } else if match_path(path, &paths::RANGE_TO_INCLUSIVE) { + } else if match_path(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_path(path, &paths::RANGE_TO_INCLUSIVE) { Some(UnsugaredRange { start: None, end: get_field("end", fields), limits: RangeLimits::Closed, }) - } else if match_path(path, &paths::RANGE_TO) { + } else if match_path(path, &paths::RANGE_TO_STD) || match_path(path, &paths::RANGE_TO) { Some(UnsugaredRange { start: None, end: get_field("end", fields), diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 38985373085..7da75c3cd55 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -1,12 +1,16 @@ //! This module contains paths to types and functions Clippy needs to know about. pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; -pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; +pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"]; pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"]; -pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; +pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; +pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; +pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"]; pub const CLONE: [&'static str; 3] = ["clone", "Clone", "clone"]; pub const CLONE_TRAIT: [&'static str; 2] = ["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 DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; @@ -15,25 +19,36 @@ pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; -pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; -pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASH: [&'static str; 2] = ["hash", "Hash"]; +pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; +pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"]; pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; +pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"]; pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; -pub const RANGE_FROM: [&'static str; 3] = ["std", "ops", "RangeFrom"]; -pub const RANGE_FULL: [&'static str; 3] = ["std", "ops", "RangeFull"]; -pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; -pub const RANGE: [&'static str; 3] = ["std", "ops", "Range"]; -pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; -pub const RANGE_TO: [&'static str; 3] = ["std", "ops", "RangeTo"]; +pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"]; +pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"]; +pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"]; +pub const RANGE_FULL: [&'static str; 3] = ["core", "ops", "RangeFull"]; +pub const RANGE_FULL_STD: [&'static str; 3] = ["std", "ops", "RangeFull"]; +pub const RANGE_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeInclusive"]; +pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["core", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE_INCLUSIVE_NON_EMPTY_STD: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeInclusive"]; +pub const RANGE_STD: [&'static str; 3] = ["std", "ops", "Range"]; +pub const RANGE_TO: [&'static str; 3] = ["core", "ops", "RangeTo"]; +pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclusive"]; +pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; +pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; pub const REGEX_NEW: [&'static str; 3] = ["regex", "Regex", "new"]; pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING: [&'static str; 3] = ["collections", "string", "String"]; pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; -pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"]; pub const VEC: [&'static str; 3] = ["collections", "vec", "Vec"]; +pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"]; +pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"]; diff --git a/tests/compile-fail/range.rs b/tests/compile-fail/range.rs index 064d9f55173..fc12155ce9c 100644 --- a/tests/compile-fail/range.rs +++ b/tests/compile-fail/range.rs @@ -1,4 +1,5 @@ #![feature(step_by)] +#![feature(inclusive_range_syntax)] #![feature(plugin)] #![plugin(clippy)] @@ -14,6 +15,7 @@ fn main() { (0..1).step_by(1); (1..).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator + (1...2).step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator let x = 0..1; x.step_by(0); //~ERROR Range::step_by(0) produces an infinite iterator -- cgit 1.4.1-3-g733a5 From 0664394a4901d0af7717ebf6abd99330ce301ab9 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 26 Apr 2016 13:43:23 +0200 Subject: Centralize more paths --- src/map_clone.rs | 2 +- src/utils/paths.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/map_clone.rs b/src/map_clone.rs index 1a0620d8834..d015a165457 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -51,7 +51,7 @@ impl LateLintPass for MapClonePass { else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { if clone_call.node.as_str() == "clone" && clone_args.len() == 1 && - match_trait_method(cx, closure_expr, &["core", "clone", "Clone"]) && + match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) && expr_eq_ident(&clone_args[0], arg_ident) { span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 7da75c3cd55..c52324a7448 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -7,8 +7,8 @@ pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"]; -pub const CLONE: [&'static str; 3] = ["clone", "Clone", "clone"]; -pub const CLONE_TRAIT: [&'static str; 2] = ["clone", "Clone"]; +pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"]; +pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"]; pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&'static str; 3] = ["core", "cmp", "min"]; pub const COW: [&'static str; 3] = ["collections", "borrow", "Cow"]; -- cgit 1.4.1-3-g733a5 From 9a99979cc4653fc54008590314028da36b7f21f0 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 30 Apr 2016 04:01:47 +0200 Subject: fix #887: New lints for integer/floating-point arithmetic --- CHANGELOG.md | 2 + README.md | 4 +- src/arithmetic.rs | 104 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 ++ tests/compile-fail/arithmetic.rs | 31 ++++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/arithmetic.rs create mode 100644 tests/compile-fail/arithmetic.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 37cdcc571a0..6c51e5595a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,6 +107,7 @@ All notable changes to this project will be documented in this file. [`explicit_iter_loop`]: https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop [`extend_from_slice`]: https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice [`filter_next`]: https://github.com/Manishearth/rust-clippy/wiki#filter_next +[`float_arithmetic`]: https://github.com/Manishearth/rust-clippy/wiki#float_arithmetic [`float_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#float_cmp [`for_kv_map`]: https://github.com/Manishearth/rust-clippy/wiki#for_kv_map [`for_loop_over_option`]: https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option @@ -118,6 +119,7 @@ All notable changes to this project will be documented in this file. [`indexing_slicing`]: https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing [`ineffective_bit_mask`]: https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask [`inline_always`]: https://github.com/Manishearth/rust-clippy/wiki#inline_always +[`integer_arithmetic`]: https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic [`invalid_regex`]: https://github.com/Manishearth/rust-clippy/wiki#invalid_regex [`invalid_upcast_comparisons`]: https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons [`items_after_statements`]: https://github.com/Manishearth/rust-clippy/wiki#items_after_statements diff --git a/README.md b/README.md index 59724457ac1..3b0ca3f4a38 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Table of contents: * [License](#license) ##Lints -There are 144 lints included in this crate: +There are 146 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -56,6 +56,7 @@ name [explicit_iter_loop](https://github.com/Manishearth/rust-clippy/wiki#explicit_iter_loop) | warn | for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do [extend_from_slice](https://github.com/Manishearth/rust-clippy/wiki#extend_from_slice) | warn | `.extend_from_slice(_)` is a faster way to extend a Vec by a slice [filter_next](https://github.com/Manishearth/rust-clippy/wiki#filter_next) | warn | using `filter(p).next()`, which is more succinctly expressed as `.find(p)` +[float_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#float_arithmetic) | allow | Any floating-point arithmetic statement [float_cmp](https://github.com/Manishearth/rust-clippy/wiki#float_cmp) | warn | using `==` or `!=` on float values (as floating-point operations usually involve rounding errors, it is always better to check for approximate equality within small bounds) [for_kv_map](https://github.com/Manishearth/rust-clippy/wiki#for_kv_map) | warn | looping on a map using `iter` when `keys` or `values` would do [for_loop_over_option](https://github.com/Manishearth/rust-clippy/wiki#for_loop_over_option) | warn | for-looping over an `Option`, which is more clearly expressed as an `if let` @@ -67,6 +68,7 @@ name [indexing_slicing](https://github.com/Manishearth/rust-clippy/wiki#indexing_slicing) | allow | indexing/slicing usage [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases +[integer_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic) | allow | Any integer arithmetic statement [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations [invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an upcast which is always true or false [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | finds blocks where an item comes after a statement diff --git a/src/arithmetic.rs b/src/arithmetic.rs new file mode 100644 index 00000000000..72375f4a15e --- /dev/null +++ b/src/arithmetic.rs @@ -0,0 +1,104 @@ +use rustc::hir; +use rustc::lint::*; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** This lint checks for plain integer arithmetic +/// +/// **Why is this bad?** This is only checked against overflow in debug builds. +/// In some applications one wants explicitly checked, wrapping or saturating +/// arithmetic. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// a + 1 +/// ``` +declare_lint! { + pub INTEGER_ARITHMETIC, + Allow, + "Any integer arithmetic statement" +} + +/// **What it does:** This lint checks for float arithmetic +/// +/// **Why is this bad?** For some embedded systems or kernel development, it +/// can be useful to rule out floating-point numbers +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// a + 1.0 +/// ``` +declare_lint! { + pub FLOAT_ARITHMETIC, + Allow, + "Any floating-point arithmetic statement" +} + +#[derive(Copy, Clone, Default)] +pub struct Arithmetic { + span: Option<Span> +} + +impl LintPass for Arithmetic { + fn get_lints(&self) -> LintArray { + lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC) + } +} + +impl LateLintPass for Arithmetic { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + if let Some(_) = self.span { return; } + match expr.node { + hir::ExprBinary(ref op, ref l, ref r) => { + match op.node { + hir::BiRem | hir::BiAnd | hir::BiOr | hir::BiBitAnd | + hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | + hir::BiGt => return, + _ => () + } + let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r)); + if l_ty.is_integral() && r_ty.is_integral() { + span_lint(cx, + INTEGER_ARITHMETIC, + expr.span, + "integer arithmetic detected"); + self.span = Some(expr.span); + } else if l_ty.is_floating_point() && r_ty.is_floating_point() { + 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.expr_ty(arg); + if ty.is_integral() { + span_lint(cx, + INTEGER_ARITHMETIC, + expr.span, + "integer arithmetic detected"); + self.span = Some(expr.span); + } else if ty.is_floating_point() { + 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) { + if Some(expr.span) == self.span { + self.span = None; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 14d1a19f262..584ae7f77eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(question_mark)] #![feature(stmt_expr_attributes)] #![allow(indexing_slicing, shadow_reuse, unknown_lints)] +#![allow(float_arithmetic, integer_arithmetic)] // this only exists to allow the "dogfood" integration test to work #[allow(dead_code)] @@ -49,6 +50,7 @@ pub mod utils; // begin lints modules, do not remove this comment, it’s used in `update_lints` pub mod approx_const; +pub mod arithmetic; pub mod array_indexing; pub mod attrs; pub mod bit_mask; @@ -238,8 +240,11 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box neg_multiply::NegMultiply); reg.register_late_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_lint_group("clippy_pedantic", vec![ + arithmetic::FLOAT_ARITHMETIC, + arithmetic::INTEGER_ARITHMETIC, array_indexing::INDEXING_SLICING, booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, diff --git a/tests/compile-fail/arithmetic.rs b/tests/compile-fail/arithmetic.rs new file mode 100644 index 00000000000..856f390943b --- /dev/null +++ b/tests/compile-fail/arithmetic.rs @@ -0,0 +1,31 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(integer_arithmetic, float_arithmetic)] +#![allow(unused, shadow_reuse, shadow_unrelated, no_effect)] +fn main() { + let i = 1i32; + 1 + i; //~ERROR integer arithmetic detected + i * 2; //~ERROR integer arithmetic detected + 1 % //~ERROR integer arithmetic detected + i / 2; + i - 2 + 2 - i; //~ERROR integer arithmetic detected + -i; //~ERROR integer arithmetic detected + + i & 1; // no wrapping + i | 1; + i ^ 1; + i % 7; + i >> 1; + i << 1; + + let f = 1.0f32; + + f * 2.0; //~ERROR floating-point arithmetic detected + + 1.0 + f; //~ERROR floating-point arithmetic detected + f * 2.0; //~ERROR floating-point arithmetic detected + f / 2.0; //~ERROR floating-point arithmetic detected + f - 2.0 * 4.2; //~ERROR floating-point arithmetic detected + -f; //~ERROR floating-point arithmetic detected +} -- cgit 1.4.1-3-g733a5 From a96744018670a29b926ee084779a1333c2542915 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 30 Apr 2016 17:11:59 +0200 Subject: lint remainder, document test w/ half expr --- src/arithmetic.rs | 2 +- tests/compile-fail/arithmetic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 72375f4a15e..6f34fdc2427 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -55,7 +55,7 @@ impl LateLintPass for Arithmetic { match expr.node { hir::ExprBinary(ref op, ref l, ref r) => { match op.node { - hir::BiRem | hir::BiAnd | hir::BiOr | hir::BiBitAnd | + hir::BiAnd | hir::BiOr | hir::BiBitAnd | hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => return, diff --git a/tests/compile-fail/arithmetic.rs b/tests/compile-fail/arithmetic.rs index 856f390943b..3b9e1b8b85a 100644 --- a/tests/compile-fail/arithmetic.rs +++ b/tests/compile-fail/arithmetic.rs @@ -8,7 +8,7 @@ fn main() { 1 + i; //~ERROR integer arithmetic detected i * 2; //~ERROR integer arithmetic detected 1 % //~ERROR integer arithmetic detected - i / 2; + i / 2; // no error, this is part of the expression in the preceding line i - 2 + 2 - i; //~ERROR integer arithmetic detected -i; //~ERROR integer arithmetic detected -- cgit 1.4.1-3-g733a5 From 0b40ae178a4e3dfa8ec5312562cf473adea3989e Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 30 Apr 2016 23:54:10 +0200 Subject: fixed tests, added clippy_restrictions lint group --- src/arithmetic.rs | 26 ++++++++++++-------------- src/lib.rs | 11 ++++++++++- tests/compile-fail/arithmetic.rs | 1 - util/update_lints.py | 39 +++++++++++++++++++++++++++++++-------- 4 files changed, 53 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 6f34fdc2427..be732740442 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -15,9 +15,8 @@ use utils::span_lint; /// ``` /// a + 1 /// ``` -declare_lint! { +declare_restriction_lint! { pub INTEGER_ARITHMETIC, - Allow, "Any integer arithmetic statement" } @@ -32,9 +31,8 @@ declare_lint! { /// ``` /// a + 1.0 /// ``` -declare_lint! { +declare_restriction_lint! { pub FLOAT_ARITHMETIC, - Allow, "Any floating-point arithmetic statement" } @@ -55,32 +53,32 @@ impl LateLintPass for Arithmetic { match expr.node { hir::ExprBinary(ref op, ref l, ref r) => { match op.node { - hir::BiAnd | hir::BiOr | hir::BiBitAnd | - hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | + hir::BiAnd | hir::BiOr | hir::BiBitAnd | + hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => return, _ => () } let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r)); if l_ty.is_integral() && r_ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, + span_lint(cx, + INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.span = Some(expr.span); + self.span = Some(expr.span); } else if l_ty.is_floating_point() && r_ty.is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.span = Some(expr.span); + self.span = Some(expr.span); } }, hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { let ty = cx.tcx.expr_ty(arg); if ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, + span_lint(cx, + INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.span = Some(expr.span); @@ -95,7 +93,7 @@ impl LateLintPass for Arithmetic { _ => () } } - + fn check_expr_post(&mut self, _: &LateContext, expr: &hir::Expr) { if Some(expr.span) == self.span { self.span = None; diff --git a/src/lib.rs b/src/lib.rs index 584ae7f77eb..e22d85a43e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,12 @@ extern crate rustc_const_eval; extern crate rustc_const_math; use rustc_plugin::Registry; +macro_rules! declare_restriction_lint { + { pub $name:tt, $description:tt } => { + declare_lint! { pub $name, Allow, $description } + }; +} + pub mod consts; #[macro_use] pub mod utils; @@ -242,9 +248,12 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box mem_forget::MemForget); reg.register_late_lint_pass(box arithmetic::Arithmetic::default()); - reg.register_lint_group("clippy_pedantic", vec![ + reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, arithmetic::INTEGER_ARITHMETIC, + ]); + + reg.register_lint_group("clippy_pedantic", vec![ array_indexing::INDEXING_SLICING, booleans::NONMINIMAL_BOOL, enum_glob_use::ENUM_GLOB_USE, diff --git a/tests/compile-fail/arithmetic.rs b/tests/compile-fail/arithmetic.rs index 3b9e1b8b85a..54ac65970ae 100644 --- a/tests/compile-fail/arithmetic.rs +++ b/tests/compile-fail/arithmetic.rs @@ -15,7 +15,6 @@ fn main() { i & 1; // no wrapping i | 1; i ^ 1; - i % 7; i >> 1; i << 1; diff --git a/util/update_lints.py b/util/update_lints.py index bf9728d4f58..bfed0430abb 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -21,12 +21,18 @@ declare_deprecated_lint_re = re.compile(r''' " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] ''', re.VERBOSE | re.DOTALL) +declare_restriction_lint_re = re.compile(r''' + declare_restriction_lint! \s* [{(] \s* + pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s* + " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})] +''', re.VERBOSE | re.DOTALL) + nl_escape_re = re.compile(r'\\\n\s*') wiki_link = 'https://github.com/Manishearth/rust-clippy/wiki' -def collect(lints, deprecated_lints, fn): +def collect(lints, deprecated_lints, restriction_lints, fn): """Collect all lints from a file. Adds entries to the lints list as `(module, name, level, desc)`. @@ -48,6 +54,14 @@ def collect(lints, deprecated_lints, fn): match.group('name').lower(), desc.replace('\\"', '"'))) + for match in declare_restriction_lint_re.finditer(code): + # remove \-newline escapes from description string + desc = nl_escape_re.sub('', match.group('desc')) + restriction_lints.append((os.path.splitext(os.path.basename(fn))[0], + match.group('name').lower(), + "allow", + desc.replace('\\"', '"'))) + def gen_table(lints, link=None): """Write lint table in Markdown format.""" @@ -86,7 +100,6 @@ def gen_deprecated(lints): for lint in lints: yield ' store.register_removed("%s", "%s");\n' % (lint[1], lint[2]) - def replace_region(fn, region_start, region_end, callback, replace_start=True, write_back=True): """Replace a region in a file delimited by two lines matching regexes. @@ -128,6 +141,7 @@ def replace_region(fn, region_start, region_end, callback, def main(print_only=False, check=False): lints = [] deprecated_lints = [] + restriction_lints = [] # check directory if not os.path.isfile('src/lib.rs'): @@ -138,22 +152,24 @@ def main(print_only=False, check=False): for root, _, files in os.walk('src'): for fn in files: if fn.endswith('.rs'): - collect(lints, deprecated_lints, os.path.join(root, fn)) + collect(lints, deprecated_lints, restriction_lints, + os.path.join(root, fn)) if print_only: - sys.stdout.writelines(gen_table(lints)) + sys.stdout.writelines(gen_table(lints + restriction_lints)) return # replace table in README.md changed = replace_region( 'README.md', r'^name +\|', '^$', - lambda: gen_table(lints, link=wiki_link), + lambda: gen_table(lints + restriction_lints, link=wiki_link), write_back=not check) changed |= replace_region( 'README.md', r'^There are \d+ lints included in this crate:', "", - lambda: ['There are %d lints included in this crate:\n' % len(lints)], + lambda: ['There are %d lints included in this crate:\n' % (len(lints) + + len(restriction_lints))], write_back=not check) # update the links in the CHANGELOG @@ -162,13 +178,14 @@ def main(print_only=False, check=False): "<!-- begin autogenerated links to wiki -->", "<!-- end autogenerated links to wiki -->", lambda: ["[`{0}`]: {1}#{0}\n".format(l[1], wiki_link) for l in - sorted(lints + deprecated_lints, key=lambda l: l[1])], + sorted(lints + restriction_lints + deprecated_lints, + key=lambda l: l[1])], replace_start=False, write_back=not check) # update the `pub mod` list changed |= replace_region( 'src/lib.rs', r'begin lints modules', r'end lints modules', - lambda: gen_mods(lints), + lambda: gen_mods(lints + restriction_lints), replace_start=False, write_back=not check) # same for "clippy" lint collection @@ -190,6 +207,12 @@ def main(print_only=False, check=False): lambda: gen_group(lints, levels=('allow',)), replace_start=False, write_back=not check) + # same for "clippy_restrictions" lint collection + changed |= replace_region( + 'src/lib.rs', r'reg.register_lint_group\("clippy_restrictions"', + r'\]\);', lambda: gen_group(restriction_lints), + replace_start=False, write_back=not check) + if check and changed: print('Please run util/update_lints.py to regenerate lints lists.') return 1 -- cgit 1.4.1-3-g733a5 From 10f468e679c0e6a6c6dc0e94431f3d63bf3e33e0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 2 May 2016 10:52:55 +0200 Subject: don't lint similar_names inside #[test] functions --- src/non_expressive_names.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index a6f0571c499..c1232fe64b1 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -2,7 +2,8 @@ use rustc::lint::*; use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ast::*; -use syntax::visit::{self, FnKind}; +use syntax::attr; +use syntax::visit; use utils::{span_lint_and_then, in_macro, span_lint}; /// **What it does:** This lint warns about names that are very similar and thus confusing @@ -237,24 +238,28 @@ impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { }); } fn visit_item(&mut self, _: &'v Item) { - // do nothing + // do not recurse into inner items } } impl EarlyLintPass for NonExpressiveNames { - fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, blk: &Block, _: Span, _: NodeId) { - let mut visitor = SimilarNamesLocalVisitor { - names: Vec::new(), - cx: cx, - lint: &self, - single_char_names: Vec::new(), - }; - // initialize with function arguments - for arg in &decl.inputs { - visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat); + fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node { + if !attr::contains_name(&item.attrs, "test") { + let mut visitor = SimilarNamesLocalVisitor { + names: Vec::new(), + cx: cx, + lint: &self, + single_char_names: Vec::new(), + }; + // initialize with function arguments + for arg in &decl.inputs { + visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat); + } + // walk all other bindings + visit::walk_block(&mut visitor, blk); + } } - // walk all other bindings - visit::walk_block(&mut visitor, blk); } } -- cgit 1.4.1-3-g733a5 From ee35c3722a25dda475a4828c5474795ddde285e2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 2 May 2016 10:53:09 +0200 Subject: similar_names should be allow-by-default --- src/non_expressive_names.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index c1232fe64b1..0c6fdc37066 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -15,7 +15,7 @@ use utils::{span_lint_and_then, in_macro, span_lint}; /// **Example:** `checked_exp` and `checked_expr` declare_lint! { pub SIMILAR_NAMES, - Warn, + Allow, "similarly named items and bindings" } -- cgit 1.4.1-3-g733a5 From 365644e9e63bc4aa100ad4d84e2212f843a912e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 2 May 2016 14:36:33 +0200 Subject: doc markdown lint's span shows the line instead of the item --- src/doc.rs | 49 +++++++++++++++++------------------------------ tests/compile-fail/doc.rs | 30 ++++++++++++++--------------- 2 files changed, 33 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 54d5366729e..6a2b3c27ba9 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -1,7 +1,6 @@ use rustc::lint::*; -use std::borrow::Cow; use syntax::ast; -use syntax::codemap::Span; +use syntax::codemap::{Span, BytePos}; use utils::span_lint; /// **What it does:** This lint checks for the presence of `_`, `::` or camel-case words outside @@ -43,50 +42,38 @@ impl LintPass for Doc { impl EarlyLintPass for Doc { fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { - check_attrs(cx, &self.valid_idents, &krate.attrs, krate.span); + check_attrs(cx, &self.valid_idents, &krate.attrs); } fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { - check_attrs(cx, &self.valid_idents, &item.attrs, item.span); + check_attrs(cx, &self.valid_idents, &item.attrs); } } -/// Collect all doc attributes. Multiple `///` are represented in different attributes. `rustdoc` -/// has a pass to merge them, but we probably don’t want to invoke that here. -fn collect_doc(attrs: &[ast::Attribute]) -> (Cow<str>, Option<Span>) { - fn doc_and_span(attr: &ast::Attribute) -> Option<(&str, Span)> { +pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) { + let mut in_multiline = false; + for attr in attrs { if attr.node.is_sugared_doc { if let ast::MetaItemKind::NameValue(_, ref doc) = attr.node.value.node { if let ast::LitKind::Str(ref doc, _) = doc.node { - return Some((&doc[..], attr.span)); + // doc comments start with `///` or `//!` + let real_doc = &doc[3..]; + let mut span = attr.span; + span.lo = span.lo + BytePos(3); + + // check for multiline code blocks + if real_doc.trim_left().starts_with("```") { + in_multiline = !in_multiline; + } + if !in_multiline { + check_doc(cx, valid_idents, real_doc, span); + } } } } - - None - } - let doc_and_span: fn(_) -> _ = doc_and_span; - - let mut doc_attrs = attrs.iter().filter_map(doc_and_span); - - let count = doc_attrs.clone().take(2).count(); - - match count { - 0 => ("".into(), None), - 1 => { - let (doc, span) = doc_attrs.next().unwrap_or_else(|| unreachable!()); - (doc.into(), Some(span)) - } - _ => (doc_attrs.map(|s| format!("{}\n", s.0)).collect::<String>().into(), None), } } -pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute], default_span: Span) { - let (doc, span) = collect_doc(attrs); - let span = span.unwrap_or(default_span); - check_doc(cx, valid_idents, &doc, span); -} - macro_rules! jump_to { // Get the next character’s first byte UTF-8 friendlyly. (@next_char, $chars: expr, $len: expr) => {{ diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 16e460e5055..7a150ba378d 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -7,14 +7,14 @@ #![deny(doc_markdown)] /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) +//~^ ERROR: you should put `foo_bar` between ticks +//~| ERROR: you should put `foo::bar` between ticks /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun +//~^ ERROR: you should put `Foo::some_fun` between ticks /// which should be reported only once despite being __doubly bad__. /// be_sure_we_got_to_the_end_of_it +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks fn foo_bar() { -//~^ ERROR: you should put `foo_bar` between ticks -//~| ERROR: you should put `foo::bar` between ticks -//~| ERROR: you should put `Foo::some_fun` between ticks -//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// That one tests multiline ticks. @@ -23,16 +23,16 @@ fn foo_bar() { /// _foo bar_ /// ``` /// be_sure_we_got_to_the_end_of_it -fn multiline_ticks() { //~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +fn multiline_ticks() { } /// This _is a test for /// multiline /// emphasis_. /// be_sure_we_got_to_the_end_of_it -fn test_emphasis() { //~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +fn test_emphasis() { } /// This tests units. See also #835. @@ -45,8 +45,8 @@ fn test_emphasis() { /// 32kB 32MB 32GB 32TB 32PB 32EB /// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb /// be_sure_we_got_to_the_end_of_it -fn test_units() { //~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +fn test_units() { } /// This one checks we don’t try to split unicode codepoints @@ -55,11 +55,15 @@ fn test_units() { /// `💣` /// `❤️` /// ß_foo +//~^ ERROR: you should put `ß_foo` between ticks /// ℝ_foo +//~^ ERROR: you should put `ℝ_foo` between ticks /// 💣_foo /// ❤️_foo /// foo_ß +//~^ ERROR: you should put `foo_ß` between ticks /// foo_ℝ +//~^ ERROR: you should put `foo_ℝ` between ticks /// foo_💣 /// foo_❤️ /// [ßdummy textß][foo_ß] @@ -75,18 +79,16 @@ fn test_units() { /// [foo_💣]: dummy text /// [foo_❤️]: dummy text /// be_sure_we_got_to_the_end_of_it +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks fn test_unicode() { -//~^ ERROR: you should put `ß_foo` between ticks -//~| ERROR: you should put `ℝ_foo` between ticks -//~| ERROR: you should put `foo_ß` between ticks -//~| ERROR: you should put `foo_ℝ` between ticks -//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks } /// This test has [a link_with_underscores][chunked-example] inside it. See #823. +//~^ ERROR: you should put `link_with_underscores` between ticks /// See also [the issue tracker](https://github.com/Manishearth/rust-clippy/search?q=doc_markdown&type=Issues) /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. /// It can also be [inline_link2]. +//~^ ERROR: you should put `inline_link2` between ticks /// /// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example /// [inline_link]: https://foobar @@ -98,10 +100,8 @@ fn test_unicode() { /// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` /// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , /// be_sure_we_got_to_the_end_of_it +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks fn main() { -//~^ ERROR: you should put `inline_link2` between ticks -//~| ERROR: you should put `link_with_underscores` between ticks -//~| ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks foo_bar(); multiline_ticks(); test_emphasis(); -- cgit 1.4.1-3-g733a5 From 3a32c2c596d1aaef4ea2c6da4656828869564ff8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 2 May 2016 14:36:48 +0200 Subject: doc markdown lint shows the exact word location --- src/doc.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 6a2b3c27ba9..6212a025c25 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -117,6 +117,15 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp } } + #[allow(cast_possible_truncation)] + fn word_span(mut span: Span, begin: usize, end: usize) -> Span { + debug_assert_eq!(end as u32 as usize, end); + debug_assert_eq!(begin as u32 as usize, begin); + span.hi = span.lo + BytePos(end as u32); + span.lo = span.lo + BytePos(begin as u32); + span + } + let len = doc.len(); let mut chars = doc.char_indices().peekable(); let mut current_word_begin = 0; @@ -133,6 +142,7 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp '[' => { let end = jump_to!(chars, ']', len); let link_text = &doc[current_word_begin + 1..end]; + let word_span = word_span(span, current_word_begin + 1, end + 1); match chars.peek() { Some(&(_, c)) => { @@ -143,18 +153,18 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp match c { '(' => { // inline link current_word_begin = jump_to!(chars, ')', len); - check_doc(cx, valid_idents, link_text, span); + check_doc(cx, valid_idents, link_text, word_span); } '[' => { // reference link current_word_begin = jump_to!(chars, ']', len); - check_doc(cx, valid_idents, link_text, span); + check_doc(cx, valid_idents, link_text, word_span); } ':' => { // reference link current_word_begin = jump_to!(chars, '\n', len); } _ => { // automatic reference link current_word_begin = jump_to!(@next_char, chars, len); - check_doc(cx, valid_idents, link_text, span); + check_doc(cx, valid_idents, link_text, word_span); } } } @@ -166,8 +176,8 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp Some((end, _)) => end, None => len, }; - - check_word(cx, valid_idents, &doc[current_word_begin..end], span); + let word_span = word_span(span, current_word_begin, end); + check_word(cx, valid_idents, &doc[current_word_begin..end], word_span); current_word_begin = jump_to!(@next_char, chars, len); } } -- cgit 1.4.1-3-g733a5 From ca743ecb77c35d7a0a26e625769aa1ec627811bf Mon Sep 17 00:00:00 2001 From: Georg Brandl <georg@python.org> Date: Wed, 4 May 2016 08:54:59 +0200 Subject: rustup: fix breakage in diagnostics API Also adds a function to add the clippy wiki note, which is used a few times. --- src/methods.rs | 2 +- src/swap.rs | 4 ++-- src/utils/mod.rs | 40 +++++++++++++++++++--------------------- 3 files changed, 22 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index e25154bd38b..44fdab454a3 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -602,7 +602,7 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, "you are getting the inner pointer of a temporary `CString`", |db| { - db.fileline_note(expr.span, "that pointer will be invalid outside this expression"); + db.note("that pointer will be invalid outside this expression"); db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime"); }); }} diff --git a/src/swap.rs b/src/swap.rs index 29db0da5cf9..724915b9dd5 100644 --- a/src/swap.rs +++ b/src/swap.rs @@ -95,7 +95,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { if !what.is_empty() { db.span_suggestion(span, "try", format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); - db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); + db.note("or maybe you should use `std::mem::replace`?"); } }); }} @@ -130,7 +130,7 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) { if !what.is_empty() { db.span_suggestion(span, "try", format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); - db.fileline_note(span, "or maybe you should use `std::mem::replace`?"); + db.note("or maybe you should use `std::mem::replace`?"); } }); }} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 83247a59174..3e77ffb2c24 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -471,44 +471,44 @@ impl<'a> Deref for DiagnosticWrapper<'a> { } } +impl<'a> DiagnosticWrapper<'a> { + fn wiki_link(&mut self, lint: &'static Lint) { + self.help(&format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); + } +} + pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, sp, msg); + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { - db.fileline_help(sp, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.wiki_link(lint); } - DiagnosticWrapper(db) + db } pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, span, msg); + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { - db.fileline_help(span, - &format!("{}\nfor further information visit \ - https://github.com/Manishearth/rust-clippy/wiki#{}", - help, - lint.name_lower())); + db.help(help); + db.wiki_link(lint); } - DiagnosticWrapper(db) + db } pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, note: &str) -> DiagnosticWrapper<'a> { - let mut db = cx.struct_span_lint(lint, span, msg); + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { if note_span == span { - db.fileline_note(note_span, note); + db.note(note); } else { db.span_note(note_span, note); } - db.fileline_help(span, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.wiki_link(lint); } - DiagnosticWrapper(db) + db } pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) @@ -518,9 +518,7 @@ pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); if cx.current_level(lint) != Level::Allow { f(&mut db); - db.fileline_help(sp, - &format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); + db.wiki_link(lint); } db } -- cgit 1.4.1-3-g733a5 From e14e1a7148375499731f9549eadf5172050fd99a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 5 May 2016 21:32:48 +0200 Subject: Fix issue with `DOC_MARKDOWN` and punctuation --- src/doc.rs | 7 ++++--- tests/compile-fail/doc.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 6212a025c25..00c3e4398ea 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -133,9 +133,6 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp match chars.next() { Some((_, c)) => { match c { - c if c.is_whitespace() => { - current_word_begin = jump_to!(@next_char, chars, len); - } '`' => { current_word_begin = jump_to!(chars, '`', len); } @@ -171,6 +168,10 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp None => return, } } + // anything that’s neither alphanumeric nor '_' is not part of an ident anyway + c if !c.is_alphanumeric() && c != '_' => { + current_word_begin = jump_to!(@next_char, chars, len); + } _ => { let end = match chars.find(|&(_, c)| !is_word_char(c)) { Some((end, _)) => end, diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 7a150ba378d..045174db78e 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -107,3 +107,11 @@ fn main() { test_emphasis(); test_units(); } + +/// I am confused by brackets? (`x_y`) +/// I am confused by brackets? (foo `x_y`) +/// I am confused by brackets? (`x_y` foo) +/// be_sure_we_got_to_the_end_of_it +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +fn issue900() { +} -- cgit 1.4.1-3-g733a5 From 3ce60e973139e1c44ad4bf67d26498c4e6c42d04 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 5 May 2016 21:42:59 +0200 Subject: Don’t warn in titles in DOC_MARKDOWN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc.rs | 6 ++++++ tests/compile-fail/doc.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+) (limited to 'src') diff --git a/src/doc.rs b/src/doc.rs index 00c3e4398ea..cf32c1731fa 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -126,6 +126,7 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp span } + let mut new_line = true; let len = doc.len(); let mut chars = doc.char_indices().peekable(); let mut current_word_begin = 0; @@ -133,6 +134,9 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp match chars.next() { Some((_, c)) => { match c { + '#' if new_line => { // don’t warn on titles + current_word_begin = jump_to!(chars, '\n', len); + } '`' => { current_word_begin = jump_to!(chars, '`', len); } @@ -182,6 +186,8 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Sp current_word_begin = jump_to!(@next_char, chars, len); } } + + new_line = c == '\n' || (new_line && c.is_whitespace()); } None => break, } diff --git a/tests/compile-fail/doc.rs b/tests/compile-fail/doc.rs index 0c8d1d50532..eca9d79354c 100755 --- a/tests/compile-fail/doc.rs +++ b/tests/compile-fail/doc.rs @@ -108,6 +108,18 @@ fn main() { test_units(); } +/// ## CamelCaseThing +/// Talks about `CamelCaseThing`. Titles should be ignored, see issue #897. +/// +/// # CamelCaseThing +/// +/// Not a title #897 CamelCaseThing +//~^ ERROR: you should put `CamelCaseThing` between ticks +/// be_sure_we_got_to_the_end_of_it +//~^ ERROR: you should put `be_sure_we_got_to_the_end_of_it` between ticks +fn issue897() { +} + /// I am confused by brackets? (`x_y`) /// I am confused by brackets? (foo `x_y`) /// I am confused by brackets? (`x_y` foo) -- cgit 1.4.1-3-g733a5 From 0a3ab78bdef4262c7ca912f8d757fb2412fcb61f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 6 May 2016 16:09:05 +0200 Subject: fix markdown generated from code --- src/escape.rs | 2 +- src/unicode.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/escape.rs b/src/escape.rs index fa235244884..ff841b18066 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -31,7 +31,7 @@ pub struct EscapePass; /// } /// ``` declare_lint! { - pub BOXED_LOCAL, Warn, "using Box<T> where unnecessary" + pub BOXED_LOCAL, Warn, "using `Box<T>` where unnecessary" } fn is_non_trait_box(ty: ty::Ty) -> bool { diff --git a/src/unicode.rs b/src/unicode.rs index 26521017ee5..8271fd3ed66 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -40,7 +40,7 @@ declare_lint! { declare_lint! { pub UNICODE_NOT_NFC, Allow, "using a unicode literal not in NFC normal form (see \ - http://www.unicode.org/reports/tr15/ for further information)" + [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" } -- cgit 1.4.1-3-g733a5 From aa10c93e8f337e43c2cbab63e98f31d95589defe Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Sun, 8 May 2016 00:56:23 +0200 Subject: Fix tests --- src/len_zero.rs | 7 +------ src/regex.rs | 19 +++++++++++-------- tests/compile-fail/for_loop.rs | 2 +- tests/compile-fail/matches.rs | 10 +++++----- tests/compile-fail/regex.rs | 2 ++ 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 7a7a17bc79d..7e9d17d643b 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -113,14 +113,9 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { if is_named_self(i, "len") { let ty = cx.tcx.node_id_to_type(item.id); - let s = i.span; span_lint(cx, LEN_WITHOUT_IS_EMPTY, - Span { - lo: s.lo, - hi: s.lo, - expn_id: s.expn_id, - }, + i.span, &format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ Consider adding one", ty)); diff --git a/src/regex.rs b/src/regex.rs index 72a33757027..e1b4237b9b2 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -143,14 +143,17 @@ impl LateLintPass for RegexPass { #[allow(cast_possible_truncation)] fn str_span(base: Span, s: &str, c: usize) -> Span { - let lo = match s.char_indices().nth(c) { - Some((b, _)) => base.lo + BytePos(b as u32), - _ => base.hi, - }; - Span { - lo: lo, - hi: lo, - ..base + let mut si = s.char_indices().skip(c); + + match (si.next(), si.next()) { + (Some((l, _)), Some((h, _))) => { + Span { + lo: base.lo + BytePos(l as u32), + hi: base.lo + BytePos(h as u32), + ..base + } + } + _ => base, } } diff --git a/tests/compile-fail/for_loop.rs b/tests/compile-fail/for_loop.rs index 064f66537eb..2f164d1e569 100644 --- a/tests/compile-fail/for_loop.rs +++ b/tests/compile-fail/for_loop.rs @@ -340,7 +340,7 @@ fn main() { for (_, v) in &m { //~^ you seem to want to iterate on a map's values //~| HELP use the corresponding method - //~| SUGGESTION for v in &m.values() + //~| SUGGESTION for v in m.values() let _v = v; } diff --git a/tests/compile-fail/matches.rs b/tests/compile-fail/matches.rs index f5f830fed51..3444e49ec51 100644 --- a/tests/compile-fail/matches.rs +++ b/tests/compile-fail/matches.rs @@ -140,7 +140,7 @@ fn ref_pats() { match v { //~^ERROR add `&` to all patterns //~|HELP instead of - //~|SUGGESTION `match *v { .. }` + //~|SUGGESTION match *v { .. } &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -153,7 +153,7 @@ fn ref_pats() { match tup { //~^ERROR add `&` to all patterns //~|HELP instead of - //~|SUGGESTION `match *tup { .. }` + //~|SUGGESTION match *tup { .. } &(v, 1) => println!("{}", v), _ => println!("none"), } @@ -162,7 +162,7 @@ fn ref_pats() { match &w { //~^ERROR add `&` to both //~|HELP try - //~|SUGGESTION `match w { .. }` + //~|SUGGESTION match w { .. } &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -176,7 +176,7 @@ fn ref_pats() { if let &None = a { //~^ERROR add `&` to all patterns //~|HELP instead of - //~|SUGGESTION `if let ... = *a { .. }` + //~|SUGGESTION if let .. = *a { .. } println!("none"); } @@ -184,7 +184,7 @@ fn ref_pats() { if let &None = &b { //~^ERROR add `&` to both //~|HELP try - //~|SUGGESTION `if let ... = b { .. }` + //~|SUGGESTION if let .. = b { .. } println!("none"); } } diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index 606c3d513b2..9cd2bc8098e 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -16,6 +16,8 @@ fn syntax_error() { //~^ERROR: regex syntax error: empty alternate let wrong_char_ranice = Regex::new("[z-a]"); //~^ERROR: regex syntax error: invalid character class range + let some_unicode = Regex::new("[é-è]"); + //~^ERROR: regex syntax error: invalid character class range let some_regex = Regex::new(OPENING_PAREN); //~^ERROR: regex syntax error on position 0: unclosed -- cgit 1.4.1-3-g733a5 From 87faaec7a30cab721aa03ad2e6301c9cd91f5847 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 26 Apr 2016 15:49:53 +0200 Subject: add needless_borrow lint --- CHANGELOG.md | 1 + README.md | 3 ++- src/lib.rs | 3 +++ src/needless_borrow.rs | 50 +++++++++++++++++++++++++++++++++++ tests/compile-fail/eta.rs | 1 + tests/compile-fail/needless_borrow.rs | 27 +++++++++++++++++++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/needless_borrow.rs create mode 100644 tests/compile-fail/needless_borrow.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff3526d841..3fb3c686948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -149,6 +149,7 @@ All notable changes to this project will be documented in this file. [`mutex_atomic`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic [`mutex_integer`]: https://github.com/Manishearth/rust-clippy/wiki#mutex_integer [`needless_bool`]: https://github.com/Manishearth/rust-clippy/wiki#needless_bool +[`needless_borrow`]: https://github.com/Manishearth/rust-clippy/wiki#needless_borrow [`needless_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes [`needless_range_loop`]: https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop [`needless_return`]: https://github.com/Manishearth/rust-clippy/wiki#needless_return diff --git a/README.md b/README.md index 17c0ce5235e..8f3519c95c4 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 146 lints included in this crate: +There are 147 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -97,6 +97,7 @@ name [mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead [mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type [needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }` +[needless_borrow](https://github.com/Manishearth/rust-clippy/wiki#needless_borrow) | warn | taking a reference that is going to be automatically dereferenced [needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice diff --git a/src/lib.rs b/src/lib.rs index 435e6998c16..dc0efe815b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub mod mut_mut; pub mod mut_reference; pub mod mutex_atomic; pub mod needless_bool; +pub mod needless_borrow; pub mod needless_update; pub mod neg_multiply; pub mod new_without_default; @@ -210,6 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); + reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow); reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_late_lint_pass(box map_clone::MapClonePass); reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); @@ -364,6 +366,7 @@ pub fn plugin_registrar(reg: &mut Registry) { mutex_atomic::MUTEX_ATOMIC, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, + needless_borrow::NEEDLESS_BORROW, needless_update::NEEDLESS_UPDATE, neg_multiply::NEG_MULTIPLY, new_without_default::NEW_WITHOUT_DEFAULT, diff --git a/src/needless_borrow.rs b/src/needless_borrow.rs new file mode 100644 index 00000000000..294a12dad99 --- /dev/null +++ b/src/needless_borrow.rs @@ -0,0 +1,50 @@ +//! Checks for needless address of operations (`&`) +//! +//! This lint is **warn** by default + +use rustc::lint::*; +use rustc::hir::*; +use rustc::ty::TyRef; +use utils::{span_lint, in_macro}; + +/// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler +/// +/// **Why is this bad?** Suggests that the receiver of the expression borrows the expression +/// +/// **Known problems:** +/// +/// **Example:** `let x: &i32 = &&&&&&5;` +declare_lint! { + pub NEEDLESS_BORROW, + Warn, + "taking a reference that is going to be automatically dereferenced" +} + +#[derive(Copy,Clone)] +pub struct NeedlessBorrow; + +impl LintPass for NeedlessBorrow { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_BORROW) + } +} + +impl LateLintPass for NeedlessBorrow { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if in_macro(cx, e.span) { + return; + } + if let ExprAddrOf(MutImmutable, ref inner) = e.node { + if let TyRef(..) = cx.tcx.expr_ty(inner).sty { + let ty = cx.tcx.expr_ty(e); + let adj_ty = cx.tcx.expr_ty_adjusted(e); + if ty != adj_ty { + span_lint(cx, + NEEDLESS_BORROW, + e.span, + "this expression borrows a reference that is immediately dereferenced by the compiler"); + } + } + } + } +} diff --git a/tests/compile-fail/eta.rs b/tests/compile-fail/eta.rs index a744489fa9c..c932f8f9a0f 100644 --- a/tests/compile-fail/eta.rs +++ b/tests/compile-fail/eta.rs @@ -18,6 +18,7 @@ fn main() { //~| SUGGESTION let c = Some(1u8).map({1+2; foo}); let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted + //~^ WARN needless_borrow unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } diff --git a/tests/compile-fail/needless_borrow.rs b/tests/compile-fail/needless_borrow.rs new file mode 100644 index 00000000000..242691aa268 --- /dev/null +++ b/tests/compile-fail/needless_borrow.rs @@ -0,0 +1,27 @@ +#![feature(plugin)] +#![plugin(clippy)] + +fn x(y: &i32) -> i32 { + *y +} + +#[deny(clippy)] +#[allow(unused_variables)] +fn main() { + let a = 5; + let b = x(&a); + let c = x(&&a); //~ ERROR: needless_borrow + let s = &String::from("hi"); + let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not + let g_val = g(&Vec::new()); // should not error, because `&Vec<T>` derefs to `&[T]` + let vec = Vec::new(); + let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]` +} + +fn f<T:Copy>(y: &T) -> T { + *y +} + +fn g(y: &[u8]) -> u8 { + y[0] +} -- cgit 1.4.1-3-g733a5 From 6edc6a13d4505f7eb20b8f6b4b72b53c328ae9b0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 26 Apr 2016 17:05:39 +0200 Subject: needless borrows found in clippy --- src/array_indexing.rs | 2 +- src/block_in_if_condition.rs | 2 +- src/booleans.rs | 4 ++-- src/consts.rs | 2 +- src/copies.rs | 6 +++--- src/cyclomatic_complexity.rs | 2 +- src/enum_variants.rs | 8 ++++---- src/len_zero.rs | 2 +- src/lib.rs | 2 +- src/lifetimes.rs | 4 ++-- src/loops.rs | 10 +++++----- src/matches.rs | 6 +++--- src/methods.rs | 4 ++-- src/misc.rs | 2 +- src/mut_reference.rs | 4 ++-- src/non_expressive_names.rs | 2 +- src/shadow.rs | 2 +- src/types.rs | 6 +++--- 18 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/array_indexing.rs b/src/array_indexing.rs index 2295bd7832a..ce2b9a7d6c0 100644 --- a/src/array_indexing.rs +++ b/src/array_indexing.rs @@ -67,7 +67,7 @@ impl LateLintPass for ArrayIndexing { let size = ConstInt::Infer(size as u64); // Index is a constant uint - let const_index = eval_const_expr_partial(cx.tcx, &index, ExprTypeChecked, None); + let const_index = eval_const_expr_partial(cx.tcx, index, ExprTypeChecked, None); if let Ok(ConstVal::Integral(const_index)) = const_index { if size <= const_index { utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs index cdaf53684c5..c56cf4dcd29 100644 --- a/src/block_in_if_condition.rs +++ b/src/block_in_if_condition.rs @@ -59,7 +59,7 @@ impl<'v> Visitor<'v> for ExVisitor<'v> { } }; if complex { - self.found_block = Some(&expr); + self.found_block = Some(expr); return; } } diff --git a/src/booleans.rs b/src/booleans.rs index 908415acc7b..9ab806f66ec 100644 --- a/src/booleans.rs +++ b/src/booleans.rs @@ -221,7 +221,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { s.push('('); } } - s.push_str(&snip(&terminals[n as usize])); + s.push_str(&snip(terminals[n as usize])); if brackets { if let ExprBinary(..) = terminals[n as usize].node { s.push(')'); @@ -319,7 +319,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } let mut improvements = Vec::new(); 'simplified: for suggestion in &simplified { - let simplified_stats = terminal_stats(&suggestion); + let simplified_stats = terminal_stats(suggestion); let mut improvement = false; for i in 0..32 { // ignore any "simplifications" that end up requiring a terminal more often than in the original expression diff --git a/src/consts.rs b/src/consts.rs index 4a5f457ed7d..248b5bfe9e6 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -164,7 +164,7 @@ impl PartialOrd for Constant { } } (&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)), - (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(&r), + (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r), (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { match lv.partial_cmp(rv) { Some(Equal) => Some(ls.cmp(rs)), diff --git a/src/copies.rs b/src/copies.rs index aba4638ab8b..aa9f243e8c7 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -142,7 +142,7 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { }; if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { - if let Some((i, j)) = search_same(&arms, hash, eq) { + if let Some((i, j)) = search_same(arms, hash, eq) { span_note_and_lint(cx, MATCH_SAME_ARMS, j.body.span, @@ -256,8 +256,8 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> match map.entry(hash(expr)) { Entry::Occupied(o) => { for o in o.get() { - if eq(&o, expr) { - return Some((&o, expr)); + if eq(o, expr) { + return Some((o, expr)); } } } diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 9b20cc4a312..858affd2bbb 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -58,7 +58,7 @@ impl CyclomaticComplexity { divergence: 0, short_circuits: 0, returns: 0, - tcx: &cx.tcx, + tcx: cx.tcx, }; helper.visit_block(block); let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; diff --git a/src/enum_variants.rs b/src/enum_variants.rs index d7bd4742ebb..a1f2c5e1441 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -68,9 +68,9 @@ impl EarlyLintPass for EnumVariantNames { for var in &def.variants { let name = var2str(var); - let pre_match = partial_match(&pre, &name); + let pre_match = partial_match(pre, &name); pre = &pre[..pre_match]; - let pre_camel = camel_case_until(&pre); + let pre_camel = camel_case_until(pre); pre = &pre[..pre_camel]; while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { if next.is_lowercase() { @@ -82,10 +82,10 @@ impl EarlyLintPass for EnumVariantNames { } } - let post_match = partial_rmatch(&post, &name); + let post_match = partial_rmatch(post, &name); let post_end = post.len() - post_match; post = &post[post_end..]; - let post_camel = camel_case_from(&post); + let post_camel = camel_case_from(post); post = &post[post_camel..]; } let (what, value) = match (pre.is_empty(), post.is_empty()) { diff --git a/src/len_zero.rs b/src/len_zero.rs index 7e9d17d643b..9dae856764a 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -184,7 +184,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { }) } - let ty = &walk_ptrs_ty(&cx.tcx.expr_ty(expr)); + let ty = &walk_ptrs_ty(cx.tcx.expr_ty(expr)); match ty.sty { ty::TyTrait(_) => { cx.tcx diff --git a/src/lib.rs b/src/lib.rs index dc0efe815b2..e5d374a560f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,7 @@ pub fn plugin_registrar(reg: &mut Registry) { ("clippy.toml", false) }; - let (conf, errors) = utils::conf::read_conf(&file_name, must_exist); + let (conf, errors) = utils::conf::read_conf(file_name, must_exist); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 67dfabe2569..b9771e18ffc 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -46,7 +46,7 @@ impl LintPass for LifetimePass { impl LateLintPass for LifetimePass { fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { - check_fn_inner(cx, decl, None, &generics, item.span); + check_fn_inner(cx, decl, None, generics, item.span); } } @@ -102,7 +102,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g span, "explicit lifetimes given in parameter types where they could be elided"); } - report_extra_lifetimes(cx, decl, &generics, slf); + report_extra_lifetimes(cx, decl, generics, slf); } fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, diff --git a/src/loops.rs b/src/loops.rs index 70abb7a1aac..2384c845303 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -328,7 +328,7 @@ 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) { - if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(&arg) { + if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) { // the var must be a single name if let PatKind::Ident(_, ref ident, _) = pat.node { let mut visitor = VarVisitor { @@ -363,7 +363,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex }; let take: Cow<_> = if let Some(ref end) = *end { - if is_len_call(&end, &indexed) { + if is_len_call(end, &indexed) { "".into() } else { format!(".take({})", snippet(cx, end.span, "..")).into() @@ -422,10 +422,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... - if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(&arg) { + if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) { // ...and both sides are compile-time constant integers... - if let Ok(start_idx) = eval_const_expr_partial(&cx.tcx, start, ExprTypeChecked, None) { - if let Ok(end_idx) = eval_const_expr_partial(&cx.tcx, end, ExprTypeChecked, None) { + if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) { + if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) { // ...and the start index is greater than the end index, // this loop will never run. This is often confusing for developers // who think that this will iterate from the larger value to the diff --git a/src/matches.rs b/src/matches.rs index bce93b717a3..db4ccf2dcdb 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -461,8 +461,8 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & let mut values = Vec::with_capacity(2 * ranges.len()); for r in ranges { - values.push(Kind::Start(r.node.0, &r)); - values.push(Kind::End(r.node.1, &r)); + values.push(Kind::Start(r.node.0, r)); + values.push(Kind::End(r.node.1, r)); } values.sort(); @@ -475,7 +475,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, & } } (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), - _ => return Some((&a.range(), &b.range())), + _ => return Some((a.range(), b.range())), } } diff --git a/src/methods.rs b/src/methods.rs index 44fdab454a3..5b86aab1aa1 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -365,7 +365,7 @@ impl LateLintPass for MethodsPass { lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]); } - lint_or_fun_call(cx, expr, &name.node.as_str(), &args); + lint_or_fun_call(cx, expr, &name.node.as_str(), args); let self_ty = cx.tcx.expr_ty_adjusted(&args[0]); if args.len() == 1 && name.node.as_str() == "clone" { @@ -420,7 +420,7 @@ impl LateLintPass for MethodsPass { // check conventions w.r.t. conversion method names and predicates let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; - let is_copy = is_copy(cx, &ty, &item); + let is_copy = is_copy(cx, ty, item); for &(ref conv, self_kinds) in &CONVENTIONS { if conv.check(&name.as_str()) && !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { diff --git a/src/misc.rs b/src/misc.rs index 7323f18a46e..25747157c0f 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -424,7 +424,7 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { match parent.node { ExprAssign(_, ref rhs) | ExprAssignOp(_, _, ref rhs) => **rhs == *expr, - _ => is_used(cx, &parent), + _ => is_used(cx, parent), } } else { true diff --git a/src/mut_reference.rs b/src/mut_reference.rs index 4ac4d83360e..f6aee54d90b 100644 --- a/src/mut_reference.rs +++ b/src/mut_reference.rs @@ -39,13 +39,13 @@ impl LateLintPass for UnnecessaryMutPassed { 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()); + 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()) + check_arguments(cx, arguments, method_type.ty, &name.node.as_str()) } _ => (), } diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 0c6fdc37066..9d2139fe422 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -249,7 +249,7 @@ impl EarlyLintPass for NonExpressiveNames { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), cx: cx, - lint: &self, + lint: self, single_char_names: Vec::new(), }; // initialize with function arguments diff --git a/src/shadow.rs b/src/shadow.rs index bb287f449e3..4b6439c4eb3 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -278,7 +278,7 @@ fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { let len = bindings.len(); for ref arm in arms { for ref 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); diff --git a/src/types.rs b/src/types.rs index 43d42cde501..f63538e974d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -910,7 +910,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { if rel == Rel::Eq || rel == Rel::Ne { if norm_rhs_val < lb || norm_rhs_val > ub { - err_upcast_comparison(cx, &span, lhs, rel == Rel::Ne); + err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); } } else if match rel { Rel::Lt => { @@ -929,7 +929,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: } Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, &span, lhs, true) + err_upcast_comparison(cx, span, lhs, true) } else if match rel { Rel::Lt => { if invert { @@ -947,7 +947,7 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons: } Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, &span, lhs, false) + err_upcast_comparison(cx, span, lhs, false) } } } -- cgit 1.4.1-3-g733a5 From ba8653a8da189aaa629bd1e70c09146e23671328 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 26 Apr 2016 17:06:08 +0200 Subject: fallout --- src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/consts.rs b/src/consts.rs index 248b5bfe9e6..96956d1793b 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -164,6 +164,7 @@ impl PartialOrd for Constant { } } (&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), (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { match lv.partial_cmp(rv) { @@ -171,7 +172,6 @@ impl PartialOrd for Constant { x => x, } } - (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l.partial_cmp(r), _ => None, //TODO: Are there any useful inter-type orderings? } } -- cgit 1.4.1-3-g733a5 From 654154d8e7e770dc7328024efb5451a7503d5d6d Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Feb 2016 18:16:29 +0100 Subject: `cargo clippy` subcommand --- .travis.yml | 3 +- Cargo.toml | 6 +++ README.md | 30 +++++++++++- src/lib.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- tests/dogfood.rs | 16 ++++--- 5 files changed, 185 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/.travis.yml b/.travis.yml index 012d6045cd2..b204bb0b2f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,9 @@ script: - remark -f README.md > /dev/null - python util/update_lints.py -c - cargo build --features debugging - - rm -rf target/ Cargo.lock - cargo test --features debugging + - SYSROOT=~/rust cargo install + - cargo clippy --lib -- -D clippy after_success: # only test regex_macros if it compiles diff --git a/Cargo.toml b/Cargo.toml index cd6b2834c56..470d2dd7096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,12 @@ keywords = ["clippy", "lint", "plugin"] [lib] name = "clippy" plugin = true +test = false + +[[bin]] +name = "cargo-clippy" +path = "src/lib.rs" +test = false [dependencies] regex-syntax = "0.3.0" diff --git a/README.md b/README.md index 8f3519c95c4..ee234432c63 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,8 @@ More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/ ## Usage +### As a Compiler Plugin + Compiler plugins are highly unstable and will only work with a nightly Rust for now. Since stable Rust is backwards compatible, you should be able to compile your stable programs with nightly Rust with clippy plugged in to circumvent @@ -217,8 +219,28 @@ src/main.rs:8:5: 11:6 help: Try if let Some(y) = x { println!("{:?}", y) } ``` -An alternate way to use clippy is by compiling and using [`cargo clippy`](https://github.com/arcnmx/cargo-clippy), -a custom cargo subcommand that runs clippy on a given project. +### 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 +`multirust run nightly cargo clippy` directly from a directory that is usually +compiled with stable. + +In case you are not using multirust, 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 +``` + +### Configuring clippy You can add options to `allow`/`warn`/`deny`: @@ -234,6 +256,8 @@ You can add options to `allow`/`warn`/`deny`: Note: `deny` produces errors instead of warnings +### 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: @@ -244,6 +268,8 @@ 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`: diff --git a/src/lib.rs b/src/lib.rs index e5d374a560f..5dd473c8d09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,11 +9,145 @@ #![allow(indexing_slicing, shadow_reuse, unknown_lints)] #![allow(float_arithmetic, integer_arithmetic)] -// this only exists to allow the "dogfood" integration test to work -#[allow(dead_code)] -#[allow(print_stdout)] -fn main() { - println!("What are you doing? Don't run clippy as an executable"); +extern crate rustc_driver; +extern crate getopts; + +use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; +use rustc::session::{config, Session}; +use rustc::session::config::{Input, ErrorOutputType}; +use syntax::diagnostics; +use std::path::PathBuf; + +struct ClippyCompilerCalls(RustcDefaultCalls); + +impl std::default::Default for ClippyCompilerCalls { + fn default() -> Self { + Self::new() + } +} + +impl ClippyCompilerCalls { + fn new() -> Self { + ClippyCompilerCalls(RustcDefaultCalls) + } +} + +impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { + fn early_callback(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + descriptions: &diagnostics::registry::Registry, + output: ErrorOutputType) + -> Compilation { + self.0.early_callback(matches, sopts, descriptions, output) + } + fn no_input(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, + descriptions: &diagnostics::registry::Registry) + -> Option<(Input, Option<PathBuf>)> { + self.0.no_input(matches, sopts, odir, ofile, descriptions) + } + fn late_callback(&mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>) + -> Compilation { + self.0.late_callback(matches, sess, input, odir, ofile) + } + fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { + let mut control = self.0.build_controller(sess, matches); + + 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")); + registry.args_hidden = Some(Vec::new()); + plugin_registrar(&mut registry); + + let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.mir_passes.borrow_mut().extend(mir_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + } + old(state); + }); + + control + } +} + +use std::path::Path; + +pub fn main() { + use std::env; + + if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + return; + } + + let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); + let sys_root = match (option_env!("MULTIRUST_HOME"), option_env!("MULTIRUST_TOOLCHAIN")) { + (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), + _ => option_env!("SYSROOT").expect("need to specify SYSROOT env var during clippy compilation or use multirust").to_owned(), + }; + + if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); + let path = std::env::current_exe().expect("current executable path invalid"); + let run = std::process::Command::new("cargo") + .args(&args) + .env("RUSTC", path) + .spawn().expect("could not run cargo") + .wait().expect("failed to wait for cargo?") + .success(); + assert!(run, "cargo rustc failed"); + } else { + let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + env::args().collect() + } else { + env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() + }; + rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); + } +} + +fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String> + where P: AsRef<Path>, I: Iterator<Item=String> { + + let mut args = vec!["rustc".to_owned()]; + + let mut found_dashes = false; + for arg in old_args { + found_dashes |= arg == "--"; + args.push(arg); + } + if !found_dashes { + args.push("--".to_owned()); + } + args.push("-L".to_owned()); + args.push(dep_path.as_ref().to_string_lossy().into_owned()); + args.push(String::from("--sysroot")); + args.push(sysroot); + args.push("-Zno-trans".to_owned()); + args } #[macro_use] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index b5ae813ae51..d050b4fc5ba 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -1,9 +1,11 @@ -#![feature(test)] +#![feature(test, plugin)] +#![plugin(clippy)] +#![deny(clippy, clippy_pedantic)] extern crate compiletest_rs as compiletest; extern crate test; -use std::env::var; +use std::env::{var, set_var}; use std::path::PathBuf; use test::TestPaths; @@ -11,15 +13,14 @@ use test::TestPaths; fn dogfood() { let mut config = compiletest::default_config(); - let cfg_mode = "run-pass".parse().ok().expect("Invalid mode"); + let cfg_mode = "run-pass".parse().expect("Invalid mode"); let mut s = String::new(); s.push_str(" -L target/debug/"); s.push_str(" -L target/debug/deps"); s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy"); config.target_rustcflags = Some(s); - if let Ok(name) = var::<&str>("TESTNAME") { - let s : String = name.to_owned(); - config.filter = Some(s) + if let Ok(name) = var("TESTNAME") { + config.filter = Some(name.to_owned()) } config.mode = cfg_mode; @@ -29,5 +30,8 @@ fn dogfood() { file: PathBuf::from("src/lib.rs"), relative_dir: PathBuf::new(), }; + + set_var("CLIPPY_DOGFOOD", "tastes like chicken"); + compiletest::runtest::run(config, &paths); } -- cgit 1.4.1-3-g733a5 From f227225acdd3ca85d619f03b6a4727def546329d Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon <sanxiyn@gmail.com> Date: Tue, 10 May 2016 00:35:51 +0900 Subject: Remove unused imports --- src/attrs.rs | 1 - src/enum_clike.rs | 1 - src/enum_variants.rs | 1 - src/if_not_else.rs | 1 - src/items_after_statements.rs | 1 - src/methods.rs | 1 - 6 files changed, 6 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index 6106486c71e..ca7813d3860 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -5,7 +5,6 @@ use rustc::lint::*; use rustc::hir::*; use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; -use syntax::attr::*; use syntax::codemap::Span; use utils::{in_macro, match_path, span_lint}; use utils::paths; diff --git a/src/enum_clike.rs b/src/enum_clike.rs index e3e8f1e5eb6..39c31864f39 100644 --- a/src/enum_clike.rs +++ b/src/enum_clike.rs @@ -4,7 +4,6 @@ use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc_const_math::*; use rustc::hir::*; -use syntax::attr::*; use utils::span_lint; /// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. diff --git a/src/enum_variants.rs b/src/enum_variants.rs index a1f2c5e1441..67a8495e155 100644 --- a/src/enum_variants.rs +++ b/src/enum_variants.rs @@ -2,7 +2,6 @@ use rustc::lint::*; use syntax::ast::*; -use syntax::attr::*; use syntax::parse::token::InternedString; use utils::span_help_and_lint; use utils::{camel_case_from, camel_case_until}; diff --git a/src/if_not_else.rs b/src/if_not_else.rs index 2fc2cc10e38..d78eba9877b 100644 --- a/src/if_not_else.rs +++ b/src/if_not_else.rs @@ -1,7 +1,6 @@ //! lint on if branches that could be swapped so no `!` operation is necessary on the condition use rustc::lint::*; -use syntax::attr::*; use syntax::ast::*; use utils::span_help_and_lint; diff --git a/src/items_after_statements.rs b/src/items_after_statements.rs index 9d8ae2e9913..2e6b33ab390 100644 --- a/src/items_after_statements.rs +++ b/src/items_after_statements.rs @@ -2,7 +2,6 @@ use rustc::lint::*; use syntax::ast::*; -use syntax::attr::*; use utils::in_macro; /// **What it does:** This lints checks for items declared after some statement in a block diff --git a/src/methods.rs b/src/methods.rs index 5b86aab1aa1..c9cc81484cd 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,7 +1,6 @@ use rustc::hir::*; use rustc::lint::*; use rustc::middle::const_val::ConstVal; -use rustc::middle::cstore::CrateStore; use rustc::ty::subst::{Subst, TypeSpace}; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; -- cgit 1.4.1-3-g733a5 From 11987f5b6f9c478cdd15543625a27fb5df1996f4 Mon Sep 17 00:00:00 2001 From: Josh Stone <cuviper@gmail.com> Date: Tue, 10 May 2016 13:45:37 -0700 Subject: Support either rustup or multirust environment variables Fixes #910 --- src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 5dd473c8d09..2d05419673d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,9 +104,14 @@ pub fn main() { } let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); - let sys_root = match (option_env!("MULTIRUST_HOME"), option_env!("MULTIRUST_TOOLCHAIN")) { + + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("SYSROOT").expect("need to specify SYSROOT env var during clippy compilation or use multirust").to_owned(), + _ => option_env!("SYSROOT") + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") + .to_owned(), }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { -- cgit 1.4.1-3-g733a5 From c6b4b19a435a825e3c28b2851966164b5ee4ca3c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 11 May 2016 15:32:20 +0200 Subject: suggest `a op= b` over `a = a op b` --- CHANGELOG.md | 2 + README.md | 4 +- src/assign_ops.rs | 158 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +- src/utils/paths.rs | 1 + tests/compile-fail/assign_ops.rs | 65 ++++++++++++++++ tests/compile-fail/strings.rs | 2 +- 7 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/assign_ops.rs create mode 100644 tests/compile-fail/assign_ops.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb3c686948..9591e207a88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,8 @@ All notable changes to this project will be documented in this file. [`absurd_extreme_comparisons`]: https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons [`almost_swapped`]: https://github.com/Manishearth/rust-clippy/wiki#almost_swapped [`approx_constant`]: https://github.com/Manishearth/rust-clippy/wiki#approx_constant +[`assign_op_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern +[`assign_ops`]: https://github.com/Manishearth/rust-clippy/wiki#assign_ops [`bad_bit_mask`]: https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask [`blacklisted_name`]: https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name [`block_in_if_condition_expr`]: https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr diff --git a/README.md b/README.md index ee234432c63..658e2eb63a5 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,15 @@ Table of contents: ## Lints -There are 147 lints included in this crate: +There are 149 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ [absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false [almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence [approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant +[assign_op_pattern](https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern) | warn | assigning the result of an operation on a variable to that same variable +[assign_ops](https://github.com/Manishearth/rust-clippy/wiki#assign_ops) | allow | Any assignment operation [bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have) [blacklisted_name](https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name) | warn | usage of a blacklisted/placeholder name [block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...` diff --git a/src/assign_ops.rs b/src/assign_ops.rs new file mode 100644 index 00000000000..8dc072e69f0 --- /dev/null +++ b/src/assign_ops.rs @@ -0,0 +1,158 @@ +use rustc::hir; +use rustc::lint::*; +use utils::{span_lint_and_then, span_lint, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait}; + +/// **What it does:** This lint checks for `+=` operations and similar +/// +/// **Why is this bad?** Projects with many developers from languages without those operations +/// may find them unreadable and not worth their weight +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// a += 1; +/// ``` +declare_restriction_lint! { + pub ASSIGN_OPS, + "Any assignment operation" +} + +/// **What it does:** Check for `a = a op b` or `a = b commutative_op a` patterns +/// +/// **Why is this bad?** These can be written as the shorter `a op= b` +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// let mut a = 5; +/// ... +/// a = a + b; +/// ``` +declare_lint! { + pub ASSIGN_OP_PATTERN, + Warn, + "assigning the result of an operation on a variable to that same variable" +} + +#[derive(Copy, Clone, Default)] +pub struct AssignOps; + +impl LintPass for AssignOps { + fn get_lints(&self) -> LintArray { + lint_array!(ASSIGN_OPS, ASSIGN_OP_PATTERN) + } +} + +impl LateLintPass for AssignOps { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + match expr.node { + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + if let (Some(l), Some(r)) = (snippet_opt(cx, lhs.span), snippet_opt(cx, rhs.span)) { + span_lint_and_then(cx, + ASSIGN_OPS, + expr.span, + "assign operation detected", + |db| { + match rhs.node { + hir::ExprBinary(op2, _, _) if op2 != op => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} ({})", l, l, op.node.as_str(), r)); + }, + _ => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} {}", l, l, op.node.as_str(), r)); + } + } + }); + } else { + span_lint(cx, + ASSIGN_OPS, + expr.span, + "assign operation detected"); + } + }, + 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| { + let ty = cx.tcx.expr_ty(assignee); + if ty.walk_shallow().next().is_some() { + return; // implements_trait does not work with generics + } + let rty = cx.tcx.expr_ty(rhs); + if rty.walk_shallow().next().is_some() { + return; // implements_trait does not work with generics + } + macro_rules! ops { + ($op:expr, $cx:expr, $ty:expr, $rty:expr, $($trait_name:ident:$full_trait_name:ident),+) => { + match $op { + $(hir::$full_trait_name => { + let [krate, module] = ::utils::paths::OPS_MODULE; + let path = [krate, module, concat!(stringify!($trait_name), "Assign")]; + let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) { + trait_id + } else { + return; // useless if the trait doesn't exist + }; + implements_trait($cx, $ty, trait_id, vec![$rty]) + },)* + _ => false, + } + } + } + if ops!(op.node, cx, ty, rty, Add:BiAdd, + Sub:BiSub, + Mul:BiMul, + Div:BiDiv, + Rem:BiRem, + And:BiAnd, + Or:BiOr, + BitAnd:BiBitAnd, + BitOr:BiBitOr, + BitXor:BiBitXor, + Shr:BiShr, + Shl:BiShl + ) { + if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { + span_lint_and_then(cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation", + |db| { + db.span_suggestion(expr.span, + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); + }); + } else { + span_lint(cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation"); + } + } + }; + // a = a op b + if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) { + lint(assignee, r); + } + // a = b commutative_op a + if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { + match op.node { + hir::BiAdd | hir::BiMul | + hir::BiAnd | hir::BiOr | + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr => { + lint(assignee, l); + }, + _ => {}, + } + } + } + }, + _ => {}, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5dd473c8d09..aac2718b1ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ #![feature(question_mark)] #![feature(stmt_expr_attributes)] #![allow(indexing_slicing, shadow_reuse, unknown_lints)] -#![allow(float_arithmetic, integer_arithmetic)] extern crate rustc_driver; extern crate getopts; @@ -192,6 +191,7 @@ pub mod utils; pub mod approx_const; pub mod arithmetic; pub mod array_indexing; +pub mod assign_ops; pub mod attrs; pub mod bit_mask; pub mod blacklisted_name; @@ -383,10 +383,12 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_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); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, arithmetic::INTEGER_ARITHMETIC, + assign_ops::ASSIGN_OPS, ]); reg.register_lint_group("clippy_pedantic", vec![ @@ -421,6 +423,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_group("clippy", vec![ approx_const::APPROX_CONSTANT, array_indexing::OUT_OF_BOUNDS_INDEXING, + assign_ops::ASSIGN_OP_PATTERN, attrs::DEPRECATED_SEMVER, attrs::INLINE_ALWAYS, bit_mask::BAD_BIT_MASK, diff --git a/src/utils/paths.rs b/src/utils/paths.rs index c52324a7448..2e6ceb50096 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -29,6 +29,7 @@ pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "Linke pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; +pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"]; pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"]; pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"]; diff --git a/tests/compile-fail/assign_ops.rs b/tests/compile-fail/assign_ops.rs new file mode 100644 index 00000000000..84d868ecfcc --- /dev/null +++ b/tests/compile-fail/assign_ops.rs @@ -0,0 +1,65 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(assign_ops)] +#[allow(unused_assignments)] +fn main() { + let mut i = 1i32; + i += 2; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i + 2 + i -= 6; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i - 6 + i *= 5; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i * 5 + i /= 32; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i / 32 + i %= 42; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i % 42 + i >>= i; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i >> i + i <<= 9 + 6 - 7; //~ ERROR assign operation detected + //~^ HELP replace it with + //~| SUGGESTION i = i << (9 + 6 - 7) +} + +#[allow(dead_code, unused_assignments)] +#[deny(assign_op_pattern)] +fn bla() { + let mut a = 5; + a = a + 1; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a += 1 + a = 1 + a; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a += 1 + a = a - 1; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a -= 1 + a = a * 99; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a *= 99 + a = 42 * a; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a *= 42 + a = a / 2; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a /= 2 + a = a % 5; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a %= 5 + a = a & 1; //~ ERROR manual implementation of an assign operation + //~^ HELP replace it with + //~| SUGGESTION a &= 1 + a = 1 - a; + a = 5 / a; + a = 42 % a; + a = 6 << a; + let mut s = String::new(); + s = s + "bla"; +} diff --git a/tests/compile-fail/strings.rs b/tests/compile-fail/strings.rs index 656349ba621..542b6db4abb 100644 --- a/tests/compile-fail/strings.rs +++ b/tests/compile-fail/strings.rs @@ -65,6 +65,6 @@ fn main() { // the add is only caught for String let mut x = 1; - x = x + 1; + x = x + 1; //~ WARN assign_op_pattern assert_eq!(2, x); } -- cgit 1.4.1-3-g733a5 From 49e2570b77558e9215b43926d2633eef4a25f7bd Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 11 May 2016 16:44:43 +0200 Subject: don't lint at the use-site of bad struct field bindings if they're shorthand fixes #899 --- src/non_expressive_names.rs | 25 +++++++++++++++---------- tests/compile-fail/non_expressive_names2.rs | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 tests/compile-fail/non_expressive_names2.rs (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index 9d2139fe422..e8f3858a37b 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -3,7 +3,7 @@ use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ast::*; use syntax::attr; -use syntax::visit; +use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr}; use utils::{span_lint_and_then, in_macro, span_lint}; /// **What it does:** This lint warns about names that are very similar and thus confusing @@ -68,12 +68,17 @@ const WHITELIST: &'static [&'static [&'static str]] = &[ struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); -impl<'v, 'a, 'b, 'c> visit::Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { +impl<'v, 'a, 'b, 'c> Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { fn visit_pat(&mut self, pat: &'v Pat) { - if let PatKind::Ident(_, id, _) = pat.node { - self.check_name(id.span, id.node.name); + match pat.node { + PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), + PatKind::Struct(_, ref fields, _) => for field in fields { + if !field.node.is_shorthand { + self.visit_pat(&field.node.pat); + } + }, + _ => walk_pat(self, pat), } - visit::walk_pat(self, pat); } } @@ -219,22 +224,22 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { } } -impl<'v, 'a, 'b> visit::Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { +impl<'v, 'a, 'b> Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { fn visit_local(&mut self, local: &'v Local) { if let Some(ref init) = local.init { - self.apply(|this| visit::walk_expr(this, &**init)); + self.apply(|this| walk_expr(this, &**init)); } // add the pattern after the expression because the bindings aren't available yet in the init expression SimilarNamesNameVisitor(self).visit_pat(&*local.pat); } fn visit_block(&mut self, blk: &'v Block) { - self.apply(|this| visit::walk_block(this, blk)); + self.apply(|this| walk_block(this, blk)); } fn visit_arm(&mut self, arm: &'v Arm) { self.apply(|this| { // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); - this.apply(|this| visit::walk_expr(this, &arm.body)); + this.apply(|this| walk_expr(this, &arm.body)); }); } fn visit_item(&mut self, _: &'v Item) { @@ -257,7 +262,7 @@ impl EarlyLintPass for NonExpressiveNames { visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat); } // walk all other bindings - visit::walk_block(&mut visitor, blk); + walk_block(&mut visitor, blk); } } } diff --git a/tests/compile-fail/non_expressive_names2.rs b/tests/compile-fail/non_expressive_names2.rs new file mode 100644 index 00000000000..a0e5885c539 --- /dev/null +++ b/tests/compile-fail/non_expressive_names2.rs @@ -0,0 +1,14 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(clippy,similar_names)] +#![allow(unused)] + +struct Foo { + apple: i32, + bpple: i32, +} + +fn main() { + let Foo { apple, bpple } = unimplemented!(); + let Foo { apple: spring, bpple: sprang } = unimplemented!(); //~ ERROR: name is too similar +} -- cgit 1.4.1-3-g733a5 From f004120495b51c925fa72156b69ebd97f011b061 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 11 May 2016 16:45:06 +0200 Subject: properly lint function argument patterns in similar_names --- src/non_expressive_names.rs | 2 +- src/shadow.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs index e8f3858a37b..cbb083a3e16 100644 --- a/src/non_expressive_names.rs +++ b/src/non_expressive_names.rs @@ -259,7 +259,7 @@ impl EarlyLintPass for NonExpressiveNames { }; // initialize with function arguments for arg in &decl.inputs { - visit::walk_pat(&mut SimilarNamesNameVisitor(&mut visitor), &arg.pat); + SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat); } // walk all other bindings walk_block(&mut visitor, blk); diff --git a/src/shadow.rs b/src/shadow.rs index 4b6439c4eb3..4639a943965 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -195,7 +195,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind } } -fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: &Option<T>, prev_span: Span) +fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, init: &Option<T>, prev_span: Span) where T: Deref<Target = Expr> { fn note_orig(cx: &LateContext, mut db: DiagnosticWrapper, lint: &'static Lint, span: Span) { @@ -209,15 +209,15 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & SHADOW_SAME, span, &format!("{} is shadowed by itself in {}", - snippet(cx, lspan, "_"), + snippet(cx, pattern_span, "_"), snippet(cx, expr.span, ".."))); note_orig(cx, db, SHADOW_SAME, prev_span); } else if contains_self(name, expr) { let db = span_note_and_lint(cx, SHADOW_REUSE, - lspan, + pattern_span, &format!("{} is shadowed by {} which reuses the original value", - snippet(cx, lspan, "_"), + snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); @@ -225,9 +225,9 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & } else { let db = span_note_and_lint(cx, SHADOW_UNRELATED, - lspan, + pattern_span, &format!("{} is shadowed by {}", - snippet(cx, lspan, "_"), + snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), expr.span, "initialization happens here"); @@ -238,7 +238,7 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, lspan: Span, init: & let db = span_lint(cx, SHADOW_UNRELATED, span, - &format!("{} shadows a previous declaration", snippet(cx, lspan, "_"))); + &format!("{} shadows a previous declaration", snippet(cx, pattern_span, "_"))); note_orig(cx, db, SHADOW_UNRELATED, prev_span); } } -- cgit 1.4.1-3-g733a5 From b0d008bc9d0e2efd92c29da9c40db768b864b52b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 11 May 2016 17:04:27 +0200 Subject: add known problems --- src/assign_ops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/assign_ops.rs b/src/assign_ops.rs index 8dc072e69f0..2b1aec83e4c 100644 --- a/src/assign_ops.rs +++ b/src/assign_ops.rs @@ -7,7 +7,7 @@ use utils::{span_lint_and_then, span_lint, snippet_opt, SpanlessEq, get_trait_de /// **Why is this bad?** Projects with many developers from languages without those operations /// may find them unreadable and not worth their weight /// -/// **Known problems:** None +/// **Known problems:** Types implementing `OpAssign` don't necessarily implement `Op` /// /// **Example:** /// ``` @@ -22,7 +22,7 @@ declare_restriction_lint! { /// /// **Why is this bad?** These can be written as the shorter `a op= b` /// -/// **Known problems:** Hopefully none. +/// **Known problems:** While forbidden by the spec, `OpAssign` traits may have implementations that differ from the regular `Op` impl /// /// **Example:** /// -- cgit 1.4.1-3-g733a5 From 03a309d1825f5a65f9835c4a1e1e53b9c726011b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 11 May 2016 11:05:34 -0700 Subject: Use rustc --print sysroot, bump to v66 --- Cargo.toml | 2 +- src/lib.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 470d2dd7096..3a767a97c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.65" +version = "0.0.66" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", diff --git a/src/lib.rs b/src/lib.rs index 2d05419673d..205f6bd079d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ use rustc::session::{config, Session}; use rustc::session::config::{Input, ErrorOutputType}; use syntax::diagnostics; use std::path::PathBuf; +use std::process::Command; struct ClippyCompilerCalls(RustcDefaultCalls); @@ -109,9 +110,14 @@ pub fn main() { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); let sys_root = match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("SYSROOT") - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - .to_owned(), + _ => option_env!("SYSROOT").map(|s| s.to_owned()) + .or(Command::new("rustc").arg("--print") + .arg("sysroot") + .output().ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + ) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"), }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { -- cgit 1.4.1-3-g733a5 From 610883b7aa8107e805cd5b43957fb7a5a300a381 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 12 May 2016 10:23:06 +0200 Subject: don't suggest closures over constants fixes #917 --- src/methods.rs | 8 ++++++++ tests/compile-fail/methods.rs | 13 +++++++++++++ 2 files changed, 21 insertions(+) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index c9cc81484cd..b47ae924bf0 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,6 +1,7 @@ use rustc::hir::*; use rustc::lint::*; use rustc::middle::const_val::ConstVal; +use rustc::middle::const_qualif::ConstQualif; use rustc::ty::subst::{Subst, TypeSpace}; use rustc::ty; use rustc_const_eval::EvalHint::ExprTypeChecked; @@ -502,6 +503,13 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) /// Check for `*or(foo())`. fn check_general_case(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &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) { + if !qualif.contains(ConstQualif::NOT_CONST) { + return; + } + } // (path, fn_has_argument, methods) let know_types: &[(&[_], _, &[_], _)] = &[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 7503cb50746..0a943840e17 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -1,4 +1,5 @@ #![feature(plugin)] +#![feature(const_fn)] #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] @@ -227,8 +228,20 @@ fn or_fun_call() { fn new() -> Foo { Foo } } + enum Enum { + A(i32), + } + + const fn make_const(i: i32) -> i32 { i } + fn make<T>() -> T { unimplemented!(); } + let with_enum = Some(Enum::A(1)); + with_enum.unwrap_or(Enum::A(5)); + + let with_const_fn = Some(1); + with_const_fn.unwrap_or(make_const(5)); + let with_constructor = Some(vec![1]); with_constructor.unwrap_or(make()); //~^ERROR use of `unwrap_or` -- cgit 1.4.1-3-g733a5 From a9bea1f52b09a66a04548b8e2b959245562db229 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 12 May 2016 19:11:13 +0200 Subject: Rustup to *1.10.0-nightly (22ac88f1a 2016-05-11)* --- src/attrs.rs | 2 +- src/cyclomatic_complexity.rs | 8 ++++---- src/derive.rs | 8 ++++---- src/escape.rs | 23 ++++++++++------------- src/methods.rs | 4 ++-- src/panic.rs | 2 +- src/types.rs | 4 ++-- src/utils/mod.rs | 30 +++++++++++++++--------------- src/utils/paths.rs | 2 +- 9 files changed, 40 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/attrs.rs b/src/attrs.rs index ca7813d3860..0cf62633de4 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -130,7 +130,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &paths::BEGIN_UNWIND) + !match_path(path, &paths::BEGIN_PANIC) } else { true } diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs index 858affd2bbb..8ae0d2c97c5 100644 --- a/src/cyclomatic_complexity.rs +++ b/src/cyclomatic_complexity.rs @@ -58,7 +58,7 @@ impl CyclomaticComplexity { divergence: 0, short_circuits: 0, returns: 0, - tcx: cx.tcx, + tcx: &cx.tcx, }; helper.visit_block(block); let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; @@ -117,15 +117,15 @@ impl LateLintPass for CyclomaticComplexity { } } -struct CCHelper<'a, 'tcx: 'a> { +struct CCHelper<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { match_arms: u64, divergence: u64, returns: u64, short_circuits: u64, // && and || - tcx: &'a ty::TyCtxt<'tcx>, + tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, } -impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> { +impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { fn visit_expr(&mut self, e: &'a Expr) { match e.node { ExprMatch(_, ref arms, _) => { diff --git a/src/derive.rs b/src/derive.rs index c9ac8f0a948..f08522953aa 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -86,7 +86,7 @@ impl LateLintPass for Derive { } /// Implementation of the `DERIVE_HASH_XOR_EQ` lint. -fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: &TraitRef, ty: ty::Ty<'tcx>, hash_is_automatically_derived: bool) { +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) { if_let_chain! {[ match_path(&trait_ref.path, &paths::HASH), let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() @@ -94,7 +94,7 @@ fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: & let peq_trait_def = cx.tcx.lookup_trait_def(peq_trait_def_id); // Look for the PartialEq implementations for `ty` - peq_trait_def.for_each_relevant_impl(&cx.tcx, ty, |impl_id| { + peq_trait_def.for_each_relevant_impl(cx.tcx, ty, |impl_id| { let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); if peq_is_automatically_derived == hash_is_automatically_derived { @@ -131,9 +131,9 @@ fn check_hash_peq<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, trait_ref: & 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) { let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - let subst_ty = ty.subst(cx.tcx, ¶meter_environment.free_substs); + let subst_ty = ty.subst(cx.tcx, parameter_environment.free_substs); - if subst_ty.moves_by_default(¶meter_environment, item.span) { + if subst_ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, item.span) { return; // ty is not Copy } diff --git a/src/escape.rs b/src/escape.rs index ff841b18066..b5172269a1e 100644 --- a/src/escape.rs +++ b/src/escape.rs @@ -1,11 +1,9 @@ use rustc::hir::*; use rustc::hir::intravisit as visit; use rustc::hir::map::Node::{NodeExpr, NodeStmt}; -use rustc::infer; use rustc::lint::*; use rustc::middle::expr_use_visitor::*; use rustc::middle::mem_categorization::{cmt, Categorization}; -use rustc::traits::ProjectionMode; use rustc::ty::adjustment::AutoAdjustment; use rustc::ty; use rustc::util::nodemap::NodeSet; @@ -42,7 +40,7 @@ fn is_non_trait_box(ty: ty::Ty) -> bool { } struct EscapeDelegate<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx>, + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, set: NodeSet, } @@ -55,15 +53,18 @@ impl LintPass for EscapePass { impl LateLintPass for EscapePass { fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(param_env), ProjectionMode::Any); + + let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env); let mut v = EscapeDelegate { - cx: cx, + tcx: cx.tcx, set: NodeSet(), }; + { let mut vis = ExprUseVisitor::new(&mut v, &infcx); vis.walk_fn(decl, body); } + for node in v.set { span_lint(cx, BOXED_LOCAL, @@ -75,7 +76,6 @@ impl LateLintPass for EscapePass { impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { - if let Categorization::Local(lid) = cmt.cat { if self.set.contains(&lid) { if let Move(DirectRefMove) = mode { @@ -87,7 +87,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { - let map = &self.cx.tcx.map; + let map = &self.tcx.map; if map.is_argument(consume_pat.id) { // Skip closure arguments if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) { @@ -132,8 +132,7 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { if let Categorization::Local(lid) = cmt.cat { if self.set.contains(&lid) { - if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.cx - .tcx + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx .tables .borrow() .adjustments @@ -148,13 +147,11 @@ impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } else if LoanCause::AddrOf == loan_cause { // &x - if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.cx - .tcx + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx .tables .borrow() .adjustments - .get(&self.cx - .tcx + .get(&self.tcx .map .get_parent_node(borrow_id)) { if adj.autoderefs <= 1 { diff --git a/src/methods.rs b/src/methods.rs index b47ae924bf0..c4ea1868d33 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -560,7 +560,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &Expr) { let parent = cx.tcx.map.get_parent(expr.id); let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); - if !ty.moves_by_default(¶meter_environment, expr.span) { + if !ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, expr.span) { span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); } } @@ -1044,5 +1044,5 @@ fn is_bool(ty: &Ty) -> bool { fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &Item) -> bool { let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - !ty.subst(cx.tcx, &env.free_substs).moves_by_default(&env, item.span) + !ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, item.span) } diff --git a/src/panic.rs b/src/panic.rs index 78499fa1a1a..d744d2a6308 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -33,7 +33,7 @@ impl LateLintPass for PanicPass { let ExprCall(ref fun, ref params) = ex.node, params.len() == 2, let ExprPath(None, ref path) = fun.node, - match_path(path, &paths::BEGIN_UNWIND), + match_path(path, &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/src/types.rs b/src/types.rs index f63538e974d..0a0c7252eb7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -105,7 +105,7 @@ declare_lint! { fn check_let_unit(cx: &LateContext, decl: &Decl) { if let DeclLocal(ref local) = decl.node { let bindtype = &cx.tcx.pat_ty(&local.pat).sty; - if *bindtype == ty::TyTuple(vec![]) { + if *bindtype == ty::TyTuple(&[]) { if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) { return; } @@ -162,7 +162,7 @@ impl LateLintPass for UnitCmp { if let ExprBinary(ref cmp, ref left, _) = expr.node { let op = cmp.node; let sty = &cx.tcx.expr_ty(left).sty; - if *sty == ty::TyTuple(vec![]) && op.is_comparison() { + if *sty == ty::TyTuple(&[]) && op.is_comparison() { let result = match op { BiEq | BiLe | BiGe => "true", _ => "false", diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3e77ffb2c24..10bfe56e925 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,7 +2,6 @@ use reexport::*; use rustc::hir::*; use rustc::hir::def_id::DefId; use rustc::hir::map::Node; -use rustc::infer; use rustc::lint::{LintContext, LateContext, Level, Lint}; use rustc::middle::cstore; use rustc::session::Session; @@ -274,15 +273,15 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let ty = cx.tcx.erase_regions(&ty); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any); - let obligation = traits::predicate_for_trait_def(cx.tcx, - traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params); - - traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) + cx.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| { + let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), + trait_id, + 0, + ty, + ty_params); + + traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) + }) } /// Match an `Expr` against a chain of methods, and return the matched `Expr`s. @@ -795,7 +794,7 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { /// Convenience function to get the return type of a function or `None` if the function diverges. pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> { let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); - let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(cx.tcx, ¶meter_env.free_substs); + let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(cx.tcx, parameter_env.free_substs); let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, &fn_sig); if let ty::FnConverging(ret_ty) = fn_sig.output { Some(ret_ty) @@ -809,10 +808,11 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Optio // 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 { let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item); - let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any); - let new_a = a.subst(infcx.tcx, &infcx.parameter_environment.free_substs); - let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs); - infcx.can_equate(&new_a, &new_b).is_ok() + cx.tcx.infer_ctxt(None, Some(parameter_env), ProjectionMode::Any).enter(|infcx| { + let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs); + let new_b = b.subst(infcx.tcx, infcx.parameter_environment.free_substs); + infcx.can_equate(&new_a, &new_b).is_ok() + }) } /// Recover the essential nodes of a desugared for loop: diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 2e6ceb50096..3db1e1c5572 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -1,6 +1,6 @@ //! This module contains paths to types and functions Clippy needs to know about. -pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"]; +pub const BEGIN_PANIC: [&'static str; 3] = ["std", "rt", "begin_panic"]; pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"]; pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"]; pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; -- cgit 1.4.1-3-g733a5 From 87df6ae8cb44d57af11ad342ec55a061d3fac199 Mon Sep 17 00:00:00 2001 From: Andreas Fackler <afck@users.noreply.github.com> Date: Thu, 12 May 2016 18:52:51 +0300 Subject: fix typos --- src/functions.rs | 4 ++-- tests/compile-fail/functions.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/functions.rs b/src/functions.rs index 37b65e471fa..d9334447226 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -8,7 +8,7 @@ use utils::span_lint; /// **What it does:** Check for functions with too many parameters. /// /// **Why is this bad?** Functions with lots of parameters are considered bad style and reduce -/// readability (“what does the 5th parameter means?”). Consider grouping some parameters into a +/// readability (“what does the 5th parameter mean?”). Consider grouping some parameters into a /// new type. /// /// **Known problems:** None. @@ -70,7 +70,7 @@ impl Functions { span_lint(cx, TOO_MANY_ARGUMENTS, span, - &format!("this function has to many arguments ({}/{})", args, self.threshold)); + &format!("this function has too many arguments ({}/{})", args, self.threshold)); } } } diff --git a/tests/compile-fail/functions.rs b/tests/compile-fail/functions.rs index d3d5eee335a..2cc16568600 100644 --- a/tests/compile-fail/functions.rs +++ b/tests/compile-fail/functions.rs @@ -7,13 +7,13 @@ fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) { - //~^ ERROR: this function has to many arguments (8/7) + //~^ ERROR: this function has too many arguments (8/7) } trait Foo { fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool); fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); - //~^ ERROR: this function has to many arguments (8/7) + //~^ ERROR: this function has too many arguments (8/7) } struct Bar; @@ -21,7 +21,7 @@ struct Bar; impl Bar { fn good_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} - //~^ ERROR: this function has to many arguments (8/7) + //~^ ERROR: this function has too many arguments (8/7) } // ok, we don’t want to warn implementations -- cgit 1.4.1-3-g733a5 From 1e897f1552aa490f821b7ebef949fa6ee873a04f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git1984941651981@oli-obk.de> Date: Fri, 13 May 2016 16:43:47 +0200 Subject: add a companion lint to `no_effect` with suggestions for partially effective statements --- CHANGELOG.md | 1 + README.md | 3 +- src/lib.rs | 1 + src/no_effect.rs | 78 +++++++++++++++++++++++- tests/compile-fail/absurd-extreme-comparisons.rs | 2 +- tests/compile-fail/arithmetic.rs | 12 ++-- tests/compile-fail/array_indexing.rs | 2 +- tests/compile-fail/bit_masks.rs | 4 +- tests/compile-fail/cast.rs | 2 +- tests/compile-fail/cmp_nan.rs | 2 +- tests/compile-fail/cmp_owned.rs | 1 + tests/compile-fail/copies.rs | 2 +- tests/compile-fail/eq_op.rs | 2 +- tests/compile-fail/float_cmp.rs | 2 +- tests/compile-fail/identity_op.rs | 2 +- tests/compile-fail/invalid_upcast_comparisons.rs | 2 +- tests/compile-fail/methods.rs | 1 + tests/compile-fail/modulo_one.rs | 2 +- tests/compile-fail/mut_mut.rs | 2 +- tests/compile-fail/neg_multiply.rs | 8 +-- tests/compile-fail/no_effect.rs | 75 +++++++++++++++++------ tests/compile-fail/unit_cmp.rs | 2 +- 22 files changed, 161 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index e442c4d7b1d..6e27b3909d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -215,6 +215,7 @@ All notable changes to this project will be documented in this file. [`unicode_not_nfc`]: https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc [`unit_cmp`]: https://github.com/Manishearth/rust-clippy/wiki#unit_cmp [`unnecessary_mut_passed`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed +[`unnecessary_operation`]: https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation [`unneeded_field_pattern`]: https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern [`unsafe_removed_from_name`]: https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name [`unstable_as_mut_slice`]: https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice diff --git a/README.md b/README.md index 658e2eb63a5..c7a839dc803 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 149 lints included in this crate: +There are 150 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -154,6 +154,7 @@ name [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) [unnecessary_mut_passed](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_mut_passed) | warn | an argument is passed as a mutable reference although the function/method only demands an immutable reference +[unnecessary_operation](https://github.com/Manishearth/rust-clippy/wiki#unnecessary_operation) | warn | outer expressions with no effect [unneeded_field_pattern](https://github.com/Manishearth/rust-clippy/wiki#unneeded_field_pattern) | warn | Struct fields are bound to a wildcard instead of using `..` [unsafe_removed_from_name](https://github.com/Manishearth/rust-clippy/wiki#unsafe_removed_from_name) | warn | unsafe removed from name [unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop diff --git a/src/lib.rs b/src/lib.rs index 37464e766b0..f1c815f0df0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -519,6 +519,7 @@ pub fn plugin_registrar(reg: &mut Registry) { neg_multiply::NEG_MULTIPLY, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, + no_effect::UNNECESSARY_OPERATION, non_expressive_names::MANY_SINGLE_CHAR_NAMES, open_options::NONSENSICAL_OPEN_OPTIONS, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, diff --git a/src/no_effect.rs b/src/no_effect.rs index d928de41578..593a6c4ad59 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,7 +1,8 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, PathResolution}; use rustc::hir::{Expr, Expr_, Stmt, StmtSemi}; -use utils::{in_macro, span_lint}; +use utils::{in_macro, span_lint, snippet_opt, span_lint_and_then}; +use std::ops::Deref; /// **What it does:** This lint checks for statements which have no effect. /// @@ -16,6 +17,19 @@ declare_lint! { "statements with no effect" } +/// **What it does:** This lint checks for expression statements that can be reduced to a sub-expression +/// +/// **Why is this bad?** Expressions by themselves often have no side-effects. Having such expressions reduces redability. +/// +/// **Known problems:** None. +/// +/// **Example:** `compute_array()[0];` +declare_lint! { + pub UNNECESSARY_OPERATION, + Warn, + "outer expressions with no effect" +} + fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { if in_macro(cx, expr.span) { return false; @@ -68,7 +82,7 @@ pub struct NoEffectPass; impl LintPass for NoEffectPass { fn get_lints(&self) -> LintArray { - lint_array!(NO_EFFECT) + lint_array!(NO_EFFECT, UNNECESSARY_OPERATION) } } @@ -77,7 +91,65 @@ impl LateLintPass for NoEffectPass { if let StmtSemi(ref expr, _) = stmt.node { if has_no_effect(cx, expr) { span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect"); + } else if let Some(reduced) = reduce_expression(cx, expr) { + let mut snippet = String::new(); + for e in reduced { + if in_macro(cx, e.span) { + return; + } + if let Some(snip) = snippet_opt(cx, e.span) { + snippet.push_str(&snip); + snippet.push(';'); + } else { + return; + } + } + span_lint_and_then(cx, UNNECESSARY_OPERATION, stmt.span, "statement can be reduced", |db| { + db.span_suggestion(stmt.span, "replace it with", snippet); + }); + } + } + } +} + + +fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Expr>> { + if in_macro(cx, expr.span) { + return None; + } + match expr.node { + Expr_::ExprIndex(ref a, ref b) | + Expr_::ExprBinary(_, ref a, ref b) => Some(vec![&**a, &**b]), + Expr_::ExprVec(ref v) | + Expr_::ExprTup(ref v) => Some(v.iter().map(Deref::deref).collect()), + Expr_::ExprRepeat(ref inner, _) | + Expr_::ExprCast(ref inner, _) | + Expr_::ExprType(ref inner, _) | + Expr_::ExprUnary(_, ref inner) | + Expr_::ExprField(ref inner, _) | + Expr_::ExprTupField(ref inner, _) | + Expr_::ExprAddrOf(_, ref inner) | + Expr_::ExprBox(ref inner) => 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(args.iter().map(Deref::deref).collect()), + _ => None, + } + } + Expr_::ExprBlock(ref block) => { + if block.stmts.is_empty() { + block.expr.as_ref().and_then(|e| if e.span == expr.span { + // in case of compiler-inserted signaling blocks + reduce_expression(cx, e) + } else { + Some(vec![e]) + }) + } else { + None } } + _ => None, } } diff --git a/tests/compile-fail/absurd-extreme-comparisons.rs b/tests/compile-fail/absurd-extreme-comparisons.rs index 7e2ad1fede5..f1e4a692800 100644 --- a/tests/compile-fail/absurd-extreme-comparisons.rs +++ b/tests/compile-fail/absurd-extreme-comparisons.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(absurd_extreme_comparisons)] -#![allow(unused, eq_op, no_effect)] +#![allow(unused, eq_op, no_effect, unnecessary_operation)] fn main() { const Z: u32 = 0; diff --git a/tests/compile-fail/arithmetic.rs b/tests/compile-fail/arithmetic.rs index 54ac65970ae..5479c55e11e 100644 --- a/tests/compile-fail/arithmetic.rs +++ b/tests/compile-fail/arithmetic.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(integer_arithmetic, float_arithmetic)] -#![allow(unused, shadow_reuse, shadow_unrelated, no_effect)] +#![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)] fn main() { let i = 1i32; 1 + i; //~ERROR integer arithmetic detected @@ -11,17 +11,17 @@ fn main() { i / 2; // no error, this is part of the expression in the preceding line i - 2 + 2 - i; //~ERROR integer arithmetic detected -i; //~ERROR integer arithmetic detected - + i & 1; // no wrapping - i | 1; + i | 1; i ^ 1; i >> 1; i << 1; - + let f = 1.0f32; - + f * 2.0; //~ERROR floating-point arithmetic detected - + 1.0 + f; //~ERROR floating-point arithmetic detected f * 2.0; //~ERROR floating-point arithmetic detected f / 2.0; //~ERROR floating-point arithmetic detected diff --git a/tests/compile-fail/array_indexing.rs b/tests/compile-fail/array_indexing.rs index 35fadf8c1e4..dacb72ee8ac 100644 --- a/tests/compile-fail/array_indexing.rs +++ b/tests/compile-fail/array_indexing.rs @@ -3,7 +3,7 @@ #![deny(indexing_slicing)] #![deny(out_of_bounds_indexing)] -#![allow(no_effect)] +#![allow(no_effect, unnecessary_operation)] fn main() { let x = [1,2,3,4]; diff --git a/tests/compile-fail/bit_masks.rs b/tests/compile-fail/bit_masks.rs index 98135295862..79772840c73 100644 --- a/tests/compile-fail/bit_masks.rs +++ b/tests/compile-fail/bit_masks.rs @@ -5,7 +5,7 @@ const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; #[deny(bad_bit_mask)] -#[allow(ineffective_bit_mask, identity_op, no_effect)] +#[allow(ineffective_bit_mask, identity_op, no_effect, unnecessary_operation)] fn main() { let x = 5; @@ -45,7 +45,7 @@ fn main() { } #[deny(ineffective_bit_mask)] -#[allow(bad_bit_mask, no_effect)] +#[allow(bad_bit_mask, no_effect, unnecessary_operation)] fn ineffective() { let x = 5; diff --git a/tests/compile-fail/cast.rs b/tests/compile-fail/cast.rs index 0f44fa2c1fd..d0ea5f40789 100644 --- a/tests/compile-fail/cast.rs +++ b/tests/compile-fail/cast.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap)] -#[allow(no_effect)] +#[allow(no_effect, unnecessary_operation)] fn main() { // Test cast_precision_loss 1i32 as f32; //~ERROR casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide) diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs index d2188130a61..8d173665a24 100644 --- a/tests/compile-fail/cmp_nan.rs +++ b/tests/compile-fail/cmp_nan.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #[deny(cmp_nan)] -#[allow(float_cmp, no_effect)] +#[allow(float_cmp, no_effect, unnecessary_operation)] fn main() { let x = 5f32; x == std::f32::NAN; //~ERROR doomed comparison with NAN diff --git a/tests/compile-fail/cmp_owned.rs b/tests/compile-fail/cmp_owned.rs index eb4070d8fd6..f7c7824e9d1 100644 --- a/tests/compile-fail/cmp_owned.rs +++ b/tests/compile-fail/cmp_owned.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #[deny(cmp_owned)] +#[allow(unnecessary_operation)] fn main() { fn with_to_string(x : &str) { x != "foo".to_string(); diff --git a/tests/compile-fail/copies.rs b/tests/compile-fail/copies.rs index 68756a57cc7..bbdd73dc0c8 100644 --- a/tests/compile-fail/copies.rs +++ b/tests/compile-fail/copies.rs @@ -1,7 +1,7 @@ #![feature(plugin, inclusive_range_syntax)] #![plugin(clippy)] -#![allow(dead_code, no_effect)] +#![allow(dead_code, no_effect, unnecessary_operation)] #![allow(let_and_return)] #![allow(needless_return)] #![allow(unused_variables)] diff --git a/tests/compile-fail/eq_op.rs b/tests/compile-fail/eq_op.rs index 443bbbaacd3..768eadd00eb 100644 --- a/tests/compile-fail/eq_op.rs +++ b/tests/compile-fail/eq_op.rs @@ -3,7 +3,7 @@ #[deny(eq_op)] #[allow(identity_op)] -#[allow(no_effect, unused_variables)] +#[allow(no_effect, unused_variables, unnecessary_operation)] #[deny(nonminimal_bool)] fn main() { // simple values and comparisons diff --git a/tests/compile-fail/float_cmp.rs b/tests/compile-fail/float_cmp.rs index d1ecb37cdd5..85df1ded5ac 100644 --- a/tests/compile-fail/float_cmp.rs +++ b/tests/compile-fail/float_cmp.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(float_cmp)] -#![allow(unused, no_effect)] +#![allow(unused, no_effect, unnecessary_operation)] use std::ops::Add; diff --git a/tests/compile-fail/identity_op.rs b/tests/compile-fail/identity_op.rs index 28873ee6b73..329c4a6bbf4 100644 --- a/tests/compile-fail/identity_op.rs +++ b/tests/compile-fail/identity_op.rs @@ -5,7 +5,7 @@ const ONE : i64 = 1; const NEG_ONE : i64 = -1; const ZERO : i64 = 0; -#[allow(eq_op, no_effect)] +#[allow(eq_op, no_effect, unnecessary_operation)] #[deny(identity_op)] fn main() { let x = 0; diff --git a/tests/compile-fail/invalid_upcast_comparisons.rs b/tests/compile-fail/invalid_upcast_comparisons.rs index 443dd89aab9..9635f3afede 100644 --- a/tests/compile-fail/invalid_upcast_comparisons.rs +++ b/tests/compile-fail/invalid_upcast_comparisons.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(invalid_upcast_comparisons)] -#![allow(unused, eq_op, no_effect)] +#![allow(unused, eq_op, no_effect, unnecessary_operation)] fn main() { let zero: u32 = 0; let u8_max: u8 = 255; diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 0a943840e17..88a1e7c4cf2 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -341,6 +341,7 @@ struct MyErrorWithParam<T> { x: T } +#[allow(unnecessary_operation)] fn starts_with() { "".chars().next() == Some(' '); //~^ ERROR starts_with diff --git a/tests/compile-fail/modulo_one.rs b/tests/compile-fail/modulo_one.rs index e84209a6d1e..496c1c60d5f 100644 --- a/tests/compile-fail/modulo_one.rs +++ b/tests/compile-fail/modulo_one.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] #![deny(modulo_one)] -#![allow(no_effect)] +#![allow(no_effect, unnecessary_operation)] fn main() { 10 % 1; //~ERROR any number modulo 1 will be 0 diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 0db9cb3bdef..865574eaec0 100644 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused, no_effect)] +#![allow(unused, no_effect, unnecessary_operation)] //#![plugin(regex_macros)] //extern crate regex; diff --git a/tests/compile-fail/neg_multiply.rs b/tests/compile-fail/neg_multiply.rs index 9deb38920de..90c63c5f263 100644 --- a/tests/compile-fail/neg_multiply.rs +++ b/tests/compile-fail/neg_multiply.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(neg_multiply)] -#![allow(no_effect)] +#![allow(no_effect, unnecessary_operation)] use std::ops::Mul; @@ -10,7 +10,7 @@ struct X; impl Mul<isize> for X { type Output = X; - + fn mul(self, _r: isize) -> Self { self } @@ -18,7 +18,7 @@ impl Mul<isize> for X { impl Mul<X> for isize { type Output = X; - + fn mul(self, _r: X) -> X { X } @@ -34,7 +34,7 @@ fn main() { //~^ ERROR Negation by multiplying with -1 -1 * -1; // should be ok - + X * -1; // should be ok -1 * X; // should also be ok } diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index 344c82f3307..ce6daa8d562 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -1,7 +1,7 @@ #![feature(plugin, box_syntax, inclusive_range_syntax)] #![plugin(clippy)] -#![deny(no_effect)] +#![deny(no_effect, unnecessary_operation)] #![allow(dead_code)] #![allow(path_statements)] @@ -50,22 +50,59 @@ fn main() { // Do not warn get_number(); - Tuple(get_number()); - Struct { field: get_number() }; - Struct { ..get_struct() }; - Enum::Tuple(get_number()); - Enum::Struct { field: get_number() }; - 5 + get_number(); - *&get_number(); - &get_number(); - (5, 6, get_number()); - box get_number(); - get_number()..; - ..get_number(); - 5..get_number(); - [42, get_number()]; - [42, 55][get_number() as usize]; - (42, get_number()).1; - [get_number(); 55]; - [42; 55][get_number() as usize]; + + Tuple(get_number()); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + Struct { field: get_number() }; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + Struct { ..get_struct() }; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + Enum::Tuple(get_number()); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + Enum::Struct { field: get_number() }; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + 5 + get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION 5;get_number(); + *&get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION &get_number(); + &get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + (5, 6, get_number()); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION 5;6;get_number(); + box get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + get_number()..; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + ..get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + 5..get_number(); //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION 5;get_number(); + [42, get_number()]; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION 42;get_number(); + [42, 55][get_number() as usize]; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION [42, 55];get_number() as usize; + (42, get_number()).1; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION 42;get_number(); + [get_number(); 55]; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); + [42; 55][get_number() as usize]; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION [42; 55];get_number() as usize; } diff --git a/tests/compile-fail/unit_cmp.rs b/tests/compile-fail/unit_cmp.rs index 1a28953ace1..13095ee6bfb 100644 --- a/tests/compile-fail/unit_cmp.rs +++ b/tests/compile-fail/unit_cmp.rs @@ -2,7 +2,7 @@ #![plugin(clippy)] #![deny(unit_cmp)] -#![allow(no_effect)] +#![allow(no_effect, unnecessary_operation)] #[derive(PartialEq)] pub struct ContainsUnit(()); // should be fine -- cgit 1.4.1-3-g733a5 From f2f5fefd0017ec22a306e6af85caa9468209a94d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 16 May 2016 22:39:16 +0530 Subject: Allow invalid upcast comparisons --- README.md | 2 +- src/lib.rs | 2 +- src/types.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index c7a839dc803..02b7365e890 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ name [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [integer_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic) | allow | Any integer arithmetic statement [invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations -[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | warn | a comparison involving an upcast which is always true or false +[invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | allow | a comparison involving an upcast which is always true or false [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended [len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()` diff --git a/src/lib.rs b/src/lib.rs index f1c815f0df0..695491e9523 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -427,6 +427,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::CAST_POSSIBLE_WRAP, types::CAST_PRECISION_LOSS, types::CAST_SIGN_LOSS, + types::INVALID_UPCAST_COMPARISONS, unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, ]); @@ -543,7 +544,6 @@ pub fn plugin_registrar(reg: &mut Registry) { types::ABSURD_EXTREME_COMPARISONS, types::BOX_VEC, types::CHAR_LIT_AS_U8, - types::INVALID_UPCAST_COMPARISONS, types::LET_UNIT_VALUE, types::LINKEDLIST, types::TYPE_COMPLEXITY, diff --git a/src/types.rs b/src/types.rs index 0a0c7252eb7..c4b810a7880 100644 --- a/src/types.rs +++ b/src/types.rs @@ -777,11 +777,11 @@ impl LateLintPass for AbsurdExtremeComparisons { /// /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` will mistakenly imply that it is possible for `x` to be outside the range of `u8`. /// -/// **Known problems:** None +/// **Known problems:** https://github.com/Manishearth/rust-clippy/issues/886 /// /// **Example:** `let x : u8 = ...; (x as u32) > 300` declare_lint! { - pub INVALID_UPCAST_COMPARISONS, Warn, + pub INVALID_UPCAST_COMPARISONS, Allow, "a comparison involving an upcast which is always true or false" } -- cgit 1.4.1-3-g733a5 From 6a309af2f3855ed16f4f914ccbe13bce7de6c59a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 16 May 2016 23:12:55 +0530 Subject: Don't panic if cargo rustc fails --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 695491e9523..d3940575659 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,13 +122,11 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); let path = std::env::current_exe().expect("current executable path invalid"); - let run = std::process::Command::new("cargo") + std::process::Command::new("cargo") .args(&args) .env("RUSTC", path) .spawn().expect("could not run cargo") - .wait().expect("failed to wait for cargo?") - .success(); - assert!(run, "cargo rustc failed"); + .wait().expect("failed to wait for cargo?"); } else { let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() -- cgit 1.4.1-3-g733a5 From ca05e93c105f6bd484258e3dca92bbd99d661e44 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 17 May 2016 23:25:20 +0200 Subject: Rustup to *1.10.0-nightly (cd6a40017 2016-05-16)* --- src/len_zero.rs | 6 +- src/lifetimes.rs | 33 +++------ src/methods.rs | 152 ++++++++++++++++++++-------------------- tests/compile-fail/unused_lt.rs | 6 ++ 4 files changed, 94 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/len_zero.rs b/src/len_zero.rs index 9dae856764a..b6dea831690 100644 --- a/src/len_zero.rs +++ b/src/len_zero.rs @@ -126,10 +126,10 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { } fn is_self_sig(sig: &MethodSig) -> bool { - if let SelfStatic = sig.explicit_self.node { - false - } else { + if sig.decl.has_self() { sig.decl.inputs.len() == 1 + } else { + false } } diff --git a/src/lifetimes.rs b/src/lifetimes.rs index b9771e18ffc..797e9708b60 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -46,19 +46,19 @@ impl LintPass for LifetimePass { impl LateLintPass for LifetimePass { fn check_item(&mut self, cx: &LateContext, item: &Item) { if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node { - check_fn_inner(cx, decl, None, generics, item.span); + check_fn_inner(cx, decl, generics, item.span); } } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { if let ImplItemKind::Method(ref sig, _) = item.node { - check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); + check_fn_inner(cx, &sig.decl, &sig.generics, item.span); } } fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { if let MethodTraitItem(ref sig, _) = item.node { - check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self), &sig.generics, item.span); + check_fn_inner(cx, &sig.decl, &sig.generics, item.span); } } } @@ -87,7 +87,7 @@ fn bound_lifetimes(bound: &TyParamBound) -> Option<HirVec<&Lifetime>> { } } -fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, generics: &Generics, span: Span) { +fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &Generics, span: Span) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } @@ -96,16 +96,16 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>, g .iter() .flat_map(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); - if could_use_elision(cx, decl, slf, &generics.lifetimes, bounds_lts) { + if could_use_elision(cx, decl, &generics.lifetimes, bounds_lts) { span_lint(cx, NEEDLESS_LIFETIMES, span, "explicit lifetimes given in parameter types where they could be elided"); } - report_extra_lifetimes(cx, decl, generics, slf); + report_extra_lifetimes(cx, decl, generics); } -fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>, +fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, named_lts: &[LifetimeDef], bounds_lts: T) -> bool { // There are two scenarios where elision works: @@ -121,15 +121,6 @@ fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, fun let mut input_visitor = RefVisitor::new(cx); let mut output_visitor = RefVisitor::new(cx); - // extract lifetime in "self" argument for methods (there is a "self" argument - // in func.inputs, but its type is TyInfer) - if let Some(slf) = slf { - match slf.node { - SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt), - SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty), - _ => (), - } - } // extract lifetimes in input argument types for arg in &func.inputs { input_visitor.visit_ty(&arg.ty); @@ -340,7 +331,7 @@ impl<'v> Visitor<'v> for LifetimeChecker { } } -fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics, slf: Option<&ExplicitSelf>) { +fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { let hs = generics.lifetimes .iter() .map(|lt| (lt.lifetime.name, lt.lifetime.span)) @@ -350,14 +341,6 @@ fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics, walk_generics(&mut checker, generics); walk_fn_decl(&mut checker, func); - if let Some(slf) = slf { - match slf.node { - SelfRegion(Some(ref lt), _, _) => checker.visit_lifetime(lt), - SelfExplicit(ref t, _) => walk_ty(&mut checker, t), - _ => (), - } - } - for &v in checker.0.values() { span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); } diff --git a/src/methods.rs b/src/methods.rs index c4ea1868d33..ecbdb62f05e 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -1,4 +1,4 @@ -use rustc::hir::*; +use rustc::hir; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::middle::const_qualif::ConstQualif; @@ -335,13 +335,13 @@ impl LintPass for MethodsPass { } impl LateLintPass for MethodsPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { if in_macro(cx, expr.span) { return; } match expr.node { - ExprMethodCall(name, _, ref args) => { + hir::ExprMethodCall(name, _, ref args) => { // Chain calls if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { lint_unwrap(cx, expr, arglists[0]); @@ -384,37 +384,36 @@ impl LateLintPass for MethodsPass { _ => (), } } - ExprBinary(op, ref lhs, ref rhs) if op.node == BiEq || op.node == BiNe => { - if !lint_chars_next(cx, expr, lhs, rhs, op.node == BiEq) { - lint_chars_next(cx, expr, rhs, lhs, op.node == BiEq); + 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_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if in_external_macro(cx, item.span) { return; } - if let ItemImpl(_, _, _, None, _, ref items) = item.node { + if let hir::ItemImpl(_, _, _, None, _, ref items) = item.node { for implitem in items { let name = implitem.name; - if let ImplItemKind::Method(ref sig, _) = implitem.node { + if_let_chain! {[ + let hir::ImplItemKind::Method(ref sig, _) = implitem.node, + let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), + ], { // check missing trait implementations for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { - if_let_chain! { - [ - name.as_str() == method_name, - sig.decl.inputs.len() == n_args, - out_type.matches(&sig.decl.output), - self_kind.matches(&sig.explicit_self.node, false) - ], { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( - "defining a method called `{}` on this type; consider implementing \ - the `{}` trait or choosing a less ambiguous name", name, trait_name)); - } + if name.as_str() == method_name && + sig.decl.inputs.len() == n_args && + out_type.matches(&sig.decl.output) && + self_kind.matches(&explicit_self, false) { + span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( + "defining a method called `{}` on this type; consider implementing \ + the `{}` trait or choosing a less ambiguous name", name, trait_name)); } } @@ -422,16 +421,19 @@ impl LateLintPass for MethodsPass { let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; let is_copy = is_copy(cx, ty, item); for &(ref conv, self_kinds) in &CONVENTIONS { - if conv.check(&name.as_str()) && - !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) { - let lint = if item.vis == Visibility::Public { + if_let_chain! {[ + conv.check(&name.as_str()), + let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), + !self_kinds.iter().any(|k| k.matches(&explicit_self, is_copy)), + ], { + let lint = if item.vis == hir::Visibility::Public { WRONG_PUB_SELF_CONVENTION } else { WRONG_SELF_CONVENTION }; span_lint(cx, lint, - sig.explicit_self.span, + explicit_self.span, &format!("methods called `{}` usually take {}; consider choosing a less \ ambiguous name", conv, @@ -439,7 +441,7 @@ impl LateLintPass for MethodsPass { .map(|k| k.description()) .collect::<Vec<_>>() .join(" or "))); - } + }} } let ret_ty = return_ty(cx, implitem.id); @@ -447,19 +449,19 @@ impl LateLintPass for MethodsPass { !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { span_lint(cx, NEW_RET_NO_SELF, - sig.explicit_self.span, + explicit_self.span, "methods called `new` usually return `Self`"); } } - } + }} } } } /// Checks for the `OR_FUN_CALL` lint. -fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) { +fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[P<hir::Expr>]) { /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. - fn check_unwrap_or_default(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, + 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 { @@ -467,7 +469,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } if name == "unwrap_or" { - if let ExprPath(_, ref path) = fun.node { + if let hir::ExprPath(_, ref path) = fun.node { let path: &str = &path.segments .last() .expect("A path must have at least one segment") @@ -501,7 +503,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } /// Check for `*or(foo())`. - fn check_general_case(cx: &LateContext, name: &str, fun: &Expr, self_expr: &Expr, arg: &Expr, or_has_args: bool, + 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? @@ -545,7 +547,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } if args.len() == 2 { - if let ExprCall(ref fun, ref or_args) = args[1].node { + if let hir::ExprCall(ref fun, ref or_args) = args[1].node { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { check_general_case(cx, name, fun, &args[0], &args[1], or_has_args, expr.span); @@ -555,7 +557,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>]) } /// Checks for the `CLONE_ON_COPY` lint. -fn lint_clone_on_copy(cx: &LateContext, expr: &Expr) { +fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr) { let ty = cx.tcx.expr_ty(expr); let parent = cx.tcx.map.get_parent(expr.id); let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); @@ -566,7 +568,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &Expr) { } /// Checks for the `CLONE_DOUBLE_REF` lint. -fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr, ty: ty::Ty) { +fn lint_clone_double_ref(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, ty: ty::Ty) { if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { if let ty::TyRef(..) = inner.sty { let mut db = span_lint(cx, @@ -582,7 +584,7 @@ fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr, ty: ty::Ty) } } -fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { +fn lint_extend(cx: &LateContext, expr: &hir::Expr, args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); if !match_type(cx, obj_ty, &paths::VEC) { return; @@ -599,11 +601,11 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) { } } -fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) { +fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) { if_let_chain!{[ - let ExprCall(ref fun, ref args) = new.node, + let hir::ExprCall(ref fun, ref args) = new.node, args.len() == 1, - let ExprPath(None, ref path) = fun.node, + let hir::ExprPath(None, ref path) = fun.node, match_path(path, &paths::CSTRING_NEW), ], { span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, @@ -615,7 +617,7 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &Expr, new: &Expr, unwrap: &Expr) }} } -fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { +fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { match ty.sty { ty::TySlice(_) => true, @@ -626,7 +628,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, _ => false, } } - if let ExprMethodCall(name, _, ref args) = expr.node { + if let hir::ExprMethodCall(name, _, ref args) = expr.node { if &name.node.as_str() == &"iter" && may_slice(cx, &cx.tcx.expr_ty(&args[0])) { Some((args[0].span, "&")) } else { @@ -651,7 +653,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &Expr, ty: &ty::Ty) -> Option<(Span, #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `unwrap()` for `Option`s and `Result`s -fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { +fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &MethodArgs) { let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); let mess = if match_type(cx, obj_ty, &paths::OPTION) { @@ -677,7 +679,7 @@ fn lint_unwrap(cx: &LateContext, expr: &Expr, unwrap_args: &MethodArgs) { #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `ok().expect()` for `Result`s -fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { +fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &MethodArgs) { // lint if the caller of `ok()` is a `Result` if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &paths::RESULT) { let result_type = cx.tcx.expr_ty(&ok_args[0]); @@ -695,7 +697,7 @@ fn lint_ok_expect(cx: &LateContext, expr: &Expr, ok_args: &MethodArgs) { #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { +fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { // lint message @@ -726,7 +728,7 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwr #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `map().unwrap_or_else()` for `Option`s -fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { // lint message @@ -757,7 +759,7 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &Expr, map_args: &MethodArgs, #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint use of `filter().next() for Iterators` -fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { +fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &MethodArgs) { // 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)` \ @@ -780,7 +782,7 @@ fn lint_filter_next(cx: &LateContext, expr: &Expr, filter_args: &MethodArgs) { #[allow(ptr_arg)] // Type of MethodArgs is potentially a Vec /// lint searching an Iterator followed by `is_some()` -fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, search_args: &MethodArgs, +fn lint_search_is_some(cx: &LateContext, expr: &hir::Expr, search_method: &str, search_args: &MethodArgs, is_some_args: &MethodArgs) { // lint if caller of search is an Iterator if match_trait_method(cx, &*is_some_args[0], &paths::ITERATOR) { @@ -803,12 +805,12 @@ fn lint_search_is_some(cx: &LateContext, expr: &Expr, search_method: &str, searc } /// Checks for the `CHARS_NEXT_CMP` lint. -fn lint_chars_next(cx: &LateContext, expr: &Expr, chain: &Expr, other: &Expr, eq: bool) -> bool { +fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other: &hir::Expr, eq: bool) -> bool { if_let_chain! {[ let Some(args) = method_chain_args(chain, &["chars", "next"]), - let ExprCall(ref fun, ref arg_char) = other.node, + let hir::ExprCall(ref fun, ref arg_char) = other.node, arg_char.len() == 1, - let ExprPath(None, ref path) = fun.node, + let hir::ExprPath(None, ref path) = fun.node, path.segments.len() == 1 && path.segments[0].identifier.name.as_str() == "Some" ], { let self_ty = walk_ptrs_ty(cx.tcx.expr_ty_adjusted(&args[0][0])); @@ -838,7 +840,7 @@ fn lint_chars_next(cx: &LateContext, expr: &Expr, chain: &Expr, other: &Expr, eq } /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern(cx: &LateContext, expr: &Expr, arg: &Expr) { +fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { if let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, arg, ExprTypeChecked, None) { if r.len() == 1 { let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); @@ -954,26 +956,26 @@ enum SelfKind { } impl SelfKind { - fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool { - match (self, slf) { - (&SelfKind::Value, &SelfValue(_)) | - (&SelfKind::Ref, &SelfRegion(_, Mutability::MutImmutable, _)) | - (&SelfKind::RefMut, &SelfRegion(_, Mutability::MutMutable, _)) | - (&SelfKind::No, &SelfStatic) => true, - (&SelfKind::Ref, &SelfValue(_)) | - (&SelfKind::RefMut, &SelfValue(_)) => allow_value_for_ref, - (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), + fn matches(self, slf: &hir::ExplicitSelf, allow_value_for_ref: bool) -> bool { + match (self, &slf.node) { + (SelfKind::Value, &hir::SelfKind::Value(_)) | + (SelfKind::Ref, &hir::SelfKind::Region(_, hir::Mutability::MutImmutable)) | + (SelfKind::RefMut, &hir::SelfKind::Region(_, hir::Mutability::MutMutable)) => true, + (SelfKind::Ref, &hir::SelfKind::Value(_)) | + (SelfKind::RefMut, &hir::SelfKind::Value(_)) => allow_value_for_ref, + (_, &hir::SelfKind::Explicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), + _ => false, } } - fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool { + fn matches_explicit_type(self, ty: &hir::Ty, allow_value_for_ref: bool) -> bool { match (self, &ty.node) { - (&SelfKind::Value, &TyPath(..)) | - (&SelfKind::Ref, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) | - (&SelfKind::RefMut, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true, - (&SelfKind::Ref, &TyPath(..)) | - (&SelfKind::RefMut, &TyPath(..)) => allow_value_for_ref, + (SelfKind::Value, &hir::TyPath(..)) | + (SelfKind::Ref, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutImmutable, .. })) | + (SelfKind::RefMut, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutMutable, .. })) => true, + (SelfKind::Ref, &hir::TyPath(..)) | + (SelfKind::RefMut, &hir::TyPath(..)) => allow_value_for_ref, _ => false, } } @@ -1015,14 +1017,14 @@ enum OutType { } impl OutType { - fn matches(&self, ty: &FunctionRetTy) -> bool { + fn matches(&self, ty: &hir::FunctionRetTy) -> bool { match (self, ty) { - (&OutType::Unit, &DefaultReturn(_)) => true, - (&OutType::Unit, &Return(ref ty)) if ty.node == TyTup(vec![].into()) => true, - (&OutType::Bool, &Return(ref ty)) if is_bool(ty) => true, - (&OutType::Any, &Return(ref ty)) if ty.node != TyTup(vec![].into()) => true, - (&OutType::Ref, &Return(ref ty)) => { - if let TyRptr(_, _) = ty.node { + (&OutType::Unit, &hir::DefaultReturn(_)) => true, + (&OutType::Unit, &hir::Return(ref ty)) if ty.node == hir::TyTup(vec![].into()) => true, + (&OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true, + (&OutType::Any, &hir::Return(ref ty)) if ty.node != hir::TyTup(vec![].into()) => true, + (&OutType::Ref, &hir::Return(ref ty)) => { + if let hir::TyRptr(_, _) = ty.node { true } else { false @@ -1033,8 +1035,8 @@ impl OutType { } } -fn is_bool(ty: &Ty) -> bool { - if let TyPath(None, ref p) = ty.node { +fn is_bool(ty: &hir::Ty) -> bool { + if let hir::TyPath(None, ref p) = ty.node { if match_path(p, &["bool"]) { return true; } @@ -1042,7 +1044,7 @@ fn is_bool(ty: &Ty) -> bool { false } -fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &Item) -> bool { +fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &hir::Item) -> bool { let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); !ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, item.span) } diff --git a/tests/compile-fail/unused_lt.rs b/tests/compile-fail/unused_lt.rs index a35718b5848..19502720993 100644 --- a/tests/compile-fail/unused_lt.rs +++ b/tests/compile-fail/unused_lt.rs @@ -44,6 +44,12 @@ impl<'a> Foo<'a> for u8 { } } +struct Bar; + +impl Bar { + fn x<'a>(&self) {} //~ ERROR this lifetime +} + // test for #489 (used lifetimes in bounds) pub fn parse<'a, I: Iterator<Item=&'a str>>(_it: &mut I) { unimplemented!() -- cgit 1.4.1-3-g733a5 From 2a5416d662724b8e8ba68aeb4069aa37e7a406d5 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 19 May 2016 23:14:34 +0200 Subject: Rustup to *1.10.0-nightly (9c6904ca1 2016-05-18)* --- README.md | 2 +- src/blacklisted_name.rs | 4 +- src/copies.rs | 2 +- src/eta_reduction.rs | 2 +- src/lib.rs | 2 +- src/loops.rs | 26 +++++------ src/map_clone.rs | 15 ++++--- src/methods.rs | 3 +- src/misc.rs | 63 ++++++++++++++++----------- src/overflow_check_conditional.rs | 4 +- src/shadow.rs | 10 ++--- src/swap.rs | 2 +- src/unsafe_removed_from_name.rs | 2 +- src/unused_label.rs | 4 +- src/utils/hir.rs | 22 +++++----- src/utils/mod.rs | 2 +- tests/compile-fail/used_underscore_binding.rs | 7 +-- 17 files changed, 93 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 02b7365e890..6843afb4ede 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ name [unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting -[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore +[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore [useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types [useless_vec](https://github.com/Manishearth/rust-clippy/wiki#useless_vec) | warn | useless `vec!` diff --git a/src/blacklisted_name.rs b/src/blacklisted_name.rs index b515da000ee..5cb84f62651 100644 --- a/src/blacklisted_name.rs +++ b/src/blacklisted_name.rs @@ -35,11 +35,11 @@ impl LintPass for BlackListedName { impl LateLintPass for BlackListedName { fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { if let PatKind::Ident(_, ref ident, _) = pat.node { - if self.blacklist.iter().any(|s| s == &*ident.node.name.as_str()) { + if self.blacklist.iter().any(|s| s == &*ident.node.as_str()) { span_lint(cx, BLACKLISTED_NAME, pat.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.node.name)); + &format!("use of a blacklisted/placeholder name `{}`", ident.node)); } } } diff --git a/src/copies.rs b/src/copies.rs index aa9f243e8c7..4344ba461dd 100644 --- a/src/copies.rs +++ b/src/copies.rs @@ -193,7 +193,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned } } PatKind::Ident(_, ref ident, ref as_pat) => { - if let Entry::Vacant(v) = map.entry(ident.node.name.as_str()) { + if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { v.insert(cx.tcx.pat_ty(pat)); } if let Some(ref as_pat) = *as_pat { diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs index c9a9ef85ede..f73b6cfed2d 100644 --- a/src/eta_reduction.rs +++ b/src/eta_reduction.rs @@ -77,7 +77,7 @@ fn check_closure(cx: &LateContext, expr: &Expr) { // If it's a proper path, it can't be a local variable return; } - if p.segments[0].identifier != ident.node { + if p.segments[0].name != ident.node { // The two idents should be the same return; } diff --git a/src/lib.rs b/src/lib.rs index d3940575659..888abbc92c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -411,6 +411,7 @@ pub fn plugin_registrar(reg: &mut Registry) { methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, + misc::USED_UNDERSCORE_BINDING, mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, non_expressive_names::SIMILAR_NAMES, @@ -505,7 +506,6 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::MODULO_ONE, misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, - misc::USED_UNDERSCORE_BINDING, misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::REDUNDANT_CLOSURE_CALL, misc_early::UNNEEDED_FIELD_PATTERN, diff --git a/src/loops.rs b/src/loops.rs index 2384c845303..061b8efaa64 100644 --- a/src/loops.rs +++ b/src/loops.rs @@ -286,7 +286,7 @@ impl LateLintPass for LoopsPass { 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.identifier.name.as_str() == "Some" && + lhs_constructor.name.as_str() == "Some" && !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, "_"); @@ -333,7 +333,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex if let PatKind::Ident(_, ref ident, _) = pat.node { let mut visitor = VarVisitor { cx: cx, - var: ident.node.name, + var: ident.node, indexed: HashMap::new(), nonindex: false, }; @@ -378,9 +378,9 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex expr.span, &format!("the loop variable `{}` is used to index `{}`. Consider using `for ({}, \ item) in {}.iter().enumerate(){}{}` or similar iterators", - ident.node.name, + ident.node, indexed, - ident.node.name, + ident.node, indexed, take, skip)); @@ -396,7 +396,7 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex expr.span, &format!("the loop variable `{}` is only used to index `{}`. \ Consider using `for item in {}` or similar iterators", - ident.node.name, + ident.node, indexed, repl)); } @@ -412,7 +412,7 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { method.node.as_str() == "len", let ExprPath(_, ref path) = len_args[0].node, path.segments.len() == 1, - &path.segments[0].identifier.name == var + &path.segments[0].name == var ], { return true; }} @@ -613,7 +613,7 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { match *pat { PatKind::Wild => true, - PatKind::Ident(_, ident, None) if ident.node.name.as_str().starts_with('_') => { + PatKind::Ident(_, ident, None) if ident.node.as_str().starts_with('_') => { let mut visitor = UsedVisitor { var: ident.node, used: false, @@ -626,14 +626,14 @@ fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { } struct UsedVisitor { - var: Ident, // var to look for + var: ast::Name, // var to look for used: bool, // has the var been used otherwise? } impl<'a> Visitor<'a> for UsedVisitor { fn visit_expr(&mut self, expr: &Expr) { if let ExprPath(None, ref path) = expr.node { - if path.segments.len() == 1 && path.segments[0].identifier == self.var { + if path.segments.len() == 1 && path.segments[0].name == self.var { self.used = true; return; } @@ -653,7 +653,7 @@ struct VarVisitor<'v, 't: 'v> { 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 && path.segments[0].identifier.name == self.var { + if path.segments.len() == 1 && path.segments[0].name == self.var { // we are referencing our variable! now check if it's as an index if_let_chain! { [ @@ -667,11 +667,11 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { match def.base_def { Def::Local(..) | Def::Upvar(..) => { let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); - self.indexed.insert(seqvar.segments[0].identifier.name, Some(extent)); + self.indexed.insert(seqvar.segments[0].name, Some(extent)); return; // no need to walk further } Def::Static(..) | Def::Const(..) => { - self.indexed.insert(seqvar.segments[0].identifier.name, None); + self.indexed.insert(seqvar.segments[0].name, None); return; // no need to walk further } _ => (), @@ -885,7 +885,7 @@ impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { if let DeclLocal(ref local) = decl.node { if local.pat.id == self.var_id { if let PatKind::Ident(_, ref ident, _) = local.pat.node { - self.name = Some(ident.node.name); + self.name = Some(ident.node); self.state = if let Some(ref init) = local.init { if is_integer_literal(init, 0) { diff --git a/src/map_clone.rs b/src/map_clone.rs index d015a165457..4ad232759cf 100644 --- a/src/map_clone.rs +++ b/src/map_clone.rs @@ -1,5 +1,6 @@ use rustc::lint::*; use rustc::hir::*; +use syntax::ast; use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet, span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; @@ -52,7 +53,7 @@ impl LateLintPass for MapClonePass { if clone_call.node.as_str() == "clone" && clone_args.len() == 1 && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) && - expr_eq_ident(&clone_args[0], arg_ident) + expr_eq_name(&clone_args[0], arg_ident) { span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( "you seem to be using .map() to clone the contents of an {}, consider \ @@ -82,11 +83,11 @@ impl LateLintPass for MapClonePass { } } -fn expr_eq_ident(expr: &Expr, id: Ident) -> bool { +fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { match expr.node { ExprPath(None, ref path) => { let arg_segment = [PathSegment { - identifier: id, + name: id, parameters: PathParameters::none(), }]; !path.global && path.segments[..] == arg_segment @@ -105,18 +106,18 @@ fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static s } } -fn get_arg_name(pat: &Pat) -> Option<Ident> { +fn get_arg_name(pat: &Pat) -> Option<ast::Name> { match pat.node { - PatKind::Ident(_, ident, None) => Some(ident.node), + PatKind::Ident(_, name, None) => Some(name.node), PatKind::Ref(ref subpat, _) => get_arg_name(subpat), _ => None, } } -fn only_derefs(cx: &LateContext, expr: &Expr, id: Ident) -> bool { +fn only_derefs(cx: &LateContext, expr: &Expr, id: ast::Name) -> bool { match expr.node { ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id), - _ => expr_eq_ident(expr, id), + _ => expr_eq_name(expr, id), } } diff --git a/src/methods.rs b/src/methods.rs index ecbdb62f05e..14bc74d467f 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -473,7 +473,6 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[P<hi let path: &str = &path.segments .last() .expect("A path must have at least one segment") - .identifier .name .as_str(); @@ -811,7 +810,7 @@ fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other: 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].identifier.name.as_str() == "Some" + path.segments.len() == 1 && path.segments[0].name.as_str() == "Some" ], { let self_ty = walk_ptrs_ty(cx.tcx.expr_ty_adjusted(&args[0][0])); diff --git a/src/misc.rs b/src/misc.rs index 25747157c0f..3ab7823e50d 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -8,8 +8,10 @@ use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_eval::eval_const_expr_partial; use syntax::codemap::{Span, Spanned, ExpnFormat}; use syntax::ptr::P; -use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint}; -use utils::{span_lint_and_then, walk_ptrs_ty, is_integer_literal, implements_trait}; +use utils::{ + get_item_name, get_parent_expr, implements_trait, is_integer_literal, match_path, snippet, + span_lint, span_lint_and_then, walk_ptrs_ty +}; /// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. /// @@ -118,7 +120,7 @@ impl LateLintPass for CmpNan { fn check_nan(cx: &LateContext, path: &Path, span: Span) { path.segments.last().map(|seg| { - if seg.identifier.name.as_str() == "NAN" { + if seg.name.as_str() == "NAN" { span_lint(cx, CMP_NAN, span, @@ -350,8 +352,8 @@ impl LateLintPass for PatternPass { REDUNDANT_PATTERN, pat.span, &format!("the `{} @ _` pattern can be written as just `{}`", - ident.node.name, - ident.node.name)); + ident.node, + ident.node)); } } } @@ -363,7 +365,8 @@ impl LateLintPass for PatternPass { /// **Why is this bad?** A single leading underscore is usually used to indicate that a binding /// will not be used. Using such a binding breaks this expectation. /// -/// **Known problems:** None +/// **Known problems:** The lint does not work properly with desugaring and macro, it has been +/// allowed in the mean time. /// /// **Example**: /// ``` @@ -371,7 +374,7 @@ impl LateLintPass for PatternPass { /// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore. /// // We should rename `_x` to `x` /// ``` -declare_lint!(pub USED_UNDERSCORE_BINDING, Warn, +declare_lint!(pub USED_UNDERSCORE_BINDING, Allow, "using a binding which is prefixed with an underscore"); #[derive(Copy, Clone)] @@ -387,32 +390,42 @@ impl LateLintPass for UsedUnderscoreBinding { #[cfg_attr(rustfmt, rustfmt_skip)] fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if in_attributes_expansion(cx, expr) { - // Don't lint things expanded by #[derive(...)], etc + // Don't lint things expanded by #[derive(...)], etc return; } - let needs_lint = match expr.node { + let binding = match expr.node { ExprPath(_, ref path) => { - let ident = path.segments + let segment = path.segments .last() .expect("path should always have at least one segment") - .identifier; - ident.name.as_str().starts_with('_') && - !ident.name.as_str().starts_with("__") && - ident.name != ident.unhygienic_name && - is_used(cx, expr) // not in bang macro + .name; + if segment.as_str().starts_with('_') && + !segment.as_str().starts_with("__") && + segment != segment.unhygienize() && // not in bang macro + is_used(cx, expr) { + Some(segment.as_str()) + } else { + None + } } ExprField(_, spanned) => { let name = spanned.node.as_str(); - name.starts_with('_') && !name.starts_with("__") + if name.starts_with('_') && !name.starts_with("__") { + Some(name) + } else { + None + } } - _ => false, + _ => None, }; - if needs_lint { - span_lint(cx, - USED_UNDERSCORE_BINDING, - expr.span, - "used binding which is prefixed with an underscore. A leading underscore signals that a \ - binding will not be used."); + if let Some(binding) = binding { + if binding != "_result" { // FIXME: #944 + span_lint(cx, + 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)); + } } } } @@ -431,8 +444,8 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { } } -/// Test whether an expression is in a macro expansion (e.g. something generated by #[derive(...)] -/// or the like) +/// Test whether an expression is in a macro expansion (e.g. something generated by +/// `#[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| { diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs index 6a8ca368fc1..34921bc2c04 100644 --- a/src/overflow_check_conditional.rs +++ b/src/overflow_check_conditional.rs @@ -31,7 +31,7 @@ impl LateLintPass for OverflowCheckConditional { let Expr_::ExprPath(_,ref path1) = ident1.node, let Expr_::ExprPath(_, ref path2) = ident2.node, let Expr_::ExprPath(_, ref path3) = second.node, - (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, + &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], cx.tcx.expr_ty(ident1).is_integral(), cx.tcx.expr_ty(ident2).is_integral() ], { @@ -53,7 +53,7 @@ impl LateLintPass for OverflowCheckConditional { let Expr_::ExprPath(_,ref path1) = ident1.node, let Expr_::ExprPath(_, ref path2) = ident2.node, let Expr_::ExprPath(_, ref path3) = first.node, - (&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier, + &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], cx.tcx.expr_ty(ident1).is_integral(), cx.tcx.expr_ty(ident2).is_integral() ], { diff --git a/src/shadow.rs b/src/shadow.rs index 4639a943965..cf7de04cb6f 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -66,7 +66,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { let mut bindings = Vec::new(); for arg in &decl.inputs { if let PatKind::Ident(_, ident, _) = arg.pat.node { - bindings.push((ident.node.unhygienic_name, ident.span)) + bindings.push((ident.node.unhygienize(), ident.span)) } } check_block(cx, block, &mut bindings); @@ -120,7 +120,7 @@ fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bind // TODO: match more stuff / destructuring match pat.node { PatKind::Ident(_, ref ident, ref inner) => { - let name = ident.node.unhygienic_name; + let name = ident.node.unhygienize(); if is_binding(cx, pat) { let mut new_binding = true; for tup in bindings.iter_mut() { @@ -326,7 +326,7 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { } fn path_eq_name(name: Name, path: &Path) -> bool { - !path.global && path.segments.len() == 1 && path.segments[0].identifier.unhygienic_name == name + !path.global && path.segments.len() == 1 && path.segments[0].name.unhygienize() == name } struct ContainsSelf { @@ -335,8 +335,8 @@ struct ContainsSelf { } impl<'v> Visitor<'v> for ContainsSelf { - fn visit_ident(&mut self, _: Span, ident: Ident) { - if self.name == ident.unhygienic_name { + fn visit_name(&mut self, _: Span, name: Name) { + if self.name == name.unhygienize() { self.result = true; } } diff --git a/src/swap.rs b/src/swap.rs index 724915b9dd5..c5572181395 100644 --- a/src/swap.rs +++ b/src/swap.rs @@ -75,7 +75,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { let ExprPath(None, ref rhs2) = rhs2.node, rhs2.segments.len() == 1, - tmp_name.node.name.as_str() == rhs2.segments[0].identifier.name.as_str(), + 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) ], { diff --git a/src/unsafe_removed_from_name.rs b/src/unsafe_removed_from_name.rs index 404d6d93604..3de6719c546 100644 --- a/src/unsafe_removed_from_name.rs +++ b/src/unsafe_removed_from_name.rs @@ -41,7 +41,7 @@ impl LateLintPass for UnsafeNameRemoval { path.segments .last() .expect("use paths cannot be empty") - .identifier.name, + .name, *name, cx, &item.span ); diff --git a/src/unused_label.rs b/src/unused_label.rs index f6ff3c3d4b4..d408f16a371 100644 --- a/src/unused_label.rs +++ b/src/unused_label.rs @@ -65,10 +65,10 @@ impl<'v> Visitor<'v> for UnusedLabelVisitor { fn visit_expr(&mut self, expr: &hir::Expr) { match expr.node { hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { - self.labels.remove(&label.node.name.as_str()); + self.labels.remove(&label.node.as_str()); } hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { - self.labels.insert(label.name.as_str(), expr.span); + self.labels.insert(label.as_str(), expr.span); } _ => (), } diff --git a/src/utils/hir.rs b/src/utils/hir.rs index fe4c6d30952..0f0a7312ee4 100644 --- a/src/utils/hir.rs +++ b/src/utils/hir.rs @@ -68,7 +68,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.node, &right.node) { (&ExprAddrOf(l_mut, ref le), &ExprAddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re), - (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), + (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.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) @@ -80,7 +80,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) } - (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()), + (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()), (&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) @@ -95,7 +95,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => { - self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str()) + self.eq_block(lb, rb) && both(ll, rl, |l, r| l.as_str() == r.as_str()) } (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { ls == rs && self.eq_expr(le, re) && @@ -124,7 +124,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), (&ExprVec(ref l), &ExprVec(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.name.as_str() == r.name.as_str()) + self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.as_str() == r.as_str()) } _ => false, } @@ -146,7 +146,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r))) } (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => { - lb == rb && li.node.name.as_str() == ri.node.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) + lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) } (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { @@ -172,7 +172,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { left.global == right.global && over(&left.segments, &right.segments, - |l, r| l.identifier.name.as_str() == r.identifier.name.as_str() && l.parameters == r.parameters) + |l, r| l.name.as_str() == r.name.as_str() && l.parameters == r.parameters) } fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool { @@ -281,7 +281,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { let c: fn(_) -> _ = ExprAgain; c.hash(&mut self.s); if let Some(i) = i { - self.hash_name(&i.node.name); + self.hash_name(&i.node); } } ExprAssign(ref l, ref r) => { @@ -313,7 +313,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { let c: fn(_) -> _ = ExprBreak; c.hash(&mut self.s); if let Some(i) = i { - self.hash_name(&i.node.name); + self.hash_name(&i.node); } } ExprBox(ref e) => { @@ -374,7 +374,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { c.hash(&mut self.s); self.hash_block(b); if let Some(i) = *i { - self.hash_name(&i.name); + self.hash_name(&i); } } ExprMatch(ref e, ref arms, ref s) => { @@ -468,7 +468,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { self.hash_expr(cond); self.hash_block(b); if let Some(l) = l { - self.hash_name(&l.name); + self.hash_name(&l); } } } @@ -487,7 +487,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { pub fn hash_path(&mut self, p: &Path) { p.global.hash(&mut self.s); for p in &p.segments { - self.hash_name(&p.identifier.name); + self.hash_name(&p.name); } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 10bfe56e925..3ff6167620a 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -200,7 +200,7 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool /// match_path(path, &["std", "rt", "begin_unwind"]) /// ``` pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name.as_str() == *b) } /// Match a `Path` against a slice of segment string literals, e.g. diff --git a/tests/compile-fail/used_underscore_binding.rs b/tests/compile-fail/used_underscore_binding.rs index 6bf4324e623..c571906c53b 100644 --- a/tests/compile-fail/used_underscore_binding.rs +++ b/tests/compile-fail/used_underscore_binding.rs @@ -3,15 +3,16 @@ #![deny(clippy)] #![allow(blacklisted_name)] +#![deny(used_underscore_binding)] /// Test that we lint if we use a binding with a single leading underscore fn prefix_underscore(_foo: u32) -> u32 { - _foo + 1 //~ ERROR used binding which is prefixed with an underscore + _foo + 1 //~ ERROR used binding `_foo` which is prefixed with an underscore } /// Test that we lint even if the use is within a macro expansion fn in_macro(_foo: u32) { - println!("{}", _foo); //~ ERROR used binding which is prefixed with an underscore + println!("{}", _foo); //~ ERROR used binding `_foo` which is prefixed with an underscore } // Struct for testing use of fields prefixed with an underscore @@ -22,7 +23,7 @@ struct StructFieldTest { /// Test that we lint the use of a struct field which is prefixed with an underscore fn in_struct_field() { let mut s = StructFieldTest { _underscore_field: 0 }; - s._underscore_field += 1; //~ Error used binding which is prefixed with an underscore + s._underscore_field += 1; //~ Error used binding `_underscore_field` which is prefixed with an underscore } /// Test that we do not lint if the underscore is not a prefix -- cgit 1.4.1-3-g733a5 From 6dd608e53e52d91d01677bc5f0a2eead4757e406 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 20 May 2016 19:18:32 +0200 Subject: Rustup to *1.10.0-nightly (764ef92ae 2016-05-19)* --- src/methods.rs | 2 +- src/vec.rs | 12 +++++++----- tests/compile-fail/methods.rs | 2 +- tests/compile-fail/mut_mut.rs | 11 ++++++----- 4 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/methods.rs b/src/methods.rs index 14bc74d467f..f9f557e7a9a 100644 --- a/src/methods.rs +++ b/src/methods.rs @@ -511,7 +511,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[P<hi return; } } - // (path, fn_has_argument, methods) + // (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, diff --git a/src/vec.rs b/src/vec.rs index 63b9952c3c8..e62a8f9c459 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -38,17 +38,19 @@ impl LateLintPass for UselessVec { let TypeVariants::TySlice(..) = ty.ty.sty, let ExprAddrOf(_, ref addressee) = expr.node, ], { - check_vec_macro(cx, expr, addressee); + check_vec_macro(cx, addressee, expr.span); }} // search for `for _ in vec![…]` if let Some((_, arg, _)) = recover_for_loop(expr) { - check_vec_macro(cx, arg, arg); + // report the error around the `vec!` not inside `<std macros>:` + let span = cx.sess().codemap().source_callsite(arg.span); + check_vec_macro(cx, arg, span); } } } -fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) { +fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) { if let Some(vec_args) = unexpand_vec(cx, vec) { let snippet = match vec_args { VecArgs::Repeat(elem, len) => { @@ -69,8 +71,8 @@ fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) { } }; - span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| { - db.span_suggestion(expr.span, "you can use a slice directly", snippet); + span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| { + db.span_suggestion(span, "you can use a slice directly", snippet); }); } } diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 88a1e7c4cf2..9753c021372 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -288,7 +288,7 @@ fn or_fun_call() { with_vec.unwrap_or(vec![]); //~^ERROR use of `unwrap_or` //~|HELP try this - //~|SUGGESTION with_vec.unwrap_or_else(|| vec![]); + // FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]); let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); diff --git a/tests/compile-fail/mut_mut.rs b/tests/compile-fail/mut_mut.rs index 865574eaec0..8d9bceb0d0d 100644 --- a/tests/compile-fail/mut_mut.rs +++ b/tests/compile-fail/mut_mut.rs @@ -18,6 +18,7 @@ fn less_fun(x : *mut *mut u32) { macro_rules! mut_ptr { ($p:expr) => { &mut $p } + //~^ ERROR generally you want to avoid `&mut &mut } #[deny(mut_mut)] @@ -30,12 +31,12 @@ fn main() { if fun(x) { let y : &mut &mut &mut u32 = &mut &mut &mut 2; - //~^ ERROR generally you want to avoid `&mut &mut - //~^^ ERROR generally you want to avoid `&mut &mut - //~^^^ ERROR generally you want to avoid `&mut &mut - //~^^^^ ERROR generally you want to avoid `&mut &mut + //~^ ERROR generally you want to avoid `&mut &mut + //~| ERROR generally you want to avoid `&mut &mut + //~| ERROR generally you want to avoid `&mut &mut + //~| ERROR generally you want to avoid `&mut &mut ***y + **x; } - let mut z = mut_ptr!(&mut 3u32); //~ERROR generally you want to avoid `&mut &mut + let mut z = mut_ptr!(&mut 3u32); //~ NOTE in this expansion of mut_ptr! } -- cgit 1.4.1-3-g733a5 From ac2e175c1b9aa6ac8da7794a86f7ec4b16f669ac Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 23 May 2016 16:34:09 +0200 Subject: Rustup to *1.10.0-nightly (476fe6eef 2016-05-21)* --- src/shadow.rs | 7 ++++--- tests/compile-fail/methods.rs | 6 ++---- tests/compile-fail/shadow.rs | 16 ++++++++-------- 3 files changed, 14 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/shadow.rs b/src/shadow.rs index cf7de04cb6f..2a0d36a80b3 100644 --- a/src/shadow.rs +++ b/src/shadow.rs @@ -208,15 +208,16 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, let db = span_lint(cx, SHADOW_SAME, span, - &format!("{} is shadowed by itself in {}", + &format!("`{}` is shadowed by itself in `{}`", snippet(cx, pattern_span, "_"), snippet(cx, expr.span, ".."))); + note_orig(cx, db, SHADOW_SAME, prev_span); } else if contains_self(name, expr) { let db = span_note_and_lint(cx, SHADOW_REUSE, pattern_span, - &format!("{} is shadowed by {} which reuses the original value", + &format!("`{}` is shadowed by `{}` which reuses the original value", snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), expr.span, @@ -226,7 +227,7 @@ fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, let db = span_note_and_lint(cx, SHADOW_UNRELATED, pattern_span, - &format!("{} is shadowed by {}", + &format!("`{}` is shadowed by `{}`", snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), expr.span, diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 9753c021372..f6e4a9a31e0 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -493,10 +493,8 @@ fn single_char_pattern() { fn temporary_cstring() { use std::ffi::CString; - ( // extra parenthesis to better test spans + CString::new("foo").unwrap().as_ptr(); //~^ ERROR you are getting the inner pointer of a temporary `CString` //~| NOTE that pointer will be invalid outside this expression - CString::new("foo").unwrap() - //~^ HELP assign the `CString` to a variable to extend its lifetime - ).as_ptr(); + //~| HELP assign the `CString` to a variable to extend its lifetime } diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 0a52a9829ae..1cfcff74a44 100644 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -10,15 +10,15 @@ fn first(x: (isize, isize)) -> isize { x.0 } fn main() { let mut x = 1; - let x = &mut x; //~ERROR x is shadowed by itself in &mut x - let x = { x }; //~ERROR x is shadowed by itself in { x } - let x = (&*x); //~ERROR x is shadowed by itself in &*x - let x = { *x + 1 }; //~ERROR x is shadowed by { *x + 1 } which reuses - let x = id(x); //~ERROR x is shadowed by id(x) which reuses - let x = (1, x); //~ERROR x is shadowed by (1, x) which reuses - let x = first(x); //~ERROR x is shadowed by first(x) which reuses + let x = &mut x; //~ERROR `x` is shadowed by itself in `&mut x` + let x = { x }; //~ERROR `x` is shadowed by itself in `{ x }` + let x = (&*x); //~ERROR `x` is shadowed by itself in `(&*x)` + let x = { *x + 1 }; //~ERROR `x` is shadowed by `{ *x + 1 }` which reuses + let x = id(x); //~ERROR `x` is shadowed by `id(x)` which reuses + let x = (1, x); //~ERROR `x` is shadowed by `(1, x)` which reuses + let x = first(x); //~ERROR `x` is shadowed by `first(x)` which reuses let y = 1; - let x = y; //~ERROR x is shadowed by y + let x = y; //~ERROR `x` is shadowed by `y` let o = Some(1u8); -- cgit 1.4.1-3-g733a5 From 7a9dac4e1cd0a44d69f203ed4c2e09cf6f464977 Mon Sep 17 00:00:00 2001 From: Benoît Zugmeyer <bzugmeyer@gmail.com> Date: Mon, 23 May 2016 22:32:51 +0200 Subject: Let cargo-clippy exit with a code > 0 if some error occured --- src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 888abbc92c5..bcf8f86b10a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,18 +122,28 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); let path = std::env::current_exe().expect("current executable path invalid"); - std::process::Command::new("cargo") + 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?"); + + if let Some(code) = exit_status.code() { + std::process::exit(code); + } } else { let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() } else { env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() }; - rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); + let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); + + if let Err(err_count) = result { + if err_count > 0 { + std::process::exit(1); + } + } } } -- cgit 1.4.1-3-g733a5 From 9cfc42275d400d5b192e10e005d4f7ef772156b7 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Tue, 17 May 2016 08:33:57 +0200 Subject: Split `new_without_default` and `new_without_default_derive`. This is still very slow, because we do a trait lookup for each field. Perhaps storing the visited types in a set to reuse types would improve performance somewhat. Also we may want to pre-decide some known types (e.g. `Vec<T>`, `Option<T>`). --- CHANGELOG.md | 1 + README.md | 3 +- src/lib.rs | 1 + src/new_without_default.rs | 84 +++++++++++++++++++++++++++---- tests/compile-fail/methods.rs | 2 +- tests/compile-fail/new_without_default.rs | 6 +-- 6 files changed, 82 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 59b03b301c6..9a1e7322e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,6 +174,7 @@ All notable changes to this project will be documented in this file. [`neg_multiply`]: https://github.com/Manishearth/rust-clippy/wiki#neg_multiply [`new_ret_no_self`]: https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self [`new_without_default`]: https://github.com/Manishearth/rust-clippy/wiki#new_without_default +[`new_without_default_derive`]: https://github.com/Manishearth/rust-clippy/wiki#new_without_default_derive [`no_effect`]: https://github.com/Manishearth/rust-clippy/wiki#no_effect [`non_ascii_literal`]: https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal [`nonminimal_bool`]: https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool diff --git a/README.md b/README.md index 6843afb4ede..4c156dfb7a0 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 150 lints included in this crate: +There are 151 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -107,6 +107,7 @@ name [neg_multiply](https://github.com/Manishearth/rust-clippy/wiki#neg_multiply) | warn | Warns on multiplying integers with -1 [new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method [new_without_default](https://github.com/Manishearth/rust-clippy/wiki#new_without_default) | warn | `fn new() -> Self` method without `Default` implementation +[new_without_default_derive](https://github.com/Manishearth/rust-clippy/wiki#new_without_default_derive) | warn | `fn new() -> Self` without `#[derive]`able `Default` implementation [no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | allow | checks for boolean expressions that can be written more concisely diff --git a/src/lib.rs b/src/lib.rs index bcf8f86b10a..41c26cf7109 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -527,6 +527,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, neg_multiply::NEG_MULTIPLY, new_without_default::NEW_WITHOUT_DEFAULT, + new_without_default::NEW_WITHOUT_DEFAULT_DERIVE, no_effect::NO_EFFECT, no_effect::UNNECESSARY_OPERATION, non_expressive_names::MANY_SINGLE_CHAR_NAMES, diff --git a/src/new_without_default.rs b/src/new_without_default.rs index 46021ec8836..08d517014ee 100644 --- a/src/new_without_default.rs +++ b/src/new_without_default.rs @@ -1,6 +1,8 @@ use rustc::hir::intravisit::FnKind; +use rustc::hir::def_id::DefId; use rustc::hir; use rustc::lint::*; +use rustc::ty; use syntax::ast; use syntax::codemap::Span; use utils::paths; @@ -20,11 +22,11 @@ use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, sa /// **Example:** /// /// ```rust,ignore -/// struct Foo; +/// struct Foo(Bar); /// /// impl Foo { /// fn new() -> Self { -/// Foo +/// Foo(Bar::new()) /// } /// } /// ``` @@ -32,29 +34,58 @@ use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, sa /// Instead, use: /// /// ```rust -/// struct Foo; +/// struct Foo(Bar); /// /// impl Default for Foo { /// fn default() -> Self { -/// Foo +/// Foo(Bar::new()) /// } /// } /// ``` /// /// You can also have `new()` call `Default::default()` -/// declare_lint! { pub NEW_WITHOUT_DEFAULT, Warn, "`fn new() -> Self` method without `Default` implementation" } +/// **What it does:** This lints about type with a `fn new() -> Self` method +/// and no implementation of +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// +/// **Why is this bad?** User might expect to be able to use +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// as the type can be +/// constructed without arguments. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ```rust,ignore +/// struct Foo; +/// +/// impl Foo { +/// fn new() -> Self { +/// Foo +/// } +/// } +/// ``` +/// +/// Just prepend `#[derive(Default)]` before the `struct` definition +declare_lint! { + pub NEW_WITHOUT_DEFAULT_DERIVE, + Warn, + "`fn new() -> Self` without `#[derive]`able `Default` implementation" +} + #[derive(Copy,Clone)] pub struct NewWithoutDefault; impl LintPass for NewWithoutDefault { fn get_lints(&self) -> LintArray { - lint_array!(NEW_WITHOUT_DEFAULT) + lint_array!(NEW_WITHOUT_DEFAULT, NEW_WITHOUT_DEFAULT_DERIVE) } } @@ -66,8 +97,8 @@ impl LateLintPass for NewWithoutDefault { if let FnKind::Method(name, _, _, _) = kind { if decl.inputs.is_empty() && name.as_str() == "new" { - let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty; - + let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id( + cx.tcx.map.get_parent(id))).ty; if_let_chain!{[ self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics let Some(ret_ty) = return_ty(cx, id), @@ -75,10 +106,43 @@ impl LateLintPass for NewWithoutDefault { let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), !implements_trait(cx, self_ty, default_trait_id, Vec::new()) ], { - span_lint(cx, NEW_WITHOUT_DEFAULT, span, - &format!("you should consider adding a `Default` implementation for `{}`", self_ty)); + if can_derive_default(self_ty, cx, default_trait_id) { + span_lint(cx, + NEW_WITHOUT_DEFAULT_DERIVE, span, + &format!("you should consider deriving a \ + `Default` implementation for `{}`", + self_ty)). + span_suggestion(span, + "try this", + "#[derive(Default)]".into()); + } else { + span_lint(cx, + NEW_WITHOUT_DEFAULT, span, + &format!("you should consider adding a \ + `Default` implementation for `{}`", + self_ty)). + span_suggestion(span, + "try this", + format!("impl Default for {} {{ fn default() -> \ + Self {{ {}::new() }} }}", self_ty, self_ty)); + } }} } } } } + +fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> bool { + match ty.sty { + ty::TyStruct(ref adt_def, ref substs) => { + for field in adt_def.all_fields() { + let f_ty = field.ty(cx.tcx, substs); + if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) { + return false + } + } + true + }, + _ => false + } +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index f6e4a9a31e0..78ffbb1a58a 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -3,7 +3,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default)] +#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/compile-fail/new_without_default.rs b/tests/compile-fail/new_without_default.rs index 30015f6c9e8..17f2a8d7b41 100644 --- a/tests/compile-fail/new_without_default.rs +++ b/tests/compile-fail/new_without_default.rs @@ -2,18 +2,18 @@ #![plugin(clippy)] #![allow(dead_code)] -#![deny(new_without_default)] +#![deny(new_without_default, new_without_default_derive)] struct Foo; impl Foo { - fn new() -> Foo { Foo } //~ERROR: you should consider adding a `Default` implementation for `Foo` + fn new() -> Foo { Foo } //~ERROR: you should consider deriving a `Default` implementation for `Foo` } struct Bar; impl Bar { - fn new() -> Self { Bar } //~ERROR: you should consider adding a `Default` implementation for `Bar` + fn new() -> Self { Bar } //~ERROR: you should consider deriving a `Default` implementation for `Bar` } struct Ok; -- cgit 1.4.1-3-g733a5 From e90a0be923906ded7c79d6168a11b8b68d85fd72 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 17 May 2016 16:34:15 +0200 Subject: simplify `mut_mut` lint --- src/mut_mut.rs | 64 +++++++++++++++++++++------------------------------------- 1 file changed, 23 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/mut_mut.rs b/src/mut_mut.rs index 7b7b5ecdf4e..4147e288c4f 100644 --- a/src/mut_mut.rs +++ b/src/mut_mut.rs @@ -28,50 +28,32 @@ impl LintPass for MutMut { impl LateLintPass for MutMut { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - check_expr_mut(cx, expr) - } - - fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { - unwrap_mut(ty).and_then(unwrap_mut).map_or((), |_| { - span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); - }); - } -} - -fn check_expr_mut(cx: &LateContext, expr: &Expr) { - fn unwrap_addr(expr: &Expr) -> Option<&Expr> { - match expr.node { - ExprAddrOf(MutMutable, ref e) => Some(e), - _ => None, + if in_external_macro(cx, expr.span) { + return; } - } - if in_external_macro(cx, expr.span) { - return; + if let ExprAddrOf(MutMutable, ref e) = expr.node { + if let ExprAddrOf(MutMutable, _) = e.node { + span_lint(cx, + MUT_MUT, + expr.span, + "generally you want to avoid `&mut &mut _` if possible"); + } else { + if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { + span_lint(cx, + MUT_MUT, + expr.span, + "this expression mutably borrows a mutable reference. Consider reborrowing"); + } + } + } } - unwrap_addr(expr).map_or((), |e| { - unwrap_addr(e).map_or_else(|| { - if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { - span_lint(cx, - MUT_MUT, - expr.span, - "this expression mutably borrows a mutable reference. Consider \ - reborrowing"); - } - }, - |_| { - span_lint(cx, - MUT_MUT, - expr.span, - "generally you want to avoid `&mut &mut _` if possible"); - }) - }) -} - -fn unwrap_mut(ty: &Ty) -> Option<&Ty> { - match ty.node { - TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) => Some(pty), - _ => None, + fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { + if let TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) = ty.node { + if let TyRptr(_, MutTy { mutbl: MutMutable, .. }) = pty.node { + span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); + } + } } } -- cgit 1.4.1-3-g733a5 From bb69e60b3088f5db72e359c19271b8561e882a39 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 25 May 2016 18:51:35 +0200 Subject: fix no_effect lint --- src/no_effect.rs | 10 +++++----- tests/compile-fail/no_effect.rs | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/no_effect.rs b/src/no_effect.rs index 593a6c4ad59..ae3bac00455 100644 --- a/src/no_effect.rs +++ b/src/no_effect.rs @@ -1,6 +1,6 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::def::{Def, PathResolution}; -use rustc::hir::{Expr, Expr_, Stmt, StmtSemi}; +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; @@ -140,11 +140,11 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp } Expr_::ExprBlock(ref block) => { if block.stmts.is_empty() { - block.expr.as_ref().and_then(|e| if e.span == expr.span { + block.expr.as_ref().and_then(|e| match block.rules { + BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None, + BlockCheckMode::DefaultBlock => Some(vec![&**e]), // in case of compiler-inserted signaling blocks - reduce_expression(cx, e) - } else { - Some(vec![e]) + _ => reduce_expression(cx, e), }) } else { None diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs index ce6daa8d562..c1d9b175428 100644 --- a/tests/compile-fail/no_effect.rs +++ b/tests/compile-fail/no_effect.rs @@ -18,6 +18,8 @@ enum Enum { fn get_number() -> i32 { 0 } fn get_struct() -> Struct { Struct { field: 0 } } +unsafe fn unsafe_fn() -> i32 { 0 } + fn main() { let s = get_struct(); let s2 = get_struct(); @@ -50,6 +52,7 @@ fn main() { // Do not warn get_number(); + unsafe { unsafe_fn() }; Tuple(get_number()); //~ERROR statement can be reduced //~^HELP replace it with @@ -105,4 +108,7 @@ fn main() { [42; 55][get_number() as usize]; //~ERROR statement can be reduced //~^HELP replace it with //~|SUGGESTION [42; 55];get_number() as usize; + {get_number()}; //~ERROR statement can be reduced + //~^HELP replace it with + //~|SUGGESTION get_number(); } -- cgit 1.4.1-3-g733a5 From 4f11f84dee891e80680f47d48cc33a0cb0229080 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 25 May 2016 17:15:19 +0200 Subject: Lint binary regexes --- CHANGELOG.md | 6 ++- src/regex.rs | 108 +++++++++++++++++++++++++++----------------- src/utils/paths.rs | 6 ++- tests/compile-fail/regex.rs | 33 +++++++++++++- 4 files changed, 109 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a1e7322e76..f17b1dd0837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.70 — TBD +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new` and + byte regexes + ## 0.0.69 — 2016-05-20 * Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)* -* `used_underscore_binding` has been made `Allow` temporarily +* [`used_underscore_binding`] has been made `Allow` temporarily ## 0.0.68 — 2016-05-17 * Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)* diff --git a/src/regex.rs b/src/regex.rs index e1b4237b9b2..8876a649e5d 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -9,7 +9,7 @@ use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; -use utils::{is_expn_of, match_path, match_type, paths, span_lint, span_help_and_lint}; +use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint}; /// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. /// @@ -81,7 +81,7 @@ impl LateLintPass for RegexPass { span, "`regex!(_)` found. \ Please use `Regex::new(_)`, which is faster for now."); - self.spans.insert(span); + self.spans.insert(span); } self.last = Some(block.id); }} @@ -96,46 +96,18 @@ impl LateLintPass for RegexPass { fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain!{[ let ExprCall(ref fun, ref args) = expr.node, - let ExprPath(_, ref path) = fun.node, - match_path(path, &paths::REGEX_NEW) && args.len() == 1 + args.len() == 1, + let Some(def) = cx.tcx.def_map.borrow().get(&fun.id), ], { - if let ExprLit(ref lit) = args[0].node { - if let LitKind::Str(ref r, _) = lit.node { - match regex_syntax::Expr::parse(r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - "trivial regex", - &format!("consider using {}", repl)); - } - } - Err(e) => { - span_lint(cx, - INVALID_REGEX, - str_span(args[0].span, &r, e.position()), - &format!("regex syntax error: {}", - e.description())); - } - } - } - } else if let Some(r) = const_str(cx, &*args[0]) { - match regex_syntax::Expr::parse(&r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span, - "trivial regex", - &format!("consider using {}", repl)); - } - } - Err(e) => { - span_lint(cx, - INVALID_REGEX, - args[0].span, - &format!("regex syntax error on position {}: {}", - e.position(), - e.description())); - } - } + let def_id = def.def_id(); + if match_def_path(cx, def_id, &paths::REGEX_NEW) { + check_regex(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) { + check_regex(cx, &args[0], false); + } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { + check_set(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { + check_set(cx, &args[0], false); } }} } @@ -193,3 +165,57 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { _ => None, } } + +fn check_set(cx: &LateContext, expr: &Expr, utf8: bool) { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, + let ExprVec(ref exprs) = expr.node, + ], { + for expr in exprs { + check_regex(cx, expr, utf8); + } + }} +} + +fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { + let builder = regex_syntax::ExprBuilder::new().unicode(utf8); + + if let ExprLit(ref lit) = expr.node { + if let LitKind::Str(ref r, _) = lit.node { + match builder.parse(r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + "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())); + } + } + } + } else if let Some(r) = const_str(cx, expr) { + match builder.parse(&r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + "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())); + } + } + } +} diff --git a/src/utils/paths.rs b/src/utils/paths.rs index 3db1e1c5572..b0ce8b4a233 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -46,7 +46,11 @@ pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclus pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; -pub const REGEX_NEW: [&'static str; 3] = ["regex", "Regex", "new"]; +pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"]; +pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"]; +pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; +pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"]; +pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; pub const STRING: [&'static str; 3] = ["collections", "string", "String"]; pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index 9cd2bc8098e..d9f262fb045 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -6,7 +6,8 @@ extern crate regex; -use regex::Regex; +use regex::{Regex, RegexSet}; +use regex::bytes::{Regex as BRegex, RegexSet as BRegexSet}; const OPENING_PAREN : &'static str = "("; const NOT_A_REAL_REGEX : &'static str = "foobar"; @@ -22,8 +23,33 @@ fn syntax_error() { let some_regex = Regex::new(OPENING_PAREN); //~^ERROR: regex syntax error on position 0: unclosed + let binary_pipe_in_wrong_position = BRegex::new("|"); + //~^ERROR: regex syntax error: empty alternate + let some_binary_regex = BRegex::new(OPENING_PAREN); + //~^ERROR: regex syntax error on position 0: unclosed + let closing_paren = ")"; let not_linted = Regex::new(closing_paren); + + let set = RegexSet::new(&[ + r"[a-z]+@[a-z]+\.(com|org|net)", + r"[a-z]+\.(com|org|net)", + ]); + let bset = BRegexSet::new(&[ + r"[a-z]+@[a-z]+\.(com|org|net)", + r"[a-z]+\.(com|org|net)", + ]); + + let set_error = RegexSet::new(&[ + OPENING_PAREN, + //~^ERROR: regex syntax error on position 0: unclosed + r"[a-z]+\.(com|org|net)", + ]); + let bset_error = BRegexSet::new(&[ + OPENING_PAREN, + //~^ERROR: regex syntax error on position 0: unclosed + r"[a-z]+\.(com|org|net)", + ]); } fn trivial_regex() { @@ -64,12 +90,17 @@ fn trivial_regex() { //~^ERROR: trivial regex //~|HELP consider using `str::is_empty` + let binary_trivial_empty = BRegex::new("^$"); + //~^ERROR: trivial regex + //~|HELP consider using `str::is_empty` + // non-trivial regexes let non_trivial_dot = Regex::new("a.b"); let non_trivial_eq = Regex::new("^foo|bar$"); let non_trivial_starts_with = Regex::new("^foo|bar"); let non_trivial_ends_with = Regex::new("^foo|bar"); let non_trivial_ends_with = Regex::new("foo|bar"); + let non_trivial_binary = BRegex::new("foo|bar"); } fn main() { -- cgit 1.4.1-3-g733a5 From 51d166f17aa2dd73226152ff7ca6c69f2db5947c Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 25 May 2016 21:36:51 +0200 Subject: Support `RegexBuilder` --- CHANGELOG.md | 4 ++-- src/regex.rs | 4 ++++ src/utils/paths.rs | 2 ++ tests/compile-fail/regex.rs | 14 ++++++++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f17b1dd0837..928fac7412e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ All notable changes to this project will be documented in this file. ## 0.0.70 — TBD -* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new` and - byte regexes +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`, + `RegexBuilder::new` and byte regexes ## 0.0.69 — 2016-05-20 * Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)* diff --git a/src/regex.rs b/src/regex.rs index 8876a649e5d..b335bf993b5 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -104,6 +104,10 @@ impl LateLintPass for RegexPass { check_regex(cx, &args[0], true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) { check_regex(cx, &args[0], false); + } else if match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { + check_regex(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { + check_regex(cx, &args[0], false); } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { check_set(cx, &args[0], true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { diff --git a/src/utils/paths.rs b/src/utils/paths.rs index b0ce8b4a233..3c91578abd0 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -46,7 +46,9 @@ pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclus pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"]; pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; +pub const REGEX_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"]; +pub const REGEX_BYTES_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"]; pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"]; diff --git a/tests/compile-fail/regex.rs b/tests/compile-fail/regex.rs index d9f262fb045..d6287b881a1 100644 --- a/tests/compile-fail/regex.rs +++ b/tests/compile-fail/regex.rs @@ -6,8 +6,8 @@ extern crate regex; -use regex::{Regex, RegexSet}; -use regex::bytes::{Regex as BRegex, RegexSet as BRegexSet}; +use regex::{Regex, RegexSet, RegexBuilder}; +use regex::bytes::{Regex as BRegex, RegexSet as BRegexSet, RegexBuilder as BRegexBuilder}; const OPENING_PAREN : &'static str = "("; const NOT_A_REAL_REGEX : &'static str = "foobar"; @@ -15,6 +15,8 @@ const NOT_A_REAL_REGEX : &'static str = "foobar"; fn syntax_error() { let pipe_in_wrong_position = Regex::new("|"); //~^ERROR: regex syntax error: empty alternate + let pipe_in_wrong_position_builder = RegexBuilder::new("|"); + //~^ERROR: regex syntax error: empty alternate let wrong_char_ranice = Regex::new("[z-a]"); //~^ERROR: regex syntax error: invalid character class range let some_unicode = Regex::new("[é-è]"); @@ -27,6 +29,8 @@ fn syntax_error() { //~^ERROR: regex syntax error: empty alternate let some_binary_regex = BRegex::new(OPENING_PAREN); //~^ERROR: regex syntax error on position 0: unclosed + let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); + //~^ERROR: regex syntax error on position 0: unclosed let closing_paren = ")"; let not_linted = Regex::new(closing_paren); @@ -57,6 +61,10 @@ fn trivial_regex() { //~^ERROR: trivial regex //~|HELP consider using `==` on `str`s + let trivial_eq_builder = RegexBuilder::new("^foobar$"); + //~^ERROR: trivial regex + //~|HELP consider using `==` on `str`s + let trivial_starts_with = Regex::new("^foobar"); //~^ERROR: trivial regex //~|HELP consider using `str::starts_with` @@ -96,11 +104,13 @@ fn trivial_regex() { // non-trivial regexes let non_trivial_dot = Regex::new("a.b"); + let non_trivial_dot_builder = RegexBuilder::new("a.b"); let non_trivial_eq = Regex::new("^foo|bar$"); let non_trivial_starts_with = Regex::new("^foo|bar"); let non_trivial_ends_with = Regex::new("^foo|bar"); let non_trivial_ends_with = Regex::new("foo|bar"); let non_trivial_binary = BRegex::new("foo|bar"); + let non_trivial_binary_builder = BRegexBuilder::new("foo|bar"); } fn main() { -- cgit 1.4.1-3-g733a5 From 8ac545d0fe224791875ed939db787cb311fac406 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Thu, 26 May 2016 00:08:31 +0200 Subject: Fix documentation --- CHANGELOG.md | 2 +- README.md | 4 ++-- src/regex.rs | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 928fac7412e..719e6ee287e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,7 +72,7 @@ All notable changes to this project will be documented in this file. ## ~~0.0.52~~ ## 0.0.51 — 2016-03-13 -* Add `str` to types considered by `len_zero` +* Add `str` to types considered by [`len_zero`] * New lints: [`indexing_slicing`] ## 0.0.50 — 2016-03-11 diff --git a/README.md b/README.md index 4c156dfb7a0..c289116809e 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ name [ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2` [inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases [integer_arithmetic](https://github.com/Manishearth/rust-clippy/wiki#integer_arithmetic) | allow | Any integer arithmetic statement -[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions in `Regex::new(_)` invocations +[invalid_regex](https://github.com/Manishearth/rust-clippy/wiki#invalid_regex) | deny | finds invalid regular expressions [invalid_upcast_comparisons](https://github.com/Manishearth/rust-clippy/wiki#invalid_upcast_comparisons) | allow | a comparison involving an upcast which is always true or false [items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | finds blocks where an item comes after a statement [iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended @@ -150,7 +150,7 @@ name [too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments [toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`. [transmute_ptr_to_ref](https://github.com/Manishearth/rust-clippy/wiki#transmute_ptr_to_ref) | warn | transmutes from a pointer to a reference type -[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations +[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions [type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions [unicode_not_nfc](https://github.com/Manishearth/rust-clippy/wiki#unicode_not_nfc) | allow | using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information) [unit_cmp](https://github.com/Manishearth/rust-clippy/wiki#unit_cmp) | warn | comparing unit values (which is always `true` or `false`, respectively) diff --git a/src/regex.rs b/src/regex.rs index b335bf993b5..c97a64ebf09 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -11,7 +11,8 @@ use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint}; -/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax. +/// **What it does:** This lint checks [regex] creation (with `Regex::new`, `RegexBuilder::new` or +/// `RegexSet::new`) for correct regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. /// @@ -21,10 +22,11 @@ use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_ declare_lint! { pub INVALID_REGEX, Deny, - "finds invalid regular expressions in `Regex::new(_)` invocations" + "finds invalid regular expressions" } -/// **What it does:** This lint checks for `Regex::new(_)` invocations with trivial regex. +/// **What it does:** This lint checks for trivial [regex] creation (with `Regex::new`, +/// `RegexBuilder::new` or `RegexSet::new`). /// /// **Why is this bad?** This can likely be replaced by `==` or `str::starts_with`, /// `str::ends_with` or `std::contains` or other `str` methods. @@ -32,10 +34,12 @@ declare_lint! { /// **Known problems:** None. /// /// **Example:** `Regex::new("^foobar")` +/// +/// [regex]: https://crates.io/crates/regex declare_lint! { pub TRIVIAL_REGEX, Warn, - "finds trivial regular expressions in `Regex::new(_)` invocations" + "finds trivial regular expressions" } /// **What it does:** This lint checks for usage of `regex!(_)` which as of now is usually slower than `Regex::new(_)` unless called in a loop (which is a bad idea anyway). -- cgit 1.4.1-3-g733a5 From 5eca09793e9e6969ce960601d83300e1d6065d97 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 27 May 2016 12:12:38 +0200 Subject: needless_borrow reported on &&T when only &T implements Trait and &Trait is required --- src/needless_borrow.rs | 17 +++++++++-------- tests/compile-fail/needless_borrow.rs | 7 +++++++ 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/needless_borrow.rs b/src/needless_borrow.rs index 294a12dad99..033811841ce 100644 --- a/src/needless_borrow.rs +++ b/src/needless_borrow.rs @@ -3,9 +3,10 @@ //! This lint is **warn** by default use rustc::lint::*; -use rustc::hir::*; +use rustc::hir::{ExprAddrOf, Expr, MutImmutable}; use rustc::ty::TyRef; use utils::{span_lint, in_macro}; +use rustc::ty::adjustment::AutoAdjustment::AdjustDerefRef; /// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler /// @@ -36,13 +37,13 @@ impl LateLintPass for NeedlessBorrow { } if let ExprAddrOf(MutImmutable, ref inner) = e.node { if let TyRef(..) = cx.tcx.expr_ty(inner).sty { - let ty = cx.tcx.expr_ty(e); - let adj_ty = cx.tcx.expr_ty_adjusted(e); - if ty != adj_ty { - span_lint(cx, - NEEDLESS_BORROW, - e.span, - "this expression borrows a reference that is immediately dereferenced by the compiler"); + if let Some(&AdjustDerefRef(ref deref)) = cx.tcx.tables.borrow().adjustments.get(&e.id) { + if deref.autoderefs > 1 && deref.autoref.is_some() { + span_lint(cx, + NEEDLESS_BORROW, + e.span, + "this expression borrows a reference that is immediately dereferenced by the compiler"); + } } } } diff --git a/tests/compile-fail/needless_borrow.rs b/tests/compile-fail/needless_borrow.rs index 242691aa268..602e1e0859b 100644 --- a/tests/compile-fail/needless_borrow.rs +++ b/tests/compile-fail/needless_borrow.rs @@ -16,6 +16,7 @@ fn main() { let g_val = g(&Vec::new()); // should not error, because `&Vec<T>` derefs to `&[T]` let vec = Vec::new(); let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]` + h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait` } fn f<T:Copy>(y: &T) -> T { @@ -25,3 +26,9 @@ fn f<T:Copy>(y: &T) -> T { fn g(y: &[u8]) -> u8 { y[0] } + +trait Trait {} + +impl<'a> Trait for &'a str {} + +fn h(_: &Trait) {} -- cgit 1.4.1-3-g733a5 From bf227f4729ecc63147bacaf05d161f3819d13d7e Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 24 May 2016 18:25:25 +0200 Subject: split clippy into lints, plugin and cargo-clippy --- .gitignore | 1 + Cargo.toml | 2 +- clippy_lints/Cargo.toml | 24 + clippy_lints/src/approx_const.rs | 95 +++ clippy_lints/src/arithmetic.rs | 102 +++ clippy_lints/src/array_indexing.rs | 135 +++ clippy_lints/src/assign_ops.rs | 158 ++++ clippy_lints/src/attrs.rs | 176 ++++ clippy_lints/src/bit_mask.rs | 276 +++++++ clippy_lints/src/blacklisted_name.rs | 46 ++ clippy_lints/src/block_in_if_condition.rs | 118 +++ clippy_lints/src/booleans.rs | 389 +++++++++ clippy_lints/src/collapsible_if.rs | 129 +++ clippy_lints/src/consts.rs | 379 +++++++++ clippy_lints/src/copies.rs | 271 ++++++ clippy_lints/src/cyclomatic_complexity.rs | 187 +++++ clippy_lints/src/deprecated_lints.rs | 44 + clippy_lints/src/derive.rs | 180 ++++ clippy_lints/src/doc.rs | 235 ++++++ clippy_lints/src/drop_ref.rs | 61 ++ clippy_lints/src/entry.rs | 148 ++++ clippy_lints/src/enum_clike.rs | 52 ++ clippy_lints/src/enum_glob_use.rs | 65 ++ clippy_lints/src/enum_variants.rs | 104 +++ clippy_lints/src/eq_op.rs | 60 ++ clippy_lints/src/escape.rs | 172 ++++ clippy_lints/src/eta_reduction.rs | 99 +++ clippy_lints/src/format.rs | 119 +++ clippy_lints/src/formatting.rs | 166 ++++ clippy_lints/src/functions.rs | 76 ++ clippy_lints/src/identity_op.rs | 72 ++ clippy_lints/src/if_not_else.rs | 52 ++ clippy_lints/src/items_after_statements.rs | 70 ++ clippy_lints/src/len_zero.rs | 202 +++++ clippy_lints/src/lib.rs | 416 ++++++++++ clippy_lints/src/lifetimes.rs | 347 ++++++++ clippy_lints/src/loops.rs | 976 ++++++++++++++++++++++ clippy_lints/src/map_clone.rs | 128 +++ clippy_lints/src/matches.rs | 483 +++++++++++ clippy_lints/src/mem_forget.rs | 44 + clippy_lints/src/methods.rs | 1049 ++++++++++++++++++++++++ clippy_lints/src/minmax.rs | 93 +++ clippy_lints/src/misc.rs | 458 +++++++++++ clippy_lints/src/misc_early.rs | 166 ++++ clippy_lints/src/mut_mut.rs | 59 ++ clippy_lints/src/mut_reference.rs | 77 ++ clippy_lints/src/mutex_atomic.rs | 75 ++ clippy_lints/src/needless_bool.rs | 192 +++++ clippy_lints/src/needless_borrow.rs | 51 ++ clippy_lints/src/needless_update.rs | 42 + clippy_lints/src/neg_multiply.rs | 57 ++ clippy_lints/src/new_without_default.rs | 148 ++++ clippy_lints/src/no_effect.rs | 155 ++++ clippy_lints/src/non_expressive_names.rs | 291 +++++++ clippy_lints/src/open_options.rs | 185 +++++ clippy_lints/src/overflow_check_conditional.rs | 72 ++ clippy_lints/src/panic.rs | 47 ++ clippy_lints/src/precedence.rs | 118 +++ clippy_lints/src/print.rs | 88 ++ clippy_lints/src/ptr_arg.rs | 78 ++ clippy_lints/src/ranges.rs | 89 ++ clippy_lints/src/regex.rs | 229 ++++++ clippy_lints/src/returns.rs | 137 ++++ clippy_lints/src/shadow.rs | 353 ++++++++ clippy_lints/src/strings.rs | 160 ++++ clippy_lints/src/swap.rs | 138 ++++ clippy_lints/src/temporary_assignment.rs | 49 ++ clippy_lints/src/transmute.rs | 131 +++ clippy_lints/src/types.rs | 974 ++++++++++++++++++++++ clippy_lints/src/unicode.rs | 109 +++ clippy_lints/src/unsafe_removed_from_name.rs | 81 ++ clippy_lints/src/unused_label.rs | 78 ++ clippy_lints/src/utils/comparisons.rs | 23 + clippy_lints/src/utils/conf.rs | 205 +++++ clippy_lints/src/utils/hir.rs | 513 ++++++++++++ clippy_lints/src/utils/mod.rs | 840 +++++++++++++++++++ clippy_lints/src/utils/paths.rs | 61 ++ clippy_lints/src/vec.rs | 116 +++ clippy_lints/src/zero_div_zero.rs | 59 ++ src/approx_const.rs | 95 --- src/arithmetic.rs | 102 --- src/array_indexing.rs | 135 --- src/assign_ops.rs | 158 ---- src/attrs.rs | 176 ---- src/bit_mask.rs | 276 ------- src/blacklisted_name.rs | 46 -- src/block_in_if_condition.rs | 118 --- src/booleans.rs | 389 --------- src/collapsible_if.rs | 129 --- src/consts.rs | 379 --------- src/copies.rs | 271 ------ src/cyclomatic_complexity.rs | 187 ----- src/deprecated_lints.rs | 44 - src/derive.rs | 180 ---- src/doc.rs | 235 ------ src/drop_ref.rs | 61 -- src/entry.rs | 148 ---- src/enum_clike.rs | 52 -- src/enum_glob_use.rs | 65 -- src/enum_variants.rs | 104 --- src/eq_op.rs | 60 -- src/escape.rs | 172 ---- src/eta_reduction.rs | 99 --- src/format.rs | 119 --- src/formatting.rs | 166 ---- src/functions.rs | 76 -- src/identity_op.rs | 72 -- src/if_not_else.rs | 52 -- src/items_after_statements.rs | 70 -- src/len_zero.rs | 202 ----- src/lib.rs | 527 +----------- src/lifetimes.rs | 347 -------- src/loops.rs | 976 ---------------------- src/main.rs | 167 ++++ src/map_clone.rs | 128 --- src/matches.rs | 483 ----------- src/mem_forget.rs | 44 - src/methods.rs | 1049 ------------------------ src/minmax.rs | 93 --- src/misc.rs | 458 ----------- src/misc_early.rs | 166 ---- src/mut_mut.rs | 59 -- src/mut_reference.rs | 77 -- src/mutex_atomic.rs | 75 -- src/needless_bool.rs | 192 ----- src/needless_borrow.rs | 51 -- src/needless_update.rs | 42 - src/neg_multiply.rs | 57 -- src/new_without_default.rs | 148 ---- src/no_effect.rs | 155 ---- src/non_expressive_names.rs | 291 ------- src/open_options.rs | 185 ----- src/overflow_check_conditional.rs | 72 -- src/panic.rs | 47 -- src/precedence.rs | 118 --- src/print.rs | 88 -- src/ptr_arg.rs | 78 -- src/ranges.rs | 89 -- src/regex.rs | 229 ------ src/returns.rs | 137 ---- src/shadow.rs | 353 -------- src/strings.rs | 160 ---- src/swap.rs | 138 ---- src/temporary_assignment.rs | 49 -- src/transmute.rs | 131 --- src/types.rs | 974 ---------------------- src/unicode.rs | 109 --- src/unsafe_removed_from_name.rs | 81 -- src/unused_label.rs | 78 -- src/utils/comparisons.rs | 23 - src/utils/conf.rs | 205 ----- src/utils/hir.rs | 513 ------------ src/utils/mod.rs | 840 ------------------- src/utils/paths.rs | 61 -- src/vec.rs | 116 --- src/zero_div_zero.rs | 59 -- tests/dogfood.rs | 24 +- util/update_lints.py | 20 +- 158 files changed, 14909 insertions(+), 14796 deletions(-) create mode 100644 clippy_lints/Cargo.toml create mode 100644 clippy_lints/src/approx_const.rs create mode 100644 clippy_lints/src/arithmetic.rs create mode 100644 clippy_lints/src/array_indexing.rs create mode 100644 clippy_lints/src/assign_ops.rs create mode 100644 clippy_lints/src/attrs.rs create mode 100644 clippy_lints/src/bit_mask.rs create mode 100644 clippy_lints/src/blacklisted_name.rs create mode 100644 clippy_lints/src/block_in_if_condition.rs create mode 100644 clippy_lints/src/booleans.rs create mode 100644 clippy_lints/src/collapsible_if.rs create mode 100644 clippy_lints/src/consts.rs create mode 100644 clippy_lints/src/copies.rs create mode 100644 clippy_lints/src/cyclomatic_complexity.rs create mode 100644 clippy_lints/src/deprecated_lints.rs create mode 100644 clippy_lints/src/derive.rs create mode 100644 clippy_lints/src/doc.rs create mode 100644 clippy_lints/src/drop_ref.rs create mode 100644 clippy_lints/src/entry.rs create mode 100644 clippy_lints/src/enum_clike.rs create mode 100644 clippy_lints/src/enum_glob_use.rs create mode 100644 clippy_lints/src/enum_variants.rs create mode 100644 clippy_lints/src/eq_op.rs create mode 100644 clippy_lints/src/escape.rs create mode 100644 clippy_lints/src/eta_reduction.rs create mode 100644 clippy_lints/src/format.rs create mode 100644 clippy_lints/src/formatting.rs create mode 100644 clippy_lints/src/functions.rs create mode 100644 clippy_lints/src/identity_op.rs create mode 100644 clippy_lints/src/if_not_else.rs create mode 100644 clippy_lints/src/items_after_statements.rs create mode 100644 clippy_lints/src/len_zero.rs create mode 100644 clippy_lints/src/lib.rs create mode 100644 clippy_lints/src/lifetimes.rs create mode 100644 clippy_lints/src/loops.rs create mode 100644 clippy_lints/src/map_clone.rs create mode 100644 clippy_lints/src/matches.rs create mode 100644 clippy_lints/src/mem_forget.rs create mode 100644 clippy_lints/src/methods.rs create mode 100644 clippy_lints/src/minmax.rs create mode 100644 clippy_lints/src/misc.rs create mode 100644 clippy_lints/src/misc_early.rs create mode 100644 clippy_lints/src/mut_mut.rs create mode 100644 clippy_lints/src/mut_reference.rs create mode 100644 clippy_lints/src/mutex_atomic.rs create mode 100644 clippy_lints/src/needless_bool.rs create mode 100644 clippy_lints/src/needless_borrow.rs create mode 100644 clippy_lints/src/needless_update.rs create mode 100644 clippy_lints/src/neg_multiply.rs create mode 100644 clippy_lints/src/new_without_default.rs create mode 100644 clippy_lints/src/no_effect.rs create mode 100644 clippy_lints/src/non_expressive_names.rs create mode 100644 clippy_lints/src/open_options.rs create mode 100644 clippy_lints/src/overflow_check_conditional.rs create mode 100644 clippy_lints/src/panic.rs create mode 100644 clippy_lints/src/precedence.rs create mode 100644 clippy_lints/src/print.rs create mode 100644 clippy_lints/src/ptr_arg.rs create mode 100644 clippy_lints/src/ranges.rs create mode 100644 clippy_lints/src/regex.rs create mode 100644 clippy_lints/src/returns.rs create mode 100644 clippy_lints/src/shadow.rs create mode 100644 clippy_lints/src/strings.rs create mode 100644 clippy_lints/src/swap.rs create mode 100644 clippy_lints/src/temporary_assignment.rs create mode 100644 clippy_lints/src/transmute.rs create mode 100644 clippy_lints/src/types.rs create mode 100644 clippy_lints/src/unicode.rs create mode 100644 clippy_lints/src/unsafe_removed_from_name.rs create mode 100644 clippy_lints/src/unused_label.rs create mode 100644 clippy_lints/src/utils/comparisons.rs create mode 100644 clippy_lints/src/utils/conf.rs create mode 100644 clippy_lints/src/utils/hir.rs create mode 100644 clippy_lints/src/utils/mod.rs create mode 100644 clippy_lints/src/utils/paths.rs create mode 100644 clippy_lints/src/vec.rs create mode 100644 clippy_lints/src/zero_div_zero.rs delete mode 100644 src/approx_const.rs delete mode 100644 src/arithmetic.rs delete mode 100644 src/array_indexing.rs delete mode 100644 src/assign_ops.rs delete mode 100644 src/attrs.rs delete mode 100644 src/bit_mask.rs delete mode 100644 src/blacklisted_name.rs delete mode 100644 src/block_in_if_condition.rs delete mode 100644 src/booleans.rs delete mode 100644 src/collapsible_if.rs delete mode 100644 src/consts.rs delete mode 100644 src/copies.rs delete mode 100644 src/cyclomatic_complexity.rs delete mode 100644 src/deprecated_lints.rs delete mode 100644 src/derive.rs delete mode 100644 src/doc.rs delete mode 100644 src/drop_ref.rs delete mode 100644 src/entry.rs delete mode 100644 src/enum_clike.rs delete mode 100644 src/enum_glob_use.rs delete mode 100644 src/enum_variants.rs delete mode 100644 src/eq_op.rs delete mode 100644 src/escape.rs delete mode 100644 src/eta_reduction.rs delete mode 100644 src/format.rs delete mode 100644 src/formatting.rs delete mode 100644 src/functions.rs delete mode 100644 src/identity_op.rs delete mode 100644 src/if_not_else.rs delete mode 100644 src/items_after_statements.rs delete mode 100644 src/len_zero.rs delete mode 100644 src/lifetimes.rs delete mode 100644 src/loops.rs create mode 100644 src/main.rs delete mode 100644 src/map_clone.rs delete mode 100644 src/matches.rs delete mode 100644 src/mem_forget.rs delete mode 100644 src/methods.rs delete mode 100644 src/minmax.rs delete mode 100644 src/misc.rs delete mode 100644 src/misc_early.rs delete mode 100644 src/mut_mut.rs delete mode 100644 src/mut_reference.rs delete mode 100644 src/mutex_atomic.rs delete mode 100644 src/needless_bool.rs delete mode 100644 src/needless_borrow.rs delete mode 100644 src/needless_update.rs delete mode 100644 src/neg_multiply.rs delete mode 100644 src/new_without_default.rs delete mode 100644 src/no_effect.rs delete mode 100644 src/non_expressive_names.rs delete mode 100644 src/open_options.rs delete mode 100644 src/overflow_check_conditional.rs delete mode 100644 src/panic.rs delete mode 100644 src/precedence.rs delete mode 100644 src/print.rs delete mode 100644 src/ptr_arg.rs delete mode 100644 src/ranges.rs delete mode 100644 src/regex.rs delete mode 100644 src/returns.rs delete mode 100644 src/shadow.rs delete mode 100644 src/strings.rs delete mode 100644 src/swap.rs delete mode 100644 src/temporary_assignment.rs delete mode 100644 src/transmute.rs delete mode 100644 src/types.rs delete mode 100644 src/unicode.rs delete mode 100644 src/unsafe_removed_from_name.rs delete mode 100644 src/unused_label.rs delete mode 100644 src/utils/comparisons.rs delete mode 100644 src/utils/conf.rs delete mode 100644 src/utils/hir.rs delete mode 100644 src/utils/mod.rs delete mode 100644 src/utils/paths.rs delete mode 100644 src/vec.rs delete mode 100644 src/zero_div_zero.rs (limited to 'src') diff --git a/.gitignore b/.gitignore index acb3c020fe7..2db1ec5144f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ # Generated by Cargo /target/ +/clippy_lints/target/ # We don't pin yet Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index fd0b07428c0..3a45da08f89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ test = false [[bin]] name = "cargo-clippy" -path = "src/lib.rs" test = false [dependencies] @@ -30,6 +29,7 @@ semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" quine-mc_cluskey = "0.2.2" +clippy_lints = { version = "0.0.*", path = "clippy_lints" } [dev-dependencies] compiletest_rs = "0.1.0" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml new file mode 100644 index 00000000000..da10ca0c0b7 --- /dev/null +++ b/clippy_lints/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "clippy_lints" +version = "0.0.69" +authors = [ + "Manish Goregaokar <manishsmail@gmail.com>", + "Andre Bogus <bogusandre@gmail.com>", + "Georg Brandl <georg@python.org>", + "Martin Carton <cartonmartin@gmail.com>" +] +description = "A bunch of helpful lints to avoid common pitfalls in Rust" +repository = "https://github.com/Manishearth/rust-clippy" +readme = "README.md" +license = "MPL-2.0" +keywords = ["clippy", "lint", "plugin"] + +[dependencies] +regex-syntax = "0.3.0" +semver = "0.2.1" +toml = "0.1" +unicode-normalization = "0.1" +quine-mc_cluskey = "0.2.2" + +[features] +debugging = [] diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs new file mode 100644 index 00000000000..731f1a45d09 --- /dev/null +++ b/clippy_lints/src/approx_const.rs @@ -0,0 +1,95 @@ +use rustc::lint::*; +use rustc::hir::*; +use std::f64::consts as f64; +use syntax::ast::{Lit, LitKind, FloatTy}; +use utils::span_lint; + +/// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. +/// +/// **Why is this bad?** Usually, the definition in the standard library is more precise than what people come up with. If you find that your definition is actually more precise, please [file a Rust issue](https://github.com/rust-lang/rust/issues). +/// +/// **Known problems:** If you happen to have a value that is within 1/8192 of a known constant, but is not *and should not* be the same, this lint will report your value anyway. We have not yet noticed any false positives in code we tested clippy with (this includes servo), but YMMV. +/// +/// **Example:** `let x = 3.14;` +declare_lint! { + pub APPROX_CONSTANT, + Warn, + "the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) \ + is found; suggests to use the constant" +} + +// Tuples are of the form (constant, name, min_digits) +const KNOWN_CONSTS: &'static [(f64, &'static str, usize)] = &[(f64::E, "E", 4), + (f64::FRAC_1_PI, "FRAC_1_PI", 4), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), + (f64::FRAC_2_PI, "FRAC_2_PI", 5), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), + (f64::FRAC_PI_2, "FRAC_PI_2", 5), + (f64::FRAC_PI_3, "FRAC_PI_3", 5), + (f64::FRAC_PI_4, "FRAC_PI_4", 5), + (f64::FRAC_PI_6, "FRAC_PI_6", 5), + (f64::FRAC_PI_8, "FRAC_PI_8", 5), + (f64::LN_10, "LN_10", 5), + (f64::LN_2, "LN_2", 5), + (f64::LOG10_E, "LOG10_E", 5), + (f64::LOG2_E, "LOG2_E", 5), + (f64::PI, "PI", 3), + (f64::SQRT_2, "SQRT_2", 5)]; + +#[derive(Copy,Clone)] +pub struct ApproxConstant; + +impl LintPass for ApproxConstant { + fn get_lints(&self) -> LintArray { + lint_array!(APPROX_CONSTANT) + } +} + +impl LateLintPass for ApproxConstant { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprLit(ref lit) = e.node { + check_lit(cx, lit, e); + } + } +} + +fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { + match lit.node { + LitKind::Float(ref s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"), + LitKind::Float(ref s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"), + LitKind::FloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), + _ => (), + } +} + +fn check_known_consts(cx: &LateContext, e: &Expr, s: &str, module: &str) { + if let Ok(_) = s.parse::<f64>() { + for &(constant, name, min_digits) in KNOWN_CONSTS { + if is_approx_const(constant, s, min_digits) { + span_lint(cx, + APPROX_CONSTANT, + e.span, + &format!("approximate value of `{}::{}` found. Consider using it directly", module, &name)); + return; + } + } + } +} + +/// Returns false if the number of significant figures in `value` are +/// less than `min_digits`; otherwise, returns true if `value` is equal +/// to `constant`, rounded to the number of digits present in `value`. +fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { + if value.len() <= min_digits { + false + } else { + let round_const = format!("{:.*}", value.len() - 2, constant); + + let mut trunc_const = constant.to_string(); + if trunc_const.len() > value.len() { + trunc_const.truncate(value.len()); + } + + (value == round_const) || (value == trunc_const) + } +} diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs new file mode 100644 index 00000000000..be732740442 --- /dev/null +++ b/clippy_lints/src/arithmetic.rs @@ -0,0 +1,102 @@ +use rustc::hir; +use rustc::lint::*; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** This lint checks for plain integer arithmetic +/// +/// **Why is this bad?** This is only checked against overflow in debug builds. +/// In some applications one wants explicitly checked, wrapping or saturating +/// arithmetic. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// a + 1 +/// ``` +declare_restriction_lint! { + pub INTEGER_ARITHMETIC, + "Any integer arithmetic statement" +} + +/// **What it does:** This lint checks for float arithmetic +/// +/// **Why is this bad?** For some embedded systems or kernel development, it +/// can be useful to rule out floating-point numbers +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// a + 1.0 +/// ``` +declare_restriction_lint! { + pub FLOAT_ARITHMETIC, + "Any floating-point arithmetic statement" +} + +#[derive(Copy, Clone, Default)] +pub struct Arithmetic { + span: Option<Span> +} + +impl LintPass for Arithmetic { + fn get_lints(&self) -> LintArray { + lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC) + } +} + +impl LateLintPass for Arithmetic { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + if let Some(_) = self.span { return; } + match expr.node { + hir::ExprBinary(ref op, ref l, ref r) => { + match op.node { + hir::BiAnd | hir::BiOr | hir::BiBitAnd | + hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | + hir::BiGt => return, + _ => () + } + let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r)); + if l_ty.is_integral() && r_ty.is_integral() { + span_lint(cx, + INTEGER_ARITHMETIC, + expr.span, + "integer arithmetic detected"); + self.span = Some(expr.span); + } else if l_ty.is_floating_point() && r_ty.is_floating_point() { + 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.expr_ty(arg); + if ty.is_integral() { + span_lint(cx, + INTEGER_ARITHMETIC, + expr.span, + "integer arithmetic detected"); + self.span = Some(expr.span); + } else if ty.is_floating_point() { + 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) { + 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 new file mode 100644 index 00000000000..ce2b9a7d6c0 --- /dev/null +++ b/clippy_lints/src/array_indexing.rs @@ -0,0 +1,135 @@ +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc::ty::TyArray; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_math::ConstInt; +use rustc::hir::*; +use syntax::ast::RangeLimits; +use utils; + +/// **What it does:** Check for out of bounds array indexing with a constant index. +/// +/// **Why is this bad?** This will always panic at runtime. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// let x = [1,2,3,4]; +/// ... +/// x[9]; +/// &x[2..9]; +/// ``` +declare_lint! { + pub OUT_OF_BOUNDS_INDEXING, + Deny, + "out of bound constant indexing" +} + +/// **What it does:** Check for usage of indexing or slicing. +/// +/// **Why is this bad?** Usually, this can be safely allowed. However, +/// in some domains such as kernel development, a panic can cause the +/// whole operating system to crash. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ``` +/// ... +/// x[2]; +/// &x[0..2]; +/// ``` +declare_lint! { + pub INDEXING_SLICING, + Allow, + "indexing/slicing usage" +} + +#[derive(Copy,Clone)] +pub struct ArrayIndexing; + +impl LintPass for ArrayIndexing { + fn get_lints(&self) -> LintArray { + lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING) + } +} + +impl LateLintPass for ArrayIndexing { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprIndex(ref array, ref index) = e.node { + // Array with known size can be checked statically + let ty = cx.tcx.expr_ty(array); + if let TyArray(_, size) = ty.sty { + let size = ConstInt::Infer(size as u64); + + // Index is a constant uint + let const_index = eval_const_expr_partial(cx.tcx, index, ExprTypeChecked, None); + if let Ok(ConstVal::Integral(const_index)) = const_index { + if size <= const_index { + utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); + } + + return; + } + + // Index is a constant range + if let Some(range) = utils::unsugar_range(index) { + let start = range.start + .map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)) + .map(|v| v.ok()); + let end = range.end + .map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)) + .map(|v| v.ok()); + + if let Some((start, end)) = to_const_range(start, end, range.limits, size) { + if start > size || end > size { + utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds"); + } + return; + } + } + } + + if let Some(range) = utils::unsugar_range(index) { + // Full ranges are always valid + if range.start.is_none() && range.end.is_none() { + return; + } + + // Impossible to know if indexing or slicing is correct + utils::span_lint(cx, INDEXING_SLICING, e.span, "slicing may panic"); + } else { + utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic"); + } + } + } +} + +/// Returns an option containing a tuple with the start and end (exclusive) of the range. +fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, + array_size: ConstInt) + -> Option<(ConstInt, ConstInt)> { + let start = match start { + Some(Some(ConstVal::Integral(x))) => x, + Some(_) => return None, + None => ConstInt::Infer(0), + }; + + let end = match end { + Some(Some(ConstVal::Integral(x))) => { + if limits == RangeLimits::Closed { + (x + ConstInt::Infer(1)).expect("such a big array is not realistic") + } else { + x + } + } + Some(_) => return None, + None => array_size, + }; + + Some((start, end)) +} diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs new file mode 100644 index 00000000000..2b1aec83e4c --- /dev/null +++ b/clippy_lints/src/assign_ops.rs @@ -0,0 +1,158 @@ +use rustc::hir; +use rustc::lint::*; +use utils::{span_lint_and_then, span_lint, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait}; + +/// **What it does:** This lint checks for `+=` operations and similar +/// +/// **Why is this bad?** Projects with many developers from languages without those operations +/// may find them unreadable and not worth their weight +/// +/// **Known problems:** Types implementing `OpAssign` don't necessarily implement `Op` +/// +/// **Example:** +/// ``` +/// a += 1; +/// ``` +declare_restriction_lint! { + pub ASSIGN_OPS, + "Any assignment operation" +} + +/// **What it does:** Check for `a = a op b` or `a = b commutative_op a` patterns +/// +/// **Why is this bad?** These can be written as the shorter `a op= b` +/// +/// **Known problems:** While forbidden by the spec, `OpAssign` traits may have implementations that differ from the regular `Op` impl +/// +/// **Example:** +/// +/// ``` +/// let mut a = 5; +/// ... +/// a = a + b; +/// ``` +declare_lint! { + pub ASSIGN_OP_PATTERN, + Warn, + "assigning the result of an operation on a variable to that same variable" +} + +#[derive(Copy, Clone, Default)] +pub struct AssignOps; + +impl LintPass for AssignOps { + fn get_lints(&self) -> LintArray { + lint_array!(ASSIGN_OPS, ASSIGN_OP_PATTERN) + } +} + +impl LateLintPass for AssignOps { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + match expr.node { + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + if let (Some(l), Some(r)) = (snippet_opt(cx, lhs.span), snippet_opt(cx, rhs.span)) { + span_lint_and_then(cx, + ASSIGN_OPS, + expr.span, + "assign operation detected", + |db| { + match rhs.node { + hir::ExprBinary(op2, _, _) if op2 != op => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} ({})", l, l, op.node.as_str(), r)); + }, + _ => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} {}", l, l, op.node.as_str(), r)); + } + } + }); + } else { + span_lint(cx, + ASSIGN_OPS, + expr.span, + "assign operation detected"); + } + }, + 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| { + let ty = cx.tcx.expr_ty(assignee); + if ty.walk_shallow().next().is_some() { + return; // implements_trait does not work with generics + } + let rty = cx.tcx.expr_ty(rhs); + if rty.walk_shallow().next().is_some() { + return; // implements_trait does not work with generics + } + macro_rules! ops { + ($op:expr, $cx:expr, $ty:expr, $rty:expr, $($trait_name:ident:$full_trait_name:ident),+) => { + match $op { + $(hir::$full_trait_name => { + let [krate, module] = ::utils::paths::OPS_MODULE; + let path = [krate, module, concat!(stringify!($trait_name), "Assign")]; + let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) { + trait_id + } else { + return; // useless if the trait doesn't exist + }; + implements_trait($cx, $ty, trait_id, vec![$rty]) + },)* + _ => false, + } + } + } + if ops!(op.node, cx, ty, rty, Add:BiAdd, + Sub:BiSub, + Mul:BiMul, + Div:BiDiv, + Rem:BiRem, + And:BiAnd, + Or:BiOr, + BitAnd:BiBitAnd, + BitOr:BiBitOr, + BitXor:BiBitXor, + Shr:BiShr, + Shl:BiShl + ) { + if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { + span_lint_and_then(cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation", + |db| { + db.span_suggestion(expr.span, + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); + }); + } else { + span_lint(cx, + ASSIGN_OP_PATTERN, + expr.span, + "manual implementation of an assign operation"); + } + } + }; + // a = a op b + if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) { + lint(assignee, r); + } + // a = b commutative_op a + if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { + match op.node { + hir::BiAdd | hir::BiMul | + hir::BiAnd | hir::BiOr | + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr => { + lint(assignee, l); + }, + _ => {}, + } + } + } + }, + _ => {}, + } + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs new file mode 100644 index 00000000000..0cf62633de4 --- /dev/null +++ b/clippy_lints/src/attrs.rs @@ -0,0 +1,176 @@ +//! checks for attributes + +use reexport::*; +use rustc::lint::*; +use rustc::hir::*; +use semver::Version; +use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; +use syntax::codemap::Span; +use utils::{in_macro, match_path, span_lint}; +use utils::paths; + +/// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. +/// +/// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it. +/// +/// As a rule of thumb, before slapping `#[inline(always)]` on a function, measure if that additional function call really affects your runtime profile sufficiently to make up for the increase in compile time. +/// +/// **Known problems:** False positives, big time. This lint is meant to be deactivated by everyone doing serious performance work. This means having done the measurement. +/// +/// **Example:** +/// ``` +/// #[inline(always)] +/// fn not_quite_hot_code(..) { ... } +/// ``` +declare_lint! { + pub INLINE_ALWAYS, Warn, + "`#[inline(always)]` is a bad idea in most cases" +} + +/// **What it does:** This lint checks for `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. +/// +/// **Why is this bad?** For checking the version of the deprecation, it must be valid semver. Failing that, the contained information is useless. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// #[deprecated(since = "forever")] +/// fn something_else(..) { ... } +/// ``` +declare_lint! { + pub DEPRECATED_SEMVER, Warn, + "`Warn` on `#[deprecated(since = \"x\")]` where x is not semver" +} + +#[derive(Copy,Clone)] +pub struct AttrPass; + +impl LintPass for AttrPass { + fn get_lints(&self) -> LintArray { + lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER) + } +} + +impl LateLintPass for AttrPass { + fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) { + if let MetaItemKind::List(ref name, ref items) = attr.node.value.node { + if items.is_empty() || name != &"deprecated" { + return; + } + for ref item in items { + if let MetaItemKind::NameValue(ref name, ref lit) = item.node { + if name == &"since" { + check_semver(cx, item.span, lit); + } + } + } + } + } + + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if is_relevant_item(item) { + check_attrs(cx, item.span, &item.name, &item.attrs) + } + } + + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + if is_relevant_impl(item) { + check_attrs(cx, item.span, &item.name, &item.attrs) + } + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + if is_relevant_trait(item) { + check_attrs(cx, item.span, &item.name, &item.attrs) + } + } +} + +fn is_relevant_item(item: &Item) -> bool { + if let ItemFn(_, _, _, _, _, ref block) = item.node { + is_relevant_block(block) + } else { + false + } +} + +fn is_relevant_impl(item: &ImplItem) -> bool { + match item.node { + ImplItemKind::Method(_, ref block) => is_relevant_block(block), + _ => false, + } +} + +fn is_relevant_trait(item: &TraitItem) -> bool { + match item.node { + MethodTraitItem(_, None) => true, + MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), + _ => false, + } +} + +fn is_relevant_block(block: &Block) -> bool { + for stmt in &block.stmts { + match stmt.node { + StmtDecl(_, _) => return true, + StmtExpr(ref expr, _) | + StmtSemi(ref expr, _) => { + return is_relevant_expr(expr); + } + } + } + block.expr.as_ref().map_or(false, |e| is_relevant_expr(e)) +} + +fn is_relevant_expr(expr: &Expr) -> bool { + match expr.node { + ExprBlock(ref block) => is_relevant_block(block), + ExprRet(Some(ref e)) => is_relevant_expr(e), + ExprRet(None) | ExprBreak(_) => false, + ExprCall(ref path_expr, _) => { + if let ExprPath(_, ref path) = path_expr.node { + !match_path(path, &paths::BEGIN_PANIC) + } else { + true + } + } + _ => true, + } +} + +fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { + if in_macro(cx, span) { + return; + } + + for attr in attrs { + if let MetaItemKind::List(ref inline, ref values) = attr.node.value.node { + if values.len() != 1 || inline != &"inline" { + continue; + } + if let MetaItemKind::Word(ref always) = values[0].node { + if always != &"always" { + continue; + } + span_lint(cx, + INLINE_ALWAYS, + attr.span, + &format!("you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", + name)); + } + } + } +} + +fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { + if let LitKind::Str(ref is, _) = lit.node { + if Version::parse(&*is).is_ok() { + return; + } + } + span_lint(cx, + DEPRECATED_SEMVER, + span, + "the since field must contain a semver-compliant version"); +} diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs new file mode 100644 index 00000000000..aec0990dcc6 --- /dev/null +++ b/clippy_lints/src/bit_mask.rs @@ -0,0 +1,276 @@ +use rustc::hir::*; +use rustc::hir::def::{Def, PathResolution}; +use rustc::lint::*; +use rustc_const_eval::lookup_const_by_id; +use syntax::ast::LitKind; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** This lint checks for incompatible bit masks in comparisons. +/// +/// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: +/// +/// |Comparison |Bit Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// +/// **Why is this bad?** If the bits that the comparison cares about are always set to zero or one by the bit mask, the comparison is constant `true` or `false` (depending on mask, compared value, and operators). +/// +/// So the code is actively misleading, and the only reason someone would write this intentionally is to win an underhanded Rust contest or create a test-case for this lint. +/// +/// **Known problems:** None +/// +/// **Example:** `x & 1 == 2` (also see table above) +declare_lint! { + pub BAD_BIT_MASK, + Warn, + "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \ + (because in the example `select` containing bits that `mask` doesn't have)" +} + +/// **What it does:** This lint checks for bit masks in comparisons which can be removed without changing the outcome. The basic structure can be seen in the following table: +/// +/// |Comparison| Bit Op |Example |equals | +/// |----------|---------|-----------|-------| +/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| +/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| +/// +/// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask), but still a bit misleading, because the bit mask is ineffective. +/// +/// **Known problems:** False negatives: This lint will only match instances where we have figured out the math (which is for a power-of-two compared value). This means things like `x | 1 >= 7` (which would be better written as `x >= 6`) will not be reported (but bit masks like this are fairly uncommon). +/// +/// **Example:** `x | 1 > 3` (also see table above) +declare_lint! { + pub INEFFECTIVE_BIT_MASK, + Warn, + "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`" +} + +/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. +/// This cannot work because the bit that makes up the value two was +/// zeroed out by the bit-and with 1. So the formula for detecting if an +/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` +/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , +/// `!=`, `>=`, `>`}) can be determined from the following table: +/// +/// |Comparison |Bit Op|Example |is always|Formula | +/// |------------|------|------------|---------|----------------------| +/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | +/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | +/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | +/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | +/// +/// This lint is **deny** by default +/// +/// There is also a lint that warns on ineffective masks that is *warn* +/// by default. +/// +/// |Comparison|Bit Op |Example |equals |Formula| +/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`| +/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` | +/// +/// `¹ power_of_two(c + 1)` +#[derive(Copy,Clone)] +pub struct BitMask; + +impl LintPass for BitMask { + fn get_lints(&self) -> LintArray { + lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) + } +} + +impl LateLintPass for BitMask { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + if cmp.node.is_comparison() { + fetch_int_literal(cx, right).map_or_else(|| { + fetch_int_literal(cx, left).map_or((), |cmp_val| { + check_compare(cx, + right, + invert_cmp(cmp.node), + cmp_val, + &e.span) + }) + }, + |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, &e.span)) + } + } + } +} + +fn invert_cmp(cmp: BinOp_) -> BinOp_ { + match cmp { + BiEq => BiEq, + BiNe => BiNe, + BiLt => BiGt, + BiGt => BiLt, + BiLe => BiGe, + BiGe => BiLe, + _ => BiOr, // Dummy + } +} + + +fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { + if let ExprBinary(ref op, ref left, ref right) = bit_op.node { + if op.node != BiBitAnd && op.node != BiBitOr { + return; + } + fetch_int_literal(cx, right) + .or_else(|| fetch_int_literal(cx, left)) + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) + } +} + +fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { + match cmp_op { + BiEq | BiNe => { + match bit_op { + BiBitAnd => { + if mask_value & cmp_value != cmp_value { + if cmp_value != 0 { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` can never be equal to `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` can never be equal to `{}`", + mask_value, + cmp_value)); + } + } + _ => (), + } + } + BiLt | BiGe => { + match bit_op { + BiBitAnd => { + if mask_value < cmp_value { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` will always be lower than `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` will never be lower than `{}`", + mask_value, + cmp_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 => { + if mask_value <= cmp_value { + span_lint(cx, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ & {}` will never be higher than `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!("incompatible bit mask: `_ | {}` will always be higher than `{}`", + mask_value, + cmp_value)); + } else { + check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); + } + } + BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), + _ => (), + } + } + _ => (), + } +} + +fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { + if c.is_power_of_two() && m < c { + span_lint(cx, + INEFFECTIVE_BIT_MASK, + span, + &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c)); + } +} + +fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { + if (c + 1).is_power_of_two() && m <= c { + span_lint(cx, + INEFFECTIVE_BIT_MASK, + span, + &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c)); + } +} + +fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { + match lit.node { + ExprLit(ref lit_ptr) => { + if let LitKind::Int(value, _) = lit_ptr.node { + Some(value) //TODO: Handle sign + } 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, + } + } + .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 new file mode 100644 index 00000000000..5cb84f62651 --- /dev/null +++ b/clippy_lints/src/blacklisted_name.rs @@ -0,0 +1,46 @@ +use rustc::lint::*; +use rustc::hir::*; +use utils::span_lint; + +/// **What it does:** This lints about usage of blacklisted names. +/// +/// **Why is this bad?** These names are usually placeholder names and should be avoided. +/// +/// **Known problems:** None. +/// +/// **Example:** `let foo = 3.14;` +declare_lint! { + pub BLACKLISTED_NAME, + Warn, + "usage of a blacklisted/placeholder name" +} + +#[derive(Clone, Debug)] +pub struct BlackListedName { + blacklist: Vec<String>, +} + +impl BlackListedName { + pub fn new(blacklist: Vec<String>) -> BlackListedName { + BlackListedName { blacklist: blacklist } + } +} + +impl LintPass for BlackListedName { + fn get_lints(&self) -> LintArray { + lint_array!(BLACKLISTED_NAME) + } +} + +impl LateLintPass for BlackListedName { + fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { + if let PatKind::Ident(_, ref ident, _) = pat.node { + if self.blacklist.iter().any(|s| s == &*ident.node.as_str()) { + span_lint(cx, + BLACKLISTED_NAME, + pat.span, + &format!("use of a blacklisted/placeholder name `{}`", ident.node)); + } + } + } +} diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs new file mode 100644 index 00000000000..c56cf4dcd29 --- /dev/null +++ b/clippy_lints/src/block_in_if_condition.rs @@ -0,0 +1,118 @@ +use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr}; +use utils::*; + +/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. +/// +/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions. +/// +/// **Known problems:** None +/// +/// **Example:** `if { true } ..` +declare_lint! { + pub BLOCK_IN_IF_CONDITION_EXPR, Warn, + "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" +} + +/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. +/// +/// **Why is this bad?** Using blocks in the condition makes it hard to read. +/// +/// **Known problems:** None +/// +/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..` +declare_lint! { + pub BLOCK_IN_IF_CONDITION_STMT, Warn, + "avoid complex blocks in conditions, instead move the block higher and bind it \ + with 'let'; e.g: `if { let x = true; x } ...`" +} + +#[derive(Copy,Clone)] +pub struct BlockInIfCondition; + +impl LintPass for BlockInIfCondition { + fn get_lints(&self) -> LintArray { + lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT) + } +} + +struct ExVisitor<'v> { + found_block: Option<&'v Expr>, +} + +impl<'v> Visitor<'v> for ExVisitor<'v> { + fn visit_expr(&mut self, expr: &'v Expr) { + if let ExprClosure(_, _, ref block, _) = expr.node { + let complex = { + if block.stmts.is_empty() { + if let Some(ref ex) = block.expr { + match ex.node { + ExprBlock(_) => true, + _ => false, + } + } else { + false + } + } else { + true + } + }; + if complex { + self.found_block = Some(expr); + return; + } + } + walk_expr(self, expr); + } +} + +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) { + if let ExprIf(ref check, ref then, _) = expr.node { + if let ExprBlock(ref block) = check.node { + if block.rules == DefaultBlock { + if block.stmts.is_empty() { + if let Some(ref ex) = block.expr { + // don't dig into the expression here, just suggest that they remove + // the block + if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, ex.span) { + return; + } + span_help_and_lint(cx, + BLOCK_IN_IF_CONDITION_EXPR, + check.span, + BRACED_EXPR_MESSAGE, + &format!("try\nif {} {} ... ", + snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, ".."))); + } + } else { + let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); + if in_macro(cx, span) || differing_macro_contexts(expr.span, span) { + return; + } + // move block higher + span_help_and_lint(cx, + BLOCK_IN_IF_CONDITION_STMT, + check.span, + COMPLEX_BLOCK_MESSAGE, + &format!("try\nlet res = {};\nif res {} ... ", + snippet_block(cx, block.span, ".."), + snippet_block(cx, then.span, ".."))); + } + } + } else { + let mut visitor = ExVisitor { found_block: None }; + walk_expr(&mut visitor, check); + if let Some(ref block) = visitor.found_block { + span_help_and_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 new file mode 100644 index 00000000000..9ab806f66ec --- /dev/null +++ b/clippy_lints/src/booleans.rs @@ -0,0 +1,389 @@ +use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; +use rustc::hir::*; +use rustc::hir::intravisit::*; +use syntax::ast::{LitKind, DUMMY_NODE_ID}; +use syntax::codemap::{DUMMY_SP, dummy_spanned}; +use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; + +/// **What it does:** This lint checks for boolean expressions that can be written more concisely +/// +/// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication +/// +/// **Known problems:** Ignores short circuting behavior of `||` and `&&`. Ignores `|`, `&` and `^`. +/// +/// **Example:** `if a && true` should be `if a` and `!(a == b)` should be `a != b` +declare_lint! { + pub NONMINIMAL_BOOL, Allow, + "checks for boolean expressions that can be written more concisely" +} + +/// **What it does:** This lint checks for boolean expressions that contain terminals that can be eliminated +/// +/// **Why is this bad?** This is most likely a logic bug +/// +/// **Known problems:** Ignores short circuiting behavior +/// +/// **Example:** The `b` in `if a && b || a` is unnecessary because the expression is equivalent to `if a` +declare_lint! { + pub LOGIC_BUG, Warn, + "checks for boolean expressions that contain terminals which can be eliminated" +} + +#[derive(Copy,Clone)] +pub struct NonminimalBool; + +impl LintPass for NonminimalBool { + fn get_lints(&self) -> LintArray { + lint_array!(NONMINIMAL_BOOL, LOGIC_BUG) + } +} + +impl LateLintPass for NonminimalBool { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + NonminimalBoolVisitor(cx).visit_item(item) + } +} + +struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); + +use quine_mc_cluskey::Bool; +struct Hir2Qmm<'a, 'tcx: 'a, 'v> { + terminals: Vec<&'v Expr>, + cx: &'a LateContext<'a, 'tcx>, +} + +impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { + fn extract(&mut self, op: BinOp_, a: &[&'v Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> { + for a in a { + if let ExprBinary(binop, ref lhs, ref rhs) = a.node { + if binop.node == op { + v = self.extract(op, &[lhs, rhs], v)?; + continue; + } + } + v.push(self.run(a)?); + } + Ok(v) + } + + fn run(&mut self, e: &'v Expr) -> Result<Bool, String> { + // prevent folding of `cfg!` macros and the like + if !in_macro(self.cx, e.span) { + match e.node { + ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), + ExprBinary(binop, ref lhs, ref rhs) => { + match binop.node { + BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), + 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), + _ => (), + } + } + _ => (), + } + } + for (n, expr) in self.terminals.iter().enumerate() { + if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { + #[allow(cast_possible_truncation)] + return Ok(Bool::Term(n as u8)); + } + let negated = match e.node { + ExprBinary(binop, ref lhs, ref rhs) => { + let mk_expr = |op| { + Expr { + id: DUMMY_NODE_ID, + span: DUMMY_SP, + attrs: None, + node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), + } + }; + match binop.node { + BiEq => mk_expr(BiNe), + BiNe => mk_expr(BiEq), + BiGt => mk_expr(BiLe), + BiGe => mk_expr(BiLt), + BiLt => mk_expr(BiGe), + BiLe => mk_expr(BiGt), + _ => continue, + } + } + _ => continue, + }; + if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { + #[allow(cast_possible_truncation)] + return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); + } + } + let n = self.terminals.len(); + self.terminals.push(e); + if n < 32 { + #[allow(cast_possible_truncation)] + Ok(Bool::Term(n as u8)) + } else { + Err("too many literals".to_owned()) + } + } +} + +fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { + fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { + use quine_mc_cluskey::Bool::*; + let snip = |e: &Expr| snippet_opt(cx, e.span).expect("don't try to improve booleans created by macros"); + match *suggestion { + 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 { + BiEq => " != ", + BiNe => " == ", + BiLt => " >= ", + BiGt => " <= ", + BiLe => " > ", + BiGe => " < ", + _ => { + s.push('!'); + return recurse(true, cx, inner, terminals, s); + } + }; + s.push_str(&snip(lhs)); + s.push_str(op); + s.push_str(&snip(rhs)); + s + } else { + s.push('!'); + recurse(false, cx, inner, terminals, s) + } + } + _ => { + s.push('!'); + recurse(false, cx, inner, terminals, s) + } + } + } + And(ref v) => { + if brackets { + s.push('('); + } + if let Or(_) = v[0] { + s = recurse(true, cx, &v[0], terminals, s); + } else { + s = recurse(false, cx, &v[0], terminals, s); + } + for inner in &v[1..] { + s.push_str(" && "); + if let Or(_) = *inner { + s = recurse(true, cx, inner, terminals, s); + } else { + s = recurse(false, cx, inner, terminals, s); + } + } + if brackets { + s.push(')'); + } + s + } + Or(ref v) => { + if brackets { + s.push('('); + } + s = recurse(false, cx, &v[0], terminals, s); + for inner in &v[1..] { + s.push_str(" || "); + s = recurse(false, cx, inner, terminals, s); + } + if brackets { + s.push(')'); + } + s + } + Term(n) => { + if brackets { + if let ExprBinary(..) = terminals[n as usize].node { + s.push('('); + } + } + s.push_str(&snip(terminals[n as usize])); + if brackets { + if let ExprBinary(..) = terminals[n as usize].node { + s.push(')'); + } + } + s + } + } + } + recurse(false, cx, suggestion, terminals, String::new()) +} + +fn simple_negate(b: Bool) -> Bool { + use quine_mc_cluskey::Bool::*; + match b { + True => False, + False => True, + t @ Term(_) => Not(Box::new(t)), + And(mut v) => { + for el in &mut v { + *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, + } +} + +#[derive(Default)] +struct Stats { + terminals: [usize; 32], + negations: usize, + ops: usize, +} + +fn terminal_stats(b: &Bool) -> Stats { + fn recurse(b: &Bool, stats: &mut Stats) { + match *b { + True | False => stats.ops += 1, + Not(ref inner) => { + match **inner { + And(_) | Or(_) => stats.ops += 1, // brackets are also operations + _ => 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, + } + } + use quine_mc_cluskey::Bool::*; + let mut stats = Stats::default(); + recurse(b, &mut stats); + stats +} + +impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { + fn bool_expr(&self, e: &Expr) { + let mut h2q = Hir2Qmm { + terminals: Vec::new(), + cx: self.0, + }; + if let Ok(expr) = h2q.run(e) { + + if h2q.terminals.len() > 8 { + // QMC has exponentially slow behavior as the number of terminals increases + // 8 is reasonable, it takes approximately 0.2 seconds. + // See #825 + return; + } + + let stats = terminal_stats(&expr); + let mut simplified = expr.simplify(); + for simple in Bool::Not(Box::new(expr.clone())).simplify() { + match simple { + Bool::Not(_) | Bool::True | Bool::False => {} + _ => simplified.push(Bool::Not(Box::new(simple.clone()))), + } + let simple_negated = simple_negate(simple); + if simplified.iter().any(|s| *s == simple_negated) { + continue; + } + simplified.push(simple_negated); + } + let mut improvements = Vec::new(); + 'simplified: for suggestion in &simplified { + let simplified_stats = terminal_stats(suggestion); + let mut improvement = false; + for i in 0..32 { + // ignore any "simplifications" that end up requiring a terminal more often than in the original expression + if stats.terminals[i] < simplified_stats.terminals[i] { + continue 'simplified; + } + if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { + span_lint_and_then(self.0, + LOGIC_BUG, + e.span, + "this boolean expression contains a logic bug", + |db| { + db.span_help(h2q.terminals[i].span, + "this expression can be optimized out by applying \ + boolean operations to the outer expression"); + db.span_suggestion(e.span, + "it would look like the following", + suggest(self.0, suggestion, &h2q.terminals)); + }); + // don't also lint `NONMINIMAL_BOOL` + return; + } + // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases + improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || + (stats.negations > simplified_stats.negations && + stats.ops == simplified_stats.ops) || + (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); + } + if improvement { + improvements.push(suggestion); + } + } + if !improvements.is_empty() { + span_lint_and_then(self.0, + 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)); + } + }); + } + } + } +} + +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) { + 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.node_types()[&inner.id].is_bool() { + self.bool_expr(e); + } else { + walk_expr(self, e); + } + } + _ => walk_expr(self, e), + } + } +} diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs new file mode 100644 index 00000000000..38e04723e53 --- /dev/null +++ b/clippy_lints/src/collapsible_if.rs @@ -0,0 +1,129 @@ +//! Checks for if expressions that contain only an if expression. +//! +//! For example, the lint would catch: +//! +//! ``` +//! if x { +//! if y { +//! println!("Hello world"); +//! } +//! } +//! ``` +//! +//! This lint is **warn** by default + +use rustc::lint::*; +use rustc::hir::*; +use std::borrow::Cow; +use syntax::codemap::Spanned; + +use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; + +/// **What it does:** This lint checks for nested `if`-statements which can be collapsed by +/// `&&`-combining their conditions and for `else { if .. }` expressions that can be collapsed to +/// `else if ..`. +/// +/// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. +/// +/// **Known problems:** None +/// +/// **Example:** `if x { if y { .. } }` +declare_lint! { + pub COLLAPSIBLE_IF, + Warn, + "two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` \ + can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to \ + `else if`" +} + +#[derive(Copy,Clone)] +pub struct CollapsibleIf; + +impl LintPass for CollapsibleIf { + fn get_lints(&self) -> LintArray { + lint_array!(COLLAPSIBLE_IF) + } +} + +impl LateLintPass for CollapsibleIf { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if !in_macro(cx, expr.span) { + check_if(cx, expr) + } + } +} + +fn check_if(cx: &LateContext, e: &Expr) { + if let ExprIf(ref check, ref then, ref else_) = e.node { + if let Some(ref else_) = *else_ { + if_let_chain! {[ + let ExprBlock(ref block) = else_.node, + block.stmts.is_empty(), + block.rules == BlockCheckMode::DefaultBlock, + let Some(ref else_) = block.expr, + let ExprIf(_, _, _) = else_.node + ], { + span_lint_and_then(cx, + COLLAPSIBLE_IF, + block.span, + "this `else { if .. }` block can be collapsed", |db| { + db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned()); + }); + }} + } else if let Some(&Expr { node: ExprIf(ref check_inner, ref content, None), span: sp, .. }) = + single_stmt_of_block(then) { + if e.span.expn_id != sp.expn_id { + return; + } + span_lint_and_then(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", |db| { + db.span_suggestion(e.span, + "try", + format!("if {} && {} {}", + check_to_string(cx, check), + check_to_string(cx, check_inner), + snippet_block(cx, content.span, ".."))); + }); + } + } +} + +fn requires_brackets(e: &Expr) -> bool { + match e.node { + ExprBinary(Spanned { node: n, .. }, _, _) if n == BiEq => false, + _ => true, + } +} + +fn check_to_string(cx: &LateContext, e: &Expr) -> Cow<'static, str> { + if requires_brackets(e) { + format!("({})", snippet(cx, e.span, "..")).into() + } else { + snippet(cx, e.span, "..") + } +} + +fn single_stmt_of_block(block: &Block) -> Option<&Expr> { + if block.stmts.len() == 1 && block.expr.is_none() { + if let StmtExpr(ref expr, _) = block.stmts[0].node { + single_stmt_of_expr(expr) + } else { + None + } + } else if block.stmts.is_empty() { + if let Some(ref p) = block.expr { + Some(p) + } else { + None + } + } else { + None + } +} + +fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> { + if let ExprBlock(ref block) = expr.node { + single_stmt_of_block(block) + } else { + Some(expr) + } +} diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs new file mode 100644 index 00000000000..96956d1793b --- /dev/null +++ b/clippy_lints/src/consts.rs @@ -0,0 +1,379 @@ +#![allow(cast_possible_truncation)] + +use rustc::lint::LateContext; +use rustc::hir::def::{Def, PathResolution}; +use rustc_const_eval::lookup_const_by_id; +use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; +use rustc::hir::*; +use std::cmp::Ordering::{self, Equal}; +use std::cmp::PartialOrd; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::ops::Deref; +use std::rc::Rc; +use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy}; +use syntax::ptr::P; + +#[derive(Debug, Copy, Clone)] +pub enum FloatWidth { + F32, + F64, + Any, +} + +impl From<FloatTy> for FloatWidth { + fn from(ty: FloatTy) -> FloatWidth { + match ty { + FloatTy::F32 => FloatWidth::F32, + FloatTy::F64 => FloatWidth::F64, + } + } +} + +/// A `LitKind`-like enum to fold constant `Expr`s into. +#[derive(Debug, Clone)] +pub enum Constant { + /// a String "abc" + Str(String, StrStyle), + /// a Binary String b"abc" + Binary(Rc<Vec<u8>>), + /// a single char 'a' + Char(char), + /// an integer, third argument is whether the value is negated + Int(ConstInt), + /// a float with given type + Float(String, FloatWidth), + /// true or false + Bool(bool), + /// an array of constants + Vec(Vec<Constant>), + /// also an array, but with only one constant, repeated N times + Repeat(Box<Constant>, usize), + /// a tuple of constants + Tuple(Vec<Constant>), +} + +impl Constant { + /// convert to u64 if possible + /// + /// # panics + /// + /// if the constant could not be converted to u64 losslessly + fn as_u64(&self) -> u64 { + if let Constant::Int(val) = *self { + val.to_u64().expect("negative constant can't be casted to u64") + } else { + panic!("Could not convert a {:?} to u64", self); + } + } + + /// convert this constant to a f64, if possible + #[allow(cast_precision_loss, cast_possible_wrap)] + pub fn as_float(&self) -> Option<f64> { + match *self { + Constant::Float(ref s, _) => s.parse().ok(), + Constant::Int(i) if i.is_negative() => Some(i.to_u64_unchecked() as i64 as f64), + Constant::Int(i) => Some(i.to_u64_unchecked() as f64), + _ => None, + } + } +} + +impl PartialEq for Constant { + fn eq(&self, other: &Constant) -> bool { + match (self, other) { + (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty, + (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, + (&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::<f64>(), rs.parse::<f64>()) { + (Ok(l), Ok(r)) => l.eq(&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, + (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, + _ => false, //TODO: Are there inter-type equalities? + } + } +} + +impl Hash for Constant { + fn hash<H>(&self, state: &mut H) + where H: Hasher + { + match *self { + 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::<f64>() { + unsafe { mem::transmute::<f64, u64>(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); + } + } + } +} + +impl PartialOrd for Constant { + fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { + match (self, other) { + (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => { + if l_sty == r_sty { + Some(ls.cmp(rs)) + } 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::<f64>(), rs.parse::<f64>()) { + (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), + _ => 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), + (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { + match lv.partial_cmp(rv) { + Some(Equal) => Some(ls.cmp(rs)), + x => x, + } + } + _ => None, //TODO: Are there any useful inter-type orderings? + } + } +} + +/// parse a `LitKind` to a `Constant` +#[allow(cast_possible_wrap)] +pub fn lit_to_constant(lit: &LitKind) -> Constant { + match *lit { + LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), + LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), + LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), + LitKind::Char(c) => Constant::Char(c), + LitKind::Int(value, LitIntType::Unsuffixed) => Constant::Int(ConstInt::Infer(value)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U8)) => Constant::Int(ConstInt::U8(value as u8)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)), + LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)), + 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), + } +} + +fn constant_not(o: Constant) -> Option<Constant> { + use self::Constant::*; + match o { + Bool(b) => Some(Bool(!b)), + Int(value) => (!value).ok().map(Int), + _ => None, + } +} + +fn constant_negate(o: Constant) -> Option<Constant> { + use self::Constant::*; + match o { + Int(value) => (-value).ok().map(Int), + Float(is, ty) => Some(Float(neg_float_str(is), ty)), + _ => None, + } +} + +fn neg_float_str(s: String) -> String { + if s.starts_with('-') { + s[1..].to_owned() + } else { + format!("-{}", s) + } +} + +pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { + let mut cx = ConstEvalLateContext { + lcx: Some(lcx), + needed_resolution: false, + }; + cx.expr(e).map(|cst| (cst, cx.needed_resolution)) +} + +pub fn constant_simple(e: &Expr) -> Option<Constant> { + let mut cx = ConstEvalLateContext { + lcx: None, + needed_resolution: false, + }; + cx.expr(e) +} + +struct ConstEvalLateContext<'c, 'cc: 'c> { + lcx: Option<&'c LateContext<'c, 'cc>>, + needed_resolution: bool, +} + +impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { + /// simple constant folding: Insert an expression, get a constant or none. + fn expr(&mut self, e: &Expr) -> Option<Constant> { + match e.node { + ExprPath(_, _) => self.fetch_path(e), + 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)), + ExprVec(ref vec) => self.multi(vec).map(Constant::Vec), + 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 { + UnNot => constant_not(o), + UnNeg => constant_negate(o), + UnDeref => Some(o), + } + }) + } + ExprBinary(op, ref left, ref right) => self.binop(op, left, right), + // TODO: add other expressions + _ => None, + } + } + + /// create `Some(Vec![..])` of all constants, unless there is any + /// non-constant part + fn multi<E: Deref<Target = Expr> + Sized>(&mut self, vec: &[E]) -> Option<Vec<Constant>> { + vec.iter() + .map(|elem| self.expr(elem)) + .collect::<Option<_>>() + } + + /// lookup a possibly constant expression from a ExprPath + fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { + if let Some(lcx) = self.lcx { + let mut maybe_id = None; + if let Some(&PathResolution { base_def: Def::Const(id), .. }) = lcx.tcx.def_map.borrow().get(&e.id) { + maybe_id = Some(id); + } + // separate if lets to avoid double borrowing the def_map + if let Some(id) = maybe_id { + if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None) { + let ret = self.expr(const_expr); + if ret.is_some() { + self.needed_resolution = true; + } + return ret; + } + } + } + None + } + + /// A block can only yield a constant if it only has one constant expression + fn block(&mut self, block: &Block) -> Option<Constant> { + if block.stmts.is_empty() { + block.expr.as_ref().and_then(|ref b| self.expr(b)) + } else { + None + } + } + + fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) -> Option<Constant> { + if let Some(Constant::Bool(b)) = self.expr(cond) { + if b { + self.block(then) + } else { + otherwise.as_ref().and_then(|expr| self.expr(expr)) + } + } else { + None + } + } + + fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { + let l = if let Some(l) = self.expr(left) { + l + } else { + return None; + }; + let r = self.expr(right); + match (op.node, l, r) { + (BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int), + (BiSub, Constant::Int(l), Some(Constant::Int(r))) => (l - r).ok().map(Constant::Int), + (BiMul, Constant::Int(l), Some(Constant::Int(r))) => (l * r).ok().map(Constant::Int), + (BiDiv, Constant::Int(l), Some(Constant::Int(r))) => (l / r).ok().map(Constant::Int), + (BiRem, Constant::Int(l), Some(Constant::Int(r))) => (l % r).ok().map(Constant::Int), + (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), + (BiAnd, Constant::Bool(true), Some(r)) => Some(r), + (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), + (BiOr, Constant::Bool(false), Some(r)) => Some(r), + (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), + (BiBitXor, Constant::Int(l), Some(Constant::Int(r))) => (l ^ r).ok().map(Constant::Int), + (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), + (BiBitAnd, Constant::Int(l), Some(Constant::Int(r))) => (l & r).ok().map(Constant::Int), + (BiBitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), + (BiBitOr, Constant::Int(l), Some(Constant::Int(r))) => (l | r).ok().map(Constant::Int), + (BiShl, Constant::Int(l), Some(Constant::Int(r))) => (l << r).ok().map(Constant::Int), + (BiShr, Constant::Int(l), Some(Constant::Int(r))) => (l >> r).ok().map(Constant::Int), + (BiEq, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l == r)), + (BiNe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l != r)), + (BiLt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l < r)), + (BiLe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l <= r)), + (BiGe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l >= r)), + (BiGt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l > r)), + _ => None, + } + } + + + fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> + where F: Fn(Constant, Constant) -> Option<Constant> + { + if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) { + op(lc, rc) + } else { + None + } + } +} diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs new file mode 100644 index 00000000000..4344ba461dd --- /dev/null +++ b/clippy_lints/src/copies.rs @@ -0,0 +1,271 @@ +use rustc::lint::*; +use rustc::ty; +use rustc::hir::*; +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use syntax::parse::token::InternedString; +use syntax::util::small_vector::SmallVector; +use utils::{SpanlessEq, SpanlessHash}; +use utils::{get_parent_expr, in_macro, span_note_and_lint}; + +/// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is +/// `Warn` by default. +/// +/// **Why is this bad?** This is probably a copy & paste error. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** `if a == b { .. } else if a == b { .. }` +declare_lint! { + pub IFS_SAME_COND, + Warn, + "consecutive `ifs` with the same condition" +} + +/// **What it does:** This lint checks for `if/else` with the same body as the *then* part and the +/// *else* part. This lint is `Warn` by default. +/// +/// **Why is this bad?** This is probably a copy & paste error. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** `if .. { 42 } else { 42 }` +declare_lint! { + pub IF_SAME_THEN_ELSE, + Warn, + "if with the same *then* and *else* blocks" +} + +/// **What it does:** This lint checks for `match` with identical arm bodies. +/// +/// **Why is this bad?** This is probably a copy & paste error. If arm bodies are the same on +/// purpose, you can factor them +/// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// ```rust,ignore +/// match foo { +/// Bar => bar(), +/// Quz => quz(), +/// Baz => bar(), // <= oops +/// } +/// ``` +declare_lint! { + pub MATCH_SAME_ARMS, + Warn, + "`match` with identical arm bodies" +} + +#[derive(Copy, Clone, Debug)] +pub struct CopyAndPaste; + +impl LintPass for CopyAndPaste { + fn get_lints(&self) -> LintArray { + lint_array![IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS] + } +} + +impl LateLintPass for CopyAndPaste { + fn check_expr(&mut self, cx: &LateContext, expr: &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) { + if else_expr.id == expr.id { + return; + } + } + + let (conds, blocks) = if_sequence(expr); + lint_same_then_else(cx, blocks.as_slice()); + lint_same_cond(cx, conds.as_slice()); + lint_match_arms(cx, expr); + } + } +} + +/// Implementation of `IF_SAME_THEN_ELSE`. +fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { + let hash: &Fn(&&Block) -> u64 = &|block| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_block(block); + h.finish() + }; + + let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; + + if let Some((i, j)) = search_same(blocks, hash, eq) { + span_note_and_lint(cx, + IF_SAME_THEN_ELSE, + j.span, + "this `if` has identical blocks", + i.span, + "same as this"); + } +} + +/// Implementation of `IFS_SAME_COND`. +fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { + let hash: &Fn(&&Expr) -> u64 = &|expr| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_expr(expr); + h.finish() + }; + + let eq: &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; + + if let Some((i, j)) = search_same(conds, hash, eq) { + span_note_and_lint(cx, + IFS_SAME_COND, + j.span, + "this `if` has the same condition as a previous if", + i.span, + "same as this"); + } +} + +/// Implementation if `MATCH_SAME_ARMS`. +fn lint_match_arms(cx: &LateContext, expr: &Expr) { + let hash = |arm: &Arm| -> u64 { + let mut h = SpanlessHash::new(cx); + h.hash_expr(&arm.body); + h.finish() + }; + + let eq = |lhs: &Arm, rhs: &Arm| -> bool { + // Arms with a guard are ignored, those can’t always be merged together + lhs.guard.is_none() && rhs.guard.is_none() && + SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && + // all patterns should have the same bindings + bindings(cx, &lhs.pats[0]) == bindings(cx, &rhs.pats[0]) + }; + + if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { + if let Some((i, j)) = search_same(arms, hash, eq) { + span_note_and_lint(cx, + MATCH_SAME_ARMS, + j.body.span, + "this `match` has identical arm bodies", + i.body.span, + "same as this"); + } + } +} + +/// Return the list of condition expressions and the list of blocks in a sequence of `if/else`. +/// Eg. would return `([a, b], [c, d, e])` for the expression +/// `if a { c } else if b { d } else { e }`. +fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { + let mut conds = SmallVector::zero(); + let mut blocks = SmallVector::zero(); + + while let ExprIf(ref cond, ref then_block, ref else_expr) = expr.node { + conds.push(&**cond); + blocks.push(&**then_block); + + if let Some(ref else_expr) = *else_expr { + expr = else_expr; + } else { + break; + } + } + + // final `else {..}` + if !blocks.is_empty() { + if let ExprBlock(ref block) = expr.node { + blocks.push(&**block); + } + } + + (conds, blocks) +} + +/// Return the list of bindings in a pattern. +fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> { + fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) { + match pat.node { + PatKind::Box(ref pat) | + PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), + PatKind::TupleStruct(_, Some(ref pats)) => { + for pat in pats { + bindings_impl(cx, pat, map); + } + } + PatKind::Ident(_, ref ident, ref as_pat) => { + if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { + v.insert(cx.tcx.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::Tup(ref fields) => { + for pat in fields { + bindings_impl(cx, pat, map); + } + } + PatKind::Vec(ref lhs, ref mid, ref rhs) => { + for pat in lhs { + bindings_impl(cx, pat, map); + } + if let Some(ref mid) = *mid { + bindings_impl(cx, mid, map); + } + for pat in rhs { + bindings_impl(cx, pat, map); + } + } + PatKind::TupleStruct(..) | + PatKind::Lit(..) | + PatKind::QPath(..) | + PatKind::Range(..) | + PatKind::Wild | + PatKind::Path(..) => (), + } + } + + let mut result = HashMap::new(); + bindings_impl(cx, pat, &mut result); + result +} + +fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> + where Hash: Fn(&T) -> u64, + Eq: Fn(&T, &T) -> bool +{ + // common cases + if exprs.len() < 2 { + return None; + } else if exprs.len() == 2 { + return if eq(&exprs[0], &exprs[1]) { + Some((&exprs[0], &exprs[1])) + } else { + None + }; + } + + let mut map: HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); + + for expr in exprs { + match map.entry(hash(expr)) { + Entry::Occupied(o) => { + for o in o.get() { + if eq(o, expr) { + return Some((o, expr)); + } + } + } + Entry::Vacant(v) => { + v.insert(vec![expr]); + } + } + } + + None +} diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs new file mode 100644 index 00000000000..8ae0d2c97c5 --- /dev/null +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -0,0 +1,187 @@ +//! calculate cyclomatic complexity and warn about overly complex functions + +use rustc::cfg::CFG; +use rustc::lint::*; +use rustc::ty; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr}; +use syntax::ast::Attribute; +use syntax::attr; +use syntax::codemap::Span; + +use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type}; + +/// **What it does:** This lint checks for methods with high cyclomatic complexity +/// +/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better. +/// +/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity +/// +/// **Example:** No. You'll see it when you get the warning. +declare_lint! { + pub CYCLOMATIC_COMPLEXITY, Warn, + "finds functions that should be split up into multiple functions" +} + +pub struct CyclomaticComplexity { + limit: LimitStack, +} + +impl CyclomaticComplexity { + pub fn new(limit: u64) -> Self { + CyclomaticComplexity { limit: LimitStack::new(limit) } + } +} + +impl LintPass for CyclomaticComplexity { + fn get_lints(&self) -> LintArray { + lint_array!(CYCLOMATIC_COMPLEXITY) + } +} + +impl CyclomaticComplexity { + fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) { + if in_macro(cx, span) { + return; + } + + let cfg = CFG::new(cx.tcx, block); + let n = cfg.graph.len_nodes() as u64; + let e = cfg.graph.len_edges() as u64; + if e + 2 < n { + // the function has unreachable code, other lints should catch this + return; + } + let cc = e + 2 - n; + let mut helper = CCHelper { + match_arms: 0, + divergence: 0, + short_circuits: 0, + returns: 0, + tcx: &cx.tcx, + }; + helper.visit_block(block); + let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; + let ret_ty = cx.tcx.node_id_to_type(block.id); + let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) { + returns + } else { + returns / 2 + }; + + if cc + divergence < match_arms + short_circuits { + report_cc_bug(cx, cc, match_arms, divergence, short_circuits, ret_adjust, span); + } else { + let mut rust_cc = cc + divergence - match_arms - short_circuits; + // prevent degenerate cases where unreachable code contains `return` statements + if rust_cc >= ret_adjust { + rust_cc -= ret_adjust; + } + if rust_cc > self.limit.limit() { + span_help_and_lint(cx, + CYCLOMATIC_COMPLEXITY, + span, + &format!("the function has a cyclomatic complexity of {}", rust_cc), + "you could split it up into multiple smaller functions"); + } + } + } +} + +impl LateLintPass for CyclomaticComplexity { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemFn(_, _, _, _, _, ref block) = item.node { + if !attr::contains_name(&item.attrs, "test") { + self.check(cx, block, item.span); + } + } + } + + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + if let ImplItemKind::Method(_, ref block) = item.node { + self.check(cx, block, item.span); + } + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + if let MethodTraitItem(_, Some(ref block)) = item.node { + self.check(cx, block, item.span); + } + } + + fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + } + fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { + self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + } +} + +struct CCHelper<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + match_arms: u64, + divergence: u64, + returns: u64, + short_circuits: u64, // && and || + tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { + fn visit_expr(&mut self, e: &'a Expr) { + match e.node { + ExprMatch(_, ref arms, _) => { + walk_expr(self, e); + let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum(); + if arms_n > 1 { + self.match_arms += arms_n - 2; + } + } + ExprCall(ref callee, _) => { + walk_expr(self, e); + let ty = self.tcx.node_id_to_type(callee.id); + match ty.sty { + ty::TyFnDef(_, _, ty) | + ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => { + self.divergence += 1; + } + _ => (), + } + } + ExprClosure(..) => (), + ExprBinary(op, _, _) => { + walk_expr(self, e); + match op.node { + BiAnd | BiOr => self.short_circuits += 1, + _ => (), + } + } + ExprRet(_) => self.returns += 1, + _ => walk_expr(self, e), + } + } +} + +#[cfg(feature="debugging")] +fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { + span_bug!(span, + "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ + div = {}, shorts = {}, returns = {}. Please file a bug report.", + cc, + narms, + div, + shorts, + returns); +} +#[cfg(not(feature="debugging"))] +fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { + if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { + cx.sess().span_note_without_error(span, + &format!("Clippy encountered a bug calculating cyclomatic complexity \ + (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ + = {}, arms = {}, div = {}, shorts = {}, returns = {}. Please file a bug report.", + cc, + narms, + div, + shorts, + returns)); + } +} diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs new file mode 100644 index 00000000000..abdb6297b9e --- /dev/null +++ b/clippy_lints/src/deprecated_lints.rs @@ -0,0 +1,44 @@ +macro_rules! declare_deprecated_lint { + (pub $name: ident, $_reason: expr) => { + declare_lint!(pub $name, Allow, "deprecated lint") + } +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good +/// stable alternatives. `Vec::as_slice` has now been stabilized. +declare_deprecated_lint! { + pub UNSTABLE_AS_SLICE, + "`Vec::as_slice` has been stabilized in 1.7" +} + + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good +/// stable alternatives. `Vec::as_mut_slice` has now been stabilized. +declare_deprecated_lint! { + pub UNSTABLE_AS_MUT_SLICE, + "`Vec::as_mut_slice` has been stabilized in 1.7" +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `.to_string()` method calls on values +/// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be +/// specialized to be as efficient as `to_owned`. +declare_deprecated_lint! { + pub STR_TO_STRING, + "using `str::to_string` is common even today and specialization will likely happen soon" +} + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This used to check for `.to_string()` method calls on values +/// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be +/// specialized to be as efficient as `clone`. +declare_deprecated_lint! { + pub STRING_TO_STRING, + "using `string::to_string` is common even today and specialization will likely happen soon" +} diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs new file mode 100644 index 00000000000..f08522953aa --- /dev/null +++ b/clippy_lints/src/derive.rs @@ -0,0 +1,180 @@ +use rustc::lint::*; +use rustc::ty::subst::Subst; +use rustc::ty::TypeVariants; +use rustc::ty; +use rustc::hir::*; +use syntax::ast::{Attribute, MetaItemKind}; +use syntax::codemap::Span; +use utils::paths; +use utils::{match_path, span_lint_and_then}; + +/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` +/// explicitly. +/// +/// **Why is this bad?** The implementation of these traits must agree (for example for use with +/// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation with +/// an explicitly defined `PartialEq`. In particular, the following must hold for any type: +/// +/// ```rust +/// k1 == k2 ⇒ hash(k1) == hash(k2) +/// ``` +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// #[derive(Hash)] +/// struct Foo; +/// +/// impl PartialEq for Foo { +/// .. +/// } +/// ``` +declare_lint! { + pub DERIVE_HASH_XOR_EQ, + Warn, + "deriving `Hash` but implementing `PartialEq` explicitly" +} + +/// **What it does:** This lint warns about explicit `Clone` implementation for `Copy` types. +/// +/// **Why is this bad?** To avoid surprising behaviour, these traits should agree and the behaviour +/// of `Copy` cannot be overridden. In almost all situations a `Copy` type should have a `Clone` +/// implementation that does nothing more than copy the object, which is what +/// `#[derive(Copy, Clone)]` gets you. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// #[derive(Copy)] +/// struct Foo; +/// +/// impl Clone for Foo { +/// .. +/// } +/// ``` +declare_lint! { + pub EXPL_IMPL_CLONE_ON_COPY, + Warn, + "implementing `Clone` explicitly on `Copy` types" +} + +pub struct Derive; + +impl LintPass for Derive { + fn get_lints(&self) -> LintArray { + lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ) + } +} + +impl LateLintPass for Derive { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if_let_chain! {[ + let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node + ], { + let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; + let is_automatically_derived = item.attrs.iter().any(is_automatically_derived); + + check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); + + if !is_automatically_derived { + check_copy_clone(cx, item, trait_ref, ty); + } + }} + } +} + +/// 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) { + if_let_chain! {[ + match_path(&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); + + // Look for the PartialEq implementations for `ty` + peq_trait_def.for_each_relevant_impl(cx.tcx, ty, |impl_id| { + let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); + + if peq_is_automatically_derived == hash_is_automatically_derived { + return; + } + + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); + + // Only care about `impl PartialEq<Foo> for Foo` + if trait_ref.input_types()[0] == ty { + let mess = if peq_is_automatically_derived { + "you are implementing `Hash` explicitly but have derived `PartialEq`" + } else { + "you are deriving `Hash` but have implemented `PartialEq` explicitly" + }; + + span_lint_and_then( + cx, DERIVE_HASH_XOR_EQ, span, + mess, + |db| { + if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { + db.span_note( + cx.tcx.map.span(node_id), + "`PartialEq` implemented here" + ); + } + }); + } + }); + }} +} + +/// 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) { + let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); + let subst_ty = ty.subst(cx.tcx, parameter_environment.free_substs); + + if subst_ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, item.span) { + return; // ty is not Copy + } + + // Some types are not Clone by default but could be cloned `by hand` if necessary + match ty.sty { + TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => { + for variant in &def.variants { + for field in &variant.fields { + match field.ty(cx.tcx, substs).sty { + TypeVariants::TyArray(_, size) if size > 32 => { + return; + } + TypeVariants::TyFnPtr(..) => { + return; + } + TypeVariants::TyTuple(ref tys) if tys.len() > 12 => { + return; + } + _ => (), + } + } + } + } + _ => (), + } + + span_lint_and_then(cx, + EXPL_IMPL_CLONE_ON_COPY, + item.span, + "you are implementing `Clone` explicitly on a `Copy` type", + |db| { + db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); + }); + } +} + +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have. +fn is_automatically_derived(attr: &Attribute) -> bool { + if let MetaItemKind::Word(ref word) = attr.node.value.node { + word == &"automatically_derived" + } else { + false + } +} diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs new file mode 100644 index 00000000000..cf32c1731fa --- /dev/null +++ b/clippy_lints/src/doc.rs @@ -0,0 +1,235 @@ +use rustc::lint::*; +use syntax::ast; +use syntax::codemap::{Span, BytePos}; +use utils::span_lint; + +/// **What it does:** This lint checks for the presence of `_`, `::` or camel-case words outside +/// ticks in documentation. +/// +/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and camel-case probably +/// indicates some code which should be included between ticks. `_` can also be used for empasis in +/// markdown, this lint tries to consider that. +/// +/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks for is limited. +/// +/// **Examples:** +/// ```rust +/// /// Do something with the foo_bar parameter. See also that::other::module::foo. +/// // ^ `foo_bar` and `that::other::module::foo` should be ticked. +/// fn doit(foo_bar) { .. } +/// ``` +declare_lint! { + pub DOC_MARKDOWN, Warn, + "checks for the presence of `_`, `::` or camel-case outside ticks in documentation" +} + +#[derive(Clone)] +pub struct Doc { + valid_idents: Vec<String>, +} + +impl Doc { + pub fn new(valid_idents: Vec<String>) -> Self { + Doc { valid_idents: valid_idents } + } +} + +impl LintPass for Doc { + fn get_lints(&self) -> LintArray { + lint_array![DOC_MARKDOWN] + } +} + +impl EarlyLintPass for Doc { + fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { + check_attrs(cx, &self.valid_idents, &krate.attrs); + } + + fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + check_attrs(cx, &self.valid_idents, &item.attrs); + } +} + +pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) { + let mut in_multiline = false; + for attr in attrs { + if attr.node.is_sugared_doc { + if let ast::MetaItemKind::NameValue(_, ref doc) = attr.node.value.node { + if let ast::LitKind::Str(ref doc, _) = doc.node { + // doc comments start with `///` or `//!` + let real_doc = &doc[3..]; + let mut span = attr.span; + span.lo = span.lo + BytePos(3); + + // check for multiline code blocks + if real_doc.trim_left().starts_with("```") { + in_multiline = !in_multiline; + } + if !in_multiline { + check_doc(cx, valid_idents, real_doc, span); + } + } + } + } + } +} + +macro_rules! jump_to { + // Get the next character’s first byte UTF-8 friendlyly. + (@next_char, $chars: expr, $len: expr) => {{ + if let Some(&(pos, _)) = $chars.peek() { + pos + } else { + $len + } + }}; + + // Jump to the next `$c`. If no such character is found, give up. + ($chars: expr, $c: expr, $len: expr) => {{ + if $chars.find(|&(_, c)| c == $c).is_some() { + jump_to!(@next_char, $chars, $len) + } + else { + return; + } + }}; +} + +#[allow(while_let_loop)] // #362 +pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Span) { + // In markdown, `_` can be used to emphasize something, or, is a raw `_` depending on context. + // There really is no markdown specification that would disambiguate this properly. This is + // what GitHub and Rustdoc do: + // + // foo_bar test_quz → foo_bar test_quz + // foo_bar_baz → foo_bar_baz (note that the “official” spec says this should be emphasized) + // _foo bar_ test_quz_ → <em>foo bar</em> test_quz_ + // \_foo bar\_ → _foo bar_ + // (_baz_) → (<em>baz</em>) + // foo _ bar _ baz → foo _ bar _ baz + + /// Character that can appear in a word + fn is_word_char(c: char) -> bool { + match c { + t if t.is_alphanumeric() => true, + ':' | '_' => true, + _ => false, + } + } + + #[allow(cast_possible_truncation)] + fn word_span(mut span: Span, begin: usize, end: usize) -> Span { + debug_assert_eq!(end as u32 as usize, end); + debug_assert_eq!(begin as u32 as usize, begin); + span.hi = span.lo + BytePos(end as u32); + span.lo = span.lo + BytePos(begin as u32); + span + } + + let mut new_line = true; + let len = doc.len(); + let mut chars = doc.char_indices().peekable(); + let mut current_word_begin = 0; + loop { + match chars.next() { + Some((_, c)) => { + match c { + '#' if new_line => { // don’t warn on titles + current_word_begin = jump_to!(chars, '\n', len); + } + '`' => { + current_word_begin = jump_to!(chars, '`', len); + } + '[' => { + let end = jump_to!(chars, ']', len); + let link_text = &doc[current_word_begin + 1..end]; + let word_span = word_span(span, current_word_begin + 1, end + 1); + + match chars.peek() { + Some(&(_, c)) => { + // Trying to parse a link. Let’s ignore the link. + + // FIXME: how does markdown handles such link? + // https://en.wikipedia.org/w/index.php?title=) + match c { + '(' => { // inline link + current_word_begin = jump_to!(chars, ')', len); + check_doc(cx, valid_idents, link_text, word_span); + } + '[' => { // reference link + current_word_begin = jump_to!(chars, ']', len); + check_doc(cx, valid_idents, link_text, word_span); + } + ':' => { // reference link + current_word_begin = jump_to!(chars, '\n', len); + } + _ => { // automatic reference link + current_word_begin = jump_to!(@next_char, chars, len); + check_doc(cx, valid_idents, link_text, word_span); + } + } + } + None => return, + } + } + // anything that’s neither alphanumeric nor '_' is not part of an ident anyway + c if !c.is_alphanumeric() && c != '_' => { + current_word_begin = jump_to!(@next_char, chars, len); + } + _ => { + let end = match chars.find(|&(_, c)| !is_word_char(c)) { + Some((end, _)) => end, + None => len, + }; + let word_span = word_span(span, current_word_begin, end); + check_word(cx, valid_idents, &doc[current_word_begin..end], word_span); + current_word_begin = jump_to!(@next_char, chars, len); + } + } + + new_line = c == '\n' || (new_line && c.is_whitespace()); + } + None => break, + } + } +} + +fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span) { + /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is + /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). + fn is_camel_case(s: &str) -> bool { + if s.starts_with(|c: char| c.is_digit(10)) { + return false; + } + + let s = if s.ends_with('s') { + &s[..s.len() - 1] + } else { + s + }; + + 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 + } + + fn has_underscore(s: &str) -> bool { + s != "_" && !s.contains("\\_") && s.contains('_') + } + + // Trim punctuation as in `some comment (see foo::bar).` + // ^^ + // Or even as in `_foo bar_` which is emphasized. + let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + + if valid_idents.iter().any(|i| i == word) { + return; + } + + if has_underscore(word) || word.contains("::") || is_camel_case(word) { + span_lint(cx, + DOC_MARKDOWN, + span, + &format!("you should put `{}` between ticks in the documentation", word)); + } +} diff --git a/clippy_lints/src/drop_ref.rs b/clippy_lints/src/drop_ref.rs new file mode 100644 index 00000000000..69156f15f31 --- /dev/null +++ b/clippy_lints/src/drop_ref.rs @@ -0,0 +1,61 @@ +use rustc::lint::*; +use rustc::ty; +use rustc::hir::*; +use syntax::codemap::Span; +use utils::{match_def_path, paths, span_note_and_lint}; + +/// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value. +/// +/// **Why is this bad?** Calling `drop` on a reference will only drop the reference itself, which is a no-op. It will not call the `drop` method (from the `Drop` trait implementation) on the underlying referenced value, which is likely what was intended. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// let mut lock_guard = mutex.lock(); +/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex still locked +/// operation_that_requires_mutex_to_be_unlocked(); +/// ``` +declare_lint! { + pub DROP_REF, Warn, + "call to `std::mem::drop` with a reference instead of an owned value, \ + which will not call the `Drop::drop` method on the underlying value" +} + +#[allow(missing_copy_implementations)] +pub struct DropRefPass; + +impl LintPass for DropRefPass { + fn get_lints(&self) -> LintArray { + lint_array!(DROP_REF) + } +} + +impl LateLintPass for DropRefPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprCall(ref path, ref args) = expr.node { + if let ExprPath(None, _) = path.node { + let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); + if match_def_path(cx, def_id, &paths::DROP) { + if args.len() != 1 { + return; + } + check_drop_arg(cx, expr.span, &*args[0]); + } + } + } + } +} + +fn check_drop_arg(cx: &LateContext, call_span: Span, arg: &Expr) { + let arg_ty = cx.tcx.expr_ty(arg); + if let ty::TyRef(..) = arg_ty.sty { + span_note_and_lint(cx, + DROP_REF, + call_span, + "call to `std::mem::drop` with a reference argument. \ + Dropping a reference does nothing", + arg.span, + &format!("argument has type {}", arg_ty.sty)); + } +} diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs new file mode 100644 index 00000000000..d63d8c67c5d --- /dev/null +++ b/clippy_lints/src/entry.rs @@ -0,0 +1,148 @@ +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block}; +use rustc::lint::*; +use syntax::codemap::Span; +use utils::SpanlessEq; +use utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; + +/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or +/// `BTreeMap`. +/// +/// **Why is this bad?** Using `entry` is more efficient. +/// +/// **Known problems:** Some false negatives, eg.: +/// ``` +/// let k = &key; +/// if !m.contains_key(k) { m.insert(k.clone(), v); } +/// ``` +/// +/// **Example:** +/// ```rust +/// if !m.contains_key(&k) { m.insert(k, v) } +/// ``` +/// can be rewritten as: +/// ```rust +/// m.entry(k).or_insert(v); +/// ``` +declare_lint! { + pub MAP_ENTRY, + Warn, + "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`" +} + +#[derive(Copy,Clone)] +pub struct HashMapLint; + +impl LintPass for HashMapLint { + fn get_lints(&self) -> LintArray { + lint_array!(MAP_ENTRY) + } +} + +impl LateLintPass for HashMapLint { + fn check_expr(&mut self, cx: &LateContext, expr: &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) { + // in case of `if !m.contains_key(&k) { m.insert(k, v); }` + // we can give a better error message + let sole_expr = else_block.is_none() && + ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1); + + let mut visitor = InsertVisitor { + cx: cx, + span: expr.span, + ty: ty, + map: map, + key: key, + sole_expr: sole_expr, + }; + + walk_block(&mut visitor, then_block); + } + } else if let Some(ref else_block) = *else_block { + if let Some((ty, map, key)) = check_cond(cx, check) { + let mut visitor = InsertVisitor { + cx: cx, + span: expr.span, + ty: ty, + map: map, + key: key, + sole_expr: false, + }; + + walk_expr(&mut visitor, else_block); + } + } + } + } +} + +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, + name.node.as_str() == "contains_key", + let ExprAddrOf(_, ref key) = params[1].node + ], { + let map = ¶ms[0]; + let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); + + return if match_type(cx, obj_ty, &paths::BTREEMAP) { + Some(("BTreeMap", map, key)) + } + else if match_type(cx, obj_ty, &paths::HASHMAP) { + Some(("HashMap", map, key)) + } + else { + None + }; + }} + + None +} + +struct InsertVisitor<'a, 'tcx: 'a, 'b> { + cx: &'a LateContext<'a, 'tcx>, + span: Span, + ty: &'static str, + map: &'b Expr, + key: &'b Expr, + sole_expr: bool, +} + +impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> { + fn visit_expr(&mut self, expr: &'v Expr) { + if_let_chain! {[ + let ExprMethodCall(ref name, _, ref params) = expr.node, + params.len() == 3, + name.node.as_str() == "insert", + get_item_name(self.cx, self.map) == get_item_name(self.cx, &*params[0]), + SpanlessEq::new(self.cx).eq_expr(self.key, ¶ms[1]) + ], { + + span_lint_and_then(self.cx, MAP_ENTRY, self.span, + &format!("usage of `contains_key` followed by `insert` on `{}`", self.ty), |db| { + if self.sole_expr { + let help = format!("{}.entry({}).or_insert({})", + snippet(self.cx, self.map.span, "map"), + snippet(self.cx, params[1].span, ".."), + snippet(self.cx, params[2].span, "..")); + + db.span_suggestion(self.span, "Consider using", help); + } + else { + let help = format!("Consider using `{}.entry({})`", + snippet(self.cx, self.map.span, "map"), + snippet(self.cx, params[1].span, "..")); + + db.span_note(self.span, &help); + } + }); + }} + + if !self.sole_expr { + walk_expr(self, expr); + } + } +} diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs new file mode 100644 index 00000000000..39c31864f39 --- /dev/null +++ b/clippy_lints/src/enum_clike.rs @@ -0,0 +1,52 @@ +//! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` + +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc_const_math::*; +use rustc::hir::*; +use utils::span_lint; + +/// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. +/// +/// **Why is this bad?** This will truncate the variant value on 32bit architectures, but works fine on 64 bit. +/// +/// **Known problems:** None +/// +/// **Example:** `#[repr(usize)] enum NonPortable { X = 0x1_0000_0000, Y = 0 }` +declare_lint! { + pub ENUM_CLIKE_UNPORTABLE_VARIANT, Warn, + "finds C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`" +} + +pub struct EnumClikeUnportableVariant; + +impl LintPass for EnumClikeUnportableVariant { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT) + } +} + +impl LateLintPass for EnumClikeUnportableVariant { + #[allow(cast_possible_truncation, cast_sign_loss)] + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemEnum(ref def, _) = item.node { + for var in &def.variants { + let variant = &var.node; + if let Some(ref disr) = variant.disr_expr { + use rustc_const_eval::*; + let bad = match eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None) { + Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i, + Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i, + _ => false, + }; + if bad { + span_lint(cx, + ENUM_CLIKE_UNPORTABLE_VARIANT, + var.span, + "Clike enum variant discriminant is not portable to 32-bit targets"); + } + } + } + } + } +} diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs new file mode 100644 index 00000000000..37a89069d19 --- /dev/null +++ b/clippy_lints/src/enum_glob_use.rs @@ -0,0 +1,65 @@ +//! 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::middle::cstore::DefLike; +use syntax::ast::NodeId; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** Warns when `use`ing all variants of an enum +/// +/// **Why is this bad?** It is usually better style to use the prefixed name of an enum variant, rather than importing variants +/// +/// **Known problems:** Old-style enums that prefix the variants are still around +/// +/// **Example:** `use std::cmp::Ordering::*;` +declare_lint! { pub ENUM_GLOB_USE, Allow, + "finds use items that import all variants of an enum" } + +pub struct EnumGlobUse; + +impl LintPass for EnumGlobUse { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_GLOB_USE) + } +} + +impl LateLintPass for EnumGlobUse { + fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { + // only check top level `use` statements + for item in &m.item_ids { + self.lint_item(cx, cx.krate.item(item.id)); + } + } +} + +impl EnumGlobUse { + fn lint_item(&self, cx: &LateContext, item: &Item) { + 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.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.def_id()); + if let Some(child) = child.first() { + if let DefLike::DlDef(Def::Variant(..)) = child.def { + 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 new file mode 100644 index 00000000000..67a8495e155 --- /dev/null +++ b/clippy_lints/src/enum_variants.rs @@ -0,0 +1,104 @@ +//! lint on enum variants that are prefixed or suffixed by the same characters + +use rustc::lint::*; +use syntax::ast::*; +use syntax::parse::token::InternedString; +use utils::span_help_and_lint; +use utils::{camel_case_from, camel_case_until}; + +/// **What it does:** Warns on enum variants that are prefixed or suffixed by the same characters +/// +/// **Why is this bad?** Enum variant names should specify their variant, not the enum, too. +/// +/// **Known problems:** None +/// +/// **Example:** enum Cake { BlackForestCake, HummingbirdCake } +declare_lint! { + pub ENUM_VARIANT_NAMES, Warn, + "finds enums where all variants share a prefix/postfix" +} + +pub struct EnumVariantNames; + +impl LintPass for EnumVariantNames { + fn get_lints(&self) -> LintArray { + lint_array!(ENUM_VARIANT_NAMES) + } +} + +fn var2str(var: &Variant) -> InternedString { + var.node.name.name.as_str() +} + +// FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 +// fn partial_match(pre: &str, name: &str) -> usize { +// // skip(1) to ensure that the prefix never takes the whole variant name +// pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() +// } +// +// fn partial_rmatch(post: &str, name: &str) -> usize { +// // skip(1) to ensure that the postfix never takes the whole variant name +// post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() +// } + +fn partial_match(pre: &str, name: &str) -> usize { + let mut name_iter = name.chars(); + let _ = name_iter.next_back(); // make sure the name is never fully matched + pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() +} + +fn partial_rmatch(post: &str, name: &str) -> usize { + let mut name_iter = name.chars(); + let _ = name_iter.next(); // make sure the name is never fully matched + post.chars().rev().zip(name_iter.rev()).take_while(|&(l, r)| l == r).count() +} + +impl EarlyLintPass for EnumVariantNames { + // FIXME: #600 + #[allow(while_let_on_iterator)] + fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + if let ItemKind::Enum(ref def, _) = item.node { + if def.variants.len() < 2 { + return; + } + let first = var2str(&def.variants[0]); + let mut pre = &first[..camel_case_until(&*first)]; + let mut post = &first[camel_case_from(&*first)..]; + for var in &def.variants { + let name = var2str(var); + + let pre_match = partial_match(pre, &name); + pre = &pre[..pre_match]; + let pre_camel = camel_case_until(pre); + pre = &pre[..pre_camel]; + while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { + if next.is_lowercase() { + let last = pre.len() - last.len_utf8(); + let last_camel = camel_case_until(&pre[..last]); + pre = &pre[..last_camel]; + } else { + break; + } + } + + let post_match = partial_rmatch(post, &name); + let post_end = post.len() - post_match; + post = &post[post_end..]; + let post_camel = camel_case_from(post); + post = &post[post_camel..]; + } + let (what, value) = match (pre.is_empty(), post.is_empty()) { + (true, true) => return, + (false, _) => ("pre", pre), + (true, false) => ("post", post), + }; + span_help_and_lint(cx, + ENUM_VARIANT_NAMES, + item.span, + &format!("All variants have the same {}fix: `{}`", what, value), + &format!("remove the {}fixes and use full paths to \ + the variants instead of glob imports", + what)); + } + } +} diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs new file mode 100644 index 00000000000..fb06639853c --- /dev/null +++ b/clippy_lints/src/eq_op.rs @@ -0,0 +1,60 @@ +use rustc::hir::*; +use rustc::lint::*; +use utils::{SpanlessEq, span_lint}; + +/// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, +/// difference and division binary operators (`==`, `>`, etc., `&&`, `||`, `&`, `|`, `^`, `-` and +/// `/`). +/// +/// **Why is this bad?** This is usually just a typo or a copy and paste error. +/// +/// **Known problems:** False negatives: We had some false positives regarding calls (notably [racer](https://github.com/phildawes/racer) had one instance of `x.pop() && x.pop()`), so we removed matching any function or method calls. We may introduce a whitelist of known pure functions in the future. +/// +/// **Example:** `x + 1 == x + 1` +declare_lint! { + pub EQ_OP, + Warn, + "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)" +} + +#[derive(Copy,Clone)] +pub struct EqOp; + +impl LintPass for EqOp { + fn get_lints(&self) -> LintArray { + lint_array!(EQ_OP) + } +} + +impl LateLintPass for EqOp { + fn check_expr(&mut self, cx: &LateContext, e: &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, + EQ_OP, + e.span, + &format!("equal expressions as operands to `{}`", op.node.as_str())); + } + } + } +} + + +fn is_valid_operator(op: &BinOp) -> bool { + match op.node { + 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 new file mode 100644 index 00000000000..b5172269a1e --- /dev/null +++ b/clippy_lints/src/escape.rs @@ -0,0 +1,172 @@ +use rustc::hir::*; +use rustc::hir::intravisit as visit; +use rustc::hir::map::Node::{NodeExpr, NodeStmt}; +use rustc::lint::*; +use rustc::middle::expr_use_visitor::*; +use rustc::middle::mem_categorization::{cmt, Categorization}; +use rustc::ty::adjustment::AutoAdjustment; +use rustc::ty; +use rustc::util::nodemap::NodeSet; +use syntax::ast::NodeId; +use syntax::codemap::Span; +use utils::span_lint; + +pub struct EscapePass; + +/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. +/// +/// **Why is this bad?** This is an unnecessary allocation, and bad for performance. It is only necessary to allocate if you wish to move the box into something. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ```rust +/// fn main() { +/// let x = Box::new(1); +/// foo(*x); +/// println!("{}", *x); +/// } +/// ``` +declare_lint! { + pub BOXED_LOCAL, Warn, "using `Box<T>` where unnecessary" +} + +fn is_non_trait_box(ty: ty::Ty) -> bool { + match ty.sty { + ty::TyBox(ref inner) => !inner.is_trait(), + _ => false, + } +} + +struct EscapeDelegate<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + set: NodeSet, +} + +impl LintPass for EscapePass { + fn get_lints(&self) -> LintArray { + lint_array!(BOXED_LOCAL) + } +} + +impl LateLintPass for EscapePass { + fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { + let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); + + let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env); + let mut v = EscapeDelegate { + tcx: cx.tcx, + set: NodeSet(), + }; + + { + let mut vis = ExprUseVisitor::new(&mut v, &infcx); + vis.walk_fn(decl, body); + } + + for node in v.set { + span_lint(cx, + BOXED_LOCAL, + cx.tcx.map.span(node), + "local variable doesn't need to be boxed here"); + } + } +} + +impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { + fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + if let Move(DirectRefMove) = mode { + // moved out or in. clearly can't be localized + self.set.remove(&lid); + } + } + } + } + fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} + fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { + let map = &self.tcx.map; + if map.is_argument(consume_pat.id) { + // Skip closure arguments + if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) { + return; + } + if is_non_trait_box(cmt.ty) { + self.set.insert(consume_pat.id); + } + return; + } + if let Categorization::Rvalue(..) = cmt.cat { + if let Some(NodeStmt(st)) = map.find(map.get_parent_node(cmt.id)) { + if let StmtDecl(ref decl, _) = st.node { + if let DeclLocal(ref loc) = decl.node { + if let Some(ref ex) = loc.init { + if let ExprBox(..) = ex.node { + if is_non_trait_box(cmt.ty) { + // let x = box (...) + self.set.insert(consume_pat.id); + } + // TODO Box::new + // TODO vec![] + // TODO "foo".to_owned() and friends + } + } + } + } + } + } + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + // let y = x where x is known + // remove x, insert y + self.set.insert(consume_pat.id); + self.set.remove(&lid); + } + } + + } + fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, + loan_cause: LoanCause) { + + if let Categorization::Local(lid) = cmt.cat { + if self.set.contains(&lid) { + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx + .tables + .borrow() + .adjustments + .get(&borrow_id) { + if LoanCause::AutoRef == loan_cause { + // x.foo() + if adj.autoderefs == 0 { + self.set.remove(&lid); // Used without autodereffing (i.e. x.clone()) + } + } else { + span_bug!(cmt.span, "Unknown adjusted AutoRef"); + } + } else if LoanCause::AddrOf == loan_cause { + // &x + if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx + .tables + .borrow() + .adjustments + .get(&self.tcx + .map + .get_parent_node(borrow_id)) { + if adj.autoderefs <= 1 { + // foo(&x) where no extra autoreffing is happening + self.set.remove(&lid); + } + } + + } else if LoanCause::MatchDiscriminant == loan_cause { + self.set.remove(&lid); // `match x` can move + } + // do nothing for matches, etc. These can't escape + } + } + } + fn decl_without_init(&mut self, _: NodeId, _: Span) {} + fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {} +} diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs new file mode 100644 index 00000000000..f73b6cfed2d --- /dev/null +++ b/clippy_lints/src/eta_reduction.rs @@ -0,0 +1,99 @@ +use rustc::lint::*; +use rustc::ty; +use rustc::hir::*; +use utils::{snippet_opt, span_lint_and_then, is_adjusted}; + +#[allow(missing_copy_implementations)] +pub struct EtaPass; + + +/// **What it does:** This lint checks for closures which just call another function where the function can be called directly. `unsafe` functions or calls where types get adjusted are ignored. +/// +/// **Why is this bad?** Needlessly creating a closure just costs heap space and adds code for no benefit. +/// +/// **Known problems:** None +/// +/// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact argument type of `x`. +declare_lint! { + pub REDUNDANT_CLOSURE, Warn, + "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)" +} + +impl LintPass for EtaPass { + fn get_lints(&self) -> LintArray { + lint_array!(REDUNDANT_CLOSURE) + } +} + +impl LateLintPass for EtaPass { + fn check_expr(&mut self, cx: &LateContext, expr: &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 blk, _) = expr.node { + if !blk.stmts.is_empty() { + // || {foo(); bar()}; can't be reduced here + return; + } + + if let Some(ref ex) = blk.expr { + if let ExprCall(ref caller, ref args) = ex.node { + if args.len() != decl.inputs.len() { + // Not the same number of arguments, there + // is no way the closure is the same as the function + return; + } + if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) { + // Are the expression or the arguments type-adjusted? Then we need the closure + return; + } + let fn_ty = cx.tcx.expr_ty(caller); + match fn_ty.sty { + // 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 == ty::FnOutput::FnDiverging { + return; + } + } + _ => (), + } + for (ref a1, ref a2) in decl.inputs.iter().zip(args) { + if let PatKind::Ident(_, ident, _) = a1.pat.node { + // XXXManishearth Should I be checking the binding mode here? + if let ExprPath(None, ref p) = a2.node { + if p.segments.len() != 1 { + // If it's a proper path, it can't be a local variable + return; + } + if p.segments[0].name != ident.node { + // The two idents should be the same + return; + } + } else { + return; + } + } else { + return; + } + } + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| { + if let Some(snippet) = snippet_opt(cx, caller.span) { + db.span_suggestion(expr.span, "remove closure as shown:", snippet); + } + }); + } + } + } +} diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs new file mode 100644 index 00000000000..0726fcaeab7 --- /dev/null +++ b/clippy_lints/src/format.rs @@ -0,0 +1,119 @@ +use rustc::hir::*; +use rustc::hir::map::Node::NodeItem; +use rustc::lint::*; +use rustc::ty::TypeVariants; +use syntax::ast::LitKind; +use utils::paths; +use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty}; + +/// **What it does:** This lints about use of `format!("string literal with no argument")` and +/// `format!("{}", foo)` where `foo` is a string. +/// +/// **Why is this bad?** There is no point of doing that. `format!("too")` can be replaced by `"foo".to_owned()` if you really need a `String`. The even worse `&format!("foo")` is often +/// encountered in the wild. `format!("{}", foo)` can be replaced by `foo.clone()` if `foo: String` +/// or `foo.to_owned()` is `foo: &str`. +/// +/// **Known problems:** None. +/// +/// **Examples:** `format!("foo")` and `format!("{}", foo)` +declare_lint! { + pub USELESS_FORMAT, + Warn, + "useless use of `format!`" +} + +#[derive(Copy, Clone, Debug)] +pub struct FormatMacLint; + +impl LintPass for FormatMacLint { + fn get_lints(&self) -> LintArray { + lint_array![USELESS_FORMAT] + } +} + +impl LateLintPass for FormatMacLint { + fn check_expr(&mut self, cx: &LateContext, expr: &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(_, ref path) = fun.node, + args.len() == 2, + match_path(path, &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 + check_arg_is_display(cx, &args[1]) + ], { + 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 { + if tup.is_empty() { + span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); + } + } + } + _ => (), + } + } + } +} + +/// Checks if the expressions matches +/// ``` +/// { static __STATIC_FMTSTR: &[""] = _; __STATIC_FMTSTR } +/// ``` +fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { + if_let_chain! {[ + let ExprBlock(ref block) = expr.node, + block.stmts.len() == 1, + let StmtDecl(ref decl, _) = block.stmts[0].node, + let DeclItem(ref decl) = decl.node, + let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id), + decl.name.as_str() == "__STATIC_FMTSTR", + let ItemStatic(_, _, ref expr) = decl.node, + let ExprAddrOf(_, ref expr) = expr.node, // &[""] + let ExprVec(ref expr) = expr.node, + expr.len() == 1, + let ExprLit(ref lit) = expr[0].node, + let LitKind::Str(ref lit, _) = lit.node, + lit.is_empty() + ], { + return true; + }} + + false +} + +/// Checks if the expressions matches +/// ``` +/// &match (&42,) { +/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)], +/// }) +/// ``` +fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, + let ExprMatch(_, ref arms, _) = expr.node, + arms.len() == 1, + arms[0].pats.len() == 1, + let PatKind::Tup(ref pat) = arms[0].pats[0].node, + pat.len() == 1, + let ExprVec(ref exprs) = arms[0].body.node, + exprs.len() == 1, + let ExprCall(_, ref args) = exprs[0].node, + args.len() == 2, + let ExprPath(None, ref path) = args[1].node, + match_path(path, &paths::DISPLAY_FMT_METHOD) + ], { + let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0])); + + return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING); + }} + + false +} diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs new file mode 100644 index 00000000000..aa6dd46cf0b --- /dev/null +++ b/clippy_lints/src/formatting.rs @@ -0,0 +1,166 @@ +use rustc::lint::*; +use syntax::codemap::mk_sp; +use syntax::ast; +use utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; +use syntax::ptr::P; + +/// **What it does:** This lint looks for use of the non-existent `=*`, `=!` and `=-` operators. +/// +/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or confusing. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? +/// ``` +declare_lint! { + pub SUSPICIOUS_ASSIGNMENT_FORMATTING, + Warn, + "suspicious formatting of `*=`, `-=` or `!=`" +} + +/// **What it does:** This lint checks for formatting of `else if`. It lints if the `else` and `if` +/// are not on the same line or the `else` seems to be missing. +/// +/// **Why is this bad?** This is probably some refactoring remnant, even if the code is correct, it +/// might look confusing. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// if foo { +/// } if bar { // looks like an `else` is missing here +/// } +/// +/// if foo { +/// } else +/// +/// if bar { // this is the `else` block of the previous `if`, but should it be? +/// } +/// ``` +declare_lint! { + pub SUSPICIOUS_ELSE_FORMATTING, + Warn, + "suspicious formatting of `else if`" +} + +#[derive(Copy,Clone)] +pub struct Formatting; + +impl LintPass for Formatting { + fn get_lints(&self) -> LintArray { + lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING, SUSPICIOUS_ELSE_FORMATTING] + } +} + +impl EarlyLintPass for Formatting { + fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { + for w in block.stmts.windows(2) { + match (&w[0].node, &w[1].node) { + (&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); + } + _ => (), + } + } + + if let Some(ref expr) = block.expr { + if let Some(ref stmt) = block.stmts.iter().last() { + if let ast::StmtKind::Expr(ref first, _) = stmt.node { + check_consecutive_ifs(cx, first, expr); + } + } + } + } + + fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { + check_assign(cx, expr); + check_else_if(cx, expr); + } +} + +/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. +fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { + if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { + if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(cx, lhs.span) { + let eq_span = mk_sp(lhs.span.hi, rhs.span.lo); + + if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node { + if let Some(eq_snippet) = snippet_opt(cx, eq_span) { + let op = ast::UnOp::to_string(op); + let eqop_span = mk_sp(lhs.span.hi, sub_rhs.span.lo); + if eq_snippet.ends_with('=') { + span_note_and_lint(cx, + SUSPICIOUS_ASSIGNMENT_FORMATTING, + eqop_span, + &format!("this looks like you are trying to use `.. {op}= ..`, but you \ + really are doing `.. = ({op} ..)`", + op = op), + eqop_span, + &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op)); + } + } + } + } + } +} + +/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`. +fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { + if let Some((then, &Some(ref else_))) = unsugar_if(expr) { + if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(cx, then.span) { + // this will be a span from the closing ‘}’ of the “then” block (excluding) to the + // “if” of the “else if” block (excluding) + let else_span = mk_sp(then.span.hi, else_.span.lo); + + // the snippet should look like " else \n " with maybe comments anywhere + // it’s bad when there is a ‘\n’ after the “else” + if let Some(else_snippet) = snippet_opt(cx, else_span) { + let else_pos = else_snippet.find("else").expect("there must be a `else` here"); + + if else_snippet[else_pos..].contains('\n') { + span_note_and_lint(cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this is an `else if` but the formatting might hide it", + else_span, + "to remove this lint, remove the `else` or remove the new line between `else` \ + and `if`"); + } + } + } + } +} + +/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. +fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { + if !differing_macro_contexts(first.span, second.span) && !in_macro(cx, first.span) && + unsugar_if(first).is_some() && unsugar_if(second).is_some() { + // where the else would be + let else_span = mk_sp(first.span.hi, second.span.lo); + + if let Some(else_snippet) = snippet_opt(cx, else_span) { + if !else_snippet.contains('\n') { + span_note_and_lint(cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this looks like an `else if` but the `else` is missing", + else_span, + "to remove this lint, add the missing `else` or add a new line before the second \ + `if`"); + } + } + } +} + +/// Match `if` or `else if` expressions and return the `then` and `else` block. +fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> { + match expr.node { + ast::ExprKind::If(_, ref then, ref else_) | + ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), + _ => None, + } +} diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs new file mode 100644 index 00000000000..d9334447226 --- /dev/null +++ b/clippy_lints/src/functions.rs @@ -0,0 +1,76 @@ +use rustc::lint::*; +use rustc::hir; +use rustc::hir::intravisit; +use syntax::ast; +use syntax::codemap::Span; +use utils::span_lint; + +/// **What it does:** Check for functions with too many parameters. +/// +/// **Why is this bad?** Functions with lots of parameters are considered bad style and reduce +/// readability (“what does the 5th parameter mean?”). Consider grouping some parameters into a +/// new type. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// +/// ``` +/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. } +/// ``` +declare_lint! { + pub TOO_MANY_ARGUMENTS, + Warn, + "functions with too many arguments" +} + +#[derive(Copy,Clone)] +pub struct Functions { + threshold: u64, +} + +impl Functions { + pub fn new(threshold: u64) -> Functions { + Functions { threshold: threshold } + } +} + +impl LintPass for Functions { + fn get_lints(&self) -> LintArray { + lint_array!(TOO_MANY_ARGUMENTS) + } +} + +impl LateLintPass for Functions { + fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) { + use rustc::hir::map::Node::*; + + if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { + match item.node { + hir::ItemImpl(_, _, _, Some(_), _, _) | + hir::ItemDefaultImpl(..) => return, + _ => (), + } + } + + self.check_arg_number(cx, decl, span); + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { + if let hir::MethodTraitItem(ref sig, _) = item.node { + self.check_arg_number(cx, &sig.decl, item.span); + } + } +} + +impl Functions { + fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { + let args = decl.inputs.len() as u64; + if args > self.threshold { + span_lint(cx, + TOO_MANY_ARGUMENTS, + span, + &format!("this function has too many arguments ({}/{})", args, self.threshold)); + } + } +} diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs new file mode 100644 index 00000000000..4c1f01b7385 --- /dev/null +++ b/clippy_lints/src/identity_op.rs @@ -0,0 +1,72 @@ +use consts::{constant_simple, Constant}; +use rustc::lint::*; +use rustc::hir::*; +use syntax::codemap::Span; +use utils::{span_lint, snippet, in_macro}; +use rustc_const_math::ConstInt; + +/// **What it does:** This lint checks for identity operations, e.g. `x + 0`. +/// +/// **Why is this bad?** This code can be removed without changing the meaning. So it just obscures what's going on. Delete it mercilessly. +/// +/// **Known problems:** None +/// +/// **Example:** `x / 1 + 0 * 1 - 0 | 0` +declare_lint! { + pub IDENTITY_OP, Warn, + "using identity operations, e.g. `x + 0` or `y / 1`" +} + +#[derive(Copy,Clone)] +pub struct IdentityOp; + +impl LintPass for IdentityOp { + fn get_lints(&self) -> LintArray { + lint_array!(IDENTITY_OP) + } +} + +impl LateLintPass for IdentityOp { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if in_macro(cx, e.span) { + return; + } + if let ExprBinary(ref cmp, ref left, ref right) = e.node { + match cmp.node { + 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); + } + _ => (), + } + } + } +} + + +fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { + if let Some(v @ Constant::Int(_)) = constant_simple(e) { + if match m { + 0 => v == Constant::Int(ConstInt::Infer(0)), + -1 => v == Constant::Int(ConstInt::InferSigned(-1)), + 1 => v == Constant::Int(ConstInt::Infer(1)), + _ => unreachable!(), + } { + span_lint(cx, + IDENTITY_OP, + span, + &format!("the operation is ineffective. Consider reducing it to `{}`", + snippet(cx, arg, ".."))); + } + } +} diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs new file mode 100644 index 00000000000..d78eba9877b --- /dev/null +++ b/clippy_lints/src/if_not_else.rs @@ -0,0 +1,52 @@ +//! lint on if branches that could be swapped so no `!` operation is necessary on the condition + +use rustc::lint::*; +use syntax::ast::*; + +use utils::span_help_and_lint; + +/// **What it does:** Warns on the use of `!` or `!=` in an if condition with an else branch +/// +/// **Why is this bad?** Negations reduce the readability of statements +/// +/// **Known problems:** None +/// +/// **Example:** if !v.is_empty() { a() } else { b() } +declare_lint! { + pub IF_NOT_ELSE, Allow, + "finds if branches that could be swapped so no negation operation is necessary on the condition" +} + +pub struct IfNotElse; + +impl LintPass for IfNotElse { + fn get_lints(&self) -> LintArray { + lint_array!(IF_NOT_ELSE) + } +} + +impl EarlyLintPass for IfNotElse { + fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { + if let ExprKind::If(ref cond, _, Some(ref els)) = item.node { + if let ExprKind::Block(..) = els.node { + match cond.node { + ExprKind::Unary(UnOp::Not, _) => { + span_help_and_lint(cx, + IF_NOT_ELSE, + 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 new file mode 100644 index 00000000000..2e6b33ab390 --- /dev/null +++ b/clippy_lints/src/items_after_statements.rs @@ -0,0 +1,70 @@ +//! lint when items are used after statements + +use rustc::lint::*; +use syntax::ast::*; +use utils::in_macro; + +/// **What it does:** This lints checks for items declared after some statement in a block +/// +/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are +/// processed in order. This might cause confusion as it's hard to figure out which item is meant +/// in a statement. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// fn foo() { +/// println!("cake"); +/// } +/// fn main() { +/// foo(); // prints "foo" +/// fn foo() { +/// println!("foo"); +/// } +/// foo(); // prints "foo" +/// } +/// ``` +declare_lint! { + pub ITEMS_AFTER_STATEMENTS, + Allow, + "finds blocks where an item comes after a statement" +} + +pub struct ItemsAfterStatements; + +impl LintPass for ItemsAfterStatements { + fn get_lints(&self) -> LintArray { + lint_array!(ITEMS_AFTER_STATEMENTS) + } +} + +impl EarlyLintPass for ItemsAfterStatements { + fn check_block(&mut self, cx: &EarlyContext, item: &Block) { + if in_macro(cx, item.span) { + return; + } + let mut stmts = item.stmts.iter().map(|stmt| &stmt.node); + // skip initial items + while let Some(&StmtKind::Decl(ref decl, _)) = stmts.next() { + if let DeclKind::Local(_) = decl.node { + break; + } + } + // lint on all further items + for stmt in stmts { + if let StmtKind::Decl(ref decl, _) = *stmt { + if let DeclKind::Item(ref it) = decl.node { + if in_macro(cx, it.span) { + return; + } + cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, + it.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope") + .emit(); + } + } + } + } +} diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs new file mode 100644 index 00000000000..b6dea831690 --- /dev/null +++ b/clippy_lints/src/len_zero.rs @@ -0,0 +1,202 @@ +use rustc::lint::*; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; +use rustc::hir::*; +use syntax::ast::{Lit, LitKind, Name}; +use syntax::codemap::{Span, Spanned}; +use syntax::ptr::P; +use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; + +/// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. +/// +/// **Why is this bad?** Some structures can answer `.is_empty()` much faster than calculating their length. So it is good to get into the habit of using `.is_empty()`, and having it is cheap. Besides, it makes the intent clearer than a comparison. +/// +/// **Known problems:** None +/// +/// **Example:** `if x.len() == 0 { .. }` +declare_lint! { + pub LEN_ZERO, Warn, + "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ + could be used instead" +} + +/// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. +/// +/// **Why is this bad?** It is good custom to have both methods, because for some data structures, asking about the length will be a costly operation, whereas `.is_empty()` can usually answer in constant time. Also it used to lead to false positives on the [`len_zero`](#len_zero) lint – currently that lint will ignore such entities. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// impl X { +/// fn len(&self) -> usize { .. } +/// } +/// ``` +declare_lint! { + pub LEN_WITHOUT_IS_EMPTY, Warn, + "traits and impls that have `.len()` but not `.is_empty()`" +} + +#[derive(Copy,Clone)] +pub struct LenZero; + +impl LintPass for LenZero { + fn get_lints(&self) -> LintArray { + lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) + } +} + +impl LateLintPass for LenZero { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if in_macro(cx, item.span) { + return; + } + + match item.node { + ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), + ItemImpl(_, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items), + _ => (), + } + } + + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_macro(cx, expr.span) { + return; + } + + if let ExprBinary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node { + match cmp { + BiEq => check_cmp(cx, expr.span, left, right, ""), + BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), + _ => (), + } + } + } +} + +fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { + fn is_named_self(item: &TraitItem, name: &str) -> bool { + item.name.as_str() == name && + if let MethodTraitItem(ref sig, _) = item.node { + is_self_sig(sig) + } else { + false + } + } + + if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { + for i in trait_items { + if is_named_self(i, "len") { + span_lint(cx, + LEN_WITHOUT_IS_EMPTY, + i.span, + &format!("trait `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ + Consider adding one", + item.name)); + } + } + } +} + +fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { + fn is_named_self(item: &ImplItem, name: &str) -> bool { + item.name.as_str() == name && + if let ImplItemKind::Method(ref sig, _) = item.node { + is_self_sig(sig) + } else { + false + } + } + + if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { + for i in impl_items { + if is_named_self(i, "len") { + let ty = cx.tcx.node_id_to_type(item.id); + + span_lint(cx, + LEN_WITHOUT_IS_EMPTY, + i.span, + &format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ + Consider adding one", + ty)); + return; + } + } + } +} + +fn is_self_sig(sig: &MethodSig) -> bool { + if sig.decl.has_self() { + sig.decl.inputs.len() == 1 + } else { + false + } +} + +fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { + // check if we are in an is_empty() method + if let Some(name) = get_item_name(cx, left) { + if name.as_str() == "is_empty" { + return; + } + } + match (&left.node, &right.node) { + (&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) + } + _ => (), + } +} + +fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { + if let Spanned { node: LitKind::Int(0, _), .. } = *lit { + if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { + span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| { + db.span_suggestion(span, + "consider using `is_empty`", + format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_"))); + }); + } + } +} + +/// Check if this type has an `is_empty` method. +fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { + /// Get an `ImplOrTraitItem` and return true if it matches `is_empty(self)`. + fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { + if let MethodTraitItemId(def_id) = *id { + if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { + method.name.as_str() == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 + } else { + false + } + } else { + false + } + } + + /// Check the inherent impl's items for an `is_empty(self)` method. + fn has_is_empty_impl(cx: &LateContext, id: &DefId) -> bool { + let impl_items = cx.tcx.impl_items.borrow(); + cx.tcx.inherent_impls.borrow().get(id).map_or(false, |ids| { + ids.iter().any(|iid| impl_items.get(iid).map_or(false, |iids| iids.iter().any(|i| is_is_empty(cx, i)))) + }) + } + + let ty = &walk_ptrs_ty(cx.tcx.expr_ty(expr)); + match ty.sty { + ty::TyTrait(_) => { + cx.tcx + .trait_item_def_ids + .borrow() + .get(&ty.ty_to_def_id().expect("trait impl not found")) + .map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))) + } + ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), + ty::TyEnum(ref id, _) | + ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), + ty::TyArray(..) | ty::TyStr => true, + _ => false, + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs new file mode 100644 index 00000000000..f6db7a3a188 --- /dev/null +++ b/clippy_lints/src/lib.rs @@ -0,0 +1,416 @@ +// error-pattern:cargo-clippy + +#![feature(type_macros)] +#![feature(plugin_registrar, box_syntax)] +#![feature(rustc_private, collections)] +#![feature(iter_arith)] +#![feature(custom_attribute)] +#![feature(slice_patterns)] +#![feature(question_mark)] +#![feature(stmt_expr_attributes)] +#![allow(indexing_slicing, shadow_reuse, unknown_lints)] + +extern crate rustc_driver; +extern crate getopts; + +#[macro_use] +extern crate syntax; +#[macro_use] +extern crate rustc; + +extern crate toml; + +// Only for the compile time checking of paths +extern crate core; +extern crate collections; + +// for unicode nfc normalization +extern crate unicode_normalization; + +// for semver check in attrs.rs +extern crate semver; + +// for regex checking +extern crate regex_syntax; + +// for finding minimal boolean expressions +extern crate quine_mc_cluskey; + +extern crate rustc_plugin; +extern crate rustc_const_eval; +extern crate rustc_const_math; + +macro_rules! declare_restriction_lint { + { pub $name:tt, $description:tt } => { + declare_lint! { pub $name, Allow, $description } + }; +} + +pub mod consts; +#[macro_use] +pub mod utils; + +// begin lints modules, do not remove this comment, it’s used in `update_lints` +pub mod approx_const; +pub mod arithmetic; +pub mod array_indexing; +pub mod assign_ops; +pub mod attrs; +pub mod bit_mask; +pub mod blacklisted_name; +pub mod block_in_if_condition; +pub mod booleans; +pub mod collapsible_if; +pub mod copies; +pub mod cyclomatic_complexity; +pub mod derive; +pub mod doc; +pub mod drop_ref; +pub mod entry; +pub mod enum_clike; +pub mod enum_glob_use; +pub mod enum_variants; +pub mod eq_op; +pub mod escape; +pub mod eta_reduction; +pub mod format; +pub mod formatting; +pub mod functions; +pub mod identity_op; +pub mod if_not_else; +pub mod items_after_statements; +pub mod len_zero; +pub mod lifetimes; +pub mod loops; +pub mod map_clone; +pub mod matches; +pub mod mem_forget; +pub mod methods; +pub mod minmax; +pub mod misc; +pub mod misc_early; +pub mod mut_mut; +pub mod mut_reference; +pub mod mutex_atomic; +pub mod needless_bool; +pub mod needless_borrow; +pub mod needless_update; +pub mod neg_multiply; +pub mod new_without_default; +pub mod no_effect; +pub mod non_expressive_names; +pub mod open_options; +pub mod overflow_check_conditional; +pub mod panic; +pub mod precedence; +pub mod print; +pub mod ptr_arg; +pub mod ranges; +pub mod regex; +pub mod returns; +pub mod shadow; +pub mod strings; +pub mod swap; +pub mod temporary_assignment; +pub mod transmute; +pub mod types; +pub mod unicode; +pub mod unsafe_removed_from_name; +pub mod unused_label; +pub mod vec; +pub mod zero_div_zero; +// end lints modules, do not remove this comment, it’s used in `update_lints` + +mod reexport { + pub use syntax::ast::{Name, NodeId}; +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +pub fn register_plugins(reg: &mut rustc_plugin::Registry) { + let conf = match utils::conf::conf_file(reg.args()) { + Ok(file_name) => { + // if the user specified a file, it must exist, otherwise default to `clippy.toml` but + // do not require the file to exist + let (ref file_name, must_exist) = if let Some(ref file_name) = file_name { + (&**file_name, true) + } else { + ("clippy.toml", false) + }; + + let (conf, errors) = utils::conf::read_conf(file_name, must_exist); + + // all conf errors are non-fatal, we just use the default conf in case of error + for error in errors { + reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit(); + } + + conf + } + Err((err, span)) => { + reg.sess.struct_span_err(span, err) + .span_note(span, "Clippy will use default configuration") + .emit(); + utils::conf::Conf::default() + } + }; + + 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"); + // end deprecated lints, do not remove this comment, it’s used in `update_lints` + + reg.register_late_lint_pass(box types::TypePass); + reg.register_late_lint_pass(box booleans::NonminimalBool); + reg.register_late_lint_pass(box misc::TopLevelRefPass); + reg.register_late_lint_pass(box misc::CmpNan); + reg.register_late_lint_pass(box eq_op::EqOp); + reg.register_early_lint_pass(box enum_variants::EnumVariantNames); + reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); + reg.register_late_lint_pass(box enum_clike::EnumClikeUnportableVariant); + reg.register_late_lint_pass(box bit_mask::BitMask); + reg.register_late_lint_pass(box ptr_arg::PtrArg); + reg.register_late_lint_pass(box needless_bool::NeedlessBool); + reg.register_late_lint_pass(box needless_bool::BoolComparison); + reg.register_late_lint_pass(box approx_const::ApproxConstant); + reg.register_late_lint_pass(box misc::FloatCmp); + reg.register_early_lint_pass(box precedence::Precedence); + reg.register_late_lint_pass(box eta_reduction::EtaPass); + reg.register_late_lint_pass(box identity_op::IdentityOp); + reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements); + reg.register_late_lint_pass(box mut_mut::MutMut); + reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); + reg.register_late_lint_pass(box len_zero::LenZero); + reg.register_late_lint_pass(box misc::CmpOwned); + reg.register_late_lint_pass(box attrs::AttrPass); + reg.register_late_lint_pass(box collapsible_if::CollapsibleIf); + reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition); + reg.register_late_lint_pass(box misc::ModuloOne); + reg.register_late_lint_pass(box unicode::Unicode); + reg.register_late_lint_pass(box strings::StringAdd); + reg.register_early_lint_pass(box returns::ReturnPass); + reg.register_late_lint_pass(box methods::MethodsPass); + reg.register_late_lint_pass(box shadow::ShadowPass); + reg.register_late_lint_pass(box types::LetPass); + reg.register_late_lint_pass(box types::UnitCmp); + reg.register_late_lint_pass(box loops::LoopsPass); + reg.register_late_lint_pass(box lifetimes::LifetimePass); + reg.register_late_lint_pass(box entry::HashMapLint); + reg.register_late_lint_pass(box ranges::StepByZero); + reg.register_late_lint_pass(box types::CastPass); + reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold)); + reg.register_late_lint_pass(box matches::MatchPass); + reg.register_late_lint_pass(box misc::PatternPass); + reg.register_late_lint_pass(box minmax::MinMaxPass); + reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions); + reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); + reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); + reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); + reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow); + reg.register_late_lint_pass(box no_effect::NoEffectPass); + reg.register_late_lint_pass(box map_clone::MapClonePass); + reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); + 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 escape::EscapePass); + reg.register_early_lint_pass(box misc_early::MiscEarly); + reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); + reg.register_late_lint_pass(box array_indexing::ArrayIndexing); + reg.register_late_lint_pass(box panic::PanicPass); + reg.register_late_lint_pass(box strings::StringLitAsBytes); + reg.register_late_lint_pass(box derive::Derive); + reg.register_late_lint_pass(box types::CharLitAsU8); + reg.register_late_lint_pass(box print::PrintLint); + reg.register_late_lint_pass(box vec::UselessVec); + reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { + max_single_char_names: conf.max_single_char_names, + }); + reg.register_late_lint_pass(box drop_ref::DropRefPass); + reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); + reg.register_late_lint_pass(box types::InvalidUpcastComparisons); + reg.register_late_lint_pass(box regex::RegexPass::default()); + reg.register_late_lint_pass(box copies::CopyAndPaste); + reg.register_late_lint_pass(box format::FormatMacLint); + reg.register_early_lint_pass(box formatting::Formatting); + reg.register_late_lint_pass(box swap::Swap); + reg.register_early_lint_pass(box if_not_else::IfNotElse); + reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); + reg.register_late_lint_pass(box unused_label::UnusedLabel); + reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); + reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); + 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_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); + + reg.register_lint_group("clippy_restrictions", vec![ + arithmetic::FLOAT_ARITHMETIC, + arithmetic::INTEGER_ARITHMETIC, + assign_ops::ASSIGN_OPS, + ]); + + reg.register_lint_group("clippy_pedantic", vec![ + array_indexing::INDEXING_SLICING, + booleans::NONMINIMAL_BOOL, + enum_glob_use::ENUM_GLOB_USE, + if_not_else::IF_NOT_ELSE, + items_after_statements::ITEMS_AFTER_STATEMENTS, + matches::SINGLE_MATCH_ELSE, + mem_forget::MEM_FORGET, + methods::OPTION_UNWRAP_USED, + methods::RESULT_UNWRAP_USED, + methods::WRONG_PUB_SELF_CONVENTION, + misc::USED_UNDERSCORE_BINDING, + mut_mut::MUT_MUT, + mutex_atomic::MUTEX_INTEGER, + non_expressive_names::SIMILAR_NAMES, + print::PRINT_STDOUT, + print::USE_DEBUG, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, + strings::STRING_ADD, + strings::STRING_ADD_ASSIGN, + types::CAST_POSSIBLE_TRUNCATION, + types::CAST_POSSIBLE_WRAP, + types::CAST_PRECISION_LOSS, + types::CAST_SIGN_LOSS, + types::INVALID_UPCAST_COMPARISONS, + unicode::NON_ASCII_LITERAL, + unicode::UNICODE_NOT_NFC, + ]); + + reg.register_lint_group("clippy", vec![ + approx_const::APPROX_CONSTANT, + array_indexing::OUT_OF_BOUNDS_INDEXING, + assign_ops::ASSIGN_OP_PATTERN, + attrs::DEPRECATED_SEMVER, + attrs::INLINE_ALWAYS, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + blacklisted_name::BLACKLISTED_NAME, + block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, + block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, + booleans::LOGIC_BUG, + collapsible_if::COLLAPSIBLE_IF, + copies::IF_SAME_THEN_ELSE, + copies::IFS_SAME_COND, + copies::MATCH_SAME_ARMS, + cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, + derive::DERIVE_HASH_XOR_EQ, + derive::EXPL_IMPL_CLONE_ON_COPY, + doc::DOC_MARKDOWN, + drop_ref::DROP_REF, + entry::MAP_ENTRY, + enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, + enum_variants::ENUM_VARIANT_NAMES, + eq_op::EQ_OP, + escape::BOXED_LOCAL, + eta_reduction::REDUNDANT_CLOSURE, + format::USELESS_FORMAT, + formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + formatting::SUSPICIOUS_ELSE_FORMATTING, + functions::TOO_MANY_ARGUMENTS, + identity_op::IDENTITY_OP, + len_zero::LEN_WITHOUT_IS_EMPTY, + len_zero::LEN_ZERO, + lifetimes::NEEDLESS_LIFETIMES, + lifetimes::UNUSED_LIFETIMES, + loops::EMPTY_LOOP, + loops::EXPLICIT_COUNTER_LOOP, + loops::EXPLICIT_ITER_LOOP, + loops::FOR_KV_MAP, + loops::FOR_LOOP_OVER_OPTION, + loops::FOR_LOOP_OVER_RESULT, + loops::ITER_NEXT_LOOP, + loops::NEEDLESS_RANGE_LOOP, + loops::REVERSE_RANGE_LOOP, + loops::UNUSED_COLLECT, + loops::WHILE_LET_LOOP, + loops::WHILE_LET_ON_ITERATOR, + map_clone::MAP_CLONE, + matches::MATCH_BOOL, + matches::MATCH_OVERLAPPING_ARM, + matches::MATCH_REF_PATS, + matches::SINGLE_MATCH, + methods::CHARS_NEXT_CMP, + methods::CLONE_DOUBLE_REF, + methods::CLONE_ON_COPY, + methods::EXTEND_FROM_SLICE, + methods::FILTER_NEXT, + methods::NEW_RET_NO_SELF, + methods::OK_EXPECT, + methods::OPTION_MAP_UNWRAP_OR, + methods::OPTION_MAP_UNWRAP_OR_ELSE, + methods::OR_FUN_CALL, + methods::SEARCH_IS_SOME, + methods::SHOULD_IMPLEMENT_TRAIT, + methods::SINGLE_CHAR_PATTERN, + methods::TEMPORARY_CSTRING_AS_PTR, + methods::WRONG_SELF_CONVENTION, + minmax::MIN_MAX, + misc::CMP_NAN, + misc::CMP_OWNED, + misc::FLOAT_CMP, + misc::MODULO_ONE, + misc::REDUNDANT_PATTERN, + misc::TOPLEVEL_REF_ARG, + misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::REDUNDANT_CLOSURE_CALL, + misc_early::UNNEEDED_FIELD_PATTERN, + mut_reference::UNNECESSARY_MUT_PASSED, + mutex_atomic::MUTEX_ATOMIC, + needless_bool::BOOL_COMPARISON, + needless_bool::NEEDLESS_BOOL, + needless_borrow::NEEDLESS_BORROW, + needless_update::NEEDLESS_UPDATE, + neg_multiply::NEG_MULTIPLY, + new_without_default::NEW_WITHOUT_DEFAULT, + new_without_default::NEW_WITHOUT_DEFAULT_DERIVE, + no_effect::NO_EFFECT, + no_effect::UNNECESSARY_OPERATION, + non_expressive_names::MANY_SINGLE_CHAR_NAMES, + open_options::NONSENSICAL_OPEN_OPTIONS, + overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + panic::PANIC_PARAMS, + precedence::PRECEDENCE, + ptr_arg::PTR_ARG, + ranges::RANGE_STEP_BY_ZERO, + ranges::RANGE_ZIP_WITH_LEN, + regex::INVALID_REGEX, + regex::REGEX_MACRO, + regex::TRIVIAL_REGEX, + returns::LET_AND_RETURN, + returns::NEEDLESS_RETURN, + strings::STRING_LIT_AS_BYTES, + swap::ALMOST_SWAPPED, + swap::MANUAL_SWAP, + temporary_assignment::TEMPORARY_ASSIGNMENT, + transmute::CROSSPOINTER_TRANSMUTE, + transmute::TRANSMUTE_PTR_TO_REF, + transmute::USELESS_TRANSMUTE, + types::ABSURD_EXTREME_COMPARISONS, + types::BOX_VEC, + types::CHAR_LIT_AS_U8, + types::LET_UNIT_VALUE, + types::LINKEDLIST, + types::TYPE_COMPLEXITY, + types::UNIT_CMP, + unicode::ZERO_WIDTH_SPACE, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_label::UNUSED_LABEL, + vec::USELESS_VEC, + zero_div_zero::ZERO_DIVIDED_BY_ZERO, + ]); +} + +// only exists to let the dogfood integration test works. +// Don't run clippy as an executable directly +#[allow(dead_code, print_stdout)] +fn main() { + panic!("Please use the cargo-clippy executable"); +} diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs new file mode 100644 index 00000000000..797e9708b60 --- /dev/null +++ b/clippy_lints/src/lifetimes.rs @@ -0,0 +1,347 @@ +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 std::collections::{HashSet, HashMap}; +use syntax::codemap::Span; +use utils::{in_external_macro, span_lint}; + +/// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. +/// +/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. +/// +/// **Known problems:** Potential false negatives: we bail out if the function has a `where` clause where lifetimes are mentioned. +/// +/// **Example:** `fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }` +declare_lint! { + pub NEEDLESS_LIFETIMES, + Warn, + "using explicit lifetimes for references in function arguments when elision rules \ + would allow omitting them" +} + +/// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. +/// +/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. +/// +/// **Known problems:** None +/// +/// **Example:** `fn unused_lifetime<'a>(x: u8) { .. }` +declare_lint! { + pub UNUSED_LIFETIMES, + Warn, + "unused lifetimes in function definitions" +} + +#[derive(Copy,Clone)] +pub struct LifetimePass; + +impl LintPass for LifetimePass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES) + } +} + +impl LateLintPass for LifetimePass { + fn check_item(&mut self, cx: &LateContext, item: &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) { + 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) { + if let MethodTraitItem(ref sig, _) = item.node { + check_fn_inner(cx, &sig.decl, &sig.generics, item.span); + } + } +} + +/// The lifetime of a &-reference. +#[derive(PartialEq, Eq, Hash, Debug)] +enum RefLt { + Unnamed, + Static, + Named(Name), +} + +fn bound_lifetimes(bound: &TyParamBound) -> Option<HirVec<&Lifetime>> { + if let TraitTyParamBound(ref trait_ref, _) = *bound { + let lt = trait_ref.trait_ref + .path + .segments + .last() + .expect("a path must have at least one segment") + .parameters + .lifetimes(); + + Some(lt) + } else { + None + } +} + +fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &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(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); + + if could_use_elision(cx, decl, &generics.lifetimes, bounds_lts) { + span_lint(cx, + NEEDLESS_LIFETIMES, + span, + "explicit lifetimes given in parameter types where they could be elided"); + } + report_extra_lifetimes(cx, decl, generics); +} + +fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, + named_lts: &[LifetimeDef], bounds_lts: T) + -> bool { + // 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 + // All lifetimes must be unnamed, 'static or defined without bounds on the + // level of the current item. + + // check named LTs + let allowed_lts = allowed_lts_from(named_lts); + + // these will collect all the lifetimes for references in arg/return types + let mut input_visitor = RefVisitor::new(cx); + let mut output_visitor = RefVisitor::new(cx); + + // extract lifetimes in input argument types + for arg in &func.inputs { + input_visitor.visit_ty(&arg.ty); + } + // extract lifetimes in output type + if let Return(ref ty) = func.output { + output_visitor.visit_ty(ty); + } + + let input_lts = lts_from_bounds(input_visitor.into_vec(), bounds_lts); + let output_lts = output_visitor.into_vec(); + + // check for lifetimes from higher scopes + for lt in input_lts.iter().chain(output_lts.iter()) { + if !allowed_lts.contains(lt) { + return false; + } + } + + // no input lifetimes? easy case! + if input_lts.is_empty() { + false + } else if output_lts.is_empty() { + // no output lifetimes, check distinctness of input lifetimes + + // only unnamed and static, ok + if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) { + return false; + } + // we have no output reference, so we only need all distinct lifetimes + input_lts.len() == unique_lifetimes(&input_lts) + } else { + // we have output references, so we need one input reference, + // and all output lifetimes must be the same + if unique_lifetimes(&output_lts) > 1 { + return false; + } + if input_lts.len() == 1 { + match (&input_lts[0], &output_lts[0]) { + (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true, + (&RefLt::Named(_), &RefLt::Unnamed) => true, + _ => false, // already elided, different named lifetimes + // or something static going on + } + } else { + false + } + } +} + +fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { + let mut allowed_lts = HashSet::new(); + for lt in named_lts { + if lt.bounds.is_empty() { + allowed_lts.insert(RefLt::Named(lt.lifetime.name)); + } + } + allowed_lts.insert(RefLt::Unnamed); + allowed_lts.insert(RefLt::Static); + allowed_lts +} + +fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> { + for lt in bounds_lts { + if lt.name.as_str() != "'static" { + vec.push(RefLt::Named(lt.name)); + } + } + + vec +} + +/// Number of unique lifetimes in the given vector. +fn unique_lifetimes(lts: &[RefLt]) -> usize { + lts.iter().collect::<HashSet<_>>().len() +} + +/// A visitor usable for `rustc_front::visit::walk_ty()`. +struct RefVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, + lts: Vec<RefLt>, +} + +impl<'v, 't> RefVisitor<'v, 't> { + fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> { + RefVisitor { + cx: cx, + lts: Vec::new(), + } + } + + fn record(&mut self, lifetime: &Option<Lifetime>) { + if let Some(ref lt) = *lifetime { + if lt.name.as_str() == "'static" { + self.lts.push(RefLt::Static); + } else { + self.lts.push(RefLt::Named(lt.name)); + } + } else { + self.lts.push(RefLt::Unnamed); + } + } + + fn into_vec(self) -> Vec<RefLt> { + 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 { + 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 type_scheme = self.cx.tcx.lookup_item_type(def_id); + for _ in type_scheme.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); + } + } + _ => (), + } + } + } + } + } +} + +impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { + // for lifetimes as parameters of generics + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + self.record(&Some(*lifetime)); + } + + fn visit_ty(&mut self, ty: &'v Ty) { + match ty.node { + TyRptr(None, _) => { + self.record(&None); + } + TyPath(_, ref path) => { + self.collect_anonymous_lifetimes(path, ty); + } + _ => (), + } + walk_ty(self, ty); + } +} + +/// 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 { + for predicate in &where_clause.predicates { + match *predicate { + WherePredicate::RegionPredicate(..) => return true, + WherePredicate::BoundPredicate(ref pred) => { + // a predicate like F: Trait or F: for<'a> Trait<'a> + let mut visitor = RefVisitor::new(cx); + // walk the type F, it may not contain LT refs + walk_ty(&mut visitor, &pred.bounded_ty); + if !visitor.lts.is_empty() { + return true; + } + // if the bounds define new lifetimes, they are fine to occur + let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); + // now walk the bounds + for bound in pred.bounds.iter() { + walk_ty_param_bound(&mut visitor, bound); + } + // and check that all lifetimes are allowed + for lt in visitor.into_vec() { + if !allowed_lts.contains(<) { + 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<Name, Span>); + +impl<'v> Visitor<'v> for LifetimeChecker { + // for lifetimes as parameters of generics + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + self.0.remove(&lifetime.name); + } + + fn visit_lifetime_def(&mut self, _: &'v 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 report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { + let hs = generics.lifetimes + .iter() + .map(|lt| (lt.lifetime.name, lt.lifetime.span)) + .collect(); + let mut checker = LifetimeChecker(hs); + + walk_generics(&mut checker, generics); + walk_fn_decl(&mut checker, func); + + for &v in checker.0.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 new file mode 100644 index 00000000000..061b8efaa64 --- /dev/null +++ b/clippy_lints/src/loops.rs @@ -0,0 +1,976 @@ +use reexport::*; +use rustc::hir::*; +use rustc::hir::def::Def; +use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; +use rustc::hir::map::Node::NodeBlock; +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc::middle::region::CodeExtent; +use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use std::borrow::Cow; +use std::collections::HashMap; +use syntax::ast; + +use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, + span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range, + walk_ptrs_ty, recover_for_loop}; +use utils::paths; +use utils::UnsugaredRange; + +/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. +/// +/// **Why is this bad?** Just iterating the collection itself makes the intent more clear and is probably faster. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// for i in 0..vec.len() { +/// println!("{}", vec[i]); +/// } +/// ``` +declare_lint! { + pub NEEDLESS_RANGE_LOOP, + Warn, + "for-looping over a range of indices where an iterator over items would do" +} + +/// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. +/// +/// **Why is this bad?** Readability. +/// +/// **Known problems:** False negatives. We currently only warn on some known types. +/// +/// **Example:** `for x in y.iter() { .. }` (where y is a `Vec` or slice) +declare_lint! { + pub EXPLICIT_ITER_LOOP, + Warn, + "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" +} + +/// **What it does:** This lint checks for loops on `x.next()`. +/// +/// **Why is this bad?** `next()` returns either `Some(value)` if there was a value, or `None` otherwise. The insidious thing is that `Option<_>` implements `IntoIterator`, so that possibly one value will be iterated, leading to some hard to find bugs. No one will want to write such code [except to win an Underhanded Rust Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). +/// +/// **Known problems:** None +/// +/// **Example:** `for x in y.next() { .. }` +declare_lint! { + pub ITER_NEXT_LOOP, + Warn, + "for-looping over `_.next()` which is probably not intended" +} + +/// **What it does:** This lint checks for `for` loops over `Option` values. +/// +/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in option { .. }`. This should be `if let Some(x) = option { .. }`. +declare_lint! { + pub FOR_LOOP_OVER_OPTION, + Warn, + "for-looping over an `Option`, which is more clearly expressed as an `if let`" +} + +/// **What it does:** This lint checks for `for` loops over `Result` values. +/// +/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in result { .. }`. This should be `if let Ok(x) = result { .. }`. +declare_lint! { + pub FOR_LOOP_OVER_RESULT, + Warn, + "for-looping over a `Result`, which is more clearly expressed as an `if let`" +} + +/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. +/// +/// **Why is this bad?** The `while let` loop is usually shorter and more readable +/// +/// **Known problems:** Sometimes the wrong binding is displayed (#383) +/// +/// **Example:** +/// +/// ``` +/// loop { +/// let x = match y { +/// Some(x) => x, +/// None => break, +/// } +/// // .. do something with x +/// } +/// // is easier written as +/// while let Some(x) = y { +/// // .. do something with x +/// } +/// ``` +declare_lint! { + pub WHILE_LET_LOOP, + Warn, + "`loop { if let { ... } else break }` can be written as a `while let` loop" +} + +/// **What it does:** This lint checks for using `collect()` on an iterator without using the result. +/// +/// **Why is this bad?** It is more idiomatic to use a `for` loop over the iterator instead. +/// +/// **Known problems:** None +/// +/// **Example:** `vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();` +declare_lint! { + pub UNUSED_COLLECT, + Warn, + "`collect()`ing an iterator without using the result; this is usually better \ + written as a for loop" +} + +/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. +/// +/// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. +/// +/// **Known problems:** The lint cannot catch loops over dynamically defined ranges. Doing this would require simulating all possible inputs and code paths through the program, which would be complex and error-prone. +/// +/// **Examples**: `for x in 5..10-5 { .. }` (oops, stray `-`) +declare_lint! { + pub REVERSE_RANGE_LOOP, + Warn, + "Iterating over an empty range, such as `10..0` or `5..5`" +} + +/// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. +/// +/// **Why is it bad?** Not only is the version using `.enumerate()` more readable, the compiler is able to remove bounds checks which can lead to faster code in some instances. +/// +/// **Known problems:** None. +/// +/// **Example:** `for i in 0..v.len() { foo(v[i]); }` or `for i in 0..v.len() { bar(i, v[i]); }` +declare_lint! { + pub EXPLICIT_COUNTER_LOOP, + Warn, + "for-looping with an explicit counter when `_.enumerate()` would do" +} + +/// **What it does:** This lint checks for empty `loop` expressions. +/// +/// **Why is this bad?** Those busy loops burn CPU cycles without doing anything. Think of the environment and either block on something or at least make the thread sleep for some microseconds. +/// +/// **Known problems:** None +/// +/// **Example:** `loop {}` +declare_lint! { + pub EMPTY_LOOP, + Warn, + "empty `loop {}` detected" +} + +/// **What it does:** This lint checks for `while let` expressions on iterators. +/// +/// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys the intent better. +/// +/// **Known problems:** None +/// +/// **Example:** `while let Some(val) = iter() { .. }` +declare_lint! { + pub WHILE_LET_ON_ITERATOR, + Warn, + "using a while-let loop instead of a for loop on an iterator" +} + +/// **What it does:** This warns when you iterate on a map (`HashMap` or `BTreeMap`) and ignore +/// either the keys or values. +/// +/// **Why is this bad?** Readability. There are `keys` and `values` methods that can be used to +/// express that don't need the values or keys. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ```rust +/// for (k, _) in &map { .. } +/// ``` +/// could be replaced by +/// ```rust +/// for k in map.keys() { .. } +/// ``` +declare_lint! { + pub FOR_KV_MAP, + Warn, + "looping on a map using `iter` when `keys` or `values` would do" +} + +#[derive(Copy, Clone)] +pub struct LoopsPass; + +impl LintPass for LoopsPass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RANGE_LOOP, + EXPLICIT_ITER_LOOP, + ITER_NEXT_LOOP, + WHILE_LET_LOOP, + UNUSED_COLLECT, + REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, + EMPTY_LOOP, + WHILE_LET_ON_ITERATOR, + FOR_KV_MAP) + } +} + +impl LateLintPass for LoopsPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let Some((pat, arg, body)) = recover_for_loop(expr) { + check_for_loop(cx, pat, arg, body, expr); + } + // check for `loop { if let {} else break }` that could be `while let` + // (also matches an explicit "match" instead of "if let") + // (even if the "match" or "if let" is used for declaration) + if let ExprLoop(ref block, _) = expr.node { + // also check for empty `loop {}` statements + if block.stmts.is_empty() && block.expr.is_none() { + span_lint(cx, + EMPTY_LOOP, + expr.span, + "empty `loop {}` detected. You may want to either use `panic!()` or add \ + `std::thread::sleep(..);` to the loop body."); + } + + // extract the expression from the first statement (if any) in a block + let inner_stmt_expr = extract_expr_from_first_stmt(block); + // or extract the first expression (if any) from the block + if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(block)) { + if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { + // ensure "if let" compatible match structure + match *source { + MatchSource::Normal | + MatchSource::IfLetDesugar { .. } => { + 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) { + return; + } + + // NOTE: we used to make build a body here instead of using + // ellipsis, this was removed because: + // 1) it was ugly with big bodies; + // 2) it was not indented properly; + // 3) it wasn’t very smart (see #675). + span_lint_and_then(cx, + WHILE_LET_LOOP, + 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); + }); + } + } + _ => (), + } + } + } + } + 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, Some(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_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_help_and_lint(cx, + WHILE_LET_ON_ITERATOR, + expr.span, + "this loop could be written as a `for` loop", + &format!("try\nfor {} in {} {{...}}", loop_var, iterator)); + } + } + } + } + } + + fn check_stmt(&mut self, cx: &LateContext, stmt: &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" && + match_trait_method(cx, expr, &paths::ITERATOR) { + span_lint(cx, + UNUSED_COLLECT, + expr.span, + "you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator"); + } + } + } + } +} + +fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &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); + check_for_loop_explicit_counter(cx, arg, body, expr); + check_for_loop_over_map_kv(cx, pat, arg, body, expr); +} + +/// 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) { + if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) { + // the var must be a single name + if let PatKind::Ident(_, ref ident, _) = pat.node { + let mut visitor = VarVisitor { + cx: cx, + var: ident.node, + indexed: HashMap::new(), + nonindex: false, + }; + walk_expr(&mut visitor, body); + + // 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 */); + + // ensure that the indexed variable was declared before the loop, see #601 + if let Some(indexed_extent) = indexed_extent { + let pat_extent = cx.tcx.region_maps.var_scope(pat.id); + if cx.tcx.region_maps.is_subscope_of(indexed_extent, pat_extent) { + return; + } + } + + let starts_at_zero = is_integer_literal(start, 0); + + let skip: Cow<_> = if starts_at_zero { + "".into() + } else { + format!(".skip({})", snippet(cx, start.span, "..")).into() + }; + + let take: Cow<_> = if let Some(ref end) = *end { + if is_len_call(end, &indexed) { + "".into() + } else { + format!(".take({})", snippet(cx, end.span, "..")).into() + } + } else { + "".into() + }; + + if visitor.nonindex { + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is used to index `{}`. Consider using `for ({}, \ + item) in {}.iter().enumerate(){}{}` or similar iterators", + ident.node, + indexed, + ident.node, + indexed, + take, + skip)); + } else { + let repl = if starts_at_zero && take.is_empty() { + format!("&{}", indexed) + } else { + format!("{}.iter(){}{}", indexed, take, skip) + }; + + span_lint(cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is only used to index `{}`. \ + Consider using `for item in {}` or similar iterators", + ident.node, + indexed, + repl)); + } + } + } + } +} + +fn is_len_call(expr: &Expr, var: &Name) -> bool { + if_let_chain! {[ + 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, + path.segments.len() == 1, + &path.segments[0].name == var + ], { + return true; + }} + + false +} + +fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { + // if this for loop is iterating over a two-sided range... + if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) { + // ...and both sides are compile-time constant integers... + if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) { + if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) { + // ...and the start index is greater than the end index, + // this loop will never run. This is often confusing for developers + // who think that this will iterate from the larger value to the + // smaller value. + 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), + }; + + if sup { + let start_snippet = snippet(cx, start.span, "_"); + let end_snippet = snippet(cx, end.span, "_"); + + span_lint_and_then(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run", + |db| { + db.span_suggestion(expr.span, + "consider using the following if \ + you are attempting to iterate \ + over this range in reverse", + format!("({}..{}).rev()` ", end_snippet, start_snippet)); + }); + } else if eq && limits != ast::RangeLimits::Closed { + // if they are equal, it's also problematic - this loop + // will never run. + span_lint(cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run"); + } + } + } + } +} + +fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { + let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used + if let ExprMethodCall(ref method, _, ref args) = arg.node { + // just the receiver, no arguments + if args.len() == 1 { + let method_name = method.node; + // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x + if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { + if is_ref_iterable_type(cx, &args[0]) { + let object = snippet(cx, args[0].span, "_"); + span_lint(cx, + EXPLICIT_ITER_LOOP, + expr.span, + &format!("it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", + if method_name.as_str() == "iter_mut" { + "mut " + } else { + "" + }, + object, + object, + method_name)); + } + } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { + span_lint(cx, + ITER_NEXT_LOOP, + expr.span, + "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ + probably not what you want"); + next_loop_linted = true; + } + } + } + if !next_loop_linted { + check_arg_type(cx, pat, arg); + } +} + +/// Check for `for` loops over `Option`s and `Results` +fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { + let ty = cx.tcx.expr_ty(arg); + if match_type(cx, ty, &paths::OPTION) { + span_help_and_lint(cx, + FOR_LOOP_OVER_OPTION, + arg.span, + &format!("for loop over `{0}`, which is an `Option`. This is more readably written as an \ + `if let` statement.", + snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_"))); + } else if match_type(cx, ty, &paths::RESULT) { + span_help_and_lint(cx, + FOR_LOOP_OVER_RESULT, + arg.span, + &format!("for loop over `{0}`, which is a `Result`. This is more readably written as an \ + `if let` statement.", + snippet(cx, arg.span, "_")), + &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_"))); + } +} + +fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { + // Look for variables that are incremented once per loop iteration. + let mut visitor = IncrementVisitor { + cx: cx, + states: HashMap::new(), + depth: 0, + done: false, + }; + walk_expr(&mut visitor, body); + + // For each candidate, check the parent block to see if + // it's initialized to zero at the start of the loop. + let map = &cx.tcx.map; + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id)); + if let Some(parent_id) = parent_scope { + if let NodeBlock(block) = map.get(parent_id) { + for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { + let mut visitor2 = InitializeVisitor { + cx: cx, + end_expr: expr, + var_id: *id, + state: VarState::IncrOnce, + name: None, + depth: 0, + past_loop: false, + }; + walk_block(&mut visitor2, block); + + if visitor2.state == VarState::Warn { + if let Some(name) = visitor2.name { + span_lint(cx, + EXPLICIT_COUNTER_LOOP, + expr.span, + &format!("the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ + item) in {1}.enumerate()` or similar iterators", + name, + snippet(cx, arg.span, "_"))); + } + } + } + } + } +} + +/// Check for the `FOR_KV_MAP` lint. +fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { + if let PatKind::Tup(ref pat) = pat.node { + if pat.len() == 2 { + let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { + (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), + (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), + _ => return, + }; + + let arg_span = match arg.node { + ExprAddrOf(MutImmutable, ref expr) => expr.span, + ExprAddrOf(MutMutable, _) => return, // for _ in &mut _, there is no {values,keys}_mut method + _ => arg.span, + }; + + let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); + if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) { + span_lint_and_then(cx, + FOR_KV_MAP, + expr.span, + &format!("you seem to want to iterate on a map's {}", kind), + |db| { + db.span_suggestion(expr.span, + "use the corresponding method", + format!("for {} in {}.{}() {{...}}", + snippet(cx, *pat_span, ".."), + snippet(cx, arg_span, ".."), + kind)); + }); + } + } + } + +} + +/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. +fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { + match *pat { + PatKind::Wild => true, + PatKind::Ident(_, ident, None) if ident.node.as_str().starts_with('_') => { + let mut visitor = UsedVisitor { + var: ident.node, + used: false, + }; + walk_expr(&mut visitor, body); + !visitor.used + } + _ => false, + } +} + +struct UsedVisitor { + var: ast::Name, // var to look for + used: bool, // has the var been used otherwise? +} + +impl<'a> Visitor<'a> for UsedVisitor { + fn visit_expr(&mut self, expr: &Expr) { + if let ExprPath(None, ref path) = expr.node { + if path.segments.len() == 1 && path.segments[0].name == self.var { + self.used = true; + return; + } + } + + walk_expr(self, expr); + } +} + +struct VarVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, // context reference + var: Name, // var name to look for as index + indexed: HashMap<Name, Option<CodeExtent>>, // indexed variables, the extent is None for global + nonindex: bool, // has the var been used otherwise? +} + +impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { + fn visit_expr(&mut self, expr: &'v Expr) { + if let ExprPath(None, ref path) = expr.node { + if path.segments.len() == 1 && path.segments[0].name == 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 { + Def::Local(..) | Def::Upvar(..) => { + let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); + self.indexed.insert(seqvar.segments[0].name, Some(extent)); + return; // no need to walk further + } + Def::Static(..) | Def::Const(..) => { + self.indexed.insert(seqvar.segments[0].name, None); + return; // no need to walk further + } + _ => (), + } + } + } + } + // we are not indexing anything, record that + self.nonindex = true; + return; + } + } + walk_expr(self, expr); + } +} + +fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { + let def_id = match var_def_id(cx, iter_expr) { + Some(id) => id, + None => return false, + }; + let mut visitor = VarUsedAfterLoopVisitor { + cx: cx, + def_id: def_id, + iter_expr_id: iter_expr.id, + past_while_let: false, + var_used_after_while_let: false, + }; + if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { + walk_block(&mut visitor, enclosing_block); + } + visitor.var_used_after_while_let +} + +struct VarUsedAfterLoopVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, + 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) { + if self.past_while_let { + if Some(self.def_id) == var_def_id(self.cx, expr) { + self.var_used_after_while_let = true; + } + } else if self.iter_expr_id == expr.id { + self.past_while_let = true; + } + walk_expr(self, expr); + } +} + + +/// Return true if the type of expr is one that provides `IntoIterator` impls +/// for `&T` and `&mut T`, such as `Vec`. +#[cfg_attr(rustfmt, rustfmt_skip)] +fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { + // no walk_ptrs_ty: calling iter() on a reference can make sense because it + // will allow further borrows afterwards + let ty = cx.tcx.expr_ty(e); + is_iterable_array(ty) || + match_type(cx, ty, &paths::VEC) || + match_type(cx, ty, &paths::LINKED_LIST) || + match_type(cx, ty, &paths::HASHMAP) || + match_type(cx, ty, &paths::HASHSET) || + match_type(cx, ty, &paths::VEC_DEQUE) || + match_type(cx, ty, &paths::BINARY_HEAP) || + match_type(cx, ty, &paths::BTREEMAP) || + match_type(cx, ty, &paths::BTREESET) +} + +fn is_iterable_array(ty: ty::Ty) -> bool { + // IntoIterator is currently only implemented for array sizes <= 32 in rustc + match ty.sty { + ty::TyArray(_, 0...32) => true, + _ => false, + } +} + +/// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. +fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { + if block.stmts.is_empty() { + return None; + } + if let StmtDecl(ref decl, _) = block.stmts[0].node { + if let DeclLocal(ref local) = decl.node { + if let Some(ref expr) = local.init { + Some(expr) + } else { + None + } + } else { + None + } + } else { + None + } +} + +/// If a block begins with an expression (with or without semicolon), return it. +fn extract_first_expr(block: &Block) -> Option<&Expr> { + match block.expr { + Some(ref expr) => Some(expr), + None if !block.stmts.is_empty() => { + match block.stmts[0].node { + StmtExpr(ref expr, _) | + StmtSemi(ref expr, _) => Some(expr), + _ => None, + } + } + _ => None, + } +} + +/// Return true if expr contains a single break expr (maybe within a block). +fn is_break_expr(expr: &Expr) -> bool { + match expr.node { + ExprBreak(None) => true, + // there won't be a `let <pat> = break` and so we can safely ignore the StmtDecl case + ExprBlock(ref b) => { + match extract_first_expr(b) { + Some(ref subexpr) => is_break_expr(subexpr), + None => false, + } + } + _ => false, + } +} + +// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be +// incremented exactly once in the loop body, and initialized to zero +// at the start of the loop. +#[derive(PartialEq)] +enum VarState { + Initial, // Not examined yet + IncrOnce, // Incremented exactly once, may be a loop counter + Declared, // Declared but not (yet) initialized to zero + Warn, + DontWarn, +} + +/// Scan a for loop for variables that are incremented exactly once. +struct IncrementVisitor<'v, 't: 'v> { + cx: &'v LateContext<'v, 't>, // context reference + states: HashMap<NodeId, VarState>, // incremented variables + depth: u32, // depth of conditional expressions + done: bool, +} + +impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { + fn visit_expr(&mut self, expr: &'v Expr) { + if self.done { + return; + } + + // If node is a variable + if let Some(def_id) = var_def_id(self.cx, expr) { + if let Some(parent) = get_parent_expr(self.cx, expr) { + let state = self.states.entry(def_id).or_insert(VarState::Initial); + + match parent.node { + ExprAssignOp(op, ref lhs, ref rhs) => { + if lhs.id == expr.id { + if op.node == BiAdd && is_integer_literal(rhs, 1) { + *state = match *state { + VarState::Initial if self.depth == 0 => VarState::IncrOnce, + _ => VarState::DontWarn, + }; + } else { + // Assigned some other value + *state = VarState::DontWarn; + } + } + } + ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, + ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, + _ => (), + } + } + } else if is_loop(expr) { + self.states.clear(); + self.done = true; + return; + } else if is_conditional(expr) { + self.depth += 1; + walk_expr(self, expr); + self.depth -= 1; + return; + } + walk_expr(self, expr); + } +} + +/// 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. + var_id: NodeId, + state: VarState, + name: Option<Name>, + depth: u32, // depth of conditional expressions + past_loop: bool, +} + +impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { + fn visit_decl(&mut self, decl: &'v Decl) { + // Look for declarations of the variable + if let DeclLocal(ref local) = decl.node { + if local.pat.id == self.var_id { + if let PatKind::Ident(_, ref ident, _) = local.pat.node { + self.name = Some(ident.node); + + self.state = if let Some(ref init) = local.init { + if is_integer_literal(init, 0) { + VarState::Warn + } else { + VarState::Declared + } + } else { + VarState::Declared + } + } + } + } + walk_decl(self, decl); + } + + fn visit_expr(&mut self, expr: &'v Expr) { + if self.state == VarState::DontWarn { + return; + } + if expr == self.end_expr { + self.past_loop = true; + return; + } + // No need to visit expressions before the variable is + // declared + if self.state == VarState::IncrOnce { + return; + } + + // If node is the desired variable, see how it's used + if var_def_id(self.cx, expr) == Some(self.var_id) { + if let Some(parent) = get_parent_expr(self.cx, expr) { + 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, + _ => (), + } + } + + if self.past_loop { + self.state = VarState::DontWarn; + return; + } + } else if !self.past_loop && is_loop(expr) { + self.state = VarState::DontWarn; + return; + } else if is_conditional(expr) { + self.depth += 1; + walk_expr(self, expr); + self.depth -= 1; + return; + } + walk_expr(self, expr); + } +} + +fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { + if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { + if let Def::Local(_, node_id) = path_res.base_def { + return Some(node_id); + } + } + None +} + +fn is_loop(expr: &Expr) -> bool { + match expr.node { + ExprLoop(..) | ExprWhile(..) => true, + _ => false, + } +} + +fn is_conditional(expr: &Expr) -> bool { + match expr.node { + ExprIf(..) | ExprMatch(..) => true, + _ => false, + } +} diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs new file mode 100644 index 00000000000..4ad232759cf --- /dev/null +++ b/clippy_lints/src/map_clone.rs @@ -0,0 +1,128 @@ +use rustc::lint::*; +use rustc::hir::*; +use syntax::ast; +use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet, + span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; + +/// **What it does:** This lint checks for mapping clone() over an iterator. +/// +/// **Why is this bad?** It makes the code less readable. +/// +/// **Known problems:** None +/// +/// **Example:** `x.map(|e| e.clone());` +declare_lint! { + pub MAP_CLONE, Warn, + "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ + `.cloned()` instead)" +} + +#[derive(Copy, Clone)] +pub struct MapClonePass; + +impl LateLintPass for MapClonePass { + fn check_expr(&mut self, cx: &LateContext, expr: &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 blk, _) => { + if_let_chain! { + [ + // just one expression in the closure + blk.stmts.is_empty(), + let Some(ref closure_expr) = blk.expr, + // nothing special in the argument, besides reference bindings + // (e.g. .map(|&x| x) ) + let Some(arg_ident) = get_arg_name(&*decl.inputs[0].pat), + // the method is being called on a known type (option or iterator) + let Some(type_name) = get_type_name(cx, expr, &args[0]) + ], { + // look for derefs, for .map(|x| *x) + if only_derefs(cx, &*closure_expr, arg_ident) && + // .cloned() only removes one level of indirection, don't lint on more + walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + // explicit clone() calls ( .map(|x| x.clone()) ) + else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { + if clone_call.node.as_str() == "clone" && + clone_args.len() == 1 && + match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) && + expr_eq_name(&clone_args[0], arg_ident) + { + span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( + "you seem to be using .map() to clone the contents of an {}, consider \ + using `.cloned()`", type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + } + } + } + } + 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, + MAP_CLONE, + expr.span, + &format!("you seem to be using .map() to clone the contents of an \ + {}, consider using `.cloned()`", + type_name), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + } + } + _ => (), + } + } + } + } +} + +fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { + match expr.node { + ExprPath(None, ref path) => { + let arg_segment = [PathSegment { + name: id, + parameters: PathParameters::none(), + }]; + !path.global && path.segments[..] == arg_segment + } + _ => false, + } +} + +fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { + if match_trait_method(cx, expr, &paths::ITERATOR) { + Some("iterator") + } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &paths::OPTION) { + Some("Option") + } else { + None + } +} + +fn get_arg_name(pat: &Pat) -> Option<ast::Name> { + match pat.node { + PatKind::Ident(_, name, None) => Some(name.node), + PatKind::Ref(ref subpat, _) => get_arg_name(subpat), + _ => None, + } +} + +fn only_derefs(cx: &LateContext, expr: &Expr, id: ast::Name) -> bool { + match expr.node { + ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id), + _ => expr_eq_name(expr, id), + } +} + +impl LintPass for MapClonePass { + fn get_lints(&self) -> LintArray { + lint_array!(MAP_CLONE) + } +} diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs new file mode 100644 index 00000000000..db4ccf2dcdb --- /dev/null +++ b/clippy_lints/src/matches.rs @@ -0,0 +1,483 @@ +use rustc::hir::*; +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use rustc_const_math::ConstInt; +use std::cmp::Ordering; +use syntax::ast::LitKind; +use syntax::codemap::Span; +use utils::paths; +use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; + +/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. +/// +/// **Why is this bad?** Just readability – `if let` nests less than a `match`. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// match x { +/// Some(ref foo) -> bar(foo), +/// _ => () +/// } +/// ``` +declare_lint! { + pub SINGLE_MATCH, Warn, + "a match statement with a single nontrivial arm (i.e, where the other arm \ + is `_ => {}`) is used; recommends `if let` instead" +} + +/// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. +/// +/// **Why is this bad?** Just readability – `if let` nests less than a `match`. +/// +/// **Known problems:** Personal style preferences may differ +/// +/// **Example:** +/// ``` +/// match x { +/// Some(ref foo) -> bar(foo), +/// _ => bar(other_ref), +/// } +/// ``` +declare_lint! { + pub SINGLE_MATCH_ELSE, Allow, + "a match statement with a two arms where the second arm's pattern is a wildcard; \ + recommends `if let` instead" +} + +/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. +/// +/// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// match x { +/// &A(ref y) => foo(y), +/// &B => bar(), +/// _ => frob(&x), +/// } +/// ``` +declare_lint! { + pub MATCH_REF_PATS, Warn, + "a match or `if let` has all arms prefixed with `&`; the match expression can be \ + dereferenced instead" +} + +/// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. +/// +/// **Why is this bad?** It makes the code less readable. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let condition: bool = true; +/// match condition { +/// true => foo(), +/// false => bar(), +/// } +/// ``` +declare_lint! { + pub MATCH_BOOL, Warn, + "a match on boolean expression; recommends `if..else` block instead" +} + +/// **What it does:** This lint checks for overlapping match arms. +/// +/// **Why is this bad?** It is likely to be an error and if not, makes the code less obvious. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let x = 5; +/// match x { +/// 1 ... 10 => println!("1 ... 10"), +/// 5 ... 15 => println!("5 ... 15"), +/// _ => (), +/// } +/// ``` +declare_lint! { + pub MATCH_OVERLAPPING_ARM, Warn, "a match has overlapping arms" +} + +#[allow(missing_copy_implementations)] +pub struct MatchPass; + +impl LintPass for MatchPass { + fn get_lints(&self) -> LintArray { + lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE) + } +} + +impl LateLintPass for MatchPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_external_macro(cx, expr.span) { + return; + } + if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { + check_single_match(cx, ex, arms, expr); + check_match_bool(cx, ex, arms, expr); + check_overlapping_arms(cx, ex, arms); + } + if let ExprMatch(ref ex, ref arms, source) = expr.node { + check_match_ref_pats(cx, ex, arms, source, expr); + } + } +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { + if arms.len() == 2 && + arms[0].pats.len() == 1 && arms[0].guard.is_none() && + arms[1].pats.len() == 1 && arms[1].guard.is_none() { + let els = if is_unit_expr(&arms[1].body) { + None + } else if let ExprBlock(_) = arms[1].body.node { + // matches with blocks that contain statements are prettier as `if let + else` + Some(&*arms[1].body) + } else { + // allow match arms with just expressions + return; + }; + let ty = cx.tcx.expr_ty(ex); + if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { + check_single_match_single_pattern(cx, ex, arms, expr, els); + check_single_match_opt_like(cx, ex, arms, expr, ty, els); + } + } +} + +fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { + if arms[1].pats[0].node == PatKind::Wild { + let lint = if els.is_some() { + SINGLE_MATCH_ELSE + } else { + SINGLE_MATCH + }; + let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); + span_lint_and_then(cx, + lint, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. \ + Consider using `if let`", + |db| { + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); + } +} + +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"), + (&paths::COW, "Cow::Owned"), + (&paths::COW, "Owned"), + (&paths::OPTION, "None"), + (&paths::RESULT, "Err"), + (&paths::RESULT, "Ok")]; + + let path = match arms[1].pats[0].node { + PatKind::TupleStruct(ref path, Some(ref inner)) => { + // contains any non wildcard patterns? e.g. Err(err) + if inner.iter().any(|pat| pat.node != PatKind::Wild) { + return; + } + path.to_string() + } + PatKind::TupleStruct(ref path, None) => path.to_string(), + PatKind::Ident(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), + _ => return, + }; + + for &(ty_path, pat_path) in candidates { + if &path == pat_path && match_type(cx, ty, ty_path) { + let lint = if els.is_some() { + SINGLE_MATCH_ELSE + } else { + SINGLE_MATCH + }; + let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); + span_lint_and_then(cx, + lint, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. Consider \ + using `if let`", + |db| { + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); + } + } +} + +fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { + // type of expression == bool + if cx.tcx.expr_ty(ex).sty == ty::TyBool { + let sugg = if arms.len() == 2 && arms[0].pats.len() == 1 { + // no guards + let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pats[0].node { + if let ExprLit(ref lit) = arm_bool.node { + match lit.node { + LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), + LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), + _ => None, + } + } else { + None + } + } else { + None + }; + + if let Some((ref true_expr, ref false_expr)) = exprs { + match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => { + Some(format!("if {} {} else {}", + 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) => { + Some(format!("try\nif !{} {}", + snippet(cx, ex.span, "b"), + expr_block(cx, false_expr, None, ".."))) + } + (true, true) => None, + } + } else { + None + } + } else { + None + }; + + span_lint_and_then(cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression. Consider using an if..else block:", + move |db| { + if let Some(sugg) = sugg { + db.span_suggestion(expr.span, "try this", sugg); + } + }); + } +} + +fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { + if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() { + let ranges = all_ranges(cx, arms); + let type_ranges = type_ranges(&ranges); + if !type_ranges.is_empty() { + if let Some((start, end)) = overlapping(&type_ranges) { + span_note_and_lint(cx, + MATCH_OVERLAPPING_ARM, + start.span, + "some ranges overlap", + end.span, + "overlaps with this"); + } + } + } +} + +fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) { + if has_only_ref_pats(arms) { + if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { + let template = match_template(cx, expr.span, source, "", inner); + span_lint_and_then(cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to both the expression and the patterns", + |db| { + db.span_suggestion(expr.span, "try", template); + }); + } else { + let template = match_template(cx, expr.span, source, "*", ex); + span_lint_and_then(cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to all patterns", + |db| { + db.span_suggestion(expr.span, + "instead of prefixing all patterns with `&`, you can \ + dereference the expression", + template); + }); + } + } +} + +/// Get all arms that are unbounded `PatRange`s. +fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { + arms.iter() + .filter_map(|arm| { + if let Arm { ref pats, guard: None, .. } = *arm { + Some(pats.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) + ], { + return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); + }} + + 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 + })) + } else { + None + } + }) + .flat_map(IntoIterator::into_iter) + .collect() +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SpannedRange<T> { + pub span: Span, + pub node: (T, T), +} + +type TypedRanges = Vec<SpannedRange<ConstInt>>; + +/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than +/// `Uint` and `Int` probably don't make sense. +fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> 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() +} + +fn is_unit_expr(expr: &Expr) -> bool { + match expr.node { + ExprTup(ref v) if v.is_empty() => true, + ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true, + _ => false, + } +} + +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::<Option<Vec<bool>>>(); + // look for Some(v) where there's at least one true element + mapped.map_or(false, |v| v.iter().any(|el| *el)) +} + +fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, expr: &Expr) -> String { + let expr_snippet = snippet(cx, expr.span, ".."); + match source { + MatchSource::Normal => format!("match {}{} {{ .. }}", op, expr_snippet), + MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet), + MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet), + MatchSource::ForLoopDesugar => span_bug!(span, "for loop desugared to match with &-patterns!"), + MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!"), + } +} + +pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> + where T: Copy + Ord +{ + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + enum Kind<'a, T: 'a> { + Start(T, &'a SpannedRange<T>), + End(T, &'a SpannedRange<T>), + } + + impl<'a, T: Copy> Kind<'a, T> { + fn range(&self) -> &'a SpannedRange<T> { + match *self { + Kind::Start(_, r) | + Kind::End(_, r) => r, + } + } + + fn value(self) -> T { + match self { + Kind::Start(t, _) | + Kind::End(t, _) => t, + } + } + } + + impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } + } + + impl<'a, T: Copy + Ord> Ord for Kind<'a, T> { + fn cmp(&self, other: &Self) -> Ordering { + self.value().cmp(&other.value()) + } + } + + let mut values = Vec::with_capacity(2 * ranges.len()); + + for r in ranges { + values.push(Kind::Start(r.node.0, r)); + values.push(Kind::End(r.node.1, r)); + } + + values.sort(); + + for (a, b) in values.iter().zip(values.iter().skip(1)) { + match (a, b) { + (&Kind::Start(_, ra), &Kind::End(_, rb)) => { + if ra.node != rb.node { + return Some((ra, rb)); + } + } + (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), + _ => return Some((a.range(), b.range())), + } + } + + None +} diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs new file mode 100644 index 00000000000..1f627d614ff --- /dev/null +++ b/clippy_lints/src/mem_forget.rs @@ -0,0 +1,44 @@ +use rustc::lint::*; +use rustc::hir::{Expr, ExprCall, ExprPath}; +use utils::{match_def_path, paths, span_lint}; + +/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`. +/// +/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks +/// +/// **Known problems:** None. +/// +/// **Example:** `mem::forget(Rc::new(55)))` +declare_lint! { + pub MEM_FORGET, + Allow, + "`mem::forget` usage on `Drop` types is likely to cause memory leaks" +} + +pub struct MemForget; + +impl LintPass for MemForget { + fn get_lints(&self) -> LintArray { + lint_array![MEM_FORGET] + } +} + +impl LateLintPass for MemForget { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, ref args) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + if match_def_path(cx, def_id, &paths::MEM_FORGET) { + let forgot_ty = cx.tcx.expr_ty(&args[0]); + + if match forgot_ty.ty_adt_def() { + Some(def) => def.has_dtor(), + _ => false + } { + span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); + } + } + } + } + } +} diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs new file mode 100644 index 00000000000..f9f557e7a9a --- /dev/null +++ b/clippy_lints/src/methods.rs @@ -0,0 +1,1049 @@ +use rustc::hir; +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc::middle::const_qualif::ConstQualif; +use rustc::ty::subst::{Subst, TypeSpace}; +use rustc::ty; +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 syntax::ptr::P; +use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, + match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, + span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; +use utils::MethodArgs; +use utils::paths; + +#[derive(Clone)] +pub struct MethodsPass; + +/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. +/// +/// **Why is this bad?** Usually it is better to handle the `None` case, or to at least call `.expect(_)` with a more helpful message. Still, for a lot of quick-and-dirty code, `unwrap` is a good choice, which is why this lint is `Allow` by default. +/// +/// **Known problems:** None +/// +/// **Example:** `x.unwrap()` +declare_lint! { + pub OPTION_UNWRAP_USED, Allow, + "using `Option.unwrap()`, which should at least get a better message using `expect()`" +} + +/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. +/// +/// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`. +/// +/// Even if you want to panic on errors, not all `Error`s implement good messages on display. Therefore it may be beneficial to look at the places where they may get displayed. Activate this lint to do just that. +/// +/// **Known problems:** None +/// +/// **Example:** `x.unwrap()` +declare_lint! { + pub RESULT_UNWRAP_USED, Allow, + "using `Result.unwrap()`, which might be better handled" +} + +/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. +/// +/// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. +/// +/// **Known problems:** None +/// +/// **Example:** +/// ``` +/// struct X; +/// impl X { +/// fn add(&self, other: &X) -> X { .. } +/// } +/// ``` +declare_lint! { + pub SHOULD_IMPLEMENT_TRAIT, Warn, + "defining a method that should be implementing a std trait" +} + +/// **What it does:** This lint checks for methods with certain name prefixes and which doesn't match how self is taken. The actual rules are: +/// +/// |Prefix |`self` taken | +/// |-------|--------------------| +/// |`as_` |`&self` or &mut self| +/// |`from_`| none | +/// |`into_`|`self` | +/// |`is_` |`&self` or none | +/// |`to_` |`&self` | +/// +/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_..` function. +/// +/// **Known problems:** None +/// +/// **Example** +/// +/// ``` +/// impl X { +/// fn as_str(self) -> &str { .. } +/// } +/// ``` +declare_lint! { + pub WRONG_SELF_CONVENTION, Warn, + "defining a method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention" +} + +/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. +/// +/// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). +/// +/// **Known problems:** Actually *renaming* the function may break clients if the function is part of the public interface. In that case, be mindful of the stability guarantees you've given your users. +/// +/// **Example:** +/// ``` +/// impl X { +/// pub fn as_str(self) -> &str { .. } +/// } +/// ``` +declare_lint! { + pub WRONG_PUB_SELF_CONVENTION, Allow, + "defining a public method named with an established prefix (like \"into_\") that takes \ + `self` with the wrong convention" +} + +/// **What it does:** This lint checks for usage of `ok().expect(..)`. +/// +/// **Why is this bad?** Because you usually call `expect()` on the `Result` directly to get a good error message. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.ok().expect("why did I do this again?")` +declare_lint! { + pub OK_EXPECT, Warn, + "using `ok().expect()`, which gives worse error messages than \ + calling `expect` directly on the Result" +} + +/// **What it does:** This lint checks for usage of `_.map(_).unwrap_or(_)`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or(_, _)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.map(|a| a + 1).unwrap_or(0)` +declare_lint! { + pub OPTION_MAP_UNWRAP_OR, Warn, + "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ + `map_or(a, f)`" +} + +/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or_else(_, _)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)` +declare_lint! { + pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, + "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ + `map_or_else(g, f)`" +} + +/// **What it does:** This lint `Warn`s on `_.filter(_).next()`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.find(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `iter.filter(|x| x == 0).next()` +declare_lint! { + pub FILTER_NEXT, Warn, + "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`" +} + +/// **What it does:** This lint `Warn`s on an iterator search (such as `find()`, `position()`, or +/// `rposition()`) followed by a call to `is_some()`. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.any(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `iter.find(|x| x == 0).is_some()` +declare_lint! { + pub SEARCH_IS_SOME, Warn, + "using an iterator search followed by `is_some()`, which is more succinctly \ + expressed as a call to `any()`" +} + +/// **What it does:** This lint `Warn`s on using `.chars().next()` on a `str` to check if it +/// starts with a given char. +/// +/// **Why is this bad?** Readability, this can be written more concisely as `_.starts_with(_)`. +/// +/// **Known problems:** None. +/// +/// **Example:** `name.chars().next() == Some('_')` +declare_lint! { + pub CHARS_NEXT_CMP, Warn, + "using `.chars().next()` to check if a string starts with a char" +} + +/// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and +/// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead. +/// +/// **Why is this bad?** The function will always be called and potentially allocate an object +/// in expressions such as: +/// ```rust +/// foo.unwrap_or(String::new()) +/// ``` +/// this can instead be written: +/// ```rust +/// foo.unwrap_or_else(String::new) +/// ``` +/// or +/// ```rust +/// foo.unwrap_or_default() +/// ``` +/// +/// **Known problems:** If the function as side-effects, not calling it will change the semantic of +/// the program, but you shouldn't rely on that anyway. +declare_lint! { + pub OR_FUN_CALL, Warn, + "using any `*or` method when the `*or_else` would do" +} + +/// **What it does:** This lint checks for usage of `.extend(s)` on a `Vec` to extend the vector by a slice. +/// +/// **Why is this bad?** Since Rust 1.6, the `extend_from_slice(_)` method is stable and at least for now faster. +/// +/// **Known problems:** None. +/// +/// **Example:** `my_vec.extend(&xs)` +declare_lint! { + pub EXTEND_FROM_SLICE, Warn, + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice" +} + +/// **What it does:** This lint warns on using `.clone()` on a `Copy` type. +/// +/// **Why is this bad?** The only reason `Copy` types implement `Clone` is for generics, not for +/// using the `clone` method on a concrete type. +/// +/// **Known problems:** None. +/// +/// **Example:** `42u64.clone()` +declare_lint! { + pub CLONE_ON_COPY, Warn, "using `clone` on a `Copy` type" +} + +/// **What it does:** This lint warns on using `.clone()` on an `&&T` +/// +/// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of cloning the underlying +/// `T` +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// fn main() { +/// let x = vec![1]; +/// let y = &&x; +/// let z = y.clone(); +/// println!("{:p} {:p}",*y, z); // prints out the same pointer +/// } +/// ``` +declare_lint! { + pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`" +} + +/// **What it does:** This lint warns about `new` not returning `Self`. +/// +/// **Why is this bad?** As a convention, `new` methods are used to make a new instance of a type. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// impl Foo { +/// fn new(..) -> NotAFoo { +/// } +/// } +/// ``` +declare_lint! { + pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method" +} + +/// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")`. +/// +/// **Why is this bad?** Performing these methods using a `char` is faster than using a `str`. +/// +/// **Known problems:** Does not catch multi-byte unicode characters. +/// +/// **Example:** `_.split("x")` could be `_.split('x')` +declare_lint! { + pub SINGLE_CHAR_PATTERN, + Warn, + "using a single-character str where a char could be used, e.g. \ + `_.split(\"x\")`" +} + +/// **What it does:** This lint checks for getting the inner pointer of a temporary `CString`. +/// +/// **Why is this bad?** The inner pointer of a `CString` is only valid as long as the `CString` is +/// alive. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// let c_str = CString::new("foo").unwrap().as_ptr(); +/// unsafe { +/// call_some_ffi_func(c_str); +/// } +/// ``` +/// Here `c_str` point to a freed address. The correct use would be: +/// ```rust,ignore +/// let c_str = CString::new("foo").unwrap(); +/// unsafe { +/// call_some_ffi_func(c_str.as_ptr()); +/// } +/// ``` +declare_lint! { + pub TEMPORARY_CSTRING_AS_PTR, + Warn, + "getting the inner pointer of a temporary `CString`" +} + +impl LintPass for MethodsPass { + fn get_lints(&self) -> LintArray { + lint_array!(EXTEND_FROM_SLICE, + OPTION_UNWRAP_USED, + RESULT_UNWRAP_USED, + SHOULD_IMPLEMENT_TRAIT, + WRONG_SELF_CONVENTION, + WRONG_PUB_SELF_CONVENTION, + OK_EXPECT, + OPTION_MAP_UNWRAP_OR, + OPTION_MAP_UNWRAP_OR_ELSE, + OR_FUN_CALL, + CHARS_NEXT_CMP, + CLONE_ON_COPY, + CLONE_DOUBLE_REF, + NEW_RET_NO_SELF, + SINGLE_CHAR_PATTERN, + SEARCH_IS_SOME, + TEMPORARY_CSTRING_AS_PTR) + } +} + +impl LateLintPass for MethodsPass { + fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { + if in_macro(cx, expr.span) { + return; + } + + match expr.node { + hir::ExprMethodCall(name, _, ref args) => { + // Chain calls + if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + lint_unwrap(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { + lint_ok_expect(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { + lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { + lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { + lint_filter_next(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { + lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { + lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { + lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); + } else if let Some(arglists) = method_chain_args(expr, &["extend"]) { + lint_extend(cx, expr, arglists[0]); + } else if let Some(arglists) = method_chain_args(expr, &["unwrap", "as_ptr"]) { + lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]); + } + + lint_or_fun_call(cx, expr, &name.node.as_str(), args); + + let self_ty = cx.tcx.expr_ty_adjusted(&args[0]); + if args.len() == 1 && name.node.as_str() == "clone" { + lint_clone_on_copy(cx, expr); + lint_clone_double_ref(cx, expr, &args[0], self_ty); + } + + match self_ty.sty { + ty::TyRef(_, ty) if ty.ty.sty == ty::TyStr => { + for &(method, pos) in &PATTERN_METHODS { + if name.node.as_str() == method && args.len() > pos { + 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_item(&mut self, cx: &LateContext, item: &hir::Item) { + if in_external_macro(cx, item.span) { + return; + } + + if let hir::ItemImpl(_, _, _, None, _, ref items) = item.node { + for implitem in items { + let name = implitem.name; + if_let_chain! {[ + let hir::ImplItemKind::Method(ref sig, _) = implitem.node, + let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), + ], { + // check missing trait implementations + for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { + if name.as_str() == method_name && + sig.decl.inputs.len() == n_args && + out_type.matches(&sig.decl.output) && + self_kind.matches(&explicit_self, false) { + span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( + "defining a method called `{}` on this type; consider implementing \ + the `{}` trait or choosing a less ambiguous name", name, trait_name)); + } + } + + // check conventions w.r.t. conversion method names and predicates + let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; + let is_copy = is_copy(cx, ty, item); + for &(ref conv, self_kinds) in &CONVENTIONS { + if_let_chain! {[ + conv.check(&name.as_str()), + let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), + !self_kinds.iter().any(|k| k.matches(&explicit_self, is_copy)), + ], { + let lint = if item.vis == hir::Visibility::Public { + WRONG_PUB_SELF_CONVENTION + } else { + WRONG_SELF_CONVENTION + }; + span_lint(cx, + lint, + explicit_self.span, + &format!("methods called `{}` usually take {}; consider choosing a less \ + ambiguous name", + conv, + &self_kinds.iter() + .map(|k| k.description()) + .collect::<Vec<_>>() + .join(" or "))); + }} + } + + let ret_ty = return_ty(cx, implitem.id); + if &name.as_str() == &"new" && + !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { + span_lint(cx, + NEW_RET_NO_SELF, + explicit_self.span, + "methods called `new` usually return `Self`"); + } + } + }} + } + } +} + +/// Checks for the `OR_FUN_CALL` lint. +fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[P<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 { + 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 ["default", "new"].contains(&path) { + let arg_ty = cx.tcx.expr_ty(arg); + let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { + default_trait_id + } else { + return false; + }; + + if implements_trait(cx, arg_ty, default_trait_id, Vec::new()) { + span_lint(cx, + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a call to `{}`", name, path)) + .span_suggestion(span, + "try this", + format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); + return true; + } + } + } + } + + false + } + + /// 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) { + // 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) { + if !qualif.contains(ConstQualif::NOT_CONST) { + return; + } + } + // (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 self_ty = cx.tcx.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)) { + (fn_has_arguments, poss, suffix) + } else { + return; + }; + + if !poss.contains(&name) { + return; + } + + let sugg: Cow<_> = match (fn_has_arguments, !or_has_args) { + (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(), + (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(), + (false, true) => snippet(cx, fun.span, ".."), + }; + + span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name)) + .span_suggestion(span, + "try this", + format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); + } + + if args.len() == 2 { + if let hir::ExprCall(ref fun, ref or_args) = args[1].node { + let or_has_args = !or_args.is_empty(); + if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { + check_general_case(cx, name, fun, &args[0], &args[1], or_has_args, expr.span); + } + } + } +} + +/// Checks for the `CLONE_ON_COPY` lint. +fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr) { + let ty = cx.tcx.expr_ty(expr); + let parent = cx.tcx.map.get_parent(expr.id); + let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); + + if !ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, expr.span) { + span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); + } +} + +/// Checks for the `CLONE_DOUBLE_REF` lint. +fn lint_clone_double_ref(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, ty: ty::Ty) { + if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { + if let ty::TyRef(..) = inner.sty { + let mut db = span_lint(cx, + CLONE_DOUBLE_REF, + expr.span, + "using `clone` on a double-reference; \ + this will copy the reference instead of cloning \ + the inner type"); + if let Some(snip) = snippet_opt(cx, arg.span) { + db.span_suggestion(expr.span, "try dereferencing it", format!("(*{}).clone()", snip)); + } + } + } +} + +fn lint_extend(cx: &LateContext, expr: &hir::Expr, args: &MethodArgs) { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); + if !match_type(cx, obj_ty, &paths::VEC) { + return; + } + let arg_ty = cx.tcx.expr_ty(&args[1]); + if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { + span_lint(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice") + .span_suggestion(expr.span, + "try this", + format!("{}.extend_from_slice({}{})", + snippet(cx, args[0].span, "_"), + r, + snippet(cx, span, "_"))); + } +} + +fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) { + 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), + ], { + span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, + "you are getting the inner pointer of a temporary `CString`", + |db| { + db.note("that pointer will be invalid outside this expression"); + db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime"); + }); + }} +} + +fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { + fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { + match ty.sty { + ty::TySlice(_) => true, + ty::TyStruct(..) => match_type(cx, ty, &paths::VEC), + ty::TyArray(_, size) => size < 32, + ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | + ty::TyBox(ref inner) => may_slice(cx, inner), + _ => false, + } + } + if let hir::ExprMethodCall(name, _, ref args) = expr.node { + if &name.node.as_str() == &"iter" && may_slice(cx, &cx.tcx.expr_ty(&args[0])) { + Some((args[0].span, "&")) + } else { + None + } + } else { + match ty.sty { + ty::TySlice(_) => Some((expr.span, "")), + ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | + ty::TyBox(ref inner) => { + if may_slice(cx, inner) { + Some((expr.span, "")) + } else { + None + } + } + _ => None, + } + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint use of `unwrap()` for `Option`s and `Result`s +fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &MethodArgs) { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); + + let mess = if match_type(cx, obj_ty, &paths::OPTION) { + Some((OPTION_UNWRAP_USED, "an Option", "None")) + } else if match_type(cx, obj_ty, &paths::RESULT) { + Some((RESULT_UNWRAP_USED, "a Result", "Err")) + } else { + None + }; + + if let Some((lint, kind, none_value)) = mess { + span_lint(cx, + lint, + expr.span, + &format!("used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ + using expect() to provide a better panic + message", + kind, + none_value)); + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint use of `ok().expect()` for `Result`s +fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &MethodArgs) { + // lint if the caller of `ok()` is a `Result` + if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &paths::RESULT) { + let result_type = cx.tcx.expr_ty(&ok_args[0]); + if let Some(error_type) = get_error_type(cx, result_type) { + if has_debug_impl(error_type, cx) { + span_lint(cx, + OK_EXPECT, + expr.span, + "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`"); + } + } + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint use of `map().unwrap_or()` for `Option`s +fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { + // lint if the caller of `map()` is an `Option` + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { + // lint message + let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling \ + `map_or(a, f)` instead"; + // get snippets for args to map() and unwrap_or() + let map_snippet = snippet(cx, map_args[1].span, ".."); + let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or() have the same span + let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; + let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint(cx, + OPTION_MAP_UNWRAP_OR, + expr.span, + msg, + expr.span, + &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", + map_snippet, + unwrap_snippet)); + } else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); + }; + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint use of `map().unwrap_or_else()` for `Option`s +fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { + // lint if the caller of `map()` is an `Option` + if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { + // lint message + let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ + `map_or_else(g, f)` instead"; + // get snippets for args to map() and unwrap_or_else() + let map_snippet = snippet(cx, map_args[1].span, ".."); + let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); + // lint, with note if neither arg is > 1 line and both map() and + // unwrap_or_else() have the same span + let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; + let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; + if same_span && !multiline { + span_note_and_lint(cx, + OPTION_MAP_UNWRAP_OR_ELSE, + expr.span, + msg, + expr.span, + &format!("replace `map({0}).unwrap_or_else({1})` with `with map_or_else({1}, {0})`", + map_snippet, + unwrap_snippet)); + } else if same_span && multiline { + span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); + }; + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint use of `filter().next() for Iterators` +fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &MethodArgs) { + // 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 filter_snippet = snippet(cx, filter_args[1].span, ".."); + if filter_snippet.lines().count() <= 1 { + // add note if not multi-line + span_note_and_lint(cx, + FILTER_NEXT, + expr.span, + msg, + expr.span, + &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); + } else { + span_lint(cx, FILTER_NEXT, expr.span, msg); + } + } +} + +#[allow(ptr_arg)] +// Type of MethodArgs is potentially a Vec +/// lint searching an Iterator followed by `is_some()` +fn lint_search_is_some(cx: &LateContext, expr: &hir::Expr, search_method: &str, search_args: &MethodArgs, + is_some_args: &MethodArgs) { + // 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()`.", + search_method); + let search_snippet = snippet(cx, search_args[1].span, ".."); + if search_snippet.lines().count() <= 1 { + // add note if not multi-line + span_note_and_lint(cx, + SEARCH_IS_SOME, + expr.span, + &msg, + expr.span, + &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet)); + } else { + span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + } + } +} + +/// Checks for the `CHARS_NEXT_CMP` lint. +fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other: &hir::Expr, eq: bool) -> bool { + if_let_chain! {[ + 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 self_ty = walk_ptrs_ty(cx.tcx.expr_ty_adjusted(&args[0][0])); + + if self_ty.sty != ty::TyStr { + return false; + } + + span_lint_and_then(cx, + CHARS_NEXT_CMP, + expr.span, + "you should use the `starts_with` method", + |db| { + let sugg = format!("{}{}.starts_with({})", + if eq { "" } else { "!" }, + snippet(cx, args[0][0].span, "_"), + snippet(cx, arg_char[0].span, "_") + ); + + db.span_suggestion(expr.span, "like this", sugg); + }); + + return true; + }} + + false +} + +/// lint for length-1 `str`s for methods in `PATTERN_METHODS` +fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { + if let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, arg, ExprTypeChecked, None) { + if r.len() == 1 { + let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); + span_lint_and_then(cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + |db| { + db.span_suggestion(expr.span, "try using a char instead:", hint); + }); + } + } +} + +/// Given a `Result<T, E>` type, return its error type (`E`). +fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { + if !match_type(cx, ty, &paths::RESULT) { + return None; + } + if let ty::TyEnum(_, substs) = ty.sty { + if let Some(err_ty) = substs.types.opt_get(TypeSpace, 1) { + return Some(err_ty); + } + } + None +} + +/// This checks whether a given type is known to implement Debug. +fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { + match cx.tcx.lang_items.debug_trait() { + Some(debug) => implements_trait(cx, ty, debug, Vec::new()), + None => false, + } +} + +enum Convention { + Eq(&'static str), + StartsWith(&'static str), +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +const CONVENTIONS: [(Convention, &'static [SelfKind]); 6] = [ + (Convention::Eq("new"), &[SelfKind::No]), + (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), + (Convention::StartsWith("from_"), &[SelfKind::No]), + (Convention::StartsWith("into_"), &[SelfKind::Value]), + (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), + (Convention::StartsWith("to_"), &[SelfKind::Ref]), +]; + +#[cfg_attr(rustfmt, rustfmt_skip)] +const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ + ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"), + ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), + ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), + ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), + ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"), + ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"), + ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), + ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), + ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"), + ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), + ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"), + ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), + ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), + ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"), + ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), + ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), + ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"), + ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"), + ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), + ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"), + ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), + ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), + ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"), + ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"), + ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), + ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"), + ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"), + ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"), + ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"), + ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), +]; + +#[cfg_attr(rustfmt, rustfmt_skip)] +const PATTERN_METHODS: [(&'static str, usize); 17] = [ + ("contains", 1), + ("starts_with", 1), + ("ends_with", 1), + ("find", 1), + ("rfind", 1), + ("split", 1), + ("rsplit", 1), + ("split_terminator", 1), + ("rsplit_terminator", 1), + ("splitn", 2), + ("rsplitn", 2), + ("matches", 1), + ("rmatches", 1), + ("match_indices", 1), + ("rmatch_indices", 1), + ("trim_left_matches", 1), + ("trim_right_matches", 1), +]; + + +#[derive(Clone, Copy)] +enum SelfKind { + Value, + Ref, + RefMut, + No, +} + +impl SelfKind { + fn matches(self, slf: &hir::ExplicitSelf, allow_value_for_ref: bool) -> bool { + match (self, &slf.node) { + (SelfKind::Value, &hir::SelfKind::Value(_)) | + (SelfKind::Ref, &hir::SelfKind::Region(_, hir::Mutability::MutImmutable)) | + (SelfKind::RefMut, &hir::SelfKind::Region(_, hir::Mutability::MutMutable)) => true, + (SelfKind::Ref, &hir::SelfKind::Value(_)) | + (SelfKind::RefMut, &hir::SelfKind::Value(_)) => allow_value_for_ref, + (_, &hir::SelfKind::Explicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), + + _ => false, + } + } + + fn matches_explicit_type(self, ty: &hir::Ty, allow_value_for_ref: bool) -> bool { + match (self, &ty.node) { + (SelfKind::Value, &hir::TyPath(..)) | + (SelfKind::Ref, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutImmutable, .. })) | + (SelfKind::RefMut, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutMutable, .. })) => true, + (SelfKind::Ref, &hir::TyPath(..)) | + (SelfKind::RefMut, &hir::TyPath(..)) => allow_value_for_ref, + _ => false, + } + } + + fn description(&self) -> &'static str { + match *self { + SelfKind::Value => "self by value", + SelfKind::Ref => "self by reference", + SelfKind::RefMut => "self by mutable reference", + SelfKind::No => "no self", + } + } +} + +impl Convention { + fn check(&self, other: &str) -> bool { + match *self { + Convention::Eq(this) => this == other, + Convention::StartsWith(this) => other.starts_with(this), + } + } +} + +impl fmt::Display for Convention { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Convention::Eq(this) => this.fmt(f), + Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), + } + } +} + +#[derive(Clone, Copy)] +enum OutType { + Unit, + Bool, + Any, + Ref, +} + +impl OutType { + fn matches(&self, ty: &hir::FunctionRetTy) -> bool { + match (self, ty) { + (&OutType::Unit, &hir::DefaultReturn(_)) => true, + (&OutType::Unit, &hir::Return(ref ty)) if ty.node == hir::TyTup(vec![].into()) => true, + (&OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true, + (&OutType::Any, &hir::Return(ref ty)) if ty.node != hir::TyTup(vec![].into()) => true, + (&OutType::Ref, &hir::Return(ref ty)) => { + if let hir::TyRptr(_, _) = ty.node { + true + } else { + false + } + } + _ => false, + } + } +} + +fn is_bool(ty: &hir::Ty) -> bool { + if let hir::TyPath(None, ref p) = ty.node { + if match_path(p, &["bool"]) { + return true; + } + } + false +} + +fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &hir::Item) -> bool { + let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); + !ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, item.span) +} diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs new file mode 100644 index 00000000000..eaba19b08e4 --- /dev/null +++ b/clippy_lints/src/minmax.rs @@ -0,0 +1,93 @@ +use consts::{Constant, constant_simple}; +use rustc::lint::*; +use rustc::hir::*; +use std::cmp::{PartialOrd, Ordering}; +use syntax::ptr::P; +use utils::{match_def_path, paths, span_lint}; + +/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. +/// +/// **Why is this bad?** This is in all probability not the intended outcome. At the least it hurts readability of the code. +/// +/// **Known problems:** None +/// +/// **Example:** `min(0, max(100, x))` will always be equal to `0`. Probably the author meant to clamp the value between 0 and 100, but has erroneously swapped `min` and `max`. +declare_lint! { + pub MIN_MAX, Warn, + "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant" +} + +#[allow(missing_copy_implementations)] +pub struct MinMaxPass; + +impl LintPass for MinMaxPass { + fn get_lints(&self) -> LintArray { + lint_array!(MIN_MAX) + } +} + +impl LateLintPass for MinMaxPass { + fn check_expr(&mut self, cx: &LateContext, expr: &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 { + return; + } + match (outer_max, outer_c.partial_cmp(&inner_c)) { + (_, None) | + (MinMax::Max, Some(Ordering::Less)) | + (MinMax::Min, Some(Ordering::Greater)) => (), + _ => { + span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); + } + } + } + } + } +} + +#[derive(PartialEq, Eq, Debug)] +enum MinMax { + Min, + Max, +} + +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.def_map.borrow()[&path.id].def_id(); + + if match_def_path(cx, def_id, &paths::CMP_MIN) { + fetch_const(args, MinMax::Min) + } else if match_def_path(cx, def_id, &paths::CMP_MAX) { + fetch_const(args, MinMax::Max) + } else { + None + } + } else { + None + } + } else { + None + } +} + +fn fetch_const(args: &[P<Expr>], m: MinMax) -> Option<(MinMax, Constant, &Expr)> { + if args.len() != 2 { + return None; + } + if let Some(c) = constant_simple(&args[0]) { + if let None = constant_simple(&args[1]) { + // otherwise ignore + Some((m, c, &args[1])) + } else { + None + } + } else { + if let Some(c) = constant_simple(&args[1]) { + Some((m, c, &args[0])) + } else { + None + } + } +} diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs new file mode 100644 index 00000000000..3ab7823e50d --- /dev/null +++ b/clippy_lints/src/misc.rs @@ -0,0 +1,458 @@ +use reexport::*; +use rustc::hir::*; +use rustc::hir::intravisit::FnKind; +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc::ty; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use syntax::codemap::{Span, Spanned, ExpnFormat}; +use syntax::ptr::P; +use utils::{ + get_item_name, get_parent_expr, implements_trait, is_integer_literal, match_path, snippet, + span_lint, span_lint_and_then, walk_ptrs_ty +}; + +/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. +/// +/// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body. +/// +/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The type of `x` is more obvious with the former. +/// +/// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function. +/// +/// **Example:** `fn foo(ref x: u8) -> bool { .. }` +declare_lint! { + pub TOPLEVEL_REF_ARG, Warn, + "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ + or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ + references with `&`." +} + +#[allow(missing_copy_implementations)] +pub struct TopLevelRefPass; + +impl LintPass for TopLevelRefPass { + fn get_lints(&self) -> LintArray { + lint_array!(TOPLEVEL_REF_ARG) + } +} + +impl LateLintPass for TopLevelRefPass { + fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + if let FnKind::Closure(_) = k { + // Does not apply to closures + return; + } + for ref arg in &decl.inputs { + if let PatKind::Ident(BindByRef(_), _, _) = arg.pat.node { + span_lint(cx, + TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. Consider using a reference type instead."); + } + } + } + fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) { + if_let_chain! { + [ + let StmtDecl(ref d, _) = s.node, + let DeclLocal(ref l) = d.node, + let PatKind::Ident(BindByRef(_), i, None) = l.pat.node, + let Some(ref init) = l.init + ], { + let tyopt = if let Some(ref ty) = l.ty { + format!(": {}", snippet(cx, ty.span, "_")) + } else { + "".to_owned() + }; + span_lint_and_then(cx, + TOPLEVEL_REF_ARG, + l.pat.span, + "`ref` on an entire `let` pattern is discouraged, take a reference with & instead", + |db| { + db.span_suggestion(s.span, + "try", + format!("let {}{} = &{};", + snippet(cx, i.span, "_"), + tyopt, + snippet(cx, init.span, "_"))); + } + ); + } + }; + } +} + +/// **What it does:** This lint checks for comparisons to NAN. +/// +/// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong. +/// +/// **Known problems:** None +/// +/// **Example:** `x == NAN` +declare_lint!(pub CMP_NAN, Deny, + "comparisons to NAN (which will always return false, which is probably not intended)"); + +#[derive(Copy,Clone)] +pub struct CmpNan; + +impl LintPass for CmpNan { + fn get_lints(&self) -> LintArray { + lint_array!(CMP_NAN) + } +} + +impl LateLintPass for CmpNan { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if cmp.node.is_comparison() { + if let ExprPath(_, ref path) = left.node { + check_nan(cx, path, expr.span); + } + if let ExprPath(_, ref path) = right.node { + check_nan(cx, path, expr.span); + } + } + } + } +} + +fn check_nan(cx: &LateContext, path: &Path, span: Span) { + path.segments.last().map(|seg| { + if seg.name.as_str() == "NAN" { + span_lint(cx, + CMP_NAN, + span, + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); + } + }); +} + +/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats). +/// +/// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison). +/// +/// **Known problems:** None +/// +/// **Example:** `y == 1.23f64` +declare_lint!(pub FLOAT_CMP, Warn, + "using `==` or `!=` on float values (as floating-point operations \ + usually involve rounding errors, it is always better to check for approximate \ + equality within small bounds)"); + +#[derive(Copy,Clone)] +pub struct FloatCmp; + +impl LintPass for FloatCmp { + fn get_lints(&self) -> LintArray { + lint_array!(FLOAT_CMP) + } +} + +impl LateLintPass for FloatCmp { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + let op = cmp.node; + if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { + if is_allowed(cx, left) || is_allowed(cx, right) { + return; + } + 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") { + return; + } + } + span_lint(cx, + FLOAT_CMP, + expr.span, + &format!("{}-comparison of f32 or f64 detected. Consider changing this to `({} - {}).abs() < \ + epsilon` for some suitable value of epsilon. \ + std::f32::EPSILON and std::f64::EPSILON are available.", + op.as_str(), + snippet(cx, left.span, ".."), + snippet(cx, right.span, ".."))); + } + } + } +} + +fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { + let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None); + if let Ok(ConstVal::Float(val)) = res { + val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY + } else { + false + } +} + +fn is_float(cx: &LateContext, expr: &Expr) -> bool { + if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { + true + } else { + false + } +} + +/// **What it does:** This lint checks for conversions to owned values just for the sake of a comparison. +/// +/// **Why is this bad?** The comparison can operate on a reference, so creating an owned value effectively throws it away directly afterwards, which is needlessly consuming code and heap space. +/// +/// **Known problems:** None +/// +/// **Example:** `x.to_owned() == y` +declare_lint!(pub CMP_OWNED, Warn, + "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"); + +#[derive(Copy,Clone)] +pub struct CmpOwned; + +impl LintPass for CmpOwned { + fn get_lints(&self) -> LintArray { + lint_array!(CMP_OWNED) + } +} + +impl LateLintPass for CmpOwned { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if cmp.node.is_comparison() { + check_to_owned(cx, left, right, true, cmp.span); + check_to_owned(cx, right, left, false, cmp.span) + } + } + } +} + +fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) { + let (arg_ty, snip) = match expr.node { + ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) if args.len() == 1 => { + if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { + (cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, "..")) + } else { + return; + } + } + ExprCall(ref path, ref v) if v.len() == 1 => { + if let ExprPath(None, ref path) = path.node { + if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { + (cx.tcx.expr_ty(&v[0]), snippet(cx, v[0].span, "..")) + } else { + return; + } + } else { + return; + } + } + _ => return, + }; + + let other_ty = cx.tcx.expr_ty(other); + let partial_eq_trait_id = match cx.tcx.lang_items.eq_trait() { + Some(id) => id, + None => return, + }; + + if !implements_trait(cx, arg_ty, partial_eq_trait_id, vec![other_ty]) { + return; + } + + if left { + span_lint(cx, + CMP_OWNED, + expr.span, + &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ + compare without allocation", + snip, + snippet(cx, op, "=="), + snippet(cx, other.span, ".."))); + } else { + span_lint(cx, + CMP_OWNED, + expr.span, + &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ + compare without allocation", + snippet(cx, other.span, ".."), + snippet(cx, op, "=="), + snip)); + } + +} + +fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { + args.len() == 1 && + if let ty::TyStr = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { + true + } else { + false + } +} + +/// **What it does:** This lint checks for getting the remainder of a division by one. +/// +/// **Why is this bad?** The result can only ever be zero. No one will write such code deliberately, unless trying to win an Underhanded Rust Contest. Even for that contest, it's probably a bad idea. Use something more underhanded. +/// +/// **Known problems:** None +/// +/// **Example:** `x % 1` +declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); + +#[derive(Copy,Clone)] +pub struct ModuloOne; + +impl LintPass for ModuloOne { + fn get_lints(&self) -> LintArray { + lint_array!(MODULO_ONE) + } +} + +impl LateLintPass for ModuloOne { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, _, ref right) = expr.node { + if let Spanned { node: BinOp_::BiRem, .. } = *cmp { + if is_integer_literal(right, 1) { + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } + } + } + } +} + +/// **What it does:** This lint checks for patterns in the form `name @ _`. +/// +/// **Why is this bad?** It's almost always more readable to just use direct bindings. +/// +/// **Known problems:** None +/// +/// **Example**: +/// ``` +/// match v { +/// Some(x) => (), +/// y @ _ => (), // easier written as `y`, +/// } +/// ``` +declare_lint!(pub REDUNDANT_PATTERN, Warn, "using `name @ _` in a pattern"); + +#[derive(Copy,Clone)] +pub struct PatternPass; + +impl LintPass for PatternPass { + fn get_lints(&self) -> LintArray { + lint_array!(REDUNDANT_PATTERN) + } +} + +impl LateLintPass for PatternPass { + fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { + if let PatKind::Ident(_, 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)); + } + } + } +} + + +/// **What it does:** This lint checks for the use of bindings with a single leading underscore +/// +/// **Why is this bad?** A single leading underscore is usually used to indicate that a binding +/// will not be used. Using such a binding breaks this expectation. +/// +/// **Known problems:** The lint does not work properly with desugaring and macro, it has been +/// allowed in the mean time. +/// +/// **Example**: +/// ``` +/// let _x = 0; +/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore. +/// // We should rename `_x` to `x` +/// ``` +declare_lint!(pub USED_UNDERSCORE_BINDING, Allow, + "using a binding which is prefixed with an underscore"); + +#[derive(Copy, Clone)] +pub struct UsedUnderscoreBinding; + +impl LintPass for UsedUnderscoreBinding { + fn get_lints(&self) -> LintArray { + lint_array!(USED_UNDERSCORE_BINDING) + } +} + +impl LateLintPass for UsedUnderscoreBinding { + #[cfg_attr(rustfmt, rustfmt_skip)] + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_attributes_expansion(cx, expr) { + // Don't lint things expanded by #[derive(...)], etc + return; + } + let binding = match expr.node { + ExprPath(_, ref path) => { + let segment = path.segments + .last() + .expect("path should always have at least one segment") + .name; + if segment.as_str().starts_with('_') && + !segment.as_str().starts_with("__") && + segment != segment.unhygienize() && // not in bang macro + is_used(cx, expr) { + Some(segment.as_str()) + } else { + None + } + } + ExprField(_, spanned) => { + let name = spanned.node.as_str(); + if name.starts_with('_') && !name.starts_with("__") { + Some(name) + } else { + None + } + } + _ => None, + }; + if let Some(binding) = binding { + if binding != "_result" { // FIXME: #944 + span_lint(cx, + 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)); + } + } + } +} + +/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea +/// of what it means for an expression to be "used". +fn is_used(cx: &LateContext, expr: &Expr) -> bool { + if let Some(ref parent) = get_parent_expr(cx, expr) { + match parent.node { + ExprAssign(_, ref rhs) | + ExprAssignOp(_, _, ref rhs) => **rhs == *expr, + _ => is_used(cx, parent), + } + } else { + true + } +} + +/// Test whether an expression is in a macro expansion (e.g. something generated by +/// `#[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| { + match info.callee.format { + ExpnFormat::MacroAttribute(_) => true, + _ => false, + } + }) + }) +} diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs new file mode 100644 index 00000000000..a7ab59497ac --- /dev/null +++ b/clippy_lints/src/misc_early.rs @@ -0,0 +1,166 @@ +use rustc::lint::*; +use std::collections::HashMap; +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::visit::FnKind; +use utils::{span_lint, span_help_and_lint, snippet, span_lint_and_then}; +/// **What it does:** This lint checks for structure field patterns bound to wildcards. +/// +/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. +/// +/// **Known problems:** None. +/// +/// **Example:** `let { a: _, b: ref b, c: _ } = ..` +declare_lint! { + pub UNNEEDED_FIELD_PATTERN, Warn, + "Struct fields are bound to a wildcard instead of using `..`" +} + +/// **What it does:** This lint checks for function arguments having the similar names differing by an underscore +/// +/// **Why is this bad?** It affects code readability +/// +/// **Known problems:** None. +/// +/// **Example:** `fn foo(a: i32, _a: i32) {}` +declare_lint! { + pub DUPLICATE_UNDERSCORE_ARGUMENT, Warn, + "Function arguments having names which only differ by an underscore" +} + +/// **What it does:** This lint detects closures called in the same expression where they are defined. +/// +/// **Why is this bad?** It is unnecessarily adding to the expression's complexity. +/// +/// **Known problems:** None. +/// +/// **Example:** `(|| 42)()` +declare_lint! { + pub REDUNDANT_CLOSURE_CALL, Warn, + "Closures should not be called in the expression they are defined" +} + +#[derive(Copy, Clone)] +pub struct MiscEarly; + +impl LintPass for MiscEarly { + fn get_lints(&self) -> LintArray { + lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL) + } +} + +impl EarlyLintPass for MiscEarly { + fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { + if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { + let mut wilds = 0; + let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name; + + for field in pfields { + if field.node.pat.node == PatKind::Wild { + wilds += 1; + } + } + if !pfields.is_empty() && wilds == pfields.len() { + span_help_and_lint(cx, + UNNEEDED_FIELD_PATTERN, + pat.span, + "All the struct fields are matched to a wildcard pattern, consider using `..`.", + &format!("Try with `{} {{ .. }}` instead", type_name)); + return; + } + if wilds > 0 { + let mut normal = vec![]; + + for field in pfields { + if field.node.pat.node != PatKind::Wild { + if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) { + normal.push(n); + } + } + } + for field in pfields { + if field.node.pat.node == PatKind::Wild { + wilds -= 1; + if wilds > 0 { + span_lint(cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` instead"); + } else { + span_help_and_lint(cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` \ + instead", + &format!("Try with `{} {{ {}, .. }}`", + type_name, + normal[..].join(", "))); + } + } + } + } + } + } + + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + let mut registered_names: HashMap<String, Span> = HashMap::new(); + + for ref arg in &decl.inputs { + if let PatKind::Ident(_, sp_ident, None) = arg.pat.node { + let arg_name = sp_ident.node.to_string(); + + if arg_name.starts_with('_') { + if let Some(correspondence) = registered_names.get(&arg_name[1..]) { + span_lint(cx, + DUPLICATE_UNDERSCORE_ARGUMENT, + *correspondence, + &format!("`{}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult", + arg_name[1..].to_owned()));; + } + } else { + registered_names.insert(arg_name, arg.pat.span); + } + } + } + } + + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + if let ExprKind::Call(ref paren, _) = expr.node { + if let ExprKind::Paren(ref closure) = paren.node { + if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node { + span_lint_and_then(cx, + REDUNDANT_CLOSURE_CALL, + expr.span, + "Try not to call a closure in the expression where it is declared.", + |db| { + if decl.inputs.is_empty() { + let hint = format!("{}", snippet(cx, block.span, "..")); + db.span_suggestion(expr.span, "Try doing something like: ", hint); + } + }); + } + } + } + } + + fn check_block(&mut self, cx: &EarlyContext, block: &Block) { + for w in block.stmts.windows(2) { + if_let_chain! {[ + let StmtKind::Decl(ref first, _) = w[0].node, + let DeclKind::Local(ref local) = first.node, + let Option::Some(ref t) = local.init, + let ExprKind::Closure(_,_,_,_) = t.node, + let PatKind::Ident(_,sp_ident,_) = local.pat.node, + let StmtKind::Semi(ref second,_) = w[1].node, + let ExprKind::Assign(_,ref call) = second.node, + let ExprKind::Call(ref closure,_) = call.node, + 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"); + } + }} + } + } +} diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs new file mode 100644 index 00000000000..4147e288c4f --- /dev/null +++ b/clippy_lints/src/mut_mut.rs @@ -0,0 +1,59 @@ +use rustc::lint::*; +use rustc::ty::{TypeAndMut, TyRef}; +use rustc::hir::*; +use utils::{in_external_macro, span_lint}; + +/// **What it does:** This lint checks for instances of `mut mut` references. +/// +/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = &mut &mut y;` +declare_lint! { + pub MUT_MUT, + Allow, + "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ + or shows a fundamental misunderstanding of references)" +} + +#[derive(Copy,Clone)] +pub struct MutMut; + +impl LintPass for MutMut { + fn get_lints(&self) -> LintArray { + lint_array!(MUT_MUT) + } +} + +impl LateLintPass for MutMut { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_external_macro(cx, expr.span) { + return; + } + + if let ExprAddrOf(MutMutable, ref e) = expr.node { + if let ExprAddrOf(MutMutable, _) = e.node { + span_lint(cx, + MUT_MUT, + expr.span, + "generally you want to avoid `&mut &mut _` if possible"); + } else { + if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { + span_lint(cx, + MUT_MUT, + expr.span, + "this expression mutably borrows a mutable reference. Consider reborrowing"); + } + } + } + } + + fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { + if let TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) = ty.node { + if let TyRptr(_, MutTy { mutbl: MutMutable, .. }) = pty.node { + span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); + } + } + } +} diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs new file mode 100644 index 00000000000..f6aee54d90b --- /dev/null +++ b/clippy_lints/src/mut_reference.rs @@ -0,0 +1,77 @@ +use rustc::lint::*; +use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; +use rustc::hir::*; +use syntax::ptr::P; +use utils::span_lint; + +/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. +/// +/// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site. +/// +/// **Known problems:** None +/// +/// **Example** `my_vec.push(&mut value)` +declare_lint! { + pub UNNECESSARY_MUT_PASSED, + Warn, + "an argument is passed as a mutable reference although the function/method only demands an \ + immutable reference" +} + + +#[derive(Copy,Clone)] +pub struct UnnecessaryMutPassed; + +impl LintPass for UnnecessaryMutPassed { + fn get_lints(&self) -> LintArray { + lint_array!(UNNECESSARY_MUT_PASSED) + } +} + +impl LateLintPass for UnnecessaryMutPassed { + fn check_expr(&mut self, cx: &LateContext, e: &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 { + 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()) + } + _ => (), + } + } +} + +fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) { + match type_definition.sty { + TypeVariants::TyFnDef(_, _, ref fn_type) | + TypeVariants::TyFnPtr(ref fn_type) => { + 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, .. }) | + TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => { + if let ExprAddrOf(MutMutable, _) = argument.node { + span_lint(cx, + UNNECESSARY_MUT_PASSED, + argument.span, + &format!("The function/method \"{}\" doesn't need a mutable reference", name)); + } + } + _ => (), + } + } + } + _ => (), + } +} diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs new file mode 100644 index 00000000000..7d637adb8b8 --- /dev/null +++ b/clippy_lints/src/mutex_atomic.rs @@ -0,0 +1,75 @@ +//! Checks for uses of Mutex where an atomic value could be used +//! +//! This lint is **warn** by default + +use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; +use rustc::ty::subst::ParamSpace; +use rustc::ty; +use rustc::hir::Expr; +use syntax::ast; +use utils::{match_type, paths, span_lint}; + +/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do. +/// +/// **Why is this bad?** Using a Mutex just to make access to a plain bool or reference sequential is shooting flies with cannons. `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and faster. +/// +/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. +/// +/// **Example:** `let x = Mutex::new(&y);` +declare_lint! { + pub MUTEX_ATOMIC, + Warn, + "using a Mutex where an atomic value could be used instead" +} + +/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type. +/// +/// **Why is this bad?** Using a Mutex just to make access to a plain integer sequential is shooting flies with cannons. `std::atomic::usize` is leaner and faster. +/// +/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. +/// +/// **Example:** `let x = Mutex::new(0usize);` +declare_lint! { + pub MUTEX_INTEGER, + Allow, + "using a Mutex for an integer type" +} + +impl LintPass for MutexAtomic { + fn get_lints(&self) -> LintArray { + lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER) + } +} + +pub struct MutexAtomic; + +impl LateLintPass for MutexAtomic { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + let ty = cx.tcx.expr_ty(expr); + if let ty::TyStruct(_, subst) = ty.sty { + if match_type(cx, ty, &paths::MUTEX) { + let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; + if let Some(atomic_name) = get_atomic_name(mutex_param) { + let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \ + behaviour and not the internal type, consider using Mutex<()>.", + atomic_name); + match *mutex_param { + ty::TyUint(t) if t != ast::UintTy::Us => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + ty::TyInt(t) if t != ast::IntTy::Is => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), + }; + } + } + } + } +} + +fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> { + match *ty { + ty::TyBool => Some("AtomicBool"), + ty::TyUint(_) => Some("AtomicUsize"), + ty::TyInt(_) => Some("AtomicIsize"), + ty::TyRawPtr(_) => Some("AtomicPtr"), + _ => None, + } +} diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs new file mode 100644 index 00000000000..f95d6f5c9c1 --- /dev/null +++ b/clippy_lints/src/needless_bool.rs @@ -0,0 +1,192 @@ +//! Checks for needless boolean results of if-else expressions +//! +//! This lint is **warn** by default + +use rustc::lint::*; +use rustc::hir::*; +use syntax::ast::LitKind; +use syntax::codemap::Spanned; +use utils::{span_lint, span_lint_and_then, snippet, snippet_opt}; + +/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. +/// +/// **Why is this bad?** Redundant code. +/// +/// **Known problems:** Maybe false positives: Sometimes, the two branches are painstakingly documented (which we of course do not detect), so they *may* have some value. Even then, the documentation can be rewritten to match the shorter code. +/// +/// **Example:** `if x { false } else { true }` +declare_lint! { + pub NEEDLESS_BOOL, + Warn, + "if-statements with plain booleans in the then- and else-clause, e.g. \ + `if p { true } else { false }`" +} + +/// **What it does:** This lint checks for expressions of the form `x == true` (or vice versa) and suggest using the variable directly. +/// +/// **Why is this bad?** Unnecessary code. +/// +/// **Known problems:** None. +/// +/// **Example:** `if x == true { }` could be `if x { }` +declare_lint! { + pub BOOL_COMPARISON, + Warn, + "comparing a variable to a boolean, e.g. \ + `if x == true`" +} + +#[derive(Copy,Clone)] +pub struct NeedlessBool; + +impl LintPass for NeedlessBool { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_BOOL) + } +} + +impl LateLintPass for NeedlessBool { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + use self::Expression::*; + if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { + let reduce = |hint: &str, not| { + let hint = match snippet_opt(cx, pred.span) { + Some(pred_snip) => format!("`{}{}`", not, pred_snip), + None => hint.into(), + }; + span_lint_and_then(cx, + NEEDLESS_BOOL, + e.span, + "this if-then-else expression returns a bool literal", + |db| { + 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)) | + (Bool(true), Bool(true)) => { + span_lint(cx, + 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("its predicate", "return "), + (Bool(true), Bool(false)) => reduce("its predicate", ""), + (RetBool(false), RetBool(true)) => reduce("`!` and its predicate", "return !"), + (Bool(false), Bool(true)) => reduce("`!` and its predicate", "!"), + _ => (), + } + } + } +} + +#[derive(Copy,Clone)] +pub struct BoolComparison; + +impl LintPass for BoolComparison { + fn get_lints(&self) -> LintArray { + lint_array!(BOOL_COMPARISON) + } +} + +impl LateLintPass for BoolComparison { + fn check_expr(&mut self, cx: &LateContext, e: &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)) { + (Bool(true), Other) => { + let hint = snippet(cx, right_side.span, "..").into_owned(); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against true are unnecessary", + |db| { + 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, + BOOL_COMPARISON, + e.span, + "equality checks against true are unnecessary", + |db| { + db.span_suggestion(e.span, "try simplifying it as shown:", hint); + }); + } + (Bool(false), Other) => { + let hint = format!("!{}", snippet(cx, right_side.span, "..")); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against false can be replaced by a negation", + |db| { + db.span_suggestion(e.span, "try simplifying it as shown:", hint); + }); + } + (Other, Bool(false)) => { + let hint = format!("!{}", snippet(cx, left_side.span, "..")); + span_lint_and_then(cx, + BOOL_COMPARISON, + e.span, + "equality checks against false can be replaced by a negation", + |db| { + db.span_suggestion(e.span, "try simplifying it as shown:", hint); + }); + } + _ => (), + } + } + } +} + +enum Expression { + Bool(bool), + RetBool(bool), + Other, +} + +fn fetch_bool_block(block: &Block) -> Expression { + match (&*block.stmts, block.expr.as_ref()) { + ([], Some(e)) => fetch_bool_expr(&**e), + ([ref e], None) => { + if let StmtSemi(ref e, _) = e.node { + if let ExprRet(_) = e.node { + fetch_bool_expr(&**e) + } else { + Expression::Other + } + } else { + Expression::Other + } + } + _ => Expression::Other, + } +} + +fn fetch_bool_expr(expr: &Expr) -> Expression { + match expr.node { + ExprBlock(ref block) => fetch_bool_block(block), + ExprLit(ref lit_ptr) => { + if let LitKind::Bool(value) = lit_ptr.node { + Expression::Bool(value) + } 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 new file mode 100644 index 00000000000..033811841ce --- /dev/null +++ b/clippy_lints/src/needless_borrow.rs @@ -0,0 +1,51 @@ +//! Checks for needless address of operations (`&`) +//! +//! This lint is **warn** by default + +use rustc::lint::*; +use rustc::hir::{ExprAddrOf, Expr, MutImmutable}; +use rustc::ty::TyRef; +use utils::{span_lint, in_macro}; +use rustc::ty::adjustment::AutoAdjustment::AdjustDerefRef; + +/// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler +/// +/// **Why is this bad?** Suggests that the receiver of the expression borrows the expression +/// +/// **Known problems:** +/// +/// **Example:** `let x: &i32 = &&&&&&5;` +declare_lint! { + pub NEEDLESS_BORROW, + Warn, + "taking a reference that is going to be automatically dereferenced" +} + +#[derive(Copy,Clone)] +pub struct NeedlessBorrow; + +impl LintPass for NeedlessBorrow { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_BORROW) + } +} + +impl LateLintPass for NeedlessBorrow { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if in_macro(cx, e.span) { + return; + } + if let ExprAddrOf(MutImmutable, ref inner) = e.node { + if let TyRef(..) = cx.tcx.expr_ty(inner).sty { + if let Some(&AdjustDerefRef(ref deref)) = cx.tcx.tables.borrow().adjustments.get(&e.id) { + if deref.autoderefs > 1 && deref.autoref.is_some() { + span_lint(cx, + NEEDLESS_BORROW, + e.span, + "this expression borrows a reference that is immediately dereferenced by the compiler"); + } + } + } + } + } +} diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs new file mode 100644 index 00000000000..d8ae9dc3471 --- /dev/null +++ b/clippy_lints/src/needless_update.rs @@ -0,0 +1,42 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty::TyStruct; +use rustc::hir::{Expr, ExprStruct}; +use utils::span_lint; + +/// **What it does:** This lint warns on needlessly including a base struct on update when all fields are changed anyway. +/// +/// **Why is this bad?** This will cost resources (because the base has to be somewhere), and make the code less readable. +/// +/// **Known problems:** None. +/// +/// **Example:** `Point { x: 1, y: 0, ..zero_point }` +declare_lint! { + pub NEEDLESS_UPDATE, + Warn, + "using `{ ..base }` when there are no missing fields" +} + +#[derive(Copy, Clone)] +pub struct NeedlessUpdatePass; + +impl LintPass for NeedlessUpdatePass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_UPDATE) + } +} + +impl LateLintPass for NeedlessUpdatePass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprStruct(_, ref fields, Some(ref base)) = expr.node { + let ty = cx.tcx.expr_ty(expr); + if let TyStruct(def, _) = ty.sty { + if fields.len() == def.struct_variant().fields.len() { + span_lint(cx, + NEEDLESS_UPDATE, + base.span, + "struct update has no effect, all the fields in the struct have already been specified"); + } + } + } + } +} diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs new file mode 100644 index 00000000000..fb986409a41 --- /dev/null +++ b/clippy_lints/src/neg_multiply.rs @@ -0,0 +1,57 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::codemap::{Span, Spanned}; + +use consts::{self, Constant}; +use utils::span_lint; + +/// **What it does:** Checks for multiplication by -1 as a form of negation. +/// +/// **Why is this bad?** It's more readable to just negate. +/// +/// **Known problems:** This only catches integers (for now) +/// +/// **Example:** `x * -1` +declare_lint! { + pub NEG_MULTIPLY, + Warn, + "Warns on multiplying integers with -1" +} + +#[derive(Copy, Clone)] +pub struct NegMultiply; + +impl LintPass for NegMultiply { + fn get_lints(&self) -> LintArray { + lint_array!(NEG_MULTIPLY) + } +} + +#[allow(match_same_arms)] +impl LateLintPass for NegMultiply { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprBinary(Spanned { node: BiMul, .. }, ref l, ref r) = e.node { + match (&l.node, &r.node) { + (&ExprUnary(..), &ExprUnary(..)) => (), + (&ExprUnary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r), + (_, &ExprUnary(UnNeg, ref lit)) => check_mul(cx, e.span, lit, l), + _ => () + } + } + } +} + +fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { + if_let_chain!([ + let ExprLit(ref l) = lit.node, + let Constant::Int(ref ci) = consts::lit_to_constant(&l.node), + let Some(val) = ci.to_u64(), + val == 1, + cx.tcx.expr_ty(exp).is_integral() + ], { + span_lint(cx, + NEG_MULTIPLY, + span, + "Negation by multiplying with -1"); + }) +} diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs new file mode 100644 index 00000000000..08d517014ee --- /dev/null +++ b/clippy_lints/src/new_without_default.rs @@ -0,0 +1,148 @@ +use rustc::hir::intravisit::FnKind; +use rustc::hir::def_id::DefId; +use rustc::hir; +use rustc::lint::*; +use rustc::ty; +use syntax::ast; +use syntax::codemap::Span; +use utils::paths; +use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint}; + +/// **What it does:** This lints about type with a `fn new() -> Self` method +/// and no implementation of +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// +/// **Why is this bad?** User might expect to be able to use +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// as the type can be +/// constructed without arguments. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ```rust,ignore +/// struct Foo(Bar); +/// +/// impl Foo { +/// fn new() -> Self { +/// Foo(Bar::new()) +/// } +/// } +/// ``` +/// +/// Instead, use: +/// +/// ```rust +/// struct Foo(Bar); +/// +/// impl Default for Foo { +/// fn default() -> Self { +/// Foo(Bar::new()) +/// } +/// } +/// ``` +/// +/// You can also have `new()` call `Default::default()` +declare_lint! { + pub NEW_WITHOUT_DEFAULT, + Warn, + "`fn new() -> Self` method without `Default` implementation" +} + +/// **What it does:** This lints about type with a `fn new() -> Self` method +/// and no implementation of +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// +/// **Why is this bad?** User might expect to be able to use +/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) +/// as the type can be +/// constructed without arguments. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// +/// ```rust,ignore +/// struct Foo; +/// +/// impl Foo { +/// fn new() -> Self { +/// Foo +/// } +/// } +/// ``` +/// +/// Just prepend `#[derive(Default)]` before the `struct` definition +declare_lint! { + pub NEW_WITHOUT_DEFAULT_DERIVE, + Warn, + "`fn new() -> Self` without `#[derive]`able `Default` implementation" +} + +#[derive(Copy,Clone)] +pub struct NewWithoutDefault; + +impl LintPass for NewWithoutDefault { + fn get_lints(&self) -> LintArray { + lint_array!(NEW_WITHOUT_DEFAULT, NEW_WITHOUT_DEFAULT_DERIVE) + } +} + +impl LateLintPass for NewWithoutDefault { + fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, id: ast::NodeId) { + if in_external_macro(cx, span) { + return; + } + + if let FnKind::Method(name, _, _, _) = kind { + if decl.inputs.is_empty() && name.as_str() == "new" { + let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id( + cx.tcx.map.get_parent(id))).ty; + if_let_chain!{[ + self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics + let Some(ret_ty) = return_ty(cx, id), + same_tys(cx, self_ty, ret_ty, id), + let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), + !implements_trait(cx, self_ty, default_trait_id, Vec::new()) + ], { + if can_derive_default(self_ty, cx, default_trait_id) { + span_lint(cx, + NEW_WITHOUT_DEFAULT_DERIVE, span, + &format!("you should consider deriving a \ + `Default` implementation for `{}`", + self_ty)). + span_suggestion(span, + "try this", + "#[derive(Default)]".into()); + } else { + span_lint(cx, + NEW_WITHOUT_DEFAULT, span, + &format!("you should consider adding a \ + `Default` implementation for `{}`", + self_ty)). + span_suggestion(span, + "try this", + format!("impl Default for {} {{ fn default() -> \ + Self {{ {}::new() }} }}", self_ty, self_ty)); + } + }} + } + } + } +} + +fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> bool { + match ty.sty { + ty::TyStruct(ref adt_def, ref substs) => { + for field in adt_def.all_fields() { + let f_ty = field.ty(cx.tcx, substs); + if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) { + return false + } + } + true + }, + _ => false + } +} diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs new file mode 100644 index 00000000000..ae3bac00455 --- /dev/null +++ b/clippy_lints/src/no_effect.rs @@ -0,0 +1,155 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::hir::def::{Def, PathResolution}; +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; + +/// **What it does:** This lint checks for statements which have no effect. +/// +/// **Why is this bad?** Similar to dead code, these statements are actually executed. However, as they have no effect, all they do is make the code less readable. +/// +/// **Known problems:** None. +/// +/// **Example:** `0;` +declare_lint! { + pub NO_EFFECT, + Warn, + "statements with no effect" +} + +/// **What it does:** This lint checks for expression statements that can be reduced to a sub-expression +/// +/// **Why is this bad?** Expressions by themselves often have no side-effects. Having such expressions reduces redability. +/// +/// **Known problems:** None. +/// +/// **Example:** `compute_array()[0];` +declare_lint! { + pub UNNECESSARY_OPERATION, + Warn, + "outer expressions with no effect" +} + +fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { + if in_macro(cx, expr.span) { + return false; + } + match expr.node { + Expr_::ExprLit(..) | + Expr_::ExprClosure(..) | + Expr_::ExprPath(..) => true, + Expr_::ExprIndex(ref a, ref b) | + Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b), + Expr_::ExprVec(ref v) | + Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), + Expr_::ExprRepeat(ref inner, _) | + Expr_::ExprCast(ref inner, _) | + Expr_::ExprType(ref inner, _) | + Expr_::ExprUnary(_, ref inner) | + Expr_::ExprField(ref inner, _) | + Expr_::ExprTupField(ref inner, _) | + Expr_::ExprAddrOf(_, ref inner) | + Expr_::ExprBox(ref inner) => has_no_effect(cx, inner), + Expr_::ExprStruct(_, ref fields, ref base) => { + fields.iter().all(|field| has_no_effect(cx, &field.expr)) && + match *base { + 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(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), + _ => false, + } + } + Expr_::ExprBlock(ref block) => { + block.stmts.is_empty() && + if let Some(ref expr) = block.expr { + has_no_effect(cx, expr) + } else { + false + } + } + _ => false, + } +} + +#[derive(Copy, Clone)] +pub struct NoEffectPass; + +impl LintPass for NoEffectPass { + fn get_lints(&self) -> LintArray { + lint_array!(NO_EFFECT, UNNECESSARY_OPERATION) + } +} + +impl LateLintPass for NoEffectPass { + fn check_stmt(&mut self, cx: &LateContext, stmt: &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"); + } else if let Some(reduced) = reduce_expression(cx, expr) { + let mut snippet = String::new(); + for e in reduced { + if in_macro(cx, e.span) { + return; + } + if let Some(snip) = snippet_opt(cx, e.span) { + snippet.push_str(&snip); + snippet.push(';'); + } else { + return; + } + } + span_lint_and_then(cx, UNNECESSARY_OPERATION, stmt.span, "statement can be reduced", |db| { + db.span_suggestion(stmt.span, "replace it with", snippet); + }); + } + } + } +} + + +fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Expr>> { + if in_macro(cx, expr.span) { + return None; + } + match expr.node { + Expr_::ExprIndex(ref a, ref b) | + Expr_::ExprBinary(_, ref a, ref b) => Some(vec![&**a, &**b]), + Expr_::ExprVec(ref v) | + Expr_::ExprTup(ref v) => Some(v.iter().map(Deref::deref).collect()), + Expr_::ExprRepeat(ref inner, _) | + Expr_::ExprCast(ref inner, _) | + Expr_::ExprType(ref inner, _) | + Expr_::ExprUnary(_, ref inner) | + Expr_::ExprField(ref inner, _) | + Expr_::ExprTupField(ref inner, _) | + Expr_::ExprAddrOf(_, ref inner) | + Expr_::ExprBox(ref inner) => 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(args.iter().map(Deref::deref).collect()), + _ => None, + } + } + Expr_::ExprBlock(ref block) => { + if block.stmts.is_empty() { + block.expr.as_ref().and_then(|e| match block.rules { + BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None, + BlockCheckMode::DefaultBlock => Some(vec![&**e]), + // in case of compiler-inserted signaling blocks + _ => reduce_expression(cx, e), + }) + } else { + None + } + } + _ => None, + } +} diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs new file mode 100644 index 00000000000..cbb083a3e16 --- /dev/null +++ b/clippy_lints/src/non_expressive_names.rs @@ -0,0 +1,291 @@ +use rustc::lint::*; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use syntax::ast::*; +use syntax::attr; +use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr}; +use utils::{span_lint_and_then, in_macro, span_lint}; + +/// **What it does:** This lint warns about names that are very similar and thus confusing +/// +/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character +/// +/// **Known problems:** None? +/// +/// **Example:** `checked_exp` and `checked_expr` +declare_lint! { + pub SIMILAR_NAMES, + Allow, + "similarly named items and bindings" +} + +/// **What it does:** This lint warns about having too many variables whose name consists of a single character +/// +/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name. +/// +/// **Known problems:** None? +/// +/// **Example:** let (a, b, c, d, e, f, g) = (...); +declare_lint! { + pub MANY_SINGLE_CHAR_NAMES, + Warn, + "too many single character bindings" +} + +pub struct NonExpressiveNames { + pub max_single_char_names: u64, +} + +impl LintPass for NonExpressiveNames { + fn get_lints(&self) -> LintArray { + lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES) + } +} + +struct ExistingName { + interned: InternedString, + span: Span, + len: usize, + whitelist: &'static [&'static str], +} + +struct SimilarNamesLocalVisitor<'a, 'b: 'a> { + names: Vec<ExistingName>, + cx: &'a EarlyContext<'b>, + lint: &'a NonExpressiveNames, + single_char_names: Vec<char>, +} + +// this list contains lists of names that are allowed to be similar +// the assumption is that no name is ever contained in multiple lists. +#[cfg_attr(rustfmt, rustfmt_skip)] +const WHITELIST: &'static [&'static [&'static str]] = &[ + &["parsed", "parser"], + &["lhs", "rhs"], + &["tx", "rx"], + &["set", "get"], +]; + +struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); + +impl<'v, 'a, 'b, 'c> Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { + fn visit_pat(&mut self, pat: &'v Pat) { + match pat.node { + PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), + PatKind::Struct(_, ref fields, _) => for field in fields { + if !field.node.is_shorthand { + self.visit_pat(&field.node.pat); + } + }, + _ => walk_pat(self, pat), + } + } +} + +fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { + for &allow in WHITELIST { + if whitelisted(interned_name, allow) { + return Some(allow); + } + } + None +} + +fn whitelisted(interned_name: &str, list: &[&str]) -> bool { + if list.iter().any(|&name| interned_name == name) { + return true; + } + for name in list { + // name_* + if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) { + return true; + } + // *_name + if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) { + return true; + } + } + false +} + +impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { + fn check_short_name(&mut self, c: char, span: Span) { + // make sure we ignore shadowing + if self.0.single_char_names.contains(&c) { + return; + } + self.0.single_char_names.push(c); + if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names { + span_lint(self.0.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("{}th binding whose name is just one char", self.0.single_char_names.len())); + } + } + fn check_name(&mut self, span: Span, name: Name) { + if in_macro(self.0.cx, span) { + return; + } + let interned_name = name.as_str(); + if interned_name.chars().any(char::is_uppercase) { + return; + } + let count = interned_name.chars().count(); + if count < 3 { + if count == 1 { + let c = interned_name.chars().next().expect("already checked"); + self.check_short_name(c, span); + } + return; + } + for existing_name in &self.0.names { + if whitelisted(&interned_name, existing_name.whitelist) { + continue; + } + let mut split_at = None; + if existing_name.len > count { + if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { + continue; + } + } else if existing_name.len < count { + if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { + continue; + } + } else { + let mut interned_chars = interned_name.chars(); + let mut existing_chars = existing_name.interned.chars(); + let first_i = interned_chars.next().expect("we know we have at least one char"); + let first_e = existing_chars.next().expect("we know we have at least one char"); + let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); + + if eq_or_numeric(first_i, first_e) { + let last_i = interned_chars.next_back().expect("we know we have at least two chars"); + let last_e = existing_chars.next_back().expect("we know we have at least two chars"); + if eq_or_numeric(last_i, last_e) { + if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 { + continue; + } + } else { + let second_last_i = interned_chars.next_back().expect("we know we have at least three chars"); + let second_last_e = existing_chars.next_back().expect("we know we have at least three chars"); + if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || + !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + // allowed similarity foo_x, foo_y + // or too many chars differ (foo_x, boo_y) or (foox, booy) + continue; + } + split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); + } + } else { + let second_i = interned_chars.next().expect("we know we have at least two chars"); + let second_e = existing_chars.next().expect("we know we have at least two chars"); + if !eq_or_numeric(second_i, second_e) || second_i == '_' || + !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + // allowed similarity x_foo, y_foo + // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) + continue; + } + split_at = interned_name.chars().next().map(|c| c.len_utf8()); + } + } + span_lint_and_then(self.0.cx, + SIMILAR_NAMES, + span, + "binding's name is too similar to existing binding", + |diag| { + diag.span_note(existing_name.span, "existing binding defined here"); + if let Some(split) = split_at { + diag.span_help(span, + &format!("separate the discriminating character by an \ + underscore like: `{}_{}`", + &interned_name[..split], + &interned_name[split..])); + } + }); + return; + } + self.0.names.push(ExistingName { + whitelist: get_whitelist(&interned_name).unwrap_or(&[]), + interned: interned_name, + span: span, + len: count, + }); + } +} + +impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { + /// ensure scoping rules work + fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) { + let n = self.names.len(); + let single_char_count = self.single_char_names.len(); + f(self); + self.names.truncate(n); + self.single_char_names.truncate(single_char_count); + } +} + +impl<'v, 'a, 'b> Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { + fn visit_local(&mut self, local: &'v Local) { + if let Some(ref init) = local.init { + self.apply(|this| walk_expr(this, &**init)); + } + // add the pattern after the expression because the bindings aren't available yet in the init expression + SimilarNamesNameVisitor(self).visit_pat(&*local.pat); + } + fn visit_block(&mut self, blk: &'v Block) { + self.apply(|this| walk_block(this, blk)); + } + fn visit_arm(&mut self, arm: &'v Arm) { + self.apply(|this| { + // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier + SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); + this.apply(|this| walk_expr(this, &arm.body)); + }); + } + fn visit_item(&mut self, _: &'v Item) { + // do not recurse into inner items + } +} + +impl EarlyLintPass for NonExpressiveNames { + fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node { + if !attr::contains_name(&item.attrs, "test") { + let mut visitor = SimilarNamesLocalVisitor { + names: Vec::new(), + cx: cx, + lint: self, + single_char_names: Vec::new(), + }; + // initialize with function arguments + for arg in &decl.inputs { + SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat); + } + // walk all other bindings + walk_block(&mut visitor, blk); + } + } + } +} + +/// Precondition: `a_name.chars().count() < b_name.chars().count()`. +fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { + debug_assert!(a_name.chars().count() < b_name.chars().count()); + let mut a_chars = a_name.chars(); + let mut b_chars = b_name.chars(); + while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) { + if a == b { + continue; + } + if let Some(b2) = b_chars.next() { + // check if there's just one character inserted + return a != b2 || a_chars.ne(b_chars); + } else { + // tuple + // ntuple + return true; + } + } + // for item in items + true +} diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs new file mode 100644 index 00000000000..1d760599e3f --- /dev/null +++ b/clippy_lints/src/open_options.rs @@ -0,0 +1,185 @@ +use rustc::hir::{Expr, ExprMethodCall, ExprLit}; +use rustc::lint::*; +use syntax::ast::LitKind; +use syntax::codemap::{Span, Spanned}; +use utils::{match_type, paths, span_lint, walk_ptrs_ty_depth}; + +/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. +/// +/// **Why is this bad?** In the best case, the code will be harder to read than necessary. I don't know the worst case. +/// +/// **Known problems:** None +/// +/// **Example:** `OpenOptions::new().read(true).truncate(true)` +declare_lint! { + pub NONSENSICAL_OPEN_OPTIONS, + Warn, + "nonsensical combination of options for opening a file" +} + + +#[derive(Copy,Clone)] +pub struct NonSensicalOpenOptions; + +impl LintPass for NonSensicalOpenOptions { + fn get_lints(&self) -> LintArray { + lint_array!(NONSENSICAL_OPEN_OPTIONS) + } +} + +impl LateLintPass for NonSensicalOpenOptions { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprMethodCall(ref name, _, ref arguments) = e.node { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); + if name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { + let mut options = Vec::new(); + get_open_options(cx, &arguments[0], &mut options); + check_open_options(cx, &options, e.span); + } + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum Argument { + True, + False, + Unknown, +} + +#[derive(Debug)] +enum OpenOption { + Write, + Read, + Truncate, + Create, + Append, +} + +fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { + if let ExprMethodCall(ref name, _, ref arguments) = argument.node { + let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); + + // Only proceed if this is a call on some object of type std::fs::OpenOptions + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { + + 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 + } + } 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)); + } + _ => (), + } + + get_open_options(cx, &arguments[0], options); + } + } +} + +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); + // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. + + for option in options { + match *option { + (OpenOption::Create, arg) => { + if create { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"create\" is called more than once"); + } else { + create = true + } + create_arg = create_arg || (arg == Argument::True);; + } + (OpenOption::Append, arg) => { + if append { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"append\" is called more than once"); + } else { + append = true + } + append_arg = append_arg || (arg == Argument::True);; + } + (OpenOption::Truncate, arg) => { + if truncate { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"truncate\" is called more than once"); + } else { + truncate = true + } + truncate_arg = truncate_arg || (arg == Argument::True); + } + (OpenOption::Read, arg) => { + if read { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"read\" is called more than once"); + } else { + read = true + } + read_arg = read_arg || (arg == Argument::True);; + } + (OpenOption::Write, arg) => { + if write { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"write\" is called more than once"); + } else { + write = true + } + write_arg = write_arg || (arg == Argument::True);; + } + } + } + + if read && truncate && read_arg && truncate_arg { + span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\""); + } + if append && truncate && append_arg && truncate_arg { + span_lint(cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "file opened with \"append\" and \"truncate\""); + } +} diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs new file mode 100644 index 00000000000..34921bc2c04 --- /dev/null +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -0,0 +1,72 @@ +use rustc::lint::*; +use rustc::hir::*; +use utils::span_lint; + +/// **What it does:** This lint finds classic underflow / overflow checks. +/// +/// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. +/// +/// **Known problems:** None. +/// +/// **Example:** `a + b < a` + +declare_lint!(pub OVERFLOW_CHECK_CONDITIONAL, Warn, + "Using overflow checks which are likely to panic"); + +#[derive(Copy, Clone)] +pub struct OverflowCheckConditional; + +impl LintPass for OverflowCheckConditional { + fn get_lints(&self) -> LintArray { + lint_array!(OVERFLOW_CHECK_CONDITIONAL) + } +} + +impl LateLintPass for OverflowCheckConditional { + // a + b < a, a > a + b, a < a - b, a - b > a + fn check_expr(&mut self, cx: &LateContext, expr: &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, + &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], + cx.tcx.expr_ty(ident1).is_integral(), + cx.tcx.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."); + } + } + 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."); + } + } + }} + + 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, + &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], + cx.tcx.expr_ty(ident1).is_integral(), + cx.tcx.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."); + } + } + 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."); + } + } + }} + } +} diff --git a/clippy_lints/src/panic.rs b/clippy_lints/src/panic.rs new file mode 100644 index 00000000000..d744d2a6308 --- /dev/null +++ b/clippy_lints/src/panic.rs @@ -0,0 +1,47 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::ast::LitKind; +use utils::{is_direct_expn_of, match_path, paths, span_lint}; + +/// **What it does:** This lint checks for missing parameters in `panic!`. +/// +/// **Known problems:** Should you want to use curly brackets in `panic!` without any parameter, +/// this lint will warn. +/// +/// **Example:** +/// ``` +/// panic!("This `panic!` is probably missing a parameter there: {}"); +/// ``` +declare_lint! { + pub PANIC_PARAMS, Warn, "missing parameters in `panic!`" +} + +#[allow(missing_copy_implementations)] +pub struct PanicPass; + +impl LintPass for PanicPass { + fn get_lints(&self) -> LintArray { + lint_array!(PANIC_PARAMS) + } +} + +impl LateLintPass for PanicPass { + fn check_expr(&mut self, cx: &LateContext, expr: &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, ref path) = fun.node, + match_path(path, &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, + let Some(par) = string.find('{'), + string[par..].contains('}') + ], { + span_lint(cx, PANIC_PARAMS, params[0].span, + "you probably are missing some parameter in your format string"); + }} + } +} diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs new file mode 100644 index 00000000000..825a1b84450 --- /dev/null +++ b/clippy_lints/src/precedence.rs @@ -0,0 +1,118 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::codemap::Spanned; +use utils::{span_lint, snippet}; + +/// **What it does:** This lint checks for operations where precedence may be unclear and suggests to add parentheses. Currently it catches the following: +/// * mixed usage of arithmetic and bit shifting/combining operators without parentheses +/// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call +/// +/// **Why is this bad?** Because not everyone knows the precedence of those operators by heart, so expressions like these may trip others trying to reason about the code. +/// +/// **Known problems:** None +/// +/// **Examples:** +/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 +/// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 +declare_lint! { + pub PRECEDENCE, Warn, + "catches operations where precedence may be unclear. See the wiki for a \ + list of cases caught" +} + +#[derive(Copy,Clone)] +pub struct Precedence; + +impl LintPass for Precedence { + fn get_lints(&self) -> LintArray { + lint_array!(PRECEDENCE) + } +} + +impl EarlyLintPass for Precedence { + fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { + if !is_bit_op(op) { + return; + } + match (is_arith_expr(left), is_arith_expr(right)) { + (true, true) => { + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`({}) {} ({})`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } + (true, false) => { + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`({}) {} {}`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } + (false, true) => { + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("operator precedence can trip the unwary. Consider parenthesizing your \ + expression:`{} {} ({})`", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, ".."))); + } + _ => (), + } + } + + if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.node { + if let ExprKind::MethodCall(_, _, ref args) = rhs.node { + if let Some(slf) = args.first() { + if let ExprKind::Lit(ref lit) = slf.node { + match lit.node { + LitKind::Int(..) | + LitKind::Float(..) | + LitKind::FloatUnsuffixed(..) => { + span_lint(cx, + PRECEDENCE, + expr.span, + &format!("unary minus has lower precedence than method call. Consider \ + adding parentheses to clarify your intent: -({})", + snippet(cx, rhs.span, ".."))); + } + _ => (), + } + } + } + } + } + } +} + +fn is_arith_expr(expr: &Expr) -> bool { + match expr.node { + ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op), + _ => false, + } +} + +fn is_bit_op(op: BinOpKind) -> bool { + use syntax::ast::BinOpKind::*; + match op { + BitXor | BitAnd | BitOr | Shl | Shr => true, + _ => false, + } +} + +fn is_arith_op(op: BinOpKind) -> bool { + use syntax::ast::BinOpKind::*; + match op { + Add | Sub | Mul | Div | Rem => true, + _ => false, + } +} diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs new file mode 100644 index 00000000000..d426286dba4 --- /dev/null +++ b/clippy_lints/src/print.rs @@ -0,0 +1,88 @@ +use rustc::hir::*; +use rustc::hir::map::Node::{NodeItem, NodeImplItem}; +use rustc::lint::*; +use utils::paths; +use utils::{is_expn_of, match_path, span_lint}; + +/// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants. +/// +/// **Why is this bad?** People often print on *stdout* while debugging an application and might +/// forget to remove those prints afterward. +/// +/// **Known problems:** Only catches `print!` and `println!` calls. +/// +/// **Example:** `println!("Hello world!");` +declare_lint! { + pub PRINT_STDOUT, + Allow, + "printing on stdout" +} + +/// **What it does:** This lint warns whenever you use `Debug` formatting. The purpose of this lint is to catch debugging remnants. +/// +/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate debugging Rust code. It +/// should not be used in in user-facing output. +/// +/// **Example:** `println!("{:?}", foo);` +declare_lint! { + pub USE_DEBUG, + Allow, + "use `Debug`-based formatting" +} + +#[derive(Copy, Clone, Debug)] +pub struct PrintLint; + +impl LintPass for PrintLint { + fn get_lints(&self) -> LintArray { + lint_array!(PRINT_STDOUT, USE_DEBUG) + } +} + +impl LateLintPass for PrintLint { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprCall(ref fun, ref args) = expr.node { + if let ExprPath(_, ref path) = fun.node { + // Search for `std::io::_print(..)` which is unique in a + // `print!` expansion. + if match_path(path, &paths::IO_PRINT) { + if let Some(span) = is_expn_of(cx, expr.span, "print") { + // `println!` uses `print!`. + let (span, name) = match is_expn_of(cx, span, "println") { + Some(span) => (span, "println"), + None => (span, "print"), + }; + + span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); + } + } + // Search for something like + // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` + else if args.len() == 2 && match_path(path, &paths::FMT_ARGUMENTV1_NEW) { + if let ExprPath(None, ref path) = args[1].node { + if match_path(path, &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"); + } + } + } + } + } + } +} + +fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { + let map = &cx.tcx.map; + + // `fmt` method + if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { + // `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"]); + } + } + } + + false +} diff --git a/clippy_lints/src/ptr_arg.rs b/clippy_lints/src/ptr_arg.rs new file mode 100644 index 00000000000..addcfc9e84d --- /dev/null +++ b/clippy_lints/src/ptr_arg.rs @@ -0,0 +1,78 @@ +//! Checks for usage of `&Vec[_]` and `&String`. + +use rustc::hir::*; +use rustc::hir::map::NodeItem; +use rustc::lint::*; +use rustc::ty; +use syntax::ast::NodeId; +use utils::{match_type, paths, span_lint}; + +/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. +/// +/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be obtained from other types, too. +/// +/// **Known problems:** None +/// +/// **Example:** `fn foo(&Vec<u32>) { .. }` +declare_lint! { + pub PTR_ARG, + Warn, + "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \ + instead, respectively" +} + +#[derive(Copy,Clone)] +pub struct PtrArg; + +impl LintPass for PtrArg { + fn get_lints(&self) -> LintArray { + lint_array!(PTR_ARG) + } +} + +impl LateLintPass for PtrArg { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemFn(ref decl, _, _, _, _, _) = item.node { + check_fn(cx, decl, item.id); + } + } + + fn check_impl_item(&mut self, cx: &LateContext, item: &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 { + return; // ignore trait impls + } + } + check_fn(cx, &sig.decl, item.id); + } + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + if let MethodTraitItem(ref sig, _) = item.node { + check_fn(cx, &sig.decl, item.id); + } + } +} + +fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { + let fn_ty = cx.tcx.node_id_to_type(fn_id).fn_sig().skip_binder(); + + 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, + PTR_ARG, + arg.ty.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ + with non-Vec-based slices. Consider changing the type to `&[...]`"); + } else if match_type(cx, ty, &paths::STRING) { + span_lint(cx, + PTR_ARG, + arg.ty.span, + "writing `&String` instead of `&str` involves a new object where a slice will do. \ + Consider changing the type to `&str`"); + } + } + } +} diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs new file mode 100644 index 00000000000..e96212a9cef --- /dev/null +++ b/clippy_lints/src/ranges.rs @@ -0,0 +1,89 @@ +use rustc::lint::*; +use rustc::hir::*; +use syntax::codemap::Spanned; +use utils::{is_integer_literal, match_type, paths, snippet, span_lint, unsugar_range, UnsugaredRange}; + +/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. +/// +/// **Why is this bad?** This very much looks like an oversight, since with `loop { .. }` there is an obvious better way to endlessly loop. +/// +/// **Known problems:** None +/// +/// **Example:** `for x in (5..5).step_by(0) { .. }` +declare_lint! { + pub RANGE_STEP_BY_ZERO, Warn, + "using Range::step_by(0), which produces an infinite iterator" +} +/// **What it does:** This lint checks for zipping a collection with the range of `0.._.len()`. +/// +/// **Why is this bad?** The code is better expressed with `.enumerate()`. +/// +/// **Known problems:** None +/// +/// **Example:** `x.iter().zip(0..x.len())` +declare_lint! { + pub RANGE_ZIP_WITH_LEN, Warn, + "zipping iterator with a range when enumerate() would do" +} + +#[derive(Copy,Clone)] +pub struct StepByZero; + +impl LintPass for StepByZero { + fn get_lints(&self) -> LintArray { + lint_array!(RANGE_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN) + } +} + +impl LateLintPass for StepByZero { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { + // Range with step_by(0). + if name.as_str() == "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, + "Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \ + instead"); + } else if name.as_str() == "zip" && args.len() == 2 { + let iter = &args[0].node; + let zip_arg = &args[1]; + if_let_chain! { + [ + // .iter() call + let ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = *iter, + iter_name.as_str() == "iter", + // range expression in .zip() call: 0..x.len() + let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(zip_arg), + is_integer_literal(start, 0), + // .len() call + 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 + ], { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("It is more idiomatic to use {}.iter().enumerate()", + snippet(cx, iter_args[0].span, "_"))); + } + } + } + } + } +} + +fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { + // No need for walk_ptrs_ty here because step_by moves self, so it + // can't be called on a borrowed range. + let ty = cx.tcx.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) +} diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs new file mode 100644 index 00000000000..c97a64ebf09 --- /dev/null +++ b/clippy_lints/src/regex.rs @@ -0,0 +1,229 @@ +use regex_syntax; +use rustc::hir::*; +use rustc::lint::*; +use rustc::middle::const_val::ConstVal; +use rustc_const_eval::EvalHint::ExprTypeChecked; +use rustc_const_eval::eval_const_expr_partial; +use std::collections::HashSet; +use std::error::Error; +use syntax::ast::{LitKind, NodeId}; +use syntax::codemap::{Span, BytePos}; +use syntax::parse::token::InternedString; +use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint}; + +/// **What it does:** This lint checks [regex] creation (with `Regex::new`, `RegexBuilder::new` or +/// `RegexSet::new`) for correct regex syntax. +/// +/// **Why is this bad?** This will lead to a runtime panic. +/// +/// **Known problems:** None. +/// +/// **Example:** `Regex::new("|")` +declare_lint! { + pub INVALID_REGEX, + Deny, + "finds invalid regular expressions" +} + +/// **What it does:** This lint checks for trivial [regex] creation (with `Regex::new`, +/// `RegexBuilder::new` or `RegexSet::new`). +/// +/// **Why is this bad?** This can likely be replaced by `==` or `str::starts_with`, +/// `str::ends_with` or `std::contains` or other `str` methods. +/// +/// **Known problems:** None. +/// +/// **Example:** `Regex::new("^foobar")` +/// +/// [regex]: https://crates.io/crates/regex +declare_lint! { + pub TRIVIAL_REGEX, + Warn, + "finds trivial regular expressions" +} + +/// **What it does:** This lint checks for usage of `regex!(_)` which as of now is usually slower than `Regex::new(_)` unless called in a loop (which is a bad idea anyway). +/// +/// **Why is this bad?** Performance, at least for now. The macro version is likely to catch up long-term, but for now the dynamic version is faster. +/// +/// **Known problems:** None +/// +/// **Example:** `regex!("foo|bar")` +declare_lint! { + pub REGEX_MACRO, + Warn, + "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" +} + +#[derive(Clone, Default)] +pub struct RegexPass { + spans: HashSet<Span>, + last: Option<NodeId>, +} + +impl LintPass for RegexPass { + fn get_lints(&self) -> LintArray { + lint_array!(INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX) + } +} + +impl LateLintPass for RegexPass { + fn check_crate(&mut self, _: &LateContext, _: &Crate) { + self.spans.clear(); + } + + fn check_block(&mut self, cx: &LateContext, block: &Block) { + if_let_chain!{[ + self.last.is_none(), + let Some(ref expr) = block.expr, + match_type(cx, cx.tcx.expr_ty(expr), &paths::REGEX), + let Some(span) = is_expn_of(cx, expr.span, "regex"), + ], { + if !self.spans.contains(&span) { + span_lint(cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now."); + self.spans.insert(span); + } + self.last = Some(block.id); + }} + } + + fn check_block_post(&mut self, _: &LateContext, block: &Block) { + if self.last.map_or(false, |id| block.id == id) { + self.last = None; + } + } + + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain!{[ + let ExprCall(ref fun, ref args) = expr.node, + args.len() == 1, + let Some(def) = cx.tcx.def_map.borrow().get(&fun.id), + ], { + let def_id = def.def_id(); + if match_def_path(cx, def_id, &paths::REGEX_NEW) { + check_regex(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) { + check_regex(cx, &args[0], false); + } else if match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { + check_regex(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { + check_regex(cx, &args[0], false); + } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { + check_set(cx, &args[0], true); + } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { + check_set(cx, &args[0], false); + } + }} + } +} + +#[allow(cast_possible_truncation)] +fn str_span(base: Span, s: &str, c: usize) -> Span { + let mut si = s.char_indices().skip(c); + + match (si.next(), si.next()) { + (Some((l, _)), Some((h, _))) => { + Span { + lo: base.lo + BytePos(l as u32), + hi: base.lo + BytePos(h as u32), + ..base + } + } + _ => base, + } +} + +fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { + match eval_const_expr_partial(cx.tcx, e, ExprTypeChecked, None) { + Ok(ConstVal::Str(r)) => Some(r), + _ => None, + } +} + +fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { + use regex_syntax::Expr; + + match *s { + Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), + Expr::Literal { .. } => Some("consider using `str::contains`"), + Expr::Concat(ref exprs) => { + match exprs.len() { + 2 => { + match (&exprs[0], &exprs[1]) { + (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), + (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), + (&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]) { + Some("consider using `==` on `str`s") + } else { + None + } + } + _ => None, + } + } + _ => None, + } +} + +fn check_set(cx: &LateContext, expr: &Expr, utf8: bool) { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, + let ExprVec(ref exprs) = expr.node, + ], { + for expr in exprs { + check_regex(cx, expr, utf8); + } + }} +} + +fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { + let builder = regex_syntax::ExprBuilder::new().unicode(utf8); + + if let ExprLit(ref lit) = expr.node { + if let LitKind::Str(ref r, _) = lit.node { + match builder.parse(r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + "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())); + } + } + } + } else if let Some(r) = const_str(cx, expr) { + match builder.parse(&r) { + Ok(r) => { + if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + "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())); + } + } + } +} diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs new file mode 100644 index 00000000000..d7893821263 --- /dev/null +++ b/clippy_lints/src/returns.rs @@ -0,0 +1,137 @@ +use rustc::lint::*; +use syntax::ast::*; +use syntax::codemap::{Span, Spanned}; +use syntax::visit::FnKind; + +use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro}; + +/// **What it does:** This lint checks for return statements at the end of a block. +/// +/// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty. +/// +/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. +/// +/// **Example:** `fn foo(x: usize) { return x; }` +declare_lint! { + pub NEEDLESS_RETURN, Warn, + "using a return statement like `return expr;` where an expression would suffice" +} + +/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. +/// +/// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. +/// +/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. +/// +/// **Example:** `{ let x = ..; x }` +declare_lint! { + pub LET_AND_RETURN, Warn, + "creating a let-binding and then immediately returning it like `let x = expr; x` at \ + the end of a block" +} + +#[derive(Copy, Clone)] +pub struct ReturnPass; + +impl ReturnPass { + // Check the final stmt or expr in a block for unnecessary return. + fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) { + if let Some(ref expr) = block.expr { + self.check_final_expr(cx, expr); + } else if let Some(stmt) = block.stmts.last() { + if let StmtKind::Semi(ref expr, _) = stmt.node { + if let ExprKind::Ret(Some(ref inner)) = expr.node { + self.emit_return_lint(cx, (stmt.span, inner.span)); + } + } + } + } + + // Check a the final expression in a block if it's a return. + fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + match expr.node { + // simple return is always "bad" + ExprKind::Ret(Some(ref inner)) => { + self.emit_return_lint(cx, (expr.span, inner.span)); + } + // a whole block? check it! + 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 + ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { + self.check_block_return(cx, ifblock); + self.check_final_expr(cx, elsexpr); + } + // a match expr, check all arms + ExprKind::Match(_, ref arms) => { + for arm in arms { + self.check_final_expr(cx, &arm.body); + } + } + _ => (), + } + } + + fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) { + if in_external_macro(cx, spans.1) { + return; + } + span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", |db| { + if let Some(snippet) = snippet_opt(cx, spans.1) { + db.span_suggestion(spans.0, "remove `return` as shown:", snippet); + } + }); + } + + // Check for "let x = EXPR; x" + fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) { + // we need both a let-binding stmt and an expr + if_let_chain! { + [ + let Some(stmt) = block.stmts.last(), + let Some(ref retexpr) = block.expr, + let StmtKind::Decl(ref decl, _) = stmt.node, + let DeclKind::Local(ref local) = decl.node, + let Some(ref initexpr) = local.init, + let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node, + let ExprKind::Path(_, ref path) = retexpr.node, + match_path_ast(path, &[&id.name.as_str()]) + ], { + self.emit_let_lint(cx, retexpr.span, initexpr.span); + } + } + } + + fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) { + if in_external_macro(cx, note_span) { + return; + } + let mut db = span_lint(cx, + LET_AND_RETURN, + lint_span, + "returning the result of a let binding from a block. Consider returning the \ + expression directly."); + if cx.current_level(LET_AND_RETURN) != Level::Allow { + db.span_note(note_span, "this expression can be directly returned"); + } + } +} + +impl LintPass for ReturnPass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RETURN, LET_AND_RETURN) + } +} + +impl EarlyLintPass for ReturnPass { + fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { + self.check_block_return(cx, block); + } + + fn check_block(&mut self, cx: &EarlyContext, block: &Block) { + self.check_let_return(cx, block); + } +} diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs new file mode 100644 index 00000000000..2a0d36a80b3 --- /dev/null +++ b/clippy_lints/src/shadow.rs @@ -0,0 +1,353 @@ +use reexport::*; +use rustc::lint::*; +use rustc::hir::def::Def; +use rustc::hir::*; +use rustc::hir::intravisit::{Visitor, FnKind}; +use std::ops::Deref; +use syntax::codemap::Span; +use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; + +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. +/// +/// **Why is this bad?** Not much, in fact it's a very common pattern in Rust code. Still, some may opt to avoid it in their code base, they can set this lint to `Warn`. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = &x;` +declare_lint! { + pub SHADOW_SAME, Allow, + "rebinding a name to itself, e.g. `let mut x = &mut x`" +} + +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. +/// +/// **Why is this bad?** Not too much, in fact it's a common pattern in Rust code. Still, some argue that name shadowing like this hurts readability, because a value may be bound to different things depending on position in the code. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = x + 1;` +declare_lint! { + pub SHADOW_REUSE, Allow, + "rebinding a name to an expression that re-uses the original value, e.g. \ + `let x = x + 1`" +} + +/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. +/// +/// **Why is this bad?** Name shadowing can hurt readability, especially in large code bases, because it is easy to lose track of the active binding at any place in the code. This can be alleviated by either giving more specific names to bindings ore introducing more scopes to contain the bindings. +/// +/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. +/// +/// **Example:** `let x = y; let x = z; // shadows the earlier binding` +declare_lint! { + pub SHADOW_UNRELATED, Allow, + "The name is re-bound without even using the original value" +} + +#[derive(Copy, Clone)] +pub struct ShadowPass; + +impl LintPass for ShadowPass { + fn get_lints(&self) -> LintArray { + lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) + } +} + +impl LateLintPass for ShadowPass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, block: &Block, _: Span, _: NodeId) { + if in_external_macro(cx, block.span) { + return; + } + check_fn(cx, decl, block); + } +} + +fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { + let mut bindings = Vec::new(); + for arg in &decl.inputs { + if let PatKind::Ident(_, ident, _) = arg.pat.node { + bindings.push((ident.node.unhygienize(), ident.span)) + } + } + check_block(cx, block, &mut bindings); +} + +fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>) { + let len = bindings.len(); + for stmt in &block.stmts { + match stmt.node { + StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), + StmtExpr(ref e, _) | + StmtSemi(ref e, _) => check_expr(cx, e, bindings), + } + } + if let Some(ref o) = block.expr { + check_expr(cx, o, bindings); + } + bindings.truncate(len); +} + +fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { + if in_external_macro(cx, decl.span) { + return; + } + if is_from_for_desugar(decl) { + return; + } + if let DeclLocal(ref local) = decl.node { + let Local { ref pat, ref ty, ref init, span, .. } = **local; + if let Some(ref t) = *ty { + check_ty(cx, t, bindings) + } + if let Some(ref o) = *init { + check_expr(cx, o, bindings); + check_pat(cx, pat, &Some(o), span, bindings); + } else { + 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, + _ => true, + } +} + +fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { + // TODO: match more stuff / destructuring + match pat.node { + PatKind::Ident(_, ref ident, ref inner) => { + let name = ident.node.unhygienize(); + if is_binding(cx, pat) { + let mut new_binding = true; + for tup in bindings.iter_mut() { + if tup.0 == name { + lint_shadow(cx, name, span, pat.span, init, tup.1); + tup.1 = ident.span; + new_binding = false; + break; + } + } + if new_binding { + bindings.push((name, ident.span)); + } + } + if let Some(ref p) = *inner { + check_pat(cx, p, init, span, bindings); + } + } + // PatEnum(Path, Option<Vec<P<Pat>>>), + PatKind::Struct(_, ref pfields, _) => { + if let Some(ref 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(|ref f| f.name.node == name) + .map(|f| &*f.expr); + check_pat(cx, &field.node.pat, &efield, span, bindings); + } + } else { + for field in pfields { + check_pat(cx, &field.node.pat, init, span, bindings); + } + } + } else { + for field in pfields { + check_pat(cx, &field.node.pat, &None, span, bindings); + } + } + } + PatKind::Tup(ref inner) => { + if let Some(ref 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); + } + } else { + for p in inner { + check_pat(cx, p, init, span, bindings); + } + } + } else { + for p in inner { + check_pat(cx, p, &None, span, bindings); + } + } + } + PatKind::Box(ref inner) => { + if let Some(ref initp) = *init { + if let ExprBox(ref inner_init) = initp.node { + 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<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), + _ => (), + } +} + +fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, init: &Option<T>, prev_span: Span) + where T: Deref<Target = Expr> +{ + fn note_orig(cx: &LateContext, mut db: DiagnosticWrapper, lint: &'static Lint, span: Span) { + if cx.current_level(lint) != Level::Allow { + db.span_note(span, "previous binding is here"); + } + } + if let Some(ref expr) = *init { + if is_self_shadow(name, expr) { + let db = span_lint(cx, + SHADOW_SAME, + span, + &format!("`{}` is shadowed by itself in `{}`", + snippet(cx, pattern_span, "_"), + snippet(cx, expr.span, ".."))); + + note_orig(cx, db, SHADOW_SAME, prev_span); + } else if contains_self(name, expr) { + let db = span_note_and_lint(cx, + SHADOW_REUSE, + pattern_span, + &format!("`{}` is shadowed by `{}` which reuses the original value", + snippet(cx, pattern_span, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); + note_orig(cx, db, SHADOW_REUSE, prev_span); + } else { + let db = span_note_and_lint(cx, + SHADOW_UNRELATED, + pattern_span, + &format!("`{}` is shadowed by `{}`", + snippet(cx, pattern_span, "_"), + snippet(cx, expr.span, "..")), + expr.span, + "initialization happens here"); + note_orig(cx, db, SHADOW_UNRELATED, prev_span); + } + + } else { + let db = span_lint(cx, + SHADOW_UNRELATED, + span, + &format!("{} shadows a previous declaration", snippet(cx, pattern_span, "_"))); + note_orig(cx, db, SHADOW_UNRELATED, prev_span); + } +} + +fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { + if in_external_macro(cx, expr.span) { + return; + } + match expr.node { + ExprUnary(_, ref e) | + ExprField(ref e, _) | + ExprTupField(ref e, _) | + ExprAddrOf(_, ref e) | + ExprBox(ref e) => check_expr(cx, e, bindings), + ExprBlock(ref block) | + ExprLoop(ref block, _) => check_block(cx, block, bindings), + // ExprCall + // ExprMethodCall + ExprVec(ref v) | ExprTup(ref v) => { + for ref 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 ref arm in arms { + for ref pat in &arm.pats { + 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); + } + check_expr(cx, &arm.body, bindings); + bindings.truncate(len); + } + } + } + _ => (), + } +} + +fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { + match ty.node { + TyObjectSum(ref sty, _) | + TyVec(ref sty) => check_ty(cx, sty, bindings), + TyFixedLengthVec(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 ref t in tup { + check_ty(cx, t, bindings) + } + } + TyTypeof(ref expr) => check_expr(cx, expr, bindings), + _ => (), + } +} + +fn is_self_shadow(name: Name, expr: &Expr) -> bool { + match expr.node { + ExprBox(ref inner) | + ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), + ExprBlock(ref block) => { + block.stmts.is_empty() && block.expr.as_ref().map_or(false, |ref 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), + _ => false, + } +} + +fn path_eq_name(name: Name, path: &Path) -> bool { + !path.global && path.segments.len() == 1 && path.segments[0].name.unhygienize() == name +} + +struct ContainsSelf { + name: Name, + result: bool, +} + +impl<'v> Visitor<'v> for ContainsSelf { + fn visit_name(&mut self, _: Span, name: Name) { + if self.name == name.unhygienize() { + self.result = true; + } + } +} + +fn contains_self(name: Name, expr: &Expr) -> bool { + let mut cs = ContainsSelf { + name: name, + result: false, + }; + cs.visit_expr(expr); + cs.result +} diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs new file mode 100644 index 00000000000..92bce8d0e42 --- /dev/null +++ b/clippy_lints/src/strings.rs @@ -0,0 +1,160 @@ +//! This lint catches both string addition and string addition + assignment +//! +//! Note that since we have two lints where one subsumes the other, we try to +//! disable the subsumed lint unless it has a higher level + +use rustc::hir::*; +use rustc::lint::*; +use syntax::codemap::Spanned; +use utils::SpanlessEq; +use utils::{match_type, paths, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr}; + +/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). +/// +/// **Why is this bad?** It's not really bad, but some people think that the `.push_str(_)` method is more readable. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// +/// ``` +/// let mut x = "Hello".to_owned(); +/// x = x + ", World"; +/// ``` +declare_lint! { + pub STRING_ADD_ASSIGN, + Allow, + "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" +} + +/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match. +/// +/// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code. +/// +/// That said, other people think that String addition, having a long tradition in other languages is actually fine, which is why we decided to make this particular lint `allow` by default. +/// +/// **Known problems:** None +/// +/// **Example:** +/// +/// ``` +/// let x = "Hello".to_owned(); +/// x + ", World" +/// ``` +declare_lint! { + pub STRING_ADD, + Allow, + "using `x + ..` where x is a `String`; suggests using `push_str()` instead" +} + +/// **What it does:** This lint matches the `as_bytes` method called on string +/// literals that contain only ascii characters. +/// +/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`. +/// +/// **Example:** +/// +/// ``` +/// let bs = "a byte string".as_bytes(); +/// ``` +declare_lint! { + pub STRING_LIT_AS_BYTES, + Warn, + "calling `as_bytes` on a string literal; suggests using a byte string literal instead" +} + +#[derive(Copy, Clone)] +pub struct StringAdd; + +impl LintPass for StringAdd { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_ADD, STRING_ADD_ASSIGN) + } +} + +impl LateLintPass for StringAdd { + fn check_expr(&mut self, cx: &LateContext, e: &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) { + // the string_add_assign is allow, so no duplicates + } else { + let parent = get_parent_expr(cx, e); + if let Some(ref p) = parent { + if let ExprAssign(ref target, _) = p.node { + // avoid duplicate matches + if SpanlessEq::new(cx).eq_expr(target, left) { + return; + } + } + } + } + span_lint(cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead"); + } + } else if let ExprAssign(ref target, ref src) = e.node { + if is_string(cx, target) && is_add(cx, src, target) { + span_lint(cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ + `String::push_str()` instead"); + } + } + } +} + +fn is_string(cx: &LateContext, e: &Expr) -> bool { + match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &paths::STRING) +} + +fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { + match src.node { + 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, + } +} + +#[derive(Copy, Clone)] +pub struct StringLitAsBytes; + +impl LintPass for StringLitAsBytes { + fn get_lints(&self) -> LintArray { + lint_array!(STRING_LIT_AS_BYTES) + } +} + +impl LateLintPass for StringLitAsBytes { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + use std::ascii::AsciiExt; + use syntax::ast::LitKind; + use utils::{snippet, in_macro}; + + if let ExprMethodCall(ref name, _, ref args) = e.node { + if name.node.as_str() == "as_bytes" { + if let ExprLit(ref lit) = args[0].node { + if let LitKind::Str(ref lit_content, _) = lit.node { + if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, args[0].span) { + span_lint_and_then(cx, + STRING_LIT_AS_BYTES, + 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); + }); + + } + } + } + } + } + } +} diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs new file mode 100644 index 00000000000..c5572181395 --- /dev/null +++ b/clippy_lints/src/swap.rs @@ -0,0 +1,138 @@ +use rustc::lint::*; +use rustc::hir::*; +use syntax::codemap::mk_sp; +use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; + +/// **What it does:** This lints manual swapping. +/// +/// **Why is this bad?** The `std::mem::swap` function exposes the intent better without +/// deinitializing or copying either variable. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// let t = b; +/// b = a; +/// a = t; +/// ``` +declare_lint! { + pub MANUAL_SWAP, + Warn, + "manual swap" +} + +/// **What it does:** This lints `foo = bar; bar = foo` sequences. +/// +/// **Why is this bad?** This looks like a failed attempt to swap. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// a = b; +/// b = a; +/// ``` +declare_lint! { + pub ALMOST_SWAPPED, + Warn, + "`foo = bar; bar = foo` sequence" +} + +#[derive(Copy,Clone)] +pub struct Swap; + +impl LintPass for Swap { + fn get_lints(&self) -> LintArray { + lint_array![MANUAL_SWAP, ALMOST_SWAPPED] + } +} + +impl LateLintPass for Swap { + fn check_block(&mut self, cx: &LateContext, block: &Block) { + check_manual_swap(cx, block); + check_suspicious_swap(cx, block); + } +} + +/// Implementation of the `MANUAL_SWAP` lint. +fn check_manual_swap(cx: &LateContext, block: &Block) { + for w in block.stmts.windows(3) { + if_let_chain!{[ + // let t = foo(); + let StmtDecl(ref tmp, _) = w[0].node, + let DeclLocal(ref tmp) = tmp.node, + let Some(ref tmp_init) = tmp.init, + let PatKind::Ident(_, ref tmp_name, None) = tmp.pat.node, + + // foo() = bar(); + let StmtSemi(ref first, _) = w[1].node, + let ExprAssign(ref lhs1, ref rhs1) = first.node, + + // bar() = t; + let StmtSemi(ref second, _) = w[2].node, + let ExprAssign(ref lhs2, ref rhs2) = second.node, + let ExprPath(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) + ], { + let (what, lhs, rhs) = if let (Some(first), Some(second)) = (snippet_opt(cx, lhs1.span), snippet_opt(cx, rhs1.span)) { + (format!(" `{}` and `{}`", first, second), first, second) + } else { + ("".to_owned(), "".to_owned(), "".to_owned()) + }; + + let span = mk_sp(tmp.span.lo, second.span.hi); + + span_lint_and_then(cx, + MANUAL_SWAP, + span, + &format!("this looks like you are swapping{} manually", what), + |db| { + if !what.is_empty() { + db.span_suggestion(span, "try", + format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); + db.note("or maybe you should use `std::mem::replace`?"); + } + }); + }} + } +} + +/// Implementation of the `ALMOST_SWAPPED` lint. +fn check_suspicious_swap(cx: &LateContext, block: &Block) { + for w in block.stmts.windows(2) { + if_let_chain!{[ + let StmtSemi(ref first, _) = w[0].node, + let StmtSemi(ref second, _) = w[1].node, + !differing_macro_contexts(first.span, second.span), + let ExprAssign(ref lhs0, ref rhs0) = first.node, + let ExprAssign(ref lhs1, ref rhs1) = second.node, + 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)) = (snippet_opt(cx, lhs0.span), snippet_opt(cx, rhs0.span)) { + (format!(" `{}` and `{}`", first, second), first, second) + } else { + ("".to_owned(), "".to_owned(), "".to_owned()) + }; + + let span = mk_sp(first.span.lo, second.span.hi); + + span_lint_and_then(cx, + ALMOST_SWAPPED, + span, + &format!("this looks like you are trying to swap{}", what), + |db| { + if !what.is_empty() { + db.span_suggestion(span, "try", + format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); + db.note("or maybe you should use `std::mem::replace`?"); + } + }); + }} + } +} diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs new file mode 100644 index 00000000000..1496a45dac2 --- /dev/null +++ b/clippy_lints/src/temporary_assignment.rs @@ -0,0 +1,49 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; +use utils::is_adjusted; +use utils::span_lint; + +/// **What it does:** This lint checks for construction of a structure or tuple just to assign a value in it. +/// +/// **Why is this bad?** Readability. If the structure is only created to be updated, why not write the structure you want in the first place? +/// +/// **Known problems:** None. +/// +/// **Example:** `(0, 0).0 = 1` +declare_lint! { + pub TEMPORARY_ASSIGNMENT, + Warn, + "assignments to temporaries" +} + +fn is_temporary(expr: &Expr) -> bool { + match expr.node { + ExprStruct(..) | ExprTup(..) => true, + _ => false, + } +} + +#[derive(Copy, Clone)] +pub struct TemporaryAssignmentPass; + +impl LintPass for TemporaryAssignmentPass { + fn get_lints(&self) -> LintArray { + lint_array!(TEMPORARY_ASSIGNMENT) + } +} + +impl LateLintPass for TemporaryAssignmentPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprAssign(ref target, _) = expr.node { + match target.node { + ExprField(ref base, _) | + ExprTupField(ref base, _) => { + 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 new file mode 100644 index 00000000000..2217fd59bd9 --- /dev/null +++ b/clippy_lints/src/transmute.rs @@ -0,0 +1,131 @@ +use rustc::lint::*; +use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; +use rustc::ty; +use rustc::hir::*; +use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; + +/// **What it does:** This lint checks for transmutes to the original type of the object. +/// +/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type. +/// +/// **Known problems:** None. +/// +/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s. +declare_lint! { + pub USELESS_TRANSMUTE, + Warn, + "transmutes that have the same to and from types" +} + +/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`. +/// +/// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type. +/// +/// **Known problems:** None. +/// +/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `*t` or `&t`'s. +declare_lint! { + pub CROSSPOINTER_TRANSMUTE, + Warn, + "transmutes that have to or from types that are a pointer to the other" +} + +/// **What it does:*** This lint checks for transmutes from a pointer to a reference. +/// +/// **Why is this bad?** This can always be rewritten with `&` and `*`. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _: &T = std::mem::transmute(p); // where p: *const T +/// // can be written: +/// let _: &T = &*p; +/// ``` +declare_lint! { + pub TRANSMUTE_PTR_TO_REF, + Warn, + "transmutes from a pointer to a reference type" +} + +pub struct Transmute; + +impl LintPass for Transmute { + fn get_lints(&self) -> LintArray { + lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE] + } +} + +impl LateLintPass for Transmute { + fn check_expr(&mut self, cx: &LateContext, e: &Expr) { + if let ExprCall(ref path_expr, ref args) = e.node { + if let ExprPath(None, _) = path_expr.node { + let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); + + if match_def_path(cx, def_id, &paths::TRANSMUTE) { + let from_ty = cx.tcx.expr_ty(&args[0]); + let to_ty = cx.tcx.expr_ty(e); + + if from_ty == to_ty { + span_lint(cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty)); + } else if is_ptr_to(to_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)); + } else if is_ptr_to(from_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)); + } else { + check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]); + } + } + } + } + } +} + +fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool { + if let TyRawPtr(from_ptr) = from.sty { + from_ptr.ty == to + } else { + false + } +} + +fn check_ptr_to_ref<'tcx>(cx: &LateContext, from_ty: ty::Ty<'tcx>, to_ty: ty::Ty<'tcx>, e: &Expr, arg: &Expr) { + if let TyRawPtr(ref from_pty) = from_ty.sty { + if let TyRef(_, ref to_rty) = to_ty.sty { + let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)", + from_ty, + to_ty); + span_lint_and_then(cx, TRANSMUTE_PTR_TO_REF, e.span, &mess, |db| { + if let Some(arg) = snippet_opt(cx, arg.span) { + let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable { + ("&mut *", "*mut") + } else { + ("&*", "*const") + }; + + + let sugg = if from_pty.ty == to_rty.ty { + format!("{}{}", deref, arg) + } else { + format!("{}({} as {} {})", deref, arg, cast, to_rty.ty) + }; + + db.span_suggestion(e.span, "try", sugg); + } + }); + } + } +} diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs new file mode 100644 index 00000000000..c4b810a7880 --- /dev/null +++ b/clippy_lints/src/types.rs @@ -0,0 +1,974 @@ +use reexport::*; +use rustc::hir::*; +use rustc::hir::intravisit::{FnKind, Visitor, walk_ty}; +use rustc::lint::*; +use rustc::ty; +use std::cmp::Ordering; +use syntax::ast::{IntTy, UintTy, FloatTy}; +use syntax::codemap::Span; +use utils::{comparisons, in_external_macro, in_macro, is_from_for_desugar, match_def_path, snippet, + span_help_and_lint, span_lint}; +use utils::paths; + +/// Handles all the linting of funky types +#[allow(missing_copy_implementations)] +pub struct TypePass; + +/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. +/// +/// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever. +/// +/// **Known problems:** None +/// +/// **Example:** `struct X { values: Box<Vec<Foo>> }` +declare_lint! { + pub BOX_VEC, Warn, + "usage of `Box<Vec<T>>`, vector elements are already on the heap" +} + +/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). +/// +/// **Why is this bad?** Gankro says: +/// +/// >The TL;DR of `LinkedList` is that it's built on a massive amount of pointers and indirection. It wastes memory, it has terrible cache locality, and is all-around slow. `RingBuf`, while "only" amortized for push/pop, should be faster in the general case for almost every possible workload, and isn't even amortized at all if you can predict the capacity you need. +/// > +/// > `LinkedList`s are only really good if you're doing a lot of merging or splitting of lists. This is because they can just mangle some pointers instead of actually copying the data. Even if you're doing a lot of insertion in the middle of the list, `RingBuf` can still be better because of how expensive it is to seek to the middle of a `LinkedList`. +/// +/// **Known problems:** False positives – the instances where using a `LinkedList` makes sense are few and far between, but they can still happen. +/// +/// **Example:** `let x = LinkedList::new();` +declare_lint! { + pub LINKEDLIST, Warn, + "usage of LinkedList, usually a vector is faster, or a more specialized data \ + structure like a VecDeque" +} + +impl LintPass for TypePass { + fn get_lints(&self) -> LintArray { + lint_array!(BOX_VEC, LINKEDLIST) + } +} + +impl LateLintPass for TypePass { + fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) { + if in_macro(cx, ast_ty.span) { + return; + } + if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) { + if let def::Def::Struct(..) = did.full_def() { + if Some(did.def_id()) == cx.tcx.lang_items.owned_box() { + 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.def_id(), &paths::VEC), + ], + { + span_help_and_lint(cx, + BOX_VEC, + ast_ty.span, + "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", + "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); + } + } + } else if match_def_path(cx, did.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"); + } + } + } + } +} + +#[allow(missing_copy_implementations)] +pub struct LetPass; + +/// **What it does:** This lint checks for binding a unit value. +/// +/// **Why is this bad?** A unit value cannot usefully be used anywhere. So binding one is kind of pointless. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = { 1; };` +declare_lint! { + pub LET_UNIT_VALUE, Warn, + "creating a let binding to a value of unit type, which usually can't be used afterwards" +} + +fn check_let_unit(cx: &LateContext, decl: &Decl) { + if let DeclLocal(ref local) = decl.node { + let bindtype = &cx.tcx.pat_ty(&local.pat).sty; + if *bindtype == ty::TyTuple(&[]) { + if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) { + return; + } + if is_from_for_desugar(decl) { + return; + } + span_lint(cx, + LET_UNIT_VALUE, + decl.span, + &format!("this let-binding has unit value. Consider omitting `let {} =`", + snippet(cx, local.pat.span, ".."))); + } + } +} + +impl LintPass for LetPass { + fn get_lints(&self) -> LintArray { + lint_array!(LET_UNIT_VALUE) + } +} + +impl LateLintPass for LetPass { + fn check_decl(&mut self, cx: &LateContext, decl: &Decl) { + check_let_unit(cx, decl) + } +} + +/// **What it does:** This lint checks for comparisons to unit. +/// +/// **Why is this bad?** Unit is always equal to itself, and thus is just a clumsily written constant. Mostly this happens when someone accidentally adds semicolons at the end of the operands. +/// +/// **Known problems:** None +/// +/// **Example:** `if { foo(); } == { bar(); } { baz(); }` is equal to `{ foo(); bar(); baz(); }` +declare_lint! { + pub UNIT_CMP, Warn, + "comparing unit values (which is always `true` or `false`, respectively)" +} + +#[allow(missing_copy_implementations)] +pub struct UnitCmp; + +impl LintPass for UnitCmp { + fn get_lints(&self) -> LintArray { + lint_array!(UNIT_CMP) + } +} + +impl LateLintPass for UnitCmp { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if in_macro(cx, expr.span) { + return; + } + if let ExprBinary(ref cmp, ref left, _) = expr.node { + let op = cmp.node; + let sty = &cx.tcx.expr_ty(left).sty; + if *sty == ty::TyTuple(&[]) && op.is_comparison() { + let result = match op { + BiEq | BiLe | BiGe => "true", + _ => "false", + }; + span_lint(cx, + UNIT_CMP, + expr.span, + &format!("{}-comparison of unit values detected. This will always be {}", + op.as_str(), + result)); + } + } + } +} + +pub struct CastPass; + +/// **What it does:** This lint checks for casts from any numerical to a float type where the receiving type cannot store all values from the original type without rounding errors. This possible rounding is to be expected, so this lint is `Allow` by default. +/// +/// Basically, this warns on casting any integer with 32 or more bits to `f32` or any 64-bit integer to `f64`. +/// +/// **Why is this bad?** It's not bad at all. But in some applications it can be helpful to know where precision loss can take place. This lint can help find those places in the code. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = u64::MAX; x as f64` +declare_lint! { + pub CAST_PRECISION_LOSS, Allow, + "casts that cause loss of precision, e.g `x as f32` where `x: u64`" +} + +/// **What it does:** This lint checks for casts from a signed to an unsigned numerical type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default. +/// +/// **Why is this bad?** Possibly surprising results. You can activate this lint as a one-time check to see where numerical wrapping can arise. +/// +/// **Known problems:** None +/// +/// **Example:** `let y : i8 = -1; y as u64` will return 18446744073709551615 +declare_lint! { + pub CAST_SIGN_LOSS, Allow, + "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`" +} + +/// **What it does:** This lint checks for on casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by default. +/// +/// **Why is this bad?** In some problem domains, it is good practice to avoid truncation. This lint can be activated to help assess where additional checks could be beneficial. +/// +/// **Known problems:** None +/// +/// **Example:** `fn as_u8(x: u64) -> u8 { x as u8 }` +declare_lint! { + pub CAST_POSSIBLE_TRUNCATION, Allow, + "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`" +} + +/// **What it does:** This lint checks for casts from an unsigned type to a signed type of the same size. Performing such a cast is a 'no-op' for the compiler, i.e. nothing is changed at the bit level, and the binary representation of the value is reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default. +/// +/// **Why is this bad?** While such a cast is not bad in itself, the results can be surprising when this is not the intended behavior, as demonstrated by the example below. +/// +/// **Known problems:** None +/// +/// **Example:** `u32::MAX as i32` will yield a value of `-1`. +declare_lint! { + pub CAST_POSSIBLE_WRAP, Allow, + "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`" +} + +/// Returns the size in bits of an integral type. +/// Will return 0 if the type is not an int or uint variant +fn int_ty_to_nbits(typ: &ty::TyS) -> usize { + let n = match typ.sty { + ty::TyInt(i) => 4 << (i as usize), + ty::TyUint(u) => 4 << (u as usize), + _ => 0, + }; + // n == 4 is the usize/isize case + if n == 4 { + ::std::mem::size_of::<usize>() * 8 + } else { + n + } +} + +fn is_isize_or_usize(typ: &ty::TyS) -> bool { + match typ.sty { + ty::TyInt(IntTy::Is) | + ty::TyUint(UintTy::Us) => true, + _ => false, + } +} + +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 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 { + "64".to_owned() + } else if is_isize_or_usize(cast_from) { + "32 or 64".to_owned() + } else { + int_ty_to_nbits(cast_from).to_string() + }; + span_lint(cx, + CAST_PRECISION_LOSS, + expr.span, + &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 arch_dependent { + arch_dependent_str + } else { + "" + }, + from_nbits_str, + mantissa_nbits)); +} + +enum ArchSuffix { + _32, + _64, + None, +} + +fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { + let arch_64_suffix = " on targets with 64-bit wide pointers"; + let arch_32_suffix = " on targets with 32-bit wide pointers"; + let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); + let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to)); + let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), + is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => { + (to_nbits < from_nbits, + 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 + }, + 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 + }) + } + }; + if span_truncation { + span_lint(cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + &format!("casting {} to {} may truncate the value{}", + cast_from, + cast_to, + match suffix_truncation { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + })); + } + if span_wrap { + span_lint(cx, + CAST_POSSIBLE_WRAP, + expr.span, + &format!("casting {} to {} may wrap around the value{}", + cast_from, + cast_to, + match suffix_wrap { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + })); + } +} + +impl LintPass for CastPass { + fn get_lints(&self) -> LintArray { + lint_array!(CAST_PRECISION_LOSS, + CAST_SIGN_LOSS, + CAST_POSSIBLE_TRUNCATION, + CAST_POSSIBLE_WRAP) + } +} + +impl LateLintPass for CastPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprCast(ref ex, _) = expr.node { + let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr)); + if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { + match (cast_from.is_integral(), cast_to.is_integral()) { + (true, false) => { + let from_nbits = int_ty_to_nbits(cast_from); + let to_nbits = if let ty::TyFloat(FloatTy::F32) = cast_to.sty { + 32 + } else { + 64 + }; + 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, + expr.span, + &format!("casting {} to {} may truncate the value", cast_from, cast_to)); + if !cast_to.is_signed() { + span_lint(cx, + CAST_SIGN_LOSS, + 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, + CAST_SIGN_LOSS, + expr.span, + &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) { + span_lint(cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + "casting f64 to f32 may truncate the value"); + } + } + } + } + } + } +} + +/// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold. +/// +/// **Why is this bad?** Too complex types make the code less readable. Consider using a `type` definition to simplify them. +/// +/// **Known problems:** None +/// +/// **Example:** `struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }` +declare_lint! { + pub TYPE_COMPLEXITY, Warn, + "usage of very complex types; recommends factoring out parts into `type` definitions" +} + +#[allow(missing_copy_implementations)] +pub struct TypeComplexityPass { + threshold: u64, +} + +impl TypeComplexityPass { + pub fn new(threshold: u64) -> Self { + TypeComplexityPass { threshold: threshold } + } +} + +impl LintPass for TypeComplexityPass { + fn get_lints(&self) -> LintArray { + lint_array!(TYPE_COMPLEXITY) + } +} + +impl LateLintPass for TypeComplexityPass { + fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + self.check_fndecl(cx, decl); + } + + fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { + // enum variants are also struct fields now + self.check_type(cx, &field.ty); + } + + fn check_item(&mut self, cx: &LateContext, item: &Item) { + match item.node { + ItemStatic(ref ty, _, _) | + ItemConst(ref ty, _) => self.check_type(cx, ty), + // functions, enums, structs, impls and traits are covered + _ => (), + } + } + + fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + match item.node { + ConstTraitItem(ref ty, _) | + TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty), + MethodTraitItem(MethodSig { ref decl, .. }, None) => self.check_fndecl(cx, decl), + // methods with default impl are covered by check_fn + _ => (), + } + } + + fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { + match item.node { + ImplItemKind::Const(ref ty, _) | + ImplItemKind::Type(ref ty) => self.check_type(cx, ty), + // methods are covered by check_fn + _ => (), + } + } + + fn check_local(&mut self, cx: &LateContext, local: &Local) { + if let Some(ref ty) = local.ty { + self.check_type(cx, ty); + } + } +} + +impl TypeComplexityPass { + fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) { + for arg in &decl.inputs { + self.check_type(cx, &arg.ty); + } + if let Return(ref ty) = decl.output { + self.check_type(cx, ty); + } + } + + fn check_type(&self, cx: &LateContext, ty: &Ty) { + if in_macro(cx, ty.span) { + return; + } + let score = { + let mut visitor = TypeComplexityVisitor { + score: 0, + nest: 1, + }; + visitor.visit_ty(ty); + visitor.score + }; + + if score > self.threshold { + span_lint(cx, + TYPE_COMPLEXITY, + ty.span, + "very complex type used. Consider factoring parts into `type` definitions"); + } + } +} + +/// Walks a type and assigns a complexity score to it. +struct TypeComplexityVisitor { + /// total complexity score of the type + score: u64, + /// current nesting level + nest: u64, +} + +impl<'v> Visitor<'v> for TypeComplexityVisitor { + fn visit_ty(&mut self, ty: &'v 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(..) | + TyVec(..) | + TyTup(..) | + TyFixedLengthVec(..) => (10 * self.nest, 1), + + // "Sum" of trait bounds + TyObjectSum(..) => (20 * self.nest, 0), + + // function types and "for<...>" bring a lot of overhead + TyBareFn(..) | + TyPolyTraitRef(..) => (50 * self.nest, 1), + + _ => (0, 0), + }; + self.score += add_score; + self.nest += sub_nest; + walk_ty(self, ty); + self.nest -= sub_nest; + } +} + +/// **What it does:** This lint points out expressions where a character literal is casted to `u8` and suggests using a byte literal instead. +/// +/// **Why is this bad?** In general, casting values to smaller types is error-prone and should be avoided where possible. In the particular case of converting a character literal to u8, it is easy to avoid by just using a byte literal instead. As an added bonus, `b'a'` is even slightly shorter than `'a' as u8`. +/// +/// **Known problems:** None +/// +/// **Example:** `'x' as u8` +declare_lint! { + pub CHAR_LIT_AS_U8, Warn, + "Casting a character literal to u8" +} + +pub struct CharLitAsU8; + +impl LintPass for CharLitAsU8 { + fn get_lints(&self) -> LintArray { + lint_array!(CHAR_LIT_AS_U8) + } +} + +impl LateLintPass for CharLitAsU8 { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + use syntax::ast::{LitKind, UintTy}; + + if let ExprCast(ref e, _) = expr.node { + if let ExprLit(ref l) = e.node { + if let LitKind::Char(_) = l.node { + if ty::TyUint(UintTy::U8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { + 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'")); + span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); + } + } + } + } + } +} + +/// **What it does:** This lint checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked. +/// +/// **Why is this bad?** An expression like `min <= x` may misleadingly imply that is is possible for `x` to be less than the minimum. Expressions like `max < x` are probably mistakes. +/// +/// **Known problems:** None +/// +/// **Example:** `vec.len() <= 0`, `100 > std::i32::MAX` +declare_lint! { + pub ABSURD_EXTREME_COMPARISONS, Warn, + "a comparison involving a maximum or minimum value involves a case that is always \ + true or always false" +} + +pub struct AbsurdExtremeComparisons; + +impl LintPass for AbsurdExtremeComparisons { + fn get_lints(&self) -> LintArray { + lint_array!(ABSURD_EXTREME_COMPARISONS) + } +} + +enum ExtremeType { + Minimum, + Maximum, +} + +struct ExtremeExpr<'a> { + which: ExtremeType, + expr: &'a Expr, +} + +enum AbsurdComparisonResult { + AlwaysFalse, + AlwaysTrue, + InequalityImpossible, +} + + + +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 { + val + } else { + return None; + }; + + let lx = detect_extreme_expr(cx, normalized_lhs); + let rx = detect_extreme_expr(cx, normalized_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 + _ => 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 + _ => return None, + } + } + Rel::Ne | Rel::Eq => return None, + }) +} + +fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> { + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::*; + use rustc_const_eval::EvalHint::ExprTypeChecked; + use rustc_const_eval::*; + use types::ExtremeType::*; + + let ty = &cx.tcx.expr_ty(expr).sty; + + match *ty { + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (), + _ => return None, + }; + + let cv = match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + Ok(val) => val, + Err(_) => return None, + }; + + let which = match (ty, cv) { + (&ty::TyBool, Bool(false)) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) | + (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) | + (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) | + (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) | + (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) | + (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) | + (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) | + (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MIN))) | + (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum, + + (&ty::TyBool, Bool(true)) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) | + (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) | + (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) | + (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) | + (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) | + (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) | + (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) | + (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) | + (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) | + (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) | + (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) => Maximum, + + _ => return None, + }; + Some(ExtremeExpr { + which: which, + expr: expr, + }) +} + +impl LateLintPass for AbsurdExtremeComparisons { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + use types::ExtremeType::*; + use types::AbsurdComparisonResult::*; + + if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { + if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { + if !in_macro(cx, expr.span) { + let msg = "this comparison involving the minimum or maximum element for this \ + type contains a case that is always true or always false"; + + let conclusion = match result { + AlwaysFalse => "this comparison is always false".to_owned(), + AlwaysTrue => "this comparison is always true".to_owned(), + InequalityImpossible => { + format!("the case where the two sides are not equal never occurs, consider using {} == {} \ + instead", + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs")) + } + }; + + let help = format!("because {} is the {} value for this type, {}", + snippet(cx, culprit.expr.span, "x"), + match culprit.which { + Minimum => "minimum", + Maximum => "maximum", + }, + conclusion); + + span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); + } + } + } + } +} + +/// **What it does:** This lint checks for comparisons where the relation is always either true or false, but where one side has been upcast so that the comparison is necessary. Only integer types are checked. +/// +/// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` will mistakenly imply that it is possible for `x` to be outside the range of `u8`. +/// +/// **Known problems:** https://github.com/Manishearth/rust-clippy/issues/886 +/// +/// **Example:** `let x : u8 = ...; (x as u32) > 300` +declare_lint! { + pub INVALID_UPCAST_COMPARISONS, Allow, + "a comparison involving an upcast which is always true or false" +} + +pub struct InvalidUpcastComparisons; + +impl LintPass for InvalidUpcastComparisons { + fn get_lints(&self) -> LintArray { + lint_array!(INVALID_UPCAST_COMPARISONS) + } +} + +#[derive(Copy, Clone, Debug, Eq)] +enum FullInt { + S(i64), + U(u64), +} + +impl FullInt { + #[allow(cast_sign_loss)] + fn cmp_s_u(s: i64, u: u64) -> Ordering { + if s < 0 { + Ordering::Less + } else if u > (i64::max_value() as u64) { + Ordering::Greater + } else { + (s as u64).cmp(&u) + } + } +} + +impl PartialEq for FullInt { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal + } +} + +impl PartialOrd for FullInt { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(match (self, other) { + (&FullInt::S(s), &FullInt::S(o)) => s.cmp(&o), + (&FullInt::U(s), &FullInt::U(o)) => s.cmp(&o), + (&FullInt::S(s), &FullInt::U(o)) => Self::cmp_s_u(s, o), + (&FullInt::U(s), &FullInt::S(o)) => Self::cmp_s_u(o, s).reverse(), + }) + } +} +impl Ord for FullInt { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).expect("partial_cmp for FullInt can never return None") + } +} + + +fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { + use rustc::ty::TypeVariants::{TyInt, TyUint}; + use syntax::ast::{IntTy, UintTy}; + use std::*; + + if let ExprCast(ref cast_exp, _) = expr.node { + match cx.tcx.expr_ty(cast_exp).sty { + TyInt(int_ty) => { + Some(match int_ty { + IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)), + IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)), + IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)), + 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)), + UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)), + UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)), + 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 { + None + } +} + +fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { + use rustc::middle::const_val::ConstVal::*; + use rustc_const_eval::EvalHint::ExprTypeChecked; + use rustc_const_eval::eval_const_expr_partial; + use rustc_const_math::ConstInt; + + match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { + Ok(val) => { + if let Integral(const_int) = val { + Some(match const_int.erase_type() { + ConstInt::InferSigned(x) => FullInt::S(x as i64), + ConstInt::Infer(x) => FullInt::U(x as u64), + _ => unreachable!(), + }) + } else { + None + } + } + Err(_) => None, + } +} + +fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) { + if let ExprCast(ref cast_val, _) = expr.node { + span_lint(cx, + INVALID_UPCAST_COMPARISONS, + *span, + &format!( + "because of the numeric bounds on `{}` prior to casting, this expression is always {}", + snippet(cx, cast_val.span, "the expression"), + if always { "true" } else { "false" }, + )); + } +} + +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 { + if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { + if rel == Rel::Eq || rel == Rel::Ne { + if norm_rhs_val < lb || norm_rhs_val > ub { + err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); + } + } else if match rel { + Rel::Lt => { + if invert { + norm_rhs_val < lb + } 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) + } else if match rel { + Rel::Lt => { + if invert { + norm_rhs_val >= ub + } 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) + } + } + } +} + +impl LateLintPass for InvalidUpcastComparisons { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { + + let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); + let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { + val + } else { + return; + }; + + let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); + let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); + + upcast_comparison_bounds_err(cx, &expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false); + upcast_comparison_bounds_err(cx, &expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true); + } + } +} diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs new file mode 100644 index 00000000000..8271fd3ed66 --- /dev/null +++ b/clippy_lints/src/unicode.rs @@ -0,0 +1,109 @@ +use rustc::lint::*; +use rustc::hir::*; +use syntax::ast::LitKind; +use syntax::codemap::Span; +use unicode_normalization::UnicodeNormalization; +use utils::{snippet, span_help_and_lint}; + +/// **What it does:** This lint checks for the unicode zero-width space in the code. +/// +/// **Why is this bad?** Having an invisible character in the code makes for all sorts of April fools, but otherwise is very much frowned upon. +/// +/// **Known problems:** None +/// +/// **Example:** You don't see it, but there may be a zero-width space somewhere in this text. +declare_lint! { + pub ZERO_WIDTH_SPACE, Deny, + "using a zero-width space in a string literal, which is confusing" +} + +/// **What it does:** This lint checks for non-ascii characters in string literals. +/// +/// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset back. Even so, there still are editors and other programs out there that don't work well with unicode. So if the code is meant to be used internationally, on multiple operating systems, or has other portability requirements, activating this lint could be useful. +/// +/// **Known problems:** None +/// +/// **Example:** `let x = "Hä?"` +declare_lint! { + pub NON_ASCII_LITERAL, Allow, + "using any literal non-ASCII chars in a string literal; suggests \ + using the \\u escape instead" +} + +/// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). +/// +/// **Why is this bad?** If such a string is compared to another, the results may be surprising. +/// +/// **Known problems** None +/// +/// **Example:** You may not see it, but "à" and "à" aren't the same string. The former when escaped is actually "a\u{300}" while the latter is "\u{e0}". +declare_lint! { + pub UNICODE_NOT_NFC, Allow, + "using a unicode literal not in NFC normal form (see \ + [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" +} + + +#[derive(Copy, Clone)] +pub struct Unicode; + +impl LintPass for Unicode { + fn get_lints(&self) -> LintArray { + lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC) + } +} + +impl LateLintPass for Unicode { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if let ExprLit(ref lit) = expr.node { + if let LitKind::Str(_, _) = lit.node { + check_str(cx, lit.span) + } + } + } +} + +fn escape<T: Iterator<Item = char>>(s: T) -> String { + let mut result = String::new(); + for c in s { + if c as u32 > 0x7F { + for d in c.escape_unicode() { + result.push(d) + } + } else { + result.push(c); + } + } + result +} + +fn check_str(cx: &LateContext, span: Span) { + let string = snippet(cx, span, ""); + if string.contains('\u{200B}') { + span_help_and_lint(cx, + ZERO_WIDTH_SPACE, + span, + "zero-width space detected", + &format!("Consider replacing the string with:\n\"{}\"", + string.replace("\u{200B}", "\\u{200B}"))); + } + if string.chars().any(|c| c as u32 > 0x7F) { + span_help_and_lint(cx, + NON_ASCII_LITERAL, + span, + "literal non-ASCII character detected", + &format!("Consider replacing the string with:\n\"{}\"", + if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { + escape(string.chars()) + } else { + escape(string.nfc()) + })); + } + if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && string.chars().zip(string.nfc()).any(|(a, b)| a != b) { + span_help_and_lint(cx, + UNICODE_NOT_NFC, + span, + "non-nfc unicode sequence detected", + &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>())); + } +} diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs new file mode 100644 index 00000000000..3de6719c546 --- /dev/null +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -0,0 +1,81 @@ +use rustc::hir::*; +use rustc::lint::*; +use syntax::ast::Name; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::span_lint; + +/// **What it does:** This lint checks for imports that remove "unsafe" from an item's name +/// +/// **Why is this bad?** Renaming makes it less clear which traits and structures are unsafe. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// use std::cell::{UnsafeCell as TotallySafeCell}; +/// +/// extern crate crossbeam; +/// use crossbeam::{spawn_unsafe as spawn}; +/// ``` +declare_lint! { + pub UNSAFE_REMOVED_FROM_NAME, + Warn, + "unsafe removed from name" +} + +pub struct UnsafeNameRemoval; + +impl LintPass for UnsafeNameRemoval { + fn get_lints(&self) -> LintArray { + lint_array!(UNSAFE_REMOVED_FROM_NAME) + } +} + +impl LateLintPass for UnsafeNameRemoval { + fn check_item(&mut self, cx: &LateContext, item: &Item) { + if let ItemUse(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 + ); + }, + ViewPath_::ViewPathList(_, ref path_list_items) => { + for path_list_item in path_list_items.iter() { + let plid = path_list_item.node; + if let (Some(name), Some(rename)) = (plid.name(), plid.rename()) { + unsafe_to_safe_check(name, rename, cx, &item.span); + }; + } + }, + 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(); + 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 + )); + } +} + +fn contains_unsafe(name: &InternedString) -> bool { + name.contains("Unsafe") || name.contains("unsafe") +} diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs new file mode 100644 index 00000000000..d408f16a371 --- /dev/null +++ b/clippy_lints/src/unused_label.rs @@ -0,0 +1,78 @@ +use rustc::lint::*; +use rustc::hir; +use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; +use std::collections::HashMap; +use syntax::ast; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::{in_macro, span_lint}; + +/// **What it does:** This lint checks for unused labels. +/// +/// **Why is this bad?** Maybe the label should be used in which case there is an error in the +/// code or it should be removed. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// ```rust,ignore +/// fn unused_label() { +/// 'label: for i in 1..2 { +/// if i > 4 { continue } +/// } +/// ``` +declare_lint! { + pub UNUSED_LABEL, + Warn, + "unused label" +} + +pub struct UnusedLabel; + +#[derive(Default)] +struct UnusedLabelVisitor { + labels: HashMap<InternedString, Span>, +} + +impl UnusedLabelVisitor { + pub fn new() -> UnusedLabelVisitor { + ::std::default::Default::default() + } +} + +impl LintPass for UnusedLabel { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_LABEL) + } +} + +impl LateLintPass for UnusedLabel { + fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Block, span: Span, _: ast::NodeId) { + if in_macro(cx, span) { + return; + } + + let mut v = UnusedLabelVisitor::new(); + walk_fn(&mut v, kind, decl, body, span); + + for (label, span) in v.labels { + span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); + } + } +} + +impl<'v> Visitor<'v> for UnusedLabelVisitor { + fn visit_expr(&mut self, expr: &hir::Expr) { + match expr.node { + hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { + self.labels.remove(&label.node.as_str()); + } + hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { + self.labels.insert(label.as_str(), expr.span); + } + _ => (), + } + + walk_expr(self, expr); + } +} diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs new file mode 100644 index 00000000000..b890a363fb7 --- /dev/null +++ b/clippy_lints/src/utils/comparisons.rs @@ -0,0 +1,23 @@ +use rustc::hir::{BinOp_, Expr}; + +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum Rel { + Lt, + Le, + Eq, + Ne, +} + +/// Put the expression in the form `lhs < rhs` or `lhs <= rhs`. +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)), + BinOp_::BiGt => Some((Rel::Lt, rhs, lhs)), + BinOp_::BiGe => Some((Rel::Le, rhs, lhs)), + BinOp_::BiEq => Some((Rel::Eq, rhs, lhs)), + BinOp_::BiNe => Some((Rel::Ne, rhs, lhs)), + _ => None, + } +} diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs new file mode 100644 index 00000000000..e773cc0e025 --- /dev/null +++ b/clippy_lints/src/utils/conf.rs @@ -0,0 +1,205 @@ +use std::{fmt, fs, io}; +use std::io::Read; +use syntax::{ast, codemap, ptr}; +use syntax::parse::token; +use toml; + +/// Get the configuration file from arguments. +pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { + for arg in args { + match arg.node { + ast::MetaItemKind::Word(ref name) | + ast::MetaItemKind::List(ref name, _) => { + if name == &"conf_file" { + return Err(("`conf_file` must be a named value", arg.span)); + } + } + ast::MetaItemKind::NameValue(ref name, ref value) => { + if name == &"conf_file" { + return if let ast::LitKind::Str(ref file, _) = value.node { + Ok(Some(file.clone())) + } else { + Err(("`conf_file` value must be a string", value.span)) + }; + } + } + } + } + + Ok(None) +} + +/// Error from reading a configuration file. +#[derive(Debug)] +pub enum ConfError { + IoError(io::Error), + TomlError(Vec<toml::ParserError>), + TypeError(&'static str, &'static str, &'static str), + UnknownKey(String), +} + +impl fmt::Display for ConfError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + ConfError::IoError(ref err) => err.fmt(f), + ConfError::TomlError(ref errs) => { + let mut first = true; + for err in errs { + if !first { + try!(", ".fmt(f)); + first = false; + } + + try!(err.fmt(f)); + } + + Ok(()) + } + ConfError::TypeError(ref key, ref expected, ref got) => { + write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) + } + ConfError::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), + } + } +} + +impl From<io::Error> for ConfError { + fn from(e: io::Error) -> Self { + ConfError::IoError(e) + } +} + +macro_rules! define_Conf { + ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { + /// Type used to store lint configuration. + pub struct Conf { + $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ + } + + impl Default for Conf { + fn default() -> Conf { + Conf { + $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ + } + } + } + + impl Conf { + /// Set the property `name` (which must be the `toml` name) to the given value + #[allow(cast_sign_loss)] + fn set(&mut self, name: String, value: toml::Value) -> Result<(), ConfError> { + match name.as_str() { + $( + define_Conf!(PAT $toml_name) => { + if let Some(value) = define_Conf!(CONV $($ty)+, value) { + self.$rust_name = value; + } + else { + return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), + stringify!($($ty)+), + value.type_str())); + } + }, + )+ + "third-party" => { + // for external tools such as clippy-service + return Ok(()); + } + _ => { + return Err(ConfError::UnknownKey(name)); + } + } + + Ok(()) + } + } + }; + + // hack to convert tts + (PAT $pat: pat) => { $pat }; + (EXPR $e: expr) => { $e }; + (TY $ty: ty) => { $ty }; + + // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; + (CONV Vec<String>, $value: expr) => {{ + let slice = $value.as_slice(); + + 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().unwrap_or_else(|| unreachable!()).to_owned()).collect()) + } + } + else { + None + } + }}; + + // provide a nicer syntax to declare the default value of `Vec<String>` variables + (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; + (DEFAULT $ty: ty, $e: expr) => { $e }; +} + +define_Conf! { + /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about + ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), + /// 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", "GitHub"] => Vec<String>), + /// 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 + ("type-complexity-threshold", type_complexity_threshold, 250 => u64), + /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have + ("single-char-binding-names-threshold", max_single_char_names, 5 => u64), +} + +/// Read the `toml` configuration file. The function will ignore “File not found” errors iif +/// `!must_exist`, in which case, it will return the default configuration. +/// In case of error, the function tries to continue as much as possible. +pub fn read_conf(path: &str, must_exist: bool) -> (Conf, Vec<ConfError>) { + let mut conf = Conf::default(); + let mut errors = Vec::new(); + + let file = match fs::File::open(path) { + Ok(mut file) => { + let mut buf = String::new(); + + if let Err(err) = file.read_to_string(&mut buf) { + errors.push(err.into()); + return (conf, errors); + } + + buf + } + Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { + return (conf, errors); + } + Err(err) => { + errors.push(err.into()); + return (conf, errors); + } + }; + + let mut parser = toml::Parser::new(&file); + let toml = if let Some(toml) = parser.parse() { + toml + } else { + errors.push(ConfError::TomlError(parser.errors)); + return (conf, errors); + }; + + for (key, value) in toml { + if let Err(err) = conf.set(key, value) { + errors.push(err); + } + } + + (conf, errors) +} diff --git a/clippy_lints/src/utils/hir.rs b/clippy_lints/src/utils/hir.rs new file mode 100644 index 00000000000..0f0a7312ee4 --- /dev/null +++ b/clippy_lints/src/utils/hir.rs @@ -0,0 +1,513 @@ +use consts::constant; +use rustc::lint::*; +use rustc::hir::*; +use std::hash::{Hash, Hasher, SipHasher}; +use syntax::ast::Name; +use syntax::ptr::P; +use utils::differing_macro_contexts; + +/// Type used to check whether two ast are the same. This is different from the operator +/// `==` on ast types as this operator would compare true equality with ID and span. +/// +/// Note that some expressions kinds are not considered but could be added. +pub struct SpanlessEq<'a, 'tcx: 'a> { + /// Context used to evaluate constant expressions. + cx: &'a LateContext<'a, 'tcx>, + /// If is true, never consider as equal expressions containing function calls. + ignore_fn: bool, +} + +impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { + pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + SpanlessEq { + cx: cx, + ignore_fn: false, + } + } + + pub fn ignore_fn(self) -> Self { + SpanlessEq { + cx: self.cx, + ignore_fn: true, + } + } + + /// Check whether two statements are the same. + pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool { + match (&left.node, &right.node) { + (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { + if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { + // TODO: tys + l.ty.is_none() && r.ty.is_none() && 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, + } + } + + /// Check whether two blocks are the same. + pub fn eq_block(&self, left: &Block, right: &Block) -> bool { + over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && + both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) + } + + pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { + if self.ignore_fn && differing_macro_contexts(left.span, right.span) { + return false; + } + + if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) { + if l == r { + return true; + } + } + + 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()), + (&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), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()), + (&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)) => 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), &ExprLoop(ref rb, ref rl)) => { + self.eq_block(lb, rb) && both(ll, rl, |l, r| l.as_str() == r.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)) => { + // TODO: tys + !self.ignore_fn && l_name.node == r_name.node && l_tys.is_empty() && r_tys.is_empty() && + 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) + } + (&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)) && + 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), + (&ExprVec(ref l), &ExprVec(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.as_str() == r.as_str()) + } + _ => false, + } + } + + fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool { + over(left, right, |l, r| self.eq_expr(l, r)) + } + + fn eq_field(&self, left: &Field, right: &Field) -> bool { + left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr) + } + + /// Check whether two patterns are the same. + pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { + match (&left.node, &right.node) { + (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), + (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => { + self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r))) + } + (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(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::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), + (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { + self.eq_qself(ls, rs) && self.eq_path(lp, rp) + } + (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => 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::Vec(ref ls, ref li, ref le), &PatKind::Vec(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_path(&self, left: &Path, right: &Path) -> bool { + // The == of idents doesn't work with different contexts, + // we have to be explicit about hygiene + left.global == right.global && + over(&left.segments, + &right.segments, + |l, r| l.name.as_str() == r.name.as_str() && l.parameters == r.parameters) + } + + fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool { + left.ty.node == right.ty.node && left.position == right.position + } + + fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { + match (&left.node, &right.node) { + (&TyVec(ref l_vec), &TyVec(ref r_vec)) => self.eq_ty(l_vec, r_vec), + (&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(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) + } + (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), + (&TyInfer, &TyInfer) => true, + _ => false, + } + } +} + +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)), + BiLt => Some((BiGt, rhs, lhs)), + BiLe => Some((BiGe, rhs, lhs)), + BiGe => Some((BiLe, rhs, lhs)), + BiGt => Some((BiLt, rhs, lhs)), + BiShl | BiShr | BiRem | BiSub | BiDiv | BiAnd | BiOr => None, + } +} + +/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. +fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool +{ + l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) +} + +/// Check if two slices are equal as per `eq_fn`. +fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool + where F: FnMut(&X, &X) -> bool +{ + left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) +} + + +/// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this +/// trait would consider IDs and spans. +/// +/// All expressions kind are hashed, but some might have a weaker hash. +pub struct SpanlessHash<'a, 'tcx: 'a> { + /// Context used to evaluate constant expressions. + cx: &'a LateContext<'a, 'tcx>, + s: SipHasher, +} + +impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { + pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + SpanlessHash { + cx: cx, + s: SipHasher::new(), + } + } + + pub fn finish(&self) -> u64 { + self.s.finish() + } + + pub fn hash_block(&mut self, b: &Block) { + for s in &b.stmts { + self.hash_stmt(s); + } + + if let Some(ref e) = b.expr { + self.hash_expr(e); + } + + b.rules.hash(&mut self.s); + } + + pub fn hash_expr(&mut self, e: &Expr) { + if let Some(e) = constant(self.cx, e) { + return e.hash(&mut self.s); + } + + match e.node { + ExprAddrOf(m, ref e) => { + let c: fn(_, _) -> _ = ExprAddrOf; + 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); + } + } + 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) => { + let c: fn(_) -> _ = ExprBreak; + c.hash(&mut self.s); + if let Some(i) = i { + self.hash_name(&i.node); + } + } + 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 b, _) => { + let c: fn(_, _, _, _) -> _ = ExprClosure; + c.hash(&mut self.s); + cap.hash(&mut self.s); + self.hash_block(b); + } + 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); + self.hash_expr(cond); + self.hash_block(t); + 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) => { + let c: fn(_, _) -> _ = ExprLoop; + c.hash(&mut self.s); + self.hash_block(b); + if let Some(i) = *i { + self.hash_name(&i); + } + } + ExprMatch(ref e, ref arms, ref s) => { + let c: fn(_, _, _) -> _ = ExprMatch; + c.hash(&mut self.s); + self.hash_expr(e); + + for arm in arms { + // TODO: arm.pat? + if let Some(ref e) = arm.guard { + self.hash_expr(e); + } + self.hash_expr(&arm.body); + } + + 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; + c.hash(&mut self.s); + self.hash_path(subpath); + } + ExprStruct(ref path, ref fields, ref expr) => { + let c: fn(_, _, _) -> _ = ExprStruct; + c.hash(&mut self.s); + + self.hash_path(path); + + for f in fields { + self.hash_name(&f.name.node); + self.hash_expr(&f.expr); + } + + 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(_, _) => { + let c: fn(_, _) -> _ = ExprType; + c.hash(&mut self.s); + // what’s an ExprType anyway? + } + ExprUnary(lop, ref le) => { + let c: fn(_, _) -> _ = ExprUnary; + c.hash(&mut self.s); + + lop.hash(&mut self.s); + self.hash_expr(le); + } + ExprVec(ref v) => { + let c: fn(_) -> _ = ExprVec; + c.hash(&mut self.s); + + self.hash_exprs(v); + } + ExprWhile(ref cond, ref b, l) => { + let c: fn(_, _, _) -> _ = ExprWhile; + c.hash(&mut self.s); + + self.hash_expr(cond); + self.hash_block(b); + if let Some(l) = l { + self.hash_name(&l); + } + } + } + } + + pub fn hash_exprs(&mut self, e: &[P<Expr>]) { + for e in e { + self.hash_expr(e); + } + } + + pub fn hash_name(&mut self, n: &Name) { + n.as_str().hash(&mut self.s); + } + + pub fn hash_path(&mut self, p: &Path) { + p.global.hash(&mut self.s); + for p in &p.segments { + self.hash_name(&p.name); + } + } + + pub fn hash_stmt(&mut self, b: &Stmt) { + match b.node { + StmtDecl(ref _decl, _) => { + let c: fn(_, _) -> _ = StmtDecl; + c.hash(&mut self.s); + // TODO: decl + } + 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/mod.rs b/clippy_lints/src/utils/mod.rs new file mode 100644 index 00000000000..3ff6167620a --- /dev/null +++ b/clippy_lints/src/utils/mod.rs @@ -0,0 +1,840 @@ +use reexport::*; +use rustc::hir::*; +use rustc::hir::def_id::DefId; +use rustc::hir::map::Node; +use rustc::lint::{LintContext, LateContext, Level, Lint}; +use rustc::middle::cstore; +use rustc::session::Session; +use rustc::traits::ProjectionMode; +use rustc::traits; +use rustc::ty::subst::Subst; +use rustc::ty; +use std::borrow::Cow; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::str::FromStr; +use syntax::ast::{self, LitKind, RangeLimits}; +use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; +use syntax::errors::DiagnosticBuilder; +use syntax::ptr::P; + +pub mod comparisons; +pub mod conf; +mod hir; +pub mod paths; +pub use self::hir::{SpanlessEq, SpanlessHash}; + +pub type MethodArgs = HirVec<P<Expr>>; + +/// 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 +/// } +/// } +/// +/// becomes +/// +/// 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) => { + if let $pat = $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([let $pat:pat = $expr:expr], $block:block) => { + if let $pat = $expr { + $block + } + }; + ([let $pat:pat = $expr:expr,], $block:block) => { + if let $pat = $expr { + $block + } + }; + ([$expr:expr, $($tt:tt)+], $block:block) => { + if $expr { + if_let_chain!{ [$($tt)+], $block } + } + }; + ([$expr:expr], $block:block) => { + if $expr { + $block + } + }; + ([$expr:expr,], $block:block) => { + if $expr { + $block + } + }; +} + +/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one +/// isn't). +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { + rhs.expn_id != lhs.expn_id +} +/// Returns true if this `expn_info` was expanded by any macro. +pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { + cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) +} + +/// Returns true if the macro that expanded the crate was outside of the current crate or was a +/// compiler plugin. +pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { + /// Invokes `in_macro` with the expansion info of the given span slightly heavy, try to use + /// this after other checks have already happened. + fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { + // no ExpnInfo = no macro + opt_info.map_or(false, |info| { + if let ExpnFormat::MacroAttribute(..) = info.callee.format { + // these are all plugins + return true; + } + // no span for the callee = external macro + info.callee.span.map_or(true, |span| { + // no snippet = external macro or compiler-builtin expansion + cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) + }) + }) + } + + cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) +} + +/// Check if a `DefId`'s path matches the given absolute type path usage. +/// +/// # Examples +/// ``` +/// match_def_path(cx, id, &["core", "option", "Option"]) +/// ``` +/// +/// See also the `paths` module. +pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { + use syntax::parse::token; + + struct AbsolutePathBuffer { + names: Vec<token::InternedString>, + } + + impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { + fn root_mode(&self) -> &ty::item_path::RootMode { + const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute; + ABSOLUTE + } + + fn push(&mut self, text: &str) { + self.names.push(token::intern(text).as_str()); + } + } + + let mut apb = AbsolutePathBuffer { + names: vec![], + }; + + cx.tcx.push_item_path(&mut apb, def_id); + + apb.names == path +} + +/// Check if type is struct or enum type with given def path. +pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { + match ty.sty { + ty::TyEnum(ref adt, _) | + ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), + _ => false, + } +} + +/// Check if the method call given in `expr` belongs to given type. +pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { + let method_call = ty::MethodCall::expr(expr.id); + + let trt_id = cx.tcx + .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 { + false + } +} + +/// Check if the method call given in `expr` belongs to given trait. +pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { + let method_call = ty::MethodCall::expr(expr.id); + + let trt_id = cx.tcx + .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 { + false + } +} + +/// Match a `Path` against a slice of segment string literals. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` +pub fn match_path(path: &Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name.as_str() == *b) +} + +/// Match a `Path` against a slice of segment string literals, e.g. +/// +/// # Examples +/// ``` +/// match_path(path, &["std", "rt", "begin_unwind"]) +/// ``` +pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { + path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) +} + +/// Get the definition associated to a path. +/// TODO: investigate if there is something more efficient for that. +pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { + let cstore = &cx.tcx.sess.cstore; + + let crates = cstore.crates(); + let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); + if let Some(krate) = krate { + let mut items = cstore.crate_top_level_items(*krate); + let mut path_it = path.iter().skip(1).peekable(); + + loop { + let segment = match path_it.next() { + Some(segment) => segment, + None => return None, + }; + + for item in &mem::replace(&mut items, vec![]) { + if item.name.as_str() == *segment { + if path_it.peek().is_none() { + return Some(item.def); + } + + let def_id = match item.def { + cstore::DefLike::DlDef(def) => def.def_id(), + cstore::DefLike::DlImpl(def_id) => def_id, + _ => panic!("Unexpected {:?}", item.def), + }; + + items = cstore.item_children(def_id); + break; + } + } + } + } else { + None + } +} + +/// Convenience function to get the `DefId` of a trait by path. +pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { + let def = match path_to_def(cx, path) { + Some(def) => def, + None => return None, + }; + + match def { + cstore::DlDef(def::Def::Trait(trait_id)) => Some(trait_id), + _ => None, + } +} + +/// 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<ty::Ty<'tcx>>) + -> bool { + cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); + + let ty = cx.tcx.erase_regions(&ty); + cx.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| { + let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), + trait_id, + 0, + ty, + ty_params); + + traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) + }) +} + +/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. +/// +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, +/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for +/// `.bar()` and `.baz()` +pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { + let mut current = expr; + let mut matched = Vec::with_capacity(methods.len()); + for method_name in methods.iter().rev() { + // method chains are stored last -> first + if let ExprMethodCall(ref name, _, ref args) = current.node { + if name.node.as_str() == *method_name { + matched.push(args); // build up `matched` backwards + current = &args[0] // go to parent expression + } else { + return None; + } + } else { + return None; + } + } + matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` + Some(matched) +} + + +/// Get the name of the item the expression is in, if available. +pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { + let parent_id = cx.tcx.map.get_parent(expr.id); + match cx.tcx.map.find(parent_id) { + Some(Node::NodeItem(&Item { ref name, .. })) | + Some(Node::NodeTraitItem(&TraitItem { ref name, .. })) | + Some(Node::NodeImplItem(&ImplItem { ref name, .. })) => Some(*name), + _ => None, + } +} + +/// Checks if a `let` decl is from a `for` loop desugaring. +pub fn is_from_for_desugar(decl: &Decl) -> bool { + if_let_chain! { + [ + let DeclLocal(ref loc) = decl.node, + let Some(ref expr) = loc.init, + let ExprMatch(_, _, MatchSource::ForLoopDesugar) = expr.node + ], + { return true; } + }; + false +} + + +/// Convert a span to a code snippet if available, otherwise use default. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) +} + +/// Convert a span to a code snippet. Returns `None` if not available. +pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { + cx.sess().codemap().span_to_snippet(span).ok() +} + +/// Convert a span (from a block) to a code snippet if available, otherwise use default. +/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// things which need to be printed as such. +/// +/// # Example +/// ``` +/// snippet(cx, expr.span, "..") +/// ``` +pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { + let snip = snippet(cx, span, default); + trim_multiline(snip, true) +} + +/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. +/// Also takes an `Option<String>` which can be put inside the braces. +pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { + let code = snippet_block(cx, expr.span, default); + let string = option.unwrap_or_default(); + if let ExprBlock(_) = expr.node { + Cow::Owned(format!("{}{}", code, string)) + } else if string.is_empty() { + Cow::Owned(format!("{{ {} }}", code)) + } else { + Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) + } +} + +/// Trim indentation from a multiline string with possibility of ignoring the first line. +pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { + let s_space = trim_multiline_inner(s, ignore_first, ' '); + let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); + trim_multiline_inner(s_tab, ignore_first, ' ') +} + +fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { + 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); + 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::<Vec<_>>() + .join("\n")) + } else { + s + } +} + +/// Get a parent expressions if any – this is useful to constrain a lint. +pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { + let map = &cx.tcx.map; + let node_id: NodeId = e.id; + let parent_id: NodeId = map.get_parent_node(node_id); + if node_id == parent_id { + return None; + } + map.find(parent_id).and_then(|node| { + if let Node::NodeExpr(parent) = node { + Some(parent) + } else { + None + } + }) +} + +pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { + let map = &cx.tcx.map; + let enclosing_node = map.get_enclosing_scope(node) + .and_then(|enclosing_id| map.find(enclosing_id)); + if let Some(node) = enclosing_node { + match node { + Node::NodeBlock(ref block) => Some(block), + Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), + _ => None, + } + } else { + None + } +} + +pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); + +impl<'a> Drop for DiagnosticWrapper<'a> { + fn drop(&mut self) { + self.0.emit(); + } +} + +impl<'a> DerefMut for DiagnosticWrapper<'a> { + fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { + &mut self.0 + } +} + +impl<'a> Deref for DiagnosticWrapper<'a> { + type Target = DiagnosticBuilder<'a>; + fn deref(&self) -> &DiagnosticBuilder<'a> { + &self.0 + } +} + +impl<'a> DiagnosticWrapper<'a> { + fn wiki_link(&mut self, lint: &'static Lint) { + self.help(&format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower())); + } +} + +pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); + if cx.current_level(lint) != Level::Allow { + db.wiki_link(lint); + } + db +} + +pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) + -> DiagnosticWrapper<'a> { + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); + if cx.current_level(lint) != Level::Allow { + db.help(help); + db.wiki_link(lint); + } + db +} + +pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, + note: &str) + -> DiagnosticWrapper<'a> { + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); + if cx.current_level(lint) != Level::Allow { + if note_span == span { + db.note(note); + } else { + db.span_note(note_span, note); + } + db.wiki_link(lint); + } + db +} + +pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) + -> DiagnosticWrapper<'a> + where F: FnOnce(&mut DiagnosticWrapper) +{ + let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); + if cx.current_level(lint) != Level::Allow { + f(&mut db); + db.wiki_link(lint); + } + db +} + +/// Return the base type for references and raw pointers. +pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { + match ty.sty { + ty::TyRef(_, ref tm) | + ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), + _ => ty, + } +} + +/// Return the base type for references and raw pointers, and count reference depth. +pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { + fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { + match ty.sty { + ty::TyRef(_, ref tm) | + ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), + _ => (ty, depth), + } + } + inner(ty, 0) +} + +/// Check whether the given expression is a constant literal of the given value. +pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { + // FIXME: use constant folding + if let ExprLit(ref spanned) = expr.node { + if let LitKind::Int(v, _) = spanned.node { + return v == value; + } + } + false +} + +pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { + cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() +} + +pub struct LimitStack { + stack: Vec<u64>, +} + +impl Drop for LimitStack { + fn drop(&mut self) { + assert_eq!(self.stack.len(), 1); + } +} + +impl LimitStack { + pub fn new(limit: u64) -> LimitStack { + LimitStack { stack: vec![limit] } + } + pub fn limit(&self) -> u64 { + *self.stack.last().expect("there should always be a value in the stack") + } + pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs(sess, attrs, name, |val| stack.push(val)); + } + pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { + let stack = &mut self.stack; + parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); + } +} + +fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { + for attr in attrs { + let attr = &attr.node; + if attr.is_sugared_doc { + continue; + } + if let ast::MetaItemKind::NameValue(ref key, ref value) = attr.value.node { + if *key == name { + if let LitKind::Str(ref s, _) = value.node { + if let Ok(value) = FromStr::from_str(s) { + f(value) + } else { + sess.span_err(value.span, "not a number"); + } + } else { + unreachable!() + } + } + } + } +} + +/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. +/// See also `is_direct_expn_of`. +pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { + 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))); + + match span_name_span { + Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), + None => return None, + Some((_, new_span)) => span = new_span, + } + } +} + +/// Return the pre-expansion span if is this directly comes from an expansion of the macro `name`. +/// The difference with `is_expn_of` is that in +/// ```rust,ignore +/// foo!(bar!(42)); +/// ``` +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by +/// `is_direct_expn_of`. +pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option<Span> { + let span_name_span = cx.tcx + .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.as_str() == name => Some(new_span), + _ => None, + } +} + +/// Return the index of the character after the first camel-case component of `s`. +pub fn camel_case_until(s: &str) -> usize { + let mut iter = s.char_indices(); + if let Some((_, first)) = iter.next() { + if !first.is_uppercase() { + return 0; + } + } else { + return 0; + } + let mut up = true; + let mut last_i = 0; + for (i, c) in iter { + if up { + if c.is_lowercase() { + up = false; + } else { + return last_i; + } + } else if c.is_uppercase() { + up = true; + last_i = i; + } else if !c.is_lowercase() { + return i; + } + } + if up { + last_i + } else { + s.len() + } +} + +/// Return index of the last camel-case component of `s`. +pub fn camel_case_from(s: &str) -> usize { + let mut iter = s.char_indices().rev(); + if let Some((_, first)) = iter.next() { + if !first.is_lowercase() { + return s.len(); + } + } else { + return s.len(); + } + let mut down = true; + let mut last_i = s.len(); + for (i, c) in iter { + if down { + if c.is_uppercase() { + down = false; + last_i = i; + } else if !c.is_lowercase() { + return last_i; + } + } else if c.is_lowercase() { + down = true; + } else { + return last_i; + } + } + last_i +} + +/// Represent a range akin to `ast::ExprKind::Range`. +#[derive(Debug, Copy, Clone)] +pub struct UnsugaredRange<'a> { + pub start: Option<&'a Expr>, + pub end: Option<&'a Expr>, + pub limits: RangeLimits, +} + +/// Unsugar a `hir` range. +pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { + // To be removed when ranges get stable. + fn unwrap_unstable(expr: &Expr) -> &Expr { + if let ExprBlock(ref block) = expr.node { + if block.rules == BlockCheckMode::PushUnstableBlock || block.rules == BlockCheckMode::PopUnstableBlock { + if let Some(ref expr) = block.expr { + return expr; + } + } + } + + expr + } + + fn get_field<'a>(name: &str, fields: &'a [Field]) -> Option<&'a Expr> { + let expr = &fields.iter() + .find(|field| field.name.node.as_str() == name) + .unwrap_or_else(|| panic!("missing {} field for range", name)) + .expr; + + Some(unwrap_unstable(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 { + ExprPath(None, ref path) => { + if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) { + Some(UnsugaredRange { + start: None, + end: None, + limits: RangeLimits::HalfOpen, + }) + } else { + None + } + } + ExprStruct(ref path, ref fields, None) => { + if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) { + Some(UnsugaredRange { + start: get_field("start", fields), + end: None, + limits: RangeLimits::HalfOpen, + }) + } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { + Some(UnsugaredRange { + start: get_field("start", fields), + end: get_field("end", fields), + limits: RangeLimits::Closed, + }) + } else if match_path(path, &paths::RANGE_STD) || match_path(path, &paths::RANGE) { + Some(UnsugaredRange { + start: get_field("start", fields), + end: get_field("end", fields), + limits: RangeLimits::HalfOpen, + }) + } else if match_path(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_path(path, &paths::RANGE_TO_INCLUSIVE) { + Some(UnsugaredRange { + start: None, + end: get_field("end", fields), + limits: RangeLimits::Closed, + }) + } else if match_path(path, &paths::RANGE_TO_STD) || match_path(path, &paths::RANGE_TO) { + Some(UnsugaredRange { + start: None, + end: get_field("end", fields), + limits: RangeLimits::HalfOpen, + }) + } else { + None + } + } + _ => None, + } +} + +/// Convenience function to get the return type of a function or `None` if the function diverges. +pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> { + let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); + let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(cx.tcx, parameter_env.free_substs); + let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, &fn_sig); + if let ty::FnConverging(ret_ty) = fn_sig.output { + Some(ret_ty) + } else { + None + } +} + +/// 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 { + let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item); + cx.tcx.infer_ctxt(None, Some(parameter_env), ProjectionMode::Any).enter(|infcx| { + let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs); + let new_b = b.subst(infcx.tcx, infcx.parameter_environment.free_substs); + infcx.can_equate(&new_a, &new_b).is_ok() + }) +} + +/// Recover the essential nodes of a desugared for loop: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. +pub fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { + if_let_chain! { + [ + let ExprMatch(ref iterexpr, ref arms, _) = expr.node, + let ExprCall(_, ref iterargs) = iterexpr.node, + iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), + let ExprLoop(ref block, _) = arms[0].body.node, + block.stmts.is_empty(), + let Some(ref loopexpr) = block.expr, + let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, + innerarms.len() == 2 && innerarms[0].pats.len() == 1, + let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, + somepats.len() == 1 + ], { + return Some((&somepats[0], + &iterargs[0], + &innerarms[0].body)); + } + } + None +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs new file mode 100644 index 00000000000..3c91578abd0 --- /dev/null +++ b/clippy_lints/src/utils/paths.rs @@ -0,0 +1,61 @@ +//! This module contains paths to types and functions Clippy needs to know about. + +pub const BEGIN_PANIC: [&'static str; 3] = ["std", "rt", "begin_panic"]; +pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"]; +pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"]; +pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; +pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; +pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; +pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"]; +pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"]; +pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"]; +pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"]; +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 DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; +pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"]; +pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; +pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; +pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; +pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; +pub const HASH: [&'static str; 2] = ["hash", "Hash"]; +pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; +pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; +pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"]; +pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; +pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"]; +pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; +pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; +pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; +pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"]; +pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; +pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"]; +pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"]; +pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"]; +pub const RANGE_FULL: [&'static str; 3] = ["core", "ops", "RangeFull"]; +pub const RANGE_FULL_STD: [&'static str; 3] = ["std", "ops", "RangeFull"]; +pub const RANGE_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeInclusive"]; +pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["core", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE_INCLUSIVE_NON_EMPTY_STD: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; +pub const RANGE_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeInclusive"]; +pub const RANGE_STD: [&'static str; 3] = ["std", "ops", "Range"]; +pub const RANGE_TO: [&'static str; 3] = ["core", "ops", "RangeTo"]; +pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclusive"]; +pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; +pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"]; +pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; +pub const REGEX_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; +pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"]; +pub const REGEX_BYTES_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; +pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"]; +pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; +pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"]; +pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; +pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; +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"]; +pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"]; +pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"]; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs new file mode 100644 index 00000000000..e62a8f9c459 --- /dev/null +++ b/clippy_lints/src/vec.rs @@ -0,0 +1,116 @@ +use rustc::lint::*; +use rustc::ty::TypeVariants; +use rustc::hir::*; +use syntax::codemap::Span; +use syntax::ptr::P; +use utils::{is_expn_of, match_path, paths, recover_for_loop, snippet, span_lint_and_then}; + +/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. +/// +/// **Why is this bad?** This is less efficient. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust,ignore +/// foo(&vec![1, 2]) +/// ``` +declare_lint! { + pub USELESS_VEC, + Warn, + "useless `vec!`" +} + +#[derive(Copy, Clone, Debug)] +pub struct UselessVec; + +impl LintPass for UselessVec { + fn get_lints(&self) -> LintArray { + lint_array!(USELESS_VEC) + } +} + +impl LateLintPass for UselessVec { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + // search for `&vec![_]` expressions where the adjusted type is `&[_]` + if_let_chain!{[ + let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, + let TypeVariants::TySlice(..) = ty.ty.sty, + let ExprAddrOf(_, ref addressee) = expr.node, + ], { + check_vec_macro(cx, addressee, expr.span); + }} + + // search for `for _ in vec![…]` + if let Some((_, arg, _)) = recover_for_loop(expr) { + // report the error around the `vec!` not inside `<std macros>:` + let span = cx.sess().codemap().source_callsite(arg.span); + check_vec_macro(cx, arg, span); + } + } +} + +fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) { + if let Some(vec_args) = unexpand_vec(cx, vec) { + let snippet = match vec_args { + VecArgs::Repeat(elem, len) => { + format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() + } + VecArgs::Vec(args) => { + if let Some(last) = args.iter().last() { + let span = Span { + lo: args[0].span.lo, + hi: last.span.hi, + expn_id: args[0].span.expn_id, + }; + + format!("&[{}]", snippet(cx, span, "..")).into() + } else { + "&[]".into() + } + } + }; + + span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| { + db.span_suggestion(span, "you can use a slice directly", snippet); + }); + } +} + +/// Represent the pre-expansion arguments of a `vec!` invocation. +pub enum VecArgs<'a> { + /// `vec![elem; len]` + Repeat(&'a P<Expr>, &'a P<Expr>), + /// `vec![a, b, c]` + Vec(&'a [P<Expr>]), +} + +/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. +pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>> { + if_let_chain!{[ + let ExprCall(ref fun, ref args) = expr.node, + let ExprPath(_, ref path) = fun.node, + is_expn_of(cx, fun.span, "vec").is_some() + ], { + return if match_path(path, &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 { + // `vec![a, b, c]` case + if_let_chain!{[ + let ExprBox(ref boxed) = args[0].node, + let ExprVec(ref args) = boxed.node + ], { + return Some(VecArgs::Vec(&*args)); + }} + + None + } + else { + None + }; + }} + + None +} diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs new file mode 100644 index 00000000000..902d84d4dd3 --- /dev/null +++ b/clippy_lints/src/zero_div_zero.rs @@ -0,0 +1,59 @@ +use consts::{Constant, constant_simple, FloatWidth}; +use rustc::lint::*; +use rustc::hir::*; +use utils::span_help_and_lint; + +/// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists +/// `of 0.0/0.0`, which is always `NaN`. It is more clear to replace instances of +/// `0.0/0.0` with `std::f32::NaN` or `std::f64::NaN`, depending on the precision. +pub struct ZeroDivZeroPass; + +/// **What it does:** This lint checks for `0.0 / 0.0`. +/// +/// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN` +/// +/// **Known problems:** None +/// +/// **Example** `0.0f32 / 0.0` +declare_lint! { + pub ZERO_DIVIDED_BY_ZERO, + Warn, + "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN" +} + +impl LintPass for ZeroDivZeroPass { + fn get_lints(&self) -> LintArray { + lint_array!(ZERO_DIVIDED_BY_ZERO) + } +} + +impl LateLintPass for ZeroDivZeroPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + // check for instances of 0.0/0.0 + if_let_chain! { + [ + let ExprBinary(ref op, ref left, ref right) = expr.node, + let BinOp_::BiDiv = op.node, + // TODO - constant_simple does not fold many operations involving floats. + // That's probably fine for this lint - it's pretty unlikely that someone would + // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. + let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(left), + let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(right), + let Some(0.0) = lhs_value.parse().ok(), + let Some(0.0) = rhs_value.parse().ok() + ], + { + // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, + // match the precision of the literals that are given. + let float_type = match (lhs_width, rhs_width) { + (FloatWidth::F64, _) + | (_, FloatWidth::F64) => "f64", + _ => "f32" + }; + span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span, + "constant division of 0.0 with 0.0 will always result in NaN", + &format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type)); + } + } + } +} diff --git a/src/approx_const.rs b/src/approx_const.rs deleted file mode 100644 index 731f1a45d09..00000000000 --- a/src/approx_const.rs +++ /dev/null @@ -1,95 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use std::f64::consts as f64; -use syntax::ast::{Lit, LitKind, FloatTy}; -use utils::span_lint; - -/// **What it does:** This lint checks for floating point literals that approximate constants which are defined in [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) or [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), respectively, suggesting to use the predefined constant. -/// -/// **Why is this bad?** Usually, the definition in the standard library is more precise than what people come up with. If you find that your definition is actually more precise, please [file a Rust issue](https://github.com/rust-lang/rust/issues). -/// -/// **Known problems:** If you happen to have a value that is within 1/8192 of a known constant, but is not *and should not* be the same, this lint will report your value anyway. We have not yet noticed any false positives in code we tested clippy with (this includes servo), but YMMV. -/// -/// **Example:** `let x = 3.14;` -declare_lint! { - pub APPROX_CONSTANT, - Warn, - "the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) \ - is found; suggests to use the constant" -} - -// Tuples are of the form (constant, name, min_digits) -const KNOWN_CONSTS: &'static [(f64, &'static str, usize)] = &[(f64::E, "E", 4), - (f64::FRAC_1_PI, "FRAC_1_PI", 4), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), - (f64::FRAC_2_PI, "FRAC_2_PI", 5), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), - (f64::FRAC_PI_2, "FRAC_PI_2", 5), - (f64::FRAC_PI_3, "FRAC_PI_3", 5), - (f64::FRAC_PI_4, "FRAC_PI_4", 5), - (f64::FRAC_PI_6, "FRAC_PI_6", 5), - (f64::FRAC_PI_8, "FRAC_PI_8", 5), - (f64::LN_10, "LN_10", 5), - (f64::LN_2, "LN_2", 5), - (f64::LOG10_E, "LOG10_E", 5), - (f64::LOG2_E, "LOG2_E", 5), - (f64::PI, "PI", 3), - (f64::SQRT_2, "SQRT_2", 5)]; - -#[derive(Copy,Clone)] -pub struct ApproxConstant; - -impl LintPass for ApproxConstant { - fn get_lints(&self) -> LintArray { - lint_array!(APPROX_CONSTANT) - } -} - -impl LateLintPass for ApproxConstant { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprLit(ref lit) = e.node { - check_lit(cx, lit, e); - } - } -} - -fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { - match lit.node { - LitKind::Float(ref s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"), - LitKind::Float(ref s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"), - LitKind::FloatUnsuffixed(ref s) => check_known_consts(cx, e, s, "f{32, 64}"), - _ => (), - } -} - -fn check_known_consts(cx: &LateContext, e: &Expr, s: &str, module: &str) { - if let Ok(_) = s.parse::<f64>() { - for &(constant, name, min_digits) in KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) { - span_lint(cx, - APPROX_CONSTANT, - e.span, - &format!("approximate value of `{}::{}` found. Consider using it directly", module, &name)); - return; - } - } - } -} - -/// Returns false if the number of significant figures in `value` are -/// less than `min_digits`; otherwise, returns true if `value` is equal -/// to `constant`, rounded to the number of digits present in `value`. -fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { - if value.len() <= min_digits { - false - } else { - let round_const = format!("{:.*}", value.len() - 2, constant); - - let mut trunc_const = constant.to_string(); - if trunc_const.len() > value.len() { - trunc_const.truncate(value.len()); - } - - (value == round_const) || (value == trunc_const) - } -} diff --git a/src/arithmetic.rs b/src/arithmetic.rs deleted file mode 100644 index be732740442..00000000000 --- a/src/arithmetic.rs +++ /dev/null @@ -1,102 +0,0 @@ -use rustc::hir; -use rustc::lint::*; -use syntax::codemap::Span; -use utils::span_lint; - -/// **What it does:** This lint checks for plain integer arithmetic -/// -/// **Why is this bad?** This is only checked against overflow in debug builds. -/// In some applications one wants explicitly checked, wrapping or saturating -/// arithmetic. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// a + 1 -/// ``` -declare_restriction_lint! { - pub INTEGER_ARITHMETIC, - "Any integer arithmetic statement" -} - -/// **What it does:** This lint checks for float arithmetic -/// -/// **Why is this bad?** For some embedded systems or kernel development, it -/// can be useful to rule out floating-point numbers -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// a + 1.0 -/// ``` -declare_restriction_lint! { - pub FLOAT_ARITHMETIC, - "Any floating-point arithmetic statement" -} - -#[derive(Copy, Clone, Default)] -pub struct Arithmetic { - span: Option<Span> -} - -impl LintPass for Arithmetic { - fn get_lints(&self) -> LintArray { - lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC) - } -} - -impl LateLintPass for Arithmetic { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - if let Some(_) = self.span { return; } - match expr.node { - hir::ExprBinary(ref op, ref l, ref r) => { - match op.node { - hir::BiAnd | hir::BiOr | hir::BiBitAnd | - hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | - hir::BiGt => return, - _ => () - } - let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r)); - if l_ty.is_integral() && r_ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, - expr.span, - "integer arithmetic detected"); - self.span = Some(expr.span); - } else if l_ty.is_floating_point() && r_ty.is_floating_point() { - 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.expr_ty(arg); - if ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, - expr.span, - "integer arithmetic detected"); - self.span = Some(expr.span); - } else if ty.is_floating_point() { - 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) { - if Some(expr.span) == self.span { - self.span = None; - } - } -} diff --git a/src/array_indexing.rs b/src/array_indexing.rs deleted file mode 100644 index ce2b9a7d6c0..00000000000 --- a/src/array_indexing.rs +++ /dev/null @@ -1,135 +0,0 @@ -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc::ty::TyArray; -use rustc_const_eval::EvalHint::ExprTypeChecked; -use rustc_const_eval::eval_const_expr_partial; -use rustc_const_math::ConstInt; -use rustc::hir::*; -use syntax::ast::RangeLimits; -use utils; - -/// **What it does:** Check for out of bounds array indexing with a constant index. -/// -/// **Why is this bad?** This will always panic at runtime. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// -/// ``` -/// let x = [1,2,3,4]; -/// ... -/// x[9]; -/// &x[2..9]; -/// ``` -declare_lint! { - pub OUT_OF_BOUNDS_INDEXING, - Deny, - "out of bound constant indexing" -} - -/// **What it does:** Check for usage of indexing or slicing. -/// -/// **Why is this bad?** Usually, this can be safely allowed. However, -/// in some domains such as kernel development, a panic can cause the -/// whole operating system to crash. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// -/// ``` -/// ... -/// x[2]; -/// &x[0..2]; -/// ``` -declare_lint! { - pub INDEXING_SLICING, - Allow, - "indexing/slicing usage" -} - -#[derive(Copy,Clone)] -pub struct ArrayIndexing; - -impl LintPass for ArrayIndexing { - fn get_lints(&self) -> LintArray { - lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING) - } -} - -impl LateLintPass for ArrayIndexing { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprIndex(ref array, ref index) = e.node { - // Array with known size can be checked statically - let ty = cx.tcx.expr_ty(array); - if let TyArray(_, size) = ty.sty { - let size = ConstInt::Infer(size as u64); - - // Index is a constant uint - let const_index = eval_const_expr_partial(cx.tcx, index, ExprTypeChecked, None); - if let Ok(ConstVal::Integral(const_index)) = const_index { - if size <= const_index { - utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds"); - } - - return; - } - - // Index is a constant range - if let Some(range) = utils::unsugar_range(index) { - let start = range.start - .map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)) - .map(|v| v.ok()); - let end = range.end - .map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)) - .map(|v| v.ok()); - - if let Some((start, end)) = to_const_range(start, end, range.limits, size) { - if start > size || end > size { - utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "range is out of bounds"); - } - return; - } - } - } - - if let Some(range) = utils::unsugar_range(index) { - // Full ranges are always valid - if range.start.is_none() && range.end.is_none() { - return; - } - - // Impossible to know if indexing or slicing is correct - utils::span_lint(cx, INDEXING_SLICING, e.span, "slicing may panic"); - } else { - utils::span_lint(cx, INDEXING_SLICING, e.span, "indexing may panic"); - } - } - } -} - -/// Returns an option containing a tuple with the start and end (exclusive) of the range. -fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, - array_size: ConstInt) - -> Option<(ConstInt, ConstInt)> { - let start = match start { - Some(Some(ConstVal::Integral(x))) => x, - Some(_) => return None, - None => ConstInt::Infer(0), - }; - - let end = match end { - Some(Some(ConstVal::Integral(x))) => { - if limits == RangeLimits::Closed { - (x + ConstInt::Infer(1)).expect("such a big array is not realistic") - } else { - x - } - } - Some(_) => return None, - None => array_size, - }; - - Some((start, end)) -} diff --git a/src/assign_ops.rs b/src/assign_ops.rs deleted file mode 100644 index 2b1aec83e4c..00000000000 --- a/src/assign_ops.rs +++ /dev/null @@ -1,158 +0,0 @@ -use rustc::hir; -use rustc::lint::*; -use utils::{span_lint_and_then, span_lint, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait}; - -/// **What it does:** This lint checks for `+=` operations and similar -/// -/// **Why is this bad?** Projects with many developers from languages without those operations -/// may find them unreadable and not worth their weight -/// -/// **Known problems:** Types implementing `OpAssign` don't necessarily implement `Op` -/// -/// **Example:** -/// ``` -/// a += 1; -/// ``` -declare_restriction_lint! { - pub ASSIGN_OPS, - "Any assignment operation" -} - -/// **What it does:** Check for `a = a op b` or `a = b commutative_op a` patterns -/// -/// **Why is this bad?** These can be written as the shorter `a op= b` -/// -/// **Known problems:** While forbidden by the spec, `OpAssign` traits may have implementations that differ from the regular `Op` impl -/// -/// **Example:** -/// -/// ``` -/// let mut a = 5; -/// ... -/// a = a + b; -/// ``` -declare_lint! { - pub ASSIGN_OP_PATTERN, - Warn, - "assigning the result of an operation on a variable to that same variable" -} - -#[derive(Copy, Clone, Default)] -pub struct AssignOps; - -impl LintPass for AssignOps { - fn get_lints(&self) -> LintArray { - lint_array!(ASSIGN_OPS, ASSIGN_OP_PATTERN) - } -} - -impl LateLintPass for AssignOps { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - match expr.node { - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if let (Some(l), Some(r)) = (snippet_opt(cx, lhs.span), snippet_opt(cx, rhs.span)) { - span_lint_and_then(cx, - ASSIGN_OPS, - expr.span, - "assign operation detected", - |db| { - match rhs.node { - hir::ExprBinary(op2, _, _) if op2 != op => { - db.span_suggestion(expr.span, - "replace it with", - format!("{} = {} {} ({})", l, l, op.node.as_str(), r)); - }, - _ => { - db.span_suggestion(expr.span, - "replace it with", - format!("{} = {} {} {}", l, l, op.node.as_str(), r)); - } - } - }); - } else { - span_lint(cx, - ASSIGN_OPS, - expr.span, - "assign operation detected"); - } - }, - 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| { - let ty = cx.tcx.expr_ty(assignee); - if ty.walk_shallow().next().is_some() { - return; // implements_trait does not work with generics - } - let rty = cx.tcx.expr_ty(rhs); - if rty.walk_shallow().next().is_some() { - return; // implements_trait does not work with generics - } - macro_rules! ops { - ($op:expr, $cx:expr, $ty:expr, $rty:expr, $($trait_name:ident:$full_trait_name:ident),+) => { - match $op { - $(hir::$full_trait_name => { - let [krate, module] = ::utils::paths::OPS_MODULE; - let path = [krate, module, concat!(stringify!($trait_name), "Assign")]; - let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) { - trait_id - } else { - return; // useless if the trait doesn't exist - }; - implements_trait($cx, $ty, trait_id, vec![$rty]) - },)* - _ => false, - } - } - } - if ops!(op.node, cx, ty, rty, Add:BiAdd, - Sub:BiSub, - Mul:BiMul, - Div:BiDiv, - Rem:BiRem, - And:BiAnd, - Or:BiOr, - BitAnd:BiBitAnd, - BitOr:BiBitOr, - BitXor:BiBitXor, - Shr:BiShr, - Shl:BiShl - ) { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { - span_lint_and_then(cx, - ASSIGN_OP_PATTERN, - expr.span, - "manual implementation of an assign operation", - |db| { - db.span_suggestion(expr.span, - "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); - }); - } else { - span_lint(cx, - ASSIGN_OP_PATTERN, - expr.span, - "manual implementation of an assign operation"); - } - } - }; - // a = a op b - if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) { - lint(assignee, r); - } - // a = b commutative_op a - if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { - match op.node { - hir::BiAdd | hir::BiMul | - hir::BiAnd | hir::BiOr | - hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr => { - lint(assignee, l); - }, - _ => {}, - } - } - } - }, - _ => {}, - } - } -} diff --git a/src/attrs.rs b/src/attrs.rs deleted file mode 100644 index 0cf62633de4..00000000000 --- a/src/attrs.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! checks for attributes - -use reexport::*; -use rustc::lint::*; -use rustc::hir::*; -use semver::Version; -use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; -use syntax::codemap::Span; -use utils::{in_macro, match_path, span_lint}; -use utils::paths; - -/// **What it does:** This lint checks for items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. -/// -/// **Why is this bad?** While there are valid uses of this annotation (and once you know when to use it, by all means `allow` this lint), it's a common newbie-mistake to pepper one's code with it. -/// -/// As a rule of thumb, before slapping `#[inline(always)]` on a function, measure if that additional function call really affects your runtime profile sufficiently to make up for the increase in compile time. -/// -/// **Known problems:** False positives, big time. This lint is meant to be deactivated by everyone doing serious performance work. This means having done the measurement. -/// -/// **Example:** -/// ``` -/// #[inline(always)] -/// fn not_quite_hot_code(..) { ... } -/// ``` -declare_lint! { - pub INLINE_ALWAYS, Warn, - "`#[inline(always)]` is a bad idea in most cases" -} - -/// **What it does:** This lint checks for `#[deprecated]` annotations with a `since` field that is not a valid semantic version.. -/// -/// **Why is this bad?** For checking the version of the deprecation, it must be valid semver. Failing that, the contained information is useless. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// #[deprecated(since = "forever")] -/// fn something_else(..) { ... } -/// ``` -declare_lint! { - pub DEPRECATED_SEMVER, Warn, - "`Warn` on `#[deprecated(since = \"x\")]` where x is not semver" -} - -#[derive(Copy,Clone)] -pub struct AttrPass; - -impl LintPass for AttrPass { - fn get_lints(&self) -> LintArray { - lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER) - } -} - -impl LateLintPass for AttrPass { - fn check_attribute(&mut self, cx: &LateContext, attr: &Attribute) { - if let MetaItemKind::List(ref name, ref items) = attr.node.value.node { - if items.is_empty() || name != &"deprecated" { - return; - } - for ref item in items { - if let MetaItemKind::NameValue(ref name, ref lit) = item.node { - if name == &"since" { - check_semver(cx, item.span, lit); - } - } - } - } - } - - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if is_relevant_item(item) { - check_attrs(cx, item.span, &item.name, &item.attrs) - } - } - - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if is_relevant_impl(item) { - check_attrs(cx, item.span, &item.name, &item.attrs) - } - } - - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - if is_relevant_trait(item) { - check_attrs(cx, item.span, &item.name, &item.attrs) - } - } -} - -fn is_relevant_item(item: &Item) -> bool { - if let ItemFn(_, _, _, _, _, ref block) = item.node { - is_relevant_block(block) - } else { - false - } -} - -fn is_relevant_impl(item: &ImplItem) -> bool { - match item.node { - ImplItemKind::Method(_, ref block) => is_relevant_block(block), - _ => false, - } -} - -fn is_relevant_trait(item: &TraitItem) -> bool { - match item.node { - MethodTraitItem(_, None) => true, - MethodTraitItem(_, Some(ref block)) => is_relevant_block(block), - _ => false, - } -} - -fn is_relevant_block(block: &Block) -> bool { - for stmt in &block.stmts { - match stmt.node { - StmtDecl(_, _) => return true, - StmtExpr(ref expr, _) | - StmtSemi(ref expr, _) => { - return is_relevant_expr(expr); - } - } - } - block.expr.as_ref().map_or(false, |e| is_relevant_expr(e)) -} - -fn is_relevant_expr(expr: &Expr) -> bool { - match expr.node { - ExprBlock(ref block) => is_relevant_block(block), - ExprRet(Some(ref e)) => is_relevant_expr(e), - ExprRet(None) | ExprBreak(_) => false, - ExprCall(ref path_expr, _) => { - if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &paths::BEGIN_PANIC) - } else { - true - } - } - _ => true, - } -} - -fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { - if in_macro(cx, span) { - return; - } - - for attr in attrs { - if let MetaItemKind::List(ref inline, ref values) = attr.node.value.node { - if values.len() != 1 || inline != &"inline" { - continue; - } - if let MetaItemKind::Word(ref always) = values[0].node { - if always != &"always" { - continue; - } - span_lint(cx, - INLINE_ALWAYS, - attr.span, - &format!("you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", - name)); - } - } - } -} - -fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { - if let LitKind::Str(ref is, _) = lit.node { - if Version::parse(&*is).is_ok() { - return; - } - } - span_lint(cx, - DEPRECATED_SEMVER, - span, - "the since field must contain a semver-compliant version"); -} diff --git a/src/bit_mask.rs b/src/bit_mask.rs deleted file mode 100644 index aec0990dcc6..00000000000 --- a/src/bit_mask.rs +++ /dev/null @@ -1,276 +0,0 @@ -use rustc::hir::*; -use rustc::hir::def::{Def, PathResolution}; -use rustc::lint::*; -use rustc_const_eval::lookup_const_by_id; -use syntax::ast::LitKind; -use syntax::codemap::Span; -use utils::span_lint; - -/// **What it does:** This lint checks for incompatible bit masks in comparisons. -/// -/// The formula for detecting if an expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` -/// is one of {`&`, `|`} and `<cmp_op>` is one of {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following table: -/// -/// |Comparison |Bit Op|Example |is always|Formula | -/// |------------|------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | -/// -/// **Why is this bad?** If the bits that the comparison cares about are always set to zero or one by the bit mask, the comparison is constant `true` or `false` (depending on mask, compared value, and operators). -/// -/// So the code is actively misleading, and the only reason someone would write this intentionally is to win an underhanded Rust contest or create a test-case for this lint. -/// -/// **Known problems:** None -/// -/// **Example:** `x & 1 == 2` (also see table above) -declare_lint! { - pub BAD_BIT_MASK, - Warn, - "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \ - (because in the example `select` containing bits that `mask` doesn't have)" -} - -/// **What it does:** This lint checks for bit masks in comparisons which can be removed without changing the outcome. The basic structure can be seen in the following table: -/// -/// |Comparison| Bit Op |Example |equals | -/// |----------|---------|-----------|-------| -/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`| -/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`| -/// -/// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask), but still a bit misleading, because the bit mask is ineffective. -/// -/// **Known problems:** False negatives: This lint will only match instances where we have figured out the math (which is for a power-of-two compared value). This means things like `x | 1 >= 7` (which would be better written as `x >= 6`) will not be reported (but bit masks like this are fairly uncommon). -/// -/// **Example:** `x | 1 > 3` (also see table above) -declare_lint! { - pub INEFFECTIVE_BIT_MASK, - Warn, - "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`" -} - -/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. -/// This cannot work because the bit that makes up the value two was -/// zeroed out by the bit-and with 1. So the formula for detecting if an -/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>` -/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` , -/// `!=`, `>=`, `>`}) can be determined from the following table: -/// -/// |Comparison |Bit Op|Example |is always|Formula | -/// |------------|------|------------|---------|----------------------| -/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` | -/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | -/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | -/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` | -/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` | -/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` | -/// -/// This lint is **deny** by default -/// -/// There is also a lint that warns on ineffective masks that is *warn* -/// by default. -/// -/// |Comparison|Bit Op |Example |equals |Formula| -/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`| -/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` | -/// -/// `¹ power_of_two(c + 1)` -#[derive(Copy,Clone)] -pub struct BitMask; - -impl LintPass for BitMask { - fn get_lints(&self) -> LintArray { - lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK) - } -} - -impl LateLintPass for BitMask { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = e.node { - if cmp.node.is_comparison() { - fetch_int_literal(cx, right).map_or_else(|| { - fetch_int_literal(cx, left).map_or((), |cmp_val| { - check_compare(cx, - right, - invert_cmp(cmp.node), - cmp_val, - &e.span) - }) - }, - |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt, &e.span)) - } - } - } -} - -fn invert_cmp(cmp: BinOp_) -> BinOp_ { - match cmp { - BiEq => BiEq, - BiNe => BiNe, - BiLt => BiGt, - BiGt => BiLt, - BiLe => BiGe, - BiGe => BiLe, - _ => BiOr, // Dummy - } -} - - -fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) { - if let ExprBinary(ref op, ref left, ref right) = bit_op.node { - if op.node != BiBitAnd && op.node != BiBitOr { - return; - } - fetch_int_literal(cx, right) - .or_else(|| fetch_int_literal(cx, left)) - .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) - } -} - -fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) { - match cmp_op { - BiEq | BiNe => { - match bit_op { - BiBitAnd => { - if mask_value & cmp_value != cmp_value { - if cmp_value != 0 { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, - cmp_value)); - } - } - _ => (), - } - } - BiLt | BiGe => { - match bit_op { - BiBitAnd => { - if mask_value < cmp_value { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, - cmp_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 => { - if mask_value <= cmp_value { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, - cmp_value)); - } else { - check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); - } - } - BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), - _ => (), - } - } - _ => (), - } -} - -fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { - if c.is_power_of_two() && m < c { - span_lint(cx, - INEFFECTIVE_BIT_MASK, - span, - &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, - m, - c)); - } -} - -fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) { - if (c + 1).is_power_of_two() && m <= c { - span_lint(cx, - INEFFECTIVE_BIT_MASK, - span, - &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, - m, - c)); - } -} - -fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> { - match lit.node { - ExprLit(ref lit_ptr) => { - if let LitKind::Int(value, _) = lit_ptr.node { - Some(value) //TODO: Handle sign - } 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, - } - } - .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/src/blacklisted_name.rs b/src/blacklisted_name.rs deleted file mode 100644 index 5cb84f62651..00000000000 --- a/src/blacklisted_name.rs +++ /dev/null @@ -1,46 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use utils::span_lint; - -/// **What it does:** This lints about usage of blacklisted names. -/// -/// **Why is this bad?** These names are usually placeholder names and should be avoided. -/// -/// **Known problems:** None. -/// -/// **Example:** `let foo = 3.14;` -declare_lint! { - pub BLACKLISTED_NAME, - Warn, - "usage of a blacklisted/placeholder name" -} - -#[derive(Clone, Debug)] -pub struct BlackListedName { - blacklist: Vec<String>, -} - -impl BlackListedName { - pub fn new(blacklist: Vec<String>) -> BlackListedName { - BlackListedName { blacklist: blacklist } - } -} - -impl LintPass for BlackListedName { - fn get_lints(&self) -> LintArray { - lint_array!(BLACKLISTED_NAME) - } -} - -impl LateLintPass for BlackListedName { - fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { - if let PatKind::Ident(_, ref ident, _) = pat.node { - if self.blacklist.iter().any(|s| s == &*ident.node.as_str()) { - span_lint(cx, - BLACKLISTED_NAME, - pat.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.node)); - } - } - } -} diff --git a/src/block_in_if_condition.rs b/src/block_in_if_condition.rs deleted file mode 100644 index c56cf4dcd29..00000000000 --- a/src/block_in_if_condition.rs +++ /dev/null @@ -1,118 +0,0 @@ -use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass}; -use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr}; -use utils::*; - -/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. -/// -/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions. -/// -/// **Known problems:** None -/// -/// **Example:** `if { true } ..` -declare_lint! { - pub BLOCK_IN_IF_CONDITION_EXPR, Warn, - "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`" -} - -/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. -/// -/// **Why is this bad?** Using blocks in the condition makes it hard to read. -/// -/// **Known problems:** None -/// -/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..` -declare_lint! { - pub BLOCK_IN_IF_CONDITION_STMT, Warn, - "avoid complex blocks in conditions, instead move the block higher and bind it \ - with 'let'; e.g: `if { let x = true; x } ...`" -} - -#[derive(Copy,Clone)] -pub struct BlockInIfCondition; - -impl LintPass for BlockInIfCondition { - fn get_lints(&self) -> LintArray { - lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT) - } -} - -struct ExVisitor<'v> { - found_block: Option<&'v Expr>, -} - -impl<'v> Visitor<'v> for ExVisitor<'v> { - fn visit_expr(&mut self, expr: &'v Expr) { - if let ExprClosure(_, _, ref block, _) = expr.node { - let complex = { - if block.stmts.is_empty() { - if let Some(ref ex) = block.expr { - match ex.node { - ExprBlock(_) => true, - _ => false, - } - } else { - false - } - } else { - true - } - }; - if complex { - self.found_block = Some(expr); - return; - } - } - walk_expr(self, expr); - } -} - -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) { - if let ExprIf(ref check, ref then, _) = expr.node { - if let ExprBlock(ref block) = check.node { - if block.rules == DefaultBlock { - if block.stmts.is_empty() { - if let Some(ref ex) = block.expr { - // don't dig into the expression here, just suggest that they remove - // the block - if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, ex.span) { - return; - } - span_help_and_lint(cx, - BLOCK_IN_IF_CONDITION_EXPR, - check.span, - BRACED_EXPR_MESSAGE, - &format!("try\nif {} {} ... ", - snippet_block(cx, ex.span, ".."), - snippet_block(cx, then.span, ".."))); - } - } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if in_macro(cx, span) || differing_macro_contexts(expr.span, span) { - return; - } - // move block higher - span_help_and_lint(cx, - BLOCK_IN_IF_CONDITION_STMT, - check.span, - COMPLEX_BLOCK_MESSAGE, - &format!("try\nlet res = {};\nif res {} ... ", - snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, ".."))); - } - } - } else { - let mut visitor = ExVisitor { found_block: None }; - walk_expr(&mut visitor, check); - if let Some(ref block) = visitor.found_block { - span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE, ""); - } - } - } - } -} diff --git a/src/booleans.rs b/src/booleans.rs deleted file mode 100644 index 9ab806f66ec..00000000000 --- a/src/booleans.rs +++ /dev/null @@ -1,389 +0,0 @@ -use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; -use rustc::hir::*; -use rustc::hir::intravisit::*; -use syntax::ast::{LitKind, DUMMY_NODE_ID}; -use syntax::codemap::{DUMMY_SP, dummy_spanned}; -use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; - -/// **What it does:** This lint checks for boolean expressions that can be written more concisely -/// -/// **Why is this bad?** Readability of boolean expressions suffers from unnecesessary duplication -/// -/// **Known problems:** Ignores short circuting behavior of `||` and `&&`. Ignores `|`, `&` and `^`. -/// -/// **Example:** `if a && true` should be `if a` and `!(a == b)` should be `a != b` -declare_lint! { - pub NONMINIMAL_BOOL, Allow, - "checks for boolean expressions that can be written more concisely" -} - -/// **What it does:** This lint checks for boolean expressions that contain terminals that can be eliminated -/// -/// **Why is this bad?** This is most likely a logic bug -/// -/// **Known problems:** Ignores short circuiting behavior -/// -/// **Example:** The `b` in `if a && b || a` is unnecessary because the expression is equivalent to `if a` -declare_lint! { - pub LOGIC_BUG, Warn, - "checks for boolean expressions that contain terminals which can be eliminated" -} - -#[derive(Copy,Clone)] -pub struct NonminimalBool; - -impl LintPass for NonminimalBool { - fn get_lints(&self) -> LintArray { - lint_array!(NONMINIMAL_BOOL, LOGIC_BUG) - } -} - -impl LateLintPass for NonminimalBool { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - NonminimalBoolVisitor(cx).visit_item(item) - } -} - -struct NonminimalBoolVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); - -use quine_mc_cluskey::Bool; -struct Hir2Qmm<'a, 'tcx: 'a, 'v> { - terminals: Vec<&'v Expr>, - cx: &'a LateContext<'a, 'tcx>, -} - -impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { - fn extract(&mut self, op: BinOp_, a: &[&'v Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> { - for a in a { - if let ExprBinary(binop, ref lhs, ref rhs) = a.node { - if binop.node == op { - v = self.extract(op, &[lhs, rhs], v)?; - continue; - } - } - v.push(self.run(a)?); - } - Ok(v) - } - - fn run(&mut self, e: &'v Expr) -> Result<Bool, String> { - // prevent folding of `cfg!` macros and the like - if !in_macro(self.cx, e.span) { - match e.node { - ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), - ExprBinary(binop, ref lhs, ref rhs) => { - match binop.node { - BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), - 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), - _ => (), - } - } - _ => (), - } - } - for (n, expr) in self.terminals.iter().enumerate() { - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { - #[allow(cast_possible_truncation)] - return Ok(Bool::Term(n as u8)); - } - let negated = match e.node { - ExprBinary(binop, ref lhs, ref rhs) => { - let mk_expr = |op| { - Expr { - id: DUMMY_NODE_ID, - span: DUMMY_SP, - attrs: None, - node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), - } - }; - match binop.node { - BiEq => mk_expr(BiNe), - BiNe => mk_expr(BiEq), - BiGt => mk_expr(BiLe), - BiGe => mk_expr(BiLt), - BiLt => mk_expr(BiGe), - BiLe => mk_expr(BiGt), - _ => continue, - } - } - _ => continue, - }; - if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { - #[allow(cast_possible_truncation)] - return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); - } - } - let n = self.terminals.len(); - self.terminals.push(e); - if n < 32 { - #[allow(cast_possible_truncation)] - Ok(Bool::Term(n as u8)) - } else { - Err("too many literals".to_owned()) - } - } -} - -fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { - fn recurse(brackets: bool, cx: &LateContext, suggestion: &Bool, terminals: &[&Expr], mut s: String) -> String { - use quine_mc_cluskey::Bool::*; - let snip = |e: &Expr| snippet_opt(cx, e.span).expect("don't try to improve booleans created by macros"); - match *suggestion { - 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 { - BiEq => " != ", - BiNe => " == ", - BiLt => " >= ", - BiGt => " <= ", - BiLe => " > ", - BiGe => " < ", - _ => { - s.push('!'); - return recurse(true, cx, inner, terminals, s); - } - }; - s.push_str(&snip(lhs)); - s.push_str(op); - s.push_str(&snip(rhs)); - s - } else { - s.push('!'); - recurse(false, cx, inner, terminals, s) - } - } - _ => { - s.push('!'); - recurse(false, cx, inner, terminals, s) - } - } - } - And(ref v) => { - if brackets { - s.push('('); - } - if let Or(_) = v[0] { - s = recurse(true, cx, &v[0], terminals, s); - } else { - s = recurse(false, cx, &v[0], terminals, s); - } - for inner in &v[1..] { - s.push_str(" && "); - if let Or(_) = *inner { - s = recurse(true, cx, inner, terminals, s); - } else { - s = recurse(false, cx, inner, terminals, s); - } - } - if brackets { - s.push(')'); - } - s - } - Or(ref v) => { - if brackets { - s.push('('); - } - s = recurse(false, cx, &v[0], terminals, s); - for inner in &v[1..] { - s.push_str(" || "); - s = recurse(false, cx, inner, terminals, s); - } - if brackets { - s.push(')'); - } - s - } - Term(n) => { - if brackets { - if let ExprBinary(..) = terminals[n as usize].node { - s.push('('); - } - } - s.push_str(&snip(terminals[n as usize])); - if brackets { - if let ExprBinary(..) = terminals[n as usize].node { - s.push(')'); - } - } - s - } - } - } - recurse(false, cx, suggestion, terminals, String::new()) -} - -fn simple_negate(b: Bool) -> Bool { - use quine_mc_cluskey::Bool::*; - match b { - True => False, - False => True, - t @ Term(_) => Not(Box::new(t)), - And(mut v) => { - for el in &mut v { - *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, - } -} - -#[derive(Default)] -struct Stats { - terminals: [usize; 32], - negations: usize, - ops: usize, -} - -fn terminal_stats(b: &Bool) -> Stats { - fn recurse(b: &Bool, stats: &mut Stats) { - match *b { - True | False => stats.ops += 1, - Not(ref inner) => { - match **inner { - And(_) | Or(_) => stats.ops += 1, // brackets are also operations - _ => 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, - } - } - use quine_mc_cluskey::Bool::*; - let mut stats = Stats::default(); - recurse(b, &mut stats); - stats -} - -impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { - fn bool_expr(&self, e: &Expr) { - let mut h2q = Hir2Qmm { - terminals: Vec::new(), - cx: self.0, - }; - if let Ok(expr) = h2q.run(e) { - - if h2q.terminals.len() > 8 { - // QMC has exponentially slow behavior as the number of terminals increases - // 8 is reasonable, it takes approximately 0.2 seconds. - // See #825 - return; - } - - let stats = terminal_stats(&expr); - let mut simplified = expr.simplify(); - for simple in Bool::Not(Box::new(expr.clone())).simplify() { - match simple { - Bool::Not(_) | Bool::True | Bool::False => {} - _ => simplified.push(Bool::Not(Box::new(simple.clone()))), - } - let simple_negated = simple_negate(simple); - if simplified.iter().any(|s| *s == simple_negated) { - continue; - } - simplified.push(simple_negated); - } - let mut improvements = Vec::new(); - 'simplified: for suggestion in &simplified { - let simplified_stats = terminal_stats(suggestion); - let mut improvement = false; - for i in 0..32 { - // ignore any "simplifications" that end up requiring a terminal more often than in the original expression - if stats.terminals[i] < simplified_stats.terminals[i] { - continue 'simplified; - } - if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { - span_lint_and_then(self.0, - LOGIC_BUG, - e.span, - "this boolean expression contains a logic bug", - |db| { - db.span_help(h2q.terminals[i].span, - "this expression can be optimized out by applying \ - boolean operations to the outer expression"); - db.span_suggestion(e.span, - "it would look like the following", - suggest(self.0, suggestion, &h2q.terminals)); - }); - // don't also lint `NONMINIMAL_BOOL` - return; - } - // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases - improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || - (stats.negations > simplified_stats.negations && - stats.ops == simplified_stats.ops) || - (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); - } - if improvement { - improvements.push(suggestion); - } - } - if !improvements.is_empty() { - span_lint_and_then(self.0, - 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)); - } - }); - } - } - } -} - -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) { - 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.node_types()[&inner.id].is_bool() { - self.bool_expr(e); - } else { - walk_expr(self, e); - } - } - _ => walk_expr(self, e), - } - } -} diff --git a/src/collapsible_if.rs b/src/collapsible_if.rs deleted file mode 100644 index 38e04723e53..00000000000 --- a/src/collapsible_if.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Checks for if expressions that contain only an if expression. -//! -//! For example, the lint would catch: -//! -//! ``` -//! if x { -//! if y { -//! println!("Hello world"); -//! } -//! } -//! ``` -//! -//! This lint is **warn** by default - -use rustc::lint::*; -use rustc::hir::*; -use std::borrow::Cow; -use syntax::codemap::Spanned; - -use utils::{in_macro, snippet, snippet_block, span_lint_and_then}; - -/// **What it does:** This lint checks for nested `if`-statements which can be collapsed by -/// `&&`-combining their conditions and for `else { if .. }` expressions that can be collapsed to -/// `else if ..`. -/// -/// **Why is this bad?** Each `if`-statement adds one level of nesting, which makes code look more complex than it really is. -/// -/// **Known problems:** None -/// -/// **Example:** `if x { if y { .. } }` -declare_lint! { - pub COLLAPSIBLE_IF, - Warn, - "two nested `if`-expressions can be collapsed into one, e.g. `if x { if y { foo() } }` \ - can be written as `if x && y { foo() }` and an `else { if .. } expression can be collapsed to \ - `else if`" -} - -#[derive(Copy,Clone)] -pub struct CollapsibleIf; - -impl LintPass for CollapsibleIf { - fn get_lints(&self) -> LintArray { - lint_array!(COLLAPSIBLE_IF) - } -} - -impl LateLintPass for CollapsibleIf { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if !in_macro(cx, expr.span) { - check_if(cx, expr) - } - } -} - -fn check_if(cx: &LateContext, e: &Expr) { - if let ExprIf(ref check, ref then, ref else_) = e.node { - if let Some(ref else_) = *else_ { - if_let_chain! {[ - let ExprBlock(ref block) = else_.node, - block.stmts.is_empty(), - block.rules == BlockCheckMode::DefaultBlock, - let Some(ref else_) = block.expr, - let ExprIf(_, _, _) = else_.node - ], { - span_lint_and_then(cx, - COLLAPSIBLE_IF, - block.span, - "this `else { if .. }` block can be collapsed", |db| { - db.span_suggestion(block.span, "try", snippet_block(cx, else_.span, "..").into_owned()); - }); - }} - } else if let Some(&Expr { node: ExprIf(ref check_inner, ref content, None), span: sp, .. }) = - single_stmt_of_block(then) { - if e.span.expn_id != sp.expn_id { - return; - } - span_lint_and_then(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", |db| { - db.span_suggestion(e.span, - "try", - format!("if {} && {} {}", - check_to_string(cx, check), - check_to_string(cx, check_inner), - snippet_block(cx, content.span, ".."))); - }); - } - } -} - -fn requires_brackets(e: &Expr) -> bool { - match e.node { - ExprBinary(Spanned { node: n, .. }, _, _) if n == BiEq => false, - _ => true, - } -} - -fn check_to_string(cx: &LateContext, e: &Expr) -> Cow<'static, str> { - if requires_brackets(e) { - format!("({})", snippet(cx, e.span, "..")).into() - } else { - snippet(cx, e.span, "..") - } -} - -fn single_stmt_of_block(block: &Block) -> Option<&Expr> { - if block.stmts.len() == 1 && block.expr.is_none() { - if let StmtExpr(ref expr, _) = block.stmts[0].node { - single_stmt_of_expr(expr) - } else { - None - } - } else if block.stmts.is_empty() { - if let Some(ref p) = block.expr { - Some(p) - } else { - None - } - } else { - None - } -} - -fn single_stmt_of_expr(expr: &Expr) -> Option<&Expr> { - if let ExprBlock(ref block) = expr.node { - single_stmt_of_block(block) - } else { - Some(expr) - } -} diff --git a/src/consts.rs b/src/consts.rs deleted file mode 100644 index 96956d1793b..00000000000 --- a/src/consts.rs +++ /dev/null @@ -1,379 +0,0 @@ -#![allow(cast_possible_truncation)] - -use rustc::lint::LateContext; -use rustc::hir::def::{Def, PathResolution}; -use rustc_const_eval::lookup_const_by_id; -use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; -use rustc::hir::*; -use std::cmp::Ordering::{self, Equal}; -use std::cmp::PartialOrd; -use std::hash::{Hash, Hasher}; -use std::mem; -use std::ops::Deref; -use std::rc::Rc; -use syntax::ast::{FloatTy, LitIntType, LitKind, StrStyle, UintTy, IntTy}; -use syntax::ptr::P; - -#[derive(Debug, Copy, Clone)] -pub enum FloatWidth { - F32, - F64, - Any, -} - -impl From<FloatTy> for FloatWidth { - fn from(ty: FloatTy) -> FloatWidth { - match ty { - FloatTy::F32 => FloatWidth::F32, - FloatTy::F64 => FloatWidth::F64, - } - } -} - -/// A `LitKind`-like enum to fold constant `Expr`s into. -#[derive(Debug, Clone)] -pub enum Constant { - /// a String "abc" - Str(String, StrStyle), - /// a Binary String b"abc" - Binary(Rc<Vec<u8>>), - /// a single char 'a' - Char(char), - /// an integer, third argument is whether the value is negated - Int(ConstInt), - /// a float with given type - Float(String, FloatWidth), - /// true or false - Bool(bool), - /// an array of constants - Vec(Vec<Constant>), - /// also an array, but with only one constant, repeated N times - Repeat(Box<Constant>, usize), - /// a tuple of constants - Tuple(Vec<Constant>), -} - -impl Constant { - /// convert to u64 if possible - /// - /// # panics - /// - /// if the constant could not be converted to u64 losslessly - fn as_u64(&self) -> u64 { - if let Constant::Int(val) = *self { - val.to_u64().expect("negative constant can't be casted to u64") - } else { - panic!("Could not convert a {:?} to u64", self); - } - } - - /// convert this constant to a f64, if possible - #[allow(cast_precision_loss, cast_possible_wrap)] - pub fn as_float(&self) -> Option<f64> { - match *self { - Constant::Float(ref s, _) => s.parse().ok(), - Constant::Int(i) if i.is_negative() => Some(i.to_u64_unchecked() as i64 as f64), - Constant::Int(i) => Some(i.to_u64_unchecked() as f64), - _ => None, - } - } -} - -impl PartialEq for Constant { - fn eq(&self, other: &Constant) -> bool { - match (self, other) { - (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => ls == rs && l_sty == r_sty, - (&Constant::Binary(ref l), &Constant::Binary(ref r)) => l == r, - (&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::<f64>(), rs.parse::<f64>()) { - (Ok(l), Ok(r)) => l.eq(&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, - (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, - _ => false, //TODO: Are there inter-type equalities? - } - } -} - -impl Hash for Constant { - fn hash<H>(&self, state: &mut H) - where H: Hasher - { - match *self { - 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::<f64>() { - unsafe { mem::transmute::<f64, u64>(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); - } - } - } -} - -impl PartialOrd for Constant { - fn partial_cmp(&self, other: &Constant) -> Option<Ordering> { - match (self, other) { - (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => { - if l_sty == r_sty { - Some(ls.cmp(rs)) - } 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::<f64>(), rs.parse::<f64>()) { - (Ok(ref l), Ok(ref r)) => l.partial_cmp(r), - _ => 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), - (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { - match lv.partial_cmp(rv) { - Some(Equal) => Some(ls.cmp(rs)), - x => x, - } - } - _ => None, //TODO: Are there any useful inter-type orderings? - } - } -} - -/// parse a `LitKind` to a `Constant` -#[allow(cast_possible_wrap)] -pub fn lit_to_constant(lit: &LitKind) -> Constant { - match *lit { - LitKind::Str(ref is, style) => Constant::Str(is.to_string(), style), - LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), - LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), - LitKind::Char(c) => Constant::Char(c), - LitKind::Int(value, LitIntType::Unsuffixed) => Constant::Int(ConstInt::Infer(value)), - LitKind::Int(value, LitIntType::Unsigned(UintTy::U8)) => Constant::Int(ConstInt::U8(value as u8)), - LitKind::Int(value, LitIntType::Unsigned(UintTy::U16)) => Constant::Int(ConstInt::U16(value as u16)), - LitKind::Int(value, LitIntType::Unsigned(UintTy::U32)) => Constant::Int(ConstInt::U32(value as u32)), - 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), - } -} - -fn constant_not(o: Constant) -> Option<Constant> { - use self::Constant::*; - match o { - Bool(b) => Some(Bool(!b)), - Int(value) => (!value).ok().map(Int), - _ => None, - } -} - -fn constant_negate(o: Constant) -> Option<Constant> { - use self::Constant::*; - match o { - Int(value) => (-value).ok().map(Int), - Float(is, ty) => Some(Float(neg_float_str(is), ty)), - _ => None, - } -} - -fn neg_float_str(s: String) -> String { - if s.starts_with('-') { - s[1..].to_owned() - } else { - format!("-{}", s) - } -} - -pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { - lcx: Some(lcx), - needed_resolution: false, - }; - cx.expr(e).map(|cst| (cst, cx.needed_resolution)) -} - -pub fn constant_simple(e: &Expr) -> Option<Constant> { - let mut cx = ConstEvalLateContext { - lcx: None, - needed_resolution: false, - }; - cx.expr(e) -} - -struct ConstEvalLateContext<'c, 'cc: 'c> { - lcx: Option<&'c LateContext<'c, 'cc>>, - needed_resolution: bool, -} - -impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { - /// simple constant folding: Insert an expression, get a constant or none. - fn expr(&mut self, e: &Expr) -> Option<Constant> { - match e.node { - ExprPath(_, _) => self.fetch_path(e), - 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)), - ExprVec(ref vec) => self.multi(vec).map(Constant::Vec), - 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 { - UnNot => constant_not(o), - UnNeg => constant_negate(o), - UnDeref => Some(o), - } - }) - } - ExprBinary(op, ref left, ref right) => self.binop(op, left, right), - // TODO: add other expressions - _ => None, - } - } - - /// create `Some(Vec![..])` of all constants, unless there is any - /// non-constant part - fn multi<E: Deref<Target = Expr> + Sized>(&mut self, vec: &[E]) -> Option<Vec<Constant>> { - vec.iter() - .map(|elem| self.expr(elem)) - .collect::<Option<_>>() - } - - /// lookup a possibly constant expression from a ExprPath - fn fetch_path(&mut self, e: &Expr) -> Option<Constant> { - if let Some(lcx) = self.lcx { - let mut maybe_id = None; - if let Some(&PathResolution { base_def: Def::Const(id), .. }) = lcx.tcx.def_map.borrow().get(&e.id) { - maybe_id = Some(id); - } - // separate if lets to avoid double borrowing the def_map - if let Some(id) = maybe_id { - if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, id, None) { - let ret = self.expr(const_expr); - if ret.is_some() { - self.needed_resolution = true; - } - return ret; - } - } - } - None - } - - /// A block can only yield a constant if it only has one constant expression - fn block(&mut self, block: &Block) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|ref b| self.expr(b)) - } else { - None - } - } - - fn ifthenelse(&mut self, cond: &Expr, then: &Block, otherwise: &Option<P<Expr>>) -> Option<Constant> { - if let Some(Constant::Bool(b)) = self.expr(cond) { - if b { - self.block(then) - } else { - otherwise.as_ref().and_then(|expr| self.expr(expr)) - } - } else { - None - } - } - - fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> { - let l = if let Some(l) = self.expr(left) { - l - } else { - return None; - }; - let r = self.expr(right); - match (op.node, l, r) { - (BiAdd, Constant::Int(l), Some(Constant::Int(r))) => (l + r).ok().map(Constant::Int), - (BiSub, Constant::Int(l), Some(Constant::Int(r))) => (l - r).ok().map(Constant::Int), - (BiMul, Constant::Int(l), Some(Constant::Int(r))) => (l * r).ok().map(Constant::Int), - (BiDiv, Constant::Int(l), Some(Constant::Int(r))) => (l / r).ok().map(Constant::Int), - (BiRem, Constant::Int(l), Some(Constant::Int(r))) => (l % r).ok().map(Constant::Int), - (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), - (BiAnd, Constant::Bool(true), Some(r)) => Some(r), - (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), - (BiOr, Constant::Bool(false), Some(r)) => Some(r), - (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), - (BiBitXor, Constant::Int(l), Some(Constant::Int(r))) => (l ^ r).ok().map(Constant::Int), - (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), - (BiBitAnd, Constant::Int(l), Some(Constant::Int(r))) => (l & r).ok().map(Constant::Int), - (BiBitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), - (BiBitOr, Constant::Int(l), Some(Constant::Int(r))) => (l | r).ok().map(Constant::Int), - (BiShl, Constant::Int(l), Some(Constant::Int(r))) => (l << r).ok().map(Constant::Int), - (BiShr, Constant::Int(l), Some(Constant::Int(r))) => (l >> r).ok().map(Constant::Int), - (BiEq, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l == r)), - (BiNe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l != r)), - (BiLt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l < r)), - (BiLe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l <= r)), - (BiGe, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l >= r)), - (BiGt, Constant::Int(l), Some(Constant::Int(r))) => Some(Constant::Bool(l > r)), - _ => None, - } - } - - - fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant> - where F: Fn(Constant, Constant) -> Option<Constant> - { - if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) { - op(lc, rc) - } else { - None - } - } -} diff --git a/src/copies.rs b/src/copies.rs deleted file mode 100644 index 4344ba461dd..00000000000 --- a/src/copies.rs +++ /dev/null @@ -1,271 +0,0 @@ -use rustc::lint::*; -use rustc::ty; -use rustc::hir::*; -use std::collections::HashMap; -use std::collections::hash_map::Entry; -use syntax::parse::token::InternedString; -use syntax::util::small_vector::SmallVector; -use utils::{SpanlessEq, SpanlessHash}; -use utils::{get_parent_expr, in_macro, span_note_and_lint}; - -/// **What it does:** This lint checks for consecutive `ifs` with the same condition. This lint is -/// `Warn` by default. -/// -/// **Why is this bad?** This is probably a copy & paste error. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** `if a == b { .. } else if a == b { .. }` -declare_lint! { - pub IFS_SAME_COND, - Warn, - "consecutive `ifs` with the same condition" -} - -/// **What it does:** This lint checks for `if/else` with the same body as the *then* part and the -/// *else* part. This lint is `Warn` by default. -/// -/// **Why is this bad?** This is probably a copy & paste error. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** `if .. { 42 } else { 42 }` -declare_lint! { - pub IF_SAME_THEN_ELSE, - Warn, - "if with the same *then* and *else* blocks" -} - -/// **What it does:** This lint checks for `match` with identical arm bodies. -/// -/// **Why is this bad?** This is probably a copy & paste error. If arm bodies are the same on -/// purpose, you can factor them -/// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// ```rust,ignore -/// match foo { -/// Bar => bar(), -/// Quz => quz(), -/// Baz => bar(), // <= oops -/// } -/// ``` -declare_lint! { - pub MATCH_SAME_ARMS, - Warn, - "`match` with identical arm bodies" -} - -#[derive(Copy, Clone, Debug)] -pub struct CopyAndPaste; - -impl LintPass for CopyAndPaste { - fn get_lints(&self) -> LintArray { - lint_array![IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS] - } -} - -impl LateLintPass for CopyAndPaste { - fn check_expr(&mut self, cx: &LateContext, expr: &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) { - if else_expr.id == expr.id { - return; - } - } - - let (conds, blocks) = if_sequence(expr); - lint_same_then_else(cx, blocks.as_slice()); - lint_same_cond(cx, conds.as_slice()); - lint_match_arms(cx, expr); - } - } -} - -/// Implementation of `IF_SAME_THEN_ELSE`. -fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { - let hash: &Fn(&&Block) -> u64 = &|block| -> u64 { - let mut h = SpanlessHash::new(cx); - h.hash_block(block); - h.finish() - }; - - let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; - - if let Some((i, j)) = search_same(blocks, hash, eq) { - span_note_and_lint(cx, - IF_SAME_THEN_ELSE, - j.span, - "this `if` has identical blocks", - i.span, - "same as this"); - } -} - -/// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { - let hash: &Fn(&&Expr) -> u64 = &|expr| -> u64 { - let mut h = SpanlessHash::new(cx); - h.hash_expr(expr); - h.finish() - }; - - let eq: &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; - - if let Some((i, j)) = search_same(conds, hash, eq) { - span_note_and_lint(cx, - IFS_SAME_COND, - j.span, - "this `if` has the same condition as a previous if", - i.span, - "same as this"); - } -} - -/// Implementation if `MATCH_SAME_ARMS`. -fn lint_match_arms(cx: &LateContext, expr: &Expr) { - let hash = |arm: &Arm| -> u64 { - let mut h = SpanlessHash::new(cx); - h.hash_expr(&arm.body); - h.finish() - }; - - let eq = |lhs: &Arm, rhs: &Arm| -> bool { - // Arms with a guard are ignored, those can’t always be merged together - lhs.guard.is_none() && rhs.guard.is_none() && - SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && - // all patterns should have the same bindings - bindings(cx, &lhs.pats[0]) == bindings(cx, &rhs.pats[0]) - }; - - if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { - if let Some((i, j)) = search_same(arms, hash, eq) { - span_note_and_lint(cx, - MATCH_SAME_ARMS, - j.body.span, - "this `match` has identical arm bodies", - i.body.span, - "same as this"); - } - } -} - -/// Return the list of condition expressions and the list of blocks in a sequence of `if/else`. -/// Eg. would return `([a, b], [c, d, e])` for the expression -/// `if a { c } else if b { d } else { e }`. -fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { - let mut conds = SmallVector::zero(); - let mut blocks = SmallVector::zero(); - - while let ExprIf(ref cond, ref then_block, ref else_expr) = expr.node { - conds.push(&**cond); - blocks.push(&**then_block); - - if let Some(ref else_expr) = *else_expr { - expr = else_expr; - } else { - break; - } - } - - // final `else {..}` - if !blocks.is_empty() { - if let ExprBlock(ref block) = expr.node { - blocks.push(&**block); - } - } - - (conds, blocks) -} - -/// Return the list of bindings in a pattern. -fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, ty::Ty<'tcx>> { - fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, ty::Ty<'tcx>>) { - match pat.node { - PatKind::Box(ref pat) | - PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), - PatKind::TupleStruct(_, Some(ref pats)) => { - for pat in pats { - bindings_impl(cx, pat, map); - } - } - PatKind::Ident(_, ref ident, ref as_pat) => { - if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { - v.insert(cx.tcx.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::Tup(ref fields) => { - for pat in fields { - bindings_impl(cx, pat, map); - } - } - PatKind::Vec(ref lhs, ref mid, ref rhs) => { - for pat in lhs { - bindings_impl(cx, pat, map); - } - if let Some(ref mid) = *mid { - bindings_impl(cx, mid, map); - } - for pat in rhs { - bindings_impl(cx, pat, map); - } - } - PatKind::TupleStruct(..) | - PatKind::Lit(..) | - PatKind::QPath(..) | - PatKind::Range(..) | - PatKind::Wild | - PatKind::Path(..) => (), - } - } - - let mut result = HashMap::new(); - bindings_impl(cx, pat, &mut result); - result -} - -fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> - where Hash: Fn(&T) -> u64, - Eq: Fn(&T, &T) -> bool -{ - // common cases - if exprs.len() < 2 { - return None; - } else if exprs.len() == 2 { - return if eq(&exprs[0], &exprs[1]) { - Some((&exprs[0], &exprs[1])) - } else { - None - }; - } - - let mut map: HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); - - for expr in exprs { - match map.entry(hash(expr)) { - Entry::Occupied(o) => { - for o in o.get() { - if eq(o, expr) { - return Some((o, expr)); - } - } - } - Entry::Vacant(v) => { - v.insert(vec![expr]); - } - } - } - - None -} diff --git a/src/cyclomatic_complexity.rs b/src/cyclomatic_complexity.rs deleted file mode 100644 index 8ae0d2c97c5..00000000000 --- a/src/cyclomatic_complexity.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! calculate cyclomatic complexity and warn about overly complex functions - -use rustc::cfg::CFG; -use rustc::lint::*; -use rustc::ty; -use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr}; -use syntax::ast::Attribute; -use syntax::attr; -use syntax::codemap::Span; - -use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type}; - -/// **What it does:** This lint checks for methods with high cyclomatic complexity -/// -/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better. -/// -/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity -/// -/// **Example:** No. You'll see it when you get the warning. -declare_lint! { - pub CYCLOMATIC_COMPLEXITY, Warn, - "finds functions that should be split up into multiple functions" -} - -pub struct CyclomaticComplexity { - limit: LimitStack, -} - -impl CyclomaticComplexity { - pub fn new(limit: u64) -> Self { - CyclomaticComplexity { limit: LimitStack::new(limit) } - } -} - -impl LintPass for CyclomaticComplexity { - fn get_lints(&self) -> LintArray { - lint_array!(CYCLOMATIC_COMPLEXITY) - } -} - -impl CyclomaticComplexity { - fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) { - if in_macro(cx, span) { - return; - } - - let cfg = CFG::new(cx.tcx, block); - let n = cfg.graph.len_nodes() as u64; - let e = cfg.graph.len_edges() as u64; - if e + 2 < n { - // the function has unreachable code, other lints should catch this - return; - } - let cc = e + 2 - n; - let mut helper = CCHelper { - match_arms: 0, - divergence: 0, - short_circuits: 0, - returns: 0, - tcx: &cx.tcx, - }; - helper.visit_block(block); - let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; - let ret_ty = cx.tcx.node_id_to_type(block.id); - let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) { - returns - } else { - returns / 2 - }; - - if cc + divergence < match_arms + short_circuits { - report_cc_bug(cx, cc, match_arms, divergence, short_circuits, ret_adjust, span); - } else { - let mut rust_cc = cc + divergence - match_arms - short_circuits; - // prevent degenerate cases where unreachable code contains `return` statements - if rust_cc >= ret_adjust { - rust_cc -= ret_adjust; - } - if rust_cc > self.limit.limit() { - span_help_and_lint(cx, - CYCLOMATIC_COMPLEXITY, - span, - &format!("the function has a cyclomatic complexity of {}", rust_cc), - "you could split it up into multiple smaller functions"); - } - } - } -} - -impl LateLintPass for CyclomaticComplexity { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemFn(_, _, _, _, _, ref block) = item.node { - if !attr::contains_name(&item.attrs, "test") { - self.check(cx, block, item.span); - } - } - } - - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - if let ImplItemKind::Method(_, ref block) = item.node { - self.check(cx, block, item.span); - } - } - - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - if let MethodTraitItem(_, Some(ref block)) = item.node { - self.check(cx, block, item.span); - } - } - - fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { - self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); - } - fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) { - self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); - } -} - -struct CCHelper<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - match_arms: u64, - divergence: u64, - returns: u64, - short_circuits: u64, // && and || - tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, -} - -impl<'a, 'b, 'tcx, 'gcx> Visitor<'a> for CCHelper<'b, 'gcx, 'tcx> { - fn visit_expr(&mut self, e: &'a Expr) { - match e.node { - ExprMatch(_, ref arms, _) => { - walk_expr(self, e); - let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum(); - if arms_n > 1 { - self.match_arms += arms_n - 2; - } - } - ExprCall(ref callee, _) => { - walk_expr(self, e); - let ty = self.tcx.node_id_to_type(callee.id); - match ty.sty { - ty::TyFnDef(_, _, ty) | - ty::TyFnPtr(ty) if ty.sig.skip_binder().output.diverges() => { - self.divergence += 1; - } - _ => (), - } - } - ExprClosure(..) => (), - ExprBinary(op, _, _) => { - walk_expr(self, e); - match op.node { - BiAnd | BiOr => self.short_circuits += 1, - _ => (), - } - } - ExprRet(_) => self.returns += 1, - _ => walk_expr(self, e), - } - } -} - -#[cfg(feature="debugging")] -fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { - span_bug!(span, - "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ - div = {}, shorts = {}, returns = {}. Please file a bug report.", - cc, - narms, - div, - shorts, - returns); -} -#[cfg(not(feature="debugging"))] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { - if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { - cx.sess().span_note_without_error(span, - &format!("Clippy encountered a bug calculating cyclomatic complexity \ - (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ - = {}, arms = {}, div = {}, shorts = {}, returns = {}. Please file a bug report.", - cc, - narms, - div, - shorts, - returns)); - } -} diff --git a/src/deprecated_lints.rs b/src/deprecated_lints.rs deleted file mode 100644 index abdb6297b9e..00000000000 --- a/src/deprecated_lints.rs +++ /dev/null @@ -1,44 +0,0 @@ -macro_rules! declare_deprecated_lint { - (pub $name: ident, $_reason: expr) => { - declare_lint!(pub $name, Allow, "deprecated lint") - } -} - -/// **What it does:** Nothing. This lint has been deprecated. -/// -/// **Deprecation reason:** This used to check for `Vec::as_slice`, which was unstable with good -/// stable alternatives. `Vec::as_slice` has now been stabilized. -declare_deprecated_lint! { - pub UNSTABLE_AS_SLICE, - "`Vec::as_slice` has been stabilized in 1.7" -} - - -/// **What it does:** Nothing. This lint has been deprecated. -/// -/// **Deprecation reason:** This used to check for `Vec::as_mut_slice`, which was unstable with good -/// stable alternatives. `Vec::as_mut_slice` has now been stabilized. -declare_deprecated_lint! { - pub UNSTABLE_AS_MUT_SLICE, - "`Vec::as_mut_slice` has been stabilized in 1.7" -} - -/// **What it does:** Nothing. This lint has been deprecated. -/// -/// **Deprecation reason:** This used to check for `.to_string()` method calls on values -/// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be -/// specialized to be as efficient as `to_owned`. -declare_deprecated_lint! { - pub STR_TO_STRING, - "using `str::to_string` is common even today and specialization will likely happen soon" -} - -/// **What it does:** Nothing. This lint has been deprecated. -/// -/// **Deprecation reason:** This used to check for `.to_string()` method calls on values -/// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be -/// specialized to be as efficient as `clone`. -declare_deprecated_lint! { - pub STRING_TO_STRING, - "using `string::to_string` is common even today and specialization will likely happen soon" -} diff --git a/src/derive.rs b/src/derive.rs deleted file mode 100644 index f08522953aa..00000000000 --- a/src/derive.rs +++ /dev/null @@ -1,180 +0,0 @@ -use rustc::lint::*; -use rustc::ty::subst::Subst; -use rustc::ty::TypeVariants; -use rustc::ty; -use rustc::hir::*; -use syntax::ast::{Attribute, MetaItemKind}; -use syntax::codemap::Span; -use utils::paths; -use utils::{match_path, span_lint_and_then}; - -/// **What it does:** This lint warns about deriving `Hash` but implementing `PartialEq` -/// explicitly. -/// -/// **Why is this bad?** The implementation of these traits must agree (for example for use with -/// `HashMap`) so it’s probably a bad idea to use a default-generated `Hash` implementation with -/// an explicitly defined `PartialEq`. In particular, the following must hold for any type: -/// -/// ```rust -/// k1 == k2 ⇒ hash(k1) == hash(k2) -/// ``` -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust -/// #[derive(Hash)] -/// struct Foo; -/// -/// impl PartialEq for Foo { -/// .. -/// } -/// ``` -declare_lint! { - pub DERIVE_HASH_XOR_EQ, - Warn, - "deriving `Hash` but implementing `PartialEq` explicitly" -} - -/// **What it does:** This lint warns about explicit `Clone` implementation for `Copy` types. -/// -/// **Why is this bad?** To avoid surprising behaviour, these traits should agree and the behaviour -/// of `Copy` cannot be overridden. In almost all situations a `Copy` type should have a `Clone` -/// implementation that does nothing more than copy the object, which is what -/// `#[derive(Copy, Clone)]` gets you. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust -/// #[derive(Copy)] -/// struct Foo; -/// -/// impl Clone for Foo { -/// .. -/// } -/// ``` -declare_lint! { - pub EXPL_IMPL_CLONE_ON_COPY, - Warn, - "implementing `Clone` explicitly on `Copy` types" -} - -pub struct Derive; - -impl LintPass for Derive { - fn get_lints(&self) -> LintArray { - lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ) - } -} - -impl LateLintPass for Derive { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if_let_chain! {[ - let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node - ], { - let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; - let is_automatically_derived = item.attrs.iter().any(is_automatically_derived); - - check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); - - if !is_automatically_derived { - check_copy_clone(cx, item, trait_ref, ty); - } - }} - } -} - -/// 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) { - if_let_chain! {[ - match_path(&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); - - // Look for the PartialEq implementations for `ty` - peq_trait_def.for_each_relevant_impl(cx.tcx, ty, |impl_id| { - let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived); - - if peq_is_automatically_derived == hash_is_automatically_derived { - return; - } - - let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - - // Only care about `impl PartialEq<Foo> for Foo` - if trait_ref.input_types()[0] == ty { - let mess = if peq_is_automatically_derived { - "you are implementing `Hash` explicitly but have derived `PartialEq`" - } else { - "you are deriving `Hash` but have implemented `PartialEq` explicitly" - }; - - span_lint_and_then( - cx, DERIVE_HASH_XOR_EQ, span, - mess, - |db| { - if let Some(node_id) = cx.tcx.map.as_local_node_id(impl_id) { - db.span_note( - cx.tcx.map.span(node_id), - "`PartialEq` implemented here" - ); - } - }); - } - }); - }} -} - -/// 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) { - let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - let subst_ty = ty.subst(cx.tcx, parameter_environment.free_substs); - - if subst_ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, item.span) { - return; // ty is not Copy - } - - // Some types are not Clone by default but could be cloned `by hand` if necessary - match ty.sty { - TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => { - for variant in &def.variants { - for field in &variant.fields { - match field.ty(cx.tcx, substs).sty { - TypeVariants::TyArray(_, size) if size > 32 => { - return; - } - TypeVariants::TyFnPtr(..) => { - return; - } - TypeVariants::TyTuple(ref tys) if tys.len() > 12 => { - return; - } - _ => (), - } - } - } - } - _ => (), - } - - span_lint_and_then(cx, - EXPL_IMPL_CLONE_ON_COPY, - item.span, - "you are implementing `Clone` explicitly on a `Copy` type", - |db| { - db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); - }); - } -} - -/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have. -fn is_automatically_derived(attr: &Attribute) -> bool { - if let MetaItemKind::Word(ref word) = attr.node.value.node { - word == &"automatically_derived" - } else { - false - } -} diff --git a/src/doc.rs b/src/doc.rs deleted file mode 100644 index cf32c1731fa..00000000000 --- a/src/doc.rs +++ /dev/null @@ -1,235 +0,0 @@ -use rustc::lint::*; -use syntax::ast; -use syntax::codemap::{Span, BytePos}; -use utils::span_lint; - -/// **What it does:** This lint checks for the presence of `_`, `::` or camel-case words outside -/// ticks in documentation. -/// -/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and camel-case probably -/// indicates some code which should be included between ticks. `_` can also be used for empasis in -/// markdown, this lint tries to consider that. -/// -/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks for is limited. -/// -/// **Examples:** -/// ```rust -/// /// Do something with the foo_bar parameter. See also that::other::module::foo. -/// // ^ `foo_bar` and `that::other::module::foo` should be ticked. -/// fn doit(foo_bar) { .. } -/// ``` -declare_lint! { - pub DOC_MARKDOWN, Warn, - "checks for the presence of `_`, `::` or camel-case outside ticks in documentation" -} - -#[derive(Clone)] -pub struct Doc { - valid_idents: Vec<String>, -} - -impl Doc { - pub fn new(valid_idents: Vec<String>) -> Self { - Doc { valid_idents: valid_idents } - } -} - -impl LintPass for Doc { - fn get_lints(&self) -> LintArray { - lint_array![DOC_MARKDOWN] - } -} - -impl EarlyLintPass for Doc { - fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { - check_attrs(cx, &self.valid_idents, &krate.attrs); - } - - fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { - check_attrs(cx, &self.valid_idents, &item.attrs); - } -} - -pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) { - let mut in_multiline = false; - for attr in attrs { - if attr.node.is_sugared_doc { - if let ast::MetaItemKind::NameValue(_, ref doc) = attr.node.value.node { - if let ast::LitKind::Str(ref doc, _) = doc.node { - // doc comments start with `///` or `//!` - let real_doc = &doc[3..]; - let mut span = attr.span; - span.lo = span.lo + BytePos(3); - - // check for multiline code blocks - if real_doc.trim_left().starts_with("```") { - in_multiline = !in_multiline; - } - if !in_multiline { - check_doc(cx, valid_idents, real_doc, span); - } - } - } - } - } -} - -macro_rules! jump_to { - // Get the next character’s first byte UTF-8 friendlyly. - (@next_char, $chars: expr, $len: expr) => {{ - if let Some(&(pos, _)) = $chars.peek() { - pos - } else { - $len - } - }}; - - // Jump to the next `$c`. If no such character is found, give up. - ($chars: expr, $c: expr, $len: expr) => {{ - if $chars.find(|&(_, c)| c == $c).is_some() { - jump_to!(@next_char, $chars, $len) - } - else { - return; - } - }}; -} - -#[allow(while_let_loop)] // #362 -pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], doc: &str, span: Span) { - // In markdown, `_` can be used to emphasize something, or, is a raw `_` depending on context. - // There really is no markdown specification that would disambiguate this properly. This is - // what GitHub and Rustdoc do: - // - // foo_bar test_quz → foo_bar test_quz - // foo_bar_baz → foo_bar_baz (note that the “official” spec says this should be emphasized) - // _foo bar_ test_quz_ → <em>foo bar</em> test_quz_ - // \_foo bar\_ → _foo bar_ - // (_baz_) → (<em>baz</em>) - // foo _ bar _ baz → foo _ bar _ baz - - /// Character that can appear in a word - fn is_word_char(c: char) -> bool { - match c { - t if t.is_alphanumeric() => true, - ':' | '_' => true, - _ => false, - } - } - - #[allow(cast_possible_truncation)] - fn word_span(mut span: Span, begin: usize, end: usize) -> Span { - debug_assert_eq!(end as u32 as usize, end); - debug_assert_eq!(begin as u32 as usize, begin); - span.hi = span.lo + BytePos(end as u32); - span.lo = span.lo + BytePos(begin as u32); - span - } - - let mut new_line = true; - let len = doc.len(); - let mut chars = doc.char_indices().peekable(); - let mut current_word_begin = 0; - loop { - match chars.next() { - Some((_, c)) => { - match c { - '#' if new_line => { // don’t warn on titles - current_word_begin = jump_to!(chars, '\n', len); - } - '`' => { - current_word_begin = jump_to!(chars, '`', len); - } - '[' => { - let end = jump_to!(chars, ']', len); - let link_text = &doc[current_word_begin + 1..end]; - let word_span = word_span(span, current_word_begin + 1, end + 1); - - match chars.peek() { - Some(&(_, c)) => { - // Trying to parse a link. Let’s ignore the link. - - // FIXME: how does markdown handles such link? - // https://en.wikipedia.org/w/index.php?title=) - match c { - '(' => { // inline link - current_word_begin = jump_to!(chars, ')', len); - check_doc(cx, valid_idents, link_text, word_span); - } - '[' => { // reference link - current_word_begin = jump_to!(chars, ']', len); - check_doc(cx, valid_idents, link_text, word_span); - } - ':' => { // reference link - current_word_begin = jump_to!(chars, '\n', len); - } - _ => { // automatic reference link - current_word_begin = jump_to!(@next_char, chars, len); - check_doc(cx, valid_idents, link_text, word_span); - } - } - } - None => return, - } - } - // anything that’s neither alphanumeric nor '_' is not part of an ident anyway - c if !c.is_alphanumeric() && c != '_' => { - current_word_begin = jump_to!(@next_char, chars, len); - } - _ => { - let end = match chars.find(|&(_, c)| !is_word_char(c)) { - Some((end, _)) => end, - None => len, - }; - let word_span = word_span(span, current_word_begin, end); - check_word(cx, valid_idents, &doc[current_word_begin..end], word_span); - current_word_begin = jump_to!(@next_char, chars, len); - } - } - - new_line = c == '\n' || (new_line && c.is_whitespace()); - } - None => break, - } - } -} - -fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span) { - /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is - /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). - fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_digit(10)) { - return false; - } - - let s = if s.ends_with('s') { - &s[..s.len() - 1] - } else { - s - }; - - 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 - } - - fn has_underscore(s: &str) -> bool { - s != "_" && !s.contains("\\_") && s.contains('_') - } - - // Trim punctuation as in `some comment (see foo::bar).` - // ^^ - // Or even as in `_foo bar_` which is emphasized. - let word = word.trim_matches(|c: char| !c.is_alphanumeric()); - - if valid_idents.iter().any(|i| i == word) { - return; - } - - if has_underscore(word) || word.contains("::") || is_camel_case(word) { - span_lint(cx, - DOC_MARKDOWN, - span, - &format!("you should put `{}` between ticks in the documentation", word)); - } -} diff --git a/src/drop_ref.rs b/src/drop_ref.rs deleted file mode 100644 index 69156f15f31..00000000000 --- a/src/drop_ref.rs +++ /dev/null @@ -1,61 +0,0 @@ -use rustc::lint::*; -use rustc::ty; -use rustc::hir::*; -use syntax::codemap::Span; -use utils::{match_def_path, paths, span_note_and_lint}; - -/// **What it does:** This lint checks for calls to `std::mem::drop` with a reference instead of an owned value. -/// -/// **Why is this bad?** Calling `drop` on a reference will only drop the reference itself, which is a no-op. It will not call the `drop` method (from the `Drop` trait implementation) on the underlying referenced value, which is likely what was intended. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ```rust -/// let mut lock_guard = mutex.lock(); -/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex still locked -/// operation_that_requires_mutex_to_be_unlocked(); -/// ``` -declare_lint! { - pub DROP_REF, Warn, - "call to `std::mem::drop` with a reference instead of an owned value, \ - which will not call the `Drop::drop` method on the underlying value" -} - -#[allow(missing_copy_implementations)] -pub struct DropRefPass; - -impl LintPass for DropRefPass { - fn get_lints(&self) -> LintArray { - lint_array!(DROP_REF) - } -} - -impl LateLintPass for DropRefPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprCall(ref path, ref args) = expr.node { - if let ExprPath(None, _) = path.node { - let def_id = cx.tcx.def_map.borrow()[&path.id].def_id(); - if match_def_path(cx, def_id, &paths::DROP) { - if args.len() != 1 { - return; - } - check_drop_arg(cx, expr.span, &*args[0]); - } - } - } - } -} - -fn check_drop_arg(cx: &LateContext, call_span: Span, arg: &Expr) { - let arg_ty = cx.tcx.expr_ty(arg); - if let ty::TyRef(..) = arg_ty.sty { - span_note_and_lint(cx, - DROP_REF, - call_span, - "call to `std::mem::drop` with a reference argument. \ - Dropping a reference does nothing", - arg.span, - &format!("argument has type {}", arg_ty.sty)); - } -} diff --git a/src/entry.rs b/src/entry.rs deleted file mode 100644 index d63d8c67c5d..00000000000 --- a/src/entry.rs +++ /dev/null @@ -1,148 +0,0 @@ -use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr, walk_block}; -use rustc::lint::*; -use syntax::codemap::Span; -use utils::SpanlessEq; -use utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; - -/// **What it does:** This lint checks for uses of `contains_key` + `insert` on `HashMap` or -/// `BTreeMap`. -/// -/// **Why is this bad?** Using `entry` is more efficient. -/// -/// **Known problems:** Some false negatives, eg.: -/// ``` -/// let k = &key; -/// if !m.contains_key(k) { m.insert(k.clone(), v); } -/// ``` -/// -/// **Example:** -/// ```rust -/// if !m.contains_key(&k) { m.insert(k, v) } -/// ``` -/// can be rewritten as: -/// ```rust -/// m.entry(k).or_insert(v); -/// ``` -declare_lint! { - pub MAP_ENTRY, - Warn, - "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`" -} - -#[derive(Copy,Clone)] -pub struct HashMapLint; - -impl LintPass for HashMapLint { - fn get_lints(&self) -> LintArray { - lint_array!(MAP_ENTRY) - } -} - -impl LateLintPass for HashMapLint { - fn check_expr(&mut self, cx: &LateContext, expr: &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) { - // in case of `if !m.contains_key(&k) { m.insert(k, v); }` - // we can give a better error message - let sole_expr = else_block.is_none() && - ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1); - - let mut visitor = InsertVisitor { - cx: cx, - span: expr.span, - ty: ty, - map: map, - key: key, - sole_expr: sole_expr, - }; - - walk_block(&mut visitor, then_block); - } - } else if let Some(ref else_block) = *else_block { - if let Some((ty, map, key)) = check_cond(cx, check) { - let mut visitor = InsertVisitor { - cx: cx, - span: expr.span, - ty: ty, - map: map, - key: key, - sole_expr: false, - }; - - walk_expr(&mut visitor, else_block); - } - } - } - } -} - -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, - name.node.as_str() == "contains_key", - let ExprAddrOf(_, ref key) = params[1].node - ], { - let map = ¶ms[0]; - let obj_ty = walk_ptrs_ty(cx.tcx.expr_ty(map)); - - return if match_type(cx, obj_ty, &paths::BTREEMAP) { - Some(("BTreeMap", map, key)) - } - else if match_type(cx, obj_ty, &paths::HASHMAP) { - Some(("HashMap", map, key)) - } - else { - None - }; - }} - - None -} - -struct InsertVisitor<'a, 'tcx: 'a, 'b> { - cx: &'a LateContext<'a, 'tcx>, - span: Span, - ty: &'static str, - map: &'b Expr, - key: &'b Expr, - sole_expr: bool, -} - -impl<'a, 'tcx, 'v, 'b> Visitor<'v> for InsertVisitor<'a, 'tcx, 'b> { - fn visit_expr(&mut self, expr: &'v Expr) { - if_let_chain! {[ - let ExprMethodCall(ref name, _, ref params) = expr.node, - params.len() == 3, - name.node.as_str() == "insert", - get_item_name(self.cx, self.map) == get_item_name(self.cx, &*params[0]), - SpanlessEq::new(self.cx).eq_expr(self.key, ¶ms[1]) - ], { - - span_lint_and_then(self.cx, MAP_ENTRY, self.span, - &format!("usage of `contains_key` followed by `insert` on `{}`", self.ty), |db| { - if self.sole_expr { - let help = format!("{}.entry({}).or_insert({})", - snippet(self.cx, self.map.span, "map"), - snippet(self.cx, params[1].span, ".."), - snippet(self.cx, params[2].span, "..")); - - db.span_suggestion(self.span, "Consider using", help); - } - else { - let help = format!("Consider using `{}.entry({})`", - snippet(self.cx, self.map.span, "map"), - snippet(self.cx, params[1].span, "..")); - - db.span_note(self.span, &help); - } - }); - }} - - if !self.sole_expr { - walk_expr(self, expr); - } - } -} diff --git a/src/enum_clike.rs b/src/enum_clike.rs deleted file mode 100644 index 39c31864f39..00000000000 --- a/src/enum_clike.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` - -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::*; -use rustc::hir::*; -use utils::span_lint; - -/// **What it does:** Lints on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`. -/// -/// **Why is this bad?** This will truncate the variant value on 32bit architectures, but works fine on 64 bit. -/// -/// **Known problems:** None -/// -/// **Example:** `#[repr(usize)] enum NonPortable { X = 0x1_0000_0000, Y = 0 }` -declare_lint! { - pub ENUM_CLIKE_UNPORTABLE_VARIANT, Warn, - "finds C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`" -} - -pub struct EnumClikeUnportableVariant; - -impl LintPass for EnumClikeUnportableVariant { - fn get_lints(&self) -> LintArray { - lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT) - } -} - -impl LateLintPass for EnumClikeUnportableVariant { - #[allow(cast_possible_truncation, cast_sign_loss)] - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemEnum(ref def, _) = item.node { - for var in &def.variants { - let variant = &var.node; - if let Some(ref disr) = variant.disr_expr { - use rustc_const_eval::*; - let bad = match eval_const_expr_partial(cx.tcx, &**disr, EvalHint::ExprTypeChecked, None) { - Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i, - Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i, - _ => false, - }; - if bad { - span_lint(cx, - ENUM_CLIKE_UNPORTABLE_VARIANT, - var.span, - "Clike enum variant discriminant is not portable to 32-bit targets"); - } - } - } - } - } -} diff --git a/src/enum_glob_use.rs b/src/enum_glob_use.rs deleted file mode 100644 index 37a89069d19..00000000000 --- a/src/enum_glob_use.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! 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::middle::cstore::DefLike; -use syntax::ast::NodeId; -use syntax::codemap::Span; -use utils::span_lint; - -/// **What it does:** Warns when `use`ing all variants of an enum -/// -/// **Why is this bad?** It is usually better style to use the prefixed name of an enum variant, rather than importing variants -/// -/// **Known problems:** Old-style enums that prefix the variants are still around -/// -/// **Example:** `use std::cmp::Ordering::*;` -declare_lint! { pub ENUM_GLOB_USE, Allow, - "finds use items that import all variants of an enum" } - -pub struct EnumGlobUse; - -impl LintPass for EnumGlobUse { - fn get_lints(&self) -> LintArray { - lint_array!(ENUM_GLOB_USE) - } -} - -impl LateLintPass for EnumGlobUse { - fn check_mod(&mut self, cx: &LateContext, m: &Mod, _: Span, _: NodeId) { - // only check top level `use` statements - for item in &m.item_ids { - self.lint_item(cx, cx.krate.item(item.id)); - } - } -} - -impl EnumGlobUse { - fn lint_item(&self, cx: &LateContext, item: &Item) { - 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.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.def_id()); - if let Some(child) = child.first() { - if let DefLike::DlDef(Def::Variant(..)) = child.def { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } - } - } - } - } - } - } -} diff --git a/src/enum_variants.rs b/src/enum_variants.rs deleted file mode 100644 index 67a8495e155..00000000000 --- a/src/enum_variants.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! lint on enum variants that are prefixed or suffixed by the same characters - -use rustc::lint::*; -use syntax::ast::*; -use syntax::parse::token::InternedString; -use utils::span_help_and_lint; -use utils::{camel_case_from, camel_case_until}; - -/// **What it does:** Warns on enum variants that are prefixed or suffixed by the same characters -/// -/// **Why is this bad?** Enum variant names should specify their variant, not the enum, too. -/// -/// **Known problems:** None -/// -/// **Example:** enum Cake { BlackForestCake, HummingbirdCake } -declare_lint! { - pub ENUM_VARIANT_NAMES, Warn, - "finds enums where all variants share a prefix/postfix" -} - -pub struct EnumVariantNames; - -impl LintPass for EnumVariantNames { - fn get_lints(&self) -> LintArray { - lint_array!(ENUM_VARIANT_NAMES) - } -} - -fn var2str(var: &Variant) -> InternedString { - var.node.name.name.as_str() -} - -// FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 -// fn partial_match(pre: &str, name: &str) -> usize { -// // skip(1) to ensure that the prefix never takes the whole variant name -// pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() -// } -// -// fn partial_rmatch(post: &str, name: &str) -> usize { -// // skip(1) to ensure that the postfix never takes the whole variant name -// post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() -// } - -fn partial_match(pre: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next_back(); // make sure the name is never fully matched - pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() -} - -fn partial_rmatch(post: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next(); // make sure the name is never fully matched - post.chars().rev().zip(name_iter.rev()).take_while(|&(l, r)| l == r).count() -} - -impl EarlyLintPass for EnumVariantNames { - // FIXME: #600 - #[allow(while_let_on_iterator)] - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { - if let ItemKind::Enum(ref def, _) = item.node { - if def.variants.len() < 2 { - return; - } - let first = var2str(&def.variants[0]); - let mut pre = &first[..camel_case_until(&*first)]; - let mut post = &first[camel_case_from(&*first)..]; - for var in &def.variants { - let name = var2str(var); - - let pre_match = partial_match(pre, &name); - pre = &pre[..pre_match]; - let pre_camel = camel_case_until(pre); - pre = &pre[..pre_camel]; - while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { - if next.is_lowercase() { - let last = pre.len() - last.len_utf8(); - let last_camel = camel_case_until(&pre[..last]); - pre = &pre[..last_camel]; - } else { - break; - } - } - - let post_match = partial_rmatch(post, &name); - let post_end = post.len() - post_match; - post = &post[post_end..]; - let post_camel = camel_case_from(post); - post = &post[post_camel..]; - } - let (what, value) = match (pre.is_empty(), post.is_empty()) { - (true, true) => return, - (false, _) => ("pre", pre), - (true, false) => ("post", post), - }; - span_help_and_lint(cx, - ENUM_VARIANT_NAMES, - item.span, - &format!("All variants have the same {}fix: `{}`", what, value), - &format!("remove the {}fixes and use full paths to \ - the variants instead of glob imports", - what)); - } - } -} diff --git a/src/eq_op.rs b/src/eq_op.rs deleted file mode 100644 index fb06639853c..00000000000 --- a/src/eq_op.rs +++ /dev/null @@ -1,60 +0,0 @@ -use rustc::hir::*; -use rustc::lint::*; -use utils::{SpanlessEq, span_lint}; - -/// **What it does:** This lint checks for equal operands to comparison, logical and bitwise, -/// difference and division binary operators (`==`, `>`, etc., `&&`, `||`, `&`, `|`, `^`, `-` and -/// `/`). -/// -/// **Why is this bad?** This is usually just a typo or a copy and paste error. -/// -/// **Known problems:** False negatives: We had some false positives regarding calls (notably [racer](https://github.com/phildawes/racer) had one instance of `x.pop() && x.pop()`), so we removed matching any function or method calls. We may introduce a whitelist of known pure functions in the future. -/// -/// **Example:** `x + 1 == x + 1` -declare_lint! { - pub EQ_OP, - Warn, - "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)" -} - -#[derive(Copy,Clone)] -pub struct EqOp; - -impl LintPass for EqOp { - fn get_lints(&self) -> LintArray { - lint_array!(EQ_OP) - } -} - -impl LateLintPass for EqOp { - fn check_expr(&mut self, cx: &LateContext, e: &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, - EQ_OP, - e.span, - &format!("equal expressions as operands to `{}`", op.node.as_str())); - } - } - } -} - - -fn is_valid_operator(op: &BinOp) -> bool { - match op.node { - BiSub | - BiDiv | - BiEq | - BiLt | - BiLe | - BiGt | - BiGe | - BiNe | - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr => true, - _ => false, - } -} diff --git a/src/escape.rs b/src/escape.rs deleted file mode 100644 index b5172269a1e..00000000000 --- a/src/escape.rs +++ /dev/null @@ -1,172 +0,0 @@ -use rustc::hir::*; -use rustc::hir::intravisit as visit; -use rustc::hir::map::Node::{NodeExpr, NodeStmt}; -use rustc::lint::*; -use rustc::middle::expr_use_visitor::*; -use rustc::middle::mem_categorization::{cmt, Categorization}; -use rustc::ty::adjustment::AutoAdjustment; -use rustc::ty; -use rustc::util::nodemap::NodeSet; -use syntax::ast::NodeId; -use syntax::codemap::Span; -use utils::span_lint; - -pub struct EscapePass; - -/// **What it does:** This lint checks for usage of `Box<T>` where an unboxed `T` would work fine. -/// -/// **Why is this bad?** This is an unnecessary allocation, and bad for performance. It is only necessary to allocate if you wish to move the box into something. -/// -/// **Known problems:** None -/// -/// **Example:** -/// -/// ```rust -/// fn main() { -/// let x = Box::new(1); -/// foo(*x); -/// println!("{}", *x); -/// } -/// ``` -declare_lint! { - pub BOXED_LOCAL, Warn, "using `Box<T>` where unnecessary" -} - -fn is_non_trait_box(ty: ty::Ty) -> bool { - match ty.sty { - ty::TyBox(ref inner) => !inner.is_trait(), - _ => false, - } -} - -struct EscapeDelegate<'a, 'tcx: 'a> { - tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - set: NodeSet, -} - -impl LintPass for EscapePass { - fn get_lints(&self) -> LintArray { - lint_array!(BOXED_LOCAL) - } -} - -impl LateLintPass for EscapePass { - fn check_fn(&mut self, cx: &LateContext, _: visit::FnKind, decl: &FnDecl, body: &Block, _: Span, id: NodeId) { - let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); - - let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env); - let mut v = EscapeDelegate { - tcx: cx.tcx, - set: NodeSet(), - }; - - { - let mut vis = ExprUseVisitor::new(&mut v, &infcx); - vis.walk_fn(decl, body); - } - - for node in v.set { - span_lint(cx, - BOXED_LOCAL, - cx.tcx.map.span(node), - "local variable doesn't need to be boxed here"); - } - } -} - -impl<'a, 'tcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { - fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { - if let Categorization::Local(lid) = cmt.cat { - if self.set.contains(&lid) { - if let Move(DirectRefMove) = mode { - // moved out or in. clearly can't be localized - self.set.remove(&lid); - } - } - } - } - fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} - fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, _: ConsumeMode) { - let map = &self.tcx.map; - if map.is_argument(consume_pat.id) { - // Skip closure arguments - if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) { - return; - } - if is_non_trait_box(cmt.ty) { - self.set.insert(consume_pat.id); - } - return; - } - if let Categorization::Rvalue(..) = cmt.cat { - if let Some(NodeStmt(st)) = map.find(map.get_parent_node(cmt.id)) { - if let StmtDecl(ref decl, _) = st.node { - if let DeclLocal(ref loc) = decl.node { - if let Some(ref ex) = loc.init { - if let ExprBox(..) = ex.node { - if is_non_trait_box(cmt.ty) { - // let x = box (...) - self.set.insert(consume_pat.id); - } - // TODO Box::new - // TODO vec![] - // TODO "foo".to_owned() and friends - } - } - } - } - } - } - if let Categorization::Local(lid) = cmt.cat { - if self.set.contains(&lid) { - // let y = x where x is known - // remove x, insert y - self.set.insert(consume_pat.id); - self.set.remove(&lid); - } - } - - } - fn borrow(&mut self, borrow_id: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, - loan_cause: LoanCause) { - - if let Categorization::Local(lid) = cmt.cat { - if self.set.contains(&lid) { - if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx - .tables - .borrow() - .adjustments - .get(&borrow_id) { - if LoanCause::AutoRef == loan_cause { - // x.foo() - if adj.autoderefs == 0 { - self.set.remove(&lid); // Used without autodereffing (i.e. x.clone()) - } - } else { - span_bug!(cmt.span, "Unknown adjusted AutoRef"); - } - } else if LoanCause::AddrOf == loan_cause { - // &x - if let Some(&AutoAdjustment::AdjustDerefRef(adj)) = self.tcx - .tables - .borrow() - .adjustments - .get(&self.tcx - .map - .get_parent_node(borrow_id)) { - if adj.autoderefs <= 1 { - // foo(&x) where no extra autoreffing is happening - self.set.remove(&lid); - } - } - - } else if LoanCause::MatchDiscriminant == loan_cause { - self.set.remove(&lid); // `match x` can move - } - // do nothing for matches, etc. These can't escape - } - } - } - fn decl_without_init(&mut self, _: NodeId, _: Span) {} - fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {} -} diff --git a/src/eta_reduction.rs b/src/eta_reduction.rs deleted file mode 100644 index f73b6cfed2d..00000000000 --- a/src/eta_reduction.rs +++ /dev/null @@ -1,99 +0,0 @@ -use rustc::lint::*; -use rustc::ty; -use rustc::hir::*; -use utils::{snippet_opt, span_lint_and_then, is_adjusted}; - -#[allow(missing_copy_implementations)] -pub struct EtaPass; - - -/// **What it does:** This lint checks for closures which just call another function where the function can be called directly. `unsafe` functions or calls where types get adjusted are ignored. -/// -/// **Why is this bad?** Needlessly creating a closure just costs heap space and adds code for no benefit. -/// -/// **Known problems:** None -/// -/// **Example:** `xs.map(|x| foo(x))` where `foo(_)` is a plain function that takes the exact argument type of `x`. -declare_lint! { - pub REDUNDANT_CLOSURE, Warn, - "using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)" -} - -impl LintPass for EtaPass { - fn get_lints(&self) -> LintArray { - lint_array!(REDUNDANT_CLOSURE) - } -} - -impl LateLintPass for EtaPass { - fn check_expr(&mut self, cx: &LateContext, expr: &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 blk, _) = expr.node { - if !blk.stmts.is_empty() { - // || {foo(); bar()}; can't be reduced here - return; - } - - if let Some(ref ex) = blk.expr { - if let ExprCall(ref caller, ref args) = ex.node { - if args.len() != decl.inputs.len() { - // Not the same number of arguments, there - // is no way the closure is the same as the function - return; - } - if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) { - // Are the expression or the arguments type-adjusted? Then we need the closure - return; - } - let fn_ty = cx.tcx.expr_ty(caller); - match fn_ty.sty { - // 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 == ty::FnOutput::FnDiverging { - return; - } - } - _ => (), - } - for (ref a1, ref a2) in decl.inputs.iter().zip(args) { - if let PatKind::Ident(_, ident, _) = a1.pat.node { - // XXXManishearth Should I be checking the binding mode here? - if let ExprPath(None, ref p) = a2.node { - if p.segments.len() != 1 { - // If it's a proper path, it can't be a local variable - return; - } - if p.segments[0].name != ident.node { - // The two idents should be the same - return; - } - } else { - return; - } - } else { - return; - } - } - span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| { - if let Some(snippet) = snippet_opt(cx, caller.span) { - db.span_suggestion(expr.span, "remove closure as shown:", snippet); - } - }); - } - } - } -} diff --git a/src/format.rs b/src/format.rs deleted file mode 100644 index 0726fcaeab7..00000000000 --- a/src/format.rs +++ /dev/null @@ -1,119 +0,0 @@ -use rustc::hir::*; -use rustc::hir::map::Node::NodeItem; -use rustc::lint::*; -use rustc::ty::TypeVariants; -use syntax::ast::LitKind; -use utils::paths; -use utils::{is_expn_of, match_path, match_type, span_lint, walk_ptrs_ty}; - -/// **What it does:** This lints about use of `format!("string literal with no argument")` and -/// `format!("{}", foo)` where `foo` is a string. -/// -/// **Why is this bad?** There is no point of doing that. `format!("too")` can be replaced by `"foo".to_owned()` if you really need a `String`. The even worse `&format!("foo")` is often -/// encountered in the wild. `format!("{}", foo)` can be replaced by `foo.clone()` if `foo: String` -/// or `foo.to_owned()` is `foo: &str`. -/// -/// **Known problems:** None. -/// -/// **Examples:** `format!("foo")` and `format!("{}", foo)` -declare_lint! { - pub USELESS_FORMAT, - Warn, - "useless use of `format!`" -} - -#[derive(Copy, Clone, Debug)] -pub struct FormatMacLint; - -impl LintPass for FormatMacLint { - fn get_lints(&self) -> LintArray { - lint_array![USELESS_FORMAT] - } -} - -impl LateLintPass for FormatMacLint { - fn check_expr(&mut self, cx: &LateContext, expr: &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(_, ref path) = fun.node, - args.len() == 2, - match_path(path, &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 - check_arg_is_display(cx, &args[1]) - ], { - 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 { - if tup.is_empty() { - span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); - } - } - } - _ => (), - } - } - } -} - -/// Checks if the expressions matches -/// ``` -/// { static __STATIC_FMTSTR: &[""] = _; __STATIC_FMTSTR } -/// ``` -fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { - if_let_chain! {[ - let ExprBlock(ref block) = expr.node, - block.stmts.len() == 1, - let StmtDecl(ref decl, _) = block.stmts[0].node, - let DeclItem(ref decl) = decl.node, - let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id), - decl.name.as_str() == "__STATIC_FMTSTR", - let ItemStatic(_, _, ref expr) = decl.node, - let ExprAddrOf(_, ref expr) = expr.node, // &[""] - let ExprVec(ref expr) = expr.node, - expr.len() == 1, - let ExprLit(ref lit) = expr[0].node, - let LitKind::Str(ref lit, _) = lit.node, - lit.is_empty() - ], { - return true; - }} - - false -} - -/// Checks if the expressions matches -/// ``` -/// &match (&42,) { -/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)], -/// }) -/// ``` -fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { - if_let_chain! {[ - let ExprAddrOf(_, ref expr) = expr.node, - let ExprMatch(_, ref arms, _) = expr.node, - arms.len() == 1, - arms[0].pats.len() == 1, - let PatKind::Tup(ref pat) = arms[0].pats[0].node, - pat.len() == 1, - let ExprVec(ref exprs) = arms[0].body.node, - exprs.len() == 1, - let ExprCall(_, ref args) = exprs[0].node, - args.len() == 2, - let ExprPath(None, ref path) = args[1].node, - match_path(path, &paths::DISPLAY_FMT_METHOD) - ], { - let ty = walk_ptrs_ty(cx.tcx.pat_ty(&pat[0])); - - return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING); - }} - - false -} diff --git a/src/formatting.rs b/src/formatting.rs deleted file mode 100644 index aa6dd46cf0b..00000000000 --- a/src/formatting.rs +++ /dev/null @@ -1,166 +0,0 @@ -use rustc::lint::*; -use syntax::codemap::mk_sp; -use syntax::ast; -use utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; -use syntax::ptr::P; - -/// **What it does:** This lint looks for use of the non-existent `=*`, `=!` and `=-` operators. -/// -/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or confusing. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`? -/// ``` -declare_lint! { - pub SUSPICIOUS_ASSIGNMENT_FORMATTING, - Warn, - "suspicious formatting of `*=`, `-=` or `!=`" -} - -/// **What it does:** This lint checks for formatting of `else if`. It lints if the `else` and `if` -/// are not on the same line or the `else` seems to be missing. -/// -/// **Why is this bad?** This is probably some refactoring remnant, even if the code is correct, it -/// might look confusing. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// if foo { -/// } if bar { // looks like an `else` is missing here -/// } -/// -/// if foo { -/// } else -/// -/// if bar { // this is the `else` block of the previous `if`, but should it be? -/// } -/// ``` -declare_lint! { - pub SUSPICIOUS_ELSE_FORMATTING, - Warn, - "suspicious formatting of `else if`" -} - -#[derive(Copy,Clone)] -pub struct Formatting; - -impl LintPass for Formatting { - fn get_lints(&self) -> LintArray { - lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING, SUSPICIOUS_ELSE_FORMATTING] - } -} - -impl EarlyLintPass for Formatting { - fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { - for w in block.stmts.windows(2) { - match (&w[0].node, &w[1].node) { - (&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); - } - _ => (), - } - } - - if let Some(ref expr) = block.expr { - if let Some(ref stmt) = block.stmts.iter().last() { - if let ast::StmtKind::Expr(ref first, _) = stmt.node { - check_consecutive_ifs(cx, first, expr); - } - } - } - } - - fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { - check_assign(cx, expr); - check_else_if(cx, expr); - } -} - -/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. -fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { - if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { - if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(cx, lhs.span) { - let eq_span = mk_sp(lhs.span.hi, rhs.span.lo); - - if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node { - if let Some(eq_snippet) = snippet_opt(cx, eq_span) { - let op = ast::UnOp::to_string(op); - let eqop_span = mk_sp(lhs.span.hi, sub_rhs.span.lo); - if eq_snippet.ends_with('=') { - span_note_and_lint(cx, - SUSPICIOUS_ASSIGNMENT_FORMATTING, - eqop_span, - &format!("this looks like you are trying to use `.. {op}= ..`, but you \ - really are doing `.. = ({op} ..)`", - op = op), - eqop_span, - &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op)); - } - } - } - } - } -} - -/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`. -fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { - if let Some((then, &Some(ref else_))) = unsugar_if(expr) { - if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(cx, then.span) { - // this will be a span from the closing ‘}’ of the “then” block (excluding) to the - // “if” of the “else if” block (excluding) - let else_span = mk_sp(then.span.hi, else_.span.lo); - - // the snippet should look like " else \n " with maybe comments anywhere - // it’s bad when there is a ‘\n’ after the “else” - if let Some(else_snippet) = snippet_opt(cx, else_span) { - let else_pos = else_snippet.find("else").expect("there must be a `else` here"); - - if else_snippet[else_pos..].contains('\n') { - span_note_and_lint(cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - "this is an `else if` but the formatting might hide it", - else_span, - "to remove this lint, remove the `else` or remove the new line between `else` \ - and `if`"); - } - } - } - } -} - -/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. -fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { - if !differing_macro_contexts(first.span, second.span) && !in_macro(cx, first.span) && - unsugar_if(first).is_some() && unsugar_if(second).is_some() { - // where the else would be - let else_span = mk_sp(first.span.hi, second.span.lo); - - if let Some(else_snippet) = snippet_opt(cx, else_span) { - if !else_snippet.contains('\n') { - span_note_and_lint(cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - "this looks like an `else if` but the `else` is missing", - else_span, - "to remove this lint, add the missing `else` or add a new line before the second \ - `if`"); - } - } - } -} - -/// Match `if` or `else if` expressions and return the `then` and `else` block. -fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> { - match expr.node { - ast::ExprKind::If(_, ref then, ref else_) | - ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), - _ => None, - } -} diff --git a/src/functions.rs b/src/functions.rs deleted file mode 100644 index d9334447226..00000000000 --- a/src/functions.rs +++ /dev/null @@ -1,76 +0,0 @@ -use rustc::lint::*; -use rustc::hir; -use rustc::hir::intravisit; -use syntax::ast; -use syntax::codemap::Span; -use utils::span_lint; - -/// **What it does:** Check for functions with too many parameters. -/// -/// **Why is this bad?** Functions with lots of parameters are considered bad style and reduce -/// readability (“what does the 5th parameter mean?”). Consider grouping some parameters into a -/// new type. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// -/// ``` -/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. } -/// ``` -declare_lint! { - pub TOO_MANY_ARGUMENTS, - Warn, - "functions with too many arguments" -} - -#[derive(Copy,Clone)] -pub struct Functions { - threshold: u64, -} - -impl Functions { - pub fn new(threshold: u64) -> Functions { - Functions { threshold: threshold } - } -} - -impl LintPass for Functions { - fn get_lints(&self) -> LintArray { - lint_array!(TOO_MANY_ARGUMENTS) - } -} - -impl LateLintPass for Functions { - fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) { - use rustc::hir::map::Node::*; - - if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { - match item.node { - hir::ItemImpl(_, _, _, Some(_), _, _) | - hir::ItemDefaultImpl(..) => return, - _ => (), - } - } - - self.check_arg_number(cx, decl, span); - } - - fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { - if let hir::MethodTraitItem(ref sig, _) = item.node { - self.check_arg_number(cx, &sig.decl, item.span); - } - } -} - -impl Functions { - fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { - let args = decl.inputs.len() as u64; - if args > self.threshold { - span_lint(cx, - TOO_MANY_ARGUMENTS, - span, - &format!("this function has too many arguments ({}/{})", args, self.threshold)); - } - } -} diff --git a/src/identity_op.rs b/src/identity_op.rs deleted file mode 100644 index 4c1f01b7385..00000000000 --- a/src/identity_op.rs +++ /dev/null @@ -1,72 +0,0 @@ -use consts::{constant_simple, Constant}; -use rustc::lint::*; -use rustc::hir::*; -use syntax::codemap::Span; -use utils::{span_lint, snippet, in_macro}; -use rustc_const_math::ConstInt; - -/// **What it does:** This lint checks for identity operations, e.g. `x + 0`. -/// -/// **Why is this bad?** This code can be removed without changing the meaning. So it just obscures what's going on. Delete it mercilessly. -/// -/// **Known problems:** None -/// -/// **Example:** `x / 1 + 0 * 1 - 0 | 0` -declare_lint! { - pub IDENTITY_OP, Warn, - "using identity operations, e.g. `x + 0` or `y / 1`" -} - -#[derive(Copy,Clone)] -pub struct IdentityOp; - -impl LintPass for IdentityOp { - fn get_lints(&self) -> LintArray { - lint_array!(IDENTITY_OP) - } -} - -impl LateLintPass for IdentityOp { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if in_macro(cx, e.span) { - return; - } - if let ExprBinary(ref cmp, ref left, ref right) = e.node { - match cmp.node { - 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); - } - _ => (), - } - } - } -} - - -fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { - if let Some(v @ Constant::Int(_)) = constant_simple(e) { - if match m { - 0 => v == Constant::Int(ConstInt::Infer(0)), - -1 => v == Constant::Int(ConstInt::InferSigned(-1)), - 1 => v == Constant::Int(ConstInt::Infer(1)), - _ => unreachable!(), - } { - span_lint(cx, - IDENTITY_OP, - span, - &format!("the operation is ineffective. Consider reducing it to `{}`", - snippet(cx, arg, ".."))); - } - } -} diff --git a/src/if_not_else.rs b/src/if_not_else.rs deleted file mode 100644 index d78eba9877b..00000000000 --- a/src/if_not_else.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! lint on if branches that could be swapped so no `!` operation is necessary on the condition - -use rustc::lint::*; -use syntax::ast::*; - -use utils::span_help_and_lint; - -/// **What it does:** Warns on the use of `!` or `!=` in an if condition with an else branch -/// -/// **Why is this bad?** Negations reduce the readability of statements -/// -/// **Known problems:** None -/// -/// **Example:** if !v.is_empty() { a() } else { b() } -declare_lint! { - pub IF_NOT_ELSE, Allow, - "finds if branches that could be swapped so no negation operation is necessary on the condition" -} - -pub struct IfNotElse; - -impl LintPass for IfNotElse { - fn get_lints(&self) -> LintArray { - lint_array!(IF_NOT_ELSE) - } -} - -impl EarlyLintPass for IfNotElse { - fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { - if let ExprKind::If(ref cond, _, Some(ref els)) = item.node { - if let ExprKind::Block(..) = els.node { - match cond.node { - ExprKind::Unary(UnOp::Not, _) => { - span_help_and_lint(cx, - IF_NOT_ELSE, - 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/src/items_after_statements.rs b/src/items_after_statements.rs deleted file mode 100644 index 2e6b33ab390..00000000000 --- a/src/items_after_statements.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! lint when items are used after statements - -use rustc::lint::*; -use syntax::ast::*; -use utils::in_macro; - -/// **What it does:** This lints checks for items declared after some statement in a block -/// -/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are -/// processed in order. This might cause confusion as it's hard to figure out which item is meant -/// in a statement. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ```rust -/// fn foo() { -/// println!("cake"); -/// } -/// fn main() { -/// foo(); // prints "foo" -/// fn foo() { -/// println!("foo"); -/// } -/// foo(); // prints "foo" -/// } -/// ``` -declare_lint! { - pub ITEMS_AFTER_STATEMENTS, - Allow, - "finds blocks where an item comes after a statement" -} - -pub struct ItemsAfterStatements; - -impl LintPass for ItemsAfterStatements { - fn get_lints(&self) -> LintArray { - lint_array!(ITEMS_AFTER_STATEMENTS) - } -} - -impl EarlyLintPass for ItemsAfterStatements { - fn check_block(&mut self, cx: &EarlyContext, item: &Block) { - if in_macro(cx, item.span) { - return; - } - let mut stmts = item.stmts.iter().map(|stmt| &stmt.node); - // skip initial items - while let Some(&StmtKind::Decl(ref decl, _)) = stmts.next() { - if let DeclKind::Local(_) = decl.node { - break; - } - } - // lint on all further items - for stmt in stmts { - if let StmtKind::Decl(ref decl, _) = *stmt { - if let DeclKind::Item(ref it) = decl.node { - if in_macro(cx, it.span) { - return; - } - cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, - it.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope") - .emit(); - } - } - } - } -} diff --git a/src/len_zero.rs b/src/len_zero.rs deleted file mode 100644 index b6dea831690..00000000000 --- a/src/len_zero.rs +++ /dev/null @@ -1,202 +0,0 @@ -use rustc::lint::*; -use rustc::hir::def_id::DefId; -use rustc::ty::{self, MethodTraitItemId, ImplOrTraitItemId}; -use rustc::hir::*; -use syntax::ast::{Lit, LitKind, Name}; -use syntax::codemap::{Span, Spanned}; -use syntax::ptr::P; -use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_then, walk_ptrs_ty}; - -/// **What it does:** This lint checks for getting the length of something via `.len()` just to compare to zero, and suggests using `.is_empty()` where applicable. -/// -/// **Why is this bad?** Some structures can answer `.is_empty()` much faster than calculating their length. So it is good to get into the habit of using `.is_empty()`, and having it is cheap. Besides, it makes the intent clearer than a comparison. -/// -/// **Known problems:** None -/// -/// **Example:** `if x.len() == 0 { .. }` -declare_lint! { - pub LEN_ZERO, Warn, - "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ - could be used instead" -} - -/// **What it does:** This lint checks for items that implement `.len()` but not `.is_empty()`. -/// -/// **Why is this bad?** It is good custom to have both methods, because for some data structures, asking about the length will be a costly operation, whereas `.is_empty()` can usually answer in constant time. Also it used to lead to false positives on the [`len_zero`](#len_zero) lint – currently that lint will ignore such entities. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// impl X { -/// fn len(&self) -> usize { .. } -/// } -/// ``` -declare_lint! { - pub LEN_WITHOUT_IS_EMPTY, Warn, - "traits and impls that have `.len()` but not `.is_empty()`" -} - -#[derive(Copy,Clone)] -pub struct LenZero; - -impl LintPass for LenZero { - fn get_lints(&self) -> LintArray { - lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) - } -} - -impl LateLintPass for LenZero { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if in_macro(cx, item.span) { - return; - } - - match item.node { - ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items), - ItemImpl(_, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items), - _ => (), - } - } - - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_macro(cx, expr.span) { - return; - } - - if let ExprBinary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node { - match cmp { - BiEq => check_cmp(cx, expr.span, left, right, ""), - BiGt | BiNe => check_cmp(cx, expr.span, left, right, "!"), - _ => (), - } - } - } -} - -fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) { - fn is_named_self(item: &TraitItem, name: &str) -> bool { - item.name.as_str() == name && - if let MethodTraitItem(ref sig, _) = item.node { - is_self_sig(sig) - } else { - false - } - } - - if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) { - for i in trait_items { - if is_named_self(i, "len") { - span_lint(cx, - LEN_WITHOUT_IS_EMPTY, - i.span, - &format!("trait `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ - Consider adding one", - item.name)); - } - } - } -} - -fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) { - fn is_named_self(item: &ImplItem, name: &str) -> bool { - item.name.as_str() == name && - if let ImplItemKind::Method(ref sig, _) = item.node { - is_self_sig(sig) - } else { - false - } - } - - if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) { - for i in impl_items { - if is_named_self(i, "len") { - let ty = cx.tcx.node_id_to_type(item.id); - - span_lint(cx, - LEN_WITHOUT_IS_EMPTY, - i.span, - &format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \ - Consider adding one", - ty)); - return; - } - } - } -} - -fn is_self_sig(sig: &MethodSig) -> bool { - if sig.decl.has_self() { - sig.decl.inputs.len() == 1 - } else { - false - } -} - -fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) { - // check if we are in an is_empty() method - if let Some(name) = get_item_name(cx, left) { - if name.as_str() == "is_empty" { - return; - } - } - match (&left.node, &right.node) { - (&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) - } - _ => (), - } -} - -fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { - if let Spanned { node: LitKind::Int(0, _), .. } = *lit { - if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { - span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| { - db.span_suggestion(span, - "consider using `is_empty`", - format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_"))); - }); - } - } -} - -/// Check if this type has an `is_empty` method. -fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { - /// Get an `ImplOrTraitItem` and return true if it matches `is_empty(self)`. - fn is_is_empty(cx: &LateContext, id: &ImplOrTraitItemId) -> bool { - if let MethodTraitItemId(def_id) = *id { - if let ty::MethodTraitItem(ref method) = cx.tcx.impl_or_trait_item(def_id) { - method.name.as_str() == "is_empty" && method.fty.sig.skip_binder().inputs.len() == 1 - } else { - false - } - } else { - false - } - } - - /// Check the inherent impl's items for an `is_empty(self)` method. - fn has_is_empty_impl(cx: &LateContext, id: &DefId) -> bool { - let impl_items = cx.tcx.impl_items.borrow(); - cx.tcx.inherent_impls.borrow().get(id).map_or(false, |ids| { - ids.iter().any(|iid| impl_items.get(iid).map_or(false, |iids| iids.iter().any(|i| is_is_empty(cx, i)))) - }) - } - - let ty = &walk_ptrs_ty(cx.tcx.expr_ty(expr)); - match ty.sty { - ty::TyTrait(_) => { - cx.tcx - .trait_item_def_ids - .borrow() - .get(&ty.ty_to_def_id().expect("trait impl not found")) - .map_or(false, |ids| ids.iter().any(|i| is_is_empty(cx, i))) - } - ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, &id)), - ty::TyEnum(ref id, _) | - ty::TyStruct(ref id, _) => has_is_empty_impl(cx, &id.did), - ty::TyArray(..) | ty::TyStr => true, - _ => false, - } -} diff --git a/src/lib.rs b/src/lib.rs index 41c26cf7109..f9a6588e904 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,173 +1,13 @@ +// error-pattern:cargo-clippy #![feature(type_macros)] #![feature(plugin_registrar, box_syntax)] #![feature(rustc_private, collections)] -#![feature(iter_arith)] #![feature(custom_attribute)] #![feature(slice_patterns)] #![feature(question_mark)] #![feature(stmt_expr_attributes)] #![allow(indexing_slicing, shadow_reuse, unknown_lints)] -extern crate rustc_driver; -extern crate getopts; - -use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; -use rustc::session::{config, Session}; -use rustc::session::config::{Input, ErrorOutputType}; -use syntax::diagnostics; -use std::path::PathBuf; -use std::process::Command; - -struct ClippyCompilerCalls(RustcDefaultCalls); - -impl std::default::Default for ClippyCompilerCalls { - fn default() -> Self { - Self::new() - } -} - -impl ClippyCompilerCalls { - fn new() -> Self { - ClippyCompilerCalls(RustcDefaultCalls) - } -} - -impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { - fn early_callback(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - descriptions: &diagnostics::registry::Registry, - output: ErrorOutputType) - -> Compilation { - self.0.early_callback(matches, sopts, descriptions, output) - } - fn no_input(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>, - descriptions: &diagnostics::registry::Registry) - -> Option<(Input, Option<PathBuf>)> { - self.0.no_input(matches, sopts, odir, ofile, descriptions) - } - fn late_callback(&mut self, - matches: &getopts::Matches, - sess: &Session, - input: &Input, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>) - -> Compilation { - self.0.late_callback(matches, sess, input, odir, ofile) - } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.0.build_controller(sess, matches); - - 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")); - registry.args_hidden = Some(Vec::new()); - plugin_registrar(&mut registry); - - let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.mir_passes.borrow_mut().extend(mir_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - } - old(state); - }); - - control - } -} - -use std::path::Path; - -pub fn main() { - use std::env; - - if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { - return; - } - - let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); - - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("SYSROOT").map(|s| s.to_owned()) - .or(Command::new("rustc").arg("--print") - .arg("sysroot") - .output().ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - ) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"), - }; - - if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); - let path = std::env::current_exe().expect("current executable path invalid"); - 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?"); - - if let Some(code) = exit_status.code() { - std::process::exit(code); - } - } else { - let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { - env::args().collect() - } else { - env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() - }; - let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); - - if let Err(err_count) = result { - if err_count > 0 { - std::process::exit(1); - } - } - } -} - -fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String> - where P: AsRef<Path>, I: Iterator<Item=String> { - - let mut args = vec!["rustc".to_owned()]; - - let mut found_dashes = false; - for arg in old_args { - found_dashes |= arg == "--"; - args.push(arg); - } - if !found_dashes { - args.push("--".to_owned()); - } - args.push("-L".to_owned()); - args.push(dep_path.as_ref().to_string_lossy().into_owned()); - args.push(String::from("--sysroot")); - args.push(sysroot); - args.push("-Zno-trans".to_owned()); - args -} - #[macro_use] extern crate syntax; #[macro_use] @@ -196,371 +36,28 @@ extern crate rustc_const_eval; extern crate rustc_const_math; use rustc_plugin::Registry; +extern crate clippy_lints; + +pub use clippy_lints::*; + macro_rules! declare_restriction_lint { { pub $name:tt, $description:tt } => { declare_lint! { pub $name, Allow, $description } }; } -pub mod consts; -#[macro_use] -pub mod utils; - -// begin lints modules, do not remove this comment, it’s used in `update_lints` -pub mod approx_const; -pub mod arithmetic; -pub mod array_indexing; -pub mod assign_ops; -pub mod attrs; -pub mod bit_mask; -pub mod blacklisted_name; -pub mod block_in_if_condition; -pub mod booleans; -pub mod collapsible_if; -pub mod copies; -pub mod cyclomatic_complexity; -pub mod derive; -pub mod doc; -pub mod drop_ref; -pub mod entry; -pub mod enum_clike; -pub mod enum_glob_use; -pub mod enum_variants; -pub mod eq_op; -pub mod escape; -pub mod eta_reduction; -pub mod format; -pub mod formatting; -pub mod functions; -pub mod identity_op; -pub mod if_not_else; -pub mod items_after_statements; -pub mod len_zero; -pub mod lifetimes; -pub mod loops; -pub mod map_clone; -pub mod matches; -pub mod mem_forget; -pub mod methods; -pub mod minmax; -pub mod misc; -pub mod misc_early; -pub mod mut_mut; -pub mod mut_reference; -pub mod mutex_atomic; -pub mod needless_bool; -pub mod needless_borrow; -pub mod needless_update; -pub mod neg_multiply; -pub mod new_without_default; -pub mod no_effect; -pub mod non_expressive_names; -pub mod open_options; -pub mod overflow_check_conditional; -pub mod panic; -pub mod precedence; -pub mod print; -pub mod ptr_arg; -pub mod ranges; -pub mod regex; -pub mod returns; -pub mod shadow; -pub mod strings; -pub mod swap; -pub mod temporary_assignment; -pub mod transmute; -pub mod types; -pub mod unicode; -pub mod unsafe_removed_from_name; -pub mod unused_label; -pub mod vec; -pub mod zero_div_zero; -// end lints modules, do not remove this comment, it’s used in `update_lints` - mod reexport { pub use syntax::ast::{Name, NodeId}; } #[plugin_registrar] -#[cfg_attr(rustfmt, rustfmt_skip)] pub fn plugin_registrar(reg: &mut Registry) { - let conf = match utils::conf::conf_file(reg.args()) { - Ok(file_name) => { - // if the user specified a file, it must exist, otherwise default to `clippy.toml` but - // do not require the file to exist - let (ref file_name, must_exist) = if let Some(ref file_name) = file_name { - (&**file_name, true) - } else { - ("clippy.toml", false) - }; - - let (conf, errors) = utils::conf::read_conf(file_name, must_exist); - - // all conf errors are non-fatal, we just use the default conf in case of error - for error in errors { - reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit(); - } - - conf - } - Err((err, span)) => { - reg.sess.struct_span_err(span, err) - .span_note(span, "Clippy will use default configuration") - .emit(); - utils::conf::Conf::default() - } - }; - - 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"); - // end deprecated lints, do not remove this comment, it’s used in `update_lints` - - reg.register_late_lint_pass(box types::TypePass); - reg.register_late_lint_pass(box booleans::NonminimalBool); - reg.register_late_lint_pass(box misc::TopLevelRefPass); - reg.register_late_lint_pass(box misc::CmpNan); - reg.register_late_lint_pass(box eq_op::EqOp); - reg.register_early_lint_pass(box enum_variants::EnumVariantNames); - reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); - reg.register_late_lint_pass(box enum_clike::EnumClikeUnportableVariant); - reg.register_late_lint_pass(box bit_mask::BitMask); - reg.register_late_lint_pass(box ptr_arg::PtrArg); - reg.register_late_lint_pass(box needless_bool::NeedlessBool); - reg.register_late_lint_pass(box needless_bool::BoolComparison); - reg.register_late_lint_pass(box approx_const::ApproxConstant); - reg.register_late_lint_pass(box misc::FloatCmp); - reg.register_early_lint_pass(box precedence::Precedence); - reg.register_late_lint_pass(box eta_reduction::EtaPass); - reg.register_late_lint_pass(box identity_op::IdentityOp); - reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements); - reg.register_late_lint_pass(box mut_mut::MutMut); - reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); - reg.register_late_lint_pass(box len_zero::LenZero); - reg.register_late_lint_pass(box misc::CmpOwned); - reg.register_late_lint_pass(box attrs::AttrPass); - reg.register_late_lint_pass(box collapsible_if::CollapsibleIf); - reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition); - reg.register_late_lint_pass(box misc::ModuloOne); - reg.register_late_lint_pass(box unicode::Unicode); - reg.register_late_lint_pass(box strings::StringAdd); - reg.register_early_lint_pass(box returns::ReturnPass); - reg.register_late_lint_pass(box methods::MethodsPass); - reg.register_late_lint_pass(box shadow::ShadowPass); - reg.register_late_lint_pass(box types::LetPass); - reg.register_late_lint_pass(box types::UnitCmp); - reg.register_late_lint_pass(box loops::LoopsPass); - reg.register_late_lint_pass(box lifetimes::LifetimePass); - reg.register_late_lint_pass(box entry::HashMapLint); - reg.register_late_lint_pass(box ranges::StepByZero); - reg.register_late_lint_pass(box types::CastPass); - reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold)); - reg.register_late_lint_pass(box matches::MatchPass); - reg.register_late_lint_pass(box misc::PatternPass); - reg.register_late_lint_pass(box minmax::MinMaxPass); - reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions); - reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass); - reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); - reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); - reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow); - reg.register_late_lint_pass(box no_effect::NoEffectPass); - reg.register_late_lint_pass(box map_clone::MapClonePass); - reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass); - 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 escape::EscapePass); - reg.register_early_lint_pass(box misc_early::MiscEarly); - reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); - reg.register_late_lint_pass(box array_indexing::ArrayIndexing); - reg.register_late_lint_pass(box panic::PanicPass); - reg.register_late_lint_pass(box strings::StringLitAsBytes); - reg.register_late_lint_pass(box derive::Derive); - reg.register_late_lint_pass(box types::CharLitAsU8); - reg.register_late_lint_pass(box print::PrintLint); - reg.register_late_lint_pass(box vec::UselessVec); - reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { - max_single_char_names: conf.max_single_char_names, - }); - reg.register_late_lint_pass(box drop_ref::DropRefPass); - reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); - reg.register_late_lint_pass(box types::InvalidUpcastComparisons); - reg.register_late_lint_pass(box regex::RegexPass::default()); - reg.register_late_lint_pass(box copies::CopyAndPaste); - reg.register_late_lint_pass(box format::FormatMacLint); - reg.register_early_lint_pass(box formatting::Formatting); - reg.register_late_lint_pass(box swap::Swap); - reg.register_early_lint_pass(box if_not_else::IfNotElse); - reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); - reg.register_late_lint_pass(box unused_label::UnusedLabel); - reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); - reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); - 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_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); - - reg.register_lint_group("clippy_restrictions", vec![ - arithmetic::FLOAT_ARITHMETIC, - arithmetic::INTEGER_ARITHMETIC, - assign_ops::ASSIGN_OPS, - ]); - - reg.register_lint_group("clippy_pedantic", vec![ - array_indexing::INDEXING_SLICING, - booleans::NONMINIMAL_BOOL, - enum_glob_use::ENUM_GLOB_USE, - if_not_else::IF_NOT_ELSE, - items_after_statements::ITEMS_AFTER_STATEMENTS, - matches::SINGLE_MATCH_ELSE, - mem_forget::MEM_FORGET, - methods::OPTION_UNWRAP_USED, - methods::RESULT_UNWRAP_USED, - methods::WRONG_PUB_SELF_CONVENTION, - misc::USED_UNDERSCORE_BINDING, - mut_mut::MUT_MUT, - mutex_atomic::MUTEX_INTEGER, - non_expressive_names::SIMILAR_NAMES, - print::PRINT_STDOUT, - print::USE_DEBUG, - shadow::SHADOW_REUSE, - shadow::SHADOW_SAME, - shadow::SHADOW_UNRELATED, - strings::STRING_ADD, - strings::STRING_ADD_ASSIGN, - types::CAST_POSSIBLE_TRUNCATION, - types::CAST_POSSIBLE_WRAP, - types::CAST_PRECISION_LOSS, - types::CAST_SIGN_LOSS, - types::INVALID_UPCAST_COMPARISONS, - unicode::NON_ASCII_LITERAL, - unicode::UNICODE_NOT_NFC, - ]); + register_plugins(reg); +} - reg.register_lint_group("clippy", vec![ - approx_const::APPROX_CONSTANT, - array_indexing::OUT_OF_BOUNDS_INDEXING, - assign_ops::ASSIGN_OP_PATTERN, - attrs::DEPRECATED_SEMVER, - attrs::INLINE_ALWAYS, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - blacklisted_name::BLACKLISTED_NAME, - block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, - block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, - booleans::LOGIC_BUG, - collapsible_if::COLLAPSIBLE_IF, - copies::IF_SAME_THEN_ELSE, - copies::IFS_SAME_COND, - copies::MATCH_SAME_ARMS, - cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, - derive::DERIVE_HASH_XOR_EQ, - derive::EXPL_IMPL_CLONE_ON_COPY, - doc::DOC_MARKDOWN, - drop_ref::DROP_REF, - entry::MAP_ENTRY, - enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - enum_variants::ENUM_VARIANT_NAMES, - eq_op::EQ_OP, - escape::BOXED_LOCAL, - eta_reduction::REDUNDANT_CLOSURE, - format::USELESS_FORMAT, - formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - formatting::SUSPICIOUS_ELSE_FORMATTING, - functions::TOO_MANY_ARGUMENTS, - identity_op::IDENTITY_OP, - len_zero::LEN_WITHOUT_IS_EMPTY, - len_zero::LEN_ZERO, - lifetimes::NEEDLESS_LIFETIMES, - lifetimes::UNUSED_LIFETIMES, - loops::EMPTY_LOOP, - loops::EXPLICIT_COUNTER_LOOP, - loops::EXPLICIT_ITER_LOOP, - loops::FOR_KV_MAP, - loops::FOR_LOOP_OVER_OPTION, - loops::FOR_LOOP_OVER_RESULT, - loops::ITER_NEXT_LOOP, - loops::NEEDLESS_RANGE_LOOP, - loops::REVERSE_RANGE_LOOP, - loops::UNUSED_COLLECT, - loops::WHILE_LET_LOOP, - loops::WHILE_LET_ON_ITERATOR, - map_clone::MAP_CLONE, - matches::MATCH_BOOL, - matches::MATCH_OVERLAPPING_ARM, - matches::MATCH_REF_PATS, - matches::SINGLE_MATCH, - methods::CHARS_NEXT_CMP, - methods::CLONE_DOUBLE_REF, - methods::CLONE_ON_COPY, - methods::EXTEND_FROM_SLICE, - methods::FILTER_NEXT, - methods::NEW_RET_NO_SELF, - methods::OK_EXPECT, - methods::OPTION_MAP_UNWRAP_OR, - methods::OPTION_MAP_UNWRAP_OR_ELSE, - methods::OR_FUN_CALL, - methods::SEARCH_IS_SOME, - methods::SHOULD_IMPLEMENT_TRAIT, - methods::SINGLE_CHAR_PATTERN, - methods::TEMPORARY_CSTRING_AS_PTR, - methods::WRONG_SELF_CONVENTION, - minmax::MIN_MAX, - misc::CMP_NAN, - misc::CMP_OWNED, - misc::FLOAT_CMP, - misc::MODULO_ONE, - misc::REDUNDANT_PATTERN, - misc::TOPLEVEL_REF_ARG, - misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - misc_early::REDUNDANT_CLOSURE_CALL, - misc_early::UNNEEDED_FIELD_PATTERN, - mut_reference::UNNECESSARY_MUT_PASSED, - mutex_atomic::MUTEX_ATOMIC, - needless_bool::BOOL_COMPARISON, - needless_bool::NEEDLESS_BOOL, - needless_borrow::NEEDLESS_BORROW, - needless_update::NEEDLESS_UPDATE, - neg_multiply::NEG_MULTIPLY, - new_without_default::NEW_WITHOUT_DEFAULT, - new_without_default::NEW_WITHOUT_DEFAULT_DERIVE, - no_effect::NO_EFFECT, - no_effect::UNNECESSARY_OPERATION, - non_expressive_names::MANY_SINGLE_CHAR_NAMES, - open_options::NONSENSICAL_OPEN_OPTIONS, - overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - panic::PANIC_PARAMS, - precedence::PRECEDENCE, - ptr_arg::PTR_ARG, - ranges::RANGE_STEP_BY_ZERO, - ranges::RANGE_ZIP_WITH_LEN, - regex::INVALID_REGEX, - regex::REGEX_MACRO, - regex::TRIVIAL_REGEX, - returns::LET_AND_RETURN, - returns::NEEDLESS_RETURN, - strings::STRING_LIT_AS_BYTES, - swap::ALMOST_SWAPPED, - swap::MANUAL_SWAP, - temporary_assignment::TEMPORARY_ASSIGNMENT, - transmute::CROSSPOINTER_TRANSMUTE, - transmute::TRANSMUTE_PTR_TO_REF, - transmute::USELESS_TRANSMUTE, - types::ABSURD_EXTREME_COMPARISONS, - types::BOX_VEC, - types::CHAR_LIT_AS_U8, - types::LET_UNIT_VALUE, - types::LINKEDLIST, - types::TYPE_COMPLEXITY, - types::UNIT_CMP, - unicode::ZERO_WIDTH_SPACE, - unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - unused_label::UNUSED_LABEL, - vec::USELESS_VEC, - zero_div_zero::ZERO_DIVIDED_BY_ZERO, - ]); +// only exists to let the dogfood integration test works. +// Don't run clippy as an executable directly +#[allow(dead_code, print_stdout)] +fn main() { + panic!("Please use the cargo-clippy executable"); } diff --git a/src/lifetimes.rs b/src/lifetimes.rs deleted file mode 100644 index 797e9708b60..00000000000 --- a/src/lifetimes.rs +++ /dev/null @@ -1,347 +0,0 @@ -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 std::collections::{HashSet, HashMap}; -use syntax::codemap::Span; -use utils::{in_external_macro, span_lint}; - -/// **What it does:** This lint checks for lifetime annotations which can be removed by relying on lifetime elision. -/// -/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. -/// -/// **Known problems:** Potential false negatives: we bail out if the function has a `where` clause where lifetimes are mentioned. -/// -/// **Example:** `fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }` -declare_lint! { - pub NEEDLESS_LIFETIMES, - Warn, - "using explicit lifetimes for references in function arguments when elision rules \ - would allow omitting them" -} - -/// **What it does:** This lint checks for lifetimes in generics that are never used anywhere else. -/// -/// **Why is this bad?** The additional lifetimes make the code look more complicated, while there is nothing out of the ordinary going on. Removing them leads to more readable code. -/// -/// **Known problems:** None -/// -/// **Example:** `fn unused_lifetime<'a>(x: u8) { .. }` -declare_lint! { - pub UNUSED_LIFETIMES, - Warn, - "unused lifetimes in function definitions" -} - -#[derive(Copy,Clone)] -pub struct LifetimePass; - -impl LintPass for LifetimePass { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES) - } -} - -impl LateLintPass for LifetimePass { - fn check_item(&mut self, cx: &LateContext, item: &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) { - 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) { - if let MethodTraitItem(ref sig, _) = item.node { - check_fn_inner(cx, &sig.decl, &sig.generics, item.span); - } - } -} - -/// The lifetime of a &-reference. -#[derive(PartialEq, Eq, Hash, Debug)] -enum RefLt { - Unnamed, - Static, - Named(Name), -} - -fn bound_lifetimes(bound: &TyParamBound) -> Option<HirVec<&Lifetime>> { - if let TraitTyParamBound(ref trait_ref, _) = *bound { - let lt = trait_ref.trait_ref - .path - .segments - .last() - .expect("a path must have at least one segment") - .parameters - .lifetimes(); - - Some(lt) - } else { - None - } -} - -fn check_fn_inner(cx: &LateContext, decl: &FnDecl, generics: &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(|ref typ| typ.bounds.iter().filter_map(bound_lifetimes).flat_map(|lts| lts)); - - if could_use_elision(cx, decl, &generics.lifetimes, bounds_lts) { - span_lint(cx, - NEEDLESS_LIFETIMES, - span, - "explicit lifetimes given in parameter types where they could be elided"); - } - report_extra_lifetimes(cx, decl, generics); -} - -fn could_use_elision<'a, T: Iterator<Item = &'a Lifetime>>(cx: &LateContext, func: &FnDecl, - named_lts: &[LifetimeDef], bounds_lts: T) - -> bool { - // 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 - // All lifetimes must be unnamed, 'static or defined without bounds on the - // level of the current item. - - // check named LTs - let allowed_lts = allowed_lts_from(named_lts); - - // these will collect all the lifetimes for references in arg/return types - let mut input_visitor = RefVisitor::new(cx); - let mut output_visitor = RefVisitor::new(cx); - - // extract lifetimes in input argument types - for arg in &func.inputs { - input_visitor.visit_ty(&arg.ty); - } - // extract lifetimes in output type - if let Return(ref ty) = func.output { - output_visitor.visit_ty(ty); - } - - let input_lts = lts_from_bounds(input_visitor.into_vec(), bounds_lts); - let output_lts = output_visitor.into_vec(); - - // check for lifetimes from higher scopes - for lt in input_lts.iter().chain(output_lts.iter()) { - if !allowed_lts.contains(lt) { - return false; - } - } - - // no input lifetimes? easy case! - if input_lts.is_empty() { - false - } else if output_lts.is_empty() { - // no output lifetimes, check distinctness of input lifetimes - - // only unnamed and static, ok - if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) { - return false; - } - // we have no output reference, so we only need all distinct lifetimes - input_lts.len() == unique_lifetimes(&input_lts) - } else { - // we have output references, so we need one input reference, - // and all output lifetimes must be the same - if unique_lifetimes(&output_lts) > 1 { - return false; - } - if input_lts.len() == 1 { - match (&input_lts[0], &output_lts[0]) { - (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true, - (&RefLt::Named(_), &RefLt::Unnamed) => true, - _ => false, // already elided, different named lifetimes - // or something static going on - } - } else { - false - } - } -} - -fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> { - let mut allowed_lts = HashSet::new(); - for lt in named_lts { - if lt.bounds.is_empty() { - allowed_lts.insert(RefLt::Named(lt.lifetime.name)); - } - } - allowed_lts.insert(RefLt::Unnamed); - allowed_lts.insert(RefLt::Static); - allowed_lts -} - -fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> { - for lt in bounds_lts { - if lt.name.as_str() != "'static" { - vec.push(RefLt::Named(lt.name)); - } - } - - vec -} - -/// Number of unique lifetimes in the given vector. -fn unique_lifetimes(lts: &[RefLt]) -> usize { - lts.iter().collect::<HashSet<_>>().len() -} - -/// A visitor usable for `rustc_front::visit::walk_ty()`. -struct RefVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, - lts: Vec<RefLt>, -} - -impl<'v, 't> RefVisitor<'v, 't> { - fn new(cx: &'v LateContext<'v, 't>) -> RefVisitor<'v, 't> { - RefVisitor { - cx: cx, - lts: Vec::new(), - } - } - - fn record(&mut self, lifetime: &Option<Lifetime>) { - if let Some(ref lt) = *lifetime { - if lt.name.as_str() == "'static" { - self.lts.push(RefLt::Static); - } else { - self.lts.push(RefLt::Named(lt.name)); - } - } else { - self.lts.push(RefLt::Unnamed); - } - } - - fn into_vec(self) -> Vec<RefLt> { - 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 { - 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 type_scheme = self.cx.tcx.lookup_item_type(def_id); - for _ in type_scheme.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); - } - } - _ => (), - } - } - } - } - } -} - -impl<'v, 't> Visitor<'v> for RefVisitor<'v, 't> { - // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { - self.record(&Some(*lifetime)); - } - - fn visit_ty(&mut self, ty: &'v Ty) { - match ty.node { - TyRptr(None, _) => { - self.record(&None); - } - TyPath(_, ref path) => { - self.collect_anonymous_lifetimes(path, ty); - } - _ => (), - } - walk_ty(self, ty); - } -} - -/// 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 { - for predicate in &where_clause.predicates { - match *predicate { - WherePredicate::RegionPredicate(..) => return true, - WherePredicate::BoundPredicate(ref pred) => { - // a predicate like F: Trait or F: for<'a> Trait<'a> - let mut visitor = RefVisitor::new(cx); - // walk the type F, it may not contain LT refs - walk_ty(&mut visitor, &pred.bounded_ty); - if !visitor.lts.is_empty() { - return true; - } - // if the bounds define new lifetimes, they are fine to occur - let allowed_lts = allowed_lts_from(&pred.bound_lifetimes); - // now walk the bounds - for bound in pred.bounds.iter() { - walk_ty_param_bound(&mut visitor, bound); - } - // and check that all lifetimes are allowed - for lt in visitor.into_vec() { - if !allowed_lts.contains(<) { - 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<Name, Span>); - -impl<'v> Visitor<'v> for LifetimeChecker { - // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { - self.0.remove(&lifetime.name); - } - - fn visit_lifetime_def(&mut self, _: &'v 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 report_extra_lifetimes(cx: &LateContext, func: &FnDecl, generics: &Generics) { - let hs = generics.lifetimes - .iter() - .map(|lt| (lt.lifetime.name, lt.lifetime.span)) - .collect(); - let mut checker = LifetimeChecker(hs); - - walk_generics(&mut checker, generics); - walk_fn_decl(&mut checker, func); - - for &v in checker.0.values() { - span_lint(cx, UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); - } -} diff --git a/src/loops.rs b/src/loops.rs deleted file mode 100644 index 061b8efaa64..00000000000 --- a/src/loops.rs +++ /dev/null @@ -1,976 +0,0 @@ -use reexport::*; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::intravisit::{Visitor, walk_expr, walk_block, walk_decl}; -use rustc::hir::map::Node::NodeBlock; -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc::middle::region::CodeExtent; -use rustc::ty; -use rustc_const_eval::EvalHint::ExprTypeChecked; -use rustc_const_eval::eval_const_expr_partial; -use std::borrow::Cow; -use std::collections::HashMap; -use syntax::ast; - -use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, - span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, unsugar_range, - walk_ptrs_ty, recover_for_loop}; -use utils::paths; -use utils::UnsugaredRange; - -/// **What it does:** This lint checks for looping over the range of `0..len` of some collection just to get the values by index. -/// -/// **Why is this bad?** Just iterating the collection itself makes the intent more clear and is probably faster. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// for i in 0..vec.len() { -/// println!("{}", vec[i]); -/// } -/// ``` -declare_lint! { - pub NEEDLESS_RANGE_LOOP, - Warn, - "for-looping over a range of indices where an iterator over items would do" -} - -/// **What it does:** This lint checks for loops on `x.iter()` where `&x` will do, and suggest the latter. -/// -/// **Why is this bad?** Readability. -/// -/// **Known problems:** False negatives. We currently only warn on some known types. -/// -/// **Example:** `for x in y.iter() { .. }` (where y is a `Vec` or slice) -declare_lint! { - pub EXPLICIT_ITER_LOOP, - Warn, - "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" -} - -/// **What it does:** This lint checks for loops on `x.next()`. -/// -/// **Why is this bad?** `next()` returns either `Some(value)` if there was a value, or `None` otherwise. The insidious thing is that `Option<_>` implements `IntoIterator`, so that possibly one value will be iterated, leading to some hard to find bugs. No one will want to write such code [except to win an Underhanded Rust Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). -/// -/// **Known problems:** None -/// -/// **Example:** `for x in y.next() { .. }` -declare_lint! { - pub ITER_NEXT_LOOP, - Warn, - "for-looping over `_.next()` which is probably not intended" -} - -/// **What it does:** This lint checks for `for` loops over `Option` values. -/// -/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. -/// -/// **Known problems:** None -/// -/// **Example:** `for x in option { .. }`. This should be `if let Some(x) = option { .. }`. -declare_lint! { - pub FOR_LOOP_OVER_OPTION, - Warn, - "for-looping over an `Option`, which is more clearly expressed as an `if let`" -} - -/// **What it does:** This lint checks for `for` loops over `Result` values. -/// -/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. -/// -/// **Known problems:** None -/// -/// **Example:** `for x in result { .. }`. This should be `if let Ok(x) = result { .. }`. -declare_lint! { - pub FOR_LOOP_OVER_RESULT, - Warn, - "for-looping over a `Result`, which is more clearly expressed as an `if let`" -} - -/// **What it does:** This lint detects `loop + match` combinations that are easier written as a `while let` loop. -/// -/// **Why is this bad?** The `while let` loop is usually shorter and more readable -/// -/// **Known problems:** Sometimes the wrong binding is displayed (#383) -/// -/// **Example:** -/// -/// ``` -/// loop { -/// let x = match y { -/// Some(x) => x, -/// None => break, -/// } -/// // .. do something with x -/// } -/// // is easier written as -/// while let Some(x) = y { -/// // .. do something with x -/// } -/// ``` -declare_lint! { - pub WHILE_LET_LOOP, - Warn, - "`loop { if let { ... } else break }` can be written as a `while let` loop" -} - -/// **What it does:** This lint checks for using `collect()` on an iterator without using the result. -/// -/// **Why is this bad?** It is more idiomatic to use a `for` loop over the iterator instead. -/// -/// **Known problems:** None -/// -/// **Example:** `vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();` -declare_lint! { - pub UNUSED_COLLECT, - Warn, - "`collect()`ing an iterator without using the result; this is usually better \ - written as a for loop" -} - -/// **What it does:** This lint checks for loops over ranges `x..y` where both `x` and `y` are constant and `x` is greater or equal to `y`, unless the range is reversed or has a negative `.step_by(_)`. -/// -/// **Why is it bad?** Such loops will either be skipped or loop until wrap-around (in debug code, this may `panic!()`). Both options are probably not intended. -/// -/// **Known problems:** The lint cannot catch loops over dynamically defined ranges. Doing this would require simulating all possible inputs and code paths through the program, which would be complex and error-prone. -/// -/// **Examples**: `for x in 5..10-5 { .. }` (oops, stray `-`) -declare_lint! { - pub REVERSE_RANGE_LOOP, - Warn, - "Iterating over an empty range, such as `10..0` or `5..5`" -} - -/// **What it does:** This lint checks `for` loops over slices with an explicit counter and suggests the use of `.enumerate()`. -/// -/// **Why is it bad?** Not only is the version using `.enumerate()` more readable, the compiler is able to remove bounds checks which can lead to faster code in some instances. -/// -/// **Known problems:** None. -/// -/// **Example:** `for i in 0..v.len() { foo(v[i]); }` or `for i in 0..v.len() { bar(i, v[i]); }` -declare_lint! { - pub EXPLICIT_COUNTER_LOOP, - Warn, - "for-looping with an explicit counter when `_.enumerate()` would do" -} - -/// **What it does:** This lint checks for empty `loop` expressions. -/// -/// **Why is this bad?** Those busy loops burn CPU cycles without doing anything. Think of the environment and either block on something or at least make the thread sleep for some microseconds. -/// -/// **Known problems:** None -/// -/// **Example:** `loop {}` -declare_lint! { - pub EMPTY_LOOP, - Warn, - "empty `loop {}` detected" -} - -/// **What it does:** This lint checks for `while let` expressions on iterators. -/// -/// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys the intent better. -/// -/// **Known problems:** None -/// -/// **Example:** `while let Some(val) = iter() { .. }` -declare_lint! { - pub WHILE_LET_ON_ITERATOR, - Warn, - "using a while-let loop instead of a for loop on an iterator" -} - -/// **What it does:** This warns when you iterate on a map (`HashMap` or `BTreeMap`) and ignore -/// either the keys or values. -/// -/// **Why is this bad?** Readability. There are `keys` and `values` methods that can be used to -/// express that don't need the values or keys. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ```rust -/// for (k, _) in &map { .. } -/// ``` -/// could be replaced by -/// ```rust -/// for k in map.keys() { .. } -/// ``` -declare_lint! { - pub FOR_KV_MAP, - Warn, - "looping on a map using `iter` when `keys` or `values` would do" -} - -#[derive(Copy, Clone)] -pub struct LoopsPass; - -impl LintPass for LoopsPass { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, - EXPLICIT_ITER_LOOP, - ITER_NEXT_LOOP, - WHILE_LET_LOOP, - UNUSED_COLLECT, - REVERSE_RANGE_LOOP, - EXPLICIT_COUNTER_LOOP, - EMPTY_LOOP, - WHILE_LET_ON_ITERATOR, - FOR_KV_MAP) - } -} - -impl LateLintPass for LoopsPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let Some((pat, arg, body)) = recover_for_loop(expr) { - check_for_loop(cx, pat, arg, body, expr); - } - // check for `loop { if let {} else break }` that could be `while let` - // (also matches an explicit "match" instead of "if let") - // (even if the "match" or "if let" is used for declaration) - if let ExprLoop(ref block, _) = expr.node { - // also check for empty `loop {}` statements - if block.stmts.is_empty() && block.expr.is_none() { - span_lint(cx, - EMPTY_LOOP, - expr.span, - "empty `loop {}` detected. You may want to either use `panic!()` or add \ - `std::thread::sleep(..);` to the loop body."); - } - - // extract the expression from the first statement (if any) in a block - let inner_stmt_expr = extract_expr_from_first_stmt(block); - // or extract the first expression (if any) from the block - if let Some(inner) = inner_stmt_expr.or_else(|| extract_first_expr(block)) { - if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { - // ensure "if let" compatible match structure - match *source { - MatchSource::Normal | - MatchSource::IfLetDesugar { .. } => { - 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) { - return; - } - - // NOTE: we used to make build a body here instead of using - // ellipsis, this was removed because: - // 1) it was ugly with big bodies; - // 2) it was not indented properly; - // 3) it wasn’t very smart (see #675). - span_lint_and_then(cx, - WHILE_LET_LOOP, - 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); - }); - } - } - _ => (), - } - } - } - } - 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, Some(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_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_help_and_lint(cx, - WHILE_LET_ON_ITERATOR, - expr.span, - "this loop could be written as a `for` loop", - &format!("try\nfor {} in {} {{...}}", loop_var, iterator)); - } - } - } - } - } - - fn check_stmt(&mut self, cx: &LateContext, stmt: &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" && - match_trait_method(cx, expr, &paths::ITERATOR) { - span_lint(cx, - UNUSED_COLLECT, - expr.span, - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator"); - } - } - } - } -} - -fn check_for_loop(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &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); - check_for_loop_explicit_counter(cx, arg, body, expr); - check_for_loop_over_map_kv(cx, pat, arg, body, expr); -} - -/// 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) { - if let Some(UnsugaredRange { start: Some(ref start), ref end, .. }) = unsugar_range(arg) { - // the var must be a single name - if let PatKind::Ident(_, ref ident, _) = pat.node { - let mut visitor = VarVisitor { - cx: cx, - var: ident.node, - indexed: HashMap::new(), - nonindex: false, - }; - walk_expr(&mut visitor, body); - - // 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 */); - - // ensure that the indexed variable was declared before the loop, see #601 - if let Some(indexed_extent) = indexed_extent { - let pat_extent = cx.tcx.region_maps.var_scope(pat.id); - if cx.tcx.region_maps.is_subscope_of(indexed_extent, pat_extent) { - return; - } - } - - let starts_at_zero = is_integer_literal(start, 0); - - let skip: Cow<_> = if starts_at_zero { - "".into() - } else { - format!(".skip({})", snippet(cx, start.span, "..")).into() - }; - - let take: Cow<_> = if let Some(ref end) = *end { - if is_len_call(end, &indexed) { - "".into() - } else { - format!(".take({})", snippet(cx, end.span, "..")).into() - } - } else { - "".into() - }; - - if visitor.nonindex { - span_lint(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is used to index `{}`. Consider using `for ({}, \ - item) in {}.iter().enumerate(){}{}` or similar iterators", - ident.node, - indexed, - ident.node, - indexed, - take, - skip)); - } else { - let repl = if starts_at_zero && take.is_empty() { - format!("&{}", indexed) - } else { - format!("{}.iter(){}{}", indexed, take, skip) - }; - - span_lint(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is only used to index `{}`. \ - Consider using `for item in {}` or similar iterators", - ident.node, - indexed, - repl)); - } - } - } - } -} - -fn is_len_call(expr: &Expr, var: &Name) -> bool { - if_let_chain! {[ - 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, - path.segments.len() == 1, - &path.segments[0].name == var - ], { - return true; - }} - - false -} - -fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { - // if this for loop is iterating over a two-sided range... - if let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), limits }) = unsugar_range(arg) { - // ...and both sides are compile-time constant integers... - if let Ok(start_idx) = eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None) { - if let Ok(end_idx) = eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None) { - // ...and the start index is greater than the end index, - // this loop will never run. This is often confusing for developers - // who think that this will iterate from the larger value to the - // smaller value. - 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), - }; - - if sup { - let start_snippet = snippet(cx, start.span, "_"); - let end_snippet = snippet(cx, end.span, "_"); - - span_lint_and_then(cx, - REVERSE_RANGE_LOOP, - expr.span, - "this range is empty so this for loop will never run", - |db| { - db.span_suggestion(expr.span, - "consider using the following if \ - you are attempting to iterate \ - over this range in reverse", - format!("({}..{}).rev()` ", end_snippet, start_snippet)); - }); - } else if eq && limits != ast::RangeLimits::Closed { - // if they are equal, it's also problematic - this loop - // will never run. - span_lint(cx, - REVERSE_RANGE_LOOP, - expr.span, - "this range is empty so this for loop will never run"); - } - } - } - } -} - -fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { - let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprMethodCall(ref method, _, ref args) = arg.node { - // just the receiver, no arguments - if args.len() == 1 { - let method_name = method.node; - // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - if method_name.as_str() == "iter" || method_name.as_str() == "iter_mut" { - if is_ref_iterable_type(cx, &args[0]) { - let object = snippet(cx, args[0].span, "_"); - span_lint(cx, - EXPLICIT_ITER_LOOP, - expr.span, - &format!("it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`", - if method_name.as_str() == "iter_mut" { - "mut " - } else { - "" - }, - object, - object, - method_name)); - } - } else if method_name.as_str() == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { - span_lint(cx, - ITER_NEXT_LOOP, - expr.span, - "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ - probably not what you want"); - next_loop_linted = true; - } - } - } - if !next_loop_linted { - check_arg_type(cx, pat, arg); - } -} - -/// Check for `for` loops over `Option`s and `Results` -fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { - let ty = cx.tcx.expr_ty(arg); - if match_type(cx, ty, &paths::OPTION) { - span_help_and_lint(cx, - FOR_LOOP_OVER_OPTION, - arg.span, - &format!("for loop over `{0}`, which is an `Option`. This is more readably written as an \ - `if let` statement.", - snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", - snippet(cx, pat.span, "_"), - snippet(cx, arg.span, "_"))); - } else if match_type(cx, ty, &paths::RESULT) { - span_help_and_lint(cx, - FOR_LOOP_OVER_RESULT, - arg.span, - &format!("for loop over `{0}`, which is a `Result`. This is more readably written as an \ - `if let` statement.", - snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", - snippet(cx, pat.span, "_"), - snippet(cx, arg.span, "_"))); - } -} - -fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { - // Look for variables that are incremented once per loop iteration. - let mut visitor = IncrementVisitor { - cx: cx, - states: HashMap::new(), - depth: 0, - done: false, - }; - walk_expr(&mut visitor, body); - - // For each candidate, check the parent block to see if - // it's initialized to zero at the start of the loop. - let map = &cx.tcx.map; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id)); - if let Some(parent_id) = parent_scope { - if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { - let mut visitor2 = InitializeVisitor { - cx: cx, - end_expr: expr, - var_id: *id, - state: VarState::IncrOnce, - name: None, - depth: 0, - past_loop: false, - }; - walk_block(&mut visitor2, block); - - if visitor2.state == VarState::Warn { - if let Some(name) = visitor2.name { - span_lint(cx, - EXPLICIT_COUNTER_LOOP, - expr.span, - &format!("the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ - item) in {1}.enumerate()` or similar iterators", - name, - snippet(cx, arg.span, "_"))); - } - } - } - } - } -} - -/// Check for the `FOR_KV_MAP` lint. -fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { - if let PatKind::Tup(ref pat) = pat.node { - if pat.len() == 2 { - let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { - (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), - (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), - _ => return, - }; - - let arg_span = match arg.node { - ExprAddrOf(MutImmutable, ref expr) => expr.span, - ExprAddrOf(MutMutable, _) => return, // for _ in &mut _, there is no {values,keys}_mut method - _ => arg.span, - }; - - let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); - if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) { - span_lint_and_then(cx, - FOR_KV_MAP, - expr.span, - &format!("you seem to want to iterate on a map's {}", kind), - |db| { - db.span_suggestion(expr.span, - "use the corresponding method", - format!("for {} in {}.{}() {{...}}", - snippet(cx, *pat_span, ".."), - snippet(cx, arg_span, ".."), - kind)); - }); - } - } - } - -} - -/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. -fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { - match *pat { - PatKind::Wild => true, - PatKind::Ident(_, ident, None) if ident.node.as_str().starts_with('_') => { - let mut visitor = UsedVisitor { - var: ident.node, - used: false, - }; - walk_expr(&mut visitor, body); - !visitor.used - } - _ => false, - } -} - -struct UsedVisitor { - var: ast::Name, // var to look for - used: bool, // has the var been used otherwise? -} - -impl<'a> Visitor<'a> for UsedVisitor { - fn visit_expr(&mut self, expr: &Expr) { - if let ExprPath(None, ref path) = expr.node { - if path.segments.len() == 1 && path.segments[0].name == self.var { - self.used = true; - return; - } - } - - walk_expr(self, expr); - } -} - -struct VarVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference - var: Name, // var name to look for as index - indexed: HashMap<Name, Option<CodeExtent>>, // indexed variables, the extent is None for global - nonindex: bool, // has the var been used otherwise? -} - -impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { - if let ExprPath(None, ref path) = expr.node { - if path.segments.len() == 1 && path.segments[0].name == 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 { - Def::Local(..) | Def::Upvar(..) => { - let extent = self.cx.tcx.region_maps.var_scope(def.base_def.var_id()); - self.indexed.insert(seqvar.segments[0].name, Some(extent)); - return; // no need to walk further - } - Def::Static(..) | Def::Const(..) => { - self.indexed.insert(seqvar.segments[0].name, None); - return; // no need to walk further - } - _ => (), - } - } - } - } - // we are not indexing anything, record that - self.nonindex = true; - return; - } - } - walk_expr(self, expr); - } -} - -fn is_iterator_used_after_while_let(cx: &LateContext, iter_expr: &Expr) -> bool { - let def_id = match var_def_id(cx, iter_expr) { - Some(id) => id, - None => return false, - }; - let mut visitor = VarUsedAfterLoopVisitor { - cx: cx, - def_id: def_id, - iter_expr_id: iter_expr.id, - past_while_let: false, - var_used_after_while_let: false, - }; - if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { - walk_block(&mut visitor, enclosing_block); - } - visitor.var_used_after_while_let -} - -struct VarUsedAfterLoopVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, - 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) { - if self.past_while_let { - if Some(self.def_id) == var_def_id(self.cx, expr) { - self.var_used_after_while_let = true; - } - } else if self.iter_expr_id == expr.id { - self.past_while_let = true; - } - walk_expr(self, expr); - } -} - - -/// Return true if the type of expr is one that provides `IntoIterator` impls -/// for `&T` and `&mut T`, such as `Vec`. -#[cfg_attr(rustfmt, rustfmt_skip)] -fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { - // no walk_ptrs_ty: calling iter() on a reference can make sense because it - // will allow further borrows afterwards - let ty = cx.tcx.expr_ty(e); - is_iterable_array(ty) || - match_type(cx, ty, &paths::VEC) || - match_type(cx, ty, &paths::LINKED_LIST) || - match_type(cx, ty, &paths::HASHMAP) || - match_type(cx, ty, &paths::HASHSET) || - match_type(cx, ty, &paths::VEC_DEQUE) || - match_type(cx, ty, &paths::BINARY_HEAP) || - match_type(cx, ty, &paths::BTREEMAP) || - match_type(cx, ty, &paths::BTREESET) -} - -fn is_iterable_array(ty: ty::Ty) -> bool { - // IntoIterator is currently only implemented for array sizes <= 32 in rustc - match ty.sty { - ty::TyArray(_, 0...32) => true, - _ => false, - } -} - -/// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. -fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { - if block.stmts.is_empty() { - return None; - } - if let StmtDecl(ref decl, _) = block.stmts[0].node { - if let DeclLocal(ref local) = decl.node { - if let Some(ref expr) = local.init { - Some(expr) - } else { - None - } - } else { - None - } - } else { - None - } -} - -/// If a block begins with an expression (with or without semicolon), return it. -fn extract_first_expr(block: &Block) -> Option<&Expr> { - match block.expr { - Some(ref expr) => Some(expr), - None if !block.stmts.is_empty() => { - match block.stmts[0].node { - StmtExpr(ref expr, _) | - StmtSemi(ref expr, _) => Some(expr), - _ => None, - } - } - _ => None, - } -} - -/// Return true if expr contains a single break expr (maybe within a block). -fn is_break_expr(expr: &Expr) -> bool { - match expr.node { - ExprBreak(None) => true, - // there won't be a `let <pat> = break` and so we can safely ignore the StmtDecl case - ExprBlock(ref b) => { - match extract_first_expr(b) { - Some(ref subexpr) => is_break_expr(subexpr), - None => false, - } - } - _ => false, - } -} - -// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be -// incremented exactly once in the loop body, and initialized to zero -// at the start of the loop. -#[derive(PartialEq)] -enum VarState { - Initial, // Not examined yet - IncrOnce, // Incremented exactly once, may be a loop counter - Declared, // Declared but not (yet) initialized to zero - Warn, - DontWarn, -} - -/// Scan a for loop for variables that are incremented exactly once. -struct IncrementVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, // context reference - states: HashMap<NodeId, VarState>, // incremented variables - depth: u32, // depth of conditional expressions - done: bool, -} - -impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> { - fn visit_expr(&mut self, expr: &'v Expr) { - if self.done { - return; - } - - // If node is a variable - if let Some(def_id) = var_def_id(self.cx, expr) { - if let Some(parent) = get_parent_expr(self.cx, expr) { - let state = self.states.entry(def_id).or_insert(VarState::Initial); - - match parent.node { - ExprAssignOp(op, ref lhs, ref rhs) => { - if lhs.id == expr.id { - if op.node == BiAdd && is_integer_literal(rhs, 1) { - *state = match *state { - VarState::Initial if self.depth == 0 => VarState::IncrOnce, - _ => VarState::DontWarn, - }; - } else { - // Assigned some other value - *state = VarState::DontWarn; - } - } - } - ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, - ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, - _ => (), - } - } - } else if is_loop(expr) { - self.states.clear(); - self.done = true; - return; - } else if is_conditional(expr) { - self.depth += 1; - walk_expr(self, expr); - self.depth -= 1; - return; - } - walk_expr(self, expr); - } -} - -/// 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. - var_id: NodeId, - state: VarState, - name: Option<Name>, - depth: u32, // depth of conditional expressions - past_loop: bool, -} - -impl<'v, 't> Visitor<'v> for InitializeVisitor<'v, 't> { - fn visit_decl(&mut self, decl: &'v Decl) { - // Look for declarations of the variable - if let DeclLocal(ref local) = decl.node { - if local.pat.id == self.var_id { - if let PatKind::Ident(_, ref ident, _) = local.pat.node { - self.name = Some(ident.node); - - self.state = if let Some(ref init) = local.init { - if is_integer_literal(init, 0) { - VarState::Warn - } else { - VarState::Declared - } - } else { - VarState::Declared - } - } - } - } - walk_decl(self, decl); - } - - fn visit_expr(&mut self, expr: &'v Expr) { - if self.state == VarState::DontWarn { - return; - } - if expr == self.end_expr { - self.past_loop = true; - return; - } - // No need to visit expressions before the variable is - // declared - if self.state == VarState::IncrOnce { - return; - } - - // If node is the desired variable, see how it's used - if var_def_id(self.cx, expr) == Some(self.var_id) { - if let Some(parent) = get_parent_expr(self.cx, expr) { - 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, - _ => (), - } - } - - if self.past_loop { - self.state = VarState::DontWarn; - return; - } - } else if !self.past_loop && is_loop(expr) { - self.state = VarState::DontWarn; - return; - } else if is_conditional(expr) { - self.depth += 1; - walk_expr(self, expr); - self.depth -= 1; - return; - } - walk_expr(self, expr); - } -} - -fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { - if let Some(path_res) = cx.tcx.def_map.borrow().get(&expr.id) { - if let Def::Local(_, node_id) = path_res.base_def { - return Some(node_id); - } - } - None -} - -fn is_loop(expr: &Expr) -> bool { - match expr.node { - ExprLoop(..) | ExprWhile(..) => true, - _ => false, - } -} - -fn is_conditional(expr: &Expr) -> bool { - match expr.node { - ExprIf(..) | ExprMatch(..) => true, - _ => false, - } -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000000..970222e1076 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,167 @@ +// error-pattern:yummy +#![feature(box_syntax)] +#![feature(rustc_private)] + +extern crate rustc_driver; +extern crate getopts; +extern crate rustc; +extern crate syntax; +extern crate rustc_plugin; +extern crate clippy_lints; + +use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; +use rustc::session::{config, Session}; +use rustc::session::config::{Input, ErrorOutputType}; +use syntax::diagnostics; +use std::path::PathBuf; +use std::process::Command; + +struct ClippyCompilerCalls(RustcDefaultCalls); + +impl std::default::Default for ClippyCompilerCalls { + fn default() -> Self { + Self::new() + } +} + +impl ClippyCompilerCalls { + fn new() -> Self { + ClippyCompilerCalls(RustcDefaultCalls) + } +} + +impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { + fn early_callback(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + descriptions: &diagnostics::registry::Registry, + output: ErrorOutputType) + -> Compilation { + self.0.early_callback(matches, sopts, descriptions, output) + } + fn no_input(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, + descriptions: &diagnostics::registry::Registry) + -> Option<(Input, Option<PathBuf>)> { + self.0.no_input(matches, sopts, odir, ofile, descriptions) + } + fn late_callback(&mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>) + -> Compilation { + self.0.late_callback(matches, sess, input, odir, ofile) + } + fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { + let mut control = self.0.build_controller(sess, matches); + + 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")); + registry.args_hidden = Some(Vec::new()); + clippy_lints::register_plugins(&mut registry); + + let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.mir_passes.borrow_mut().extend(mir_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + } + old(state); + }); + + control + } +} + +use std::path::Path; + +pub fn main() { + use std::env; + + if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + panic!("yummy"); + } + + let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); + + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = match (home, toolchain) { + (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), + _ => option_env!("SYSROOT").map(|s| s.to_owned()) + .or(Command::new("rustc").arg("--print") + .arg("sysroot") + .output().ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + ) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"), + }; + + if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); + let path = std::env::current_exe().expect("current executable path invalid"); + 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?"); + + if let Some(code) = exit_status.code() { + std::process::exit(code); + } + } else { + let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + env::args().collect() + } else { + env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() + }; + let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); + + if let Err(err_count) = result { + if err_count > 0 { + std::process::exit(1); + } + } + } +} + +fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String> + where P: AsRef<Path>, I: Iterator<Item=String> { + + let mut args = vec!["rustc".to_owned()]; + + let mut found_dashes = false; + for arg in old_args { + found_dashes |= arg == "--"; + args.push(arg); + } + if !found_dashes { + args.push("--".to_owned()); + } + args.push("-L".to_owned()); + args.push(dep_path.as_ref().to_string_lossy().into_owned()); + args.push(String::from("--sysroot")); + args.push(sysroot); + args.push("-Zno-trans".to_owned()); + args +} diff --git a/src/map_clone.rs b/src/map_clone.rs deleted file mode 100644 index 4ad232759cf..00000000000 --- a/src/map_clone.rs +++ /dev/null @@ -1,128 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use syntax::ast; -use utils::{is_adjusted, match_path, match_trait_method, match_type, paths, snippet, - span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; - -/// **What it does:** This lint checks for mapping clone() over an iterator. -/// -/// **Why is this bad?** It makes the code less readable. -/// -/// **Known problems:** None -/// -/// **Example:** `x.map(|e| e.clone());` -declare_lint! { - pub MAP_CLONE, Warn, - "using `.map(|x| x.clone())` to clone an iterator or option's contents (recommends \ - `.cloned()` instead)" -} - -#[derive(Copy, Clone)] -pub struct MapClonePass; - -impl LateLintPass for MapClonePass { - fn check_expr(&mut self, cx: &LateContext, expr: &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 blk, _) => { - if_let_chain! { - [ - // just one expression in the closure - blk.stmts.is_empty(), - let Some(ref closure_expr) = blk.expr, - // nothing special in the argument, besides reference bindings - // (e.g. .map(|&x| x) ) - let Some(arg_ident) = get_arg_name(&*decl.inputs[0].pat), - // the method is being called on a known type (option or iterator) - let Some(type_name) = get_type_name(cx, expr, &args[0]) - ], { - // look for derefs, for .map(|x| *x) - if only_derefs(cx, &*closure_expr, arg_ident) && - // .cloned() only removes one level of indirection, don't lint on more - walk_ptrs_ty_depth(cx.tcx.pat_ty(&*decl.inputs[0].pat)).1 == 1 - { - span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( - "you seem to be using .map() to clone the contents of an {}, consider \ - using `.cloned()`", type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); - } - // explicit clone() calls ( .map(|x| x.clone()) ) - else if let ExprMethodCall(clone_call, _, ref clone_args) = closure_expr.node { - if clone_call.node.as_str() == "clone" && - clone_args.len() == 1 && - match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) && - expr_eq_name(&clone_args[0], arg_ident) - { - span_help_and_lint(cx, MAP_CLONE, expr.span, &format!( - "you seem to be using .map() to clone the contents of an {}, consider \ - using `.cloned()`", type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); - } - } - } - } - } - 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, - MAP_CLONE, - expr.span, - &format!("you seem to be using .map() to clone the contents of an \ - {}, consider using `.cloned()`", - type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); - } - } - _ => (), - } - } - } - } -} - -fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { - match expr.node { - ExprPath(None, ref path) => { - let arg_segment = [PathSegment { - name: id, - parameters: PathParameters::none(), - }]; - !path.global && path.segments[..] == arg_segment - } - _ => false, - } -} - -fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { - if match_trait_method(cx, expr, &paths::ITERATOR) { - Some("iterator") - } else if match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(arg)), &paths::OPTION) { - Some("Option") - } else { - None - } -} - -fn get_arg_name(pat: &Pat) -> Option<ast::Name> { - match pat.node { - PatKind::Ident(_, name, None) => Some(name.node), - PatKind::Ref(ref subpat, _) => get_arg_name(subpat), - _ => None, - } -} - -fn only_derefs(cx: &LateContext, expr: &Expr, id: ast::Name) -> bool { - match expr.node { - ExprUnary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id), - _ => expr_eq_name(expr, id), - } -} - -impl LintPass for MapClonePass { - fn get_lints(&self) -> LintArray { - lint_array!(MAP_CLONE) - } -} diff --git a/src/matches.rs b/src/matches.rs deleted file mode 100644 index db4ccf2dcdb..00000000000 --- a/src/matches.rs +++ /dev/null @@ -1,483 +0,0 @@ -use rustc::hir::*; -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc::ty; -use rustc_const_eval::EvalHint::ExprTypeChecked; -use rustc_const_eval::eval_const_expr_partial; -use rustc_const_math::ConstInt; -use std::cmp::Ordering; -use syntax::ast::LitKind; -use syntax::codemap::Span; -use utils::paths; -use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block}; - -/// **What it does:** This lint checks for matches with a single arm where an `if let` will usually suffice. -/// -/// **Why is this bad?** Just readability – `if let` nests less than a `match`. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// match x { -/// Some(ref foo) -> bar(foo), -/// _ => () -/// } -/// ``` -declare_lint! { - pub SINGLE_MATCH, Warn, - "a match statement with a single nontrivial arm (i.e, where the other arm \ - is `_ => {}`) is used; recommends `if let` instead" -} - -/// **What it does:** This lint checks for matches with a two arms where an `if let` will usually suffice. -/// -/// **Why is this bad?** Just readability – `if let` nests less than a `match`. -/// -/// **Known problems:** Personal style preferences may differ -/// -/// **Example:** -/// ``` -/// match x { -/// Some(ref foo) -> bar(foo), -/// _ => bar(other_ref), -/// } -/// ``` -declare_lint! { - pub SINGLE_MATCH_ELSE, Allow, - "a match statement with a two arms where the second arm's pattern is a wildcard; \ - recommends `if let` instead" -} - -/// **What it does:** This lint checks for matches where all arms match a reference, suggesting to remove the reference and deref the matched expression instead. It also checks for `if let &foo = bar` blocks. -/// -/// **Why is this bad?** It just makes the code less readable. That reference destructuring adds nothing to the code. -/// -/// **Known problems:** None -/// -/// **Example:** -/// -/// ``` -/// match x { -/// &A(ref y) => foo(y), -/// &B => bar(), -/// _ => frob(&x), -/// } -/// ``` -declare_lint! { - pub MATCH_REF_PATS, Warn, - "a match or `if let` has all arms prefixed with `&`; the match expression can be \ - dereferenced instead" -} - -/// **What it does:** This lint checks for matches where match expression is a `bool`. It suggests to replace the expression with an `if...else` block. -/// -/// **Why is this bad?** It makes the code less readable. -/// -/// **Known problems:** None -/// -/// **Example:** -/// -/// ``` -/// let condition: bool = true; -/// match condition { -/// true => foo(), -/// false => bar(), -/// } -/// ``` -declare_lint! { - pub MATCH_BOOL, Warn, - "a match on boolean expression; recommends `if..else` block instead" -} - -/// **What it does:** This lint checks for overlapping match arms. -/// -/// **Why is this bad?** It is likely to be an error and if not, makes the code less obvious. -/// -/// **Known problems:** None -/// -/// **Example:** -/// -/// ``` -/// let x = 5; -/// match x { -/// 1 ... 10 => println!("1 ... 10"), -/// 5 ... 15 => println!("5 ... 15"), -/// _ => (), -/// } -/// ``` -declare_lint! { - pub MATCH_OVERLAPPING_ARM, Warn, "a match has overlapping arms" -} - -#[allow(missing_copy_implementations)] -pub struct MatchPass; - -impl LintPass for MatchPass { - fn get_lints(&self) -> LintArray { - lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE) - } -} - -impl LateLintPass for MatchPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_external_macro(cx, expr.span) { - return; - } - if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node { - check_single_match(cx, ex, arms, expr); - check_match_bool(cx, ex, arms, expr); - check_overlapping_arms(cx, ex, arms); - } - if let ExprMatch(ref ex, ref arms, source) = expr.node { - check_match_ref_pats(cx, ex, arms, source, expr); - } - } -} - -#[cfg_attr(rustfmt, rustfmt_skip)] -fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { - if arms.len() == 2 && - arms[0].pats.len() == 1 && arms[0].guard.is_none() && - arms[1].pats.len() == 1 && arms[1].guard.is_none() { - let els = if is_unit_expr(&arms[1].body) { - None - } else if let ExprBlock(_) = arms[1].body.node { - // matches with blocks that contain statements are prettier as `if let + else` - Some(&*arms[1].body) - } else { - // allow match arms with just expressions - return; - }; - let ty = cx.tcx.expr_ty(ex); - if ty.sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow { - check_single_match_single_pattern(cx, ex, arms, expr, els); - check_single_match_opt_like(cx, ex, arms, expr, ty, els); - } - } -} - -fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { - if arms[1].pats[0].node == PatKind::Wild { - let lint = if els.is_some() { - SINGLE_MATCH_ELSE - } else { - SINGLE_MATCH - }; - let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); - span_lint_and_then(cx, - lint, - expr.span, - "you seem to be trying to use match for destructuring a single pattern. \ - Consider using `if let`", - |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); - } -} - -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"), - (&paths::COW, "Cow::Owned"), - (&paths::COW, "Owned"), - (&paths::OPTION, "None"), - (&paths::RESULT, "Err"), - (&paths::RESULT, "Ok")]; - - let path = match arms[1].pats[0].node { - PatKind::TupleStruct(ref path, Some(ref inner)) => { - // contains any non wildcard patterns? e.g. Err(err) - if inner.iter().any(|pat| pat.node != PatKind::Wild) { - return; - } - path.to_string() - } - PatKind::TupleStruct(ref path, None) => path.to_string(), - PatKind::Ident(BindByValue(MutImmutable), ident, None) => ident.node.to_string(), - _ => return, - }; - - for &(ty_path, pat_path) in candidates { - if &path == pat_path && match_type(cx, ty, ty_path) { - let lint = if els.is_some() { - SINGLE_MATCH_ELSE - } else { - SINGLE_MATCH - }; - let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); - span_lint_and_then(cx, - lint, - expr.span, - "you seem to be trying to use match for destructuring a single pattern. Consider \ - using `if let`", - |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); - } - } -} - -fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { - // type of expression == bool - if cx.tcx.expr_ty(ex).sty == ty::TyBool { - let sugg = if arms.len() == 2 && arms[0].pats.len() == 1 { - // no guards - let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pats[0].node { - if let ExprLit(ref lit) = arm_bool.node { - match lit.node { - LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), - LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), - _ => None, - } - } else { - None - } - } else { - None - }; - - if let Some((ref true_expr, ref false_expr)) = exprs { - match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => { - Some(format!("if {} {} else {}", - 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) => { - Some(format!("try\nif !{} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, false_expr, None, ".."))) - } - (true, true) => None, - } - } else { - None - } - } else { - None - }; - - span_lint_and_then(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression. Consider using an if..else block:", - move |db| { - if let Some(sugg) = sugg { - db.span_suggestion(expr.span, "try this", sugg); - } - }); - } -} - -fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { - if arms.len() >= 2 && cx.tcx.expr_ty(ex).is_integral() { - let ranges = all_ranges(cx, arms); - let type_ranges = type_ranges(&ranges); - if !type_ranges.is_empty() { - if let Some((start, end)) = overlapping(&type_ranges) { - span_note_and_lint(cx, - MATCH_OVERLAPPING_ARM, - start.span, - "some ranges overlap", - end.span, - "overlaps with this"); - } - } - } -} - -fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) { - if has_only_ref_pats(arms) { - if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { - let template = match_template(cx, expr.span, source, "", inner); - span_lint_and_then(cx, - MATCH_REF_PATS, - expr.span, - "you don't need to add `&` to both the expression and the patterns", - |db| { - db.span_suggestion(expr.span, "try", template); - }); - } else { - let template = match_template(cx, expr.span, source, "*", ex); - span_lint_and_then(cx, - MATCH_REF_PATS, - expr.span, - "you don't need to add `&` to all patterns", - |db| { - db.span_suggestion(expr.span, - "instead of prefixing all patterns with `&`, you can \ - dereference the expression", - template); - }); - } - } -} - -/// Get all arms that are unbounded `PatRange`s. -fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> { - arms.iter() - .filter_map(|arm| { - if let Arm { ref pats, guard: None, .. } = *arm { - Some(pats.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) - ], { - return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); - }} - - 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 - })) - } else { - None - } - }) - .flat_map(IntoIterator::into_iter) - .collect() -} - -#[derive(Debug, Eq, PartialEq)] -pub struct SpannedRange<T> { - pub span: Span, - pub node: (T, T), -} - -type TypedRanges = Vec<SpannedRange<ConstInt>>; - -/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than -/// `Uint` and `Int` probably don't make sense. -fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> 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() -} - -fn is_unit_expr(expr: &Expr) -> bool { - match expr.node { - ExprTup(ref v) if v.is_empty() => true, - ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true, - _ => false, - } -} - -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::<Option<Vec<bool>>>(); - // look for Some(v) where there's at least one true element - mapped.map_or(false, |v| v.iter().any(|el| *el)) -} - -fn match_template(cx: &LateContext, span: Span, source: MatchSource, op: &str, expr: &Expr) -> String { - let expr_snippet = snippet(cx, expr.span, ".."); - match source { - MatchSource::Normal => format!("match {}{} {{ .. }}", op, expr_snippet), - MatchSource::IfLetDesugar { .. } => format!("if let .. = {}{} {{ .. }}", op, expr_snippet), - MatchSource::WhileLetDesugar => format!("while let .. = {}{} {{ .. }}", op, expr_snippet), - MatchSource::ForLoopDesugar => span_bug!(span, "for loop desugared to match with &-patterns!"), - MatchSource::TryDesugar => span_bug!(span, "`?` operator desugared to match with &-patterns!"), - } -} - -pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> - where T: Copy + Ord -{ - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - enum Kind<'a, T: 'a> { - Start(T, &'a SpannedRange<T>), - End(T, &'a SpannedRange<T>), - } - - impl<'a, T: Copy> Kind<'a, T> { - fn range(&self) -> &'a SpannedRange<T> { - match *self { - Kind::Start(_, r) | - Kind::End(_, r) => r, - } - } - - fn value(self) -> T { - match self { - Kind::Start(t, _) | - Kind::End(t, _) => t, - } - } - } - - impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.cmp(other)) - } - } - - impl<'a, T: Copy + Ord> Ord for Kind<'a, T> { - fn cmp(&self, other: &Self) -> Ordering { - self.value().cmp(&other.value()) - } - } - - let mut values = Vec::with_capacity(2 * ranges.len()); - - for r in ranges { - values.push(Kind::Start(r.node.0, r)); - values.push(Kind::End(r.node.1, r)); - } - - values.sort(); - - for (a, b) in values.iter().zip(values.iter().skip(1)) { - match (a, b) { - (&Kind::Start(_, ra), &Kind::End(_, rb)) => { - if ra.node != rb.node { - return Some((ra, rb)); - } - } - (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), - _ => return Some((a.range(), b.range())), - } - } - - None -} diff --git a/src/mem_forget.rs b/src/mem_forget.rs deleted file mode 100644 index 1f627d614ff..00000000000 --- a/src/mem_forget.rs +++ /dev/null @@ -1,44 +0,0 @@ -use rustc::lint::*; -use rustc::hir::{Expr, ExprCall, ExprPath}; -use utils::{match_def_path, paths, span_lint}; - -/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`. -/// -/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks -/// -/// **Known problems:** None. -/// -/// **Example:** `mem::forget(Rc::new(55)))` -declare_lint! { - pub MEM_FORGET, - Allow, - "`mem::forget` usage on `Drop` types is likely to cause memory leaks" -} - -pub struct MemForget; - -impl LintPass for MemForget { - fn get_lints(&self) -> LintArray { - lint_array![MEM_FORGET] - } -} - -impl LateLintPass for MemForget { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprCall(ref path_expr, ref args) = e.node { - if let ExprPath(None, _) = path_expr.node { - let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - if match_def_path(cx, def_id, &paths::MEM_FORGET) { - let forgot_ty = cx.tcx.expr_ty(&args[0]); - - if match forgot_ty.ty_adt_def() { - Some(def) => def.has_dtor(), - _ => false - } { - span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); - } - } - } - } - } -} diff --git a/src/methods.rs b/src/methods.rs deleted file mode 100644 index f9f557e7a9a..00000000000 --- a/src/methods.rs +++ /dev/null @@ -1,1049 +0,0 @@ -use rustc::hir; -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc::middle::const_qualif::ConstQualif; -use rustc::ty::subst::{Subst, TypeSpace}; -use rustc::ty; -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 syntax::ptr::P; -use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method, - match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint, - span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; -use utils::MethodArgs; -use utils::paths; - -#[derive(Clone)] -pub struct MethodsPass; - -/// **What it does:** This lint checks for `.unwrap()` calls on `Option`s. -/// -/// **Why is this bad?** Usually it is better to handle the `None` case, or to at least call `.expect(_)` with a more helpful message. Still, for a lot of quick-and-dirty code, `unwrap` is a good choice, which is why this lint is `Allow` by default. -/// -/// **Known problems:** None -/// -/// **Example:** `x.unwrap()` -declare_lint! { - pub OPTION_UNWRAP_USED, Allow, - "using `Option.unwrap()`, which should at least get a better message using `expect()`" -} - -/// **What it does:** This lint checks for `.unwrap()` calls on `Result`s. -/// -/// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` values. Normally, you want to implement more sophisticated error handling, and propagate errors upwards with `try!`. -/// -/// Even if you want to panic on errors, not all `Error`s implement good messages on display. Therefore it may be beneficial to look at the places where they may get displayed. Activate this lint to do just that. -/// -/// **Known problems:** None -/// -/// **Example:** `x.unwrap()` -declare_lint! { - pub RESULT_UNWRAP_USED, Allow, - "using `Result.unwrap()`, which might be better handled" -} - -/// **What it does:** This lint checks for methods that should live in a trait implementation of a `std` trait (see [llogiq's blog post](http://llogiq.github.io/2015/07/30/traits.html) for further information) instead of an inherent implementation. -/// -/// **Why is this bad?** Implementing the traits improve ergonomics for users of the code, often with very little cost. Also people seeing a `mul(..)` method may expect `*` to work equally, so you should have good reason to disappoint them. -/// -/// **Known problems:** None -/// -/// **Example:** -/// ``` -/// struct X; -/// impl X { -/// fn add(&self, other: &X) -> X { .. } -/// } -/// ``` -declare_lint! { - pub SHOULD_IMPLEMENT_TRAIT, Warn, - "defining a method that should be implementing a std trait" -} - -/// **What it does:** This lint checks for methods with certain name prefixes and which doesn't match how self is taken. The actual rules are: -/// -/// |Prefix |`self` taken | -/// |-------|--------------------| -/// |`as_` |`&self` or &mut self| -/// |`from_`| none | -/// |`into_`|`self` | -/// |`is_` |`&self` or none | -/// |`to_` |`&self` | -/// -/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_..` function. -/// -/// **Known problems:** None -/// -/// **Example** -/// -/// ``` -/// impl X { -/// fn as_str(self) -> &str { .. } -/// } -/// ``` -declare_lint! { - pub WRONG_SELF_CONVENTION, Warn, - "defining a method named with an established prefix (like \"into_\") that takes \ - `self` with the wrong convention" -} - -/// **What it does:** This is the same as [`wrong_self_convention`](#wrong_self_convention), but for public items. -/// -/// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). -/// -/// **Known problems:** Actually *renaming* the function may break clients if the function is part of the public interface. In that case, be mindful of the stability guarantees you've given your users. -/// -/// **Example:** -/// ``` -/// impl X { -/// pub fn as_str(self) -> &str { .. } -/// } -/// ``` -declare_lint! { - pub WRONG_PUB_SELF_CONVENTION, Allow, - "defining a public method named with an established prefix (like \"into_\") that takes \ - `self` with the wrong convention" -} - -/// **What it does:** This lint checks for usage of `ok().expect(..)`. -/// -/// **Why is this bad?** Because you usually call `expect()` on the `Result` directly to get a good error message. -/// -/// **Known problems:** None. -/// -/// **Example:** `x.ok().expect("why did I do this again?")` -declare_lint! { - pub OK_EXPECT, Warn, - "using `ok().expect()`, which gives worse error messages than \ - calling `expect` directly on the Result" -} - -/// **What it does:** This lint checks for usage of `_.map(_).unwrap_or(_)`. -/// -/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or(_, _)`. -/// -/// **Known problems:** None. -/// -/// **Example:** `x.map(|a| a + 1).unwrap_or(0)` -declare_lint! { - pub OPTION_MAP_UNWRAP_OR, Warn, - "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ - `map_or(a, f)`" -} - -/// **What it does:** This lint `Warn`s on `_.map(_).unwrap_or_else(_)`. -/// -/// **Why is this bad?** Readability, this can be written more concisely as `_.map_or_else(_, _)`. -/// -/// **Known problems:** None. -/// -/// **Example:** `x.map(|a| a + 1).unwrap_or_else(some_function)` -declare_lint! { - pub OPTION_MAP_UNWRAP_OR_ELSE, Warn, - "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ - `map_or_else(g, f)`" -} - -/// **What it does:** This lint `Warn`s on `_.filter(_).next()`. -/// -/// **Why is this bad?** Readability, this can be written more concisely as `_.find(_)`. -/// -/// **Known problems:** None. -/// -/// **Example:** `iter.filter(|x| x == 0).next()` -declare_lint! { - pub FILTER_NEXT, Warn, - "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`" -} - -/// **What it does:** This lint `Warn`s on an iterator search (such as `find()`, `position()`, or -/// `rposition()`) followed by a call to `is_some()`. -/// -/// **Why is this bad?** Readability, this can be written more concisely as `_.any(_)`. -/// -/// **Known problems:** None. -/// -/// **Example:** `iter.find(|x| x == 0).is_some()` -declare_lint! { - pub SEARCH_IS_SOME, Warn, - "using an iterator search followed by `is_some()`, which is more succinctly \ - expressed as a call to `any()`" -} - -/// **What it does:** This lint `Warn`s on using `.chars().next()` on a `str` to check if it -/// starts with a given char. -/// -/// **Why is this bad?** Readability, this can be written more concisely as `_.starts_with(_)`. -/// -/// **Known problems:** None. -/// -/// **Example:** `name.chars().next() == Some('_')` -declare_lint! { - pub CHARS_NEXT_CMP, Warn, - "using `.chars().next()` to check if a string starts with a char" -} - -/// **What it does:** This lint checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, etc., and -/// suggests to use `or_else`, `unwrap_or_else`, etc., or `unwrap_or_default` instead. -/// -/// **Why is this bad?** The function will always be called and potentially allocate an object -/// in expressions such as: -/// ```rust -/// foo.unwrap_or(String::new()) -/// ``` -/// this can instead be written: -/// ```rust -/// foo.unwrap_or_else(String::new) -/// ``` -/// or -/// ```rust -/// foo.unwrap_or_default() -/// ``` -/// -/// **Known problems:** If the function as side-effects, not calling it will change the semantic of -/// the program, but you shouldn't rely on that anyway. -declare_lint! { - pub OR_FUN_CALL, Warn, - "using any `*or` method when the `*or_else` would do" -} - -/// **What it does:** This lint checks for usage of `.extend(s)` on a `Vec` to extend the vector by a slice. -/// -/// **Why is this bad?** Since Rust 1.6, the `extend_from_slice(_)` method is stable and at least for now faster. -/// -/// **Known problems:** None. -/// -/// **Example:** `my_vec.extend(&xs)` -declare_lint! { - pub EXTEND_FROM_SLICE, Warn, - "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice" -} - -/// **What it does:** This lint warns on using `.clone()` on a `Copy` type. -/// -/// **Why is this bad?** The only reason `Copy` types implement `Clone` is for generics, not for -/// using the `clone` method on a concrete type. -/// -/// **Known problems:** None. -/// -/// **Example:** `42u64.clone()` -declare_lint! { - pub CLONE_ON_COPY, Warn, "using `clone` on a `Copy` type" -} - -/// **What it does:** This lint warns on using `.clone()` on an `&&T` -/// -/// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of cloning the underlying -/// `T` -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust -/// fn main() { -/// let x = vec![1]; -/// let y = &&x; -/// let z = y.clone(); -/// println!("{:p} {:p}",*y, z); // prints out the same pointer -/// } -/// ``` -declare_lint! { - pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`" -} - -/// **What it does:** This lint warns about `new` not returning `Self`. -/// -/// **Why is this bad?** As a convention, `new` methods are used to make a new instance of a type. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust -/// impl Foo { -/// fn new(..) -> NotAFoo { -/// } -/// } -/// ``` -declare_lint! { - pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method" -} - -/// **What it does:** This lint checks for string methods that receive a single-character `str` as an argument, e.g. `_.split("x")`. -/// -/// **Why is this bad?** Performing these methods using a `char` is faster than using a `str`. -/// -/// **Known problems:** Does not catch multi-byte unicode characters. -/// -/// **Example:** `_.split("x")` could be `_.split('x')` -declare_lint! { - pub SINGLE_CHAR_PATTERN, - Warn, - "using a single-character str where a char could be used, e.g. \ - `_.split(\"x\")`" -} - -/// **What it does:** This lint checks for getting the inner pointer of a temporary `CString`. -/// -/// **Why is this bad?** The inner pointer of a `CString` is only valid as long as the `CString` is -/// alive. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// let c_str = CString::new("foo").unwrap().as_ptr(); -/// unsafe { -/// call_some_ffi_func(c_str); -/// } -/// ``` -/// Here `c_str` point to a freed address. The correct use would be: -/// ```rust,ignore -/// let c_str = CString::new("foo").unwrap(); -/// unsafe { -/// call_some_ffi_func(c_str.as_ptr()); -/// } -/// ``` -declare_lint! { - pub TEMPORARY_CSTRING_AS_PTR, - Warn, - "getting the inner pointer of a temporary `CString`" -} - -impl LintPass for MethodsPass { - fn get_lints(&self) -> LintArray { - lint_array!(EXTEND_FROM_SLICE, - OPTION_UNWRAP_USED, - RESULT_UNWRAP_USED, - SHOULD_IMPLEMENT_TRAIT, - WRONG_SELF_CONVENTION, - WRONG_PUB_SELF_CONVENTION, - OK_EXPECT, - OPTION_MAP_UNWRAP_OR, - OPTION_MAP_UNWRAP_OR_ELSE, - OR_FUN_CALL, - CHARS_NEXT_CMP, - CLONE_ON_COPY, - CLONE_DOUBLE_REF, - NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN, - SEARCH_IS_SOME, - TEMPORARY_CSTRING_AS_PTR) - } -} - -impl LateLintPass for MethodsPass { - fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - if in_macro(cx, expr.span) { - return; - } - - match expr.node { - hir::ExprMethodCall(name, _, ref args) => { - // Chain calls - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - lint_unwrap(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) { - lint_ok_expect(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) { - lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) { - lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) { - lint_filter_next(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) { - lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) { - lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) { - lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]); - } else if let Some(arglists) = method_chain_args(expr, &["extend"]) { - lint_extend(cx, expr, arglists[0]); - } else if let Some(arglists) = method_chain_args(expr, &["unwrap", "as_ptr"]) { - lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]); - } - - lint_or_fun_call(cx, expr, &name.node.as_str(), args); - - let self_ty = cx.tcx.expr_ty_adjusted(&args[0]); - if args.len() == 1 && name.node.as_str() == "clone" { - lint_clone_on_copy(cx, expr); - lint_clone_double_ref(cx, expr, &args[0], self_ty); - } - - match self_ty.sty { - ty::TyRef(_, ty) if ty.ty.sty == ty::TyStr => { - for &(method, pos) in &PATTERN_METHODS { - if name.node.as_str() == method && args.len() > pos { - 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_item(&mut self, cx: &LateContext, item: &hir::Item) { - if in_external_macro(cx, item.span) { - return; - } - - if let hir::ItemImpl(_, _, _, None, _, ref items) = item.node { - for implitem in items { - let name = implitem.name; - if_let_chain! {[ - let hir::ImplItemKind::Method(ref sig, _) = implitem.node, - let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), - ], { - // check missing trait implementations - for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS { - if name.as_str() == method_name && - sig.decl.inputs.len() == n_args && - out_type.matches(&sig.decl.output) && - self_kind.matches(&explicit_self, false) { - span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!( - "defining a method called `{}` on this type; consider implementing \ - the `{}` trait or choosing a less ambiguous name", name, trait_name)); - } - } - - // check conventions w.r.t. conversion method names and predicates - let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty; - let is_copy = is_copy(cx, ty, item); - for &(ref conv, self_kinds) in &CONVENTIONS { - if_let_chain! {[ - conv.check(&name.as_str()), - let Some(explicit_self) = sig.decl.inputs.get(0).and_then(hir::Arg::to_self), - !self_kinds.iter().any(|k| k.matches(&explicit_self, is_copy)), - ], { - let lint = if item.vis == hir::Visibility::Public { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; - span_lint(cx, - lint, - explicit_self.span, - &format!("methods called `{}` usually take {}; consider choosing a less \ - ambiguous name", - conv, - &self_kinds.iter() - .map(|k| k.description()) - .collect::<Vec<_>>() - .join(" or "))); - }} - } - - let ret_ty = return_ty(cx, implitem.id); - if &name.as_str() == &"new" && - !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) { - span_lint(cx, - NEW_RET_NO_SELF, - explicit_self.span, - "methods called `new` usually return `Self`"); - } - } - }} - } - } -} - -/// Checks for the `OR_FUN_CALL` lint. -fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[P<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 { - 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 ["default", "new"].contains(&path) { - let arg_ty = cx.tcx.expr_ty(arg); - let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { - default_trait_id - } else { - return false; - }; - - if implements_trait(cx, arg_ty, default_trait_id, Vec::new()) { - span_lint(cx, - OR_FUN_CALL, - span, - &format!("use of `{}` followed by a call to `{}`", name, path)) - .span_suggestion(span, - "try this", - format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); - return true; - } - } - } - } - - false - } - - /// 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) { - // 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) { - if !qualif.contains(ConstQualif::NOT_CONST) { - return; - } - } - // (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 self_ty = cx.tcx.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)) { - (fn_has_arguments, poss, suffix) - } else { - return; - }; - - if !poss.contains(&name) { - return; - } - - let sugg: Cow<_> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(), - (false, true) => snippet(cx, fun.span, ".."), - }; - - span_lint(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name)) - .span_suggestion(span, - "try this", - format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); - } - - if args.len() == 2 { - if let hir::ExprCall(ref fun, ref or_args) = args[1].node { - let or_has_args = !or_args.is_empty(); - if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - check_general_case(cx, name, fun, &args[0], &args[1], or_has_args, expr.span); - } - } - } -} - -/// Checks for the `CLONE_ON_COPY` lint. -fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr) { - let ty = cx.tcx.expr_ty(expr); - let parent = cx.tcx.map.get_parent(expr.id); - let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, parent); - - if !ty.moves_by_default(cx.tcx.global_tcx(), ¶meter_environment, expr.span) { - span_lint(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type"); - } -} - -/// Checks for the `CLONE_DOUBLE_REF` lint. -fn lint_clone_double_ref(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, ty: ty::Ty) { - if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { - if let ty::TyRef(..) = inner.sty { - let mut db = span_lint(cx, - CLONE_DOUBLE_REF, - expr.span, - "using `clone` on a double-reference; \ - this will copy the reference instead of cloning \ - the inner type"); - if let Some(snip) = snippet_opt(cx, arg.span) { - db.span_suggestion(expr.span, "try dereferencing it", format!("(*{}).clone()", snip)); - } - } - } -} - -fn lint_extend(cx: &LateContext, expr: &hir::Expr, args: &MethodArgs) { - let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0])); - if !match_type(cx, obj_ty, &paths::VEC) { - return; - } - let arg_ty = cx.tcx.expr_ty(&args[1]); - if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { - span_lint(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice") - .span_suggestion(expr.span, - "try this", - format!("{}.extend_from_slice({}{})", - snippet(cx, args[0].span, "_"), - r, - snippet(cx, span, "_"))); - } -} - -fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) { - 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), - ], { - span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, - "you are getting the inner pointer of a temporary `CString`", - |db| { - db.note("that pointer will be invalid outside this expression"); - db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime"); - }); - }} -} - -fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: &ty::Ty) -> Option<(Span, &'static str)> { - fn may_slice(cx: &LateContext, ty: &ty::Ty) -> bool { - match ty.sty { - ty::TySlice(_) => true, - ty::TyStruct(..) => match_type(cx, ty, &paths::VEC), - ty::TyArray(_, size) => size < 32, - ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => may_slice(cx, inner), - _ => false, - } - } - if let hir::ExprMethodCall(name, _, ref args) = expr.node { - if &name.node.as_str() == &"iter" && may_slice(cx, &cx.tcx.expr_ty(&args[0])) { - Some((args[0].span, "&")) - } else { - None - } - } else { - match ty.sty { - ty::TySlice(_) => Some((expr.span, "")), - ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) | - ty::TyBox(ref inner) => { - if may_slice(cx, inner) { - Some((expr.span, "")) - } else { - None - } - } - _ => None, - } - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `unwrap()` for `Option`s and `Result`s -fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &MethodArgs) { - let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&unwrap_args[0])); - - let mess = if match_type(cx, obj_ty, &paths::OPTION) { - Some((OPTION_UNWRAP_USED, "an Option", "None")) - } else if match_type(cx, obj_ty, &paths::RESULT) { - Some((RESULT_UNWRAP_USED, "a Result", "Err")) - } else { - None - }; - - if let Some((lint, kind, none_value)) = mess { - span_lint(cx, - lint, - expr.span, - &format!("used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ - using expect() to provide a better panic - message", - kind, - none_value)); - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `ok().expect()` for `Result`s -fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &MethodArgs) { - // lint if the caller of `ok()` is a `Result` - if match_type(cx, cx.tcx.expr_ty(&ok_args[0]), &paths::RESULT) { - let result_type = cx.tcx.expr_ty(&ok_args[0]); - if let Some(error_type) = get_error_type(cx, result_type) { - if has_debug_impl(error_type, cx) { - span_lint(cx, - OK_EXPECT, - expr.span, - "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`"); - } - } - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { - // lint if the caller of `map()` is an `Option` - if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { - // lint message - let msg = "called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling \ - `map_or(a, f)` instead"; - // get snippets for args to map() and unwrap_or() - let map_snippet = snippet(cx, map_args[1].span, ".."); - let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or() have the same span - let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; - if same_span && !multiline { - span_note_and_lint(cx, - OPTION_MAP_UNWRAP_OR, - expr.span, - msg, - expr.span, - &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", - map_snippet, - unwrap_snippet)); - } else if same_span && multiline { - span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); - }; - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `map().unwrap_or_else()` for `Option`s -fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &MethodArgs, unwrap_args: &MethodArgs) { - // lint if the caller of `map()` is an `Option` - if match_type(cx, cx.tcx.expr_ty(&map_args[0]), &paths::OPTION) { - // lint message - let msg = "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ - `map_or_else(g, f)` instead"; - // get snippets for args to map() and unwrap_or_else() - let map_snippet = snippet(cx, map_args[1].span, ".."); - let unwrap_snippet = snippet(cx, unwrap_args[1].span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or_else() have the same span - let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_args[1].span.expn_id == unwrap_args[1].span.expn_id; - if same_span && !multiline { - span_note_and_lint(cx, - OPTION_MAP_UNWRAP_OR_ELSE, - expr.span, - msg, - expr.span, - &format!("replace `map({0}).unwrap_or_else({1})` with `with map_or_else({1}, {0})`", - map_snippet, - unwrap_snippet)); - } else if same_span && multiline { - span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); - }; - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint use of `filter().next() for Iterators` -fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &MethodArgs) { - // 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 filter_snippet = snippet(cx, filter_args[1].span, ".."); - if filter_snippet.lines().count() <= 1 { - // add note if not multi-line - span_note_and_lint(cx, - FILTER_NEXT, - expr.span, - msg, - expr.span, - &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); - } else { - span_lint(cx, FILTER_NEXT, expr.span, msg); - } - } -} - -#[allow(ptr_arg)] -// Type of MethodArgs is potentially a Vec -/// lint searching an Iterator followed by `is_some()` -fn lint_search_is_some(cx: &LateContext, expr: &hir::Expr, search_method: &str, search_args: &MethodArgs, - is_some_args: &MethodArgs) { - // 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()`.", - search_method); - let search_snippet = snippet(cx, search_args[1].span, ".."); - if search_snippet.lines().count() <= 1 { - // add note if not multi-line - span_note_and_lint(cx, - SEARCH_IS_SOME, - expr.span, - &msg, - expr.span, - &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet)); - } else { - span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); - } - } -} - -/// Checks for the `CHARS_NEXT_CMP` lint. -fn lint_chars_next(cx: &LateContext, expr: &hir::Expr, chain: &hir::Expr, other: &hir::Expr, eq: bool) -> bool { - if_let_chain! {[ - 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 self_ty = walk_ptrs_ty(cx.tcx.expr_ty_adjusted(&args[0][0])); - - if self_ty.sty != ty::TyStr { - return false; - } - - span_lint_and_then(cx, - CHARS_NEXT_CMP, - expr.span, - "you should use the `starts_with` method", - |db| { - let sugg = format!("{}{}.starts_with({})", - if eq { "" } else { "!" }, - snippet(cx, args[0][0].span, "_"), - snippet(cx, arg_char[0].span, "_") - ); - - db.span_suggestion(expr.span, "like this", sugg); - }); - - return true; - }} - - false -} - -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { - if let Ok(ConstVal::Str(r)) = eval_const_expr_partial(cx.tcx, arg, ExprTypeChecked, None) { - if r.len() == 1 { - let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); - span_lint_and_then(cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - |db| { - db.span_suggestion(expr.span, "try using a char instead:", hint); - }); - } - } -} - -/// Given a `Result<T, E>` type, return its error type (`E`). -fn get_error_type<'a>(cx: &LateContext, ty: ty::Ty<'a>) -> Option<ty::Ty<'a>> { - if !match_type(cx, ty, &paths::RESULT) { - return None; - } - if let ty::TyEnum(_, substs) = ty.sty { - if let Some(err_ty) = substs.types.opt_get(TypeSpace, 1) { - return Some(err_ty); - } - } - None -} - -/// This checks whether a given type is known to implement Debug. -fn has_debug_impl<'a, 'b>(ty: ty::Ty<'a>, cx: &LateContext<'b, 'a>) -> bool { - match cx.tcx.lang_items.debug_trait() { - Some(debug) => implements_trait(cx, ty, debug, Vec::new()), - None => false, - } -} - -enum Convention { - Eq(&'static str), - StartsWith(&'static str), -} - -#[cfg_attr(rustfmt, rustfmt_skip)] -const CONVENTIONS: [(Convention, &'static [SelfKind]); 6] = [ - (Convention::Eq("new"), &[SelfKind::No]), - (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]), - (Convention::StartsWith("from_"), &[SelfKind::No]), - (Convention::StartsWith("into_"), &[SelfKind::Value]), - (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]), - (Convention::StartsWith("to_"), &[SelfKind::Ref]), -]; - -#[cfg_attr(rustfmt, rustfmt_skip)] -const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [ - ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"), - ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"), - ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"), - ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"), - ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"), - ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"), - ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"), - ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"), - ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"), - ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"), - ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"), - ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"), - ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"), - ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"), - ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"), - ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"), - ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"), - ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"), - ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"), - ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"), - ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"), - ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"), - ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"), - ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"), - ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"), - ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"), - ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"), - ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"), - ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"), - ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"), -]; - -#[cfg_attr(rustfmt, rustfmt_skip)] -const PATTERN_METHODS: [(&'static str, usize); 17] = [ - ("contains", 1), - ("starts_with", 1), - ("ends_with", 1), - ("find", 1), - ("rfind", 1), - ("split", 1), - ("rsplit", 1), - ("split_terminator", 1), - ("rsplit_terminator", 1), - ("splitn", 2), - ("rsplitn", 2), - ("matches", 1), - ("rmatches", 1), - ("match_indices", 1), - ("rmatch_indices", 1), - ("trim_left_matches", 1), - ("trim_right_matches", 1), -]; - - -#[derive(Clone, Copy)] -enum SelfKind { - Value, - Ref, - RefMut, - No, -} - -impl SelfKind { - fn matches(self, slf: &hir::ExplicitSelf, allow_value_for_ref: bool) -> bool { - match (self, &slf.node) { - (SelfKind::Value, &hir::SelfKind::Value(_)) | - (SelfKind::Ref, &hir::SelfKind::Region(_, hir::Mutability::MutImmutable)) | - (SelfKind::RefMut, &hir::SelfKind::Region(_, hir::Mutability::MutMutable)) => true, - (SelfKind::Ref, &hir::SelfKind::Value(_)) | - (SelfKind::RefMut, &hir::SelfKind::Value(_)) => allow_value_for_ref, - (_, &hir::SelfKind::Explicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref), - - _ => false, - } - } - - fn matches_explicit_type(self, ty: &hir::Ty, allow_value_for_ref: bool) -> bool { - match (self, &ty.node) { - (SelfKind::Value, &hir::TyPath(..)) | - (SelfKind::Ref, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutImmutable, .. })) | - (SelfKind::RefMut, &hir::TyRptr(_, hir::MutTy { mutbl: hir::Mutability::MutMutable, .. })) => true, - (SelfKind::Ref, &hir::TyPath(..)) | - (SelfKind::RefMut, &hir::TyPath(..)) => allow_value_for_ref, - _ => false, - } - } - - fn description(&self) -> &'static str { - match *self { - SelfKind::Value => "self by value", - SelfKind::Ref => "self by reference", - SelfKind::RefMut => "self by mutable reference", - SelfKind::No => "no self", - } - } -} - -impl Convention { - fn check(&self, other: &str) -> bool { - match *self { - Convention::Eq(this) => this == other, - Convention::StartsWith(this) => other.starts_with(this), - } - } -} - -impl fmt::Display for Convention { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - Convention::Eq(this) => this.fmt(f), - Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), - } - } -} - -#[derive(Clone, Copy)] -enum OutType { - Unit, - Bool, - Any, - Ref, -} - -impl OutType { - fn matches(&self, ty: &hir::FunctionRetTy) -> bool { - match (self, ty) { - (&OutType::Unit, &hir::DefaultReturn(_)) => true, - (&OutType::Unit, &hir::Return(ref ty)) if ty.node == hir::TyTup(vec![].into()) => true, - (&OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true, - (&OutType::Any, &hir::Return(ref ty)) if ty.node != hir::TyTup(vec![].into()) => true, - (&OutType::Ref, &hir::Return(ref ty)) => { - if let hir::TyRptr(_, _) = ty.node { - true - } else { - false - } - } - _ => false, - } - } -} - -fn is_bool(ty: &hir::Ty) -> bool { - if let hir::TyPath(None, ref p) = ty.node { - if match_path(p, &["bool"]) { - return true; - } - } - false -} - -fn is_copy<'a, 'ctx>(cx: &LateContext<'a, 'ctx>, ty: ty::Ty<'ctx>, item: &hir::Item) -> bool { - let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id); - !ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, item.span) -} diff --git a/src/minmax.rs b/src/minmax.rs deleted file mode 100644 index eaba19b08e4..00000000000 --- a/src/minmax.rs +++ /dev/null @@ -1,93 +0,0 @@ -use consts::{Constant, constant_simple}; -use rustc::lint::*; -use rustc::hir::*; -use std::cmp::{PartialOrd, Ordering}; -use syntax::ptr::P; -use utils::{match_def_path, paths, span_lint}; - -/// **What it does:** This lint checks for expressions where `std::cmp::min` and `max` are used to clamp values, but switched so that the result is constant. -/// -/// **Why is this bad?** This is in all probability not the intended outcome. At the least it hurts readability of the code. -/// -/// **Known problems:** None -/// -/// **Example:** `min(0, max(100, x))` will always be equal to `0`. Probably the author meant to clamp the value between 0 and 100, but has erroneously swapped `min` and `max`. -declare_lint! { - pub MIN_MAX, Warn, - "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant" -} - -#[allow(missing_copy_implementations)] -pub struct MinMaxPass; - -impl LintPass for MinMaxPass { - fn get_lints(&self) -> LintArray { - lint_array!(MIN_MAX) - } -} - -impl LateLintPass for MinMaxPass { - fn check_expr(&mut self, cx: &LateContext, expr: &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 { - return; - } - match (outer_max, outer_c.partial_cmp(&inner_c)) { - (_, None) | - (MinMax::Max, Some(Ordering::Less)) | - (MinMax::Min, Some(Ordering::Greater)) => (), - _ => { - span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); - } - } - } - } - } -} - -#[derive(PartialEq, Eq, Debug)] -enum MinMax { - Min, - Max, -} - -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.def_map.borrow()[&path.id].def_id(); - - if match_def_path(cx, def_id, &paths::CMP_MIN) { - fetch_const(args, MinMax::Min) - } else if match_def_path(cx, def_id, &paths::CMP_MAX) { - fetch_const(args, MinMax::Max) - } else { - None - } - } else { - None - } - } else { - None - } -} - -fn fetch_const(args: &[P<Expr>], m: MinMax) -> Option<(MinMax, Constant, &Expr)> { - if args.len() != 2 { - return None; - } - if let Some(c) = constant_simple(&args[0]) { - if let None = constant_simple(&args[1]) { - // otherwise ignore - Some((m, c, &args[1])) - } else { - None - } - } else { - if let Some(c) = constant_simple(&args[1]) { - Some((m, c, &args[0])) - } else { - None - } - } -} diff --git a/src/misc.rs b/src/misc.rs deleted file mode 100644 index 3ab7823e50d..00000000000 --- a/src/misc.rs +++ /dev/null @@ -1,458 +0,0 @@ -use reexport::*; -use rustc::hir::*; -use rustc::hir::intravisit::FnKind; -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc::ty; -use rustc_const_eval::EvalHint::ExprTypeChecked; -use rustc_const_eval::eval_const_expr_partial; -use syntax::codemap::{Span, Spanned, ExpnFormat}; -use syntax::ptr::P; -use utils::{ - get_item_name, get_parent_expr, implements_trait, is_integer_literal, match_path, snippet, - span_lint, span_lint_and_then, walk_ptrs_ty -}; - -/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`. -/// -/// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body. -/// -/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The type of `x` is more obvious with the former. -/// -/// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function. -/// -/// **Example:** `fn foo(ref x: u8) -> bool { .. }` -declare_lint! { - pub TOPLEVEL_REF_ARG, Warn, - "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \ - or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \ - references with `&`." -} - -#[allow(missing_copy_implementations)] -pub struct TopLevelRefPass; - -impl LintPass for TopLevelRefPass { - fn get_lints(&self) -> LintArray { - lint_array!(TOPLEVEL_REF_ARG) - } -} - -impl LateLintPass for TopLevelRefPass { - fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - if let FnKind::Closure(_) = k { - // Does not apply to closures - return; - } - for ref arg in &decl.inputs { - if let PatKind::Ident(BindByRef(_), _, _) = arg.pat.node { - span_lint(cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. Consider using a reference type instead."); - } - } - } - fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) { - if_let_chain! { - [ - let StmtDecl(ref d, _) = s.node, - let DeclLocal(ref l) = d.node, - let PatKind::Ident(BindByRef(_), i, None) = l.pat.node, - let Some(ref init) = l.init - ], { - let tyopt = if let Some(ref ty) = l.ty { - format!(": {}", snippet(cx, ty.span, "_")) - } else { - "".to_owned() - }; - span_lint_and_then(cx, - TOPLEVEL_REF_ARG, - l.pat.span, - "`ref` on an entire `let` pattern is discouraged, take a reference with & instead", - |db| { - db.span_suggestion(s.span, - "try", - format!("let {}{} = &{};", - snippet(cx, i.span, "_"), - tyopt, - snippet(cx, init.span, "_"))); - } - ); - } - }; - } -} - -/// **What it does:** This lint checks for comparisons to NAN. -/// -/// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong. -/// -/// **Known problems:** None -/// -/// **Example:** `x == NAN` -declare_lint!(pub CMP_NAN, Deny, - "comparisons to NAN (which will always return false, which is probably not intended)"); - -#[derive(Copy,Clone)] -pub struct CmpNan; - -impl LintPass for CmpNan { - fn get_lints(&self) -> LintArray { - lint_array!(CMP_NAN) - } -} - -impl LateLintPass for CmpNan { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if cmp.node.is_comparison() { - if let ExprPath(_, ref path) = left.node { - check_nan(cx, path, expr.span); - } - if let ExprPath(_, ref path) = right.node { - check_nan(cx, path, expr.span); - } - } - } - } -} - -fn check_nan(cx: &LateContext, path: &Path, span: Span) { - path.segments.last().map(|seg| { - if seg.name.as_str() == "NAN" { - span_lint(cx, - CMP_NAN, - span, - "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); - } - }); -} - -/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats). -/// -/// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison). -/// -/// **Known problems:** None -/// -/// **Example:** `y == 1.23f64` -declare_lint!(pub FLOAT_CMP, Warn, - "using `==` or `!=` on float values (as floating-point operations \ - usually involve rounding errors, it is always better to check for approximate \ - equality within small bounds)"); - -#[derive(Copy,Clone)] -pub struct FloatCmp; - -impl LintPass for FloatCmp { - fn get_lints(&self) -> LintArray { - lint_array!(FLOAT_CMP) - } -} - -impl LateLintPass for FloatCmp { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - let op = cmp.node; - if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } - 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") { - return; - } - } - span_lint(cx, - FLOAT_CMP, - expr.span, - &format!("{}-comparison of f32 or f64 detected. Consider changing this to `({} - {}).abs() < \ - epsilon` for some suitable value of epsilon. \ - std::f32::EPSILON and std::f64::EPSILON are available.", - op.as_str(), - snippet(cx, left.span, ".."), - snippet(cx, right.span, ".."))); - } - } - } -} - -fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { - let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None); - if let Ok(ConstVal::Float(val)) = res { - val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY - } else { - false - } -} - -fn is_float(cx: &LateContext, expr: &Expr) -> bool { - if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty { - true - } else { - false - } -} - -/// **What it does:** This lint checks for conversions to owned values just for the sake of a comparison. -/// -/// **Why is this bad?** The comparison can operate on a reference, so creating an owned value effectively throws it away directly afterwards, which is needlessly consuming code and heap space. -/// -/// **Known problems:** None -/// -/// **Example:** `x.to_owned() == y` -declare_lint!(pub CMP_OWNED, Warn, - "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"); - -#[derive(Copy,Clone)] -pub struct CmpOwned; - -impl LintPass for CmpOwned { - fn get_lints(&self) -> LintArray { - lint_array!(CMP_OWNED) - } -} - -impl LateLintPass for CmpOwned { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, ref left, ref right) = expr.node { - if cmp.node.is_comparison() { - check_to_owned(cx, left, right, true, cmp.span); - check_to_owned(cx, right, left, false, cmp.span) - } - } - } -} - -fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: Span) { - let (arg_ty, snip) = match expr.node { - ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) if args.len() == 1 => { - if name.as_str() == "to_string" || name.as_str() == "to_owned" && is_str_arg(cx, args) { - (cx.tcx.expr_ty(&args[0]), snippet(cx, args[0].span, "..")) - } else { - return; - } - } - ExprCall(ref path, ref v) if v.len() == 1 => { - if let ExprPath(None, ref path) = path.node { - if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { - (cx.tcx.expr_ty(&v[0]), snippet(cx, v[0].span, "..")) - } else { - return; - } - } else { - return; - } - } - _ => return, - }; - - let other_ty = cx.tcx.expr_ty(other); - let partial_eq_trait_id = match cx.tcx.lang_items.eq_trait() { - Some(id) => id, - None => return, - }; - - if !implements_trait(cx, arg_ty, partial_eq_trait_id, vec![other_ty]) { - return; - } - - if left { - span_lint(cx, - CMP_OWNED, - expr.span, - &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ - compare without allocation", - snip, - snippet(cx, op, "=="), - snippet(cx, other.span, ".."))); - } else { - span_lint(cx, - CMP_OWNED, - expr.span, - &format!("this creates an owned instance just for comparison. Consider using `{} {} {}` to \ - compare without allocation", - snippet(cx, other.span, ".."), - snippet(cx, op, "=="), - snip)); - } - -} - -fn is_str_arg(cx: &LateContext, args: &[P<Expr>]) -> bool { - args.len() == 1 && - if let ty::TyStr = walk_ptrs_ty(cx.tcx.expr_ty(&args[0])).sty { - true - } else { - false - } -} - -/// **What it does:** This lint checks for getting the remainder of a division by one. -/// -/// **Why is this bad?** The result can only ever be zero. No one will write such code deliberately, unless trying to win an Underhanded Rust Contest. Even for that contest, it's probably a bad idea. Use something more underhanded. -/// -/// **Known problems:** None -/// -/// **Example:** `x % 1` -declare_lint!(pub MODULO_ONE, Warn, "taking a number modulo 1, which always returns 0"); - -#[derive(Copy,Clone)] -pub struct ModuloOne; - -impl LintPass for ModuloOne { - fn get_lints(&self) -> LintArray { - lint_array!(MODULO_ONE) - } -} - -impl LateLintPass for ModuloOne { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, _, ref right) = expr.node { - if let Spanned { node: BinOp_::BiRem, .. } = *cmp { - if is_integer_literal(right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); - } - } - } - } -} - -/// **What it does:** This lint checks for patterns in the form `name @ _`. -/// -/// **Why is this bad?** It's almost always more readable to just use direct bindings. -/// -/// **Known problems:** None -/// -/// **Example**: -/// ``` -/// match v { -/// Some(x) => (), -/// y @ _ => (), // easier written as `y`, -/// } -/// ``` -declare_lint!(pub REDUNDANT_PATTERN, Warn, "using `name @ _` in a pattern"); - -#[derive(Copy,Clone)] -pub struct PatternPass; - -impl LintPass for PatternPass { - fn get_lints(&self) -> LintArray { - lint_array!(REDUNDANT_PATTERN) - } -} - -impl LateLintPass for PatternPass { - fn check_pat(&mut self, cx: &LateContext, pat: &Pat) { - if let PatKind::Ident(_, 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)); - } - } - } -} - - -/// **What it does:** This lint checks for the use of bindings with a single leading underscore -/// -/// **Why is this bad?** A single leading underscore is usually used to indicate that a binding -/// will not be used. Using such a binding breaks this expectation. -/// -/// **Known problems:** The lint does not work properly with desugaring and macro, it has been -/// allowed in the mean time. -/// -/// **Example**: -/// ``` -/// let _x = 0; -/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore. -/// // We should rename `_x` to `x` -/// ``` -declare_lint!(pub USED_UNDERSCORE_BINDING, Allow, - "using a binding which is prefixed with an underscore"); - -#[derive(Copy, Clone)] -pub struct UsedUnderscoreBinding; - -impl LintPass for UsedUnderscoreBinding { - fn get_lints(&self) -> LintArray { - lint_array!(USED_UNDERSCORE_BINDING) - } -} - -impl LateLintPass for UsedUnderscoreBinding { - #[cfg_attr(rustfmt, rustfmt_skip)] - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_attributes_expansion(cx, expr) { - // Don't lint things expanded by #[derive(...)], etc - return; - } - let binding = match expr.node { - ExprPath(_, ref path) => { - let segment = path.segments - .last() - .expect("path should always have at least one segment") - .name; - if segment.as_str().starts_with('_') && - !segment.as_str().starts_with("__") && - segment != segment.unhygienize() && // not in bang macro - is_used(cx, expr) { - Some(segment.as_str()) - } else { - None - } - } - ExprField(_, spanned) => { - let name = spanned.node.as_str(); - if name.starts_with('_') && !name.starts_with("__") { - Some(name) - } else { - None - } - } - _ => None, - }; - if let Some(binding) = binding { - if binding != "_result" { // FIXME: #944 - span_lint(cx, - 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)); - } - } - } -} - -/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea -/// of what it means for an expression to be "used". -fn is_used(cx: &LateContext, expr: &Expr) -> bool { - if let Some(ref parent) = get_parent_expr(cx, expr) { - match parent.node { - ExprAssign(_, ref rhs) | - ExprAssignOp(_, _, ref rhs) => **rhs == *expr, - _ => is_used(cx, parent), - } - } else { - true - } -} - -/// Test whether an expression is in a macro expansion (e.g. something generated by -/// `#[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| { - match info.callee.format { - ExpnFormat::MacroAttribute(_) => true, - _ => false, - } - }) - }) -} diff --git a/src/misc_early.rs b/src/misc_early.rs deleted file mode 100644 index a7ab59497ac..00000000000 --- a/src/misc_early.rs +++ /dev/null @@ -1,166 +0,0 @@ -use rustc::lint::*; -use std::collections::HashMap; -use syntax::ast::*; -use syntax::codemap::Span; -use syntax::visit::FnKind; -use utils::{span_lint, span_help_and_lint, snippet, span_lint_and_then}; -/// **What it does:** This lint checks for structure field patterns bound to wildcards. -/// -/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound. -/// -/// **Known problems:** None. -/// -/// **Example:** `let { a: _, b: ref b, c: _ } = ..` -declare_lint! { - pub UNNEEDED_FIELD_PATTERN, Warn, - "Struct fields are bound to a wildcard instead of using `..`" -} - -/// **What it does:** This lint checks for function arguments having the similar names differing by an underscore -/// -/// **Why is this bad?** It affects code readability -/// -/// **Known problems:** None. -/// -/// **Example:** `fn foo(a: i32, _a: i32) {}` -declare_lint! { - pub DUPLICATE_UNDERSCORE_ARGUMENT, Warn, - "Function arguments having names which only differ by an underscore" -} - -/// **What it does:** This lint detects closures called in the same expression where they are defined. -/// -/// **Why is this bad?** It is unnecessarily adding to the expression's complexity. -/// -/// **Known problems:** None. -/// -/// **Example:** `(|| 42)()` -declare_lint! { - pub REDUNDANT_CLOSURE_CALL, Warn, - "Closures should not be called in the expression they are defined" -} - -#[derive(Copy, Clone)] -pub struct MiscEarly; - -impl LintPass for MiscEarly { - fn get_lints(&self) -> LintArray { - lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL) - } -} - -impl EarlyLintPass for MiscEarly { - fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { - if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { - let mut wilds = 0; - let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name; - - for field in pfields { - if field.node.pat.node == PatKind::Wild { - wilds += 1; - } - } - if !pfields.is_empty() && wilds == pfields.len() { - span_help_and_lint(cx, - UNNEEDED_FIELD_PATTERN, - pat.span, - "All the struct fields are matched to a wildcard pattern, consider using `..`.", - &format!("Try with `{} {{ .. }}` instead", type_name)); - return; - } - if wilds > 0 { - let mut normal = vec![]; - - for field in pfields { - if field.node.pat.node != PatKind::Wild { - if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) { - normal.push(n); - } - } - } - for field in pfields { - if field.node.pat.node == PatKind::Wild { - wilds -= 1; - if wilds > 0 { - span_lint(cx, - UNNEEDED_FIELD_PATTERN, - field.span, - "You matched a field with a wildcard pattern. Consider using `..` instead"); - } else { - span_help_and_lint(cx, - UNNEEDED_FIELD_PATTERN, - field.span, - "You matched a field with a wildcard pattern. Consider using `..` \ - instead", - &format!("Try with `{} {{ {}, .. }}`", - type_name, - normal[..].join(", "))); - } - } - } - } - } - } - - fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - let mut registered_names: HashMap<String, Span> = HashMap::new(); - - for ref arg in &decl.inputs { - if let PatKind::Ident(_, sp_ident, None) = arg.pat.node { - let arg_name = sp_ident.node.to_string(); - - if arg_name.starts_with('_') { - if let Some(correspondence) = registered_names.get(&arg_name[1..]) { - span_lint(cx, - DUPLICATE_UNDERSCORE_ARGUMENT, - *correspondence, - &format!("`{}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult", - arg_name[1..].to_owned()));; - } - } else { - registered_names.insert(arg_name, arg.pat.span); - } - } - } - } - - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { - if let ExprKind::Call(ref paren, _) = expr.node { - if let ExprKind::Paren(ref closure) = paren.node { - if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node { - span_lint_and_then(cx, - REDUNDANT_CLOSURE_CALL, - expr.span, - "Try not to call a closure in the expression where it is declared.", - |db| { - if decl.inputs.is_empty() { - let hint = format!("{}", snippet(cx, block.span, "..")); - db.span_suggestion(expr.span, "Try doing something like: ", hint); - } - }); - } - } - } - } - - fn check_block(&mut self, cx: &EarlyContext, block: &Block) { - for w in block.stmts.windows(2) { - if_let_chain! {[ - let StmtKind::Decl(ref first, _) = w[0].node, - let DeclKind::Local(ref local) = first.node, - let Option::Some(ref t) = local.init, - let ExprKind::Closure(_,_,_,_) = t.node, - let PatKind::Ident(_,sp_ident,_) = local.pat.node, - let StmtKind::Semi(ref second,_) = w[1].node, - let ExprKind::Assign(_,ref call) = second.node, - let ExprKind::Call(ref closure,_) = call.node, - 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"); - } - }} - } - } -} diff --git a/src/mut_mut.rs b/src/mut_mut.rs deleted file mode 100644 index 4147e288c4f..00000000000 --- a/src/mut_mut.rs +++ /dev/null @@ -1,59 +0,0 @@ -use rustc::lint::*; -use rustc::ty::{TypeAndMut, TyRef}; -use rustc::hir::*; -use utils::{in_external_macro, span_lint}; - -/// **What it does:** This lint checks for instances of `mut mut` references. -/// -/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the source. -/// -/// **Known problems:** None -/// -/// **Example:** `let x = &mut &mut y;` -declare_lint! { - pub MUT_MUT, - Allow, - "usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, \ - or shows a fundamental misunderstanding of references)" -} - -#[derive(Copy,Clone)] -pub struct MutMut; - -impl LintPass for MutMut { - fn get_lints(&self) -> LintArray { - lint_array!(MUT_MUT) - } -} - -impl LateLintPass for MutMut { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_external_macro(cx, expr.span) { - return; - } - - if let ExprAddrOf(MutMutable, ref e) = expr.node { - if let ExprAddrOf(MutMutable, _) = e.node { - span_lint(cx, - MUT_MUT, - expr.span, - "generally you want to avoid `&mut &mut _` if possible"); - } else { - if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { - span_lint(cx, - MUT_MUT, - expr.span, - "this expression mutably borrows a mutable reference. Consider reborrowing"); - } - } - } - } - - fn check_ty(&mut self, cx: &LateContext, ty: &Ty) { - if let TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) = ty.node { - if let TyRptr(_, MutTy { mutbl: MutMutable, .. }) = pty.node { - span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); - } - } - } -} diff --git a/src/mut_reference.rs b/src/mut_reference.rs deleted file mode 100644 index f6aee54d90b..00000000000 --- a/src/mut_reference.rs +++ /dev/null @@ -1,77 +0,0 @@ -use rustc::lint::*; -use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS}; -use rustc::hir::*; -use syntax::ptr::P; -use utils::span_lint; - -/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference. -/// -/// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site. -/// -/// **Known problems:** None -/// -/// **Example** `my_vec.push(&mut value)` -declare_lint! { - pub UNNECESSARY_MUT_PASSED, - Warn, - "an argument is passed as a mutable reference although the function/method only demands an \ - immutable reference" -} - - -#[derive(Copy,Clone)] -pub struct UnnecessaryMutPassed; - -impl LintPass for UnnecessaryMutPassed { - fn get_lints(&self) -> LintArray { - lint_array!(UNNECESSARY_MUT_PASSED) - } -} - -impl LateLintPass for UnnecessaryMutPassed { - fn check_expr(&mut self, cx: &LateContext, e: &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 { - 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()) - } - _ => (), - } - } -} - -fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) { - match type_definition.sty { - TypeVariants::TyFnDef(_, _, ref fn_type) | - TypeVariants::TyFnPtr(ref fn_type) => { - 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, .. }) | - TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => { - if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, - UNNECESSARY_MUT_PASSED, - argument.span, - &format!("The function/method \"{}\" doesn't need a mutable reference", name)); - } - } - _ => (), - } - } - } - _ => (), - } -} diff --git a/src/mutex_atomic.rs b/src/mutex_atomic.rs deleted file mode 100644 index 7d637adb8b8..00000000000 --- a/src/mutex_atomic.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Checks for uses of Mutex where an atomic value could be used -//! -//! This lint is **warn** by default - -use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; -use rustc::ty::subst::ParamSpace; -use rustc::ty; -use rustc::hir::Expr; -use syntax::ast; -use utils::{match_type, paths, span_lint}; - -/// **What it does:** This lint checks for usages of `Mutex<X>` where an atomic will do. -/// -/// **Why is this bad?** Using a Mutex just to make access to a plain bool or reference sequential is shooting flies with cannons. `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and faster. -/// -/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. -/// -/// **Example:** `let x = Mutex::new(&y);` -declare_lint! { - pub MUTEX_ATOMIC, - Warn, - "using a Mutex where an atomic value could be used instead" -} - -/// **What it does:** This lint checks for usages of `Mutex<X>` where `X` is an integral type. -/// -/// **Why is this bad?** Using a Mutex just to make access to a plain integer sequential is shooting flies with cannons. `std::atomic::usize` is leaner and faster. -/// -/// **Known problems:** This lint cannot detect if the Mutex is actually used for waiting before a critical section. -/// -/// **Example:** `let x = Mutex::new(0usize);` -declare_lint! { - pub MUTEX_INTEGER, - Allow, - "using a Mutex for an integer type" -} - -impl LintPass for MutexAtomic { - fn get_lints(&self) -> LintArray { - lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER) - } -} - -pub struct MutexAtomic; - -impl LateLintPass for MutexAtomic { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - let ty = cx.tcx.expr_ty(expr); - if let ty::TyStruct(_, subst) = ty.sty { - if match_type(cx, ty, &paths::MUTEX) { - let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty; - if let Some(atomic_name) = get_atomic_name(mutex_param) { - let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \ - behaviour and not the internal type, consider using Mutex<()>.", - atomic_name); - match *mutex_param { - ty::TyUint(t) if t != ast::UintTy::Us => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::TyInt(t) if t != ast::IntTy::Is => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), - }; - } - } - } - } -} - -fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> { - match *ty { - ty::TyBool => Some("AtomicBool"), - ty::TyUint(_) => Some("AtomicUsize"), - ty::TyInt(_) => Some("AtomicIsize"), - ty::TyRawPtr(_) => Some("AtomicPtr"), - _ => None, - } -} diff --git a/src/needless_bool.rs b/src/needless_bool.rs deleted file mode 100644 index f95d6f5c9c1..00000000000 --- a/src/needless_bool.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Checks for needless boolean results of if-else expressions -//! -//! This lint is **warn** by default - -use rustc::lint::*; -use rustc::hir::*; -use syntax::ast::LitKind; -use syntax::codemap::Spanned; -use utils::{span_lint, span_lint_and_then, snippet, snippet_opt}; - -/// **What it does:** This lint checks for expressions of the form `if c { true } else { false }` (or vice versa) and suggest using the condition directly. -/// -/// **Why is this bad?** Redundant code. -/// -/// **Known problems:** Maybe false positives: Sometimes, the two branches are painstakingly documented (which we of course do not detect), so they *may* have some value. Even then, the documentation can be rewritten to match the shorter code. -/// -/// **Example:** `if x { false } else { true }` -declare_lint! { - pub NEEDLESS_BOOL, - Warn, - "if-statements with plain booleans in the then- and else-clause, e.g. \ - `if p { true } else { false }`" -} - -/// **What it does:** This lint checks for expressions of the form `x == true` (or vice versa) and suggest using the variable directly. -/// -/// **Why is this bad?** Unnecessary code. -/// -/// **Known problems:** None. -/// -/// **Example:** `if x == true { }` could be `if x { }` -declare_lint! { - pub BOOL_COMPARISON, - Warn, - "comparing a variable to a boolean, e.g. \ - `if x == true`" -} - -#[derive(Copy,Clone)] -pub struct NeedlessBool; - -impl LintPass for NeedlessBool { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_BOOL) - } -} - -impl LateLintPass for NeedlessBool { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - use self::Expression::*; - if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { - let reduce = |hint: &str, not| { - let hint = match snippet_opt(cx, pred.span) { - Some(pred_snip) => format!("`{}{}`", not, pred_snip), - None => hint.into(), - }; - span_lint_and_then(cx, - NEEDLESS_BOOL, - e.span, - "this if-then-else expression returns a bool literal", - |db| { - 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)) | - (Bool(true), Bool(true)) => { - span_lint(cx, - 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("its predicate", "return "), - (Bool(true), Bool(false)) => reduce("its predicate", ""), - (RetBool(false), RetBool(true)) => reduce("`!` and its predicate", "return !"), - (Bool(false), Bool(true)) => reduce("`!` and its predicate", "!"), - _ => (), - } - } - } -} - -#[derive(Copy,Clone)] -pub struct BoolComparison; - -impl LintPass for BoolComparison { - fn get_lints(&self) -> LintArray { - lint_array!(BOOL_COMPARISON) - } -} - -impl LateLintPass for BoolComparison { - fn check_expr(&mut self, cx: &LateContext, e: &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)) { - (Bool(true), Other) => { - let hint = snippet(cx, right_side.span, "..").into_owned(); - span_lint_and_then(cx, - BOOL_COMPARISON, - e.span, - "equality checks against true are unnecessary", - |db| { - 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, - BOOL_COMPARISON, - e.span, - "equality checks against true are unnecessary", - |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", hint); - }); - } - (Bool(false), Other) => { - let hint = format!("!{}", snippet(cx, right_side.span, "..")); - span_lint_and_then(cx, - BOOL_COMPARISON, - e.span, - "equality checks against false can be replaced by a negation", - |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", hint); - }); - } - (Other, Bool(false)) => { - let hint = format!("!{}", snippet(cx, left_side.span, "..")); - span_lint_and_then(cx, - BOOL_COMPARISON, - e.span, - "equality checks against false can be replaced by a negation", - |db| { - db.span_suggestion(e.span, "try simplifying it as shown:", hint); - }); - } - _ => (), - } - } - } -} - -enum Expression { - Bool(bool), - RetBool(bool), - Other, -} - -fn fetch_bool_block(block: &Block) -> Expression { - match (&*block.stmts, block.expr.as_ref()) { - ([], Some(e)) => fetch_bool_expr(&**e), - ([ref e], None) => { - if let StmtSemi(ref e, _) = e.node { - if let ExprRet(_) = e.node { - fetch_bool_expr(&**e) - } else { - Expression::Other - } - } else { - Expression::Other - } - } - _ => Expression::Other, - } -} - -fn fetch_bool_expr(expr: &Expr) -> Expression { - match expr.node { - ExprBlock(ref block) => fetch_bool_block(block), - ExprLit(ref lit_ptr) => { - if let LitKind::Bool(value) = lit_ptr.node { - Expression::Bool(value) - } 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/src/needless_borrow.rs b/src/needless_borrow.rs deleted file mode 100644 index 033811841ce..00000000000 --- a/src/needless_borrow.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Checks for needless address of operations (`&`) -//! -//! This lint is **warn** by default - -use rustc::lint::*; -use rustc::hir::{ExprAddrOf, Expr, MutImmutable}; -use rustc::ty::TyRef; -use utils::{span_lint, in_macro}; -use rustc::ty::adjustment::AutoAdjustment::AdjustDerefRef; - -/// **What it does:** This lint checks for address of operations (`&`) that are going to be dereferenced immediately by the compiler -/// -/// **Why is this bad?** Suggests that the receiver of the expression borrows the expression -/// -/// **Known problems:** -/// -/// **Example:** `let x: &i32 = &&&&&&5;` -declare_lint! { - pub NEEDLESS_BORROW, - Warn, - "taking a reference that is going to be automatically dereferenced" -} - -#[derive(Copy,Clone)] -pub struct NeedlessBorrow; - -impl LintPass for NeedlessBorrow { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_BORROW) - } -} - -impl LateLintPass for NeedlessBorrow { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if in_macro(cx, e.span) { - return; - } - if let ExprAddrOf(MutImmutable, ref inner) = e.node { - if let TyRef(..) = cx.tcx.expr_ty(inner).sty { - if let Some(&AdjustDerefRef(ref deref)) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if deref.autoderefs > 1 && deref.autoref.is_some() { - span_lint(cx, - NEEDLESS_BORROW, - e.span, - "this expression borrows a reference that is immediately dereferenced by the compiler"); - } - } - } - } - } -} diff --git a/src/needless_update.rs b/src/needless_update.rs deleted file mode 100644 index d8ae9dc3471..00000000000 --- a/src/needless_update.rs +++ /dev/null @@ -1,42 +0,0 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::ty::TyStruct; -use rustc::hir::{Expr, ExprStruct}; -use utils::span_lint; - -/// **What it does:** This lint warns on needlessly including a base struct on update when all fields are changed anyway. -/// -/// **Why is this bad?** This will cost resources (because the base has to be somewhere), and make the code less readable. -/// -/// **Known problems:** None. -/// -/// **Example:** `Point { x: 1, y: 0, ..zero_point }` -declare_lint! { - pub NEEDLESS_UPDATE, - Warn, - "using `{ ..base }` when there are no missing fields" -} - -#[derive(Copy, Clone)] -pub struct NeedlessUpdatePass; - -impl LintPass for NeedlessUpdatePass { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_UPDATE) - } -} - -impl LateLintPass for NeedlessUpdatePass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprStruct(_, ref fields, Some(ref base)) = expr.node { - let ty = cx.tcx.expr_ty(expr); - if let TyStruct(def, _) = ty.sty { - if fields.len() == def.struct_variant().fields.len() { - span_lint(cx, - NEEDLESS_UPDATE, - base.span, - "struct update has no effect, all the fields in the struct have already been specified"); - } - } - } - } -} diff --git a/src/neg_multiply.rs b/src/neg_multiply.rs deleted file mode 100644 index fb986409a41..00000000000 --- a/src/neg_multiply.rs +++ /dev/null @@ -1,57 +0,0 @@ -use rustc::hir::*; -use rustc::lint::*; -use syntax::codemap::{Span, Spanned}; - -use consts::{self, Constant}; -use utils::span_lint; - -/// **What it does:** Checks for multiplication by -1 as a form of negation. -/// -/// **Why is this bad?** It's more readable to just negate. -/// -/// **Known problems:** This only catches integers (for now) -/// -/// **Example:** `x * -1` -declare_lint! { - pub NEG_MULTIPLY, - Warn, - "Warns on multiplying integers with -1" -} - -#[derive(Copy, Clone)] -pub struct NegMultiply; - -impl LintPass for NegMultiply { - fn get_lints(&self) -> LintArray { - lint_array!(NEG_MULTIPLY) - } -} - -#[allow(match_same_arms)] -impl LateLintPass for NegMultiply { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprBinary(Spanned { node: BiMul, .. }, ref l, ref r) = e.node { - match (&l.node, &r.node) { - (&ExprUnary(..), &ExprUnary(..)) => (), - (&ExprUnary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r), - (_, &ExprUnary(UnNeg, ref lit)) => check_mul(cx, e.span, lit, l), - _ => () - } - } - } -} - -fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { - if_let_chain!([ - let ExprLit(ref l) = lit.node, - let Constant::Int(ref ci) = consts::lit_to_constant(&l.node), - let Some(val) = ci.to_u64(), - val == 1, - cx.tcx.expr_ty(exp).is_integral() - ], { - span_lint(cx, - NEG_MULTIPLY, - span, - "Negation by multiplying with -1"); - }) -} diff --git a/src/new_without_default.rs b/src/new_without_default.rs deleted file mode 100644 index 08d517014ee..00000000000 --- a/src/new_without_default.rs +++ /dev/null @@ -1,148 +0,0 @@ -use rustc::hir::intravisit::FnKind; -use rustc::hir::def_id::DefId; -use rustc::hir; -use rustc::lint::*; -use rustc::ty; -use syntax::ast; -use syntax::codemap::Span; -use utils::paths; -use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint}; - -/// **What it does:** This lints about type with a `fn new() -> Self` method -/// and no implementation of -/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) -/// -/// **Why is this bad?** User might expect to be able to use -/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) -/// as the type can be -/// constructed without arguments. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// -/// ```rust,ignore -/// struct Foo(Bar); -/// -/// impl Foo { -/// fn new() -> Self { -/// Foo(Bar::new()) -/// } -/// } -/// ``` -/// -/// Instead, use: -/// -/// ```rust -/// struct Foo(Bar); -/// -/// impl Default for Foo { -/// fn default() -> Self { -/// Foo(Bar::new()) -/// } -/// } -/// ``` -/// -/// You can also have `new()` call `Default::default()` -declare_lint! { - pub NEW_WITHOUT_DEFAULT, - Warn, - "`fn new() -> Self` method without `Default` implementation" -} - -/// **What it does:** This lints about type with a `fn new() -> Self` method -/// and no implementation of -/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) -/// -/// **Why is this bad?** User might expect to be able to use -/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) -/// as the type can be -/// constructed without arguments. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// -/// ```rust,ignore -/// struct Foo; -/// -/// impl Foo { -/// fn new() -> Self { -/// Foo -/// } -/// } -/// ``` -/// -/// Just prepend `#[derive(Default)]` before the `struct` definition -declare_lint! { - pub NEW_WITHOUT_DEFAULT_DERIVE, - Warn, - "`fn new() -> Self` without `#[derive]`able `Default` implementation" -} - -#[derive(Copy,Clone)] -pub struct NewWithoutDefault; - -impl LintPass for NewWithoutDefault { - fn get_lints(&self) -> LintArray { - lint_array!(NEW_WITHOUT_DEFAULT, NEW_WITHOUT_DEFAULT_DERIVE) - } -} - -impl LateLintPass for NewWithoutDefault { - fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, id: ast::NodeId) { - if in_external_macro(cx, span) { - return; - } - - if let FnKind::Method(name, _, _, _) = kind { - if decl.inputs.is_empty() && name.as_str() == "new" { - let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id( - cx.tcx.map.get_parent(id))).ty; - if_let_chain!{[ - self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics - let Some(ret_ty) = return_ty(cx, id), - same_tys(cx, self_ty, ret_ty, id), - let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), - !implements_trait(cx, self_ty, default_trait_id, Vec::new()) - ], { - if can_derive_default(self_ty, cx, default_trait_id) { - span_lint(cx, - NEW_WITHOUT_DEFAULT_DERIVE, span, - &format!("you should consider deriving a \ - `Default` implementation for `{}`", - self_ty)). - span_suggestion(span, - "try this", - "#[derive(Default)]".into()); - } else { - span_lint(cx, - NEW_WITHOUT_DEFAULT, span, - &format!("you should consider adding a \ - `Default` implementation for `{}`", - self_ty)). - span_suggestion(span, - "try this", - format!("impl Default for {} {{ fn default() -> \ - Self {{ {}::new() }} }}", self_ty, self_ty)); - } - }} - } - } - } -} - -fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> bool { - match ty.sty { - ty::TyStruct(ref adt_def, ref substs) => { - for field in adt_def.all_fields() { - let f_ty = field.ty(cx.tcx, substs); - if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) { - return false - } - } - true - }, - _ => false - } -} diff --git a/src/no_effect.rs b/src/no_effect.rs deleted file mode 100644 index ae3bac00455..00000000000 --- a/src/no_effect.rs +++ /dev/null @@ -1,155 +0,0 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::hir::def::{Def, PathResolution}; -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; - -/// **What it does:** This lint checks for statements which have no effect. -/// -/// **Why is this bad?** Similar to dead code, these statements are actually executed. However, as they have no effect, all they do is make the code less readable. -/// -/// **Known problems:** None. -/// -/// **Example:** `0;` -declare_lint! { - pub NO_EFFECT, - Warn, - "statements with no effect" -} - -/// **What it does:** This lint checks for expression statements that can be reduced to a sub-expression -/// -/// **Why is this bad?** Expressions by themselves often have no side-effects. Having such expressions reduces redability. -/// -/// **Known problems:** None. -/// -/// **Example:** `compute_array()[0];` -declare_lint! { - pub UNNECESSARY_OPERATION, - Warn, - "outer expressions with no effect" -} - -fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { - if in_macro(cx, expr.span) { - return false; - } - match expr.node { - Expr_::ExprLit(..) | - Expr_::ExprClosure(..) | - Expr_::ExprPath(..) => true, - Expr_::ExprIndex(ref a, ref b) | - Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b), - Expr_::ExprVec(ref v) | - Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), - Expr_::ExprRepeat(ref inner, _) | - Expr_::ExprCast(ref inner, _) | - Expr_::ExprType(ref inner, _) | - Expr_::ExprUnary(_, ref inner) | - Expr_::ExprField(ref inner, _) | - Expr_::ExprTupField(ref inner, _) | - Expr_::ExprAddrOf(_, ref inner) | - Expr_::ExprBox(ref inner) => has_no_effect(cx, inner), - Expr_::ExprStruct(_, ref fields, ref base) => { - fields.iter().all(|field| has_no_effect(cx, &field.expr)) && - match *base { - 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(..)) => args.iter().all(|arg| has_no_effect(cx, arg)), - _ => false, - } - } - Expr_::ExprBlock(ref block) => { - block.stmts.is_empty() && - if let Some(ref expr) = block.expr { - has_no_effect(cx, expr) - } else { - false - } - } - _ => false, - } -} - -#[derive(Copy, Clone)] -pub struct NoEffectPass; - -impl LintPass for NoEffectPass { - fn get_lints(&self) -> LintArray { - lint_array!(NO_EFFECT, UNNECESSARY_OPERATION) - } -} - -impl LateLintPass for NoEffectPass { - fn check_stmt(&mut self, cx: &LateContext, stmt: &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"); - } else if let Some(reduced) = reduce_expression(cx, expr) { - let mut snippet = String::new(); - for e in reduced { - if in_macro(cx, e.span) { - return; - } - if let Some(snip) = snippet_opt(cx, e.span) { - snippet.push_str(&snip); - snippet.push(';'); - } else { - return; - } - } - span_lint_and_then(cx, UNNECESSARY_OPERATION, stmt.span, "statement can be reduced", |db| { - db.span_suggestion(stmt.span, "replace it with", snippet); - }); - } - } - } -} - - -fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Expr>> { - if in_macro(cx, expr.span) { - return None; - } - match expr.node { - Expr_::ExprIndex(ref a, ref b) | - Expr_::ExprBinary(_, ref a, ref b) => Some(vec![&**a, &**b]), - Expr_::ExprVec(ref v) | - Expr_::ExprTup(ref v) => Some(v.iter().map(Deref::deref).collect()), - Expr_::ExprRepeat(ref inner, _) | - Expr_::ExprCast(ref inner, _) | - Expr_::ExprType(ref inner, _) | - Expr_::ExprUnary(_, ref inner) | - Expr_::ExprField(ref inner, _) | - Expr_::ExprTupField(ref inner, _) | - Expr_::ExprAddrOf(_, ref inner) | - Expr_::ExprBox(ref inner) => 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(args.iter().map(Deref::deref).collect()), - _ => None, - } - } - Expr_::ExprBlock(ref block) => { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|e| match block.rules { - BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None, - BlockCheckMode::DefaultBlock => Some(vec![&**e]), - // in case of compiler-inserted signaling blocks - _ => reduce_expression(cx, e), - }) - } else { - None - } - } - _ => None, - } -} diff --git a/src/non_expressive_names.rs b/src/non_expressive_names.rs deleted file mode 100644 index cbb083a3e16..00000000000 --- a/src/non_expressive_names.rs +++ /dev/null @@ -1,291 +0,0 @@ -use rustc::lint::*; -use syntax::codemap::Span; -use syntax::parse::token::InternedString; -use syntax::ast::*; -use syntax::attr; -use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr}; -use utils::{span_lint_and_then, in_macro, span_lint}; - -/// **What it does:** This lint warns about names that are very similar and thus confusing -/// -/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character -/// -/// **Known problems:** None? -/// -/// **Example:** `checked_exp` and `checked_expr` -declare_lint! { - pub SIMILAR_NAMES, - Allow, - "similarly named items and bindings" -} - -/// **What it does:** This lint warns about having too many variables whose name consists of a single character -/// -/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name. -/// -/// **Known problems:** None? -/// -/// **Example:** let (a, b, c, d, e, f, g) = (...); -declare_lint! { - pub MANY_SINGLE_CHAR_NAMES, - Warn, - "too many single character bindings" -} - -pub struct NonExpressiveNames { - pub max_single_char_names: u64, -} - -impl LintPass for NonExpressiveNames { - fn get_lints(&self) -> LintArray { - lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES) - } -} - -struct ExistingName { - interned: InternedString, - span: Span, - len: usize, - whitelist: &'static [&'static str], -} - -struct SimilarNamesLocalVisitor<'a, 'b: 'a> { - names: Vec<ExistingName>, - cx: &'a EarlyContext<'b>, - lint: &'a NonExpressiveNames, - single_char_names: Vec<char>, -} - -// this list contains lists of names that are allowed to be similar -// the assumption is that no name is ever contained in multiple lists. -#[cfg_attr(rustfmt, rustfmt_skip)] -const WHITELIST: &'static [&'static [&'static str]] = &[ - &["parsed", "parser"], - &["lhs", "rhs"], - &["tx", "rx"], - &["set", "get"], -]; - -struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); - -impl<'v, 'a, 'b, 'c> Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { - fn visit_pat(&mut self, pat: &'v Pat) { - match pat.node { - PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), - PatKind::Struct(_, ref fields, _) => for field in fields { - if !field.node.is_shorthand { - self.visit_pat(&field.node.pat); - } - }, - _ => walk_pat(self, pat), - } - } -} - -fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { - for &allow in WHITELIST { - if whitelisted(interned_name, allow) { - return Some(allow); - } - } - None -} - -fn whitelisted(interned_name: &str, list: &[&str]) -> bool { - if list.iter().any(|&name| interned_name == name) { - return true; - } - for name in list { - // name_* - if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) { - return true; - } - // *_name - if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) { - return true; - } - } - false -} - -impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { - fn check_short_name(&mut self, c: char, span: Span) { - // make sure we ignore shadowing - if self.0.single_char_names.contains(&c) { - return; - } - self.0.single_char_names.push(c); - if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names { - span_lint(self.0.cx, - MANY_SINGLE_CHAR_NAMES, - span, - &format!("{}th binding whose name is just one char", self.0.single_char_names.len())); - } - } - fn check_name(&mut self, span: Span, name: Name) { - if in_macro(self.0.cx, span) { - return; - } - let interned_name = name.as_str(); - if interned_name.chars().any(char::is_uppercase) { - return; - } - let count = interned_name.chars().count(); - if count < 3 { - if count == 1 { - let c = interned_name.chars().next().expect("already checked"); - self.check_short_name(c, span); - } - return; - } - for existing_name in &self.0.names { - if whitelisted(&interned_name, existing_name.whitelist) { - continue; - } - let mut split_at = None; - if existing_name.len > count { - if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { - continue; - } - } else if existing_name.len < count { - if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { - continue; - } - } else { - let mut interned_chars = interned_name.chars(); - let mut existing_chars = existing_name.interned.chars(); - let first_i = interned_chars.next().expect("we know we have at least one char"); - let first_e = existing_chars.next().expect("we know we have at least one char"); - let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); - - if eq_or_numeric(first_i, first_e) { - let last_i = interned_chars.next_back().expect("we know we have at least two chars"); - let last_e = existing_chars.next_back().expect("we know we have at least two chars"); - if eq_or_numeric(last_i, last_e) { - if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 { - continue; - } - } else { - let second_last_i = interned_chars.next_back().expect("we know we have at least three chars"); - let second_last_e = existing_chars.next_back().expect("we know we have at least three chars"); - if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { - // allowed similarity foo_x, foo_y - // or too many chars differ (foo_x, boo_y) or (foox, booy) - continue; - } - split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); - } - } else { - let second_i = interned_chars.next().expect("we know we have at least two chars"); - let second_e = existing_chars.next().expect("we know we have at least two chars"); - if !eq_or_numeric(second_i, second_e) || second_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { - // allowed similarity x_foo, y_foo - // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) - continue; - } - split_at = interned_name.chars().next().map(|c| c.len_utf8()); - } - } - span_lint_and_then(self.0.cx, - SIMILAR_NAMES, - span, - "binding's name is too similar to existing binding", - |diag| { - diag.span_note(existing_name.span, "existing binding defined here"); - if let Some(split) = split_at { - diag.span_help(span, - &format!("separate the discriminating character by an \ - underscore like: `{}_{}`", - &interned_name[..split], - &interned_name[split..])); - } - }); - return; - } - self.0.names.push(ExistingName { - whitelist: get_whitelist(&interned_name).unwrap_or(&[]), - interned: interned_name, - span: span, - len: count, - }); - } -} - -impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { - /// ensure scoping rules work - fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) { - let n = self.names.len(); - let single_char_count = self.single_char_names.len(); - f(self); - self.names.truncate(n); - self.single_char_names.truncate(single_char_count); - } -} - -impl<'v, 'a, 'b> Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { - fn visit_local(&mut self, local: &'v Local) { - if let Some(ref init) = local.init { - self.apply(|this| walk_expr(this, &**init)); - } - // add the pattern after the expression because the bindings aren't available yet in the init expression - SimilarNamesNameVisitor(self).visit_pat(&*local.pat); - } - fn visit_block(&mut self, blk: &'v Block) { - self.apply(|this| walk_block(this, blk)); - } - fn visit_arm(&mut self, arm: &'v Arm) { - self.apply(|this| { - // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier - SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); - this.apply(|this| walk_expr(this, &arm.body)); - }); - } - fn visit_item(&mut self, _: &'v Item) { - // do not recurse into inner items - } -} - -impl EarlyLintPass for NonExpressiveNames { - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { - if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node { - if !attr::contains_name(&item.attrs, "test") { - let mut visitor = SimilarNamesLocalVisitor { - names: Vec::new(), - cx: cx, - lint: self, - single_char_names: Vec::new(), - }; - // initialize with function arguments - for arg in &decl.inputs { - SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat); - } - // walk all other bindings - walk_block(&mut visitor, blk); - } - } - } -} - -/// Precondition: `a_name.chars().count() < b_name.chars().count()`. -fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { - debug_assert!(a_name.chars().count() < b_name.chars().count()); - let mut a_chars = a_name.chars(); - let mut b_chars = b_name.chars(); - while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) { - if a == b { - continue; - } - if let Some(b2) = b_chars.next() { - // check if there's just one character inserted - return a != b2 || a_chars.ne(b_chars); - } else { - // tuple - // ntuple - return true; - } - } - // for item in items - true -} diff --git a/src/open_options.rs b/src/open_options.rs deleted file mode 100644 index 1d760599e3f..00000000000 --- a/src/open_options.rs +++ /dev/null @@ -1,185 +0,0 @@ -use rustc::hir::{Expr, ExprMethodCall, ExprLit}; -use rustc::lint::*; -use syntax::ast::LitKind; -use syntax::codemap::{Span, Spanned}; -use utils::{match_type, paths, span_lint, walk_ptrs_ty_depth}; - -/// **What it does:** This lint checks for duplicate open options as well as combinations that make no sense. -/// -/// **Why is this bad?** In the best case, the code will be harder to read than necessary. I don't know the worst case. -/// -/// **Known problems:** None -/// -/// **Example:** `OpenOptions::new().read(true).truncate(true)` -declare_lint! { - pub NONSENSICAL_OPEN_OPTIONS, - Warn, - "nonsensical combination of options for opening a file" -} - - -#[derive(Copy,Clone)] -pub struct NonSensicalOpenOptions; - -impl LintPass for NonSensicalOpenOptions { - fn get_lints(&self) -> LintArray { - lint_array!(NONSENSICAL_OPEN_OPTIONS) - } -} - -impl LateLintPass for NonSensicalOpenOptions { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprMethodCall(ref name, _, ref arguments) = e.node { - let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); - if name.node.as_str() == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { - let mut options = Vec::new(); - get_open_options(cx, &arguments[0], &mut options); - check_open_options(cx, &options, e.span); - } - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum Argument { - True, - False, - Unknown, -} - -#[derive(Debug)] -enum OpenOption { - Write, - Read, - Truncate, - Create, - Append, -} - -fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprMethodCall(ref name, _, ref arguments) = argument.node { - let (obj_ty, _) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&arguments[0])); - - // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { - - 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 - } - } 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)); - } - _ => (), - } - - get_open_options(cx, &arguments[0], options); - } - } -} - -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); - // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. - - for option in options { - match *option { - (OpenOption::Create, arg) => { - if create { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"create\" is called more than once"); - } else { - create = true - } - create_arg = create_arg || (arg == Argument::True);; - } - (OpenOption::Append, arg) => { - if append { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"append\" is called more than once"); - } else { - append = true - } - append_arg = append_arg || (arg == Argument::True);; - } - (OpenOption::Truncate, arg) => { - if truncate { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"truncate\" is called more than once"); - } else { - truncate = true - } - truncate_arg = truncate_arg || (arg == Argument::True); - } - (OpenOption::Read, arg) => { - if read { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"read\" is called more than once"); - } else { - read = true - } - read_arg = read_arg || (arg == Argument::True);; - } - (OpenOption::Write, arg) => { - if write { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"write\" is called more than once"); - } else { - write = true - } - write_arg = write_arg || (arg == Argument::True);; - } - } - } - - if read && truncate && read_arg && truncate_arg { - span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\""); - } - if append && truncate && append_arg && truncate_arg { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "file opened with \"append\" and \"truncate\""); - } -} diff --git a/src/overflow_check_conditional.rs b/src/overflow_check_conditional.rs deleted file mode 100644 index 34921bc2c04..00000000000 --- a/src/overflow_check_conditional.rs +++ /dev/null @@ -1,72 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use utils::span_lint; - -/// **What it does:** This lint finds classic underflow / overflow checks. -/// -/// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. -/// -/// **Known problems:** None. -/// -/// **Example:** `a + b < a` - -declare_lint!(pub OVERFLOW_CHECK_CONDITIONAL, Warn, - "Using overflow checks which are likely to panic"); - -#[derive(Copy, Clone)] -pub struct OverflowCheckConditional; - -impl LintPass for OverflowCheckConditional { - fn get_lints(&self) -> LintArray { - lint_array!(OVERFLOW_CHECK_CONDITIONAL) - } -} - -impl LateLintPass for OverflowCheckConditional { - // a + b < a, a > a + b, a < a - b, a - b > a - fn check_expr(&mut self, cx: &LateContext, expr: &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, - &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], - cx.tcx.expr_ty(ident1).is_integral(), - cx.tcx.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."); - } - } - 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."); - } - } - }} - - 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, - &path1.segments[0] == &path3.segments[0] || &path2.segments[0] == &path3.segments[0], - cx.tcx.expr_ty(ident1).is_integral(), - cx.tcx.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."); - } - } - 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."); - } - } - }} - } -} diff --git a/src/panic.rs b/src/panic.rs deleted file mode 100644 index d744d2a6308..00000000000 --- a/src/panic.rs +++ /dev/null @@ -1,47 +0,0 @@ -use rustc::hir::*; -use rustc::lint::*; -use syntax::ast::LitKind; -use utils::{is_direct_expn_of, match_path, paths, span_lint}; - -/// **What it does:** This lint checks for missing parameters in `panic!`. -/// -/// **Known problems:** Should you want to use curly brackets in `panic!` without any parameter, -/// this lint will warn. -/// -/// **Example:** -/// ``` -/// panic!("This `panic!` is probably missing a parameter there: {}"); -/// ``` -declare_lint! { - pub PANIC_PARAMS, Warn, "missing parameters in `panic!`" -} - -#[allow(missing_copy_implementations)] -pub struct PanicPass; - -impl LintPass for PanicPass { - fn get_lints(&self) -> LintArray { - lint_array!(PANIC_PARAMS) - } -} - -impl LateLintPass for PanicPass { - fn check_expr(&mut self, cx: &LateContext, expr: &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, ref path) = fun.node, - match_path(path, &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, - let Some(par) = string.find('{'), - string[par..].contains('}') - ], { - span_lint(cx, PANIC_PARAMS, params[0].span, - "you probably are missing some parameter in your format string"); - }} - } -} diff --git a/src/precedence.rs b/src/precedence.rs deleted file mode 100644 index 825a1b84450..00000000000 --- a/src/precedence.rs +++ /dev/null @@ -1,118 +0,0 @@ -use rustc::lint::*; -use syntax::ast::*; -use syntax::codemap::Spanned; -use utils::{span_lint, snippet}; - -/// **What it does:** This lint checks for operations where precedence may be unclear and suggests to add parentheses. Currently it catches the following: -/// * mixed usage of arithmetic and bit shifting/combining operators without parentheses -/// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) followed by a method call -/// -/// **Why is this bad?** Because not everyone knows the precedence of those operators by heart, so expressions like these may trip others trying to reason about the code. -/// -/// **Known problems:** None -/// -/// **Examples:** -/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 -/// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 -declare_lint! { - pub PRECEDENCE, Warn, - "catches operations where precedence may be unclear. See the wiki for a \ - list of cases caught" -} - -#[derive(Copy,Clone)] -pub struct Precedence; - -impl LintPass for Precedence { - fn get_lints(&self) -> LintArray { - lint_array!(PRECEDENCE) - } -} - -impl EarlyLintPass for Precedence { - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { - if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { - if !is_bit_op(op) { - return; - } - match (is_arith_expr(left), is_arith_expr(right)) { - (true, true) => { - span_lint(cx, - PRECEDENCE, - expr.span, - &format!("operator precedence can trip the unwary. Consider parenthesizing your \ - expression:`({}) {} ({})`", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, ".."))); - } - (true, false) => { - span_lint(cx, - PRECEDENCE, - expr.span, - &format!("operator precedence can trip the unwary. Consider parenthesizing your \ - expression:`({}) {} {}`", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, ".."))); - } - (false, true) => { - span_lint(cx, - PRECEDENCE, - expr.span, - &format!("operator precedence can trip the unwary. Consider parenthesizing your \ - expression:`{} {} ({})`", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, ".."))); - } - _ => (), - } - } - - if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.node { - if let ExprKind::MethodCall(_, _, ref args) = rhs.node { - if let Some(slf) = args.first() { - if let ExprKind::Lit(ref lit) = slf.node { - match lit.node { - LitKind::Int(..) | - LitKind::Float(..) | - LitKind::FloatUnsuffixed(..) => { - span_lint(cx, - PRECEDENCE, - expr.span, - &format!("unary minus has lower precedence than method call. Consider \ - adding parentheses to clarify your intent: -({})", - snippet(cx, rhs.span, ".."))); - } - _ => (), - } - } - } - } - } - } -} - -fn is_arith_expr(expr: &Expr) -> bool { - match expr.node { - ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op), - _ => false, - } -} - -fn is_bit_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; - match op { - BitXor | BitAnd | BitOr | Shl | Shr => true, - _ => false, - } -} - -fn is_arith_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; - match op { - Add | Sub | Mul | Div | Rem => true, - _ => false, - } -} diff --git a/src/print.rs b/src/print.rs deleted file mode 100644 index d426286dba4..00000000000 --- a/src/print.rs +++ /dev/null @@ -1,88 +0,0 @@ -use rustc::hir::*; -use rustc::hir::map::Node::{NodeItem, NodeImplItem}; -use rustc::lint::*; -use utils::paths; -use utils::{is_expn_of, match_path, span_lint}; - -/// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants. -/// -/// **Why is this bad?** People often print on *stdout* while debugging an application and might -/// forget to remove those prints afterward. -/// -/// **Known problems:** Only catches `print!` and `println!` calls. -/// -/// **Example:** `println!("Hello world!");` -declare_lint! { - pub PRINT_STDOUT, - Allow, - "printing on stdout" -} - -/// **What it does:** This lint warns whenever you use `Debug` formatting. The purpose of this lint is to catch debugging remnants. -/// -/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate debugging Rust code. It -/// should not be used in in user-facing output. -/// -/// **Example:** `println!("{:?}", foo);` -declare_lint! { - pub USE_DEBUG, - Allow, - "use `Debug`-based formatting" -} - -#[derive(Copy, Clone, Debug)] -pub struct PrintLint; - -impl LintPass for PrintLint { - fn get_lints(&self) -> LintArray { - lint_array!(PRINT_STDOUT, USE_DEBUG) - } -} - -impl LateLintPass for PrintLint { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprCall(ref fun, ref args) = expr.node { - if let ExprPath(_, ref path) = fun.node { - // Search for `std::io::_print(..)` which is unique in a - // `print!` expansion. - if match_path(path, &paths::IO_PRINT) { - if let Some(span) = is_expn_of(cx, expr.span, "print") { - // `println!` uses `print!`. - let (span, name) = match is_expn_of(cx, span, "println") { - Some(span) => (span, "println"), - None => (span, "print"), - }; - - span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); - } - } - // Search for something like - // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` - else if args.len() == 2 && match_path(path, &paths::FMT_ARGUMENTV1_NEW) { - if let ExprPath(None, ref path) = args[1].node { - if match_path(path, &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"); - } - } - } - } - } - } -} - -fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { - let map = &cx.tcx.map; - - // `fmt` method - if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { - // `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"]); - } - } - } - - false -} diff --git a/src/ptr_arg.rs b/src/ptr_arg.rs deleted file mode 100644 index addcfc9e84d..00000000000 --- a/src/ptr_arg.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Checks for usage of `&Vec[_]` and `&String`. - -use rustc::hir::*; -use rustc::hir::map::NodeItem; -use rustc::lint::*; -use rustc::ty; -use syntax::ast::NodeId; -use utils::{match_type, paths, span_lint}; - -/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless the references are mutable. -/// -/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be obtained from other types, too. -/// -/// **Known problems:** None -/// -/// **Example:** `fn foo(&Vec<u32>) { .. }` -declare_lint! { - pub PTR_ARG, - Warn, - "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \ - instead, respectively" -} - -#[derive(Copy,Clone)] -pub struct PtrArg; - -impl LintPass for PtrArg { - fn get_lints(&self) -> LintArray { - lint_array!(PTR_ARG) - } -} - -impl LateLintPass for PtrArg { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemFn(ref decl, _, _, _, _, _) = item.node { - check_fn(cx, decl, item.id); - } - } - - fn check_impl_item(&mut self, cx: &LateContext, item: &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 { - return; // ignore trait impls - } - } - check_fn(cx, &sig.decl, item.id); - } - } - - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - if let MethodTraitItem(ref sig, _) = item.node { - check_fn(cx, &sig.decl, item.id); - } - } -} - -fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { - let fn_ty = cx.tcx.node_id_to_type(fn_id).fn_sig().skip_binder(); - - 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, - PTR_ARG, - arg.ty.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices. Consider changing the type to `&[...]`"); - } else if match_type(cx, ty, &paths::STRING) { - span_lint(cx, - PTR_ARG, - arg.ty.span, - "writing `&String` instead of `&str` involves a new object where a slice will do. \ - Consider changing the type to `&str`"); - } - } - } -} diff --git a/src/ranges.rs b/src/ranges.rs deleted file mode 100644 index e96212a9cef..00000000000 --- a/src/ranges.rs +++ /dev/null @@ -1,89 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use syntax::codemap::Spanned; -use utils::{is_integer_literal, match_type, paths, snippet, span_lint, unsugar_range, UnsugaredRange}; - -/// **What it does:** This lint checks for iterating over ranges with a `.step_by(0)`, which never terminates. -/// -/// **Why is this bad?** This very much looks like an oversight, since with `loop { .. }` there is an obvious better way to endlessly loop. -/// -/// **Known problems:** None -/// -/// **Example:** `for x in (5..5).step_by(0) { .. }` -declare_lint! { - pub RANGE_STEP_BY_ZERO, Warn, - "using Range::step_by(0), which produces an infinite iterator" -} -/// **What it does:** This lint checks for zipping a collection with the range of `0.._.len()`. -/// -/// **Why is this bad?** The code is better expressed with `.enumerate()`. -/// -/// **Known problems:** None -/// -/// **Example:** `x.iter().zip(0..x.len())` -declare_lint! { - pub RANGE_ZIP_WITH_LEN, Warn, - "zipping iterator with a range when enumerate() would do" -} - -#[derive(Copy,Clone)] -pub struct StepByZero; - -impl LintPass for StepByZero { - fn get_lints(&self) -> LintArray { - lint_array!(RANGE_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN) - } -} - -impl LateLintPass for StepByZero { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprMethodCall(Spanned { node: ref name, .. }, _, ref args) = expr.node { - // Range with step_by(0). - if name.as_str() == "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, - "Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \ - instead"); - } else if name.as_str() == "zip" && args.len() == 2 { - let iter = &args[0].node; - let zip_arg = &args[1]; - if_let_chain! { - [ - // .iter() call - let ExprMethodCall( Spanned { node: ref iter_name, .. }, _, ref iter_args ) = *iter, - iter_name.as_str() == "iter", - // range expression in .zip() call: 0..x.len() - let Some(UnsugaredRange { start: Some(ref start), end: Some(ref end), .. }) = unsugar_range(zip_arg), - is_integer_literal(start, 0), - // .len() call - 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 - ], { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - expr.span, - &format!("It is more idiomatic to use {}.iter().enumerate()", - snippet(cx, iter_args[0].span, "_"))); - } - } - } - } - } -} - -fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { - // No need for walk_ptrs_ty here because step_by moves self, so it - // can't be called on a borrowed range. - let ty = cx.tcx.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) -} diff --git a/src/regex.rs b/src/regex.rs deleted file mode 100644 index c97a64ebf09..00000000000 --- a/src/regex.rs +++ /dev/null @@ -1,229 +0,0 @@ -use regex_syntax; -use rustc::hir::*; -use rustc::lint::*; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::EvalHint::ExprTypeChecked; -use rustc_const_eval::eval_const_expr_partial; -use std::collections::HashSet; -use std::error::Error; -use syntax::ast::{LitKind, NodeId}; -use syntax::codemap::{Span, BytePos}; -use syntax::parse::token::InternedString; -use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint}; - -/// **What it does:** This lint checks [regex] creation (with `Regex::new`, `RegexBuilder::new` or -/// `RegexSet::new`) for correct regex syntax. -/// -/// **Why is this bad?** This will lead to a runtime panic. -/// -/// **Known problems:** None. -/// -/// **Example:** `Regex::new("|")` -declare_lint! { - pub INVALID_REGEX, - Deny, - "finds invalid regular expressions" -} - -/// **What it does:** This lint checks for trivial [regex] creation (with `Regex::new`, -/// `RegexBuilder::new` or `RegexSet::new`). -/// -/// **Why is this bad?** This can likely be replaced by `==` or `str::starts_with`, -/// `str::ends_with` or `std::contains` or other `str` methods. -/// -/// **Known problems:** None. -/// -/// **Example:** `Regex::new("^foobar")` -/// -/// [regex]: https://crates.io/crates/regex -declare_lint! { - pub TRIVIAL_REGEX, - Warn, - "finds trivial regular expressions" -} - -/// **What it does:** This lint checks for usage of `regex!(_)` which as of now is usually slower than `Regex::new(_)` unless called in a loop (which is a bad idea anyway). -/// -/// **Why is this bad?** Performance, at least for now. The macro version is likely to catch up long-term, but for now the dynamic version is faster. -/// -/// **Known problems:** None -/// -/// **Example:** `regex!("foo|bar")` -declare_lint! { - pub REGEX_MACRO, - Warn, - "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" -} - -#[derive(Clone, Default)] -pub struct RegexPass { - spans: HashSet<Span>, - last: Option<NodeId>, -} - -impl LintPass for RegexPass { - fn get_lints(&self) -> LintArray { - lint_array!(INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX) - } -} - -impl LateLintPass for RegexPass { - fn check_crate(&mut self, _: &LateContext, _: &Crate) { - self.spans.clear(); - } - - fn check_block(&mut self, cx: &LateContext, block: &Block) { - if_let_chain!{[ - self.last.is_none(), - let Some(ref expr) = block.expr, - match_type(cx, cx.tcx.expr_ty(expr), &paths::REGEX), - let Some(span) = is_expn_of(cx, expr.span, "regex"), - ], { - if !self.spans.contains(&span) { - span_lint(cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); - self.spans.insert(span); - } - self.last = Some(block.id); - }} - } - - fn check_block_post(&mut self, _: &LateContext, block: &Block) { - if self.last.map_or(false, |id| block.id == id) { - self.last = None; - } - } - - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if_let_chain!{[ - let ExprCall(ref fun, ref args) = expr.node, - args.len() == 1, - let Some(def) = cx.tcx.def_map.borrow().get(&fun.id), - ], { - let def_id = def.def_id(); - if match_def_path(cx, def_id, &paths::REGEX_NEW) { - check_regex(cx, &args[0], true); - } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) { - check_regex(cx, &args[0], false); - } else if match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { - check_regex(cx, &args[0], true); - } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { - check_regex(cx, &args[0], false); - } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { - check_set(cx, &args[0], true); - } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { - check_set(cx, &args[0], false); - } - }} - } -} - -#[allow(cast_possible_truncation)] -fn str_span(base: Span, s: &str, c: usize) -> Span { - let mut si = s.char_indices().skip(c); - - match (si.next(), si.next()) { - (Some((l, _)), Some((h, _))) => { - Span { - lo: base.lo + BytePos(l as u32), - hi: base.lo + BytePos(h as u32), - ..base - } - } - _ => base, - } -} - -fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { - match eval_const_expr_partial(cx.tcx, e, ExprTypeChecked, None) { - Ok(ConstVal::Str(r)) => Some(r), - _ => None, - } -} - -fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { - use regex_syntax::Expr; - - match *s { - Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), - Expr::Literal { .. } => Some("consider using `str::contains`"), - Expr::Concat(ref exprs) => { - match exprs.len() { - 2 => { - match (&exprs[0], &exprs[1]) { - (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), - (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), - (&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]) { - Some("consider using `==` on `str`s") - } else { - None - } - } - _ => None, - } - } - _ => None, - } -} - -fn check_set(cx: &LateContext, expr: &Expr, utf8: bool) { - if_let_chain! {[ - let ExprAddrOf(_, ref expr) = expr.node, - let ExprVec(ref exprs) = expr.node, - ], { - for expr in exprs { - check_regex(cx, expr, utf8); - } - }} -} - -fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { - let builder = regex_syntax::ExprBuilder::new().unicode(utf8); - - if let ExprLit(ref lit) = expr.node { - if let LitKind::Str(ref r, _) = lit.node { - match builder.parse(r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, - "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())); - } - } - } - } else if let Some(r) = const_str(cx, expr) { - match builder.parse(&r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, - "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())); - } - } - } -} diff --git a/src/returns.rs b/src/returns.rs deleted file mode 100644 index d7893821263..00000000000 --- a/src/returns.rs +++ /dev/null @@ -1,137 +0,0 @@ -use rustc::lint::*; -use syntax::ast::*; -use syntax::codemap::{Span, Spanned}; -use syntax::visit::FnKind; - -use utils::{span_lint, span_lint_and_then, snippet_opt, match_path_ast, in_external_macro}; - -/// **What it does:** This lint checks for return statements at the end of a block. -/// -/// **Why is this bad?** Removing the `return` and semicolon will make the code more rusty. -/// -/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. -/// -/// **Example:** `fn foo(x: usize) { return x; }` -declare_lint! { - pub NEEDLESS_RETURN, Warn, - "using a return statement like `return expr;` where an expression would suffice" -} - -/// **What it does:** This lint checks for `let`-bindings, which are subsequently returned. -/// -/// **Why is this bad?** It is just extraneous code. Remove it to make your code more rusty. -/// -/// **Known problems:** Following this lint's advice may currently run afoul of Rust issue [#31439](https://github.com/rust-lang/rust/issues/31439), so if you get lifetime errors, please roll back the change until that issue is fixed. -/// -/// **Example:** `{ let x = ..; x }` -declare_lint! { - pub LET_AND_RETURN, Warn, - "creating a let-binding and then immediately returning it like `let x = expr; x` at \ - the end of a block" -} - -#[derive(Copy, Clone)] -pub struct ReturnPass; - -impl ReturnPass { - // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) { - if let Some(ref expr) = block.expr { - self.check_final_expr(cx, expr); - } else if let Some(stmt) = block.stmts.last() { - if let StmtKind::Semi(ref expr, _) = stmt.node { - if let ExprKind::Ret(Some(ref inner)) = expr.node { - self.emit_return_lint(cx, (stmt.span, inner.span)); - } - } - } - } - - // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &EarlyContext, expr: &Expr) { - match expr.node { - // simple return is always "bad" - ExprKind::Ret(Some(ref inner)) => { - self.emit_return_lint(cx, (expr.span, inner.span)); - } - // a whole block? check it! - 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 - ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { - self.check_block_return(cx, ifblock); - self.check_final_expr(cx, elsexpr); - } - // a match expr, check all arms - ExprKind::Match(_, ref arms) => { - for arm in arms { - self.check_final_expr(cx, &arm.body); - } - } - _ => (), - } - } - - fn emit_return_lint(&mut self, cx: &EarlyContext, spans: (Span, Span)) { - if in_external_macro(cx, spans.1) { - return; - } - span_lint_and_then(cx, NEEDLESS_RETURN, spans.0, "unneeded return statement", |db| { - if let Some(snippet) = snippet_opt(cx, spans.1) { - db.span_suggestion(spans.0, "remove `return` as shown:", snippet); - } - }); - } - - // Check for "let x = EXPR; x" - fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) { - // we need both a let-binding stmt and an expr - if_let_chain! { - [ - let Some(stmt) = block.stmts.last(), - let Some(ref retexpr) = block.expr, - let StmtKind::Decl(ref decl, _) = stmt.node, - let DeclKind::Local(ref local) = decl.node, - let Some(ref initexpr) = local.init, - let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node, - let ExprKind::Path(_, ref path) = retexpr.node, - match_path_ast(path, &[&id.name.as_str()]) - ], { - self.emit_let_lint(cx, retexpr.span, initexpr.span); - } - } - } - - fn emit_let_lint(&mut self, cx: &EarlyContext, lint_span: Span, note_span: Span) { - if in_external_macro(cx, note_span) { - return; - } - let mut db = span_lint(cx, - LET_AND_RETURN, - lint_span, - "returning the result of a let binding from a block. Consider returning the \ - expression directly."); - if cx.current_level(LET_AND_RETURN) != Level::Allow { - db.span_note(note_span, "this expression can be directly returned"); - } - } -} - -impl LintPass for ReturnPass { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RETURN, LET_AND_RETURN) - } -} - -impl EarlyLintPass for ReturnPass { - fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, _: &FnDecl, block: &Block, _: Span, _: NodeId) { - self.check_block_return(cx, block); - } - - fn check_block(&mut self, cx: &EarlyContext, block: &Block) { - self.check_let_return(cx, block); - } -} diff --git a/src/shadow.rs b/src/shadow.rs deleted file mode 100644 index 2a0d36a80b3..00000000000 --- a/src/shadow.rs +++ /dev/null @@ -1,353 +0,0 @@ -use reexport::*; -use rustc::lint::*; -use rustc::hir::def::Def; -use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, FnKind}; -use std::ops::Deref; -use syntax::codemap::Span; -use utils::{is_from_for_desugar, in_external_macro, snippet, span_lint, span_note_and_lint, DiagnosticWrapper}; - -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while just changing reference level or mutability. -/// -/// **Why is this bad?** Not much, in fact it's a very common pattern in Rust code. Still, some may opt to avoid it in their code base, they can set this lint to `Warn`. -/// -/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. -/// -/// **Example:** `let x = &x;` -declare_lint! { - pub SHADOW_SAME, Allow, - "rebinding a name to itself, e.g. `let mut x = &mut x`" -} - -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, while reusing the original value. -/// -/// **Why is this bad?** Not too much, in fact it's a common pattern in Rust code. Still, some argue that name shadowing like this hurts readability, because a value may be bound to different things depending on position in the code. -/// -/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. -/// -/// **Example:** `let x = x + 1;` -declare_lint! { - pub SHADOW_REUSE, Allow, - "rebinding a name to an expression that re-uses the original value, e.g. \ - `let x = x + 1`" -} - -/// **What it does:** This lint checks for bindings that shadow other bindings already in scope, either without a initialization or with one that does not even use the original value. -/// -/// **Why is this bad?** Name shadowing can hurt readability, especially in large code bases, because it is easy to lose track of the active binding at any place in the code. This can be alleviated by either giving more specific names to bindings ore introducing more scopes to contain the bindings. -/// -/// **Known problems:** This lint, as the other shadowing related lints, currently only catches very simple patterns. -/// -/// **Example:** `let x = y; let x = z; // shadows the earlier binding` -declare_lint! { - pub SHADOW_UNRELATED, Allow, - "The name is re-bound without even using the original value" -} - -#[derive(Copy, Clone)] -pub struct ShadowPass; - -impl LintPass for ShadowPass { - fn get_lints(&self) -> LintArray { - lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) - } -} - -impl LateLintPass for ShadowPass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, block: &Block, _: Span, _: NodeId) { - if in_external_macro(cx, block.span) { - return; - } - check_fn(cx, decl, block); - } -} - -fn check_fn(cx: &LateContext, decl: &FnDecl, block: &Block) { - let mut bindings = Vec::new(); - for arg in &decl.inputs { - if let PatKind::Ident(_, ident, _) = arg.pat.node { - bindings.push((ident.node.unhygienize(), ident.span)) - } - } - check_block(cx, block, &mut bindings); -} - -fn check_block(cx: &LateContext, block: &Block, bindings: &mut Vec<(Name, Span)>) { - let len = bindings.len(); - for stmt in &block.stmts { - match stmt.node { - StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), - StmtExpr(ref e, _) | - StmtSemi(ref e, _) => check_expr(cx, e, bindings), - } - } - if let Some(ref o) = block.expr { - check_expr(cx, o, bindings); - } - bindings.truncate(len); -} - -fn check_decl(cx: &LateContext, decl: &Decl, bindings: &mut Vec<(Name, Span)>) { - if in_external_macro(cx, decl.span) { - return; - } - if is_from_for_desugar(decl) { - return; - } - if let DeclLocal(ref local) = decl.node { - let Local { ref pat, ref ty, ref init, span, .. } = **local; - if let Some(ref t) = *ty { - check_ty(cx, t, bindings) - } - if let Some(ref o) = *init { - check_expr(cx, o, bindings); - check_pat(cx, pat, &Some(o), span, bindings); - } else { - 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, - _ => true, - } -} - -fn check_pat(cx: &LateContext, pat: &Pat, init: &Option<&Expr>, span: Span, bindings: &mut Vec<(Name, Span)>) { - // TODO: match more stuff / destructuring - match pat.node { - PatKind::Ident(_, ref ident, ref inner) => { - let name = ident.node.unhygienize(); - if is_binding(cx, pat) { - let mut new_binding = true; - for tup in bindings.iter_mut() { - if tup.0 == name { - lint_shadow(cx, name, span, pat.span, init, tup.1); - tup.1 = ident.span; - new_binding = false; - break; - } - } - if new_binding { - bindings.push((name, ident.span)); - } - } - if let Some(ref p) = *inner { - check_pat(cx, p, init, span, bindings); - } - } - // PatEnum(Path, Option<Vec<P<Pat>>>), - PatKind::Struct(_, ref pfields, _) => { - if let Some(ref 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(|ref f| f.name.node == name) - .map(|f| &*f.expr); - check_pat(cx, &field.node.pat, &efield, span, bindings); - } - } else { - for field in pfields { - check_pat(cx, &field.node.pat, init, span, bindings); - } - } - } else { - for field in pfields { - check_pat(cx, &field.node.pat, &None, span, bindings); - } - } - } - PatKind::Tup(ref inner) => { - if let Some(ref 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); - } - } else { - for p in inner { - check_pat(cx, p, init, span, bindings); - } - } - } else { - for p in inner { - check_pat(cx, p, &None, span, bindings); - } - } - } - PatKind::Box(ref inner) => { - if let Some(ref initp) = *init { - if let ExprBox(ref inner_init) = initp.node { - 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<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), - _ => (), - } -} - -fn lint_shadow<T>(cx: &LateContext, name: Name, span: Span, pattern_span: Span, init: &Option<T>, prev_span: Span) - where T: Deref<Target = Expr> -{ - fn note_orig(cx: &LateContext, mut db: DiagnosticWrapper, lint: &'static Lint, span: Span) { - if cx.current_level(lint) != Level::Allow { - db.span_note(span, "previous binding is here"); - } - } - if let Some(ref expr) = *init { - if is_self_shadow(name, expr) { - let db = span_lint(cx, - SHADOW_SAME, - span, - &format!("`{}` is shadowed by itself in `{}`", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, ".."))); - - note_orig(cx, db, SHADOW_SAME, prev_span); - } else if contains_self(name, expr) { - let db = span_note_and_lint(cx, - SHADOW_REUSE, - pattern_span, - &format!("`{}` is shadowed by `{}` which reuses the original value", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); - note_orig(cx, db, SHADOW_REUSE, prev_span); - } else { - let db = span_note_and_lint(cx, - SHADOW_UNRELATED, - pattern_span, - &format!("`{}` is shadowed by `{}`", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..")), - expr.span, - "initialization happens here"); - note_orig(cx, db, SHADOW_UNRELATED, prev_span); - } - - } else { - let db = span_lint(cx, - SHADOW_UNRELATED, - span, - &format!("{} shadows a previous declaration", snippet(cx, pattern_span, "_"))); - note_orig(cx, db, SHADOW_UNRELATED, prev_span); - } -} - -fn check_expr(cx: &LateContext, expr: &Expr, bindings: &mut Vec<(Name, Span)>) { - if in_external_macro(cx, expr.span) { - return; - } - match expr.node { - ExprUnary(_, ref e) | - ExprField(ref e, _) | - ExprTupField(ref e, _) | - ExprAddrOf(_, ref e) | - ExprBox(ref e) => check_expr(cx, e, bindings), - ExprBlock(ref block) | - ExprLoop(ref block, _) => check_block(cx, block, bindings), - // ExprCall - // ExprMethodCall - ExprVec(ref v) | ExprTup(ref v) => { - for ref 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 ref arm in arms { - for ref pat in &arm.pats { - 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); - } - check_expr(cx, &arm.body, bindings); - bindings.truncate(len); - } - } - } - _ => (), - } -} - -fn check_ty(cx: &LateContext, ty: &Ty, bindings: &mut Vec<(Name, Span)>) { - match ty.node { - TyObjectSum(ref sty, _) | - TyVec(ref sty) => check_ty(cx, sty, bindings), - TyFixedLengthVec(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 ref t in tup { - check_ty(cx, t, bindings) - } - } - TyTypeof(ref expr) => check_expr(cx, expr, bindings), - _ => (), - } -} - -fn is_self_shadow(name: Name, expr: &Expr) -> bool { - match expr.node { - ExprBox(ref inner) | - ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), - ExprBlock(ref block) => { - block.stmts.is_empty() && block.expr.as_ref().map_or(false, |ref 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), - _ => false, - } -} - -fn path_eq_name(name: Name, path: &Path) -> bool { - !path.global && path.segments.len() == 1 && path.segments[0].name.unhygienize() == name -} - -struct ContainsSelf { - name: Name, - result: bool, -} - -impl<'v> Visitor<'v> for ContainsSelf { - fn visit_name(&mut self, _: Span, name: Name) { - if self.name == name.unhygienize() { - self.result = true; - } - } -} - -fn contains_self(name: Name, expr: &Expr) -> bool { - let mut cs = ContainsSelf { - name: name, - result: false, - }; - cs.visit_expr(expr); - cs.result -} diff --git a/src/strings.rs b/src/strings.rs deleted file mode 100644 index 92bce8d0e42..00000000000 --- a/src/strings.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! This lint catches both string addition and string addition + assignment -//! -//! Note that since we have two lints where one subsumes the other, we try to -//! disable the subsumed lint unless it has a higher level - -use rustc::hir::*; -use rustc::lint::*; -use syntax::codemap::Spanned; -use utils::SpanlessEq; -use utils::{match_type, paths, span_lint, span_lint_and_then, walk_ptrs_ty, get_parent_expr}; - -/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!). -/// -/// **Why is this bad?** It's not really bad, but some people think that the `.push_str(_)` method is more readable. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// -/// ``` -/// let mut x = "Hello".to_owned(); -/// x = x + ", World"; -/// ``` -declare_lint! { - pub STRING_ADD_ASSIGN, - Allow, - "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead" -} - -/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match. -/// -/// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code. -/// -/// That said, other people think that String addition, having a long tradition in other languages is actually fine, which is why we decided to make this particular lint `allow` by default. -/// -/// **Known problems:** None -/// -/// **Example:** -/// -/// ``` -/// let x = "Hello".to_owned(); -/// x + ", World" -/// ``` -declare_lint! { - pub STRING_ADD, - Allow, - "using `x + ..` where x is a `String`; suggests using `push_str()` instead" -} - -/// **What it does:** This lint matches the `as_bytes` method called on string -/// literals that contain only ascii characters. -/// -/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`. -/// -/// **Example:** -/// -/// ``` -/// let bs = "a byte string".as_bytes(); -/// ``` -declare_lint! { - pub STRING_LIT_AS_BYTES, - Warn, - "calling `as_bytes` on a string literal; suggests using a byte string literal instead" -} - -#[derive(Copy, Clone)] -pub struct StringAdd; - -impl LintPass for StringAdd { - fn get_lints(&self) -> LintArray { - lint_array!(STRING_ADD, STRING_ADD_ASSIGN) - } -} - -impl LateLintPass for StringAdd { - fn check_expr(&mut self, cx: &LateContext, e: &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) { - // the string_add_assign is allow, so no duplicates - } else { - let parent = get_parent_expr(cx, e); - if let Some(ref p) = parent { - if let ExprAssign(ref target, _) = p.node { - // avoid duplicate matches - if SpanlessEq::new(cx).eq_expr(target, left) { - return; - } - } - } - } - span_lint(cx, - STRING_ADD, - e.span, - "you added something to a string. Consider using `String::push_str()` instead"); - } - } else if let ExprAssign(ref target, ref src) = e.node { - if is_string(cx, target) && is_add(cx, src, target) { - span_lint(cx, - STRING_ADD_ASSIGN, - e.span, - "you assigned the result of adding something to this string. Consider using \ - `String::push_str()` instead"); - } - } - } -} - -fn is_string(cx: &LateContext, e: &Expr) -> bool { - match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &paths::STRING) -} - -fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { - match src.node { - 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, - } -} - -#[derive(Copy, Clone)] -pub struct StringLitAsBytes; - -impl LintPass for StringLitAsBytes { - fn get_lints(&self) -> LintArray { - lint_array!(STRING_LIT_AS_BYTES) - } -} - -impl LateLintPass for StringLitAsBytes { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - use std::ascii::AsciiExt; - use syntax::ast::LitKind; - use utils::{snippet, in_macro}; - - if let ExprMethodCall(ref name, _, ref args) = e.node { - if name.node.as_str() == "as_bytes" { - if let ExprLit(ref lit) = args[0].node { - if let LitKind::Str(ref lit_content, _) = lit.node { - if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, args[0].span) { - span_lint_and_then(cx, - STRING_LIT_AS_BYTES, - 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); - }); - - } - } - } - } - } - } -} diff --git a/src/swap.rs b/src/swap.rs deleted file mode 100644 index c5572181395..00000000000 --- a/src/swap.rs +++ /dev/null @@ -1,138 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use syntax::codemap::mk_sp; -use utils::{differing_macro_contexts, snippet_opt, span_lint_and_then, SpanlessEq}; - -/// **What it does:** This lints manual swapping. -/// -/// **Why is this bad?** The `std::mem::swap` function exposes the intent better without -/// deinitializing or copying either variable. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// let t = b; -/// b = a; -/// a = t; -/// ``` -declare_lint! { - pub MANUAL_SWAP, - Warn, - "manual swap" -} - -/// **What it does:** This lints `foo = bar; bar = foo` sequences. -/// -/// **Why is this bad?** This looks like a failed attempt to swap. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// a = b; -/// b = a; -/// ``` -declare_lint! { - pub ALMOST_SWAPPED, - Warn, - "`foo = bar; bar = foo` sequence" -} - -#[derive(Copy,Clone)] -pub struct Swap; - -impl LintPass for Swap { - fn get_lints(&self) -> LintArray { - lint_array![MANUAL_SWAP, ALMOST_SWAPPED] - } -} - -impl LateLintPass for Swap { - fn check_block(&mut self, cx: &LateContext, block: &Block) { - check_manual_swap(cx, block); - check_suspicious_swap(cx, block); - } -} - -/// Implementation of the `MANUAL_SWAP` lint. -fn check_manual_swap(cx: &LateContext, block: &Block) { - for w in block.stmts.windows(3) { - if_let_chain!{[ - // let t = foo(); - let StmtDecl(ref tmp, _) = w[0].node, - let DeclLocal(ref tmp) = tmp.node, - let Some(ref tmp_init) = tmp.init, - let PatKind::Ident(_, ref tmp_name, None) = tmp.pat.node, - - // foo() = bar(); - let StmtSemi(ref first, _) = w[1].node, - let ExprAssign(ref lhs1, ref rhs1) = first.node, - - // bar() = t; - let StmtSemi(ref second, _) = w[2].node, - let ExprAssign(ref lhs2, ref rhs2) = second.node, - let ExprPath(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) - ], { - let (what, lhs, rhs) = if let (Some(first), Some(second)) = (snippet_opt(cx, lhs1.span), snippet_opt(cx, rhs1.span)) { - (format!(" `{}` and `{}`", first, second), first, second) - } else { - ("".to_owned(), "".to_owned(), "".to_owned()) - }; - - let span = mk_sp(tmp.span.lo, second.span.hi); - - span_lint_and_then(cx, - MANUAL_SWAP, - span, - &format!("this looks like you are swapping{} manually", what), - |db| { - if !what.is_empty() { - db.span_suggestion(span, "try", - format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); - db.note("or maybe you should use `std::mem::replace`?"); - } - }); - }} - } -} - -/// Implementation of the `ALMOST_SWAPPED` lint. -fn check_suspicious_swap(cx: &LateContext, block: &Block) { - for w in block.stmts.windows(2) { - if_let_chain!{[ - let StmtSemi(ref first, _) = w[0].node, - let StmtSemi(ref second, _) = w[1].node, - !differing_macro_contexts(first.span, second.span), - let ExprAssign(ref lhs0, ref rhs0) = first.node, - let ExprAssign(ref lhs1, ref rhs1) = second.node, - 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)) = (snippet_opt(cx, lhs0.span), snippet_opt(cx, rhs0.span)) { - (format!(" `{}` and `{}`", first, second), first, second) - } else { - ("".to_owned(), "".to_owned(), "".to_owned()) - }; - - let span = mk_sp(first.span.lo, second.span.hi); - - span_lint_and_then(cx, - ALMOST_SWAPPED, - span, - &format!("this looks like you are trying to swap{}", what), - |db| { - if !what.is_empty() { - db.span_suggestion(span, "try", - format!("std::mem::swap(&mut {}, &mut {})", lhs, rhs)); - db.note("or maybe you should use `std::mem::replace`?"); - } - }); - }} - } -} diff --git a/src/temporary_assignment.rs b/src/temporary_assignment.rs deleted file mode 100644 index 1496a45dac2..00000000000 --- a/src/temporary_assignment.rs +++ /dev/null @@ -1,49 +0,0 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::hir::{Expr, ExprAssign, ExprField, ExprStruct, ExprTup, ExprTupField}; -use utils::is_adjusted; -use utils::span_lint; - -/// **What it does:** This lint checks for construction of a structure or tuple just to assign a value in it. -/// -/// **Why is this bad?** Readability. If the structure is only created to be updated, why not write the structure you want in the first place? -/// -/// **Known problems:** None. -/// -/// **Example:** `(0, 0).0 = 1` -declare_lint! { - pub TEMPORARY_ASSIGNMENT, - Warn, - "assignments to temporaries" -} - -fn is_temporary(expr: &Expr) -> bool { - match expr.node { - ExprStruct(..) | ExprTup(..) => true, - _ => false, - } -} - -#[derive(Copy, Clone)] -pub struct TemporaryAssignmentPass; - -impl LintPass for TemporaryAssignmentPass { - fn get_lints(&self) -> LintArray { - lint_array!(TEMPORARY_ASSIGNMENT) - } -} - -impl LateLintPass for TemporaryAssignmentPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprAssign(ref target, _) = expr.node { - match target.node { - ExprField(ref base, _) | - ExprTupField(ref base, _) => { - if is_temporary(base) && !is_adjusted(cx, base) { - span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); - } - } - _ => (), - } - } - } -} diff --git a/src/transmute.rs b/src/transmute.rs deleted file mode 100644 index 2217fd59bd9..00000000000 --- a/src/transmute.rs +++ /dev/null @@ -1,131 +0,0 @@ -use rustc::lint::*; -use rustc::ty::TypeVariants::{TyRawPtr, TyRef}; -use rustc::ty; -use rustc::hir::*; -use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; - -/// **What it does:** This lint checks for transmutes to the original type of the object. -/// -/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type. -/// -/// **Known problems:** None. -/// -/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s. -declare_lint! { - pub USELESS_TRANSMUTE, - Warn, - "transmutes that have the same to and from types" -} - -/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`. -/// -/// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type. -/// -/// **Known problems:** None. -/// -/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `*t` or `&t`'s. -declare_lint! { - pub CROSSPOINTER_TRANSMUTE, - Warn, - "transmutes that have to or from types that are a pointer to the other" -} - -/// **What it does:*** This lint checks for transmutes from a pointer to a reference. -/// -/// **Why is this bad?** This can always be rewritten with `&` and `*`. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust -/// let _: &T = std::mem::transmute(p); // where p: *const T -/// // can be written: -/// let _: &T = &*p; -/// ``` -declare_lint! { - pub TRANSMUTE_PTR_TO_REF, - Warn, - "transmutes from a pointer to a reference type" -} - -pub struct Transmute; - -impl LintPass for Transmute { - fn get_lints(&self) -> LintArray { - lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE] - } -} - -impl LateLintPass for Transmute { - fn check_expr(&mut self, cx: &LateContext, e: &Expr) { - if let ExprCall(ref path_expr, ref args) = e.node { - if let ExprPath(None, _) = path_expr.node { - let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id(); - - if match_def_path(cx, def_id, &paths::TRANSMUTE) { - let from_ty = cx.tcx.expr_ty(&args[0]); - let to_ty = cx.tcx.expr_ty(e); - - if from_ty == to_ty { - span_lint(cx, - USELESS_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to itself", from_ty)); - } else if is_ptr_to(to_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)); - } else if is_ptr_to(from_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)); - } else { - check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]); - } - } - } - } - } -} - -fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool { - if let TyRawPtr(from_ptr) = from.sty { - from_ptr.ty == to - } else { - false - } -} - -fn check_ptr_to_ref<'tcx>(cx: &LateContext, from_ty: ty::Ty<'tcx>, to_ty: ty::Ty<'tcx>, e: &Expr, arg: &Expr) { - if let TyRawPtr(ref from_pty) = from_ty.sty { - if let TyRef(_, ref to_rty) = to_ty.sty { - let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)", - from_ty, - to_ty); - span_lint_and_then(cx, TRANSMUTE_PTR_TO_REF, e.span, &mess, |db| { - if let Some(arg) = snippet_opt(cx, arg.span) { - let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable { - ("&mut *", "*mut") - } else { - ("&*", "*const") - }; - - - let sugg = if from_pty.ty == to_rty.ty { - format!("{}{}", deref, arg) - } else { - format!("{}({} as {} {})", deref, arg, cast, to_rty.ty) - }; - - db.span_suggestion(e.span, "try", sugg); - } - }); - } - } -} diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index c4b810a7880..00000000000 --- a/src/types.rs +++ /dev/null @@ -1,974 +0,0 @@ -use reexport::*; -use rustc::hir::*; -use rustc::hir::intravisit::{FnKind, Visitor, walk_ty}; -use rustc::lint::*; -use rustc::ty; -use std::cmp::Ordering; -use syntax::ast::{IntTy, UintTy, FloatTy}; -use syntax::codemap::Span; -use utils::{comparisons, in_external_macro, in_macro, is_from_for_desugar, match_def_path, snippet, - span_help_and_lint, span_lint}; -use utils::paths; - -/// Handles all the linting of funky types -#[allow(missing_copy_implementations)] -pub struct TypePass; - -/// **What it does:** This lint checks for use of `Box<Vec<_>>` anywhere in the code. -/// -/// **Why is this bad?** `Vec` already keeps its contents in a separate area on the heap. So if you `Box` it, you just add another level of indirection without any benefit whatsoever. -/// -/// **Known problems:** None -/// -/// **Example:** `struct X { values: Box<Vec<Foo>> }` -declare_lint! { - pub BOX_VEC, Warn, - "usage of `Box<Vec<T>>`, vector elements are already on the heap" -} - -/// **What it does:** This lint checks for usage of any `LinkedList`, suggesting to use a `Vec` or a `VecDeque` (formerly called `RingBuf`). -/// -/// **Why is this bad?** Gankro says: -/// -/// >The TL;DR of `LinkedList` is that it's built on a massive amount of pointers and indirection. It wastes memory, it has terrible cache locality, and is all-around slow. `RingBuf`, while "only" amortized for push/pop, should be faster in the general case for almost every possible workload, and isn't even amortized at all if you can predict the capacity you need. -/// > -/// > `LinkedList`s are only really good if you're doing a lot of merging or splitting of lists. This is because they can just mangle some pointers instead of actually copying the data. Even if you're doing a lot of insertion in the middle of the list, `RingBuf` can still be better because of how expensive it is to seek to the middle of a `LinkedList`. -/// -/// **Known problems:** False positives – the instances where using a `LinkedList` makes sense are few and far between, but they can still happen. -/// -/// **Example:** `let x = LinkedList::new();` -declare_lint! { - pub LINKEDLIST, Warn, - "usage of LinkedList, usually a vector is faster, or a more specialized data \ - structure like a VecDeque" -} - -impl LintPass for TypePass { - fn get_lints(&self) -> LintArray { - lint_array!(BOX_VEC, LINKEDLIST) - } -} - -impl LateLintPass for TypePass { - fn check_ty(&mut self, cx: &LateContext, ast_ty: &Ty) { - if in_macro(cx, ast_ty.span) { - return; - } - if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) { - if let def::Def::Struct(..) = did.full_def() { - if Some(did.def_id()) == cx.tcx.lang_items.owned_box() { - 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.def_id(), &paths::VEC), - ], - { - span_help_and_lint(cx, - BOX_VEC, - ast_ty.span, - "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", - "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); - } - } - } else if match_def_path(cx, did.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"); - } - } - } - } -} - -#[allow(missing_copy_implementations)] -pub struct LetPass; - -/// **What it does:** This lint checks for binding a unit value. -/// -/// **Why is this bad?** A unit value cannot usefully be used anywhere. So binding one is kind of pointless. -/// -/// **Known problems:** None -/// -/// **Example:** `let x = { 1; };` -declare_lint! { - pub LET_UNIT_VALUE, Warn, - "creating a let binding to a value of unit type, which usually can't be used afterwards" -} - -fn check_let_unit(cx: &LateContext, decl: &Decl) { - if let DeclLocal(ref local) = decl.node { - let bindtype = &cx.tcx.pat_ty(&local.pat).sty; - if *bindtype == ty::TyTuple(&[]) { - if in_external_macro(cx, decl.span) || in_macro(cx, local.pat.span) { - return; - } - if is_from_for_desugar(decl) { - return; - } - span_lint(cx, - LET_UNIT_VALUE, - decl.span, - &format!("this let-binding has unit value. Consider omitting `let {} =`", - snippet(cx, local.pat.span, ".."))); - } - } -} - -impl LintPass for LetPass { - fn get_lints(&self) -> LintArray { - lint_array!(LET_UNIT_VALUE) - } -} - -impl LateLintPass for LetPass { - fn check_decl(&mut self, cx: &LateContext, decl: &Decl) { - check_let_unit(cx, decl) - } -} - -/// **What it does:** This lint checks for comparisons to unit. -/// -/// **Why is this bad?** Unit is always equal to itself, and thus is just a clumsily written constant. Mostly this happens when someone accidentally adds semicolons at the end of the operands. -/// -/// **Known problems:** None -/// -/// **Example:** `if { foo(); } == { bar(); } { baz(); }` is equal to `{ foo(); bar(); baz(); }` -declare_lint! { - pub UNIT_CMP, Warn, - "comparing unit values (which is always `true` or `false`, respectively)" -} - -#[allow(missing_copy_implementations)] -pub struct UnitCmp; - -impl LintPass for UnitCmp { - fn get_lints(&self) -> LintArray { - lint_array!(UNIT_CMP) - } -} - -impl LateLintPass for UnitCmp { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if in_macro(cx, expr.span) { - return; - } - if let ExprBinary(ref cmp, ref left, _) = expr.node { - let op = cmp.node; - let sty = &cx.tcx.expr_ty(left).sty; - if *sty == ty::TyTuple(&[]) && op.is_comparison() { - let result = match op { - BiEq | BiLe | BiGe => "true", - _ => "false", - }; - span_lint(cx, - UNIT_CMP, - expr.span, - &format!("{}-comparison of unit values detected. This will always be {}", - op.as_str(), - result)); - } - } - } -} - -pub struct CastPass; - -/// **What it does:** This lint checks for casts from any numerical to a float type where the receiving type cannot store all values from the original type without rounding errors. This possible rounding is to be expected, so this lint is `Allow` by default. -/// -/// Basically, this warns on casting any integer with 32 or more bits to `f32` or any 64-bit integer to `f64`. -/// -/// **Why is this bad?** It's not bad at all. But in some applications it can be helpful to know where precision loss can take place. This lint can help find those places in the code. -/// -/// **Known problems:** None -/// -/// **Example:** `let x = u64::MAX; x as f64` -declare_lint! { - pub CAST_PRECISION_LOSS, Allow, - "casts that cause loss of precision, e.g `x as f32` where `x: u64`" -} - -/// **What it does:** This lint checks for casts from a signed to an unsigned numerical type. In this case, negative values wrap around to large positive values, which can be quite surprising in practice. However, as the cast works as defined, this lint is `Allow` by default. -/// -/// **Why is this bad?** Possibly surprising results. You can activate this lint as a one-time check to see where numerical wrapping can arise. -/// -/// **Known problems:** None -/// -/// **Example:** `let y : i8 = -1; y as u64` will return 18446744073709551615 -declare_lint! { - pub CAST_SIGN_LOSS, Allow, - "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`" -} - -/// **What it does:** This lint checks for on casts between numerical types that may truncate large values. This is expected behavior, so the cast is `Allow` by default. -/// -/// **Why is this bad?** In some problem domains, it is good practice to avoid truncation. This lint can be activated to help assess where additional checks could be beneficial. -/// -/// **Known problems:** None -/// -/// **Example:** `fn as_u8(x: u64) -> u8 { x as u8 }` -declare_lint! { - pub CAST_POSSIBLE_TRUNCATION, Allow, - "casts that may cause truncation of the value, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`" -} - -/// **What it does:** This lint checks for casts from an unsigned type to a signed type of the same size. Performing such a cast is a 'no-op' for the compiler, i.e. nothing is changed at the bit level, and the binary representation of the value is reinterpreted. This can cause wrapping if the value is too big for the target signed type. However, the cast works as defined, so this lint is `Allow` by default. -/// -/// **Why is this bad?** While such a cast is not bad in itself, the results can be surprising when this is not the intended behavior, as demonstrated by the example below. -/// -/// **Known problems:** None -/// -/// **Example:** `u32::MAX as i32` will yield a value of `-1`. -declare_lint! { - pub CAST_POSSIBLE_WRAP, Allow, - "casts that may cause wrapping around the value, e.g `x as i32` where `x: u32` and `x > i32::MAX`" -} - -/// Returns the size in bits of an integral type. -/// Will return 0 if the type is not an int or uint variant -fn int_ty_to_nbits(typ: &ty::TyS) -> usize { - let n = match typ.sty { - ty::TyInt(i) => 4 << (i as usize), - ty::TyUint(u) => 4 << (u as usize), - _ => 0, - }; - // n == 4 is the usize/isize case - if n == 4 { - ::std::mem::size_of::<usize>() * 8 - } else { - n - } -} - -fn is_isize_or_usize(typ: &ty::TyS) -> bool { - match typ.sty { - ty::TyInt(IntTy::Is) | - ty::TyUint(UintTy::Us) => true, - _ => false, - } -} - -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 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 { - "64".to_owned() - } else if is_isize_or_usize(cast_from) { - "32 or 64".to_owned() - } else { - int_ty_to_nbits(cast_from).to_string() - }; - span_lint(cx, - CAST_PRECISION_LOSS, - expr.span, - &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 arch_dependent { - arch_dependent_str - } else { - "" - }, - from_nbits_str, - mantissa_nbits)); -} - -enum ArchSuffix { - _32, - _64, - None, -} - -fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to: &ty::TyS) { - let arch_64_suffix = " on targets with 64-bit wide pointers"; - let arch_32_suffix = " on targets with 32-bit wide pointers"; - let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); - let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to)); - let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), - is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => { - (to_nbits < from_nbits, - 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 - }, - 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 - }) - } - }; - if span_truncation { - span_lint(cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - &format!("casting {} to {} may truncate the value{}", - cast_from, - cast_to, - match suffix_truncation { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "", - })); - } - if span_wrap { - span_lint(cx, - CAST_POSSIBLE_WRAP, - expr.span, - &format!("casting {} to {} may wrap around the value{}", - cast_from, - cast_to, - match suffix_wrap { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "", - })); - } -} - -impl LintPass for CastPass { - fn get_lints(&self) -> LintArray { - lint_array!(CAST_PRECISION_LOSS, - CAST_SIGN_LOSS, - CAST_POSSIBLE_TRUNCATION, - CAST_POSSIBLE_WRAP) - } -} - -impl LateLintPass for CastPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprCast(ref ex, _) = expr.node { - let (cast_from, cast_to) = (cx.tcx.expr_ty(ex), cx.tcx.expr_ty(expr)); - if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) { - match (cast_from.is_integral(), cast_to.is_integral()) { - (true, false) => { - let from_nbits = int_ty_to_nbits(cast_from); - let to_nbits = if let ty::TyFloat(FloatTy::F32) = cast_to.sty { - 32 - } else { - 64 - }; - 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, - expr.span, - &format!("casting {} to {} may truncate the value", cast_from, cast_to)); - if !cast_to.is_signed() { - span_lint(cx, - CAST_SIGN_LOSS, - 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, - CAST_SIGN_LOSS, - expr.span, - &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) { - span_lint(cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - "casting f64 to f32 may truncate the value"); - } - } - } - } - } - } -} - -/// **What it does:** This lint checks for types used in structs, parameters and `let` declarations above a certain complexity threshold. -/// -/// **Why is this bad?** Too complex types make the code less readable. Consider using a `type` definition to simplify them. -/// -/// **Known problems:** None -/// -/// **Example:** `struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }` -declare_lint! { - pub TYPE_COMPLEXITY, Warn, - "usage of very complex types; recommends factoring out parts into `type` definitions" -} - -#[allow(missing_copy_implementations)] -pub struct TypeComplexityPass { - threshold: u64, -} - -impl TypeComplexityPass { - pub fn new(threshold: u64) -> Self { - TypeComplexityPass { threshold: threshold } - } -} - -impl LintPass for TypeComplexityPass { - fn get_lints(&self) -> LintArray { - lint_array!(TYPE_COMPLEXITY) - } -} - -impl LateLintPass for TypeComplexityPass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { - self.check_fndecl(cx, decl); - } - - fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { - // enum variants are also struct fields now - self.check_type(cx, &field.ty); - } - - fn check_item(&mut self, cx: &LateContext, item: &Item) { - match item.node { - ItemStatic(ref ty, _, _) | - ItemConst(ref ty, _) => self.check_type(cx, ty), - // functions, enums, structs, impls and traits are covered - _ => (), - } - } - - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { - match item.node { - ConstTraitItem(ref ty, _) | - TypeTraitItem(_, Some(ref ty)) => self.check_type(cx, ty), - MethodTraitItem(MethodSig { ref decl, .. }, None) => self.check_fndecl(cx, decl), - // methods with default impl are covered by check_fn - _ => (), - } - } - - fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { - match item.node { - ImplItemKind::Const(ref ty, _) | - ImplItemKind::Type(ref ty) => self.check_type(cx, ty), - // methods are covered by check_fn - _ => (), - } - } - - fn check_local(&mut self, cx: &LateContext, local: &Local) { - if let Some(ref ty) = local.ty { - self.check_type(cx, ty); - } - } -} - -impl TypeComplexityPass { - fn check_fndecl(&self, cx: &LateContext, decl: &FnDecl) { - for arg in &decl.inputs { - self.check_type(cx, &arg.ty); - } - if let Return(ref ty) = decl.output { - self.check_type(cx, ty); - } - } - - fn check_type(&self, cx: &LateContext, ty: &Ty) { - if in_macro(cx, ty.span) { - return; - } - let score = { - let mut visitor = TypeComplexityVisitor { - score: 0, - nest: 1, - }; - visitor.visit_ty(ty); - visitor.score - }; - - if score > self.threshold { - span_lint(cx, - TYPE_COMPLEXITY, - ty.span, - "very complex type used. Consider factoring parts into `type` definitions"); - } - } -} - -/// Walks a type and assigns a complexity score to it. -struct TypeComplexityVisitor { - /// total complexity score of the type - score: u64, - /// current nesting level - nest: u64, -} - -impl<'v> Visitor<'v> for TypeComplexityVisitor { - fn visit_ty(&mut self, ty: &'v 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(..) | - TyVec(..) | - TyTup(..) | - TyFixedLengthVec(..) => (10 * self.nest, 1), - - // "Sum" of trait bounds - TyObjectSum(..) => (20 * self.nest, 0), - - // function types and "for<...>" bring a lot of overhead - TyBareFn(..) | - TyPolyTraitRef(..) => (50 * self.nest, 1), - - _ => (0, 0), - }; - self.score += add_score; - self.nest += sub_nest; - walk_ty(self, ty); - self.nest -= sub_nest; - } -} - -/// **What it does:** This lint points out expressions where a character literal is casted to `u8` and suggests using a byte literal instead. -/// -/// **Why is this bad?** In general, casting values to smaller types is error-prone and should be avoided where possible. In the particular case of converting a character literal to u8, it is easy to avoid by just using a byte literal instead. As an added bonus, `b'a'` is even slightly shorter than `'a' as u8`. -/// -/// **Known problems:** None -/// -/// **Example:** `'x' as u8` -declare_lint! { - pub CHAR_LIT_AS_U8, Warn, - "Casting a character literal to u8" -} - -pub struct CharLitAsU8; - -impl LintPass for CharLitAsU8 { - fn get_lints(&self) -> LintArray { - lint_array!(CHAR_LIT_AS_U8) - } -} - -impl LateLintPass for CharLitAsU8 { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - use syntax::ast::{LitKind, UintTy}; - - if let ExprCast(ref e, _) = expr.node { - if let ExprLit(ref l) = e.node { - if let LitKind::Char(_) = l.node { - if ty::TyUint(UintTy::U8) == cx.tcx.expr_ty(expr).sty && !in_macro(cx, expr.span) { - 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'")); - span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); - } - } - } - } - } -} - -/// **What it does:** This lint checks for comparisons where one side of the relation is either the minimum or maximum value for its type and warns if it involves a case that is always true or always false. Only integer and boolean types are checked. -/// -/// **Why is this bad?** An expression like `min <= x` may misleadingly imply that is is possible for `x` to be less than the minimum. Expressions like `max < x` are probably mistakes. -/// -/// **Known problems:** None -/// -/// **Example:** `vec.len() <= 0`, `100 > std::i32::MAX` -declare_lint! { - pub ABSURD_EXTREME_COMPARISONS, Warn, - "a comparison involving a maximum or minimum value involves a case that is always \ - true or always false" -} - -pub struct AbsurdExtremeComparisons; - -impl LintPass for AbsurdExtremeComparisons { - fn get_lints(&self) -> LintArray { - lint_array!(ABSURD_EXTREME_COMPARISONS) - } -} - -enum ExtremeType { - Minimum, - Maximum, -} - -struct ExtremeExpr<'a> { - which: ExtremeType, - expr: &'a Expr, -} - -enum AbsurdComparisonResult { - AlwaysFalse, - AlwaysTrue, - InequalityImpossible, -} - - - -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 { - val - } else { - return None; - }; - - let lx = detect_extreme_expr(cx, normalized_lhs); - let rx = detect_extreme_expr(cx, normalized_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 - _ => 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 - _ => return None, - } - } - Rel::Ne | Rel::Eq => return None, - }) -} - -fn detect_extreme_expr<'a>(cx: &LateContext, expr: &'a Expr) -> Option<ExtremeExpr<'a>> { - use rustc::middle::const_val::ConstVal::*; - use rustc_const_math::*; - use rustc_const_eval::EvalHint::ExprTypeChecked; - use rustc_const_eval::*; - use types::ExtremeType::*; - - let ty = &cx.tcx.expr_ty(expr).sty; - - match *ty { - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) => (), - _ => return None, - }; - - let cv = match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { - Ok(val) => val, - Err(_) => return None, - }; - - let which = match (ty, cv) { - (&ty::TyBool, Bool(false)) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MIN)))) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MIN)))) | - (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MIN))) | - (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MIN))) | - (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MIN))) | - (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MIN))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MIN)))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MIN)))) | - (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MIN))) | - (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MIN))) | - (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MIN))) | - (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MIN))) => Minimum, - - (&ty::TyBool, Bool(true)) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is32(::std::i32::MAX)))) | - (&ty::TyInt(IntTy::Is), Integral(Isize(Is64(::std::i64::MAX)))) | - (&ty::TyInt(IntTy::I8), Integral(I8(::std::i8::MAX))) | - (&ty::TyInt(IntTy::I16), Integral(I16(::std::i16::MAX))) | - (&ty::TyInt(IntTy::I32), Integral(I32(::std::i32::MAX))) | - (&ty::TyInt(IntTy::I64), Integral(I64(::std::i64::MAX))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us32(::std::u32::MAX)))) | - (&ty::TyUint(UintTy::Us), Integral(Usize(Us64(::std::u64::MAX)))) | - (&ty::TyUint(UintTy::U8), Integral(U8(::std::u8::MAX))) | - (&ty::TyUint(UintTy::U16), Integral(U16(::std::u16::MAX))) | - (&ty::TyUint(UintTy::U32), Integral(U32(::std::u32::MAX))) | - (&ty::TyUint(UintTy::U64), Integral(U64(::std::u64::MAX))) => Maximum, - - _ => return None, - }; - Some(ExtremeExpr { - which: which, - expr: expr, - }) -} - -impl LateLintPass for AbsurdExtremeComparisons { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - use types::ExtremeType::*; - use types::AbsurdComparisonResult::*; - - if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { - if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { - if !in_macro(cx, expr.span) { - let msg = "this comparison involving the minimum or maximum element for this \ - type contains a case that is always true or always false"; - - let conclusion = match result { - AlwaysFalse => "this comparison is always false".to_owned(), - AlwaysTrue => "this comparison is always true".to_owned(), - InequalityImpossible => { - format!("the case where the two sides are not equal never occurs, consider using {} == {} \ - instead", - snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs")) - } - }; - - let help = format!("because {} is the {} value for this type, {}", - snippet(cx, culprit.expr.span, "x"), - match culprit.which { - Minimum => "minimum", - Maximum => "maximum", - }, - conclusion); - - span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); - } - } - } - } -} - -/// **What it does:** This lint checks for comparisons where the relation is always either true or false, but where one side has been upcast so that the comparison is necessary. Only integer types are checked. -/// -/// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300` will mistakenly imply that it is possible for `x` to be outside the range of `u8`. -/// -/// **Known problems:** https://github.com/Manishearth/rust-clippy/issues/886 -/// -/// **Example:** `let x : u8 = ...; (x as u32) > 300` -declare_lint! { - pub INVALID_UPCAST_COMPARISONS, Allow, - "a comparison involving an upcast which is always true or false" -} - -pub struct InvalidUpcastComparisons; - -impl LintPass for InvalidUpcastComparisons { - fn get_lints(&self) -> LintArray { - lint_array!(INVALID_UPCAST_COMPARISONS) - } -} - -#[derive(Copy, Clone, Debug, Eq)] -enum FullInt { - S(i64), - U(u64), -} - -impl FullInt { - #[allow(cast_sign_loss)] - fn cmp_s_u(s: i64, u: u64) -> Ordering { - if s < 0 { - Ordering::Less - } else if u > (i64::max_value() as u64) { - Ordering::Greater - } else { - (s as u64).cmp(&u) - } - } -} - -impl PartialEq for FullInt { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal - } -} - -impl PartialOrd for FullInt { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(match (self, other) { - (&FullInt::S(s), &FullInt::S(o)) => s.cmp(&o), - (&FullInt::U(s), &FullInt::U(o)) => s.cmp(&o), - (&FullInt::S(s), &FullInt::U(o)) => Self::cmp_s_u(s, o), - (&FullInt::U(s), &FullInt::S(o)) => Self::cmp_s_u(o, s).reverse(), - }) - } -} -impl Ord for FullInt { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).expect("partial_cmp for FullInt can never return None") - } -} - - -fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { - use rustc::ty::TypeVariants::{TyInt, TyUint}; - use syntax::ast::{IntTy, UintTy}; - use std::*; - - if let ExprCast(ref cast_exp, _) = expr.node { - match cx.tcx.expr_ty(cast_exp).sty { - TyInt(int_ty) => { - Some(match int_ty { - IntTy::I8 => (FullInt::S(i8::min_value() as i64), FullInt::S(i8::max_value() as i64)), - IntTy::I16 => (FullInt::S(i16::min_value() as i64), FullInt::S(i16::max_value() as i64)), - IntTy::I32 => (FullInt::S(i32::min_value() as i64), FullInt::S(i32::max_value() as i64)), - 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)), - UintTy::U16 => (FullInt::U(u16::min_value() as u64), FullInt::U(u16::max_value() as u64)), - UintTy::U32 => (FullInt::U(u32::min_value() as u64), FullInt::U(u32::max_value() as u64)), - 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 { - None - } -} - -fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { - use rustc::middle::const_val::ConstVal::*; - use rustc_const_eval::EvalHint::ExprTypeChecked; - use rustc_const_eval::eval_const_expr_partial; - use rustc_const_math::ConstInt; - - match eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None) { - Ok(val) => { - if let Integral(const_int) = val { - Some(match const_int.erase_type() { - ConstInt::InferSigned(x) => FullInt::S(x as i64), - ConstInt::Infer(x) => FullInt::U(x as u64), - _ => unreachable!(), - }) - } else { - None - } - } - Err(_) => None, - } -} - -fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) { - if let ExprCast(ref cast_val, _) = expr.node { - span_lint(cx, - INVALID_UPCAST_COMPARISONS, - *span, - &format!( - "because of the numeric bounds on `{}` prior to casting, this expression is always {}", - snippet(cx, cast_val.span, "the expression"), - if always { "true" } else { "false" }, - )); - } -} - -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 { - if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { - if rel == Rel::Eq || rel == Rel::Ne { - if norm_rhs_val < lb || norm_rhs_val > ub { - err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); - } - } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val < lb - } 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) - } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val >= ub - } 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) - } - } - } -} - -impl LateLintPass for InvalidUpcastComparisons { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprBinary(ref cmp, ref lhs, ref rhs) = expr.node { - - let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs); - let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { - val - } else { - return; - }; - - let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs); - let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs); - - upcast_comparison_bounds_err(cx, &expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false); - upcast_comparison_bounds_err(cx, &expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true); - } - } -} diff --git a/src/unicode.rs b/src/unicode.rs deleted file mode 100644 index 8271fd3ed66..00000000000 --- a/src/unicode.rs +++ /dev/null @@ -1,109 +0,0 @@ -use rustc::lint::*; -use rustc::hir::*; -use syntax::ast::LitKind; -use syntax::codemap::Span; -use unicode_normalization::UnicodeNormalization; -use utils::{snippet, span_help_and_lint}; - -/// **What it does:** This lint checks for the unicode zero-width space in the code. -/// -/// **Why is this bad?** Having an invisible character in the code makes for all sorts of April fools, but otherwise is very much frowned upon. -/// -/// **Known problems:** None -/// -/// **Example:** You don't see it, but there may be a zero-width space somewhere in this text. -declare_lint! { - pub ZERO_WIDTH_SPACE, Deny, - "using a zero-width space in a string literal, which is confusing" -} - -/// **What it does:** This lint checks for non-ascii characters in string literals. -/// -/// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset back. Even so, there still are editors and other programs out there that don't work well with unicode. So if the code is meant to be used internationally, on multiple operating systems, or has other portability requirements, activating this lint could be useful. -/// -/// **Known problems:** None -/// -/// **Example:** `let x = "Hä?"` -declare_lint! { - pub NON_ASCII_LITERAL, Allow, - "using any literal non-ASCII chars in a string literal; suggests \ - using the \\u escape instead" -} - -/// **What it does:** This lint checks for string literals that contain unicode in a form that is not equal to its [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). -/// -/// **Why is this bad?** If such a string is compared to another, the results may be surprising. -/// -/// **Known problems** None -/// -/// **Example:** You may not see it, but "à" and "à" aren't the same string. The former when escaped is actually "a\u{300}" while the latter is "\u{e0}". -declare_lint! { - pub UNICODE_NOT_NFC, Allow, - "using a unicode literal not in NFC normal form (see \ - [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" -} - - -#[derive(Copy, Clone)] -pub struct Unicode; - -impl LintPass for Unicode { - fn get_lints(&self) -> LintArray { - lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC) - } -} - -impl LateLintPass for Unicode { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - if let ExprLit(ref lit) = expr.node { - if let LitKind::Str(_, _) = lit.node { - check_str(cx, lit.span) - } - } - } -} - -fn escape<T: Iterator<Item = char>>(s: T) -> String { - let mut result = String::new(); - for c in s { - if c as u32 > 0x7F { - for d in c.escape_unicode() { - result.push(d) - } - } else { - result.push(c); - } - } - result -} - -fn check_str(cx: &LateContext, span: Span) { - let string = snippet(cx, span, ""); - if string.contains('\u{200B}') { - span_help_and_lint(cx, - ZERO_WIDTH_SPACE, - span, - "zero-width space detected", - &format!("Consider replacing the string with:\n\"{}\"", - string.replace("\u{200B}", "\\u{200B}"))); - } - if string.chars().any(|c| c as u32 > 0x7F) { - span_help_and_lint(cx, - NON_ASCII_LITERAL, - span, - "literal non-ASCII character detected", - &format!("Consider replacing the string with:\n\"{}\"", - if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { - escape(string.chars()) - } else { - escape(string.nfc()) - })); - } - if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && string.chars().zip(string.nfc()).any(|(a, b)| a != b) { - span_help_and_lint(cx, - UNICODE_NOT_NFC, - span, - "non-nfc unicode sequence detected", - &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>())); - } -} diff --git a/src/unsafe_removed_from_name.rs b/src/unsafe_removed_from_name.rs deleted file mode 100644 index 3de6719c546..00000000000 --- a/src/unsafe_removed_from_name.rs +++ /dev/null @@ -1,81 +0,0 @@ -use rustc::hir::*; -use rustc::lint::*; -use syntax::ast::Name; -use syntax::codemap::Span; -use syntax::parse::token::InternedString; -use utils::span_lint; - -/// **What it does:** This lint checks for imports that remove "unsafe" from an item's name -/// -/// **Why is this bad?** Renaming makes it less clear which traits and structures are unsafe. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// use std::cell::{UnsafeCell as TotallySafeCell}; -/// -/// extern crate crossbeam; -/// use crossbeam::{spawn_unsafe as spawn}; -/// ``` -declare_lint! { - pub UNSAFE_REMOVED_FROM_NAME, - Warn, - "unsafe removed from name" -} - -pub struct UnsafeNameRemoval; - -impl LintPass for UnsafeNameRemoval { - fn get_lints(&self) -> LintArray { - lint_array!(UNSAFE_REMOVED_FROM_NAME) - } -} - -impl LateLintPass for UnsafeNameRemoval { - fn check_item(&mut self, cx: &LateContext, item: &Item) { - if let ItemUse(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 - ); - }, - ViewPath_::ViewPathList(_, ref path_list_items) => { - for path_list_item in path_list_items.iter() { - let plid = path_list_item.node; - if let (Some(name), Some(rename)) = (plid.name(), plid.rename()) { - unsafe_to_safe_check(name, rename, cx, &item.span); - }; - } - }, - 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(); - 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 - )); - } -} - -fn contains_unsafe(name: &InternedString) -> bool { - name.contains("Unsafe") || name.contains("unsafe") -} diff --git a/src/unused_label.rs b/src/unused_label.rs deleted file mode 100644 index d408f16a371..00000000000 --- a/src/unused_label.rs +++ /dev/null @@ -1,78 +0,0 @@ -use rustc::lint::*; -use rustc::hir; -use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; -use std::collections::HashMap; -use syntax::ast; -use syntax::codemap::Span; -use syntax::parse::token::InternedString; -use utils::{in_macro, span_lint}; - -/// **What it does:** This lint checks for unused labels. -/// -/// **Why is this bad?** Maybe the label should be used in which case there is an error in the -/// code or it should be removed. -/// -/// **Known problems:** Hopefully none. -/// -/// **Example:** -/// ```rust,ignore -/// fn unused_label() { -/// 'label: for i in 1..2 { -/// if i > 4 { continue } -/// } -/// ``` -declare_lint! { - pub UNUSED_LABEL, - Warn, - "unused label" -} - -pub struct UnusedLabel; - -#[derive(Default)] -struct UnusedLabelVisitor { - labels: HashMap<InternedString, Span>, -} - -impl UnusedLabelVisitor { - pub fn new() -> UnusedLabelVisitor { - ::std::default::Default::default() - } -} - -impl LintPass for UnusedLabel { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_LABEL) - } -} - -impl LateLintPass for UnusedLabel { - fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Block, span: Span, _: ast::NodeId) { - if in_macro(cx, span) { - return; - } - - let mut v = UnusedLabelVisitor::new(); - walk_fn(&mut v, kind, decl, body, span); - - for (label, span) in v.labels { - span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); - } - } -} - -impl<'v> Visitor<'v> for UnusedLabelVisitor { - fn visit_expr(&mut self, expr: &hir::Expr) { - match expr.node { - hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { - self.labels.remove(&label.node.as_str()); - } - hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { - self.labels.insert(label.as_str(), expr.span); - } - _ => (), - } - - walk_expr(self, expr); - } -} diff --git a/src/utils/comparisons.rs b/src/utils/comparisons.rs deleted file mode 100644 index b890a363fb7..00000000000 --- a/src/utils/comparisons.rs +++ /dev/null @@ -1,23 +0,0 @@ -use rustc::hir::{BinOp_, Expr}; - -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub enum Rel { - Lt, - Le, - Eq, - Ne, -} - -/// Put the expression in the form `lhs < rhs` or `lhs <= rhs`. -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)), - BinOp_::BiGt => Some((Rel::Lt, rhs, lhs)), - BinOp_::BiGe => Some((Rel::Le, rhs, lhs)), - BinOp_::BiEq => Some((Rel::Eq, rhs, lhs)), - BinOp_::BiNe => Some((Rel::Ne, rhs, lhs)), - _ => None, - } -} diff --git a/src/utils/conf.rs b/src/utils/conf.rs deleted file mode 100644 index e773cc0e025..00000000000 --- a/src/utils/conf.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::{fmt, fs, io}; -use std::io::Read; -use syntax::{ast, codemap, ptr}; -use syntax::parse::token; -use toml; - -/// Get the configuration file from arguments. -pub fn conf_file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> { - for arg in args { - match arg.node { - ast::MetaItemKind::Word(ref name) | - ast::MetaItemKind::List(ref name, _) => { - if name == &"conf_file" { - return Err(("`conf_file` must be a named value", arg.span)); - } - } - ast::MetaItemKind::NameValue(ref name, ref value) => { - if name == &"conf_file" { - return if let ast::LitKind::Str(ref file, _) = value.node { - Ok(Some(file.clone())) - } else { - Err(("`conf_file` value must be a string", value.span)) - }; - } - } - } - } - - Ok(None) -} - -/// Error from reading a configuration file. -#[derive(Debug)] -pub enum ConfError { - IoError(io::Error), - TomlError(Vec<toml::ParserError>), - TypeError(&'static str, &'static str, &'static str), - UnknownKey(String), -} - -impl fmt::Display for ConfError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ConfError::IoError(ref err) => err.fmt(f), - ConfError::TomlError(ref errs) => { - let mut first = true; - for err in errs { - if !first { - try!(", ".fmt(f)); - first = false; - } - - try!(err.fmt(f)); - } - - Ok(()) - } - ConfError::TypeError(ref key, ref expected, ref got) => { - write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) - } - ConfError::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), - } - } -} - -impl From<io::Error> for ConfError { - fn from(e: io::Error) -> Self { - ConfError::IoError(e) - } -} - -macro_rules! define_Conf { - ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => { - /// Type used to store lint configuration. - pub struct Conf { - $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+ - } - - impl Default for Conf { - fn default() -> Conf { - Conf { - $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+ - } - } - } - - impl Conf { - /// Set the property `name` (which must be the `toml` name) to the given value - #[allow(cast_sign_loss)] - fn set(&mut self, name: String, value: toml::Value) -> Result<(), ConfError> { - match name.as_str() { - $( - define_Conf!(PAT $toml_name) => { - if let Some(value) = define_Conf!(CONV $($ty)+, value) { - self.$rust_name = value; - } - else { - return Err(ConfError::TypeError(define_Conf!(EXPR $toml_name), - stringify!($($ty)+), - value.type_str())); - } - }, - )+ - "third-party" => { - // for external tools such as clippy-service - return Ok(()); - } - _ => { - return Err(ConfError::UnknownKey(name)); - } - } - - Ok(()) - } - } - }; - - // hack to convert tts - (PAT $pat: pat) => { $pat }; - (EXPR $e: expr) => { $e }; - (TY $ty: ty) => { $ty }; - - // 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 String, $value: expr) => { $value.as_str().map(Into::into) }; - (CONV Vec<String>, $value: expr) => {{ - let slice = $value.as_slice(); - - 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().unwrap_or_else(|| unreachable!()).to_owned()).collect()) - } - } - else { - None - } - }}; - - // provide a nicer syntax to declare the default value of `Vec<String>` variables - (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() }; - (DEFAULT $ty: ty, $e: expr) => { $e }; -} - -define_Conf! { - /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about - ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>), - /// 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", "GitHub"] => Vec<String>), - /// 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 - ("type-complexity-threshold", type_complexity_threshold, 250 => u64), - /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have - ("single-char-binding-names-threshold", max_single_char_names, 5 => u64), -} - -/// Read the `toml` configuration file. The function will ignore “File not found” errors iif -/// `!must_exist`, in which case, it will return the default configuration. -/// In case of error, the function tries to continue as much as possible. -pub fn read_conf(path: &str, must_exist: bool) -> (Conf, Vec<ConfError>) { - let mut conf = Conf::default(); - let mut errors = Vec::new(); - - let file = match fs::File::open(path) { - Ok(mut file) => { - let mut buf = String::new(); - - if let Err(err) = file.read_to_string(&mut buf) { - errors.push(err.into()); - return (conf, errors); - } - - buf - } - Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => { - return (conf, errors); - } - Err(err) => { - errors.push(err.into()); - return (conf, errors); - } - }; - - let mut parser = toml::Parser::new(&file); - let toml = if let Some(toml) = parser.parse() { - toml - } else { - errors.push(ConfError::TomlError(parser.errors)); - return (conf, errors); - }; - - for (key, value) in toml { - if let Err(err) = conf.set(key, value) { - errors.push(err); - } - } - - (conf, errors) -} diff --git a/src/utils/hir.rs b/src/utils/hir.rs deleted file mode 100644 index 0f0a7312ee4..00000000000 --- a/src/utils/hir.rs +++ /dev/null @@ -1,513 +0,0 @@ -use consts::constant; -use rustc::lint::*; -use rustc::hir::*; -use std::hash::{Hash, Hasher, SipHasher}; -use syntax::ast::Name; -use syntax::ptr::P; -use utils::differing_macro_contexts; - -/// Type used to check whether two ast are the same. This is different from the operator -/// `==` on ast types as this operator would compare true equality with ID and span. -/// -/// Note that some expressions kinds are not considered but could be added. -pub struct SpanlessEq<'a, 'tcx: 'a> { - /// Context used to evaluate constant expressions. - cx: &'a LateContext<'a, 'tcx>, - /// If is true, never consider as equal expressions containing function calls. - ignore_fn: bool, -} - -impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { - pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { - SpanlessEq { - cx: cx, - ignore_fn: false, - } - } - - pub fn ignore_fn(self) -> Self { - SpanlessEq { - cx: self.cx, - ignore_fn: true, - } - } - - /// Check whether two statements are the same. - pub fn eq_stmt(&self, left: &Stmt, right: &Stmt) -> bool { - match (&left.node, &right.node) { - (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { - if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { - // TODO: tys - l.ty.is_none() && r.ty.is_none() && 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, - } - } - - /// Check whether two blocks are the same. - pub fn eq_block(&self, left: &Block, right: &Block) -> bool { - over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && - both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) - } - - pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { - if self.ignore_fn && differing_macro_contexts(left.span, right.span) { - return false; - } - - if let (Some(l), Some(r)) = (constant(self.cx, left), constant(self.cx, right)) { - if l == r { - return true; - } - } - - 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()), - (&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), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.as_str() == r.node.as_str()), - (&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)) => 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), &ExprLoop(ref rb, ref rl)) => { - self.eq_block(lb, rb) && both(ll, rl, |l, r| l.as_str() == r.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)) => { - // TODO: tys - !self.ignore_fn && l_name.node == r_name.node && l_tys.is_empty() && r_tys.is_empty() && - 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) - } - (&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)) && - 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), - (&ExprVec(ref l), &ExprVec(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.as_str() == r.as_str()) - } - _ => false, - } - } - - fn eq_exprs(&self, left: &[P<Expr>], right: &[P<Expr>]) -> bool { - over(left, right, |l, r| self.eq_expr(l, r)) - } - - fn eq_field(&self, left: &Field, right: &Field) -> bool { - left.name.node == right.name.node && self.eq_expr(&left.expr, &right.expr) - } - - /// Check whether two patterns are the same. - pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { - match (&left.node, &right.node) { - (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), - (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => { - self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r))) - } - (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(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::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), - (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { - self.eq_qself(ls, rs) && self.eq_path(lp, rp) - } - (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => 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::Vec(ref ls, ref li, ref le), &PatKind::Vec(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_path(&self, left: &Path, right: &Path) -> bool { - // The == of idents doesn't work with different contexts, - // we have to be explicit about hygiene - left.global == right.global && - over(&left.segments, - &right.segments, - |l, r| l.name.as_str() == r.name.as_str() && l.parameters == r.parameters) - } - - fn eq_qself(&self, left: &QSelf, right: &QSelf) -> bool { - left.ty.node == right.ty.node && left.position == right.position - } - - fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { - match (&left.node, &right.node) { - (&TyVec(ref l_vec), &TyVec(ref r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyFixedLengthVec(ref lt, ref ll), &TyFixedLengthVec(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) - } - (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), - (&TyInfer, &TyInfer) => true, - _ => false, - } - } -} - -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)), - BiLt => Some((BiGt, rhs, lhs)), - BiLe => Some((BiGe, rhs, lhs)), - BiGe => Some((BiLe, rhs, lhs)), - BiGt => Some((BiLt, rhs, lhs)), - BiShl | BiShr | BiRem | BiSub | BiDiv | BiAnd | BiOr => None, - } -} - -/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool -{ - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) -} - -/// Check if two slices are equal as per `eq_fn`. -fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool -{ - left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) -} - - -/// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this -/// trait would consider IDs and spans. -/// -/// All expressions kind are hashed, but some might have a weaker hash. -pub struct SpanlessHash<'a, 'tcx: 'a> { - /// Context used to evaluate constant expressions. - cx: &'a LateContext<'a, 'tcx>, - s: SipHasher, -} - -impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { - pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { - SpanlessHash { - cx: cx, - s: SipHasher::new(), - } - } - - pub fn finish(&self) -> u64 { - self.s.finish() - } - - pub fn hash_block(&mut self, b: &Block) { - for s in &b.stmts { - self.hash_stmt(s); - } - - if let Some(ref e) = b.expr { - self.hash_expr(e); - } - - b.rules.hash(&mut self.s); - } - - pub fn hash_expr(&mut self, e: &Expr) { - if let Some(e) = constant(self.cx, e) { - return e.hash(&mut self.s); - } - - match e.node { - ExprAddrOf(m, ref e) => { - let c: fn(_, _) -> _ = ExprAddrOf; - 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); - } - } - 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) => { - let c: fn(_) -> _ = ExprBreak; - c.hash(&mut self.s); - if let Some(i) = i { - self.hash_name(&i.node); - } - } - 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 b, _) => { - let c: fn(_, _, _, _) -> _ = ExprClosure; - c.hash(&mut self.s); - cap.hash(&mut self.s); - self.hash_block(b); - } - 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); - self.hash_expr(cond); - self.hash_block(t); - 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) => { - let c: fn(_, _) -> _ = ExprLoop; - c.hash(&mut self.s); - self.hash_block(b); - if let Some(i) = *i { - self.hash_name(&i); - } - } - ExprMatch(ref e, ref arms, ref s) => { - let c: fn(_, _, _) -> _ = ExprMatch; - c.hash(&mut self.s); - self.hash_expr(e); - - for arm in arms { - // TODO: arm.pat? - if let Some(ref e) = arm.guard { - self.hash_expr(e); - } - self.hash_expr(&arm.body); - } - - 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; - c.hash(&mut self.s); - self.hash_path(subpath); - } - ExprStruct(ref path, ref fields, ref expr) => { - let c: fn(_, _, _) -> _ = ExprStruct; - c.hash(&mut self.s); - - self.hash_path(path); - - for f in fields { - self.hash_name(&f.name.node); - self.hash_expr(&f.expr); - } - - 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(_, _) => { - let c: fn(_, _) -> _ = ExprType; - c.hash(&mut self.s); - // what’s an ExprType anyway? - } - ExprUnary(lop, ref le) => { - let c: fn(_, _) -> _ = ExprUnary; - c.hash(&mut self.s); - - lop.hash(&mut self.s); - self.hash_expr(le); - } - ExprVec(ref v) => { - let c: fn(_) -> _ = ExprVec; - c.hash(&mut self.s); - - self.hash_exprs(v); - } - ExprWhile(ref cond, ref b, l) => { - let c: fn(_, _, _) -> _ = ExprWhile; - c.hash(&mut self.s); - - self.hash_expr(cond); - self.hash_block(b); - if let Some(l) = l { - self.hash_name(&l); - } - } - } - } - - pub fn hash_exprs(&mut self, e: &[P<Expr>]) { - for e in e { - self.hash_expr(e); - } - } - - pub fn hash_name(&mut self, n: &Name) { - n.as_str().hash(&mut self.s); - } - - pub fn hash_path(&mut self, p: &Path) { - p.global.hash(&mut self.s); - for p in &p.segments { - self.hash_name(&p.name); - } - } - - pub fn hash_stmt(&mut self, b: &Stmt) { - match b.node { - StmtDecl(ref _decl, _) => { - let c: fn(_, _) -> _ = StmtDecl; - c.hash(&mut self.s); - // TODO: decl - } - 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/src/utils/mod.rs b/src/utils/mod.rs deleted file mode 100644 index 3ff6167620a..00000000000 --- a/src/utils/mod.rs +++ /dev/null @@ -1,840 +0,0 @@ -use reexport::*; -use rustc::hir::*; -use rustc::hir::def_id::DefId; -use rustc::hir::map::Node; -use rustc::lint::{LintContext, LateContext, Level, Lint}; -use rustc::middle::cstore; -use rustc::session::Session; -use rustc::traits::ProjectionMode; -use rustc::traits; -use rustc::ty::subst::Subst; -use rustc::ty; -use std::borrow::Cow; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::str::FromStr; -use syntax::ast::{self, LitKind, RangeLimits}; -use syntax::codemap::{ExpnInfo, Span, ExpnFormat}; -use syntax::errors::DiagnosticBuilder; -use syntax::ptr::P; - -pub mod comparisons; -pub mod conf; -mod hir; -pub mod paths; -pub use self::hir::{SpanlessEq, SpanlessHash}; - -pub type MethodArgs = HirVec<P<Expr>>; - -/// 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 -/// } -/// } -/// -/// becomes -/// -/// 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) => { - if let $pat = $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([let $pat:pat = $expr:expr], $block:block) => { - if let $pat = $expr { - $block - } - }; - ([let $pat:pat = $expr:expr,], $block:block) => { - if let $pat = $expr { - $block - } - }; - ([$expr:expr, $($tt:tt)+], $block:block) => { - if $expr { - if_let_chain!{ [$($tt)+], $block } - } - }; - ([$expr:expr], $block:block) => { - if $expr { - $block - } - }; - ([$expr:expr,], $block:block) => { - if $expr { - $block - } - }; -} - -/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one -/// isn't). -pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { - rhs.expn_id != lhs.expn_id -} -/// Returns true if this `expn_info` was expanded by any macro. -pub fn in_macro<T: LintContext>(cx: &T, span: Span) -> bool { - cx.sess().codemap().with_expn_info(span.expn_id, |info| info.is_some()) -} - -/// Returns true if the macro that expanded the crate was outside of the current crate or was a -/// compiler plugin. -pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool { - /// Invokes `in_macro` with the expansion info of the given span slightly heavy, try to use - /// this after other checks have already happened. - fn in_macro_ext<T: LintContext>(cx: &T, opt_info: Option<&ExpnInfo>) -> bool { - // no ExpnInfo = no macro - opt_info.map_or(false, |info| { - if let ExpnFormat::MacroAttribute(..) = info.callee.format { - // these are all plugins - return true; - } - // no span for the callee = external macro - info.callee.span.map_or(true, |span| { - // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) - }) - }) - } - - cx.sess().codemap().with_expn_info(span.expn_id, |info| in_macro_ext(cx, info)) -} - -/// Check if a `DefId`'s path matches the given absolute type path usage. -/// -/// # Examples -/// ``` -/// match_def_path(cx, id, &["core", "option", "Option"]) -/// ``` -/// -/// See also the `paths` module. -pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { - use syntax::parse::token; - - struct AbsolutePathBuffer { - names: Vec<token::InternedString>, - } - - impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { - fn root_mode(&self) -> &ty::item_path::RootMode { - const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute; - ABSOLUTE - } - - fn push(&mut self, text: &str) { - self.names.push(token::intern(text).as_str()); - } - } - - let mut apb = AbsolutePathBuffer { - names: vec![], - }; - - cx.tcx.push_item_path(&mut apb, def_id); - - apb.names == path -} - -/// Check if type is struct or enum type with given def path. -pub fn match_type(cx: &LateContext, ty: ty::Ty, path: &[&str]) -> bool { - match ty.sty { - ty::TyEnum(ref adt, _) | - ty::TyStruct(ref adt, _) => match_def_path(cx, adt.did, path), - _ => false, - } -} - -/// Check if the method call given in `expr` belongs to given type. -pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { - let method_call = ty::MethodCall::expr(expr.id); - - let trt_id = cx.tcx - .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 { - false - } -} - -/// Check if the method call given in `expr` belongs to given trait. -pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { - let method_call = ty::MethodCall::expr(expr.id); - - let trt_id = cx.tcx - .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 { - false - } -} - -/// Match a `Path` against a slice of segment string literals. -/// -/// # Examples -/// ``` -/// match_path(path, &["std", "rt", "begin_unwind"]) -/// ``` -pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name.as_str() == *b) -} - -/// Match a `Path` against a slice of segment string literals, e.g. -/// -/// # Examples -/// ``` -/// match_path(path, &["std", "rt", "begin_unwind"]) -/// ``` -pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name.as_str() == *b) -} - -/// Get the definition associated to a path. -/// TODO: investigate if there is something more efficient for that. -pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<cstore::DefLike> { - let cstore = &cx.tcx.sess.cstore; - - let crates = cstore.crates(); - let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); - if let Some(krate) = krate { - let mut items = cstore.crate_top_level_items(*krate); - let mut path_it = path.iter().skip(1).peekable(); - - loop { - let segment = match path_it.next() { - Some(segment) => segment, - None => return None, - }; - - for item in &mem::replace(&mut items, vec![]) { - if item.name.as_str() == *segment { - if path_it.peek().is_none() { - return Some(item.def); - } - - let def_id = match item.def { - cstore::DefLike::DlDef(def) => def.def_id(), - cstore::DefLike::DlImpl(def_id) => def_id, - _ => panic!("Unexpected {:?}", item.def), - }; - - items = cstore.item_children(def_id); - break; - } - } - } - } else { - None - } -} - -/// Convenience function to get the `DefId` of a trait by path. -pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { - let def = match path_to_def(cx, path) { - Some(def) => def, - None => return None, - }; - - match def { - cstore::DlDef(def::Def::Trait(trait_id)) => Some(trait_id), - _ => None, - } -} - -/// 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<ty::Ty<'tcx>>) - -> bool { - cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); - - let ty = cx.tcx.erase_regions(&ty); - cx.tcx.infer_ctxt(None, None, ProjectionMode::Any).enter(|infcx| { - let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params); - - traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) - }) -} - -/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. -/// -/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, -/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for -/// `.bar()` and `.baz()` -pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a MethodArgs>> { - let mut current = expr; - let mut matched = Vec::with_capacity(methods.len()); - for method_name in methods.iter().rev() { - // method chains are stored last -> first - if let ExprMethodCall(ref name, _, ref args) = current.node { - if name.node.as_str() == *method_name { - matched.push(args); // build up `matched` backwards - current = &args[0] // go to parent expression - } else { - return None; - } - } else { - return None; - } - } - matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` - Some(matched) -} - - -/// Get the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { - let parent_id = cx.tcx.map.get_parent(expr.id); - match cx.tcx.map.find(parent_id) { - Some(Node::NodeItem(&Item { ref name, .. })) | - Some(Node::NodeTraitItem(&TraitItem { ref name, .. })) | - Some(Node::NodeImplItem(&ImplItem { ref name, .. })) => Some(*name), - _ => None, - } -} - -/// Checks if a `let` decl is from a `for` loop desugaring. -pub fn is_from_for_desugar(decl: &Decl) -> bool { - if_let_chain! { - [ - let DeclLocal(ref loc) = decl.node, - let Some(ref expr) = loc.init, - let ExprMatch(_, _, MatchSource::ForLoopDesugar) = expr.node - ], - { return true; } - }; - false -} - - -/// Convert a span to a code snippet if available, otherwise use default. -/// -/// # Example -/// ``` -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) -} - -/// Convert a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> { - cx.sess().codemap().span_to_snippet(span).ok() -} - -/// Convert a span (from a block) to a code snippet if available, otherwise use default. -/// This trims the code of indentation, except for the first line. Use it for blocks or block-like -/// things which need to be printed as such. -/// -/// # Example -/// ``` -/// snippet(cx, expr.span, "..") -/// ``` -pub fn snippet_block<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - let snip = snippet(cx, span, default); - trim_multiline(snip, true) -} - -/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. -/// Also takes an `Option<String>` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default); - let string = option.unwrap_or_default(); - if let ExprBlock(_) = expr.node { - Cow::Owned(format!("{}{}", code, string)) - } else if string.is_empty() { - Cow::Owned(format!("{{ {} }}", code)) - } else { - Cow::Owned(format!("{{\n{};\n{}\n}}", code, string)) - } -} - -/// Trim indentation from a multiline string with possibility of ignoring the first line. -pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { - let s_space = trim_multiline_inner(s, ignore_first, ' '); - let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); - trim_multiline_inner(s_tab, ignore_first, ' ') -} - -fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { - 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); - 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::<Vec<_>>() - .join("\n")) - } else { - s - } -} - -/// Get a parent expressions if any – this is useful to constrain a lint. -pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { - let map = &cx.tcx.map; - let node_id: NodeId = e.id; - let parent_id: NodeId = map.get_parent_node(node_id); - if node_id == parent_id { - return None; - } - map.find(parent_id).and_then(|node| { - if let Node::NodeExpr(parent) = node { - Some(parent) - } else { - None - } - }) -} - -pub fn get_enclosing_block<'c>(cx: &'c LateContext, node: NodeId) -> Option<&'c Block> { - let map = &cx.tcx.map; - let enclosing_node = map.get_enclosing_scope(node) - .and_then(|enclosing_id| map.find(enclosing_id)); - if let Some(node) = enclosing_node { - match node { - Node::NodeBlock(ref block) => Some(block), - Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, ref block), .. }) => Some(block), - _ => None, - } - } else { - None - } -} - -pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>); - -impl<'a> Drop for DiagnosticWrapper<'a> { - fn drop(&mut self) { - self.0.emit(); - } -} - -impl<'a> DerefMut for DiagnosticWrapper<'a> { - fn deref_mut(&mut self) -> &mut DiagnosticBuilder<'a> { - &mut self.0 - } -} - -impl<'a> Deref for DiagnosticWrapper<'a> { - type Target = DiagnosticBuilder<'a>; - fn deref(&self) -> &DiagnosticBuilder<'a> { - &self.0 - } -} - -impl<'a> DiagnosticWrapper<'a> { - fn wiki_link(&mut self, lint: &'static Lint) { - self.help(&format!("for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", - lint.name_lower())); - } -} - -pub fn span_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str) -> DiagnosticWrapper<'a> { - let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); - if cx.current_level(lint) != Level::Allow { - db.wiki_link(lint); - } - db -} - -pub fn span_help_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) - -> DiagnosticWrapper<'a> { - let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); - if cx.current_level(lint) != Level::Allow { - db.help(help); - db.wiki_link(lint); - } - db -} - -pub fn span_note_and_lint<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, note_span: Span, - note: &str) - -> DiagnosticWrapper<'a> { - let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); - if cx.current_level(lint) != Level::Allow { - if note_span == span { - db.note(note); - } else { - db.span_note(note_span, note); - } - db.wiki_link(lint); - } - db -} - -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) - -> DiagnosticWrapper<'a> - where F: FnOnce(&mut DiagnosticWrapper) -{ - let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); - if cx.current_level(lint) != Level::Allow { - f(&mut db); - db.wiki_link(lint); - } - db -} - -/// Return the base type for references and raw pointers. -pub fn walk_ptrs_ty(ty: ty::Ty) -> ty::Ty { - match ty.sty { - ty::TyRef(_, ref tm) | - ty::TyRawPtr(ref tm) => walk_ptrs_ty(tm.ty), - _ => ty, - } -} - -/// Return the base type for references and raw pointers, and count reference depth. -pub fn walk_ptrs_ty_depth(ty: ty::Ty) -> (ty::Ty, usize) { - fn inner(ty: ty::Ty, depth: usize) -> (ty::Ty, usize) { - match ty.sty { - ty::TyRef(_, ref tm) | - ty::TyRawPtr(ref tm) => inner(tm.ty, depth + 1), - _ => (ty, depth), - } - } - inner(ty, 0) -} - -/// Check whether the given expression is a constant literal of the given value. -pub fn is_integer_literal(expr: &Expr, value: u64) -> bool { - // FIXME: use constant folding - if let ExprLit(ref spanned) = expr.node { - if let LitKind::Int(v, _) = spanned.node { - return v == value; - } - } - false -} - -pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { - cx.tcx.tables.borrow().adjustments.get(&e.id).is_some() -} - -pub struct LimitStack { - stack: Vec<u64>, -} - -impl Drop for LimitStack { - fn drop(&mut self) { - assert_eq!(self.stack.len(), 1); - } -} - -impl LimitStack { - pub fn new(limit: u64) -> LimitStack { - LimitStack { stack: vec![limit] } - } - pub fn limit(&self) -> u64 { - *self.stack.last().expect("there should always be a value in the stack") - } - pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { - let stack = &mut self.stack; - parse_attrs(sess, attrs, name, |val| stack.push(val)); - } - pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { - let stack = &mut self.stack; - parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); - } -} - -fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { - for attr in attrs { - let attr = &attr.node; - if attr.is_sugared_doc { - continue; - } - if let ast::MetaItemKind::NameValue(ref key, ref value) = attr.value.node { - if *key == name { - if let LitKind::Str(ref s, _) = value.node { - if let Ok(value) = FromStr::from_str(s) { - f(value) - } else { - sess.span_err(value.span, "not a number"); - } - } else { - unreachable!() - } - } - } - } -} - -/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. -/// See also `is_direct_expn_of`. -pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { - 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))); - - match span_name_span { - Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), - None => return None, - Some((_, new_span)) => span = new_span, - } - } -} - -/// Return the pre-expansion span if is this directly comes from an expansion of the macro `name`. -/// The difference with `is_expn_of` is that in -/// ```rust,ignore -/// foo!(bar!(42)); -/// ``` -/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by -/// `is_direct_expn_of`. -pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option<Span> { - let span_name_span = cx.tcx - .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.as_str() == name => Some(new_span), - _ => None, - } -} - -/// Return the index of the character after the first camel-case component of `s`. -pub fn camel_case_until(s: &str) -> usize { - let mut iter = s.char_indices(); - if let Some((_, first)) = iter.next() { - if !first.is_uppercase() { - return 0; - } - } else { - return 0; - } - let mut up = true; - let mut last_i = 0; - for (i, c) in iter { - if up { - if c.is_lowercase() { - up = false; - } else { - return last_i; - } - } else if c.is_uppercase() { - up = true; - last_i = i; - } else if !c.is_lowercase() { - return i; - } - } - if up { - last_i - } else { - s.len() - } -} - -/// Return index of the last camel-case component of `s`. -pub fn camel_case_from(s: &str) -> usize { - let mut iter = s.char_indices().rev(); - if let Some((_, first)) = iter.next() { - if !first.is_lowercase() { - return s.len(); - } - } else { - return s.len(); - } - let mut down = true; - let mut last_i = s.len(); - for (i, c) in iter { - if down { - if c.is_uppercase() { - down = false; - last_i = i; - } else if !c.is_lowercase() { - return last_i; - } - } else if c.is_lowercase() { - down = true; - } else { - return last_i; - } - } - last_i -} - -/// Represent a range akin to `ast::ExprKind::Range`. -#[derive(Debug, Copy, Clone)] -pub struct UnsugaredRange<'a> { - pub start: Option<&'a Expr>, - pub end: Option<&'a Expr>, - pub limits: RangeLimits, -} - -/// Unsugar a `hir` range. -pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { - // To be removed when ranges get stable. - fn unwrap_unstable(expr: &Expr) -> &Expr { - if let ExprBlock(ref block) = expr.node { - if block.rules == BlockCheckMode::PushUnstableBlock || block.rules == BlockCheckMode::PopUnstableBlock { - if let Some(ref expr) = block.expr { - return expr; - } - } - } - - expr - } - - fn get_field<'a>(name: &str, fields: &'a [Field]) -> Option<&'a Expr> { - let expr = &fields.iter() - .find(|field| field.name.node.as_str() == name) - .unwrap_or_else(|| panic!("missing {} field for range", name)) - .expr; - - Some(unwrap_unstable(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 { - ExprPath(None, ref path) => { - if match_path(path, &paths::RANGE_FULL_STD) || match_path(path, &paths::RANGE_FULL) { - Some(UnsugaredRange { - start: None, - end: None, - limits: RangeLimits::HalfOpen, - }) - } else { - None - } - } - ExprStruct(ref path, ref fields, None) => { - if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) { - Some(UnsugaredRange { - start: get_field("start", fields), - end: None, - limits: RangeLimits::HalfOpen, - }) - } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { - Some(UnsugaredRange { - start: get_field("start", fields), - end: get_field("end", fields), - limits: RangeLimits::Closed, - }) - } else if match_path(path, &paths::RANGE_STD) || match_path(path, &paths::RANGE) { - Some(UnsugaredRange { - start: get_field("start", fields), - end: get_field("end", fields), - limits: RangeLimits::HalfOpen, - }) - } else if match_path(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_path(path, &paths::RANGE_TO_INCLUSIVE) { - Some(UnsugaredRange { - start: None, - end: get_field("end", fields), - limits: RangeLimits::Closed, - }) - } else if match_path(path, &paths::RANGE_TO_STD) || match_path(path, &paths::RANGE_TO) { - Some(UnsugaredRange { - start: None, - end: get_field("end", fields), - limits: RangeLimits::HalfOpen, - }) - } else { - None - } - } - _ => None, - } -} - -/// Convenience function to get the return type of a function or `None` if the function diverges. -pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> { - let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item); - let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(cx.tcx, parameter_env.free_substs); - let fn_sig = cx.tcx.liberate_late_bound_regions(parameter_env.free_id_outlive, &fn_sig); - if let ty::FnConverging(ret_ty) = fn_sig.output { - Some(ret_ty) - } else { - None - } -} - -/// 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 { - let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item); - cx.tcx.infer_ctxt(None, Some(parameter_env), ProjectionMode::Any).enter(|infcx| { - let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs); - let new_b = b.subst(infcx.tcx, infcx.parameter_environment.free_substs); - infcx.can_equate(&new_a, &new_b).is_ok() - }) -} - -/// Recover the essential nodes of a desugared for loop: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. -pub fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> { - if_let_chain! { - [ - let ExprMatch(ref iterexpr, ref arms, _) = expr.node, - let ExprCall(_, ref iterargs) = iterexpr.node, - iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(), - let ExprLoop(ref block, _) = arms[0].body.node, - block.stmts.is_empty(), - let Some(ref loopexpr) = block.expr, - let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node, - innerarms.len() == 2 && innerarms[0].pats.len() == 1, - let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node, - somepats.len() == 1 - ], { - return Some((&somepats[0], - &iterargs[0], - &innerarms[0].body)); - } - } - None -} diff --git a/src/utils/paths.rs b/src/utils/paths.rs deleted file mode 100644 index 3c91578abd0..00000000000 --- a/src/utils/paths.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! This module contains paths to types and functions Clippy needs to know about. - -pub const BEGIN_PANIC: [&'static str; 3] = ["std", "rt", "begin_panic"]; -pub const BINARY_HEAP: [&'static str; 3] = ["collections", "binary_heap", "BinaryHeap"]; -pub const BOX: [&'static str; 3] = ["std", "boxed", "Box"]; -pub const BOX_NEW: [&'static str; 4] = ["std", "boxed", "Box", "new"]; -pub const BTREEMAP: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"]; -pub const BTREEMAP_ENTRY: [&'static str; 4] = ["collections", "btree", "map", "Entry"]; -pub const BTREESET: [&'static str; 4] = ["collections", "btree", "set", "BTreeSet"]; -pub const CLONE: [&'static str; 4] = ["core", "clone", "Clone", "clone"]; -pub const CLONE_TRAIT: [&'static str; 3] = ["core", "clone", "Clone"]; -pub const CMP_MAX: [&'static str; 3] = ["core", "cmp", "max"]; -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 DEBUG_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Debug", "fmt"]; -pub const DEFAULT_TRAIT: [&'static str; 3] = ["core", "default", "Default"]; -pub const DISPLAY_FMT_METHOD: [&'static str; 4] = ["std", "fmt", "Display", "fmt"]; -pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; -pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["std", "fmt", "Arguments", "new_v1"]; -pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["std", "fmt", "ArgumentV1", "new"]; -pub const HASH: [&'static str; 2] = ["hash", "Hash"]; -pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; -pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; -pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"]; -pub const IO_PRINT: [&'static str; 3] = ["std", "io", "_print"]; -pub const ITERATOR: [&'static str; 4] = ["core", "iter", "iterator", "Iterator"]; -pub const LINKED_LIST: [&'static str; 3] = ["collections", "linked_list", "LinkedList"]; -pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; -pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; -pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; -pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"]; -pub const OPTION: [&'static str; 3] = ["core", "option", "Option"]; -pub const RANGE: [&'static str; 3] = ["core", "ops", "Range"]; -pub const RANGE_FROM: [&'static str; 3] = ["core", "ops", "RangeFrom"]; -pub const RANGE_FROM_STD: [&'static str; 3] = ["std", "ops", "RangeFrom"]; -pub const RANGE_FULL: [&'static str; 3] = ["core", "ops", "RangeFull"]; -pub const RANGE_FULL_STD: [&'static str; 3] = ["std", "ops", "RangeFull"]; -pub const RANGE_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeInclusive"]; -pub const RANGE_INCLUSIVE_NON_EMPTY: [&'static str; 4] = ["core", "ops", "RangeInclusive", "NonEmpty"]; -pub const RANGE_INCLUSIVE_NON_EMPTY_STD: [&'static str; 4] = ["std", "ops", "RangeInclusive", "NonEmpty"]; -pub const RANGE_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeInclusive"]; -pub const RANGE_STD: [&'static str; 3] = ["std", "ops", "Range"]; -pub const RANGE_TO: [&'static str; 3] = ["core", "ops", "RangeTo"]; -pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclusive"]; -pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"]; -pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"]; -pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"]; -pub const REGEX_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; -pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"]; -pub const REGEX_BYTES_BUILDER_NEW: [&'static str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; -pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"]; -pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; -pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"]; -pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; -pub const RESULT: [&'static str; 3] = ["core", "result", "Result"]; -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"]; -pub const VEC_DEQUE: [&'static str; 3] = ["collections", "vec_deque", "VecDeque"]; -pub const VEC_FROM_ELEM: [&'static str; 3] = ["std", "vec", "from_elem"]; diff --git a/src/vec.rs b/src/vec.rs deleted file mode 100644 index e62a8f9c459..00000000000 --- a/src/vec.rs +++ /dev/null @@ -1,116 +0,0 @@ -use rustc::lint::*; -use rustc::ty::TypeVariants; -use rustc::hir::*; -use syntax::codemap::Span; -use syntax::ptr::P; -use utils::{is_expn_of, match_path, paths, recover_for_loop, snippet, span_lint_and_then}; - -/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. -/// -/// **Why is this bad?** This is less efficient. -/// -/// **Known problems:** None. -/// -/// **Example:** -/// ```rust,ignore -/// foo(&vec![1, 2]) -/// ``` -declare_lint! { - pub USELESS_VEC, - Warn, - "useless `vec!`" -} - -#[derive(Copy, Clone, Debug)] -pub struct UselessVec; - -impl LintPass for UselessVec { - fn get_lints(&self) -> LintArray { - lint_array!(USELESS_VEC) - } -} - -impl LateLintPass for UselessVec { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - // search for `&vec![_]` expressions where the adjusted type is `&[_]` - if_let_chain!{[ - let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty, - let TypeVariants::TySlice(..) = ty.ty.sty, - let ExprAddrOf(_, ref addressee) = expr.node, - ], { - check_vec_macro(cx, addressee, expr.span); - }} - - // search for `for _ in vec![…]` - if let Some((_, arg, _)) = recover_for_loop(expr) { - // report the error around the `vec!` not inside `<std macros>:` - let span = cx.sess().codemap().source_callsite(arg.span); - check_vec_macro(cx, arg, span); - } - } -} - -fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) { - if let Some(vec_args) = unexpand_vec(cx, vec) { - let snippet = match vec_args { - VecArgs::Repeat(elem, len) => { - format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() - } - VecArgs::Vec(args) => { - if let Some(last) = args.iter().last() { - let span = Span { - lo: args[0].span.lo, - hi: last.span.hi, - expn_id: args[0].span.expn_id, - }; - - format!("&[{}]", snippet(cx, span, "..")).into() - } else { - "&[]".into() - } - } - }; - - span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| { - db.span_suggestion(span, "you can use a slice directly", snippet); - }); - } -} - -/// Represent the pre-expansion arguments of a `vec!` invocation. -pub enum VecArgs<'a> { - /// `vec![elem; len]` - Repeat(&'a P<Expr>, &'a P<Expr>), - /// `vec![a, b, c]` - Vec(&'a [P<Expr>]), -} - -/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. -pub fn unexpand_vec<'e>(cx: &LateContext, expr: &'e Expr) -> Option<VecArgs<'e>> { - if_let_chain!{[ - let ExprCall(ref fun, ref args) = expr.node, - let ExprPath(_, ref path) = fun.node, - is_expn_of(cx, fun.span, "vec").is_some() - ], { - return if match_path(path, &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 { - // `vec![a, b, c]` case - if_let_chain!{[ - let ExprBox(ref boxed) = args[0].node, - let ExprVec(ref args) = boxed.node - ], { - return Some(VecArgs::Vec(&*args)); - }} - - None - } - else { - None - }; - }} - - None -} diff --git a/src/zero_div_zero.rs b/src/zero_div_zero.rs deleted file mode 100644 index 902d84d4dd3..00000000000 --- a/src/zero_div_zero.rs +++ /dev/null @@ -1,59 +0,0 @@ -use consts::{Constant, constant_simple, FloatWidth}; -use rustc::lint::*; -use rustc::hir::*; -use utils::span_help_and_lint; - -/// `ZeroDivZeroPass` is a pass that checks for a binary expression that consists -/// `of 0.0/0.0`, which is always `NaN`. It is more clear to replace instances of -/// `0.0/0.0` with `std::f32::NaN` or `std::f64::NaN`, depending on the precision. -pub struct ZeroDivZeroPass; - -/// **What it does:** This lint checks for `0.0 / 0.0`. -/// -/// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN` -/// -/// **Known problems:** None -/// -/// **Example** `0.0f32 / 0.0` -declare_lint! { - pub ZERO_DIVIDED_BY_ZERO, - Warn, - "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN" -} - -impl LintPass for ZeroDivZeroPass { - fn get_lints(&self) -> LintArray { - lint_array!(ZERO_DIVIDED_BY_ZERO) - } -} - -impl LateLintPass for ZeroDivZeroPass { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { - // check for instances of 0.0/0.0 - if_let_chain! { - [ - let ExprBinary(ref op, ref left, ref right) = expr.node, - let BinOp_::BiDiv = op.node, - // TODO - constant_simple does not fold many operations involving floats. - // That's probably fine for this lint - it's pretty unlikely that someone would - // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. - let Some(Constant::Float(ref lhs_value, lhs_width)) = constant_simple(left), - let Some(Constant::Float(ref rhs_value, rhs_width)) = constant_simple(right), - let Some(0.0) = lhs_value.parse().ok(), - let Some(0.0) = rhs_value.parse().ok() - ], - { - // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, - // match the precision of the literals that are given. - let float_type = match (lhs_width, rhs_width) { - (FloatWidth::F64, _) - | (_, FloatWidth::F64) => "f64", - _ => "f32" - }; - span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span, - "constant division of 0.0 with 0.0 will always result in NaN", - &format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type)); - } - } - } -} diff --git a/tests/dogfood.rs b/tests/dogfood.rs index d3021b8f2f9..5121fd08628 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -13,7 +13,7 @@ use test::TestPaths; fn dogfood() { let mut config = compiletest::default_config(); - let cfg_mode = "run-pass".parse().expect("Invalid mode"); + let cfg_mode = "run-fail".parse().expect("Invalid mode"); let mut s = String::new(); s.push_str(" -L target/debug/"); s.push_str(" -L target/debug/deps"); @@ -30,13 +30,21 @@ fn dogfood() { config.mode = cfg_mode; - let paths = TestPaths { - base: PathBuf::new(), - file: PathBuf::from("src/lib.rs"), - relative_dir: PathBuf::new(), - }; + let files = [ + "src/main.rs", + "src/lib.rs", + "clippy_lints/src/lib.rs", + ]; - set_var("CLIPPY_DOGFOOD", "tastes like chicken"); + for file in &files { + let paths = TestPaths { + base: PathBuf::new(), + file: PathBuf::from(file), + relative_dir: PathBuf::new(), + }; - compiletest::runtest::run(config, &paths); + set_var("CLIPPY_DOGFOOD", "tastes like chicken"); + + compiletest::runtest::run(config.clone(), &paths); + } } diff --git a/util/update_lints.py b/util/update_lints.py index bfed0430abb..8078b68367b 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -61,7 +61,7 @@ def collect(lints, deprecated_lints, restriction_lints, fn): match.group('name').lower(), "allow", desc.replace('\\"', '"'))) - + def gen_table(lints, link=None): """Write lint table in Markdown format.""" @@ -144,15 +144,15 @@ def main(print_only=False, check=False): restriction_lints = [] # check directory - if not os.path.isfile('src/lib.rs'): + if not os.path.isfile('clippy_lints/src/lib.rs'): print('Error: call this script from clippy checkout directory!') return # collect all lints from source files - for root, _, files in os.walk('src'): + for root, _, files in os.walk('clippy_lints/src'): for fn in files: if fn.endswith('.rs'): - collect(lints, deprecated_lints, restriction_lints, + collect(lints, deprecated_lints, restriction_lints, os.path.join(root, fn)) if print_only: @@ -178,38 +178,38 @@ def main(print_only=False, check=False): "<!-- begin autogenerated links to wiki -->", "<!-- end autogenerated links to wiki -->", lambda: ["[`{0}`]: {1}#{0}\n".format(l[1], wiki_link) for l in - sorted(lints + restriction_lints + deprecated_lints, + sorted(lints + restriction_lints + deprecated_lints, key=lambda l: l[1])], replace_start=False, write_back=not check) # update the `pub mod` list changed |= replace_region( - 'src/lib.rs', r'begin lints modules', r'end lints modules', + 'clippy_lints/src/lib.rs', r'begin lints modules', r'end lints modules', lambda: gen_mods(lints + restriction_lints), replace_start=False, write_back=not check) # same for "clippy" lint collection changed |= replace_region( - 'src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', + 'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);', lambda: gen_group(lints, levels=('warn', 'deny')), replace_start=False, write_back=not check) # same for "deprecated" lint collection changed |= replace_region( - 'src/lib.rs', r'let mut store', r'end deprecated lints', + 'clippy_lints/src/lib.rs', r'let mut store', r'end deprecated lints', lambda: gen_deprecated(deprecated_lints), replace_start=False, write_back=not check) # same for "clippy_pedantic" lint collection changed |= replace_region( - 'src/lib.rs', r'reg.register_lint_group\("clippy_pedantic"', r'\]\);', + 'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy_pedantic"', r'\]\);', lambda: gen_group(lints, levels=('allow',)), replace_start=False, write_back=not check) # same for "clippy_restrictions" lint collection changed |= replace_region( - 'src/lib.rs', r'reg.register_lint_group\("clippy_restrictions"', + 'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy_restrictions"', r'\]\);', lambda: gen_group(restriction_lints), replace_start=False, write_back=not check) -- cgit 1.4.1-3-g733a5 From 0818e70497f9f18075dbc5c5d56f62fa5025f1d1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 27 May 2016 15:31:19 +0200 Subject: don't require `cargo clippy` to pass a `--lib` or `--bin x` argument --- Cargo.toml | 2 +- src/cargo.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 42 +++++++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 src/cargo.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 672b9d7ef94..828857701d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,12 +32,12 @@ quine-mc_cluskey = "0.2.2" # begin automatic update clippy_lints = { version = "0.0.70", path = "clippy_lints" } # end automatic update +rustc-serialize = "0.3" [dev-dependencies] compiletest_rs = "0.1.0" lazy_static = "0.1.15" regex = "0.1.56" -rustc-serialize = "0.3" [features] debugging = [] diff --git a/src/cargo.rs b/src/cargo.rs new file mode 100644 index 00000000000..188d4d38e8d --- /dev/null +++ b/src/cargo.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; + +#[derive(RustcDecodable, Debug)] +pub struct Metadata { + pub packages: Vec<Package>, + resolve: Option<()>, + pub version: usize, +} + +#[derive(RustcDecodable, Debug)] +pub struct Package { + name: String, + version: String, + id: String, + source: Option<()>, + dependencies: Vec<Dependency>, + pub targets: Vec<Target>, + features: HashMap<String, Vec<String>>, + manifest_path: String, +} + +#[derive(RustcDecodable, Debug)] +pub struct Dependency { + name: String, + source: Option<String>, + req: String, + kind: Option<String>, + optional: bool, + uses_default_features: bool, + features: Vec<HashMap<String, String>>, + target: Option<()>, +} + +#[allow(non_camel_case_types)] +#[derive(RustcDecodable, Debug)] +pub enum Kind { + dylib, + test, + bin, + lib, +} + +#[derive(RustcDecodable, Debug)] +pub struct Target { + pub name: String, + pub kind: Vec<Kind>, + src_path: String, +} diff --git a/src/main.rs b/src/main.rs index 970222e1076..51683060be2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ extern crate rustc; extern crate syntax; extern crate rustc_plugin; extern crate clippy_lints; +extern crate rustc_serialize; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session}; @@ -16,6 +17,8 @@ use syntax::diagnostics; use std::path::PathBuf; use std::process::Command; +mod cargo; + struct ClippyCompilerCalls(RustcDefaultCalls); impl std::default::Default for ClippyCompilerCalls { @@ -118,16 +121,19 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let args = wrap_args(std::env::args().skip(2), dep_path, sys_root); - let path = std::env::current_exe().expect("current executable path invalid"); - 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?"); - - if let Some(code) = exit_status.code() { - std::process::exit(code); + let output = std::process::Command::new("cargo").args(&["metadata", "--no-deps"]).output().expect("could not run `cargo metadata`"); + let stdout = std::str::from_utf8(&output.stdout).expect("`cargo metadata` output is not utf8"); + let mut metadata: cargo::Metadata = rustc_serialize::json::decode(stdout).expect("`cargo metadata` output is not valid json"); + assert_eq!(metadata.version, 1); + for target in metadata.packages.remove(0).targets { + let args = std::env::args().skip(2); + assert_eq!(target.kind.len(), 1); + match target.kind[0] { + cargo::Kind::dylib => process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root), + cargo::Kind::bin => process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root), + // don't process tests + _ => {}, + } } } else { let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { @@ -145,7 +151,7 @@ pub fn main() { } } -fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String> +fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) where P: AsRef<Path>, I: Iterator<Item=String> { let mut args = vec!["rustc".to_owned()]; @@ -161,7 +167,17 @@ fn wrap_args<P, I>(old_args: I, dep_path: P, sysroot: String) -> Vec<String> args.push("-L".to_owned()); args.push(dep_path.as_ref().to_string_lossy().into_owned()); args.push(String::from("--sysroot")); - args.push(sysroot); + args.push(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); - args + + let path = std::env::current_exe().expect("current executable path invalid"); + 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?"); + + if let Some(code) = exit_status.code() { + std::process::exit(code); + } } -- cgit 1.4.1-3-g733a5 From e6a089efa952b94af35050e782e7e809f5dca3dc Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 27 May 2016 15:42:33 +0200 Subject: dogfood --- src/main.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 51683060be2..05096e80548 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(slice_patterns)] extern crate rustc_driver; extern crate getopts; @@ -128,10 +129,11 @@ pub fn main() { for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); assert_eq!(target.kind.len(), 1); - match target.kind[0] { - cargo::Kind::dylib => process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root), - cargo::Kind::bin => process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root), - // don't process tests + match &target.kind[..] { + [cargo::Kind::lib] | + [cargo::Kind::dylib] => process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root), + [cargo::Kind::bin] => process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root), + // don't process tests and other stuff _ => {}, } } -- cgit 1.4.1-3-g733a5 From 80e81d351d27e7464ea416e13eb06b30fa31e452 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 30 May 2016 12:47:04 +0200 Subject: add version check to the unit tests --- clippy_lints/Cargo.toml | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/utils/cargo.rs | 75 +++++++++++++++++++++++++++++++++++++++++ clippy_lints/src/utils/mod.rs | 1 + src/cargo.rs | 48 -------------------------- src/main.rs | 6 ++-- tests/versioncheck.rs | 16 +++++++++ 7 files changed, 97 insertions(+), 52 deletions(-) create mode 100644 clippy_lints/src/utils/cargo.rs delete mode 100644 src/cargo.rs create mode 100644 tests/versioncheck.rs (limited to 'src') diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index aa994cd7259..c309b7a63e2 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -21,6 +21,7 @@ semver = "0.2.1" toml = "0.1" unicode-normalization = "0.1" quine-mc_cluskey = "0.2.2" +rustc-serialize = "0.3" [features] debugging = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4a5c3a87c8c..944825e2bdc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -36,6 +36,8 @@ extern crate regex_syntax; // for finding minimal boolean expressions extern crate quine_mc_cluskey; +extern crate rustc_serialize; + extern crate rustc_plugin; extern crate rustc_const_eval; extern crate rustc_const_math; diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs new file mode 100644 index 00000000000..c6004864bf0 --- /dev/null +++ b/clippy_lints/src/utils/cargo.rs @@ -0,0 +1,75 @@ +use std::collections::HashMap; +use std::process::Command; +use std::str::{from_utf8, Utf8Error}; +use std::io; +use rustc_serialize::json; + +#[derive(RustcDecodable, Debug)] +pub struct Metadata { + pub packages: Vec<Package>, + resolve: Option<()>, + pub version: usize, +} + +#[derive(RustcDecodable, Debug)] +pub struct Package { + pub name: String, + pub version: String, + id: String, + source: Option<()>, + pub dependencies: Vec<Dependency>, + pub targets: Vec<Target>, + features: HashMap<String, Vec<String>>, + manifest_path: String, +} + +#[derive(RustcDecodable, Debug)] +pub struct Dependency { + pub name: String, + source: Option<String>, + pub req: String, + kind: Option<String>, + optional: bool, + uses_default_features: bool, + features: Vec<HashMap<String, String>>, + target: Option<()>, +} + +#[allow(non_camel_case_types)] +#[derive(RustcDecodable, Debug)] +pub enum Kind { + dylib, + test, + bin, + lib, +} + +#[derive(RustcDecodable, Debug)] +pub struct Target { + pub name: String, + pub kind: Vec<Kind>, + src_path: String, +} + +#[derive(Debug)] +pub enum Error { + Io(io::Error), + Utf8(Utf8Error), + Json(json::DecoderError), +} + +impl From<io::Error> for Error { + fn from(err: io::Error) -> Self { Error::Io(err) } +} +impl From<Utf8Error> for Error { + fn from(err: Utf8Error) -> Self { Error::Utf8(err) } +} +impl From<json::DecoderError> for Error { + fn from(err: json::DecoderError) -> Self { Error::Json(err) } +} + +pub fn metadata() -> Result<Metadata, Error> { + let output = Command::new("cargo").args(&["metadata", "--no-deps"]).output()?; + let stdout = from_utf8(&output.stdout)?; + Ok(json::decode(stdout)?) +} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index c1cbd7ffe93..986462b3723 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -23,6 +23,7 @@ pub mod conf; mod hir; pub mod paths; pub use self::hir::{SpanlessEq, SpanlessHash}; +pub mod cargo; pub type MethodArgs = HirVec<P<Expr>>; diff --git a/src/cargo.rs b/src/cargo.rs deleted file mode 100644 index 188d4d38e8d..00000000000 --- a/src/cargo.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::collections::HashMap; - -#[derive(RustcDecodable, Debug)] -pub struct Metadata { - pub packages: Vec<Package>, - resolve: Option<()>, - pub version: usize, -} - -#[derive(RustcDecodable, Debug)] -pub struct Package { - name: String, - version: String, - id: String, - source: Option<()>, - dependencies: Vec<Dependency>, - pub targets: Vec<Target>, - features: HashMap<String, Vec<String>>, - manifest_path: String, -} - -#[derive(RustcDecodable, Debug)] -pub struct Dependency { - name: String, - source: Option<String>, - req: String, - kind: Option<String>, - optional: bool, - uses_default_features: bool, - features: Vec<HashMap<String, String>>, - target: Option<()>, -} - -#[allow(non_camel_case_types)] -#[derive(RustcDecodable, Debug)] -pub enum Kind { - dylib, - test, - bin, - lib, -} - -#[derive(RustcDecodable, Debug)] -pub struct Target { - pub name: String, - pub kind: Vec<Kind>, - src_path: String, -} diff --git a/src/main.rs b/src/main.rs index 05096e80548..3ad32a54058 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use syntax::diagnostics; use std::path::PathBuf; use std::process::Command; -mod cargo; +use clippy_lints::utils::cargo; struct ClippyCompilerCalls(RustcDefaultCalls); @@ -122,9 +122,7 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let output = std::process::Command::new("cargo").args(&["metadata", "--no-deps"]).output().expect("could not run `cargo metadata`"); - let stdout = std::str::from_utf8(&output.stdout).expect("`cargo metadata` output is not utf8"); - let mut metadata: cargo::Metadata = rustc_serialize::json::decode(stdout).expect("`cargo metadata` output is not valid json"); + let mut metadata = cargo::metadata().expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs new file mode 100644 index 00000000000..b2a2f416a8f --- /dev/null +++ b/tests/versioncheck.rs @@ -0,0 +1,16 @@ +extern crate clippy_lints; +use clippy_lints::utils::cargo; + +#[test] +fn check_that_clippy_lints_has_the_same_version_as_clippy() { + let clippy_meta = cargo::metadata().expect("could not obtain cargo metadata"); + std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); + let clippy_lints_meta = cargo::metadata().expect("could not obtain cargo metadata"); + assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); + for package in &clippy_meta.packages[0].dependencies { + if package.name == "clippy_lints" { + assert_eq!(clippy_lints_meta.packages[0].version, package.req[1..]); + return; + } + } +} -- cgit 1.4.1-3-g733a5 From 7bb8ba46318667da94b1533d371aa28025871a59 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 2 Jun 2016 17:29:25 +0200 Subject: process more kinds of metadata --- clippy_lints/src/utils/cargo.rs | 15 +++------------ src/main.rs | 12 +++++------- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index c6004864bf0..c51cfc7304b 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -16,7 +16,7 @@ pub struct Package { pub name: String, pub version: String, id: String, - source: Option<()>, + source: Option<String>, pub dependencies: Vec<Dependency>, pub targets: Vec<Target>, features: HashMap<String, Vec<String>>, @@ -31,23 +31,14 @@ pub struct Dependency { kind: Option<String>, optional: bool, uses_default_features: bool, - features: Vec<HashMap<String, String>>, + features: Vec<String>, target: Option<()>, } -#[allow(non_camel_case_types)] -#[derive(RustcDecodable, Debug)] -pub enum Kind { - dylib, - test, - bin, - lib, -} - #[derive(RustcDecodable, Debug)] pub struct Target { pub name: String, - pub kind: Vec<Kind>, + pub kind: Vec<String>, src_path: String, } diff --git a/src/main.rs b/src/main.rs index 3ad32a54058..8c9220c7fc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -126,13 +126,11 @@ pub fn main() { assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); - assert_eq!(target.kind.len(), 1); - match &target.kind[..] { - [cargo::Kind::lib] | - [cargo::Kind::dylib] => process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root), - [cargo::Kind::bin] => process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root), - // don't process tests and other stuff - _ => {}, + assert!(!target.kind.is_empty()); + if target.kind.len() > 1 || target.kind[0].ends_with("lib") { + process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root); + } else if target.kind[0] == "bin" { + process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root); } } } else { -- cgit 1.4.1-3-g733a5 From 078cc68c527faa35c52a88aca22e46ee7402f356 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 2 Jun 2016 17:39:28 +0200 Subject: no indexing --- src/main.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 8c9220c7fc2..db0c6613f3f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -126,11 +126,14 @@ pub fn main() { assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); - assert!(!target.kind.is_empty()); - if target.kind.len() > 1 || target.kind[0].ends_with("lib") { - process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root); - } else if target.kind[0] == "bin" { - process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root); + if let Some(first) = target.kind.get(0) { + if target.kind.len() > 1 || first.ends_with("lib") { + process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root); + } else if first == "bin" { + process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root); + } + } else { + panic!("badly formatted cargo metadata: target::kind is an empty array"); } } } else { -- cgit 1.4.1-3-g733a5 From a81181b75854fb23f816dec0e53ceefbb8d22605 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 6 Jun 2016 11:28:09 +0200 Subject: don't abort after successfully linting a target --- src/main.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index db0c6613f3f..75cc507740a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,9 +128,13 @@ pub fn main() { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { - process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root); + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root) { + std::process::exit(code); + } } else if first == "bin" { - process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root); + if let Err(code) = process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { + std::process::exit(code); + } } } else { panic!("badly formatted cargo metadata: target::kind is an empty array"); @@ -152,7 +156,7 @@ pub fn main() { } } -fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) +fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> where P: AsRef<Path>, I: Iterator<Item=String> { let mut args = vec!["rustc".to_owned()]; @@ -178,7 +182,10 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) .spawn().expect("could not run cargo") .wait().expect("failed to wait for cargo?"); - if let Some(code) = exit_status.code() { - std::process::exit(code); + if exit_status.success() { + Ok(()) + } else { + use std::os::unix::process::ExitStatusExt; + Err(exit_status.code().or(exit_status.signal()).unwrap_or(-1)) } } -- cgit 1.4.1-3-g733a5 From 8d5524f1daf9af3c5e6892c5af91bda49e589835 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 6 Jun 2016 16:43:58 +0200 Subject: clippy should work on all systems --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 75cc507740a..a42610e1732 100644 --- a/src/main.rs +++ b/src/main.rs @@ -185,7 +185,6 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> if exit_status.success() { Ok(()) } else { - use std::os::unix::process::ExitStatusExt; - Err(exit_status.code().or(exit_status.signal()).unwrap_or(-1)) + Err(exit_status.code().unwrap_or(-1)) } } -- cgit 1.4.1-3-g733a5 From d7ba66bf44f993e64114e17cc15f1b0d56ae8f70 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 8 Jun 2016 21:48:10 +0200 Subject: Automatically defines the `clippy` feature --- CHANGELOG.md | 3 +++ README.md | 39 +++++++++++++++++++++++---------------- src/main.rs | 7 ++++++- 3 files changed, 32 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ff32fe13f..4009246507c 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.76 — TBD +* `cargo clippy` now automatically defines the `clippy` feature + ## 0.0.75 — 2016-06-08 * Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)* diff --git a/README.md b/README.md index 8f699d2f741..2e40f6ed74c 100644 --- a/README.md +++ b/README.md @@ -245,22 +245,6 @@ similar crates. SYSROOT=/path/to/rustc/sysroot cargo install clippy ``` -### Configuring clippy - -You can add options to `allow`/`warn`/`deny`: - -* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy)]`) - -* all lints using both the `clippy` and `clippy_pedantic` lint groups (`#![deny(clippy)]`, - `#![deny(clippy_pedantic)]`). Note that `clippy_pedantic` contains some very aggressive - lints prone to false positives. - -* only some lints (`#![deny(single_match, box_vec)]`, etc) - -* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc - -Note: `deny` produces errors instead of warnings - ### Running clippy from the command line without installing To have cargo compile your crate with clippy without needing `#![plugin(clippy)]` @@ -321,6 +305,29 @@ You can also specify the path to the configuration file with: To deactivate the “for further information visit *wiki-link*” message you can define the `CLIPPY_DISABLE_WIKI_LINKS` environment variable. +### Allowing/denying lints + +You can add options to `allow`/`warn`/`deny`: + +* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy)]`) + +* all lints using both the `clippy` and `clippy_pedantic` lint groups (`#![deny(clippy)]`, + `#![deny(clippy_pedantic)]`). Note that `clippy_pedantic` contains some very aggressive + lints prone to false positives. + +* only some lints (`#![deny(single_match, box_vec)]`, etc) + +* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc + +Note: `deny` produces errors instead of warnings. + +For convenience, `cargo clippy` automatically defines a `clippy` features. This +lets you set lints level and compile with or without clippy transparently: + +```rust +#[cfg_attr(feature = "clippy", allow(needless_lifetimes))] +``` + ## Link with clippy service `clippy-service` is a rust web initiative providing `rust-clippy` as a web service. diff --git a/src/main.rs b/src/main.rs index a42610e1732..43483e76a0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,11 +141,14 @@ pub fn main() { } } } else { - let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() } else { env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() }; + + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="clippy""#.to_owned()]); + let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); if let Err(err_count) = result { @@ -174,6 +177,8 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> args.push(String::from("--sysroot")); args.push(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); + args.push("--cfg".to_owned()); + args.push(r#"feature="clippy""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = std::process::Command::new("cargo") -- cgit 1.4.1-3-g733a5 From 90453fd893c1f1ad739a8f79516591db1af6d307 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 6 Jun 2016 01:42:39 +0200 Subject: Run rustfmt Only partially apply suggestions. --- clippy_lints/src/arithmetic.rs | 40 +++++-------- clippy_lints/src/array_indexing.rs | 8 +-- clippy_lints/src/assign_ops.rs | 88 +++++++++++++--------------- clippy_lints/src/booleans.rs | 30 +++++----- clippy_lints/src/cyclomatic_complexity.rs | 12 ++-- clippy_lints/src/derive.rs | 6 +- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/functions.rs | 3 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/loops.rs | 14 ++--- clippy_lints/src/matches.rs | 32 +++++----- clippy_lints/src/mem_forget.rs | 2 +- clippy_lints/src/methods.rs | 8 +-- clippy_lints/src/mut_mut.rs | 5 +- clippy_lints/src/needless_borrow.rs | 3 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 14 ++--- clippy_lints/src/no_effect.rs | 16 +++-- clippy_lints/src/non_expressive_names.rs | 22 +++---- clippy_lints/src/regex.rs | 10 +++- clippy_lints/src/unsafe_removed_from_name.rs | 13 ++-- clippy_lints/src/unused_label.rs | 6 +- clippy_lints/src/utils/cargo.rs | 12 +++- clippy_lints/src/utils/hir.rs | 4 +- clippy_lints/src/utils/mod.rs | 7 +-- src/main.rs | 32 ++++++---- tests/cc_seme.rs | 5 +- tests/compile-test.rs | 2 +- tests/consts.rs | 23 ++++---- tests/dogfood.rs | 6 +- tests/issue-825.rs | 2 +- tests/matches.rs | 7 ++- tests/used_underscore_binding_macro.rs | 2 +- 33 files changed, 231 insertions(+), 209 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index be732740442..4481ab403f8 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -38,7 +38,7 @@ declare_restriction_lint! { #[derive(Copy, Clone, Default)] pub struct Arithmetic { - span: Option<Span> + span: Option<Span>, } impl LintPass for Arithmetic { @@ -49,48 +49,36 @@ impl LintPass for Arithmetic { impl LateLintPass for Arithmetic { fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - if let Some(_) = self.span { return; } + if let Some(_) = self.span { + return; + } match expr.node { hir::ExprBinary(ref op, ref l, ref r) => { match op.node { - hir::BiAnd | hir::BiOr | hir::BiBitAnd | - hir::BiBitOr | hir::BiBitXor | hir::BiShl | hir::BiShr | - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | - hir::BiGt => return, - _ => () + hir::BiAnd | hir::BiOr | hir::BiBitAnd | hir::BiBitOr | hir::BiBitXor | hir::BiShl | + hir::BiShr | hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => return, + _ => (), } let (l_ty, r_ty) = (cx.tcx.expr_ty(l), cx.tcx.expr_ty(r)); if l_ty.is_integral() && r_ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, - expr.span, - "integer arithmetic detected"); + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.span = Some(expr.span); } else if l_ty.is_floating_point() && r_ty.is_floating_point() { - span_lint(cx, - FLOAT_ARITHMETIC, - expr.span, - "floating-point arithmetic detected"); + 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.expr_ty(arg); if ty.is_integral() { - span_lint(cx, - INTEGER_ARITHMETIC, - expr.span, - "integer arithmetic detected"); + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.span = Some(expr.span); } else if ty.is_floating_point() { - span_lint(cx, - FLOAT_ARITHMETIC, - expr.span, - "floating-point arithmetic detected"); + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.span = Some(expr.span); } - }, - _ => () + } + _ => (), } } diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index ce2b9a7d6c0..f3b7297b296 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -79,11 +79,11 @@ impl LateLintPass for ArrayIndexing { // Index is a constant range if let Some(range) = utils::unsugar_range(index) { let start = range.start - .map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)) - .map(|v| v.ok()); + .map(|start| eval_const_expr_partial(cx.tcx, start, ExprTypeChecked, None)) + .map(|v| v.ok()); let end = range.end - .map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)) - .map(|v| v.ok()); + .map(|end| eval_const_expr_partial(cx.tcx, end, ExprTypeChecked, None)) + .map(|v| v.ok()); if let Some((start, end)) = to_const_range(start, end, range.limits, size) { if start > size || end > size { diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 2b1aec83e4c..1a5ca16b9c5 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -51,31 +51,24 @@ impl LateLintPass for AssignOps { match expr.node { hir::ExprAssignOp(op, ref lhs, ref rhs) => { if let (Some(l), Some(r)) = (snippet_opt(cx, lhs.span), snippet_opt(cx, rhs.span)) { - span_lint_and_then(cx, - ASSIGN_OPS, - expr.span, - "assign operation detected", - |db| { - match rhs.node { - hir::ExprBinary(op2, _, _) if op2 != op => { - db.span_suggestion(expr.span, - "replace it with", - format!("{} = {} {} ({})", l, l, op.node.as_str(), r)); - }, - _ => { - db.span_suggestion(expr.span, - "replace it with", - format!("{} = {} {} {}", l, l, op.node.as_str(), r)); - } - } - }); + span_lint_and_then(cx, ASSIGN_OPS, expr.span, "assign operation detected", |db| { + match rhs.node { + hir::ExprBinary(op2, _, _) if op2 != op => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} ({})", l, l, op.node.as_str(), r)); + } + _ => { + db.span_suggestion(expr.span, + "replace it with", + format!("{} = {} {} {}", l, l, op.node.as_str(), r)); + } + } + }); } else { - span_lint(cx, - ASSIGN_OPS, - expr.span, - "assign operation detected"); + span_lint(cx, ASSIGN_OPS, expr.span, "assign operation detected"); } - }, + } 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| { @@ -104,28 +97,32 @@ impl LateLintPass for AssignOps { } } } - if ops!(op.node, cx, ty, rty, Add:BiAdd, - Sub:BiSub, - Mul:BiMul, - Div:BiDiv, - Rem:BiRem, - And:BiAnd, - Or:BiOr, - BitAnd:BiBitAnd, - BitOr:BiBitOr, - BitXor:BiBitXor, - Shr:BiShr, - Shl:BiShl - ) { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) { + if ops!(op.node, + cx, + ty, + rty, + Add: BiAdd, + Sub: BiSub, + Mul: BiMul, + Div: BiDiv, + Rem: BiRem, + And: BiAnd, + Or: BiOr, + BitAnd: BiBitAnd, + BitOr: BiBitOr, + BitXor: BiBitXor, + Shr: BiShr, + Shl: BiShl) { + if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), + snippet_opt(cx, rhs.span)) { span_lint_and_then(cx, ASSIGN_OP_PATTERN, expr.span, "manual implementation of an assign operation", |db| { db.span_suggestion(expr.span, - "replace it with", - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); + "replace it with", + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); }); } else { span_lint(cx, @@ -142,17 +139,16 @@ impl LateLintPass for AssignOps { // a = b commutative_op a if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { match op.node { - hir::BiAdd | hir::BiMul | - hir::BiAnd | hir::BiOr | - hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr => { + hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd | + hir::BiBitOr => { lint(assignee, l); - }, - _ => {}, + } + _ => {} } } } - }, - _ => {}, + } + _ => {} } } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 9ab806f66ec..8b7952b3746 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -322,7 +322,8 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { let simplified_stats = terminal_stats(suggestion); let mut improvement = false; for i in 0..32 { - // ignore any "simplifications" that end up requiring a terminal more often than in the original expression + // ignore any "simplifications" that end up requiring a terminal more often + // than in the original expression if stats.terminals[i] < simplified_stats.terminals[i] { continue 'simplified; } @@ -332,17 +333,18 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { e.span, "this boolean expression contains a logic bug", |db| { - db.span_help(h2q.terminals[i].span, - "this expression can be optimized out by applying \ - boolean operations to the outer expression"); - db.span_suggestion(e.span, - "it would look like the following", - suggest(self.0, suggestion, &h2q.terminals)); - }); + db.span_help(h2q.terminals[i].span, + "this expression can be optimized out by applying boolean operations to the \ + outer expression"); + db.span_suggestion(e.span, + "it would look like the following", + suggest(self.0, suggestion, &h2q.terminals)); + }); // don't also lint `NONMINIMAL_BOOL` return; } - // if the number of occurrences of a terminal decreases or any of the stats decreases while none increases + // if the number of occurrences of a terminal decreases or any of the stats + // decreases while none increases improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || @@ -358,12 +360,10 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { 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)); - } - }); + for suggestion in &improvements { + db.span_suggestion(e.span, "try", suggest(self.0, suggestion, &h2q.terminals)); + } + }); } } } diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index 8ae0d2c97c5..038d888b0ae 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -13,7 +13,8 @@ use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type}; /// **What it does:** This lint checks for methods with high cyclomatic complexity /// -/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better. +/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM +/// will usually optimize small methods better. /// /// **Known problems:** Sometimes it's hard to find a way to reduce the complexity /// @@ -69,7 +70,7 @@ impl CyclomaticComplexity { returns / 2 }; - if cc + divergence < match_arms + short_circuits { + if cc + divergence < match_arms + short_circuits { report_cc_bug(cx, cc, match_arms, divergence, short_circuits, ret_adjust, span); } else { let mut rust_cc = cc + divergence - match_arms - short_circuits; @@ -117,7 +118,7 @@ impl LateLintPass for CyclomaticComplexity { } } -struct CCHelper<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct CCHelper<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { match_arms: u64, divergence: u64, returns: u64, @@ -176,8 +177,9 @@ fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, r if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { cx.sess().span_note_without_error(span, &format!("Clippy encountered a bug calculating cyclomatic complexity \ - (hide this message with `#[allow(cyclomatic_complexity)]`): cc \ - = {}, arms = {}, div = {}, shorts = {}, returns = {}. Please file a bug report.", + (hide this message with `#[allow(cyclomatic_complexity)]`): \ + cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \ + Please file a bug report.", cc, narms, div, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index b941d9a7fca..5d1eb267343 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -84,7 +84,8 @@ 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: 'a>(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), let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() @@ -137,7 +138,8 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref // Some types are not Clone by default but could be cloned `by hand` if necessary match ty.sty { - TypeVariants::TyEnum(def, substs) | TypeVariants::TyStruct(def, substs) => { + TypeVariants::TyEnum(def, substs) | + TypeVariants::TyStruct(def, substs) => { for variant in &def.variants { for field in &variant.fields { match field.ty(cx.tcx, substs).sty { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index af1fbaa0f7d..fc9e95f9495 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -108,7 +108,7 @@ pub fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(&str, Span /// First byte of the current potential match current_word_begin: usize, /// List of lines and their associated span - docs: &'a[(&'a str, Span)], + docs: &'a [(&'a str, Span)], /// Index of the current line we are parsing line: usize, /// Whether we are in a link diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index d9334447226..3d3423a4743 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -42,7 +42,8 @@ impl LintPass for Functions { } impl LateLintPass for Functions { - fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) { + fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, + nodeid: ast::NodeId) { use rustc::hir::map::Node::*; if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 2f98d10dee0..ac6bee00ff5 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -182,7 +182,7 @@ fn used_in_expr(cx: &LateContext, id: hir::def_id::DefId, expr: &hir::Expr) -> b let mut v = UsedVisitor { cx: cx, id: id, - used: false + used: false, }; hir::intravisit::walk_expr(&mut v, expr); v.used diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5d431e47465..08978e2c5a0 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -608,13 +608,13 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex expr.span, &format!("you seem to want to iterate on a map's {}", kind), |db| { - db.span_suggestion(expr.span, - "use the corresponding method", - format!("for {} in {}.{}() {{ .. }}", - snippet(cx, *pat_span, ".."), - snippet(cx, arg_span, ".."), - kind)); - }); + db.span_suggestion(expr.span, + "use the corresponding method", + format!("for {} in {}.{}() {{ .. }}", + snippet(cx, *pat_span, ".."), + snippet(cx, arg_span, ".."), + kind)); + }); } } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 46bd251016b..d80f9f3d587 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -171,14 +171,14 @@ fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], "you seem to be trying to use match for destructuring a single pattern. \ Consider using `if let`", |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); } } @@ -219,14 +219,14 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: "you seem to be trying to use match for destructuring a single pattern. Consider \ using `if let`", |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); } } } diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 1f627d614ff..4dfb0fe88e0 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -33,7 +33,7 @@ impl LateLintPass for MemForget { if match forgot_ty.ty_adt_def() { Some(def) => def.has_dtor(), - _ => false + _ => false, } { span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index c37fbba9250..9dcc8f9d016 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -452,8 +452,8 @@ impl LateLintPass for MethodsPass { explicit_self.span, "methods called `new` usually return `Self`"); } - } - }} + }} + } } } } @@ -1022,9 +1022,7 @@ impl OutType { (&OutType::Unit, &hir::Return(ref ty)) if ty.node == hir::TyTup(vec![].into()) => true, (&OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true, (&OutType::Any, &hir::Return(ref ty)) if ty.node != hir::TyTup(vec![].into()) => true, - (&OutType::Ref, &hir::Return(ref ty)) => { - matches!(ty.node, hir::TyRptr(_, _)) - } + (&OutType::Ref, &hir::Return(ref ty)) => matches!(ty.node, hir::TyRptr(_, _)), _ => false, } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 4147e288c4f..0bed45b0b5b 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -34,10 +34,7 @@ impl LateLintPass for MutMut { if let ExprAddrOf(MutMutable, ref e) = expr.node { if let ExprAddrOf(MutMutable, _) = e.node { - span_lint(cx, - MUT_MUT, - expr.span, - "generally you want to avoid `&mut &mut _` if possible"); + span_lint(cx, MUT_MUT, expr.span, "generally you want to avoid `&mut &mut _` if possible"); } else { if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty { span_lint(cx, diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 033811841ce..356a46c28c3 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -42,7 +42,8 @@ impl LateLintPass for NeedlessBorrow { span_lint(cx, NEEDLESS_BORROW, e.span, - "this expression borrows a reference that is immediately dereferenced by the compiler"); + "this expression borrows a reference that is immediately dereferenced by the \ + compiler"); } } } diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index fb986409a41..c661fad2c02 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -35,7 +35,7 @@ impl LateLintPass for NegMultiply { (&ExprUnary(..), &ExprUnary(..)) => (), (&ExprUnary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r), (_, &ExprUnary(UnNeg, ref lit)) => check_mul(cx, e.span, lit, l), - _ => () + _ => (), } } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index dfaefb39ba0..f400f1b6643 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -100,10 +100,10 @@ impl LateLintPass for NewWithoutDefault { // can't be implemented by default return; } - if decl.inputs.is_empty() && name.as_str() == "new" && - cx.access_levels.is_reachable(id) { - let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id( - cx.tcx.map.get_parent(id))).ty; + if decl.inputs.is_empty() && name.as_str() == "new" && cx.access_levels.is_reachable(id) { + let self_ty = cx.tcx + .lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))) + .ty; if_let_chain!{[ self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics let Some(ret_ty) = return_ty(cx, id), @@ -143,11 +143,11 @@ fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_ for field in adt_def.all_fields() { let f_ty = field.ty(cx.tcx, substs); if !implements_trait(cx, f_ty, default_trait_id, Vec::new()) { - return false + return false; } } true - }, - _ => false + } + _ => false, } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index ae3bac00455..a9ac0a24856 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -130,7 +130,9 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp Expr_::ExprTupField(ref inner, _) | Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprBox(ref inner) => 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_::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(..)) | @@ -140,11 +142,13 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp } Expr_::ExprBlock(ref block) => { if block.stmts.is_empty() { - block.expr.as_ref().and_then(|e| match block.rules { - BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None, - BlockCheckMode::DefaultBlock => Some(vec![&**e]), - // in case of compiler-inserted signaling blocks - _ => reduce_expression(cx, e), + block.expr.as_ref().and_then(|e| { + match block.rules { + BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => None, + BlockCheckMode::DefaultBlock => Some(vec![&**e]), + // in case of compiler-inserted signaling blocks + _ => reduce_expression(cx, e), + } }) } else { None diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index cbb083a3e16..aa8608fb7bd 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -72,11 +72,13 @@ impl<'v, 'a, 'b, 'c> Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { fn visit_pat(&mut self, pat: &'v Pat) { match pat.node { PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), - PatKind::Struct(_, ref fields, _) => for field in fields { - if !field.node.is_shorthand { - self.visit_pat(&field.node.pat); + PatKind::Struct(_, ref fields, _) => { + for field in fields { + if !field.node.is_shorthand { + self.visit_pat(&field.node.pat); + } } - }, + } _ => walk_pat(self, pat), } } @@ -193,15 +195,15 @@ impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> { span, "binding's name is too similar to existing binding", |diag| { - diag.span_note(existing_name.span, "existing binding defined here"); - if let Some(split) = split_at { - diag.span_help(span, - &format!("separate the discriminating character by an \ + diag.span_note(existing_name.span, "existing binding defined here"); + if let Some(split) = split_at { + diag.span_help(span, + &format!("separate the discriminating character by an \ underscore like: `{}_{}`", &interned_name[..split], &interned_name[split..])); - } - }); + } + }); return; } self.0.names.push(ExistingName { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index c97a64ebf09..fb59c8c61d3 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -125,7 +125,7 @@ impl LateLintPass for RegexPass { fn str_span(base: Span, s: &str, c: usize) -> Span { let mut si = s.char_indices().skip(c); - match (si.next(), si.next()) { + match (si.next(), si.next()) { (Some((l, _)), Some((h, _))) => { Span { lo: base.lo + BytePos(l as u32), @@ -193,7 +193,9 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { match builder.parse(r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + span_help_and_lint(cx, + TRIVIAL_REGEX, + expr.span, "trivial regex", &format!("consider using {}", repl)); } @@ -211,7 +213,9 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { match builder.parse(&r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, + span_help_and_lint(cx, + TRIVIAL_REGEX, + expr.span, "trivial regex", &format!("consider using {}", repl)); } diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 3de6719c546..116e1eb1bdc 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -45,7 +45,7 @@ impl LateLintPass for UnsafeNameRemoval { *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; @@ -53,7 +53,7 @@ impl LateLintPass for UnsafeNameRemoval { unsafe_to_safe_check(name, rename, cx, &item.span); }; } - }, + } ViewPath_::ViewPathGlob(_) => {} } } @@ -64,11 +64,10 @@ fn unsafe_to_safe_check(old_name: Name, new_name: Name, cx: &LateContext, span: let old_str = old_name.as_str(); let new_str = new_name.as_str(); if contains_unsafe(&old_str) && !contains_unsafe(&new_str) { - span_lint( - cx, - UNSAFE_REMOVED_FROM_NAME, - *span, - &format!( + span_lint(cx, + UNSAFE_REMOVED_FROM_NAME, + *span, + &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 6539b835dc7..a97b593095f 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -64,10 +64,12 @@ impl LateLintPass for UnusedLabel { impl<'v> Visitor<'v> for UnusedLabelVisitor { fn visit_expr(&mut self, expr: &hir::Expr) { match expr.node { - hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { + hir::ExprBreak(Some(label)) | + hir::ExprAgain(Some(label)) => { self.labels.remove(&label.node.as_str()); } - hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { + hir::ExprLoop(_, Some(label)) | + hir::ExprWhile(_, _, Some(label)) => { self.labels.insert(label.node.as_str(), expr.span); } _ => (), diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index b183db84d57..f81fcbc38ab 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -50,13 +50,19 @@ pub enum Error { } impl From<io::Error> for Error { - fn from(err: io::Error) -> Self { Error::Io(err) } + fn from(err: io::Error) -> Self { + Error::Io(err) + } } impl From<Utf8Error> for Error { - fn from(err: Utf8Error) -> Self { Error::Utf8(err) } + fn from(err: Utf8Error) -> Self { + Error::Utf8(err) + } } impl From<json::DecoderError> for Error { - fn from(err: json::DecoderError) -> Self { Error::Json(err) } + fn from(err: json::DecoderError) -> Self { + Error::Json(err) + } } pub fn metadata() -> Result<Metadata, Error> { diff --git a/clippy_lints/src/utils/hir.rs b/clippy_lints/src/utils/hir.rs index e9c4023e226..88a9e03182c 100644 --- a/clippy_lints/src/utils/hir.rs +++ b/clippy_lints/src/utils/hir.rs @@ -153,7 +153,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { self.eq_qself(ls, rs) && self.eq_path(lp, rp) } - (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(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) } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index beec30b32de..5c61a33cec0 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -143,9 +143,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool { } } - let mut apb = AbsolutePathBuffer { - names: vec![], - }; + let mut apb = AbsolutePathBuffer { names: vec![] }; cx.tcx.push_item_path(&mut apb, def_id); @@ -763,7 +761,8 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> { end: None, limits: RangeLimits::HalfOpen, }) - } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { + } else if match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY_STD) || + match_path(path, &paths::RANGE_INCLUSIVE_NON_EMPTY) { Some(UnsugaredRange { start: get_field("start", fields), end: get_field("end", fields), diff --git a/src/main.rs b/src/main.rs index 43483e76a0f..041b828e016 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,7 +71,13 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { registry.args_hidden = Some(Vec::new()); clippy_lints::register_plugins(&mut registry); - let rustc_plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry; + let rustc_plugin::registry::Registry { early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + mir_passes, + .. } = registry; let sess = &state.session; let mut ls = sess.lint_store.borrow_mut(); for pass in early_lint_passes { @@ -111,14 +117,18 @@ pub fn main() { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); let sys_root = match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("SYSROOT").map(|s| s.to_owned()) - .or(Command::new("rustc").arg("--print") - .arg("sysroot") - .output().ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - ) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"), + _ => { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or(Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned())) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") + } }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { @@ -160,7 +170,9 @@ pub fn main() { } fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> - where P: AsRef<Path>, I: Iterator<Item=String> { + where P: AsRef<Path>, + I: Iterator<Item = String> +{ let mut args = vec!["rustc".to_owned()]; diff --git a/tests/cc_seme.rs b/tests/cc_seme.rs index cc02853c70a..df2579cab57 100644 --- a/tests/cc_seme.rs +++ b/tests/cc_seme.rs @@ -14,7 +14,10 @@ struct Test { fn main() { use Baz::*; - let x = Test { t: Some(0), b: One }; + let x = Test { + t: Some(0), + b: One, + }; match x { Test { t: Some(_), b: One } => unreachable!(), diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 42a7dd96ae2..2e50f7d9241 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -9,7 +9,7 @@ fn run_mode(dir: &'static str, mode: &'static str) { let cfg_mode = mode.parse().ok().expect("Invalid mode"); config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps".to_owned()); if let Ok(name) = var::<&str>("TESTNAME") { - let s : String = name.to_owned(); + let s: String = name.to_owned(); config.filter = Some(s) } diff --git a/tests/consts.rs b/tests/consts.rs index 4b3aba3f6be..81500f9d393 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -16,15 +16,18 @@ use syntax::parse::token::InternedString; use syntax::ptr::P; fn spanned<T>(t: T) -> Spanned<T> { - Spanned{ node: t, span: COMMAND_LINE_SP } + Spanned { + node: t, + span: COMMAND_LINE_SP, + } } fn expr(n: Expr_) -> Expr { - Expr{ + Expr { id: 1, node: n, span: COMMAND_LINE_SP, - attrs: None + attrs: None, } } @@ -40,19 +43,19 @@ fn check(expect: Constant, expr: &Expr) { assert_eq!(Some(expect), constant_simple(expr)) } -const TRUE : Constant = Constant::Bool(true); -const FALSE : Constant = Constant::Bool(false); -const ZERO : Constant = Constant::Int(ConstInt::Infer(0)); -const ONE : Constant = Constant::Int(ConstInt::Infer(1)); -const TWO : Constant = Constant::Int(ConstInt::Infer(2)); +const TRUE: Constant = Constant::Bool(true); +const FALSE: Constant = Constant::Bool(false); +const ZERO: Constant = Constant::Int(ConstInt::Infer(0)); +const ONE: Constant = Constant::Int(ConstInt::Infer(1)); +const TWO: Constant = Constant::Int(ConstInt::Infer(2)); #[test] fn test_lit() { check(TRUE, &lit(LitKind::Bool(true))); check(FALSE, &lit(LitKind::Bool(false))); check(ZERO, &lit(LitKind::Int(0, LitIntType::Unsuffixed))); - check(Constant::Str("cool!".into(), StrStyle::Cooked), &lit(LitKind::Str( - InternedString::new("cool!"), StrStyle::Cooked))); + check(Constant::Str("cool!".into(), StrStyle::Cooked), + &lit(LitKind::Str(InternedString::new("cool!"), StrStyle::Cooked))); } #[test] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 5121fd08628..821279d909c 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -30,11 +30,7 @@ fn dogfood() { config.mode = cfg_mode; - let files = [ - "src/main.rs", - "src/lib.rs", - "clippy_lints/src/lib.rs", - ]; + let files = ["src/main.rs", "src/lib.rs", "clippy_lints/src/lib.rs"]; for file in &files { let paths = TestPaths { diff --git a/tests/issue-825.rs b/tests/issue-825.rs index f5c0725f812..76b0250ca0e 100644 --- a/tests/issue-825.rs +++ b/tests/issue-825.rs @@ -22,4 +22,4 @@ fn rust_type_id(name: String) { } } -fn main() {} \ No newline at end of file +fn main() {} diff --git a/tests/matches.rs b/tests/matches.rs index 03cc5281741..74433fc1f56 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -9,7 +9,12 @@ fn test_overlapping() { use clippy::matches::overlapping; use syntax::codemap::DUMMY_SP; - let sp = |s, e| clippy::matches::SpannedRange { span: DUMMY_SP, node: (s, e) }; + let sp = |s, e| { + clippy::matches::SpannedRange { + span: DUMMY_SP, + node: (s, e), + } + }; assert_eq!(None, overlapping::<u8>(&[])); assert_eq!(None, overlapping(&[sp(1, 4)])); diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs index 7a8faa62742..9cd44d44001 100644 --- a/tests/used_underscore_binding_macro.rs +++ b/tests/used_underscore_binding_macro.rs @@ -12,5 +12,5 @@ struct MacroAttributesTest { #[test] fn macro_attributes_test() { - let _ = MacroAttributesTest{_foo: 0}; + let _ = MacroAttributesTest { _foo: 0 }; } -- cgit 1.4.1-3-g733a5 From 11665a0d79c0413e0e3147b036e206a976a1f897 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 6 Jun 2016 01:53:21 +0200 Subject: Dogfood --- src/main.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 041b828e016..fb2fffab67d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,20 +115,19 @@ pub fn main() { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => { - option_env!("SYSROOT") - .map(|s| s.to_owned()) - .or(Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned())) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - } + let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or(Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned())) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { -- cgit 1.4.1-3-g733a5 From 489576437d5c72029c7af77fc6921b5946cd22e6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 6 Jun 2016 17:09:51 +0200 Subject: Cleanup dependencies and features --- Cargo.toml | 7 +------ clippy_lints/src/lib.rs | 15 +++++++-------- src/lib.rs | 46 +++------------------------------------------- src/main.rs | 2 -- 4 files changed, 11 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 1ea542c7737..12c74b653e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,21 +23,16 @@ name = "cargo-clippy" test = false [dependencies] -regex-syntax = "0.3.0" regex_macros = { version = "0.1.33", optional = true } -semver = "0.2.1" -toml = "0.1" -unicode-normalization = "0.1" -quine-mc_cluskey = "0.2.2" # begin automatic update clippy_lints = { version = "0.0.75", path = "clippy_lints" } # end automatic update -rustc-serialize = "0.3" [dev-dependencies] compiletest_rs = "0.2.0" lazy_static = "0.1.15" regex = "0.1.56" +rustc-serialize = "0.3" [features] debugging = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 857e11b0bd3..42a35e7009b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,17 +1,16 @@ // error-pattern:cargo-clippy -#![feature(type_macros)] -#![feature(plugin_registrar, box_syntax)] -#![feature(rustc_private, collections)] -#![feature(iter_arith)] +#![feature(box_syntax)] +#![feature(collections)] #![feature(custom_attribute)] -#![feature(slice_patterns)] +#![feature(iter_arith)] #![feature(question_mark)] +#![feature(rustc_private)] +#![feature(slice_patterns)] #![feature(stmt_expr_attributes)] -#![allow(indexing_slicing, shadow_reuse, unknown_lints)] +#![feature(type_macros)] -extern crate rustc_driver; -extern crate getopts; +#![allow(indexing_slicing, shadow_reuse, unknown_lints)] #[macro_use] extern crate syntax; diff --git a/src/lib.rs b/src/lib.rs index f9a6588e904..f5229d3cb39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,55 +1,15 @@ // error-pattern:cargo-clippy -#![feature(type_macros)] -#![feature(plugin_registrar, box_syntax)] -#![feature(rustc_private, collections)] -#![feature(custom_attribute)] -#![feature(slice_patterns)] -#![feature(question_mark)] -#![feature(stmt_expr_attributes)] -#![allow(indexing_slicing, shadow_reuse, unknown_lints)] - -#[macro_use] -extern crate syntax; -#[macro_use] -extern crate rustc; - -extern crate toml; - -// Only for the compile time checking of paths -extern crate core; -extern crate collections; - -// for unicode nfc normalization -extern crate unicode_normalization; - -// for semver check in attrs.rs -extern crate semver; - -// for regex checking -extern crate regex_syntax; - -// for finding minimal boolean expressions -extern crate quine_mc_cluskey; +#![feature(plugin_registrar)] +#![feature(rustc_private)] +#![allow(unknown_lints)] extern crate rustc_plugin; -extern crate rustc_const_eval; -extern crate rustc_const_math; use rustc_plugin::Registry; extern crate clippy_lints; pub use clippy_lints::*; -macro_rules! declare_restriction_lint { - { pub $name:tt, $description:tt } => { - declare_lint! { pub $name, Allow, $description } - }; -} - -mod reexport { - pub use syntax::ast::{Name, NodeId}; -} - #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { register_plugins(reg); diff --git a/src/main.rs b/src/main.rs index fb2fffab67d..de3361d514f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(slice_patterns)] extern crate rustc_driver; extern crate getopts; @@ -9,7 +8,6 @@ extern crate rustc; extern crate syntax; extern crate rustc_plugin; extern crate clippy_lints; -extern crate rustc_serialize; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session}; -- cgit 1.4.1-3-g733a5 From b31bebeea4b7ae1a1312049745649d8d2c89c0f4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 21 Jun 2016 11:35:34 +0200 Subject: fix cargo clippy when using with `--manifest-path` --- clippy_lints/src/utils/cargo.rs | 9 +++++++-- src/main.rs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index f81fcbc38ab..48a97f2f1fc 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -65,8 +65,13 @@ impl From<json::DecoderError> for Error { } } -pub fn metadata() -> Result<Metadata, Error> { - let output = Command::new("cargo").args(&["metadata", "--no-deps"]).output()?; +pub fn metadata(manifest_path: Option<String>) -> Result<Metadata, Error> { + let mut cmd = Command::new("cargo"); + cmd.arg("metadata").arg("--no-deps"); + if let Some(ref mani) = manifest_path { + cmd.arg(mani); + } + let output = cmd.output()?; let stdout = from_utf8(&output.stdout)?; Ok(json::decode(stdout)?) } diff --git a/src/main.rs b/src/main.rs index de3361d514f..cf57926440b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,7 +129,8 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let mut metadata = cargo::metadata().expect("could not obtain cargo metadata"); + let manifest_path = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); + let mut metadata = cargo::metadata(manifest_path).expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); -- cgit 1.4.1-3-g733a5 From 5b1d849c7e1df0b413237d7a0a0a70c2cbfd52e9 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Tue, 21 Jun 2016 15:24:04 +0530 Subject: Revert "fix cargo clippy when using with `--manifest-path`" This reverts commit b31bebeea4b7ae1a1312049745649d8d2c89c0f4. --- clippy_lints/src/utils/cargo.rs | 9 ++------- src/main.rs | 3 +-- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index 48a97f2f1fc..f81fcbc38ab 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -65,13 +65,8 @@ impl From<json::DecoderError> for Error { } } -pub fn metadata(manifest_path: Option<String>) -> Result<Metadata, Error> { - let mut cmd = Command::new("cargo"); - cmd.arg("metadata").arg("--no-deps"); - if let Some(ref mani) = manifest_path { - cmd.arg(mani); - } - let output = cmd.output()?; +pub fn metadata() -> Result<Metadata, Error> { + let output = Command::new("cargo").args(&["metadata", "--no-deps"]).output()?; let stdout = from_utf8(&output.stdout)?; Ok(json::decode(stdout)?) } diff --git a/src/main.rs b/src/main.rs index cf57926440b..de3361d514f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,8 +129,7 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let manifest_path = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = cargo::metadata(manifest_path).expect("could not obtain cargo metadata"); + let mut metadata = cargo::metadata().expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); -- cgit 1.4.1-3-g733a5 From 36c5026c48f1beed77cb4bfacc37d798c1b505a2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 21 Jun 2016 12:31:30 +0200 Subject: fix cargo clippy when using with `--manifest-path` --- clippy_lints/src/utils/cargo.rs | 9 +++++++-- src/main.rs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index f81fcbc38ab..48a97f2f1fc 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -65,8 +65,13 @@ impl From<json::DecoderError> for Error { } } -pub fn metadata() -> Result<Metadata, Error> { - let output = Command::new("cargo").args(&["metadata", "--no-deps"]).output()?; +pub fn metadata(manifest_path: Option<String>) -> Result<Metadata, Error> { + let mut cmd = Command::new("cargo"); + cmd.arg("metadata").arg("--no-deps"); + if let Some(ref mani) = manifest_path { + cmd.arg(mani); + } + let output = cmd.output()?; let stdout = from_utf8(&output.stdout)?; Ok(json::decode(stdout)?) } diff --git a/src/main.rs b/src/main.rs index de3361d514f..cf57926440b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -129,7 +129,8 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - let mut metadata = cargo::metadata().expect("could not obtain cargo metadata"); + let manifest_path = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); + let mut metadata = cargo::metadata(manifest_path).expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); for target in metadata.packages.remove(0).targets { let args = std::env::args().skip(2); -- cgit 1.4.1-3-g733a5 From e4dceef7e79c96c4ddeffd59a2c532bd239f98a6 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Wed, 29 Jun 2016 13:58:07 +0200 Subject: Revert "Automatically defines the `clippy` feature" This reverts commit d7ba66bf44f993e64114e17cc15f1b0d56ae8f70. It was causing problems with crates with: ```rust #![cfg_attr(feature="clippy", plugin(clippy))] ``` --- CHANGELOG.md | 2 ++ README.md | 7 ------- src/main.rs | 7 +------ 3 files changed, 3 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index a71b410a5f6..168d7a12065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. ## 0.0.78 - TBA * New lints: [`wrong_transmute`] +* For compatibility, `cargo clippy` does not defines the `clippy` feature + introduced in 0.0.76 anymore ## 0.0.77 — 2016-06-21 * Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)* diff --git a/README.md b/README.md index 5096ee953b2..2f54835d538 100644 --- a/README.md +++ b/README.md @@ -326,13 +326,6 @@ You can add options to `allow`/`warn`/`deny`: Note: `deny` produces errors instead of warnings. -For convenience, `cargo clippy` automatically defines a `clippy` features. This -lets you set lints level and compile with or without clippy transparently: - -```rust -#[cfg_attr(feature = "clippy", allow(needless_lifetimes))] -``` - ## Link with clippy service `clippy-service` is a rust web initiative providing `rust-clippy` as a web service. diff --git a/src/main.rs b/src/main.rs index cf57926440b..17a219cafa0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -149,14 +149,11 @@ pub fn main() { } } } else { - let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() } else { env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() }; - - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="clippy""#.to_owned()]); - let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); if let Err(err_count) = result { @@ -187,8 +184,6 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> args.push(String::from("--sysroot")); args.push(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); - args.push("--cfg".to_owned()); - args.push(r#"feature="clippy""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = std::process::Command::new("cargo") -- cgit 1.4.1-3-g733a5 From 3c4af496621cbd5a2a89b2532a2e5f3338cdddf1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 28 Jun 2016 15:54:23 +0200 Subject: Rustup to ea0dc9297283daff6486807f43e190b4eb561412 --- clippy_lints/src/booleans.rs | 3 ++- clippy_lints/src/formatting.rs | 12 ++---------- clippy_lints/src/items_after_statements.rs | 31 ++++++++++++++---------------- clippy_lints/src/misc_early.rs | 15 +++++++-------- clippy_lints/src/non_expressive_names.rs | 14 +++++++------- clippy_lints/src/returns.rs | 21 ++++++++++---------- mini-macro/src/lib.rs | 2 +- src/main.rs | 12 ++++++------ tests/compile-fail/formatting.rs | 16 ++++++++++++++- tests/compile-fail/item_after_statement.rs | 10 ++++++++++ tests/compile-fail/needless_bool.rs | 18 ++++++++--------- tests/consts.rs | 3 ++- 12 files changed, 86 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 8b7952b3746..672dee77783 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -3,6 +3,7 @@ use rustc::hir::*; use rustc::hir::intravisit::*; use syntax::ast::{LitKind, DUMMY_NODE_ID}; use syntax::codemap::{DUMMY_SP, dummy_spanned}; +use syntax::util::ThinVec; use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; /// **What it does:** This lint checks for boolean expressions that can be written more concisely @@ -99,7 +100,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { Expr { id: DUMMY_NODE_ID, span: DUMMY_SP, - attrs: None, + attrs: ThinVec::new(), node: ExprBinary(dummy_spanned(op), lhs.clone(), rhs.clone()), } }; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index aa6dd46cf0b..930fd7ae9a6 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -59,21 +59,13 @@ impl EarlyLintPass for Formatting { fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { for w in block.stmts.windows(2) { match (&w[0].node, &w[1].node) { - (&ast::StmtKind::Expr(ref first, _), &ast::StmtKind::Expr(ref second, _)) | - (&ast::StmtKind::Expr(ref first, _), &ast::StmtKind::Semi(ref second, _)) => { + (&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); } _ => (), } } - - if let Some(ref expr) = block.expr { - if let Some(ref stmt) = block.stmts.iter().last() { - if let ast::StmtKind::Expr(ref first, _) = stmt.node { - check_consecutive_ifs(cx, first, expr); - } - } - } } fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 2e6b33ab390..0afc2e8f7ce 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::in_macro; +use utils::{in_macro, span_lint}; /// **What it does:** This lints checks for items declared after some statement in a block /// @@ -44,26 +44,23 @@ impl EarlyLintPass for ItemsAfterStatements { if in_macro(cx, item.span) { return; } - let mut stmts = item.stmts.iter().map(|stmt| &stmt.node); + // skip initial items - while let Some(&StmtKind::Decl(ref decl, _)) = stmts.next() { - if let DeclKind::Local(_) = decl.node { - break; - } - } + 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 { - if let StmtKind::Decl(ref decl, _) = *stmt { - if let DeclKind::Item(ref it) = decl.node { - if in_macro(cx, it.span) { - return; - } - cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, - it.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope") - .emit(); + if let StmtKind::Item(ref it) = *stmt { + if in_macro(cx, it.span) { + return; } + span_lint(cx, + ITEMS_AFTER_STATEMENTS, + it.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope"); } } } diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index e382b7dc5f6..45964cf3ce7 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -171,15 +171,14 @@ impl EarlyLintPass for MiscEarly { fn check_block(&mut self, cx: &EarlyContext, block: &Block) { for w in block.stmts.windows(2) { if_let_chain! {[ - let StmtKind::Decl(ref first, _) = w[0].node, - let DeclKind::Local(ref local) = first.node, + let StmtKind::Local(ref local) = w[0].node, let Option::Some(ref t) = local.init, - let ExprKind::Closure(_,_,_,_) = t.node, - let PatKind::Ident(_,sp_ident,_) = local.pat.node, - let StmtKind::Semi(ref second,_) = w[1].node, - let ExprKind::Assign(_,ref call) = second.node, - let ExprKind::Call(ref closure,_) = call.node, - let ExprKind::Path(_,ref path) = closure.node + let ExprKind::Closure(_, _, _, _) = t.node, + let PatKind::Ident(_, sp_ident, _) = local.pat.node, + let StmtKind::Semi(ref second) = w[1].node, + let ExprKind::Assign(_, ref call) = second.node, + let ExprKind::Call(ref closure, _) = call.node, + 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"); diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index aa8608fb7bd..17f12afcaec 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -68,8 +68,8 @@ const WHITELIST: &'static [&'static [&'static str]] = &[ struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>); -impl<'v, 'a, 'b, 'c> Visitor<'v> for SimilarNamesNameVisitor<'a, 'b, 'c> { - fn visit_pat(&mut self, pat: &'v Pat) { +impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> { + fn visit_pat(&mut self, pat: &Pat) { match pat.node { PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name), PatKind::Struct(_, ref fields, _) => { @@ -226,25 +226,25 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> { } } -impl<'v, 'a, 'b> Visitor<'v> for SimilarNamesLocalVisitor<'a, 'b> { - fn visit_local(&mut self, local: &'v Local) { +impl<'a, 'b> Visitor for SimilarNamesLocalVisitor<'a, 'b> { + fn visit_local(&mut self, local: &Local) { if let Some(ref init) = local.init { self.apply(|this| walk_expr(this, &**init)); } // add the pattern after the expression because the bindings aren't available yet in the init expression SimilarNamesNameVisitor(self).visit_pat(&*local.pat); } - fn visit_block(&mut self, blk: &'v Block) { + fn visit_block(&mut self, blk: &Block) { self.apply(|this| walk_block(this, blk)); } - fn visit_arm(&mut self, arm: &'v Arm) { + fn visit_arm(&mut self, arm: &Arm) { self.apply(|this| { // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]); this.apply(|this| walk_expr(this, &arm.body)); }); } - fn visit_item(&mut self, _: &'v Item) { + fn visit_item(&mut self, _: &Item) { // do not recurse into inner items } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 6beed822a81..fda151cd6d7 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -36,13 +36,12 @@ pub struct ReturnPass; impl ReturnPass { // Check the final stmt or expr in a block for unnecessary return. fn check_block_return(&mut self, cx: &EarlyContext, block: &Block) { - if let Some(ref expr) = block.expr { - self.check_final_expr(cx, expr); - } else if let Some(stmt) = block.stmts.last() { - if let StmtKind::Semi(ref expr, _) = stmt.node { - if let ExprKind::Ret(Some(ref inner)) = expr.node { - self.emit_return_lint(cx, (stmt.span, inner.span)); + if let Some(stmt) = block.stmts.last() { + match stmt.node { + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + self.check_final_expr(cx, expr); } + _ => (), } } } @@ -88,12 +87,14 @@ impl ReturnPass { // Check for "let x = EXPR; x" fn check_let_return(&mut self, cx: &EarlyContext, block: &Block) { + let mut it = block.stmts.iter(); + // we need both a let-binding stmt and an expr if_let_chain! {[ - let Some(stmt) = block.stmts.last(), - let Some(ref retexpr) = block.expr, - let StmtKind::Decl(ref decl, _) = stmt.node, - let DeclKind::Local(ref local) = decl.node, + let Some(ref retexpr) = it.next_back(), + let StmtKind::Expr(ref retexpr) = retexpr.node, + let Some(stmt) = it.next_back(), + let StmtKind::Local(ref local) = stmt.node, let Some(ref initexpr) = local.init, let PatKind::Ident(_, Spanned { node: id, .. }, _) = local.pat.node, let ExprKind::Path(_, ref path) = retexpr.node, diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index 699d17d4d70..4b0c5ea5afd 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -5,7 +5,7 @@ extern crate rustc; extern crate rustc_plugin; use syntax::codemap::Span; -use syntax::ast::TokenTree; +use syntax::tokenstream::TokenTree; use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; use syntax::ext::build::AstBuilder; // trait for expr_usize use rustc_plugin::Registry; diff --git a/src/main.rs b/src/main.rs index 17a219cafa0..c4ad6d66177 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,17 +2,17 @@ #![feature(box_syntax)] #![feature(rustc_private)] -extern crate rustc_driver; +extern crate clippy_lints; extern crate getopts; extern crate rustc; -extern crate syntax; +extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_plugin; -extern crate clippy_lints; +extern crate syntax; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session}; use rustc::session::config::{Input, ErrorOutputType}; -use syntax::diagnostics; use std::path::PathBuf; use std::process::Command; @@ -36,7 +36,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { fn early_callback(&mut self, matches: &getopts::Matches, sopts: &config::Options, - descriptions: &diagnostics::registry::Registry, + descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType) -> Compilation { self.0.early_callback(matches, sopts, descriptions, output) @@ -46,7 +46,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { sopts: &config::Options, odir: &Option<PathBuf>, ofile: &Option<PathBuf>, - descriptions: &diagnostics::registry::Registry) + descriptions: &rustc_errors::registry::Registry) -> Option<(Input, Option<PathBuf>)> { self.0.no_input(matches, sopts, odir, ofile, descriptions) } diff --git a/tests/compile-fail/formatting.rs b/tests/compile-fail/formatting.rs index 2436f64d216..9b8146dc229 100644 --- a/tests/compile-fail/formatting.rs +++ b/tests/compile-fail/formatting.rs @@ -16,7 +16,9 @@ fn main() { //~| NOTE add the missing `else` or } - let _ = { + let _ = { // if as the last expression + let _ = 0; + if foo() { } if foo() { //~^ ERROR this looks like an `else if` but the `else` is missing @@ -26,6 +28,18 @@ fn main() { } }; + let _ = { // if in the middle of a block + if foo() { + } if foo() { + //~^ ERROR this looks like an `else if` but the `else` is missing + //~| NOTE add the missing `else` or + } + else { + } + + let _ = 0; + }; + if foo() { } else //~^ ERROR this is an `else if` but the formatting might hide it diff --git a/tests/compile-fail/item_after_statement.rs b/tests/compile-fail/item_after_statement.rs index f104081faa9..4be89176fc7 100644 --- a/tests/compile-fail/item_after_statement.rs +++ b/tests/compile-fail/item_after_statement.rs @@ -2,6 +2,16 @@ #![plugin(clippy)] #![deny(items_after_statements)] +fn ok() { + fn foo() { println!("foo"); } + foo(); +} + +fn last() { + foo(); + fn foo() { println!("foo"); } //~ ERROR adding items after statements is confusing +} + fn main() { foo(); fn foo() { println!("foo"); } //~ ERROR adding items after statements is confusing diff --git a/tests/compile-fail/needless_bool.rs b/tests/compile-fail/needless_bool.rs index 7f2d7754bda..480c16f1666 100644 --- a/tests/compile-fail/needless_bool.rs +++ b/tests/compile-fail/needless_bool.rs @@ -1,8 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] +#![deny(needless_bool)] #[allow(if_same_then_else)] -#[deny(needless_bool)] fn main() { let x = true; if x { true } else { true }; //~ERROR this if-then-else expression will always return true @@ -22,19 +22,19 @@ fn main() { bool_ret4(x); } -#[deny(needless_bool)] -#[allow(if_same_then_else)] +#[allow(if_same_then_else, needless_return)] fn bool_ret(x: bool) -> bool { - if x { return true } else { return true }; //~ERROR this if-then-else expression will always return true + if x { return true } else { return true }; + //~^ ERROR this if-then-else expression will always return true } -#[deny(needless_bool)] -#[allow(if_same_then_else)] +#[allow(if_same_then_else, needless_return)] fn bool_ret2(x: bool) -> bool { - if x { return false } else { return false }; //~ERROR this if-then-else expression will always return false + if x { return false } else { return false }; + //~^ ERROR this if-then-else expression will always return false } -#[deny(needless_bool)] +#[allow(needless_return)] fn bool_ret3(x: bool) -> bool { if x { return true } else { return false }; //~^ ERROR this if-then-else expression returns a bool literal @@ -42,7 +42,7 @@ fn bool_ret3(x: bool) -> bool { //~| SUGGESTION `return x` } -#[deny(needless_bool)] +#[allow(needless_return)] fn bool_ret4(x: bool) -> bool { if x { return false } else { return true }; //~^ ERROR this if-then-else expression returns a bool literal diff --git a/tests/consts.rs b/tests/consts.rs index 81500f9d393..773b889ebff 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -14,6 +14,7 @@ use syntax::ast::{LitIntType, LitKind, StrStyle}; use syntax::codemap::{Spanned, COMMAND_LINE_SP}; use syntax::parse::token::InternedString; use syntax::ptr::P; +use syntax::util::ThinVec; fn spanned<T>(t: T) -> Spanned<T> { Spanned { @@ -27,7 +28,7 @@ fn expr(n: Expr_) -> Expr { id: 1, node: n, span: COMMAND_LINE_SP, - attrs: None, + attrs: ThinVec::new(), } } -- cgit 1.4.1-3-g733a5 From 871f8dcab3ef4ed2a5e65f531afc7b6bd5762cba Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 4 Jul 2016 13:33:48 +0200 Subject: don't run clippy on dependencies when running cargo clippy --- src/main.rs | 100 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index c4ad6d66177..9541e70ecc0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,17 +18,17 @@ use std::process::Command; use clippy_lints::utils::cargo; -struct ClippyCompilerCalls(RustcDefaultCalls); - -impl std::default::Default for ClippyCompilerCalls { - fn default() -> Self { - Self::new() - } +struct ClippyCompilerCalls { + default: RustcDefaultCalls, + run_lints: bool, } impl ClippyCompilerCalls { - fn new() -> Self { - ClippyCompilerCalls(RustcDefaultCalls) + fn new(run_lints: bool) -> Self { + ClippyCompilerCalls { + default: RustcDefaultCalls, + run_lints: run_lints, + } } } @@ -39,7 +39,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType) -> Compilation { - self.0.early_callback(matches, sopts, descriptions, output) + self.default.early_callback(matches, sopts, descriptions, output) } fn no_input(&mut self, matches: &getopts::Matches, @@ -48,7 +48,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry) -> Option<(Input, Option<PathBuf>)> { - self.0.no_input(matches, sopts, odir, ofile, descriptions) + self.default.no_input(matches, sopts, odir, ofile, descriptions) } fn late_callback(&mut self, matches: &getopts::Matches, @@ -57,44 +57,46 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { odir: &Option<PathBuf>, ofile: &Option<PathBuf>) -> Compilation { - self.0.late_callback(matches, sess, input, odir, ofile) + self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.0.build_controller(sess, matches); - - 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")); - registry.args_hidden = Some(Vec::new()); - clippy_lints::register_plugins(&mut registry); - - let rustc_plugin::registry::Registry { early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - mir_passes, - .. } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } + let mut control = self.default.build_controller(sess, matches); + + if self.run_lints { + 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")); + registry.args_hidden = Some(Vec::new()); + clippy_lints::register_plugins(&mut registry); + + let rustc_plugin::registry::Registry { early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + mir_passes, + .. } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.mir_passes.borrow_mut().extend(mir_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - } - old(state); - }); + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.mir_passes.borrow_mut().extend(mir_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + } + old(state); + }); + } control } @@ -129,6 +131,7 @@ pub fn main() { }; if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + // this arm is executed on the initial call to `cargo clippy` let manifest_path = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); let mut metadata = cargo::metadata(manifest_path).expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); @@ -149,12 +152,19 @@ pub fn main() { } } } else { + // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` env var set to itself + + // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly + // without having to pass --sysroot or anything let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() } else { env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() }; - let (result, _) = rustc_driver::run_compiler(&args, &mut ClippyCompilerCalls::new()); + // this check ensures that dependencies are built but not linted and the final crate is + // linted but not built + let mut ccc = ClippyCompilerCalls::new(env::args().any(|s| s == "-Zno-trans")); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc); if let Err(err_count) = result { if err_count > 0 { -- cgit 1.4.1-3-g733a5 From 9aa770126267aaa14404a181ffedfb27f60fe872 Mon Sep 17 00:00:00 2001 From: Sascha Hanse <shanse@gmail.com> Date: Wed, 17 Aug 2016 00:21:58 +0200 Subject: make clippy compile again with the latest nightly after rust-lang/rust@65eb024542835c0235c31ef0e2381d155c797b03 --- src/main.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 9541e70ecc0..f5fad298b1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use rustc::session::{config, Session}; use rustc::session::config::{Input, ErrorOutputType}; use std::path::PathBuf; use std::process::Command; +use syntax::{ast}; use clippy_lints::utils::cargo; @@ -36,28 +37,31 @@ 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 { - self.default.early_callback(matches, sopts, descriptions, output) + 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<PathBuf>, ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry) -> Option<(Input, Option<PathBuf>)> { - self.default.no_input(matches, sopts, odir, ofile, descriptions) + self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, + cfg: &ast::CrateConfig, input: &Input, odir: &Option<PathBuf>, ofile: &Option<PathBuf>) -> Compilation { - self.default.late_callback(matches, sess, input, odir, ofile) + self.default.late_callback(matches, sess, cfg, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); -- cgit 1.4.1-3-g733a5 From f006805c4a858be582c748058723e041fcb8f88e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 17 Aug 2016 09:18:15 +0530 Subject: Bump to 0.0.82 --- CHANGELOG.md | 3 +++ Cargo.toml | 6 +++--- clippy_lints/Cargo.toml | 2 +- src/main.rs | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 725cdcc10b8..9e4097c0996 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.82 — 2016-08-17 +* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)* + ## 0.0.81 - 2016-08-14 * Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)* * New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`] diff --git a/Cargo.toml b/Cargo.toml index 2f1d9571e46..61d2e8bec6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.81" +version = "0.0.82" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", @@ -25,11 +25,11 @@ test = false [dependencies] # begin automatic update -clippy_lints = { version = "0.0.81", path = "clippy_lints" } +clippy_lints = { version = "0.0.82", path = "clippy_lints" } # end automatic update [dev-dependencies] -compiletest_rs = "0.2.0" +compiletest_rs = "0.2.1" lazy_static = "0.1.15" regex = "0.1.71" rustc-serialize = "0.3" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index dd2bcc7cd71..896f4a6fb92 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.81" +version = "0.0.82" # end automatic update authors = [ "Manish Goregaokar <manishsmail@gmail.com>", diff --git a/src/main.rs b/src/main.rs index f5fad298b1d..e5043c927bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use rustc::session::{config, Session}; use rustc::session::config::{Input, ErrorOutputType}; use std::path::PathBuf; use std::process::Command; -use syntax::{ast}; +use syntax::ast; use clippy_lints::utils::cargo; -- cgit 1.4.1-3-g733a5 From 6d7269a675371bb8ccebab9ef9e72b3a1f341771 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 17:04:21 +0200 Subject: also run clippy on examples --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index e5043c927bb..d476aa8435f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,13 +143,20 @@ pub fn main() { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { + println!("compiling library"); if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root) { std::process::exit(code); } } else if first == "bin" { + println!("compiling bin target `{}`", target.name); if let Err(code) = process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { std::process::exit(code); } + } else if first == "example" { + println!("compiling example target `{}`", target.name); + if let Err(code) = process(vec!["--example".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { + std::process::exit(code); + } } } else { panic!("badly formatted cargo metadata: target::kind is an empty array"); -- cgit 1.4.1-3-g733a5 From 32a0069f672d24409837499be21ae3850a1d9c5c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 17:42:59 +0200 Subject: no println output --- src/main.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index d476aa8435f..421885152c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,17 +143,14 @@ pub fn main() { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { - println!("compiling library"); if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root) { std::process::exit(code); } } else if first == "bin" { - println!("compiling bin target `{}`", target.name); if let Err(code) = process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { std::process::exit(code); } } else if first == "example" { - println!("compiling example target `{}`", target.name); if let Err(code) = process(vec!["--example".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { std::process::exit(code); } -- cgit 1.4.1-3-g733a5 From 0dab78b3e628ed551f625f098d849c4fd865e1c8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 17:43:21 +0200 Subject: unify "test", "bench", "example" and "bin" into one branch --- src/main.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 421885152c5..6c4d3bbdeab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -146,12 +146,8 @@ pub fn main() { if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root) { std::process::exit(code); } - } else if first == "bin" { - if let Err(code) = process(vec!["--bin".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { - std::process::exit(code); - } - } else if first == "example" { - if let Err(code) = process(vec!["--example".to_owned(), target.name].into_iter().chain(args), &dep_path, &sys_root) { + } else if ["bin", "example", "test", "bench"].contains(&&**first) { + if let Err(code) = process(vec![format!("--{}", first), target.name].into_iter().chain(args), &dep_path, &sys_root) { std::process::exit(code); } } -- cgit 1.4.1-3-g733a5 From e3723cb9383b58fc8ea02f3c1b510530a4e99b16 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 17:43:49 +0200 Subject: running cargo clippy on a crate that has the clippy plugin enabled errors out due to duplicate lints --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f5229d3cb39..cd91b85e59b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,11 @@ pub use clippy_lints::*; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - register_plugins(reg); + if 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 { + register_plugins(reg); + } } // only exists to let the dogfood integration test works. -- cgit 1.4.1-3-g733a5 From 59c31d319ae376dcb1c6757e99eb059c27c7d00b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 18:26:58 +0200 Subject: plugin mode still needs to work --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index cd91b85e59b..5a02b514812 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![feature(plugin_registrar)] #![feature(rustc_private)] #![allow(unknown_lints)] +#![feature(borrow_state)] extern crate rustc_plugin; use rustc_plugin::Registry; @@ -12,7 +13,7 @@ pub use clippy_lints::*; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - if reg.sess.lint_store.borrow().get_lint_groups().iter().any(|&(s, _, _)| s == "clippy") { + 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 { register_plugins(reg); -- cgit 1.4.1-3-g733a5 From 7b717d3152e9ad1b3e874d9b5dd957521640f40b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 17 Aug 2016 18:35:25 +0200 Subject: fallout --- src/lib.rs | 6 ++---- tests/camel_case.rs | 5 ++--- tests/compile-test.rs | 2 +- tests/consts.rs | 5 ++--- tests/matches.rs | 7 +++---- tests/trim_multiline.rs | 5 ++--- 6 files changed, 12 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 5a02b514812..9e83a96fee6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,20 +9,18 @@ use rustc_plugin::Registry; extern crate clippy_lints; -pub use 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 { - register_plugins(reg); + clippy_lints::register_plugins(reg); } } // only exists to let the dogfood integration test works. // Don't run clippy as an executable directly -#[allow(dead_code, print_stdout)] +#[allow(dead_code)] fn main() { panic!("Please use the cargo-clippy executable"); } diff --git a/tests/camel_case.rs b/tests/camel_case.rs index 201b796af1c..b7efbde6596 100644 --- a/tests/camel_case.rs +++ b/tests/camel_case.rs @@ -1,7 +1,6 @@ -#[allow(plugin_as_library)] -extern crate clippy; +extern crate clippy_lints; -use clippy::utils::{camel_case_from, camel_case_until}; +use clippy_lints::utils::{camel_case_from, camel_case_until}; #[test] fn from_full() { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index d21d9750924..deadd499192 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -6,7 +6,7 @@ use std::env::{set_var, var}; fn run_mode(dir: &'static str, mode: &'static str) { let mut config = compiletest::default_config(); - let cfg_mode = mode.parse().ok().expect("Invalid mode"); + let cfg_mode = mode.parse().expect("Invalid mode"); config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps".to_owned()); if let Ok(name) = var::<&str>("TESTNAME") { let s: String = name.to_owned(); diff --git a/tests/consts.rs b/tests/consts.rs index 5f5f4cb47d0..47ea4d874b6 100644 --- a/tests/consts.rs +++ b/tests/consts.rs @@ -1,13 +1,12 @@ -#![allow(plugin_as_library)] #![feature(rustc_private)] -extern crate clippy; +extern crate clippy_lints; extern crate rustc; extern crate rustc_const_eval; extern crate rustc_const_math; extern crate syntax; -use clippy::consts::{constant_simple, Constant, FloatWidth}; +use clippy_lints::consts::{constant_simple, Constant, FloatWidth}; use rustc_const_math::ConstInt; use rustc::hir::*; use syntax::ast::{LitIntType, LitKind, StrStyle}; diff --git a/tests/matches.rs b/tests/matches.rs index 74433fc1f56..1d9d3dedd5d 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -1,16 +1,15 @@ -#![allow(plugin_as_library)] #![feature(rustc_private)] -extern crate clippy; +extern crate clippy_lints; extern crate syntax; #[test] fn test_overlapping() { - use clippy::matches::overlapping; + use clippy_lints::matches::overlapping; use syntax::codemap::DUMMY_SP; let sp = |s, e| { - clippy::matches::SpannedRange { + clippy_lints::matches::SpannedRange { span: DUMMY_SP, node: (s, e), } diff --git a/tests/trim_multiline.rs b/tests/trim_multiline.rs index e29ee4922cd..90f1c76fb80 100644 --- a/tests/trim_multiline.rs +++ b/tests/trim_multiline.rs @@ -1,8 +1,7 @@ /// test the multiline-trim function -#[allow(plugin_as_library)] -extern crate clippy; +extern crate clippy_lints; -use clippy::utils::trim_multiline; +use clippy_lints::utils::trim_multiline; #[test] fn test_single_line() { -- cgit 1.4.1-3-g733a5 From 36d8ca04a158ba617ae020c73f14792d808ad103 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 23 Aug 2016 18:09:37 +0200 Subject: Add a `MISSING_DOCS_IN_PRIVATE_ITEMS` lint --- CHANGELOG.md | 3 +- README.md | 3 +- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/missing_doc.rs | 172 +++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 2 + tests/compile-fail/enum_glob_use.rs | 2 +- tests/compile-fail/filter_methods.rs | 2 + tests/compile-fail/methods.rs | 2 +- tests/compile-fail/missing-doc.rs | 202 +++++++++++++++++++++++++++++++++++ tests/compile-fail/shadow.rs | 2 +- 11 files changed, 390 insertions(+), 6 deletions(-) create mode 100644 clippy_lints/src/missing_doc.rs create mode 100644 tests/compile-fail/missing-doc.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e198b57073..7723b558376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. ## 0.0.86 — ? -* New lint: [`zero_prefixed_literal`] +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`] ## 0.0.85 — 2016-08-19 * Fix ICE with [`useless_attribute`] @@ -241,6 +241,7 @@ All notable changes to this project will be documented in this file. [`mem_forget`]: https://github.com/Manishearth/rust-clippy/wiki#mem_forget [`min_max`]: https://github.com/Manishearth/rust-clippy/wiki#min_max [`misrefactored_assign_op`]: https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op +[`missing_docs_in_private_items`]: https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items [`mixed_case_hex_literals`]: https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals [`module_inception`]: https://github.com/Manishearth/rust-clippy/wiki#module_inception [`modulo_one`]: https://github.com/Manishearth/rust-clippy/wiki#modulo_one diff --git a/README.md b/README.md index b294c75a756..45c20f06c06 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 167 lints included in this crate: +There are 168 lints included in this crate: name | default | triggers on ---------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------- @@ -100,6 +100,7 @@ name [mem_forget](https://github.com/Manishearth/rust-clippy/wiki#mem_forget) | allow | `mem::forget` usage on `Drop` types, likely to cause memory leaks [min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant [misrefactored_assign_op](https://github.com/Manishearth/rust-clippy/wiki#misrefactored_assign_op) | warn | having a variable on both sides of an assign op +[missing_docs_in_private_items](https://github.com/Manishearth/rust-clippy/wiki#missing_docs_in_private_items) | allow | detects missing documentation for public and private members [mixed_case_hex_literals](https://github.com/Manishearth/rust-clippy/wiki#mixed_case_hex_literals) | warn | hex literals whose letter digits are not consistently upper- or lowercased [module_inception](https://github.com/Manishearth/rust-clippy/wiki#module_inception) | warn | modules that have the same name as their parent module [modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index df0b0d9efff..f7b1dcb40f4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -10,7 +10,7 @@ #![feature(stmt_expr_attributes)] #![feature(type_macros)] -#![allow(indexing_slicing, shadow_reuse, unknown_lints)] +#![allow(indexing_slicing, shadow_reuse, unknown_lints, missing_docs_in_private_items)] #[macro_use] extern crate syntax; @@ -96,6 +96,7 @@ pub mod methods; pub mod minmax; pub mod misc; pub mod misc_early; +pub mod missing_doc; pub mod module_inception; pub mod mut_mut; pub mod mut_reference; @@ -260,6 +261,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box assign_ops::AssignOps); reg.register_late_lint_pass(box let_if_seq::LetIfSeq); reg.register_late_lint_pass(box eval_order_dependence::EvalOrderDependence); + reg.register_late_lint_pass(box missing_doc::MissingDoc::new()); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -282,6 +284,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { methods::WRONG_PUB_SELF_CONVENTION, misc::USED_UNDERSCORE_BINDING, misc_early::UNSEPARATED_LITERAL_SUFFIX, + missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, mut_mut::MUT_MUT, mutex_atomic::MUTEX_INTEGER, non_expressive_names::SIMILAR_NAMES, diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs new file mode 100644 index 00000000000..b2b52677038 --- /dev/null +++ b/clippy_lints/src/missing_doc.rs @@ -0,0 +1,172 @@ +/* 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 <LICENSE-APACHE or + * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license + * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +/* 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::*; +use rustc::ty; +use syntax::ast; +use syntax::attr::{self, AttrMetaMethods}; +use syntax::codemap::Span; + +/// **What it does:** Warns if there is missing doc for any documentable item (public or private). +/// +/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` allowed-by-default lint for +/// public members, but has no way to enforce documentation of private items. This lint fixes that. +/// +/// **Known problems:** None. +declare_lint! { + pub MISSING_DOCS_IN_PRIVATE_ITEMS, + Allow, + "detects missing documentation for public and private members" +} + +pub struct MissingDoc { + /// Stack of whether #[doc(hidden)] is set + /// at each level which has lint attributes. + doc_hidden_stack: Vec<bool>, +} + +impl ::std::default::Default for MissingDoc { + fn default() -> MissingDoc { + MissingDoc::new() + } +} + +impl MissingDoc { + pub fn new() -> MissingDoc { + 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) { + // If we're building a test harness, then warning about + // documentation is probably not really relevant right now. + if cx.sess().opts.test { + return; + } + + // `#[doc(hidden)]` disables missing_docs check. + if self.doc_hidden() { + return; + } + + 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, + &format!("missing documentation for {}", desc)); + } + } +} + +impl LintPass for MissingDoc { + fn get_lints(&self) -> LintArray { + lint_array![MISSING_DOCS_IN_PRIVATE_ITEMS] + } +} + +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() { + None => false, + Some(l) => attr::contains_name(&l[..], "hidden"), + } + }); + self.doc_hidden_stack.push(doc_hidden); + } + + fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { + self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); + } + + fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { + self.check_missing_docs_attrs(cx, &krate.attrs, krate.span, "crate"); + } + + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + let desc = match it.node { + hir::ItemConst(..) => "a constant", + hir::ItemEnum(..) => "an enum", + hir::ItemFn(..) => "a function", + hir::ItemMod(..) => "a module", + hir::ItemStatic(..) => "a static", + hir::ItemStruct(..) => "a struct", + hir::ItemTrait(..) => "a trait", + hir::ItemTy(..) => "a type alias", + hir::ItemDefaultImpl(..) | + hir::ItemExternCrate(..) | + hir::ItemForeignMod(..) | + hir::ItemImpl(..) | + hir::ItemUse(..) => return, + }; + + self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc); + } + + fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { + let desc = match trait_item.node { + hir::ConstTraitItem(..) => "an associated constant", + hir::MethodTraitItem(..) => "a trait method", + hir::TypeTraitItem(..) => "an associated type", + }; + + 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) { + // 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.impl_or_trait_items.borrow() + .get(&def_id) + .expect("missing method descriptor?!") + .container() { + ty::TraitContainer(_) => return, + ty::ImplContainer(cid) => { + if cx.tcx.impl_trait_ref(cid).is_some() { + return + } + } + } + + let desc = match impl_item.node { + hir::ImplItemKind::Const(..) => "an associated constant", + hir::ImplItemKind::Method(..) => "a method", + hir::ImplItemKind::Type(_) => "an associated type", + }; + self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc); + } + + fn check_struct_field(&mut self, cx: &LateContext, sf: &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) { + self.check_missing_docs_attrs(cx, &v.node.attrs, v.span, "a variant"); + } +} diff --git a/src/lib.rs b/src/lib.rs index f5229d3cb39..e0a6cc28a02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![feature(plugin_registrar)] #![feature(rustc_private)] #![allow(unknown_lints)] +#![allow(missing_docs_in_private_items)] extern crate rustc_plugin; use rustc_plugin::Registry; diff --git a/src/main.rs b/src/main.rs index e5043c927bb..efe6459f587 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ #![feature(box_syntax)] #![feature(rustc_private)] +#![allow(unknown_lints, missing_docs_in_private_items)] + extern crate clippy_lints; extern crate getopts; extern crate rustc; diff --git a/tests/compile-fail/enum_glob_use.rs b/tests/compile-fail/enum_glob_use.rs index 27f0ff24579..12fd104312a 100644 --- a/tests/compile-fail/enum_glob_use.rs +++ b/tests/compile-fail/enum_glob_use.rs @@ -1,7 +1,7 @@ #![feature(plugin)] #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(unused_imports, dead_code)] +#![allow(unused_imports, dead_code, missing_docs_in_private_items)] use std::cmp::Ordering::*; //~ ERROR: don't use glob imports for enum variants diff --git a/tests/compile-fail/filter_methods.rs b/tests/compile-fail/filter_methods.rs index bee9688f581..20803c8d0e8 100644 --- a/tests/compile-fail/filter_methods.rs +++ b/tests/compile-fail/filter_methods.rs @@ -2,6 +2,8 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] +#![allow(missing_docs_in_private_items)] + fn main() { let _: Vec<_> = vec![5; 6].into_iter() //~ERROR called `filter(p).map(q)` on an `Iterator` .filter(|&x| x == 0) diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs index 7235bad11bf..0412dfecac1 100644 --- a/tests/compile-fail/methods.rs +++ b/tests/compile-fail/methods.rs @@ -3,7 +3,7 @@ #![plugin(clippy)] #![deny(clippy, clippy_pedantic)] -#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive)] +#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/compile-fail/missing-doc.rs b/tests/compile-fail/missing-doc.rs new file mode 100644 index 00000000000..acd86f18ea3 --- /dev/null +++ b/tests/compile-fail/missing-doc.rs @@ -0,0 +1,202 @@ +/* This file incorporates work covered by the following copyright and + * permission notice: + * Copyright 2013 The Rust Project Developers. See the COPYRIGHT + * file at the top-level directory of this distribution and at + * http://rust-lang.org/COPYRIGHT. + * + * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or + * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license + * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +#![feature(plugin)] +#![plugin(clippy)] +#![deny(missing_docs_in_private_items)] + +// When denying at the crate level, be sure to not get random warnings from the +// injected intrinsics by the compiler. +#![allow(dead_code)] +#![feature(associated_type_defaults)] + +//! Some garbage docs for the crate here +#![doc="More garbage"] + +type Typedef = String; //~ ERROR: missing documentation for a type alias +pub type PubTypedef = String; //~ ERROR: missing documentation for a type alias + +struct Foo { //~ ERROR: missing documentation for a struct + a: isize, //~ ERROR: missing documentation for a struct field + b: isize, //~ ERROR: missing documentation for a struct field +} + +pub struct PubFoo { //~ ERROR: missing documentation for a struct + pub a: isize, //~ ERROR: missing documentation for a struct field + b: isize, //~ ERROR: missing documentation for a struct field +} + +#[allow(missing_docs_in_private_items)] +pub struct PubFoo2 { + pub a: isize, + pub c: isize, +} + +mod module_no_dox {} //~ ERROR: missing documentation for a module +pub mod pub_module_no_dox {} //~ ERROR: missing documentation for a module + +/// dox +pub fn foo() {} +pub fn foo2() {} //~ ERROR: missing documentation for a function +fn foo3() {} //~ ERROR: missing documentation for a function +#[allow(missing_docs_in_private_items)] pub fn foo4() {} + +/// dox +pub trait A { + /// dox + fn foo(&self); + /// dox + fn foo_with_impl(&self) {} +} + +#[allow(missing_docs_in_private_items)] +trait B { + fn foo(&self); + fn foo_with_impl(&self) {} +} + +pub trait C { //~ ERROR: missing documentation for a trait + fn foo(&self); //~ ERROR: missing documentation for a trait method + fn foo_with_impl(&self) {} //~ ERROR: missing documentation for a trait method +} + +#[allow(missing_docs_in_private_items)] +pub trait D { + fn dummy(&self) { } +} + +/// dox +pub trait E { + type AssociatedType; //~ ERROR: missing documentation for an associated type + type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type + + /// dox + type DocumentedType; + /// dox + type DocumentedTypeDef = Self; + /// dox + fn dummy(&self) {} +} + +impl Foo { + pub fn foo() {} //~ ERROR: missing documentation for a method + fn bar() {} //~ ERROR: missing documentation for a method +} + +impl PubFoo { + pub fn foo() {} //~ ERROR: missing documentation for a method + /// dox + pub fn foo1() {} + fn foo2() {} //~ ERROR: missing documentation for a method + #[allow(missing_docs_in_private_items)] pub fn foo3() {} +} + +#[allow(missing_docs_in_private_items)] +trait F { + fn a(); + fn b(&self); +} + +// should need to redefine documentation for implementations of traits +impl F for Foo { + fn a() {} + fn b(&self) {} +} + +// It sure is nice if doc(hidden) implies allow(missing_docs), and that it +// applies recursively +#[doc(hidden)] +mod a { + pub fn baz() {} + pub mod b { + pub fn baz() {} + } +} + +enum Baz { //~ ERROR: missing documentation for an enum + BazA { //~ ERROR: missing documentation for a variant + a: isize, //~ ERROR: missing documentation for a struct field + b: isize //~ ERROR: missing documentation for a struct field + }, + BarB //~ ERROR: missing documentation for a variant +} + +pub enum PubBaz { //~ ERROR: missing documentation for an enum + PubBazA { //~ ERROR: missing documentation for a variant + a: isize, //~ ERROR: missing documentation for a struct field + }, +} + +/// dox +pub enum PubBaz2 { + /// dox + PubBaz2A { + /// dox + a: isize, + }, +} + +#[allow(missing_docs_in_private_items)] +pub enum PubBaz3 { + PubBaz3A { + b: isize + }, +} + +#[doc(hidden)] +pub fn baz() {} + + +const FOO: u32 = 0; //~ ERROR: missing documentation for a const +/// dox +pub const FOO1: u32 = 0; +#[allow(missing_docs_in_private_items)] +pub const FOO2: u32 = 0; +#[doc(hidden)] +pub const FOO3: u32 = 0; +pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const + + +static BAR: u32 = 0; //~ ERROR: missing documentation for a static +/// dox +pub static BAR1: u32 = 0; +#[allow(missing_docs_in_private_items)] +pub static BAR2: u32 = 0; +#[doc(hidden)] +pub static BAR3: u32 = 0; +pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static + + +mod internal_impl { //~ ERROR: missing documentation for a module + /// dox + pub fn documented() {} + pub fn undocumented1() {} //~ ERROR: missing documentation for a function + pub fn undocumented2() {} //~ ERROR: missing documentation for a function + fn undocumented3() {} //~ ERROR: missing documentation for a function + /// dox + pub mod globbed { + /// dox + pub fn also_documented() {} + pub fn also_undocumented1() {} //~ ERROR: missing documentation for a function + fn also_undocumented2() {} //~ ERROR: missing documentation for a function + } +} +/// dox +pub mod public_interface { + pub use internal_impl::documented as foo; + pub use internal_impl::undocumented1 as bar; + pub use internal_impl::{documented, undocumented2}; + pub use internal_impl::globbed::*; +} + +fn main() {} //~ ERROR: missing documentation for a function diff --git a/tests/compile-fail/shadow.rs b/tests/compile-fail/shadow.rs index 1200e25cdbc..fae87cd9750 100644 --- a/tests/compile-fail/shadow.rs +++ b/tests/compile-fail/shadow.rs @@ -1,8 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] -#![allow(unused_parens, unused_variables)] #![deny(clippy, clippy_pedantic)] +#![allow(unused_parens, unused_variables, missing_docs_in_private_items)] fn id<T>(x: T) -> T { x } -- cgit 1.4.1-3-g733a5 From c090c3df21ba1f4f9b4ce2a9f3f10005a93f3713 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 6 Sep 2016 19:04:38 +0200 Subject: Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)* --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index efe6459f587..120fa247ba7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,7 +72,7 @@ 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")); + 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); -- cgit 1.4.1-3-g733a5 From eec5425b34d6acee62788a417e840fffbbbe1530 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Fri, 30 Sep 2016 15:33:24 +0200 Subject: Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)* --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 83c569ebb39..ed1c30d567b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -170,7 +170,7 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final crate is // linted but not built let mut ccc = ClippyCompilerCalls::new(env::args().any(|s| s == "-Zno-trans")); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); if let Err(err_count) = result { if err_count > 0 { -- cgit 1.4.1-3-g733a5 From ebbd00b1abb2d6d2f189288a10f23556ee997424 Mon Sep 17 00:00:00 2001 From: Arnavion <arnavion@gmail.com> Date: Sat, 22 Oct 2016 18:15:42 -0700 Subject: Don't assume the first package in the result of `cargo metadata` is the current crate. Instead find the one with the manifest path that matches the --manifest-path argument or the current directory. Fixes #1247 --- clippy_lints/src/utils/cargo.rs | 6 +++--- src/main.rs | 26 +++++++++++++++++++++++--- tests/versioncheck.rs | 4 ++-- 3 files changed, 28 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index 48a97f2f1fc..0722cef96d7 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -20,7 +20,7 @@ pub struct Package { pub dependencies: Vec<Dependency>, pub targets: Vec<Target>, features: HashMap<String, Vec<String>>, - manifest_path: String, + pub manifest_path: String, } #[derive(RustcDecodable, Debug)] @@ -65,10 +65,10 @@ impl From<json::DecoderError> for Error { } } -pub fn metadata(manifest_path: Option<String>) -> Result<Metadata, Error> { +pub fn metadata(manifest_path_arg: &Option<String>) -> Result<Metadata, Error> { let mut cmd = Command::new("cargo"); cmd.arg("metadata").arg("--no-deps"); - if let Some(ref mani) = manifest_path { + if let Some(ref mani) = *manifest_path_arg { cmd.arg(mani); } let output = cmd.output()?; diff --git a/src/main.rs b/src/main.rs index ed1c30d567b..29713a183eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,10 +138,30 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - let manifest_path = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = cargo::metadata(manifest_path).expect("could not obtain cargo metadata"); + let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); + + let mut metadata = cargo::metadata(&manifest_path_arg).expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); - for target in metadata.packages.remove(0).targets { + + let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); + + let current_dir = std::env::current_dir(); + + 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 if let Ok(ref current_dir) = current_dir { + let package_manifest_directory = package_manifest_path.parent().expect("could not find parent directory of package manifest"); + package_manifest_directory == current_dir + } else { + panic!("could not read current directory") + } + }) + .expect("could not find matching package"); + let package = metadata.packages.remove(package_index); + for target in package.targets { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index e216c801546..8abb95c570a 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -3,9 +3,9 @@ use clippy_lints::utils::cargo; #[test] fn check_that_clippy_lints_has_the_same_version_as_clippy() { - let clippy_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); + let clippy_meta = cargo::metadata(&None).expect("could not obtain cargo metadata"); std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); - let clippy_lints_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); + let clippy_lints_meta = cargo::metadata(&None).expect("could not obtain cargo metadata"); assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { -- cgit 1.4.1-3-g733a5 From 2315a817ce6589f3f27d0f80192c037c3e9bb5ad Mon Sep 17 00:00:00 2001 From: Arnavion <arnavion@gmail.com> Date: Sun, 23 Oct 2016 12:24:16 -0700 Subject: Changed signature of cargo::metadata according to review comment. --- clippy_lints/src/utils/cargo.rs | 4 ++-- src/main.rs | 2 +- tests/versioncheck.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs index 0722cef96d7..b9ce8626eb9 100644 --- a/clippy_lints/src/utils/cargo.rs +++ b/clippy_lints/src/utils/cargo.rs @@ -65,10 +65,10 @@ impl From<json::DecoderError> for Error { } } -pub fn metadata(manifest_path_arg: &Option<String>) -> Result<Metadata, Error> { +pub fn metadata(manifest_path_arg: Option<&str>) -> Result<Metadata, Error> { let mut cmd = Command::new("cargo"); cmd.arg("metadata").arg("--no-deps"); - if let Some(ref mani) = *manifest_path_arg { + if let Some(mani) = manifest_path_arg { cmd.arg(mani); } let output = cmd.output()?; diff --git a/src/main.rs b/src/main.rs index 29713a183eb..c008dae2fe8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -140,7 +140,7 @@ pub fn main() { // this arm is executed on the initial call to `cargo clippy` let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = cargo::metadata(&manifest_path_arg).expect("could not obtain cargo metadata"); + let mut metadata = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)).expect("could not obtain cargo metadata"); assert_eq!(metadata.version, 1); let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 8abb95c570a..e216c801546 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -3,9 +3,9 @@ use clippy_lints::utils::cargo; #[test] fn check_that_clippy_lints_has_the_same_version_as_clippy() { - let clippy_meta = cargo::metadata(&None).expect("could not obtain cargo metadata"); + let clippy_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); - let clippy_lints_meta = cargo::metadata(&None).expect("could not obtain cargo metadata"); + let clippy_lints_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { -- cgit 1.4.1-3-g733a5 From 604694bc0b2f445520469d62ecf54d60f3cc39db Mon Sep 17 00:00:00 2001 From: Arnavion <arnavion@gmail.com> Date: Sun, 23 Oct 2016 12:29:33 -0700 Subject: Use .expect() for extracting the current_dir. --- src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index c008dae2fe8..0eef99bfc12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -152,11 +152,10 @@ pub fn main() { let package_manifest_path = Path::new(&package.manifest_path); if let Some(ref manifest_path) = manifest_path { package_manifest_path == manifest_path - } else if let Ok(ref current_dir) = current_dir { + } 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"); package_manifest_directory == current_dir - } else { - panic!("could not read current directory") } }) .expect("could not find matching package"); -- cgit 1.4.1-3-g733a5 From 492341593094d3b1a3ffa2e5d6e5820fb0dd7a83 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 24 Oct 2016 15:31:11 +0200 Subject: Be more helping with `cargo clippy --help` --- src/main.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 0eef99bfc12..594e017fd01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(static_in_const)] #![allow(unknown_lints, missing_docs_in_private_items)] @@ -110,6 +111,27 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { use std::path::Path; +const CARGO_CLIPPY_HELP: &str = "\ +Checks a package to catch common mistakes and improve your Rust code. + +Usage: + cargo clippy [options] [--] [<opts>...] + +Common options: + -h, --help Print this message + --features Features to compile for the package + +Other options are the same as `cargo rustc`. + +To allow or deny a lint from the command line you can use `cargo clippy --` with +one of: + + -W --warn OPT Set lint warnings + -A --allow OPT Set lint allowed + -D --deny OPT Set lint denied + -F --forbid OPT Set lint forbidden\ +"; + pub fn main() { use std::env; @@ -138,9 +160,19 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` + + match std::env::args().nth(2).as_ref().map(AsRef::as_ref) { + Some("--help") | Some("-h") => { + println!("{}", CARGO_CLIPPY_HELP); + return; + } + _ => (), + } + let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); let mut metadata = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)).expect("could not obtain cargo metadata"); + assert_eq!(metadata.version, 1); let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); -- cgit 1.4.1-3-g733a5 From 409b8e73434ed4eeef4c460f4f03687ca1c9623d Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 24 Oct 2016 16:04:00 +0200 Subject: Revert "Revert "Automatically defines the `clippy` feature"" This reverts commit e4dceef7e79c96c4ddeffd59a2c532bd239f98a6. --- CHANGELOG.md | 6 ++++++ README.md | 8 ++++++++ src/main.rs | 19 ++++++++++++++----- 3 files changed, 28 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6aef22bab..fd75c7d0745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.97 — 2016-10-24 +* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was + previously added for a short time under the name `clippy` but removed for + compatibility. +* `cargo clippy --help` is more helping (and less helpful :smile:) + ## 0.0.96 — 2016-10-22 * Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)* * New lint: [`iter_skip_next`] diff --git a/README.md b/README.md index fee1c5427f2..385a6998238 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,14 @@ You can add options to `allow`/`warn`/`deny`: Note: `deny` produces errors instead of warnings. +For convenience, `cargo clippy` automatically defines a `cargo-clippy` +features. This lets you set lints level and compile with or without clippy +transparently: + +```rust +#[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] +``` + ## Link with clippy service `clippy-service` is a rust web initiative providing `rust-clippy` as a web service. diff --git a/src/main.rs b/src/main.rs index 594e017fd01..fe1a453ff62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,8 +111,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { use std::path::Path; -const CARGO_CLIPPY_HELP: &str = "\ -Checks a package to catch common mistakes and improve your Rust code. +const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. Usage: cargo clippy [options] [--] [<opts>...] @@ -129,8 +128,13 @@ one of: -W --warn OPT Set lint warnings -A --allow OPT Set lint allowed -D --deny OPT Set lint denied - -F --forbid OPT Set lint forbidden\ -"; + -F --forbid OPT Set lint forbidden + +The feature `cargo-clippy` is automatically defined for convinence. You can use +it to allow or deny lints, eg.: + + #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] +"#; pub fn main() { use std::env; @@ -213,13 +217,16 @@ pub fn main() { // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly // without having to pass --sysroot or anything - let args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { env::args().collect() } else { env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() }; + // this check ensures that dependencies are built but not linted and the final crate is // linted but not built + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + let mut ccc = ClippyCompilerCalls::new(env::args().any(|s| s == "-Zno-trans")); let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); @@ -251,6 +258,8 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> args.push(String::from("--sysroot")); args.push(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); + args.push("--cfg".to_owned()); + args.push(r#"feature="cargo-clippy""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = std::process::Command::new("cargo") -- cgit 1.4.1-3-g733a5 From da943f5ec881a8f969903bd96b8cfa046d801ba1 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 24 Oct 2016 16:29:36 +0200 Subject: Allow `--help` to be any argument Also dogfoog. --- src/main.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index fe1a453ff62..6ae388401cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -136,6 +136,11 @@ it to allow or deny lints, eg.: #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] "#; +#[allow(print_stdout)] +fn show_help() { + println!("{}", CARGO_CLIPPY_HELP); +} + pub fn main() { use std::env; @@ -165,12 +170,9 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - match std::env::args().nth(2).as_ref().map(AsRef::as_ref) { - Some("--help") | Some("-h") => { - println!("{}", CARGO_CLIPPY_HELP); - return; - } - _ => (), + if std::env::args().any(|a| a == "--help" || a == "-h") { + show_help(); + return; } let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); -- cgit 1.4.1-3-g733a5 From ec893a198fd20ee0c481ac410223fc8aaa246525 Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Tue, 25 Oct 2016 15:09:56 +0200 Subject: Fix small nits on the help message --- src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 6ae388401cf..44c3b61d22c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -122,16 +122,16 @@ Common options: Other options are the same as `cargo rustc`. -To allow or deny a lint from the command line you can use `cargo clippy --` with -one of: +To allow or deny a lint from the command line you can use `cargo clippy --` +with: -W --warn OPT Set lint warnings -A --allow OPT Set lint allowed -D --deny OPT Set lint denied -F --forbid OPT Set lint forbidden -The feature `cargo-clippy` is automatically defined for convinence. You can use -it to allow or deny lints, eg.: +The feature `cargo-clippy` is automatically defined for convenience. You can use +it to allow or deny lints from the code, eg.: #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] "#; -- cgit 1.4.1-3-g733a5 From e25b010847c82a78389c7a6a343f525bfcd1c0e4 Mon Sep 17 00:00:00 2001 From: Epicat Supercell <epicatsupercell@gmail.com> Date: Wed, 2 Nov 2016 21:27:42 +0200 Subject: fixed callback changes from rustc 1.14.0-nightly (7c69b0d5a 2016-11-01) --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 44c3b61d22c..b5ce8019151 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,12 +59,11 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, - cfg: &ast::CrateConfig, input: &Input, odir: &Option<PathBuf>, ofile: &Option<PathBuf>) -> Compilation { - self.default.late_callback(matches, sess, cfg, input, odir, ofile) + self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); -- cgit 1.4.1-3-g733a5 From 6a73c8f8e3f513f6a16c6876be3d326633dbc78d Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 8 Nov 2016 11:35:26 +0100 Subject: --sysroot isn't necessary anymore for the outer cargo clippy call --- src/main.rs | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index b5ce8019151..dd7f912e4f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -149,23 +149,6 @@ pub fn main() { let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("SYSROOT") - .map(|s| s.to_owned()) - .or(Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned())) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - }; - if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` @@ -201,11 +184,11 @@ pub fn main() { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path, &sys_root) { + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path) { 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, &sys_root) { + if let Err(code) = process(vec![format!("--{}", first), target.name].into_iter().chain(args), &dep_path) { std::process::exit(code); } } @@ -216,6 +199,23 @@ pub fn main() { } else { // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` env var set to itself + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or(Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned())) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") + }; + // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly // without having to pass --sysroot or anything let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { @@ -239,7 +239,7 @@ pub fn main() { } } -fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> +fn process<P, I>(old_args: I, dep_path: P) -> Result<(), i32> where P: AsRef<Path>, I: Iterator<Item = String> { @@ -256,8 +256,6 @@ fn process<P, I>(old_args: I, dep_path: P, sysroot: &str) -> Result<(), i32> } args.push("-L".to_owned()); args.push(dep_path.as_ref().to_string_lossy().into_owned()); - args.push(String::from("--sysroot")); - args.push(sysroot.to_owned()); args.push("-Zno-trans".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); -- cgit 1.4.1-3-g733a5 From 3800bff4de9f081ef2f02b95d9ba4bae529c82af Mon Sep 17 00:00:00 2001 From: Machtan <jako3047@gmail.com> Date: Tue, 8 Nov 2016 13:54:08 +0100 Subject: Add '--version' flag and allow version and help flags when called as 'cargo-clippy' --- src/main.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index dd7f912e4f6..d1e9bd74c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -118,6 +118,7 @@ Usage: Common options: -h, --help Print this message --features Features to compile for the package + -V, --version Print version info and exit Other options are the same as `cargo rustc`. @@ -146,17 +147,22 @@ 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(); + return; + } + if std::env::args().any(|a| a == "--version" || a == "-V") { + println!("{}", env!("CARGO_PKG_VERSION")); + return; + } let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - if std::env::args().any(|a| a == "--help" || a == "-h") { - show_help(); - return; - } - let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); let mut metadata = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)).expect("could not obtain cargo metadata"); -- cgit 1.4.1-3-g733a5 From e5a5a95a1071be7b9f0523cd2b706e4cdf09e53d Mon Sep 17 00:00:00 2001 From: Machtan <jako3047@gmail.com> Date: Tue, 8 Nov 2016 14:28:46 +0100 Subject: Add '--version' flag and use version and help flags when called as 'cargo-clippy' --- src/main.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index d1e9bd74c1e..387cdb864ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,8 +17,9 @@ use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session}; use rustc::session::config::{Input, ErrorOutputType}; use std::path::PathBuf; -use std::process::Command; +use std::process::{self, Command}; use syntax::ast; +use std::io::{self, Write}; use clippy_lints::utils::cargo; @@ -141,6 +142,12 @@ fn show_help() { println!("{}", CARGO_CLIPPY_HELP); } +#[allow(print_stdout)] +fn show_version() { + println!("{}", env!("CARGO_PKG_VERSION")); +} + +#[cfg_attr(feature = "cargo-clippy", allow(print_stdout))] pub fn main() { use std::env; @@ -154,7 +161,7 @@ pub fn main() { return; } if std::env::args().any(|a| a == "--version" || a == "-V") { - println!("{}", env!("CARGO_PKG_VERSION")); + show_version(); return; } @@ -165,7 +172,12 @@ pub fn main() { let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)).expect("could not obtain cargo metadata"); + let mut metadata = if let Ok(metadata) = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { + metadata + } else { + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.")); + process::exit(101); + }; assert_eq!(metadata.version, 1); -- cgit 1.4.1-3-g733a5 From d16cc47ae8e414613619754df50241f74a59d5d9 Mon Sep 17 00:00:00 2001 From: debris <marek.kotewicz@gmail.com> Date: Tue, 8 Nov 2016 21:50:35 +0100 Subject: fixed #1331 --- src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index dd7f912e4f6..74a2b3e3feb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -226,9 +226,13 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final crate is // linted but not built - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); - let mut ccc = ClippyCompilerCalls::new(env::args().any(|s| s == "-Zno-trans")); + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } + + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); if let Err(err_count) = result { -- cgit 1.4.1-3-g733a5 From 2d9386f86dd93bf4e048c7fe362dde0a603b858c Mon Sep 17 00:00:00 2001 From: Jakob Lautrup Nysom <jako3047@gmail.com> Date: Wed, 9 Nov 2016 10:44:55 +0100 Subject: Remove unnecessary #[allow] --- src/main.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 387cdb864ee..8f2975636e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -147,7 +147,6 @@ fn show_version() { println!("{}", env!("CARGO_PKG_VERSION")); } -#[cfg_attr(feature = "cargo-clippy", allow(print_stdout))] pub fn main() { use std::env; -- cgit 1.4.1-3-g733a5 From 7dd3679ac346180c53c6167c541cd1cb16adac7a Mon Sep 17 00:00:00 2001 From: mcarton <cartonmartin+git@gmail.com> Date: Mon, 19 Dec 2016 20:22:38 +0100 Subject: Fix a couple warnings --- clippy_lints/src/types.rs | 13 ++++++------- src/lib.rs | 12 +++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index d2bc850e207..930c44c8863 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -757,7 +757,6 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs 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 { @@ -772,17 +771,17 @@ 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, } } diff --git a/src/lib.rs b/src/lib.rs index 1b9333d80b0..9672f16eddc 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. -- cgit 1.4.1-3-g733a5 From 0a7ae5fec80d31b89bdc8ecd1ef90350a6f61f66 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 20 Dec 2016 10:20:41 +0100 Subject: run rustfmt --- .gitignore | 3 +++ rustfmt.toml | 4 +++- src/main.rs | 47 ++++++++++++++++++++++------------------------- tests/ice_exacte_size.rs | 2 +- tests/issue-825.rs | 17 ++++------------- tests/trim_multiline.rs | 2 ++ 6 files changed, 35 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index a6b636709c5..33ecb63593c 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/rustfmt.toml b/rustfmt.toml index c0695c04126..da21e5a30e7 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -2,4 +2,6 @@ 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 +fn_args_paren_newline = false +closure_block_indent_threshold = -1 +match_block_trailing_comma = true diff --git a/src/main.rs b/src/main.rs index a839bbad341..89db653929c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,30 +38,17 @@ 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) + 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<PathBuf>, - ofile: &Option<PathBuf>, - descriptions: &rustc_errors::registry::Registry) + fn no_input(&mut self, matches: &getopts::Matches, sopts: &config::Options, cfg: &ast::CrateConfig, + odir: &Option<PathBuf>, ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry) -> Option<(Input, Option<PathBuf>)> { self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } - fn late_callback(&mut self, - matches: &getopts::Matches, - sess: &Session, - input: &Input, - odir: &Option<PathBuf>, + fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, input: &Input, odir: &Option<PathBuf>, ofile: &Option<PathBuf>) -> Compilation { self.default.late_callback(matches, sess, input, odir, ofile) @@ -73,7 +60,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 +145,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 +176,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 +199,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 +280,10 @@ fn process<P, I>(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/ice_exacte_size.rs b/tests/ice_exacte_size.rs index 37e3b4ebe7a..eeab3a2bec5 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 76b0250ca0e..87cbb72f585 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 90f1c76fb80..d6de36bfca7 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 { -- cgit 1.4.1-3-g733a5 From ed9d71f2c9ff058f1b3ae02b8b7351dcace97190 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 21 Dec 2016 10:25:14 +0100 Subject: remove nondeterminism by adjusting thresholds --- clippy_lints/src/array_indexing.rs | 5 ++-- clippy_lints/src/attrs.rs | 14 +++++------ clippy_lints/src/copies.rs | 3 ++- clippy_lints/src/derive.rs | 4 +-- clippy_lints/src/doc.rs | 4 ++- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_variants.rs | 12 +++++---- clippy_lints/src/escape.rs | 6 +++-- clippy_lints/src/eval_order_dependence.rs | 3 ++- clippy_lints/src/functions.rs | 12 ++++++--- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/lifetimes.rs | 6 ++--- clippy_lints/src/loops.rs | 28 ++++++++++----------- clippy_lints/src/matches.rs | 11 ++++----- clippy_lints/src/methods.rs | 34 ++++++++++++++------------ clippy_lints/src/misc_early.rs | 10 ++++---- clippy_lints/src/missing_doc.rs | 5 +++- clippy_lints/src/needless_bool.rs | 24 ++++++++---------- clippy_lints/src/new_without_default.rs | 6 +++-- clippy_lints/src/non_expressive_names.rs | 6 +++-- clippy_lints/src/overflow_check_conditional.rs | 12 ++++++--- clippy_lints/src/shadow.rs | 20 +++++++-------- clippy_lints/src/strings.rs | 8 +++--- clippy_lints/src/types.rs | 8 +++--- clippy_lints/src/unused_label.rs | 6 +++-- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/inspector.rs | 3 ++- clippy_lints/src/utils/mod.rs | 9 +++---- rustfmt.toml | 4 +++ src/main.rs | 21 +++++++++------- 30 files changed, 157 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index 3387f68d93b..aa9af2e681d 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -107,9 +107,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { } /// Returns an option containing a tuple with the start and end (exclusive) of the range. -fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, - array_size: ConstInt) - -> Option<(ConstInt, ConstInt)> { +fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>, limits: RangeLimits, array_size: ConstInt) + -> Option<(ConstInt, ConstInt)> { let start = match start { Some(Some(ConstVal::Integral(x))) => x, Some(_) => return None, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 528a62d7f02..24fd5a1483d 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 @@ -125,11 +127,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { attr.span, "useless lint attribute", |db| { - sugg.insert(1, '!'); - db.span_suggestion(attr.span, - "if you just forgot a `!`, use", - sugg); - }); + sugg.insert(1, '!'); + db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg); + }); } } }, diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 5ef9f67a3b8..9a9b97d0e81 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -204,7 +204,8 @@ 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 + // 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)); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 463923136ff..8836af28d09 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -169,7 +169,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 76e8f867040..20c82ee4660 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -268,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; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 657018a0ab9..2ff31b3a4fe 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { } fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr) - -> Option<(&'static str, &'b Expr, &'b Expr)> { + -> Option<(&'static str, &'b Expr, &'b Expr)> { if_let_chain! {[ let ExprMethodCall(ref name, _, ref params) = check.node, params.len() >= 2, diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index ab47b7cffe2..e3bfca0b2f5 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -49,10 +49,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. /// @@ -111,8 +114,7 @@ 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) { if (def.variants.len() as u64) < threshold { return; } diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 17ff2613dda..d66c8757ef2 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -61,8 +61,10 @@ impl LintPass for Pass { } 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) { + 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); diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index d975a88f7ab..f83b3271d50 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -146,7 +146,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { } }, _ => { - // 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); diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 801532a1c3b..58425ff2a40 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -69,8 +69,10 @@ impl LintPass for Functions { } 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) { + 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)) { @@ -124,8 +126,10 @@ impl<'a, 'tcx> Functions { } } - fn check_raw_ptr(&self, cx: &LateContext<'a, 'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl, - expr: &'tcx hir::Expr, nodeid: ast::NodeId) { + fn check_raw_ptr( + &self, cx: &LateContext<'a, 'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl, expr: &'tcx hir::Expr, + nodeid: ast::NodeId + ) { if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::<HashSet<_>>(); diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 786420bbe65..c6efc3fd736 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -150,7 +150,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> { } fn check_assign<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: hir::def_id::DefId, block: &'tcx hir::Block) - -> Option<&'tcx hir::Expr> { + -> Option<&'tcx hir::Expr> { if_let_chain! {[ block.expr.is_none(), let Some(expr) = block.stmts.iter().last(), diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 081345a09e6..e9f93d04360 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -116,10 +116,8 @@ fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, gene report_extra_lifetimes(cx, decl, generics); } -fn could_use_elision<'a, 'tcx: 'a, T: Iterator<Item = &'tcx Lifetime>>(cx: &LateContext<'a, 'tcx>, - func: &'tcx FnDecl, - named_lts: &'tcx [LifetimeDef], bounds_lts: T) - -> bool { +fn could_use_elision<'a, 'tcx: 'a, T: Iterator<Item = &'tcx Lifetime>>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, named_lts: &'tcx [LifetimeDef], bounds_lts: T) + -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT // * output references, exactly one input reference with same LT diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index e85d0f40c4b..3a7012972ba 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -351,11 +351,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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); + }); } }, _ => (), @@ -379,10 +379,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { expr.span, "this loop could be written as a `for` loop", |db| { - db.span_suggestion(expr.span, - "try", - format!("for {} in {} {{ .. }}", loop_var, iterator)); - }); + db.span_suggestion(expr.span, "try", format!("for {} in {} {{ .. }}", loop_var, iterator)); + }); } } } @@ -473,11 +471,11 @@ fn check_for_loop_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, ar expr.span, &format!("the loop variable `{}` is used to index `{}`", ident.node, indexed), |db| { - multispan_sugg(db, + multispan_sugg(db, "consider using an iterator".to_string(), &[(pat.span, &format!("({}, <item>)", ident.node)), (arg.span, &format!("{}.iter().enumerate(){}{}", indexed, take, skip))]); - }); + }); } else { let repl = if starts_at_zero && take.is_empty() { format!("&{}", indexed) @@ -492,10 +490,10 @@ fn check_for_loop_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, ar ident.node, indexed), |db| { - multispan_sugg(db, - "consider using an iterator".to_string(), - &[(pat.span, "<item>"), (arg.span, &repl)]); - }); + multispan_sugg(db, + "consider using an iterator".to_string(), + &[(pat.span, "<item>"), (arg.span, &repl)]); + }); } } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index e1216c8493b..b1b52cfb015 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -322,10 +322,10 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match expr.span, "you don't need to add `&` to both the expression and the patterns", |db| { - let inner = Sugg::hir(cx, inner, ".."); - let template = match_template(expr.span, source, inner); - db.span_suggestion(expr.span, "try", template); - }); + let inner = Sugg::hir(cx, inner, ".."); + let template = match_template(expr.span, source, inner); + db.span_suggestion(expr.span, "try", template); + }); } else { span_lint_and_then(cx, MATCH_REF_PATS, @@ -335,8 +335,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); }); } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 5ecd1c06a5d..ebb90c9eef0 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -695,9 +695,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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; } @@ -721,11 +722,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: 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, "_"))); - }); + db.span_suggestion(span, + "try this", + format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); + }); return true; } } @@ -736,8 +736,10 @@ 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) { @@ -776,10 +778,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: span, &format!("use of `{}` followed by a function call", name), |db| { - db.span_suggestion(span, + db.span_suggestion(span, "try this", format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); - }); + }); } if args.len() == 2 { @@ -836,10 +838,10 @@ fn lint_vec_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { expr.span, "use of `extend` to extend a Vec by a slice", |db| { - db.span_suggestion(expr.span, + db.span_suggestion(expr.span, "try this", format!("{}.extend_from_slice({})", snippet(cx, args[0].span, "_"), slice)); - }); + }); } } @@ -1223,8 +1225,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); + }); } } } diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 9d9f30c820c..bccc1164047 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -277,11 +277,11 @@ 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); + } + }); } } }, diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 403c6ddcbdf..70696ea3908 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -14,7 +14,10 @@ // 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 +// [`missing_doc`]: +// https://github. +// com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin. +// rs#L246 // use rustc::hir; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 9a0d5f1bb36..5eae3034aff 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -75,8 +75,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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)) | @@ -124,8 +124,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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(); @@ -134,8 +134,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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, ".."); @@ -144,10 +144,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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, ".."); @@ -156,10 +154,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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()); + }); }, _ => (), } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 4c9ff328896..2a75a19dd28 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -90,8 +90,10 @@ impl LintPass for NewWithoutDefault { } 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) { + 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; } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index fd8ffb36d46..a195673a53b 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -241,7 +241,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { 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: &'tcx Block) { @@ -249,7 +250,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { } 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/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index a09ff3bebf6..f2e47886549 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -44,12 +44,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional { ], { 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."); } } }} @@ -66,12 +68,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional { ], { 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/shadow.rs b/clippy_lints/src/shadow.rs index 9961a26b5c4..36fd33b22ce 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -233,8 +233,8 @@ fn lint_shadow<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, span: Span, snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..")), |db| { - db.span_note(prev_span, "previous binding is here"); - }); + db.span_note(prev_span, "previous binding is here"); + }); } else if contains_self(cx, name, expr) { span_lint_and_then(cx, SHADOW_REUSE, @@ -243,9 +243,9 @@ fn lint_shadow<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, 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, @@ -254,9 +254,9 @@ fn lint_shadow<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, 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 { @@ -265,8 +265,8 @@ fn lint_shadow<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, span: Span, span, &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), |db| { - db.span_note(prev_span, "previous binding is here"); - }); + db.span_note(prev_span, "previous binding is here"); + }); } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 844fd9482ff..195b49c72f6 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -152,11 +152,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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/types.rs b/clippy_lints/src/types.rs index 2ef66cf7644..e3a9758d2b7 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -741,7 +741,7 @@ enum AbsurdComparisonResult { fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) - -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { + -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { use types::ExtremeType::*; use types::AbsurdComparisonResult::*; use utils::comparisons::*; @@ -1007,8 +1007,10 @@ 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 { diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index b58456ce85e..ebb7735171e 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -41,8 +41,10 @@ impl LintPass for UnusedLabel { } 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) { + 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; } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0ba86ff55dc..7c83a7f69a5 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -9,7 +9,7 @@ use toml; /// Get the configuration file from arguments. pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) - -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> { + -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> { for arg in args.iter().filter_map(|a| a.meta_item()) { if arg.name() == "conf_file" { return match arg.node { diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 83d96b8db61..79cf15b6c5f 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -73,7 +73,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // } // } // - // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: &hir::Generics) { + // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: + // &hir::Generics) { // if !has_attr(&var.node.attrs) { // return; // } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f31ce3706eb..dc25020d3fc 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -317,9 +317,8 @@ pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { /// 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<ty::Ty<'tcx>>) - -> bool { +pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, trait_id: DefId, ty_params: Vec<ty::Ty<'tcx>>) + -> bool { cx.tcx.populate_implementations_for_trait_if_necessary(trait_id); let ty = cx.tcx.erase_regions(&ty); @@ -403,7 +402,7 @@ pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &' /// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. /// Also takes an `Option<String>` which can be put inside the braces. pub fn expr_block<'a, 'b, T: LintContext<'b>>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) - -> Cow<'a, str> { + -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.unwrap_or_default(); if let ExprBlock(_) = expr.node { @@ -758,7 +757,7 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T // 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 { + -> 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); diff --git a/rustfmt.toml b/rustfmt.toml index 6daad2b65bd..0d8362496c1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -4,3 +4,7 @@ fn_args_density = "Compressed" fn_call_width = 80 fn_args_paren_newline = false 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/main.rs b/src/main.rs index 89db653929c..35153ebe8af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,19 +38,22 @@ 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<PathBuf>, ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry) - -> Option<(Input, Option<PathBuf>)> { + fn no_input( + &mut self, matches: &getopts::Matches, sopts: &config::Options, cfg: &ast::CrateConfig, odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry + ) -> Option<(Input, Option<PathBuf>)> { self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } - fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, input: &Input, odir: &Option<PathBuf>, - ofile: &Option<PathBuf>) - -> Compilation { + fn late_callback( + &mut self, matches: &getopts::Matches, sess: &Session, input: &Input, odir: &Option<PathBuf>, + ofile: &Option<PathBuf> + ) -> Compilation { self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { -- cgit 1.4.1-3-g733a5 From 0553de85738f67cdb760c170e013599449a9613d Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 21 Dec 2016 12:36:25 +0100 Subject: run rustfmt on clippy, not only on clippy_lints --- src/main.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 35153ebe8af..0b91c79d21b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,19 +39,32 @@ 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 + &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<PathBuf>, - ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry + &mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, + descriptions: &rustc_errors::registry::Registry ) -> Option<(Input, Option<PathBuf>)> { self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback( - &mut self, matches: &getopts::Matches, sess: &Session, input: &Input, odir: &Option<PathBuf>, + &mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option<PathBuf>, ofile: &Option<PathBuf> ) -> Compilation { self.default.late_callback(matches, sess, input, odir, ofile) -- cgit 1.4.1-3-g733a5 From dbde3b8e1c724580a450176f05cdd413ba535454 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 15 Jan 2017 00:33:29 +0100 Subject: dogfood fallout --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 0b91c79d21b..38610701808 100644 --- a/src/main.rs +++ b/src/main.rs @@ -234,7 +234,7 @@ pub fn main() { } else { option_env!("SYSROOT") .map(|s| s.to_owned()) - .or(Command::new("rustc") + .or_else(|| Command::new("rustc") .arg("--print") .arg("sysroot") .output() -- cgit 1.4.1-3-g733a5 From 94c97d2ec9c2d6a88d3e9fabf3d9a9d640f8bd47 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sun, 15 Jan 2017 01:03:46 +0100 Subject: formatting --- clippy_lints/src/methods.rs | 6 +++--- src/main.rs | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 4d48ff45c92..578fda8e791 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -786,11 +786,11 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { check_general_case(cx, name, fun.span, &args[0], &args[1], or_has_args, expr.span); } - } + }, hir::ExprMethodCall(fun, _, ref or_args) => { check_general_case(cx, name, fun.span, &args[0], &args[1], !or_args.is_empty(), expr.span) - } - _ => {} + }, + _ => {}, } } } diff --git a/src/main.rs b/src/main.rs index 38610701808..036adae8366 100644 --- a/src/main.rs +++ b/src/main.rs @@ -234,13 +234,15 @@ pub fn main() { } else { option_env!("SYSROOT") .map(|s| s.to_owned()) - .or_else(|| Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned())) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") }; -- cgit 1.4.1-3-g733a5 From 26e8558d8a7bb72f621696e36a02ea575574a69b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 24 Jan 2017 11:31:42 +0100 Subject: remove rustc-serialize dependency and factor `util::cargo` out into a crate --- Cargo.toml | 5 ++- clippy_lints/Cargo.toml | 1 - clippy_lints/src/lib.rs | 2 - clippy_lints/src/utils/cargo.rs | 77 ---------------------------------- clippy_lints/src/utils/mod.rs | 1 - src/main.rs | 6 +-- tests/compile-fail/serde.rs | 21 +++++++--- tests/used_underscore_binding_macro.rs | 4 +- tests/versioncheck.rs | 7 ++-- 9 files changed, 25 insertions(+), 99 deletions(-) delete mode 100644 clippy_lints/src/utils/cargo.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 98f71d01ea0..a21a4a65875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,14 +32,15 @@ test = false # begin automatic update clippy_lints = { version = "0.0.111", path = "clippy_lints" } # end automatic update +cargo_metadata = "0.1" [dev-dependencies] compiletest_rs = "0.2.5" lazy_static = "0.1.15" regex = "0.2" -rustc-serialize = "0.3" +serde_derive = "0.9.0-rc3" clippy-mini-macro-test = { version = "0.1", path = "mini-macro" } -serde = "0.7" +serde = "0.9.0-rc3" [features] debugging = [] diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 9a5ea23e6a5..fb147b2a186 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -22,7 +22,6 @@ semver = "0.2.1" toml = "0.2" unicode-normalization = "0.1" quine-mc_cluskey = "0.2.2" -rustc-serialize = "0.3" [features] debugging = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d797c567b8..2b778e12cb3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -38,8 +38,6 @@ extern crate regex_syntax; // for finding minimal boolean expressions extern crate quine_mc_cluskey; -extern crate rustc_serialize; - extern crate rustc_errors; extern crate rustc_plugin; extern crate rustc_const_eval; diff --git a/clippy_lints/src/utils/cargo.rs b/clippy_lints/src/utils/cargo.rs deleted file mode 100644 index b9ce8626eb9..00000000000 --- a/clippy_lints/src/utils/cargo.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::collections::HashMap; -use std::process::Command; -use std::str::{from_utf8, Utf8Error}; -use std::io; -use rustc_serialize::json; - -#[derive(RustcDecodable, Debug)] -pub struct Metadata { - pub packages: Vec<Package>, - resolve: Option<()>, - pub version: usize, -} - -#[derive(RustcDecodable, Debug)] -pub struct Package { - pub name: String, - pub version: String, - id: String, - source: Option<String>, - pub dependencies: Vec<Dependency>, - pub targets: Vec<Target>, - features: HashMap<String, Vec<String>>, - pub manifest_path: String, -} - -#[derive(RustcDecodable, Debug)] -pub struct Dependency { - pub name: String, - source: Option<String>, - pub req: String, - kind: Option<String>, - optional: bool, - uses_default_features: bool, - features: Vec<String>, - target: Option<String>, -} - -#[derive(RustcDecodable, Debug)] -pub struct Target { - pub name: String, - pub kind: Vec<String>, - src_path: String, -} - -#[derive(Debug)] -pub enum Error { - Io(io::Error), - Utf8(Utf8Error), - Json(json::DecoderError), -} - -impl From<io::Error> for Error { - fn from(err: io::Error) -> Self { - Error::Io(err) - } -} -impl From<Utf8Error> for Error { - fn from(err: Utf8Error) -> Self { - Error::Utf8(err) - } -} -impl From<json::DecoderError> for Error { - fn from(err: json::DecoderError) -> Self { - Error::Json(err) - } -} - -pub fn metadata(manifest_path_arg: Option<&str>) -> Result<Metadata, Error> { - let mut cmd = Command::new("cargo"); - cmd.arg("metadata").arg("--no-deps"); - if let Some(mani) = manifest_path_arg { - cmd.arg(mani); - } - let output = cmd.output()?; - let stdout = from_utf8(&output.stdout)?; - Ok(json::decode(stdout)?) -} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d453a90950b..ef9c6b9c38a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -21,7 +21,6 @@ use syntax::errors::DiagnosticBuilder; use syntax::ptr::P; use syntax::symbol::keywords; -pub mod cargo; pub mod comparisons; pub mod conf; pub mod constants; diff --git a/src/main.rs b/src/main.rs index 036adae8366..1be98cbeb92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ use std::process::{self, Command}; use syntax::ast; use std::io::{self, Write}; -use clippy_lints::utils::cargo; +extern crate cargo_metadata; struct ClippyCompilerCalls { default: RustcDefaultCalls, @@ -179,15 +179,13 @@ pub fn main() { let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = if let Ok(metadata) = cargo::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata } else { let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.")); process::exit(101); }; - assert_eq!(metadata.version, 1); - let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); let current_dir = std::env::current_dir(); diff --git a/tests/compile-fail/serde.rs b/tests/compile-fail/serde.rs index d5099edbc0c..a0671f07101 100644 --- a/tests/compile-fail/serde.rs +++ b/tests/compile-fail/serde.rs @@ -9,14 +9,19 @@ struct A; impl serde::de::Visitor for A { type Value = (); - fn visit_str<E>(&mut self, _v: &str) -> Result<Self::Value, E> - where E: serde::Error, + + fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + unimplemented!() + } + + fn visit_str<E>(self, _v: &str) -> Result<Self::Value, E> + where E: serde::de::Error, { unimplemented!() } - fn visit_string<E>(&mut self, _v: String) -> Result<Self::Value, E> - where E: serde::Error, + fn visit_string<E>(self, _v: String) -> Result<Self::Value, E> + where E: serde::de::Error, { unimplemented!() } @@ -27,9 +32,13 @@ struct B; impl serde::de::Visitor for B { type Value = (); - fn visit_string<E>(&mut self, _v: String) -> Result<Self::Value, E> + fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + unimplemented!() + } + + fn visit_string<E>(self, _v: String) -> Result<Self::Value, E> //~^ ERROR you should not implement `visit_string` without also implementing `visit_str` - where E: serde::Error, + where E: serde::de::Error, { unimplemented!() } diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs index 9cd44d44001..c7da8e4f9c1 100644 --- a/tests/used_underscore_binding_macro.rs +++ b/tests/used_underscore_binding_macro.rs @@ -1,11 +1,11 @@ #![feature(plugin)] #![plugin(clippy)] -extern crate rustc_serialize; +#[macro_use] extern crate serde_derive; /// Test that we do not lint for unused underscores in a `MacroAttribute` expansion #[deny(used_underscore_binding)] -#[derive(RustcEncodable)] +#[derive(Deserialize)] struct MacroAttributesTest { _foo: u32, } diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index e216c801546..beea9ab7e64 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -1,11 +1,10 @@ -extern crate clippy_lints; -use clippy_lints::utils::cargo; +extern crate cargo_metadata; #[test] fn check_that_clippy_lints_has_the_same_version_as_clippy() { - let clippy_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); + let clippy_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); - let clippy_lints_meta = cargo::metadata(None).expect("could not obtain cargo metadata"); + let clippy_lints_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { -- cgit 1.4.1-3-g733a5 From 4a70a46d2ddd567c71b5d3042d1ff8efea1909d3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 24 Jan 2017 18:06:17 +0100 Subject: run rustfmt --- src/main.rs | 3 ++- tests/used_underscore_binding_macro.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 1be98cbeb92..7a744356eb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,7 +179,8 @@ pub fn main() { let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref() + .map(AsRef::as_ref)) { metadata } else { let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.")); diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs index c7da8e4f9c1..90cb106dea6 100644 --- a/tests/used_underscore_binding_macro.rs +++ b/tests/used_underscore_binding_macro.rs @@ -1,7 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] -#[macro_use] extern crate serde_derive; +#[macro_use] +extern crate serde_derive; /// Test that we do not lint for unused underscores in a `MacroAttribute` expansion #[deny(used_underscore_binding)] -- cgit 1.4.1-3-g733a5 From ad01fa9b57a0d30358e5ab74e0ecbc565e005f7d Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 11 Feb 2017 01:42:14 +0100 Subject: Remove stabilized feature flag --- src/main.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 7a744356eb4..ac90528c606 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(static_in_const)] #![allow(unknown_lints, missing_docs_in_private_items)] -- cgit 1.4.1-3-g733a5 From 1b0749a6d0e219e4936b13dbec08d2fd027e9077 Mon Sep 17 00:00:00 2001 From: Ben Boeckel <ben.boeckel@kitware.com> Date: Thu, 16 Feb 2017 13:18:00 -0500 Subject: main: end error messages with a newline --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index ac90528c606..9d67ba3958a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -182,7 +182,7 @@ pub fn main() { .map(AsRef::as_ref)) { metadata } else { - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.")); + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); process::exit(101); }; -- cgit 1.4.1-3-g733a5 From 5c2549482a9974a145e5c45c61d03f9606d5e8a3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 28 Feb 2017 12:47:48 +0100 Subject: Get cargo clippy working on 64 bit windows again fixes #1244 --- appveyor.yml | 4 +--- src/main.rs | 41 +++++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/appveyor.yml b/appveyor.yml index 74b659b0b0f..d83d3478c32 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,10 +4,8 @@ environment: matrix: - TARGET: i686-pc-windows-gnu MSYS2_BITS: 32 - RUN_CARGO_CLIPPY: true - TARGET: i686-pc-windows-msvc MSYS2_BITS: 32 - RUN_CARGO_CLIPPY: true - TARGET: x86_64-pc-windows-gnu MSYS2_BITS: 64 - TARGET: x86_64-pc-windows-msvc @@ -29,7 +27,7 @@ test_script: - cargo test --features debugging - copy target\debug\cargo-clippy.exe C:\Users\appveyor\.cargo\bin\ - cargo clippy -- -D clippy - - if defined RUN_CARGO_CLIPPY cd clippy_lints && cargo clippy -- -D clippy && cd .. + - cd clippy_lints && cargo clippy -- -D clippy && cd .. notifications: - provider: Email diff --git a/src/main.rs b/src/main.rs index 9d67ba3958a..c7681364f18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -244,30 +244,31 @@ pub fn main() { .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") }; - // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { - env::args().collect() - } else { - env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() - }; - - // this check ensures that dependencies are built but not linted and the final crate is - // linted but not built - let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); + rustc_driver::in_rustc_thread(|| { + // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + env::args().collect() + } else { + env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() + }; - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - } + // this check ensures that dependencies are built but not linted and the final crate is + // linted but not built + let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } - if let Err(err_count) = result { - if err_count > 0 { - std::process::exit(1); + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if let Err(err_count) = result { + if err_count > 0 { + std::process::exit(1); + } } - } + }).expect("rustc_thread failed"); } } -- cgit 1.4.1-3-g733a5 From a78ca9e955d66c7f676482e348c6ba4e89cfc24a Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 28 Feb 2017 14:29:06 +0100 Subject: Run rustfmt --- src/main.rs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index c7681364f18..12dd5d1f695 100644 --- a/src/main.rs +++ b/src/main.rs @@ -245,30 +245,31 @@ pub fn main() { }; rustc_driver::in_rustc_thread(|| { - // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { - env::args().collect() - } else { - env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() - }; + // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + env::args().collect() + } else { + env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() + }; - // this check ensures that dependencies are built but not linted and the final crate is - // linted but not built - let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); + // this check ensures that dependencies are built but not linted and the final crate is + // linted but not built + let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - } + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(err_count) = result { - if err_count > 0 { - std::process::exit(1); + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if let Err(err_count) = result { + if err_count > 0 { + std::process::exit(1); + } } - } - }).expect("rustc_thread failed"); + }) + .expect("rustc_thread failed"); } } -- cgit 1.4.1-3-g733a5 From 9aebb59a680997b82f7008886b7a31a3e71a1e1f Mon Sep 17 00:00:00 2001 From: Techcable <Techcable@techcable.net> Date: Sun, 12 Mar 2017 20:13:20 -0700 Subject: Fix compilation on latest nightly The ability for plugins to add MIR passes was removed as of 4ca9c97ac. Luckily, we don't use this feature at all and can safely ignore it. Fixes #1618 --- src/main.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 12dd5d1f695..1ca0d2b92f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,7 +89,6 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { lint_groups, llvm_passes, attributes, - mir_passes, .. } = registry; let sess = &state.session; let mut ls = sess.lint_store.borrow_mut(); @@ -105,7 +104,6 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { } sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.mir_passes.borrow_mut().extend(mir_passes); sess.plugin_attributes.borrow_mut().extend(attributes); } old(state); -- cgit 1.4.1-3-g733a5 From 8f88ead7d65ad9a80fa2535dfce83458efda3a7b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 27 Mar 2017 14:51:37 +0200 Subject: Remove some legacy code --- src/main.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 1ca0d2b92f3..0e25ca9734e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -169,8 +169,6 @@ pub fn main() { return; } - let dep_path = env::current_dir().expect("current dir is not readable").join("target").join("debug").join("deps"); - if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` @@ -207,12 +205,11 @@ pub fn main() { let args = std::env::args().skip(2); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args), &dep_path) { + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { 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)) { std::process::exit(code); } } @@ -271,9 +268,8 @@ pub fn main() { } } -fn process<P, I>(old_args: I, dep_path: P) -> Result<(), i32> - where P: AsRef<Path>, - I: Iterator<Item = String> +fn process<I>(old_args: I) -> Result<(), i32> + where I: Iterator<Item = String> { let mut args = vec!["rustc".to_owned()]; @@ -286,8 +282,6 @@ fn process<P, I>(old_args: I, dep_path: P) -> Result<(), i32> if !found_dashes { args.push("--".to_owned()); } - args.push("-L".to_owned()); - args.push(dep_path.as_ref().to_string_lossy().into_owned()); args.push("-Zno-trans".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); -- cgit 1.4.1-3-g733a5 From 584246356214bfd8aeaecda95bf76af7b6264cb0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de> Date: Wed, 12 Apr 2017 11:06:32 +0200 Subject: Run rustfmt --- clippy_lints/src/copies.rs | 10 +-- clippy_lints/src/entry.rs | 4 +- clippy_lints/src/eq_op.rs | 97 +++++++++++++-------------- clippy_lints/src/formatting.rs | 40 ++++++++--- clippy_lints/src/lifetimes.rs | 24 ++++--- clippy_lints/src/loops.rs | 3 +- clippy_lints/src/misc.rs | 4 +- clippy_lints/src/needless_bool.rs | 42 ++++++------ clippy_lints/src/utils/hir.rs | 2 +- clippy_lints/src/utils/mod.rs | 12 ++-- src/lib.rs | 9 ++- src/main.rs | 118 +++++++++++++++++++-------------- tests/cc_seme.rs | 10 +-- tests/matches.rs | 8 ++- tests/used_underscore_binding_macro.rs | 3 +- 15 files changed, 219 insertions(+), 167 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index ea7bbfe81e0..6fe089cf916 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -223,7 +223,7 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { /// `if a { c } else if b { d } else { e }`. fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { let mut conds = SmallVector::new(); - let mut blocks : SmallVector<&Block> = SmallVector::new(); + let mut blocks: SmallVector<&Block> = SmallVector::new(); while let ExprIf(ref cond, ref then_expr, ref else_expr) = expr.node { conds.push(&**cond); @@ -315,10 +315,10 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> return None; } else if exprs.len() == 2 { return if eq(&exprs[0], &exprs[1]) { - Some((&exprs[0], &exprs[1])) - } else { - None - }; + Some((&exprs[0], &exprs[1])) + } else { + None + }; } let mut map: HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len()); diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 06e9268d22a..73d9f8ba161 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -46,11 +46,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { if let Some((ty, map, key)) = check_cond(cx, check) { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message - let sole_expr = { + let sole_expr = { else_block.is_none() && if let ExprBlock(ref then_block) = then_block.node { (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 - } else { + } else { true } }; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 6fbf99f1342..764bcded5ed 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -56,9 +56,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { if is_valid_operator(op) { if SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) { span_lint(cx, - EQ_OP, - e.span, - &format!("equal expressions as operands to `{}`", op.node.as_str())); + EQ_OP, + e.span, + &format!("equal expressions as operands to `{}`", op.node.as_str())); } else { let trait_id = match op.node { BiAdd => cx.tcx.lang_items.add_trait(), @@ -66,19 +66,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { BiMul => cx.tcx.lang_items.mul_trait(), BiDiv => cx.tcx.lang_items.div_trait(), BiRem => cx.tcx.lang_items.rem_trait(), - BiAnd | - BiOr => None, + BiAnd | BiOr => None, BiBitXor => cx.tcx.lang_items.bitxor_trait(), BiBitAnd => cx.tcx.lang_items.bitand_trait(), BiBitOr => cx.tcx.lang_items.bitor_trait(), BiShl => cx.tcx.lang_items.shl_trait(), BiShr => cx.tcx.lang_items.shr_trait(), - BiNe | - BiEq => cx.tcx.lang_items.eq_trait(), - BiLt | - BiLe | - BiGe | - BiGt => cx.tcx.lang_items.ord_trait(), + BiNe | BiEq => cx.tcx.lang_items.eq_trait(), + BiLt | BiLe | BiGe | BiGt => cx.tcx.lang_items.ord_trait(), }; if let Some(trait_id) = trait_id { #[allow(match_same_arms)] @@ -90,57 +85,55 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { (&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => { if implements_trait(cx, cx.tables.expr_ty(l), trait_id, &[cx.tables.expr_ty(r)], None) { span_lint_and_then(cx, - OP_REF, - e.span, - "taken reference of both operands, which is done automatically by the operator anyway", - |db| { - let lsnip = snippet(cx, l.span, "...").to_string(); - let rsnip = snippet(cx, r.span, "...").to_string(); - multispan_sugg(db, - "use the values directly".to_string(), - vec![(left.span, lsnip), + OP_REF, + e.span, + "taken reference of both operands, which is done automatically \ + by the operator anyway", + |db| { + let lsnip = snippet(cx, l.span, "...").to_string(); + let rsnip = snippet(cx, r.span, "...").to_string(); + multispan_sugg(db, + "use the values directly".to_string(), + vec![(left.span, lsnip), (right.span, rsnip)]); - } - ) + }) } - } + }, // &foo == bar (&ExprAddrOf(_, ref l), _) => { - if implements_trait(cx, cx.tables.expr_ty(l), trait_id, &[cx.tables.expr_ty(right)], None) { - span_lint_and_then(cx, - OP_REF, - e.span, - "taken reference of left operand", - |db| { - let lsnip = snippet(cx, l.span, "...").to_string(); - let rsnip = Sugg::hir(cx, right, "...").deref().to_string(); - multispan_sugg(db, - "dereference the right operand instead".to_string(), - vec![(left.span, lsnip), + if implements_trait(cx, + cx.tables.expr_ty(l), + trait_id, + &[cx.tables.expr_ty(right)], + None) { + span_lint_and_then(cx, OP_REF, e.span, "taken reference of left operand", |db| { + let lsnip = snippet(cx, l.span, "...").to_string(); + let rsnip = Sugg::hir(cx, right, "...").deref().to_string(); + multispan_sugg(db, + "dereference the right operand instead".to_string(), + vec![(left.span, lsnip), (right.span, rsnip)]); - } - ) + }) } - } + }, // foo == &bar (_, &ExprAddrOf(_, ref r)) => { - if implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[cx.tables.expr_ty(r)], None) { - span_lint_and_then(cx, - OP_REF, - e.span, - "taken reference of right operand", - |db| { - let lsnip = Sugg::hir(cx, left, "...").deref().to_string(); - let rsnip = snippet(cx, r.span, "...").to_string(); - multispan_sugg(db, - "dereference the left operand instead".to_string(), - vec![(left.span, lsnip), + if implements_trait(cx, + cx.tables.expr_ty(left), + trait_id, + &[cx.tables.expr_ty(r)], + None) { + span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| { + let lsnip = Sugg::hir(cx, left, "...").deref().to_string(); + let rsnip = snippet(cx, r.span, "...").to_string(); + multispan_sugg(db, + "dereference the left operand instead".to_string(), + vec![(left.span, lsnip), (right.span, rsnip)]); - } - ) + }) } - } - _ => {} + }, + _ => {}, } } } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 7fa8c3deb99..8f8c7db64cf 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -100,11 +100,19 @@ impl EarlyLintPass for Formatting { fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) { - let eq_span = Span { lo: lhs.span.hi, hi: rhs.span.lo, ctxt: NO_EXPANSION }; + let eq_span = Span { + lo: lhs.span.hi, + hi: rhs.span.lo, + ctxt: NO_EXPANSION, + }; if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { let op = ast::UnOp::to_string(op); - let eqop_span= Span { lo: lhs.span.hi, hi: sub_rhs.span.lo, ctxt: NO_EXPANSION }; + let eqop_span = Span { + lo: lhs.span.hi, + hi: sub_rhs.span.lo, + ctxt: NO_EXPANSION, + }; if eq_snippet.ends_with('=') { span_note_and_lint(cx, SUSPICIOUS_ASSIGNMENT_FORMATTING, @@ -127,7 +135,11 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) { // this will be a span from the closing ‘}’ of the “then” block (excluding) to the // “if” of the “else if” block (excluding) - let else_span = Span { lo: then.span.hi, hi: else_.span.lo, ctxt: NO_EXPANSION }; + let else_span = Span { + lo: then.span.hi, + hi: else_.span.lo, + ctxt: NO_EXPANSION, + }; // the snippet should look like " else \n " with maybe comments anywhere // it’s bad when there is a ‘\n’ after the “else” @@ -154,9 +166,17 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { for element in array { if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node { if !differing_macro_contexts(lhs.span, op.span) { - let space_span = Span { lo: lhs.span.hi, hi: op.span.lo, ctxt: NO_EXPANSION }; + let space_span = Span { + lo: lhs.span.hi, + hi: op.span.lo, + ctxt: NO_EXPANSION, + }; if let Some(space_snippet) = snippet_opt(cx, space_span) { - let lint_span = Span { lo: lhs.span.hi, hi: lhs.span.hi, ctxt: NO_EXPANSION }; + let lint_span = Span { + lo: lhs.span.hi, + hi: lhs.span.hi, + ctxt: NO_EXPANSION, + }; if space_snippet.contains('\n') { span_note_and_lint(cx, POSSIBLE_MISSING_COMMA, @@ -174,10 +194,14 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { - if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && - unsugar_if(first).is_some() && unsugar_if(second).is_some() { + if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() && + unsugar_if(second).is_some() { // where the else would be - let else_span = Span { lo: first.span.hi, hi: second.span.lo, ctxt: NO_EXPANSION }; + let else_span = Span { + lo: first.span.hi, + hi: second.span.lo, + ctxt: NO_EXPANSION, + }; if let Some(else_snippet) = snippet_opt(cx, else_span) { if !else_snippet.contains('\n') { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index be8e04c42df..a691e228a77 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -89,7 +89,13 @@ enum RefLt { Named(Name), } -fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, body: Option<BodyId>, generics: &'tcx Generics, span: Span) { +fn check_fn_inner<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + decl: &'tcx FnDecl, + body: Option<BodyId>, + generics: &'tcx Generics, + span: Span +) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; } @@ -128,7 +134,7 @@ fn could_use_elision<'a, 'tcx: 'a>( func: &'tcx FnDecl, body: Option<BodyId>, named_lts: &'tcx [LifetimeDef], - bounds_lts: Vec<&'tcx Lifetime>, + bounds_lts: Vec<&'tcx Lifetime> ) -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -265,11 +271,7 @@ impl<'v, 't> RefVisitor<'v, 't> { } fn into_vec(self) -> Option<Vec<RefLt>> { - if self.abort { - None - } else { - Some(self.lts) - } + if self.abort { None } else { Some(self.lts) } } fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) { @@ -359,9 +361,11 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: & // and check that all lifetimes are allowed match visitor.into_vec() { None => return false, - Some(lts) => for lt in lts { - if !allowed_lts.contains(<) { - return true; + Some(lts) => { + for lt in lts { + if !allowed_lts.contains(<) { + return true; + } } }, } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index d7760a30622..7f0174fce58 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -409,8 +409,7 @@ 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 let ExprMethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 && method.node == "collect" && - match_trait_method(cx, expr, &paths::ITERATOR) { + if args.len() == 1 && method.node == "collect" && match_trait_method(cx, expr, &paths::ITERATOR) { span_lint(cx, UNUSED_COLLECT, expr.span, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e84fd196874..c2fc932a678 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -499,9 +499,7 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { /// Test whether an expression is in a macro expansion (e.g. something generated by /// `#[derive(...)`] or the like). fn in_attributes_expansion(expr: &Expr) -> bool { - expr.span.ctxt.outer().expn_info().map_or(false, |info| { - matches!(info.callee.format, ExpnFormat::MacroAttribute(_)) - }) + expr.span.ctxt.outer().expn_info().map_or(false, |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_))) } /// Test whether `def` is a variable defined outside a macro. diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 53b26fc1276..70ae9471bab 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -77,27 +77,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { |db| { db.span_suggestion(e.span, "you can reduce it to", hint); }); }; if let ExprBlock(ref then_block) = then_block.node { - match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (RetBool(true), RetBool(true)) | - (Bool(true), Bool(true)) => { - span_lint(cx, - 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), - (Bool(false), Bool(true)) => reduce(false, true), - _ => (), - } + match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { + (RetBool(true), RetBool(true)) | + (Bool(true), Bool(true)) => { + span_lint(cx, + 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), + (Bool(false), Bool(true)) => reduce(false, true), + _ => (), + } } else { panic!("IfExpr 'then' node is not an ExprBlock"); } diff --git a/clippy_lints/src/utils/hir.rs b/clippy_lints/src/utils/hir.rs index a818f99fec4..5820f600434 100644 --- a/clippy_lints/src/utils/hir.rs +++ b/clippy_lints/src/utils/hir.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { }, (&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_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) + self.eq_expr(lc, rc) && self.eq_expr(&**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)) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index db595b07969..87b43062631 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -690,8 +690,10 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' /// See also `is_direct_expn_of`. pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { loop { - let span_name_span = span.ctxt.outer() - .expn_info().map(|ei| (ei.callee.name(), ei.call_site)); + let span_name_span = span.ctxt + .outer() + .expn_info() + .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), @@ -709,8 +711,10 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by /// `is_direct_expn_of`. pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { - let span_name_span = span.ctxt.outer() - .expn_info().map(|ei| (ei.callee.name(), ei.call_site)); + let span_name_span = span.ctxt + .outer() + .expn_info() + .map(|ei| (ei.callee.name(), ei.call_site)); match span_name_span { Some((mac_name, new_span)) if mac_name == name => Some(new_span), diff --git a/src/lib.rs b/src/lib.rs index 9672f16eddc..a1e18ecc9b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,13 @@ extern crate clippy_lints; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { 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(); + 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; } } diff --git a/src/main.rs b/src/main.rs index 0e25ca9734e..1b3dd4f05e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,9 +43,10 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { sopts: &config::Options, cfg: &ast::CrateConfig, descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType + output: ErrorOutputType, ) -> Compilation { - self.default.early_callback(matches, sopts, cfg, descriptions, output) + self.default + .early_callback(matches, sopts, cfg, descriptions, output) } fn no_input( &mut self, @@ -54,9 +55,10 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { cfg: &ast::CrateConfig, odir: &Option<PathBuf>, ofile: &Option<PathBuf>, - descriptions: &rustc_errors::registry::Registry + descriptions: &rustc_errors::registry::Registry, ) -> Option<(Input, Option<PathBuf>)> { - self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) + self.default + .no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback( &mut self, @@ -64,9 +66,10 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { sess: &Session, input: &Input, odir: &Option<PathBuf>, - ofile: &Option<PathBuf> + ofile: &Option<PathBuf>, ) -> Compilation { - self.default.late_callback(matches, sess, input, odir, ofile) + self.default + .late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); @@ -76,7 +79,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { control.after_parse.callback = Box::new(move |state| { { let mut registry = rustc_plugin::registry::Registry::new(state.session, - state.krate + state + .krate .as_ref() .expect("at this compilation stage \ the krate must be parsed") @@ -84,12 +88,14 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { registry.args_hidden = Some(Vec::new()); clippy_lints::register_plugins(&mut registry); - let rustc_plugin::registry::Registry { early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. } = registry; + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; let sess = &state.session; let mut ls = sess.lint_store.borrow_mut(); for pass in early_lint_passes { @@ -172,29 +178,35 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); + let manifest_path_arg = std::env::args() + .skip(2) + .find(|val| val.starts_with("--manifest-path=")); - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref() - .map(AsRef::as_ref)) { - metadata - } else { - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); - process::exit(101); - }; + let mut metadata = + if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { + metadata + } else { + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); + process::exit(101); + }; let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); let current_dir = std::env::current_dir(); - let package_index = metadata.packages + 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() + 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"); package_manifest_directory == current_dir } @@ -209,7 +221,9 @@ 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)) { + if let Err(code) = process(vec![format!("--{}", first), target.name] + .into_iter() + .chain(args)) { std::process::exit(code); } } @@ -218,7 +232,8 @@ pub fn main() { } } } else { - // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` env var set to itself + // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` + // env var set to itself let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); @@ -240,31 +255,36 @@ pub fn main() { }; rustc_driver::in_rustc_thread(|| { - // this conditional check for the --sysroot flag is there so users can call `cargo-clippy` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { - env::args().collect() - } else { - env::args().chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect() - }; - - // this check ensures that dependencies are built but not linted and the final crate is - // linted but not built - let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); + // this conditional check for the --sysroot flag is there so users can call + // `cargo-clippy` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { + env::args().collect() + } else { + env::args() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); + + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if let Err(err_count) = result { + if err_count > 0 { + std::process::exit(1); } - - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(err_count) = result { - if err_count > 0 { - std::process::exit(1); - } - } - }) - .expect("rustc_thread failed"); + } + }) + .expect("rustc_thread failed"); } } diff --git a/tests/cc_seme.rs b/tests/cc_seme.rs index df2579cab57..c81b32c54bc 100644 --- a/tests/cc_seme.rs +++ b/tests/cc_seme.rs @@ -14,14 +14,14 @@ struct Test { fn main() { use Baz::*; - let x = Test { - t: Some(0), - b: One, - }; + let x = Test { t: Some(0), b: One }; match x { Test { t: Some(_), b: One } => unreachable!(), - Test { t: Some(42), b: Two } => unreachable!(), + Test { + t: Some(42), + b: Two, + } => unreachable!(), Test { t: None, .. } => unreachable!(), Test { .. } => unreachable!(), } diff --git a/tests/matches.rs b/tests/matches.rs index 506926501a2..ade8db2aa27 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -20,9 +20,13 @@ fn test_overlapping() { assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))])); assert_eq!(None, overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])); assert_eq!(None, - overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6)), sp(10, Bound::Included(11))])); + overlapping(&[sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(10, Bound::Included(11))])); assert_eq!(Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))), overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])); assert_eq!(Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))), - overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6)), sp(6, Bound::Included(11))])); + overlapping(&[sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(6, Bound::Included(11))])); } diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs index 90cb106dea6..b323cb5d25b 100644 --- a/tests/used_underscore_binding_macro.rs +++ b/tests/used_underscore_binding_macro.rs @@ -4,7 +4,8 @@ #[macro_use] extern crate serde_derive; -/// Test that we do not lint for unused underscores in a `MacroAttribute` expansion +/// Test that we do not lint for unused underscores in a `MacroAttribute` +/// expansion #[deny(used_underscore_binding)] #[derive(Deserialize)] struct MacroAttributesTest { -- cgit 1.4.1-3-g733a5 From 22dd3eef0b09742ae959835512982db0c10206b8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 26 Jun 2017 14:49:30 +0200 Subject: Use `--emit=metadata` instead of `-Zno-trans` fixes #1500 --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 1b3dd4f05e0..7e904ba8bf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -270,7 +270,7 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::args().any(|s| s == "-Zno-trans"); + let clippy_enabled = env::args().any(|s| s == "--emit=metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); @@ -302,7 +302,7 @@ fn process<I>(old_args: I) -> Result<(), i32> if !found_dashes { args.push("--".to_owned()); } - args.push("-Zno-trans".to_owned()); + args.push("--emit=metadata".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); -- cgit 1.4.1-3-g733a5 From 956a98c0c7efbc7bb7dda33a2179dccc336a1bdd Mon Sep 17 00:00:00 2001 From: Vurich <jackefransham@hotmail.co.uk> Date: Thu, 29 Jun 2017 12:57:28 +0200 Subject: Allow cargo-clippy to work in subdirectories --- src/main.rs | 56 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 1b3dd4f05e0..6e4aa05480c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -158,6 +158,10 @@ fn show_version() { println!("{}", env!("CARGO_PKG_VERSION")); } +fn has_prefix<'a, T: PartialEq, I: Iterator<Item = &'a T>>(v: &'a [T], itr: I) -> bool { + v.iter().zip(itr).all(|(a, b)| a == b) +} + pub fn main() { use std::env; @@ -192,26 +196,48 @@ pub fn main() { let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); - let current_dir = std::env::current_dir(); + let package_index = { + let mut iterator = 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 + iterator.position(|package| { + let package_manifest_path = Path::new(&package.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"); - package_manifest_directory == current_dir + let current_dir = std::env::current_dir() + .expect("could not read current directory") + .canonicalize() + .expect("current directory cannot be canonicalized"); + let current_dir_components = current_dir.components().collect::<Vec<_>>(); + + // This gets the most-recent parent (the one that takes the fewest `cd ..`s to + // reach). + iterator + .enumerate() + .filter_map(|(i, package)| { + let package_manifest_path = Path::new(&package.manifest_path); + let canonical_path = package_manifest_path + .parent() + .expect("could not find parent directory of package manifest") + .canonicalize() + .expect("package directory cannot be canonicalized"); + + // TODO: We can do this in `O(1)` by combining the `len` and the + // iteration. + let components = canonical_path.components().collect::<Vec<_>>(); + if has_prefix(¤t_dir_components, components.iter()) { + Some((i, components.len())) + } else { + None + } + }) + .max_by_key(|&(_, length)| length) + .map(|(i, _)| i) } - }) + } .expect("could not find matching package"); + let package = metadata.packages.remove(package_index); for target in package.targets { let args = std::env::args().skip(2); -- cgit 1.4.1-3-g733a5 From edadbff4eadae43ec5f6845c69ad653566c0e6f3 Mon Sep 17 00:00:00 2001 From: messense <messense@icloud.com> Date: Mon, 3 Jul 2017 12:26:03 +0800 Subject: Fix compilation on rustc 1.20.0-nightly (067971139 2017-07-02) --- src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 1b3dd4f05e0..b8cc7adb083 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ extern crate rustc_plugin; extern crate syntax; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; -use rustc::session::{config, Session}; +use rustc::session::{config, Session, CompileIncomplete}; use rustc::session::config::{Input, ErrorOutputType}; use std::path::PathBuf; use std::process::{self, Command}; @@ -278,10 +278,8 @@ pub fn main() { let mut ccc = ClippyCompilerCalls::new(clippy_enabled); let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(err_count) = result { - if err_count > 0 { - std::process::exit(1); - } + if let Err(CompileIncomplete::Errored(_)) = result { + std::process::exit(1); } }) .expect("rustc_thread failed"); -- cgit 1.4.1-3-g733a5 From 01bb0f9e51711248914ce78ed9f353c93c80c6b8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <oli-obk@users.noreply.github.com> Date: Tue, 4 Jul 2017 16:07:33 +0200 Subject: ignore needless_lifetimes false positive --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 6e4aa05480c..df39b5b9c1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -158,6 +158,8 @@ fn show_version() { println!("{}", env!("CARGO_PKG_VERSION")); } +// FIXME: false positive for needless_lifetimes +#[allow(needless_lifetimes)] fn has_prefix<'a, T: PartialEq, I: Iterator<Item = &'a T>>(v: &'a [T], itr: I) -> bool { v.iter().zip(itr).all(|(a, b)| a == b) } -- cgit 1.4.1-3-g733a5 From db7a5c69f10430b3a3853ca559adccc468b72d52 Mon Sep 17 00:00:00 2001 From: Arnavion <arnavion@gmail.com> Date: Thu, 27 Jul 2017 00:04:17 -0700 Subject: Fix logic that determines closest parent crate when invoked from a subdirectory. The previous logic incorrectly matches the deepest child of the current directory that is a crate. --- .travis.yml | 4 ++ clippy_workspace_tests/Cargo.toml | 6 +++ clippy_workspace_tests/src/main.rs | 2 + clippy_workspace_tests/subcrate/Cargo.toml | 3 ++ clippy_workspace_tests/subcrate/src/lib.rs | 0 src/main.rs | 59 +++++++++++++++--------------- 6 files changed, 44 insertions(+), 30 deletions(-) create mode 100644 clippy_workspace_tests/Cargo.toml create mode 100644 clippy_workspace_tests/src/main.rs create mode 100644 clippy_workspace_tests/subcrate/Cargo.toml create mode 100644 clippy_workspace_tests/subcrate/src/lib.rs (limited to 'src') diff --git a/.travis.yml b/.travis.yml index 7abe1025ad9..e4fa4608f0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,10 @@ script: - cp clippy_tests/target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy - PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy - cd clippy_lints && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd .. + - cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd .. + - cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. + - cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. + - cd clippy_workspace_tests/subcrate/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../../.. - set +e after_success: | diff --git a/clippy_workspace_tests/Cargo.toml b/clippy_workspace_tests/Cargo.toml new file mode 100644 index 00000000000..a282378c951 --- /dev/null +++ b/clippy_workspace_tests/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "clippy_workspace_tests" +version = "0.1.0" + +[workspace] +members = ["subcrate"] diff --git a/clippy_workspace_tests/src/main.rs b/clippy_workspace_tests/src/main.rs new file mode 100644 index 00000000000..f79c691f085 --- /dev/null +++ b/clippy_workspace_tests/src/main.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/clippy_workspace_tests/subcrate/Cargo.toml b/clippy_workspace_tests/subcrate/Cargo.toml new file mode 100644 index 00000000000..83ea5868160 --- /dev/null +++ b/clippy_workspace_tests/subcrate/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "subcrate" +version = "0.1.0" diff --git a/clippy_workspace_tests/subcrate/src/lib.rs b/clippy_workspace_tests/subcrate/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main.rs b/src/main.rs index 82c87b737c0..a48e91aa342 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ extern crate syntax; use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; use rustc::session::{config, Session, CompileIncomplete}; use rustc::session::config::{Input, ErrorOutputType}; +use std::collections::HashMap; use std::path::PathBuf; use std::process::{self, Command}; use syntax::ast; @@ -158,12 +159,6 @@ fn show_version() { println!("{}", env!("CARGO_PKG_VERSION")); } -// FIXME: false positive for needless_lifetimes -#[allow(needless_lifetimes)] -fn has_prefix<'a, T: PartialEq, I: Iterator<Item = &'a T>>(v: &'a [T], itr: I) -> bool { - v.iter().zip(itr).all(|(a, b)| a == b) -} - pub fn main() { use std::env; @@ -199,43 +194,47 @@ pub fn main() { let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); let package_index = { - let mut iterator = metadata.packages.iter(); - if let Some(ref manifest_path) = manifest_path { - iterator.position(|package| { + metadata.packages.iter().position(|package| { let package_manifest_path = Path::new(&package.manifest_path); package_manifest_path == manifest_path }) } else { + let package_manifest_paths: HashMap<_, _> = + metadata.packages.iter() + .enumerate() + .map(|(i, package)| { + let package_manifest_path = Path::new(&package.manifest_path) + .parent() + .expect("could not find parent directory of package manifest") + .canonicalize() + .expect("package directory cannot be canonicalized"); + (package_manifest_path, i) + }) + .collect(); + let current_dir = std::env::current_dir() .expect("could not read current directory") .canonicalize() .expect("current directory cannot be canonicalized"); - let current_dir_components = current_dir.components().collect::<Vec<_>>(); + + let mut current_path: &Path = ¤t_dir; // This gets the most-recent parent (the one that takes the fewest `cd ..`s to // reach). - iterator - .enumerate() - .filter_map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path); - let canonical_path = package_manifest_path + loop { + if let Some(&package_index) = package_manifest_paths.get(current_path) { + break Some(package_index); + } + else { + // We'll never reach the filesystem root, because to get to this point in the code + // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to + // unwrap the current path's parent. + current_path = current_path .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - - // TODO: We can do this in `O(1)` by combining the `len` and the - // iteration. - let components = canonical_path.components().collect::<Vec<_>>(); - if has_prefix(¤t_dir_components, components.iter()) { - Some((i, components.len())) - } else { - None - } - }) - .max_by_key(|&(_, length)| length) - .map(|(i, _)| i) + .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); + } + } } } .expect("could not find matching package"); -- cgit 1.4.1-3-g733a5 From d3bdec216b3cf1854b457f9d922d2a2daa870489 Mon Sep 17 00:00:00 2001 From: Arnavion <arnavion@gmail.com> Date: Fri, 28 Jul 2017 15:22:31 -0700 Subject: Canonicalize --manifest-path argument before comparing it to cargo metadata. Before this change, a relative path like `--manifest-path=./Cargo.toml` would fail to find a matching package in the cargo metadata. With this change, both the argument and the cargo metadata path are canonicalized before comparison. --- .travis.yml | 2 ++ src/main.rs | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/.travis.yml b/.travis.yml index e4fa4608f0e..b0459e72911 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,8 @@ script: - cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. - cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. - cd clippy_workspace_tests/subcrate/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../../.. + - PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=clippy_workspace_tests/Cargo.toml -- -D clippy && cd .. + - cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=../Cargo.toml -- -D clippy && cd ../.. - set +e after_success: | diff --git a/src/main.rs b/src/main.rs index a48e91aa342..266c1373ff2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -191,12 +191,14 @@ pub fn main() { process::exit(101); }; - let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))); + let manifest_path = manifest_path_arg.map(|arg| Path::new(&arg["--manifest-path=".len()..]) + .canonicalize().expect("manifest path could not be canonicalized")); let package_index = { - if let Some(ref manifest_path) = manifest_path { + if let Some(manifest_path) = manifest_path { metadata.packages.iter().position(|package| { - let package_manifest_path = Path::new(&package.manifest_path); + let package_manifest_path = Path::new(&package.manifest_path) + .canonicalize().expect("package manifest path could not be canonicalized"); package_manifest_path == manifest_path }) } else { -- cgit 1.4.1-3-g733a5 From b25b6b3355efa33c797f4a37afb2f516531ad581 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 9 Aug 2017 09:30:56 +0200 Subject: Rustfmt --- clippy_lints/src/approx_const.rs | 58 +-- clippy_lints/src/array_indexing.rs | 58 ++- clippy_lints/src/assign_ops.rs | 81 ++-- clippy_lints/src/attrs.rs | 62 +-- clippy_lints/src/bit_mask.rs | 137 ++++--- clippy_lints/src/blacklisted_name.rs | 10 +- clippy_lints/src/block_in_if_condition.rs | 35 +- clippy_lints/src/booleans.rs | 75 ++-- clippy_lints/src/collapsible_if.rs | 5 +- clippy_lints/src/consts.rs | 3 +- clippy_lints/src/copies.rs | 93 +++-- clippy_lints/src/cyclomatic_complexity.rs | 75 ++-- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc.rs | 52 ++- clippy_lints/src/drop_forget_ref.rs | 18 +- clippy_lints/src/empty_enum.rs | 9 +- clippy_lints/src/entry.rs | 14 +- clippy_lints/src/enum_clike.rs | 17 +- clippy_lints/src/enum_glob_use.rs | 9 +- clippy_lints/src/enum_variants.rs | 48 ++- clippy_lints/src/eq_op.rs | 59 +-- clippy_lints/src/escape.rs | 12 +- clippy_lints/src/eta_reduction.rs | 15 +- clippy_lints/src/eval_order_dependence.rs | 17 +- clippy_lints/src/format.rs | 6 +- clippy_lints/src/formatting.rs | 88 +++-- clippy_lints/src/functions.rs | 32 +- clippy_lints/src/identity_op.rs | 19 +- .../src/if_let_redundant_pattern_matching.rs | 6 +- clippy_lints/src/if_not_else.rs | 27 +- clippy_lints/src/items_after_statements.rs | 19 +- clippy_lints/src/large_enum_variant.rs | 64 ++-- clippy_lints/src/len_zero.rs | 84 +++-- clippy_lints/src/let_if_seq.rs | 4 +- clippy_lints/src/lifetimes.rs | 27 +- clippy_lints/src/literal_digit_grouping.rs | 45 ++- clippy_lints/src/loops.rs | 337 ++++++++++------- clippy_lints/src/map_clone.rs | 30 +- clippy_lints/src/matches.rs | 211 ++++++----- clippy_lints/src/mem_forget.rs | 6 +- clippy_lints/src/methods.rs | 401 +++++++++++--------- clippy_lints/src/misc.rs | 174 +++++---- clippy_lints/src/misc_early.rs | 112 +++--- clippy_lints/src/missing_doc.rs | 45 ++- clippy_lints/src/mut_mut.rs | 39 +- clippy_lints/src/mut_reference.rs | 22 +- clippy_lints/src/mutex_atomic.rs | 12 +- clippy_lints/src/needless_bool.rs | 97 +++-- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 6 +- clippy_lints/src/needless_continue.rs | 125 ++++--- clippy_lints/src/needless_pass_by_value.rs | 29 +- clippy_lints/src/needless_update.rs | 10 +- clippy_lints/src/new_without_default.rs | 12 +- clippy_lints/src/no_effect.rs | 41 +- clippy_lints/src/non_expressive_names.rs | 101 +++-- clippy_lints/src/ok_if_let.rs | 3 +- clippy_lints/src/open_options.rs | 65 ++-- clippy_lints/src/precedence.rs | 66 ++-- clippy_lints/src/print.rs | 6 +- clippy_lints/src/ptr.rs | 78 ++-- clippy_lints/src/ranges.rs | 15 +- clippy_lints/src/reference.rs | 14 +- clippy_lints/src/regex.rs | 47 ++- clippy_lints/src/returns.rs | 15 +- clippy_lints/src/serde_api.rs | 13 +- clippy_lints/src/shadow.rs | 92 +++-- clippy_lints/src/should_assert_eq.rs | 9 +- clippy_lints/src/strings.rs | 42 ++- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/transmute.rs | 147 ++++---- clippy_lints/src/types.rs | 415 ++++++++++++--------- clippy_lints/src/unicode.rs | 55 +-- clippy_lints/src/unsafe_removed_from_name.rs | 26 +- clippy_lints/src/unused_io_amount.rs | 29 +- clippy_lints/src/unused_label.rs | 2 +- clippy_lints/src/utils/author.rs | 46 ++- clippy_lints/src/utils/comparisons.rs | 3 +- clippy_lints/src/utils/conf.rs | 39 +- clippy_lints/src/utils/constants.rs | 19 +- clippy_lints/src/utils/higher.rs | 15 +- clippy_lints/src/utils/hir_utils.rs | 59 +-- clippy_lints/src/utils/inspector.rs | 43 ++- clippy_lints/src/utils/internal_lints.rs | 46 ++- clippy_lints/src/utils/mod.rs | 212 +++++++---- clippy_lints/src/utils/paths.rs | 3 +- clippy_lints/src/utils/sugg.rs | 62 ++- clippy_lints/src/vec.rs | 19 +- clippy_lints/src/zero_div_zero.rs | 3 +- src/main.rs | 159 ++++---- tests/compile-test.rs | 6 +- tests/dogfood.rs | 4 +- tests/issue-825.rs | 7 +- tests/matches.rs | 34 +- tests/needless_continue_helpers.rs | 1 - 95 files changed, 3093 insertions(+), 2025 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 7093e18454f..cbe12e58119 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -7,9 +7,11 @@ use utils::span_lint; /// **What it does:** Checks for floating point literals that approximate /// constants which are defined in -/// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) +/// [`std::f32::consts`](https://doc.rust-lang. +/// org/stable/std/f32/consts/#constants) /// or -/// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), +/// [`std::f64::consts`](https://doc.rust-lang. +/// org/stable/std/f64/consts/#constants), /// respectively, suggesting to use the predefined constant. /// /// **Why is this bad?** Usually, the definition in the standard library is more @@ -33,24 +35,26 @@ declare_lint! { } // Tuples are of the form (constant, name, min_digits) -const KNOWN_CONSTS: &'static [(f64, &'static str, usize)] = &[(f64::E, "E", 4), - (f64::FRAC_1_PI, "FRAC_1_PI", 4), - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), - (f64::FRAC_2_PI, "FRAC_2_PI", 5), - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), - (f64::FRAC_PI_2, "FRAC_PI_2", 5), - (f64::FRAC_PI_3, "FRAC_PI_3", 5), - (f64::FRAC_PI_4, "FRAC_PI_4", 5), - (f64::FRAC_PI_6, "FRAC_PI_6", 5), - (f64::FRAC_PI_8, "FRAC_PI_8", 5), - (f64::LN_10, "LN_10", 5), - (f64::LN_2, "LN_2", 5), - (f64::LOG10_E, "LOG10_E", 5), - (f64::LOG2_E, "LOG2_E", 5), - (f64::PI, "PI", 3), - (f64::SQRT_2, "SQRT_2", 5)]; +const KNOWN_CONSTS: &'static [(f64, &'static str, usize)] = &[ + (f64::E, "E", 4), + (f64::FRAC_1_PI, "FRAC_1_PI", 4), + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), + (f64::FRAC_2_PI, "FRAC_2_PI", 5), + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), + (f64::FRAC_PI_2, "FRAC_PI_2", 5), + (f64::FRAC_PI_3, "FRAC_PI_3", 5), + (f64::FRAC_PI_4, "FRAC_PI_4", 5), + (f64::FRAC_PI_6, "FRAC_PI_6", 5), + (f64::FRAC_PI_8, "FRAC_PI_8", 5), + (f64::LN_10, "LN_10", 5), + (f64::LN_2, "LN_2", 5), + (f64::LOG10_E, "LOG10_E", 5), + (f64::LOG2_E, "LOG2_E", 5), + (f64::PI, "PI", 3), + (f64::SQRT_2, "SQRT_2", 5), +]; -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Pass; impl LintPass for Pass { @@ -81,13 +85,17 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &symbol::Symbol, module: &s if s.parse::<f64>().is_ok() { for &(constant, name, min_digits) in KNOWN_CONSTS { if is_approx_const(constant, &s, min_digits) { - span_lint(cx, - APPROX_CONSTANT, - e.span, - &format!("approximate value of `{}::consts::{}` found. \ + span_lint( + cx, + APPROX_CONSTANT, + e.span, + &format!( + "approximate value of `{}::consts::{}` found. \ Consider using it directly", - module, - &name)); + module, + &name + ), + ); return; } } diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index baac8d790ba..422935fa067 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -8,7 +8,8 @@ use rustc::hir; use syntax::ast::RangeLimits; use utils::{self, higher}; -/// **What it does:** Checks for out of bounds array indexing with a constant index. +/// **What it does:** Checks for out of bounds array indexing with a constant +/// index. /// /// **Why is this bad?** This will always panic at runtime. /// @@ -46,7 +47,7 @@ declare_restriction_lint! { "indexing/slicing usage" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct ArrayIndexing; impl LintPass for ArrayIndexing { @@ -61,8 +62,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { // Array with known size can be checked statically let ty = cx.tables.expr_ty(array); if let ty::TyArray(_, size) = ty.sty { - let size = ConstInt::Usize(ConstUsize::new(size as u64, cx.sess().target.uint_type) - .expect("array size is invalid")); + let size = ConstInt::Usize( + ConstUsize::new(size as u64, cx.sess().target.uint_type).expect("array size is invalid"), + ); let parent_item = cx.tcx.hir.get_parent(e.id); let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); @@ -80,12 +82,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { // Index is a constant range if let Some(range) = higher::range(index) { - let start = range.start - .map(|start| constcx.eval(start)) - .map(|v| v.ok()); - let end = range.end - .map(|end| constcx.eval(end)) - .map(|v| v.ok()); + let start = range.start.map(|start| constcx.eval(start)).map(|v| v.ok()); + let end = range.end.map(|end| constcx.eval(end)).map(|v| v.ok()); if let Some((start, end)) = to_const_range(&start, &end, range.limits, size) { if start > size || end > size { @@ -111,12 +109,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing { } } -/// Returns an option containing a tuple with the start and end (exclusive) of the range. +/// Returns an option containing a tuple with the start and end (exclusive) of +/// the range. fn to_const_range( start: &Option<Option<ConstVal>>, end: &Option<Option<ConstVal>>, limits: RangeLimits, - array_size: ConstInt + array_size: ConstInt, ) -> Option<(ConstInt, ConstInt)> { let start = match *start { Some(Some(ConstVal::Integral(x))) => x, @@ -128,24 +127,23 @@ fn to_const_range( Some(Some(ConstVal::Integral(x))) => { if limits == RangeLimits::Closed { match x { - ConstInt::U8(_) => (x + ConstInt::U8(1)), - ConstInt::U16(_) => (x + ConstInt::U16(1)), - ConstInt::U32(_) => (x + ConstInt::U32(1)), - ConstInt::U64(_) => (x + ConstInt::U64(1)), - ConstInt::U128(_) => (x + ConstInt::U128(1)), - ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))), - ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))), - ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))), - ConstInt::I8(_) => (x + ConstInt::I8(1)), - ConstInt::I16(_) => (x + ConstInt::I16(1)), - ConstInt::I32(_) => (x + ConstInt::I32(1)), - ConstInt::I64(_) => (x + ConstInt::I64(1)), - ConstInt::I128(_) => (x + ConstInt::I128(1)), - ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))), - ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))), - ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))), - } - .expect("such a big array is not realistic") + ConstInt::U8(_) => (x + ConstInt::U8(1)), + ConstInt::U16(_) => (x + ConstInt::U16(1)), + ConstInt::U32(_) => (x + ConstInt::U32(1)), + ConstInt::U64(_) => (x + ConstInt::U64(1)), + ConstInt::U128(_) => (x + ConstInt::U128(1)), + ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))), + ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))), + ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))), + ConstInt::I8(_) => (x + ConstInt::I8(1)), + ConstInt::I16(_) => (x + ConstInt::I16(1)), + ConstInt::I32(_) => (x + ConstInt::I32(1)), + ConstInt::I64(_) => (x + ConstInt::I64(1)), + ConstInt::I128(_) => (x + ConstInt::I128(1)), + ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))), + ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))), + ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))), + }.expect("such a big array is not realistic") } else { x } diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 07d838bef2e..759bb9f12ec 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -4,12 +4,14 @@ use syntax::ast; use utils::{span_lint_and_then, snippet_opt, SpanlessEq, get_trait_def_id, implements_trait}; use utils::{higher, sugg}; -/// **What it does:** Checks for compound assignment operations (`+=` and similar). +/// **What it does:** Checks for compound assignment operations (`+=` and +/// similar). /// /// **Why is this bad?** Projects with many developers from languages without /// those operations may find them unreadable and not worth their weight. /// -/// **Known problems:** Types implementing `OpAssign` don't necessarily implement `Op`. +/// **Known problems:** Types implementing `OpAssign` don't necessarily +/// implement `Op`. /// /// **Example:** /// ```rust @@ -20,7 +22,8 @@ declare_restriction_lint! { "any compound assignment operation" } -/// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` patterns. +/// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` +/// patterns. /// /// **Why is this bad?** These can be written as the shorter `a op= b`. /// @@ -41,7 +44,8 @@ declare_lint! { /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns. /// -/// **Why is this bad?** Most likely these are bugs where one meant to write `a op= b`. +/// **Why is this bad?** Most likely these are bugs where one meant to write `a +/// op= b`. /// /// **Known problems:** Someone might actually mean `a op= a op b`, but that /// should rather be written as `a = (2 * a) op b` where applicable. @@ -75,9 +79,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { let lhs = &sugg::Sugg::hir(cx, lhs, ".."); let rhs = &sugg::Sugg::hir(cx, rhs, ".."); - db.span_suggestion(expr.span, - "replace it with", - format!("{} = {}", lhs, sugg::make_binop(higher::binop(op.node), lhs, rhs))); + db.span_suggestion( + expr.span, + "replace it with", + format!("{} = {}", lhs, sugg::make_binop(higher::binop(op.node), lhs, rhs)), + ); }); if let hir::ExprBinary(binop, ref l, ref r) = rhs.node { if op.node == binop.node { @@ -144,35 +150,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { } } } - if ops!(op.node, + if ops!( + op.node, + cx, + ty, + rty, + Add: BiAdd, + Sub: BiSub, + Mul: BiMul, + Div: BiDiv, + Rem: BiRem, + And: BiAnd, + Or: BiOr, + BitAnd: BiBitAnd, + BitOr: BiBitOr, + BitXor: BiBitXor, + Shr: BiShr, + Shl: BiShl + ) + { + span_lint_and_then( cx, - ty, - rty, - Add: BiAdd, - Sub: BiSub, - Mul: BiMul, - Div: BiDiv, - Rem: BiRem, - And: BiAnd, - Or: BiOr, - BitAnd: BiBitAnd, - BitOr: BiBitOr, - BitXor: BiBitXor, - Shr: BiShr, - Shl: BiShl) { - span_lint_and_then(cx, - ASSIGN_OP_PATTERN, - 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)); - }); + ASSIGN_OP_PATTERN, + 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), + ); + }, + ); } }; // a = a op b diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 88f0ef0955c..a52c4d90aab 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -35,12 +35,15 @@ declare_lint! { "use of `#[inline(always)]`" } -/// **What it does:** Checks for `extern crate` and `use` items annotated with lint attributes +/// **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 +/// **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, +/// **Known problems:** Technically one might allow `unused_import` on a `use` +/// item, /// but it's easier to remove the unused item. /// /// **Example:** @@ -75,7 +78,7 @@ declare_lint! { "use of `#[deprecated(since = \"x\")]` where x is not semver" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct AttrPass; impl LintPass for AttrPass { @@ -124,14 +127,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { } if let Some(mut sugg) = snippet_opt(cx, attr.span) { if sugg.len() > 1 { - span_lint_and_then(cx, - USELESS_ATTRIBUTE, - attr.span, - "useless lint attribute", - |db| { - sugg.insert(1, '!'); - db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg); - }); + span_lint_and_then( + cx, + USELESS_ATTRIBUTE, + attr.span, + "useless lint attribute", + |db| { + sugg.insert(1, '!'); + db.span_suggestion( + attr.span, + "if you just forgot a `!`, use", + sugg, + ); + }, + ); } } }, @@ -191,7 +200,10 @@ fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> b StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr), } } else { - block.expr.as_ref().map_or(false, |e| is_relevant_expr(tcx, tables, e)) + block.expr.as_ref().map_or( + false, + |e| is_relevant_expr(tcx, tables, e), + ) } } @@ -224,11 +236,15 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) { continue; } if is_word(&values[0], "always") { - span_lint(cx, - INLINE_ALWAYS, - attr.span, - &format!("you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", - name)); + span_lint( + cx, + INLINE_ALWAYS, + attr.span, + &format!( + "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea", + name + ), + ); } } } @@ -240,10 +256,12 @@ fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { return; } } - span_lint(cx, - DEPRECATED_SEMVER, - span, - "the since field must contain a semver-compliant version"); + span_lint( + cx, + DEPRECATED_SEMVER, + span, + "the since field must contain a semver-compliant version", + ); } fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool { diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index f56c0b2aeb3..64f007bf521 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -74,7 +74,8 @@ declare_lint! { /// **What it does:** Checks for bit masks that can be replaced by a call /// to `trailing_zeros` /// -/// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15 == 0` +/// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15 +/// == 0` /// /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86 /// @@ -88,7 +89,7 @@ declare_lint! { "expressions where a bit mask is less readable than the corresponding method call" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct BitMask; impl LintPass for BitMask { @@ -162,12 +163,16 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: BiBitAnd => { if mask_value & cmp_value != cmp_value { if cmp_value != 0 { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` can never be equal to `{}`", + mask_value, + cmp_value + ), + ); } } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); @@ -175,12 +180,16 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: }, BiBitOr => { if mask_value | cmp_value != cmp_value { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` can never be equal to `{}`", + mask_value, + cmp_value + ), + ); } }, _ => (), @@ -190,24 +199,32 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: match bit_op { BiBitAnd => { if mask_value < cmp_value { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` will always be lower than `{}`", + mask_value, + cmp_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, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` will never be lower than `{}`", + mask_value, + cmp_value + ), + ); } else { check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); } @@ -220,24 +237,32 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: match bit_op { BiBitAnd => { if mask_value <= cmp_value { - span_lint(cx, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` will never be higher than `{}`", + mask_value, + cmp_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, - BAD_BIT_MASK, - *span, - &format!("incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, - cmp_value)); + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` will always be higher than `{}`", + mask_value, + cmp_value + ), + ); } else { check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); } @@ -252,25 +277,33 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: fn check_ineffective_lt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str) { if c.is_power_of_two() && m < c { - span_lint(cx, - INEFFECTIVE_BIT_MASK, - span, - &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, - m, - c)); + span_lint( + cx, + INEFFECTIVE_BIT_MASK, + span, + &format!( + "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c + ), + ); } } fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str) { if (c + 1).is_power_of_two() && m <= c { - span_lint(cx, - INEFFECTIVE_BIT_MASK, - span, - &format!("ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", - op, - m, - c)); + span_lint( + cx, + INEFFECTIVE_BIT_MASK, + span, + &format!( + "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", + op, + m, + c + ), + ); } } diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index f8f0ea998bc..e88e4108d3d 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -41,10 +41,12 @@ 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| ident.node == *s) { - span_lint(cx, - BLACKLISTED_NAME, - ident.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.node)); + span_lint( + cx, + BLACKLISTED_NAME, + ident.span, + &format!("use of a blacklisted/placeholder name `{}`", ident.node), + ); } } } diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 6c0523dc198..eea44393e3d 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -40,7 +40,7 @@ declare_lint! { "complex blocks in conditions, e.g. `if { let x = true; x } ...`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct BlockInIfCondition; impl LintPass for BlockInIfCondition { @@ -87,27 +87,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { if in_macro(expr.span) || differing_macro_contexts(expr.span, ex.span) { return; } - span_help_and_lint(cx, - BLOCK_IN_IF_CONDITION_EXPR, - check.span, - BRACED_EXPR_MESSAGE, - &format!("try\nif {} {} ... ", + span_help_and_lint( + cx, + BLOCK_IN_IF_CONDITION_EXPR, + check.span, + BRACED_EXPR_MESSAGE, + &format!("try\nif {} {} ... ", snippet_block(cx, ex.span, ".."), - snippet_block(cx, then.span, ".."))); + snippet_block(cx, then.span, "..")), + ); } } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); + let span = block.expr.as_ref().map_or_else( + || block.stmts[0].span, + |e| e.span, + ); if in_macro(span) || differing_macro_contexts(expr.span, span) { return; } // move block higher - span_help_and_lint(cx, - BLOCK_IN_IF_CONDITION_STMT, - check.span, - COMPLEX_BLOCK_MESSAGE, - &format!("try\nlet res = {};\nif res {} ... ", + span_help_and_lint( + cx, + BLOCK_IN_IF_CONDITION_STMT, + check.span, + COMPLEX_BLOCK_MESSAGE, + &format!("try\nlet res = {};\nif res {} ... ", snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, ".."))); + snippet_block(cx, then.span, "..")), + ); } } } else { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index c338189cefe..4c67b260046 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -44,7 +44,7 @@ declare_lint! { "boolean expressions that contain terminals which can be eliminated" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NonminimalBool; impl LintPass for NonminimalBool { @@ -61,7 +61,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonminimalBool { _: &'tcx FnDecl, body: &'tcx Body, _: Span, - _: NodeId + _: NodeId, ) { NonminimalBoolVisitor { cx: cx }.visit_body(body) } @@ -115,8 +115,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } for (n, expr) in self.terminals.iter().enumerate() { if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { - #[allow(cast_possible_truncation)] - return Ok(Bool::Term(n as u8)); + #[allow(cast_possible_truncation)] return Ok(Bool::Term(n as u8)); } let negated = match e.node { ExprBinary(binop, ref lhs, ref rhs) => { @@ -141,15 +140,13 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => continue, }; if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { - #[allow(cast_possible_truncation)] - return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); + #[allow(cast_possible_truncation)] return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); } } let n = self.terminals.len(); self.terminals.push(e); if n < 32 { - #[allow(cast_possible_truncation)] - Ok(Bool::Term(n as u8)) + #[allow(cast_possible_truncation)] Ok(Bool::Term(n as u8)) } else { Err("too many literals".to_owned()) } @@ -353,44 +350,54 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { continue 'simplified; } if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { - span_lint_and_then(self.cx, - LOGIC_BUG, - e.span, - "this boolean expression contains a logic bug", - |db| { - db.span_help(h2q.terminals[i].span, - "this expression can be optimized out by applying boolean operations to the \ - outer expression"); - db.span_suggestion(e.span, - "it would look like the following", - suggest(self.cx, suggestion, &h2q.terminals)); - }); + span_lint_and_then( + self.cx, + LOGIC_BUG, + e.span, + "this boolean expression contains a logic bug", + |db| { + db.span_help( + h2q.terminals[i].span, + "this expression can be optimized out by applying boolean operations to the \ + outer expression", + ); + db.span_suggestion( + e.span, + "it would look like the following", + suggest(self.cx, suggestion, &h2q.terminals), + ); + }, + ); // don't also lint `NONMINIMAL_BOOL` return; } // if the number of occurrences of a terminal decreases or any of the stats // decreases while none increases improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || - (stats.negations > simplified_stats.negations && - stats.ops == simplified_stats.ops) || - (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); + (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || + (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); } if improvement { improvements.push(suggestion); } } if !improvements.is_empty() { - span_lint_and_then(self.cx, - NONMINIMAL_BOOL, - e.span, - "this boolean expression can be simplified", - |db| { - db.span_suggestions(e.span, - "try", - improvements.into_iter() - .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals)) - .collect()); - }); + span_lint_and_then( + self.cx, + NONMINIMAL_BOOL, + e.span, + "this boolean expression can be simplified", + |db| { + db.span_suggestions( + e.span, + "try", + improvements + .into_iter() + .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals)) + .collect(), + ); + }, + ); } } } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 1178f98db59..54b6490a183 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -19,7 +19,8 @@ use utils::{in_macro, snippet_block, span_lint_and_then, span_lint_and_sugg}; use utils::sugg::Sugg; /// **What it does:** Checks for nested `if` statements which can be collapsed -/// by `&&`-combining their conditions and for `else { if ... }` expressions that +/// by `&&`-combining their conditions and for `else { if ... }` expressions +/// that /// can be collapsed to `else if ...`. /// /// **Why is this bad?** Each `if`-statement adds one level of nesting, which @@ -67,7 +68,7 @@ declare_lint! { "`if`s that can be collapsed (e.g. `if x { if y { ... } }` and `else { if x { ... } }`)" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct CollapsibleIf; impl LintPass for CollapsibleIf { diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 54b297d588d..095fcf06e09 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -83,7 +83,8 @@ impl PartialEq for Constant { impl Hash for Constant { fn hash<H>(&self, state: &mut H) - where H: Hasher + where + H: Hasher, { match *self { Constant::Str(ref s, ref k) => { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 8f8bdf472a5..8a37c7a846d 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -138,12 +138,14 @@ fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same(blocks, hash, eq) { - span_note_and_lint(cx, - IF_SAME_THEN_ELSE, - j.span, - "this `if` has identical blocks", - i.span, - "same as this"); + span_note_and_lint( + cx, + IF_SAME_THEN_ELSE, + j.span, + "this `if` has identical blocks", + i.span, + "same as this", + ); } } @@ -158,12 +160,14 @@ fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { let eq: &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; if let Some((i, j)) = search_same(conds, hash, eq) { - span_note_and_lint(cx, - IFS_SAME_COND, - j.span, - "this `if` has the same condition as a previous if", - i.span, - "same as this"); + span_note_and_lint( + cx, + IFS_SAME_COND, + j.span, + "this `if` has the same condition as a previous if", + i.span, + "same as this", + ); } } @@ -185,40 +189,48 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) { if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node { if let Some((i, j)) = search_same(arms, hash, eq) { - span_lint_and_then(cx, - MATCH_SAME_ARMS, - j.body.span, - "this `match` has identical arm bodies", - |db| { - db.span_note(i.body.span, "same as this"); + span_lint_and_then( + cx, + MATCH_SAME_ARMS, + j.body.span, + "this `match` has identical arm bodies", + |db| { + db.span_note(i.body.span, "same as this"); - // Note: this does not use `span_suggestion` on purpose: there is no clean way to - // remove the other arm. Building a span and suggest to replace it to "" makes an - // even more confusing error message. Also in order not to make up a span for the - // whole pattern, the suggestion is only shown when there is only one pattern. The - // user should know about `|` if they are already using it… + // Note: this does not use `span_suggestion` on purpose: there is no clean way + // to + // remove the other arm. Building a span and suggest to replace it to "" makes + // an + // even more confusing error message. Also in order not to make up a span for + // the + // whole pattern, the suggestion is only shown when there is only one pattern. + // The + // user should know about `|` if they are already using it… - if i.pats.len() == 1 && j.pats.len() == 1 { - let lhs = snippet(cx, i.pats[0].span, "<pat1>"); - let rhs = snippet(cx, j.pats[0].span, "<pat2>"); + if i.pats.len() == 1 && j.pats.len() == 1 { + let lhs = snippet(cx, i.pats[0].span, "<pat1>"); + let rhs = snippet(cx, j.pats[0].span, "<pat2>"); - 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)); - } else { - db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs)); + 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), + ); + } else { + db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs)); + } } - } - }); + }, + ); } } } -/// Return the list of condition expressions and the list of blocks in a sequence of `if/else`. +/// Return the list of condition expressions and the list of blocks in a +/// sequence of `if/else`. /// Eg. would return `([a, b], [c, d, e])` for the expression /// `if a { c } else if b { d } else { e }`. fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { @@ -303,8 +315,9 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned } fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)> - where Hash: Fn(&T) -> u64, - Eq: Fn(&T, &T) -> bool +where + Hash: Fn(&T) -> u64, + Eq: Fn(&T, &T) -> bool, { // common cases if exprs.len() < 2 { diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index ffb240d3ab4..e87e60f9d23 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -15,7 +15,8 @@ use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type}; /// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly /// readable. Also LLVM will usually optimize small methods better. /// -/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity. +/// **Known problems:** Sometimes it's hard to find a way to reduce the +/// complexity. /// /// **Example:** No. You'll see it when you get the warning. declare_lint! { @@ -63,7 +64,13 @@ impl CyclomaticComplexity { cx: cx, }; helper.visit_expr(expr); - let CCHelper { match_arms, divergence, short_circuits, returns, .. } = helper; + let CCHelper { + match_arms, + divergence, + short_circuits, + returns, + .. + } = helper; let ret_ty = cx.tables.node_id_to_type(expr.id); let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) { returns @@ -80,11 +87,13 @@ impl CyclomaticComplexity { rust_cc -= ret_adjust; } if rust_cc > self.limit.limit() { - span_help_and_lint(cx, - CYCLOMATIC_COMPLEXITY, - span, - &format!("the function has a cyclomatic complexity of {}", rust_cc), - "you could split it up into multiple smaller functions"); + span_help_and_lint( + cx, + CYCLOMATIC_COMPLEXITY, + span, + &format!("the function has a cyclomatic complexity of {}", rust_cc), + "you could split it up into multiple smaller functions", + ); } } } @@ -98,7 +107,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity { _: &'tcx FnDecl, body: &'tcx Body, span: Span, - node_id: NodeId + node_id: NodeId, ) { let def_id = cx.tcx.hir.local_def_id(node_id); if !cx.tcx.has_attr(def_id, "test") { @@ -107,10 +116,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity { } fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { - self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + self.limit.push_attrs( + cx.sess(), + attrs, + "cyclomatic_complexity", + ); } fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { - self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); + self.limit.pop_attrs( + cx.sess(), + attrs, + "cyclomatic_complexity", + ); } } @@ -162,29 +179,35 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> { } } -#[cfg(feature="debugging")] +#[cfg(feature = "debugging")] fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { - span_bug!(span, - "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ + span_bug!( + span, + "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ div = {}, shorts = {}, returns = {}. Please file a bug report.", - cc, - narms, - div, - shorts, - returns); + cc, + narms, + div, + shorts, + returns + ); } -#[cfg(not(feature="debugging"))] +#[cfg(not(feature = "debugging"))] fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span) { if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow { - cx.sess().span_note_without_error(span, - &format!("Clippy encountered a bug calculating cyclomatic complexity \ + cx.sess().span_note_without_error( + span, + &format!( + "Clippy encountered a bug calculating cyclomatic complexity \ (hide this message with `#[allow(cyclomatic_complexity)]`): \ cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \ Please file a bug report.", - cc, - narms, - div, - shorts, - returns)); + cc, + narms, + div, + shorts, + returns + ), + ); } } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 5ac4a342274..e186dd5e4db 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -89,7 +89,7 @@ fn check_hash_peq<'a, 'tcx>( span: Span, trait_ref: &TraitRef, ty: Ty<'tcx>, - hash_is_automatically_derived: bool + hash_is_automatically_derived: bool, ) { if_let_chain! {[ match_path_old(&trait_ref.path, &paths::HASH), diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 46c3bd51068..3ca71694bbd 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -19,7 +19,8 @@ use utils::span_lint; /// /// **Examples:** /// ```rust -/// /// Do something with the foo_bar parameter. See also that::other::module::foo. +/// /// Do something with the foo_bar parameter. See also +/// that::other::module::foo. /// // ^ `foo_bar` and `that::other::module::foo` should be ticked. /// fn doit(foo_bar) { .. } /// ``` @@ -78,7 +79,8 @@ impl<'a> Iterator for Parser<'a> { /// Cleanup documentation decoration (`///` and such). /// /// We can't use `syntax::attr::AttributeMethods::with_desugared_doc` or -/// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we need to keep track of +/// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we +/// need to keep track of /// the spans but this function is inspired from the later. #[allow(cast_possible_truncation)] pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) { @@ -89,7 +91,18 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<( let doc = &comment[prefix.len()..]; let mut doc = doc.to_owned(); doc.push('\n'); - return (doc.to_owned(), vec![(doc.len(), Span { lo: span.lo + BytePos(prefix.len() as u32), ..span })]); + return ( + doc.to_owned(), + vec![ + ( + doc.len(), + Span { + lo: span.lo + BytePos(prefix.len() as u32), + ..span + } + ), + ], + ); } } @@ -102,7 +115,13 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<( debug_assert_eq!(offset as u32 as usize, offset); // +1 for the newline - sizes.push((line.len() + 1, Span { lo: span.lo + BytePos(offset as u32), ..span })); + sizes.push(( + line.len() + 1, + Span { + lo: span.lo + BytePos(offset as u32), + ..span + }, + )); } return (doc.to_string(), sizes); @@ -163,7 +182,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( cx: &EarlyContext, valid_idents: &[String], docs: Events, - spans: &[(usize, Span)] + spans: &[(usize, Span)], ) { use pulldown_cmark::Event::*; use pulldown_cmark::Tag::*; @@ -192,7 +211,10 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( let (begin, span) = spans[index]; // Adjust for the begining of the current `Event` - let span = Span { lo: span.lo + BytePos::from_usize(offset - begin), ..span }; + let span = Span { + lo: span.lo + BytePos::from_usize(offset - begin), + ..span + }; check_text(cx, valid_idents, &text, span); } @@ -225,8 +247,10 @@ fn check_text(cx: &EarlyContext, valid_idents: &[String], text: &str, span: Span } fn check_word(cx: &EarlyContext, word: &str, span: Span) { - /// Checks if a string is camel-case, ie. contains at least two uppercase letter (`Clippy` is - /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok). + /// Checks if a string is camel-case, ie. contains at least two uppercase + /// letter (`Clippy` is + /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded + /// (`IDs` is ok). fn is_camel_case(s: &str) -> bool { if s.starts_with(|c: char| c.is_digit(10)) { return false; @@ -239,7 +263,7 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { }; 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 + s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 } fn has_underscore(s: &str) -> bool { @@ -247,9 +271,11 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { } if has_underscore(word) || word.contains("::") || is_camel_case(word) { - span_lint(cx, - DOC_MARKDOWN, - span, - &format!("you should put `{}` between ticks in the documentation", word)); + span_lint( + cx, + DOC_MARKDOWN, + span, + &format!("you should put `{}` between ticks in the documentation", word), + ); } } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 6112aec7cb6..b02333b89a0 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -16,7 +16,8 @@ use utils::{match_def_path, paths, span_note_and_lint, is_copy}; /// **Example:** /// ```rust /// let mut lock_guard = mutex.lock(); -/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex still locked +/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex +/// still locked /// operation_that_requires_mutex_to_be_unlocked(); /// ``` declare_lint! { @@ -29,7 +30,8 @@ declare_lint! { /// instead of an owned value. /// /// **Why is this bad?** Calling `forget` on a reference will only forget the -/// reference itself, which is a no-op. It will not forget the underlying referenced +/// reference itself, which is a no-op. It will not forget the underlying +/// referenced /// value, which is likely what was intended. /// /// **Known problems:** None. @@ -57,7 +59,8 @@ declare_lint! { /// **Example:** /// ```rust /// let x:i32 = 42; // i32 implements Copy -/// std::mem::drop(x) // A copy of x is passed to the function, leaving the original unaffected +/// std::mem::drop(x) // A copy of x is passed to the function, leaving the +/// original unaffected /// ``` declare_lint! { pub DROP_COPY, @@ -72,8 +75,10 @@ declare_lint! { /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the /// value will be copied and moved into the function on invocation. /// -/// An alternative, but also valid, explanation is that Copy types do not implement -/// the Drop trait, which means they have no destructors. Without a destructor, there +/// An alternative, but also valid, explanation is that Copy types do not +/// implement +/// the Drop trait, which means they have no destructors. Without a destructor, +/// there /// is nothing for `std::mem::forget` to ignore. /// /// **Known problems:** None. @@ -81,7 +86,8 @@ declare_lint! { /// **Example:** /// ```rust /// let x:i32 = 42; // i32 implements Copy -/// std::mem::forget(x) // A copy of x is passed to the function, leaving the original unaffected +/// std::mem::forget(x) // A copy of x is passed to the function, leaving the +/// original unaffected /// ``` declare_lint! { pub FORGET_COPY, diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 431e8779842..7845c85b687 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -6,7 +6,8 @@ use utils::span_lint_and_then; /// **What it does:** Checks for `enum`s with no variants. /// -/// **Why is this bad?** Enum's with no variants should be replaced with `!`, the uninhabited type, +/// **Why is this bad?** Enum's with no variants should be replaced with `!`, +/// the uninhabited type, /// or a wrapper around it. /// /// **Known problems:** None. @@ -21,7 +22,7 @@ declare_lint! { "enum with no variants" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct EmptyEnum; impl LintPass for EmptyEnum { @@ -35,7 +36,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { let did = cx.tcx.hir.local_def_id(item.id); if let ItemEnum(..) = item.node { let ty = cx.tcx.type_of(did); - let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); + let adt = ty.ty_adt_def().expect( + "already checked whether this is an enum", + ); if adt.variants.is_empty() { span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| { db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it"); diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 43d8357e335..80288ff2268 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -30,7 +30,7 @@ declare_lint! { "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct HashMapLint; impl LintPass for HashMapLint { @@ -48,11 +48,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { // we can give a better error message let sole_expr = { else_block.is_none() && - if let ExprBlock(ref then_block) = then_block.node { - (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 - } else { - true - } + if let ExprBlock(ref then_block) = then_block.node { + (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 + } else { + true + } }; let mut visitor = InsertVisitor { @@ -86,7 +86,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { fn check_cond<'a, 'tcx, 'b>( cx: &'a LateContext<'a, 'tcx>, - check: &'b Expr + check: &'b Expr, ) -> Option<(&'static str, &'b Expr, &'b Expr)> { if_let_chain! {[ let ExprMethodCall(ref path, _, ref params) = check.node, diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 3741b3934bd..bf2ba847ec8 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,4 +1,5 @@ -//! lint on C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32` +//! lint on C-like enums that are `repr(isize/usize)` and have values that +//! don't fit into an `i32` use rustc::lint::*; use rustc::middle::const_val::ConstVal; @@ -50,16 +51,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { let did = cx.tcx.hir.body_owner_def_id(body_id); let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did); - let bad = match cx.tcx.at(expr.span).const_eval(param_env.and((did, substs))) { + let bad = match cx.tcx.at(expr.span).const_eval( + param_env.and((did, substs)), + ) { Ok(ConstVal::Integral(Usize(Us64(i)))) => i as u32 as u64 != i, Ok(ConstVal::Integral(Isize(Is64(i)))) => i as i32 as i64 != i, _ => false, }; if bad { - span_lint(cx, - ENUM_CLIKE_UNPORTABLE_VARIANT, - var.span, - "Clike enum variant discriminant is not portable to 32-bit targets"); + span_lint( + cx, + ENUM_CLIKE_UNPORTABLE_VARIANT, + var.span, + "Clike enum variant discriminant is not portable to 32-bit targets", + ); } } } diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 12b588967f8..6738f5bb63b 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -48,9 +48,14 @@ impl EnumGlobUse { } 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` + // 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) { + 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 16a2e021723..1227de69db2 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -68,13 +68,16 @@ declare_lint! { "type names prefixed/postfixed with their containing module's name" } -/// **What it does:** Checks for modules that have the same name as their parent module +/// **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 { .. +/// **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`. +/// 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. /// @@ -123,14 +126,21 @@ fn var2str(var: &Variant) -> InternedString { fn partial_match(pre: &str, name: &str) -> usize { let mut name_iter = name.chars(); let _ = name_iter.next_back(); // make sure the name is never fully matched - pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() + pre.chars() + .zip(name_iter) + .take_while(|&(l, r)| l == r) + .count() } /// Returns the number of chars that match from the end fn partial_rmatch(post: &str, name: &str) -> usize { let mut name_iter = name.chars(); let _ = name_iter.next(); // make sure the name is never fully matched - post.chars().rev().zip(name_iter.rev()).take_while(|&(l, r)| l == r).count() + post.chars() + .rev() + .zip(name_iter.rev()) + .take_while(|&(l, r)| l == r) + .count() } // FIXME: #600 @@ -142,7 +152,7 @@ fn check_variant( item_name: &str, item_name_chars: usize, span: Span, - lint: &'static Lint + lint: &'static Lint, ) { if (def.variants.len() as u64) < threshold { return; @@ -187,13 +197,17 @@ fn check_variant( (false, _) => ("pre", pre), (true, false) => ("post", post), }; - span_help_and_lint(cx, - lint, - span, - &format!("All variants have the same {}fix: `{}`", what, value), - &format!("remove the {}fixes and use full paths to \ + span_help_and_lint( + cx, + lint, + span, + &format!("All variants have the same {}fix: `{}`", what, value), + &format!( + "remove the {}fixes and use full paths to \ the variants instead of glob imports", - what)); + what + ), + ); } fn to_camel_case(item_name: &str) -> String { @@ -234,10 +248,12 @@ 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 { diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 10e5f2ba7c0..84a54dd215b 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -23,7 +23,8 @@ declare_lint! { "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)" } -/// **What it does:** Checks for arguments to `==` which have their address taken to satisfy a bound +/// **What it does:** Checks for arguments to `==` which have their address +/// taken to satisfy a bound /// and suggests to dereference the other argument instead /// /// **Why is this bad?** It is more idiomatic to dereference the other argument. @@ -40,7 +41,7 @@ declare_lint! { "taking a reference to satisfy the type constraints on `==`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct EqOp; impl LintPass for EqOp { @@ -53,10 +54,12 @@ 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, - EQ_OP, - e.span, - &format!("equal expressions as operands to `{}`", op.node.as_str())); + span_lint( + cx, + EQ_OP, + e.span, + &format!("equal expressions as operands to `{}`", op.node.as_str()), + ); return; } let (trait_id, requires_ref) = match op.node { @@ -89,31 +92,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { let rcpy = is_copy(cx, rty); // either operator autorefs or both args are copyable if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty]) { - span_lint_and_then(cx, - OP_REF, - e.span, - "needlessly taken reference of both operands", - |db| { - let lsnip = snippet(cx, l.span, "...").to_string(); - let rsnip = snippet(cx, r.span, "...").to_string(); - multispan_sugg(db, - "use the values directly".to_string(), - vec![(left.span, lsnip), (right.span, rsnip)]); - }) + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of both operands", + |db| { + let lsnip = snippet(cx, l.span, "...").to_string(); + let rsnip = snippet(cx, r.span, "...").to_string(); + multispan_sugg( + db, + "use the values directly".to_string(), + vec![(left.span, lsnip), (right.span, rsnip)], + ); + }, + ) } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right)]) { span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| { let lsnip = snippet(cx, l.span, "...").to_string(); db.span_suggestion(left.span, "use the left value directly", lsnip); }) } else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty]) { - span_lint_and_then(cx, - OP_REF, - e.span, - "needlessly taken reference of right operand", - |db| { - let rsnip = snippet(cx, r.span, "...").to_string(); - db.span_suggestion(right.span, "use the right value directly", rsnip); - }) + span_lint_and_then( + cx, + OP_REF, + e.span, + "needlessly taken reference of right operand", + |db| { + let rsnip = snippet(cx, r.span, "...").to_string(); + db.span_suggestion(right.span, "use the right value directly", rsnip); + }, + ) } }, // &foo == bar diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index c3a3f37fab5..68f0ede8a6c 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { _: &'tcx FnDecl, body: &'tcx Body, _: Span, - node_id: NodeId + node_id: NodeId, ) { let fn_def_id = cx.tcx.hir.local_def_id(node_id); let mut v = EscapeDelegate { @@ -74,10 +74,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { ExprUseVisitor::new(&mut v, cx.tcx, cx.param_env, region_maps, cx.tables).consume_body(body); for node in v.set { - span_lint(cx, - BOXED_LOCAL, - cx.tcx.hir.span(node), - "local variable doesn't need to be boxed here"); + span_lint( + cx, + BOXED_LOCAL, + cx.tcx.hir.span(node), + "local variable doesn't need to be boxed here", + ); } } } diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 7ec528b90f4..b5667db920c 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -20,7 +20,8 @@ pub struct EtaPass; /// ```rust /// xs.map(|x| foo(x)) /// ``` -/// where `foo(_)` is a plain function that takes the exact argument type of `x`. +/// where `foo(_)` is a plain function that takes the exact argument type of +/// `x`. declare_lint! { pub REDUNDANT_CLOSURE, Warn, @@ -91,13 +92,11 @@ fn check_closure(cx: &LateContext, expr: &Expr) { return; } } - span_lint_and_then(cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure found", - |db| if let Some(snippet) = snippet_opt(cx, caller.span) { - db.span_suggestion(expr.span, "remove closure as shown", snippet); - }); + span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| { + if let Some(snippet) = snippet_opt(cx, caller.span) { + db.span_suggestion(expr.span, "remove closure as shown", snippet); + } + }); } } } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 765da9ea877..81109761ca7 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -27,12 +27,14 @@ declare_lint! { "whether a variable read occurs before a write depends on sub-expression evaluation order" } -/// **What it does:** Checks for diverging calls that are not match arms or statements. +/// **What it does:** Checks for diverging calls that are not match arms or +/// statements. /// /// **Why is this bad?** It is often confusing to read. In addition, the /// sub-expression evaluation order for Rust is not well documented. /// -/// **Known problems:** Someone might want to use `some_bool || panic!()` as a shorthand. +/// **Known problems:** Someone might want to use `some_bool || panic!()` as a +/// shorthand. /// /// **Example:** /// ```rust @@ -47,7 +49,7 @@ declare_lint! { "whether an expression contains a diverging sub expression" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct EvalOrderDependence; impl LintPass for EvalOrderDependence { @@ -144,7 +146,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { } }, _ => { - // do not lint expressions referencing objects of type `!`, as that required a diverging expression + // do not lint expressions referencing objects of type `!`, as that required a + // diverging expression // to begin with }, } @@ -271,8 +274,10 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> St DeclLocal(ref local) => Some(local), _ => None, }; - local.and_then(|local| local.init.as_ref()) - .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)) + local.and_then(|local| local.init.as_ref()).map_or( + StopEarly::KeepGoing, + |expr| check_expr(vis, expr), + ) }, } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index e7dbc3250f7..16dced95760 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -99,7 +99,8 @@ pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Exp /// Checks if the expressions matches /// ```rust, ignore -/// { static __STATIC_FMTSTR: &'static[&'static str] = &["a", "b", c]; __STATIC_FMTSTR } +/// { static __STATIC_FMTSTR: &'static[&'static str] = &["a", "b", c]; +/// __STATIC_FMTSTR } /// ``` fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { if let Some(expr) = get_argument_fmtstr_parts(cx, expr) { @@ -112,7 +113,8 @@ fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { /// Checks if the expressions matches /// ```rust,ignore /// &match (&42,) { -/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)], +/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, +/// ::std::fmt::Display::fmt)], /// } /// ``` fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 8f8c7db64cf..c478974a5bd 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -4,9 +4,11 @@ use syntax_pos::{Span, NO_EXPANSION}; use utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; use syntax::ptr::P; -/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` operators. +/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` +/// operators. /// -/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or confusing. +/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or +/// confusing. /// /// **Known problems:** None. /// @@ -67,12 +69,16 @@ declare_lint! { } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Formatting; impl LintPass for Formatting { fn get_lints(&self) -> LintArray { - lint_array![SUSPICIOUS_ASSIGNMENT_FORMATTING, SUSPICIOUS_ELSE_FORMATTING, POSSIBLE_MISSING_COMMA] + lint_array!( + SUSPICIOUS_ASSIGNMENT_FORMATTING, + SUSPICIOUS_ELSE_FORMATTING, + POSSIBLE_MISSING_COMMA + ) } } @@ -114,14 +120,18 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { ctxt: NO_EXPANSION, }; if eq_snippet.ends_with('=') { - span_note_and_lint(cx, - SUSPICIOUS_ASSIGNMENT_FORMATTING, - eqop_span, - &format!("this looks like you are trying to use `.. {op}= ..`, but you \ + span_note_and_lint( + cx, + SUSPICIOUS_ASSIGNMENT_FORMATTING, + eqop_span, + &format!( + "this looks like you are trying to use `.. {op}= ..`, but you \ really are doing `.. = ({op} ..)`", - op = op), - eqop_span, - &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op)); + op = op + ), + eqop_span, + &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op), + ); } } } @@ -133,7 +143,8 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) { if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) { - // this will be a span from the closing ‘}’ of the “then” block (excluding) to the + // this will be a span from the closing ‘}’ of the “then” block (excluding) to + // the // “if” of the “else if” block (excluding) let else_span = Span { lo: then.span.hi, @@ -144,16 +155,20 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { // the snippet should look like " else \n " with maybe comments anywhere // it’s bad when there is a ‘\n’ after the “else” if let Some(else_snippet) = snippet_opt(cx, else_span) { - let else_pos = else_snippet.find("else").expect("there must be a `else` here"); + let else_pos = else_snippet.find("else").expect( + "there must be a `else` here", + ); if else_snippet[else_pos..].contains('\n') { - span_note_and_lint(cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - "this is an `else if` but the formatting might hide it", - else_span, - "to remove this lint, remove the `else` or remove the new line between `else` \ - and `if`"); + span_note_and_lint( + cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this is an `else if` but the formatting might hide it", + else_span, + "to remove this lint, remove the `else` or remove the new line between `else` \ + and `if`", + ); } } } @@ -178,12 +193,14 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { ctxt: NO_EXPANSION, }; if space_snippet.contains('\n') { - span_note_and_lint(cx, - POSSIBLE_MISSING_COMMA, - lint_span, - "possibly missing a comma here", - lint_span, - "to remove this lint, add a comma or write the expr in a single line"); + span_note_and_lint( + cx, + POSSIBLE_MISSING_COMMA, + lint_span, + "possibly missing a comma here", + lint_span, + "to remove this lint, add a comma or write the expr in a single line", + ); } } } @@ -195,7 +212,8 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() && - unsugar_if(second).is_some() { + unsugar_if(second).is_some() + { // where the else would be let else_span = Span { lo: first.span.hi, @@ -205,13 +223,15 @@ fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Exp if let Some(else_snippet) = snippet_opt(cx, else_span) { if !else_snippet.contains('\n') { - span_note_and_lint(cx, - SUSPICIOUS_ELSE_FORMATTING, - else_span, - "this looks like an `else if` but the `else` is missing", - else_span, - "to remove this lint, add the missing `else` or add a new line before the second \ - `if`"); + span_note_and_lint( + cx, + SUSPICIOUS_ELSE_FORMATTING, + else_span, + "this looks like an `else if` but the `else` is missing", + else_span, + "to remove this lint, add the missing `else` or add a new line before the second \ + `if`", + ); } } } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 79d47b1e7da..e45ab558089 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -17,7 +17,8 @@ use utils::{span_lint, type_is_unsafe_function, iter_input_pats}; /// /// **Example:** /// ```rust -/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. } +/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: +/// f32) { .. } /// ``` declare_lint! { pub TOO_MANY_ARGUMENTS, @@ -35,7 +36,8 @@ declare_lint! { /// **Known problems:** /// /// * It does not check functions recursively so if the pointer is passed to a -/// private non-`unsafe` function which does the dereferencing, the lint won't trigger. +/// private non-`unsafe` function which does the dereferencing, the lint won't +/// trigger. /// * It only checks for arguments whose type are raw pointers, not raw pointers /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or /// `some_argument.get_raw_ptr()`). @@ -50,7 +52,7 @@ declare_lint! { "public functions dereferencing raw pointer arguments but not marked `unsafe`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Functions { threshold: u64, } @@ -75,7 +77,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { decl: &'tcx hir::FnDecl, body: &'tcx hir::Body, span: Span, - nodeid: ast::NodeId + nodeid: ast::NodeId, ) { use rustc::hir::map::Node::*; @@ -123,10 +125,12 @@ 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 { - span_lint(cx, - TOO_MANY_ARGUMENTS, - span, - &format!("this function has too many arguments ({}/{})", args, self.threshold)); + span_lint( + cx, + TOO_MANY_ARGUMENTS, + span, + &format!("this function has too many arguments ({}/{})", args, self.threshold), + ); } } @@ -136,7 +140,7 @@ impl<'a, 'tcx> Functions { unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl, body: &'tcx hir::Body, - nodeid: ast::NodeId + nodeid: ast::NodeId, ) { let expr = &body.value; if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { @@ -208,10 +212,12 @@ impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> { if let hir::ExprPath(ref qpath) = ptr.node { let def = self.cx.tables.qpath_def(qpath, ptr.id); if self.ptrs.contains(&def.def_id()) { - span_lint(self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function dereferences a raw pointer but is not marked `unsafe`"); + span_lint( + self.cx, + NOT_UNSAFE_PTR_ARG_DEREF, + ptr.span, + "this public function dereferences a raw pointer but is not marked `unsafe`", + ); } } } diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 7bac29f6808..a7c254e1e46 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -22,7 +22,7 @@ declare_lint! { "using identity operations, e.g. `x + 0` or `y / 1`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct IdentityOp; impl LintPass for IdentityOp { @@ -71,12 +71,17 @@ fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { }, 1 => v.to_u128_unchecked() == 1, _ => unreachable!(), - } { - span_lint(cx, - IDENTITY_OP, - span, - &format!("the operation is ineffective. Consider reducing it to `{}`", - snippet(cx, arg, ".."))); + } + { + span_lint( + cx, + IDENTITY_OP, + span, + &format!( + "the operation is ineffective. Consider reducing it to `{}`", + snippet(cx, arg, "..") + ), + ); } } } diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs index 8d6a28e62db..058052769ef 100644 --- a/clippy_lints/src/if_let_redundant_pattern_matching.rs +++ b/clippy_lints/src/if_let_redundant_pattern_matching.rs @@ -3,9 +3,11 @@ use rustc::hir::*; use syntax::codemap::Span; use utils::{paths, span_lint_and_then, match_path, snippet}; -/// **What it does:*** Lint for redundant pattern matching over `Result` or `Option` +/// **What it does:*** Lint for redundant pattern matching over `Result` or +/// `Option` /// -/// **Why is this bad?** It's more concise and clear to just use the proper utility function +/// **Why is this bad?** It's more concise and clear to just use the proper +/// utility function /// /// **Known problems:** None. /// diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 72a3d485bd0..66f2778f215 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,4 +1,5 @@ -//! lint on if branches that could be swapped so no `!` operation is necessary on the condition +//! lint on if branches that could be swapped so no `!` operation is necessary +//! on the condition use rustc::lint::*; use syntax::ast::*; @@ -50,18 +51,22 @@ impl EarlyLintPass for IfNotElse { if let ExprKind::Block(..) = els.node { match cond.node { ExprKind::Unary(UnOp::Not, _) => { - span_help_and_lint(cx, - IF_NOT_ELSE, - item.span, - "Unnecessary boolean `not` operation", - "remove the `!` and swap the blocks of the if/else"); + span_help_and_lint( + cx, + IF_NOT_ELSE, + 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"); + 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 b3561720cc7..f14c70dc4dd 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -47,10 +47,9 @@ 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 { @@ -62,11 +61,13 @@ impl EarlyLintPass for ItemsAfterStatements { // do not lint `macro_rules`, but continue processing further statements continue; } - span_lint(cx, - ITEMS_AFTER_STATEMENTS, - it.span, - "adding items after statements is confusing, since items exist from the \ - start of the scope"); + span_lint( + cx, + ITEMS_AFTER_STATEMENTS, + it.span, + "adding items after statements is confusing, since items exist from the \ + start of the scope", + ); } } } diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 4e9c792c42a..73a62c97bc8 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -5,9 +5,11 @@ use rustc::hir::*; use utils::{span_lint_and_then, snippet_opt, type_size}; use rustc::ty::TypeFoldable; -/// **What it does:** Checks for large size differences between variants on `enum`s. +/// **What it does:** Checks for large size differences between variants on +/// `enum`s. /// -/// **Why is this bad?** Enum size is bounded by the largest variant. Having a large variant +/// **Why is this bad?** Enum size is bounded by the largest variant. Having a +/// large variant /// can penalize the memory layout of that enum. /// /// **Known problems:** None. @@ -25,7 +27,7 @@ declare_lint! { "large size difference between variants on an enum" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct LargeEnumVariant { maximum_size_difference_allowed: u64, } @@ -47,13 +49,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { let did = cx.tcx.hir.local_def_id(item.id); if let ItemEnum(ref def, _) = item.node { let ty = cx.tcx.type_of(did); - let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); + let adt = ty.ty_adt_def().expect( + "already checked whether this is an enum", + ); let mut smallest_variant: Option<(_, _)> = None; let mut largest_variant: Option<(_, _)> = None; for (i, variant) in adt.variants.iter().enumerate() { - let size: u64 = variant.fields + let size: u64 = variant + .fields .iter() .map(|f| { let ty = cx.tcx.type_of(f.did); @@ -77,28 +82,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { if difference > self.maximum_size_difference_allowed { let (i, variant) = largest.1; - span_lint_and_then(cx, - LARGE_ENUM_VARIANT, - def.variants[i].span, - "large size difference between variants", - |db| { - if variant.fields.len() == 1 { - let span = match def.variants[i].node.data { - VariantData::Struct(ref fields, _) | - VariantData::Tuple(ref fields, _) => fields[0].ty.span, - VariantData::Unit(_) => unreachable!(), - }; - if let Some(snip) = snippet_opt(cx, span) { - db.span_suggestion(span, - "consider boxing the large fields to reduce the total size of the \ + span_lint_and_then( + cx, + LARGE_ENUM_VARIANT, + def.variants[i].span, + "large size difference between variants", + |db| { + if variant.fields.len() == 1 { + let span = match def.variants[i].node.data { + VariantData::Struct(ref fields, _) | + VariantData::Tuple(ref fields, _) => fields[0].ty.span, + VariantData::Unit(_) => unreachable!(), + }; + if let Some(snip) = snippet_opt(cx, span) { + db.span_suggestion( + span, + "consider boxing the large fields to reduce the total size of the \ enum", - format!("Box<{}>", snip)); - return; + format!("Box<{}>", snip), + ); + return; + } } - } - db.span_help(def.variants[i].span, - "consider boxing the large fields to reduce the total size of the enum"); - }); + db.span_help( + def.variants[i].span, + "consider boxing the large fields to reduce the total size of the enum", + ); + }, + ); } } @@ -107,7 +118,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { } fn update_if<T, F>(old: &mut Option<T>, new: T, f: F) - where F: Fn(&T, &T) -> bool +where + F: Fn(&T, &T) -> bool, { if let Some(ref mut val) = *old { if f(val, &new) { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 9b76986dbcc..4e40348facf 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -51,7 +51,7 @@ declare_lint! { "traits or impls with a public `len` method but no corresponding `is_empty` method" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct LenZero; impl LintPass for LenZero { @@ -91,24 +91,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef]) { fn is_named_self(cx: &LateContext, item: &TraitItemRef, name: &str) -> bool { item.name == name && - if let AssociatedItemKind::Method { has_self } = item.kind { - has_self && - { - let did = cx.tcx.hir.local_def_id(item.id.node_id); - cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 + if let AssociatedItemKind::Method { has_self } = item.kind { + has_self && + { + let did = cx.tcx.hir.local_def_id(item.id.node_id); + cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 + } + } else { + false } - } else { - false - } } if !trait_items.iter().any(|i| is_named_self(cx, i, "is_empty")) { if let Some(i) = trait_items.iter().find(|i| is_named_self(cx, i, "len")) { if cx.access_levels.is_exported(i.id.node_id) { - span_lint(cx, - LEN_WITHOUT_IS_EMPTY, - item.span, - &format!("trait `{}` has a `len` method but no `is_empty` method", item.name)); + span_lint( + cx, + LEN_WITHOUT_IS_EMPTY, + item.span, + &format!("trait `{}` has a `len` method but no `is_empty` method", item.name), + ); } } } @@ -117,15 +119,15 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef] fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool { item.name == name && - if let AssociatedItemKind::Method { has_self } = item.kind { - has_self && - { - let did = cx.tcx.hir.local_def_id(item.id.node_id); - cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 + if let AssociatedItemKind::Method { has_self } = item.kind { + has_self && + { + let did = cx.tcx.hir.local_def_id(item.id.node_id); + cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 + } + } else { + false } - } else { - false - } } let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) { @@ -143,10 +145,12 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { let def_id = cx.tcx.hir.local_def_id(item.id); let ty = cx.tcx.type_of(def_id); - span_lint(cx, - LEN_WITHOUT_IS_EMPTY, - item.span, - &format!("item `{}` has a public `len` method but {} `is_empty` method", ty, is_empty)); + span_lint( + cx, + LEN_WITHOUT_IS_EMPTY, + item.span, + &format!("item `{}` has a public `len` method but {} `is_empty` method", ty, is_empty), + ); } } } @@ -170,12 +174,14 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) fn check_len_zero(cx: &LateContext, span: Span, name: Name, args: &[Expr], lit: &Lit, op: &str) { if let Spanned { node: LitKind::Int(0, _), .. } = *lit { if name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { - span_lint_and_sugg(cx, - LEN_ZERO, - span, - "length comparison to zero", - "using `is_empty` is more concise", - format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_"))); + span_lint_and_sugg( + cx, + LEN_ZERO, + span, + "length comparison to zero", + "using `is_empty` is more concise", + format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")), + ); } } } @@ -199,10 +205,11 @@ 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(id) - .iter() - .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item))) + cx.tcx.inherent_impls(id).iter().any(|imp| { + cx.tcx.associated_items(*imp).any( + |item| is_is_empty(cx, &item), + ) + }) } let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr)); @@ -212,7 +219,12 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { .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::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::TySlice(..) | ty::TyStr => true, _ => false, diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 93b981a2b4a..ecd18424bd8 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -49,7 +49,7 @@ declare_lint! { "unidiomatic `let mut` declaration followed by initialization in `if`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct LetIfSeq; impl LintPass for LetIfSeq { @@ -154,7 +154,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> { fn check_assign<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, decl: hir::def_id::DefId, - block: &'tcx hir::Block + block: &'tcx hir::Block, ) -> Option<&'tcx hir::Expr> { if_let_chain! {[ block.expr.is_none(), diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index d29ef8200ec..dd721db0f09 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -48,7 +48,7 @@ declare_lint! { "unused lifetimes in function definitions" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct LifetimePass; impl LintPass for LifetimePass { @@ -94,7 +94,7 @@ fn check_fn_inner<'a, 'tcx>( decl: &'tcx FnDecl, body: Option<BodyId>, generics: &'tcx Generics, - span: Span + span: Span, ) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { return; @@ -104,7 +104,8 @@ fn check_fn_inner<'a, 'tcx>( for typ in &generics.ty_params { for bound in &typ.bounds { if let TraitTyParamBound(ref trait_ref, _) = *bound { - let bounds = trait_ref.trait_ref + let bounds = trait_ref + .trait_ref .path .segments .last() @@ -121,10 +122,12 @@ fn check_fn_inner<'a, 'tcx>( } } if could_use_elision(cx, decl, body, &generics.lifetimes, bounds_lts) { - span_lint(cx, - NEEDLESS_LIFETIMES, - span, - "explicit lifetimes given in parameter types where they could be elided"); + span_lint( + cx, + NEEDLESS_LIFETIMES, + span, + "explicit lifetimes given in parameter types where they could be elided", + ); } report_extra_lifetimes(cx, decl, generics); } @@ -134,7 +137,7 @@ fn could_use_elision<'a, 'tcx: 'a>( func: &'tcx FnDecl, body: Option<BodyId>, named_lts: &'tcx [LifetimeDef], - bounds_lts: Vec<&'tcx Lifetime> + bounds_lts: Vec<&'tcx Lifetime>, ) -> bool { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -189,7 +192,10 @@ fn could_use_elision<'a, 'tcx: 'a>( // no output lifetimes, check distinctness of input lifetimes // only unnamed and static, ok - if input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static) { + if input_lts.iter().all(|lt| { + *lt == RefLt::Unnamed || *lt == RefLt::Static + }) + { return false; } // we have no output reference, so we only need all distinct lifetimes @@ -406,7 +412,8 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { } fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) { - let hs = generics.lifetimes + let hs = generics + .lifetimes .iter() .map(|lt| (lt.lifetime.name, lt.lifetime.span)) .collect(); diff --git a/clippy_lints/src/literal_digit_grouping.rs b/clippy_lints/src/literal_digit_grouping.rs index 2b1599d79f3..0da8ffd0a30 100644 --- a/clippy_lints/src/literal_digit_grouping.rs +++ b/clippy_lints/src/literal_digit_grouping.rs @@ -146,7 +146,8 @@ impl<'a> DigitInfo<'a> { let group_size = self.radix.suggest_grouping(); if self.digits.contains('.') { let mut parts = self.digits.split('.'); - let int_part_hint = parts.next() + let int_part_hint = parts + .next() .expect("split always returns at least one element") .chars() .rev() @@ -157,7 +158,8 @@ impl<'a> DigitInfo<'a> { .rev() .collect::<Vec<String>>() .join("_"); - let frac_part_hint = parts.next() + let frac_part_hint = parts + .next() .expect("already checked that there is a `.`") .chars() .filter(|&c| c != '_') @@ -194,25 +196,31 @@ impl WarningType { pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: &syntax_pos::Span) { match *self { WarningType::UnreadableLiteral => { - span_help_and_lint(cx, - UNREADABLE_LITERAL, - *span, - "long literal lacking separators", - &format!("consider: {}", grouping_hint)) + span_help_and_lint( + cx, + UNREADABLE_LITERAL, + *span, + "long literal lacking separators", + &format!("consider: {}", grouping_hint), + ) }, WarningType::LargeDigitGroups => { - span_help_and_lint(cx, - LARGE_DIGIT_GROUPS, - *span, - "digit groups should be smaller", - &format!("consider: {}", grouping_hint)) + span_help_and_lint( + cx, + LARGE_DIGIT_GROUPS, + *span, + "digit groups should be smaller", + &format!("consider: {}", grouping_hint), + ) }, WarningType::InconsistentDigitGrouping => { - span_help_and_lint(cx, - INCONSISTENT_DIGIT_GROUPING, - *span, - "digits grouped inconsistently by underscores", - &format!("consider: {}", grouping_hint)) + span_help_and_lint( + cx, + INCONSISTENT_DIGIT_GROUPING, + *span, + "digits grouped inconsistently by underscores", + &format!("consider: {}", grouping_hint), + ) }, }; } @@ -309,7 +317,8 @@ impl LiteralDigitGrouping { /// size on success or `WarningType` when emitting a warning. fn do_lint(digits: &str) -> Result<usize, WarningType> { // Grab underscore indices with respect to the units digit. - let underscore_positions: Vec<usize> = digits.chars() + let underscore_positions: Vec<usize> = digits + .chars() .rev() .enumerate() .filter_map(|(idx, digit)| if digit == '_' { Some(idx) } else { None }) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index fc28918ff16..25015cb26bb 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -83,7 +83,8 @@ declare_lint! { /// implements `IntoIterator`, so that possibly one value will be iterated, /// leading to some hard to find bugs. No one will want to write such code /// [except to win an Underhanded Rust -/// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). +/// Contest](https://www.reddit. +/// com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). /// /// **Known problems:** None. /// @@ -99,7 +100,8 @@ declare_lint! { /// **What it does:** Checks for `for` loops over `Option` values. /// -/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// **Why is this bad?** Readability. This is more clearly expressed as an `if +/// let`. /// /// **Known problems:** None. /// @@ -120,7 +122,8 @@ declare_lint! { /// **What it does:** Checks for `for` loops over `Result` values. /// -/// **Why is this bad?** Readability. This is more clearly expressed as an `if let`. +/// **Why is this bad?** Readability. This is more clearly expressed as an `if +/// let`. /// /// **Known problems:** None. /// @@ -142,7 +145,8 @@ declare_lint! { /// **What it does:** Detects `loop + match` combinations that are easier /// written as a `while let` loop. /// -/// **Why is this bad?** The `while let` loop is usually shorter and more readable. +/// **Why is this bad?** The `while let` loop is usually shorter and more +/// readable. /// /// **Known problems:** Sometimes the wrong binding is displayed (#383). /// @@ -309,20 +313,22 @@ pub struct Pass; impl LintPass for Pass { fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RANGE_LOOP, - EXPLICIT_ITER_LOOP, - EXPLICIT_INTO_ITER_LOOP, - ITER_NEXT_LOOP, - FOR_LOOP_OVER_RESULT, - FOR_LOOP_OVER_OPTION, - WHILE_LET_LOOP, - UNUSED_COLLECT, - REVERSE_RANGE_LOOP, - EXPLICIT_COUNTER_LOOP, - EMPTY_LOOP, - WHILE_LET_ON_ITERATOR, - FOR_KV_MAP, - NEVER_LOOP) + lint_array!( + NEEDLESS_RANGE_LOOP, + EXPLICIT_ITER_LOOP, + EXPLICIT_INTO_ITER_LOOP, + ITER_NEXT_LOOP, + FOR_LOOP_OVER_RESULT, + FOR_LOOP_OVER_OPTION, + WHILE_LET_LOOP, + UNUSED_COLLECT, + REVERSE_RANGE_LOOP, + EXPLICIT_COUNTER_LOOP, + EMPTY_LOOP, + WHILE_LET_ON_ITERATOR, + FOR_KV_MAP, + NEVER_LOOP + ) } } @@ -349,11 +355,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprLoop(ref block, _, LoopSource::Loop) = expr.node { // also check for empty `loop {}` statements if block.stmts.is_empty() && block.expr.is_none() { - span_lint(cx, - EMPTY_LOOP, - expr.span, - "empty `loop {}` detected. You may want to either use `panic!()` or add \ - `std::thread::sleep(..);` to the loop body."); + span_lint( + cx, + EMPTY_LOOP, + expr.span, + "empty `loop {}` detected. You may want to either use `panic!()` or add \ + `std::thread::sleep(..);` to the loop body.", + ); } // extract the expression from the first statement (if any) in a block @@ -366,8 +374,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { 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) { + arms[1].pats.len() == 1 && arms[1].guard.is_none() && + is_break_expr(&arms[1].body) + { if in_external_macro(cx, expr.span) { return; } @@ -377,14 +386,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // 1) it was ugly with big bodies; // 2) it was not indented properly; // 3) it wasn’t very smart (see #675). - span_lint_and_sugg(cx, - WHILE_LET_LOOP, - expr.span, - "this loop could be written as a `while let` loop", - "try", - format!("while let {} = {} {{ .. }}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, ".."))); + span_lint_and_sugg( + cx, + WHILE_LET_LOOP, + expr.span, + "this loop could be written as a `while let` loop", + "try", + format!( + "while let {} = {} {{ .. }}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, matchexpr.span, "..") + ), + ); } }, _ => (), @@ -395,20 +408,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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 qpath, ref pat_args, _), - &ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node) { + &ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node) + { let iter_expr = &method_args[0]; let lhs_constructor = last_path_segment(qpath); if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) && - lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) && - !is_iterator_used_after_while_let(cx, iter_expr) && !is_nested(cx, expr, &method_args[0]) { + lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) && + !is_iterator_used_after_while_let(cx, iter_expr) && + !is_nested(cx, expr, &method_args[0]) + { let iterator = snippet(cx, method_args[0].span, "_"); let loop_var = snippet(cx, pat_args[0].span, "_"); - span_lint_and_sugg(cx, - WHILE_LET_ON_ITERATOR, - expr.span, - "this loop could be written as a `for` loop", - "try", - format!("for {} in {} {{ .. }}", loop_var, iterator)); + span_lint_and_sugg( + cx, + WHILE_LET_ON_ITERATOR, + expr.span, + "this loop could be written as a `for` loop", + "try", + format!("for {} in {} {{ .. }}", loop_var, iterator), + ); } } } @@ -418,11 +436,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let StmtSemi(ref expr, _) = stmt.node { if let ExprMethodCall(ref method, _, ref args) = expr.node { if args.len() == 1 && method.name == "collect" && match_trait_method(cx, expr, &paths::ITERATOR) { - span_lint(cx, - UNUSED_COLLECT, - expr.span, - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator"); + span_lint( + cx, + UNUSED_COLLECT, + expr.span, + "you are collect()ing an iterator and throwing away the result. \ + Consider using an explicit for loop to exhaust the iterator", + ); } } } @@ -435,7 +455,10 @@ fn never_loop(block: &Block, id: &NodeId) -> bool { fn contains_continue_block(block: &Block, dest: &NodeId) -> bool { block.stmts.iter().any(|e| contains_continue_stmt(e, dest)) || - block.expr.as_ref().map_or(false, |e| contains_continue_expr(e, dest)) + block.expr.as_ref().map_or( + false, + |e| contains_continue_expr(e, dest), + ) } fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool { @@ -448,7 +471,12 @@ fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool { fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool { match decl.node { - DeclLocal(ref local) => local.init.as_ref().map_or(false, |e| contains_continue_expr(e, dest)), + DeclLocal(ref local) => { + local.init.as_ref().map_or( + false, + |e| contains_continue_expr(e, dest), + ) + }, _ => false, } } @@ -475,14 +503,21 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool { ExprAssignOp(_, ref e1, ref e2) | ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| contains_continue_expr(e, dest)), ExprIf(ref e, ref e2, ref e3) => { - [e, e2].iter().chain(e3.as_ref().iter()).any(|e| contains_continue_expr(e, dest)) + [e, e2].iter().chain(e3.as_ref().iter()).any(|e| { + contains_continue_expr(e, dest) + }) }, ExprWhile(ref e, ref b, _) => contains_continue_expr(e, dest) || contains_continue_block(b, dest), ExprMatch(ref e, ref arms, _) => { contains_continue_expr(e, dest) || arms.iter().any(|a| contains_continue_expr(&a.body, dest)) }, ExprBlock(ref block) => contains_continue_block(block, dest), - ExprStruct(_, _, ref base) => base.as_ref().map_or(false, |e| contains_continue_expr(e, dest)), + ExprStruct(_, _, ref base) => { + base.as_ref().map_or( + false, + |e| contains_continue_expr(e, dest), + ) + }, ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| id == *dest), _ => false, } @@ -541,7 +576,7 @@ fn check_for_loop<'a, 'tcx>( pat: &'tcx Pat, arg: &'tcx Expr, body: &'tcx Expr, - expr: &'tcx Expr + expr: &'tcx Expr, ) { check_for_loop_range(cx, pat, arg, body, expr); check_for_loop_reverse_range(cx, arg, expr); @@ -557,9 +592,14 @@ fn check_for_loop_range<'a, 'tcx>( pat: &'tcx Pat, arg: &'tcx Expr, body: &'tcx Expr, - expr: &'tcx Expr + expr: &'tcx Expr, ) { - if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::range(arg) { + 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(_, def_id, ref ident, _) = pat.node { let mut visitor = VarVisitor { @@ -573,10 +613,9 @@ fn check_for_loop_range<'a, 'tcx>( // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let (indexed, indexed_extent) = visitor.indexed - .into_iter() - .next() - .expect("already checked that we have exactly 1 element"); + let (indexed, indexed_extent) = visitor.indexed.into_iter().next().expect( + "already checked that we have exactly 1 element", + ); // ensure that the indexed variable was declared before the loop, see #601 if let Some(indexed_extent) = indexed_extent { @@ -589,7 +628,8 @@ fn check_for_loop_range<'a, 'tcx>( } } - // don't lint if the container that is indexed into is also used without indexing + // don't lint if the container that is indexed into is also used without + // indexing if visitor.referenced.contains(&indexed) { return; } @@ -670,7 +710,12 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... - if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { + if let Some(higher::Range { + start: Some(start), + end: Some(end), + limits, + }) = higher::range(arg) + { // ...and both sides are compile-time constant integers... let parent_item = cx.tcx.hir.get_parent(arg.id); let parent_def_id = cx.tcx.hir.local_def_id(parent_item); @@ -714,10 +759,12 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { } else if eq && limits != ast::RangeLimits::Closed { // if they are equal, it's also problematic - this loop // will never run. - span_lint(cx, - REVERSE_RANGE_LOOP, - expr.span, - "this range is empty so this for loop will never run"); + span_lint( + cx, + REVERSE_RANGE_LOOP, + expr.span, + "this range is empty so this for loop will never run", + ); } } } @@ -731,13 +778,15 @@ fn lint_iter_method(cx: &LateContext, args: &[Expr], arg: &Expr, method_name: &s } else { "" }; - span_lint_and_sugg(cx, - EXPLICIT_ITER_LOOP, - arg.span, - "it is more idiomatic to loop over references to containers instead of using explicit \ + span_lint_and_sugg( + cx, + EXPLICIT_ITER_LOOP, + arg.span, + "it is more idiomatic to loop over references to containers instead of using explicit \ iteration methods", - "to write this more concisely, try", - format!("&{}{}", muta, object)) + "to write this more concisely, try", + format!("&{}{}", muta, object), + ) } fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { @@ -762,20 +811,24 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { lint_iter_method(cx, args, arg, method_name); } else { let object = snippet(cx, args[0].span, "_"); - span_lint_and_sugg(cx, - EXPLICIT_INTO_ITER_LOOP, - arg.span, - "it is more idiomatic to loop over containers instead of using explicit \ + span_lint_and_sugg( + cx, + EXPLICIT_INTO_ITER_LOOP, + arg.span, + "it is more idiomatic to loop over containers instead of using explicit \ iteration methods`", - "to write this more concisely, try", - object.to_string()); + "to write this more concisely, try", + object.to_string(), + ); } } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { - span_lint(cx, - ITER_NEXT_LOOP, - expr.span, - "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ - probably not what you want"); + span_lint( + cx, + ITER_NEXT_LOOP, + expr.span, + "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ + probably not what you want", + ); next_loop_linted = true; } } @@ -789,25 +842,37 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { let ty = cx.tables.expr_ty(arg); if match_type(cx, ty, &paths::OPTION) { - span_help_and_lint(cx, - FOR_LOOP_OVER_OPTION, - arg.span, - &format!("for loop over `{0}`, which is an `Option`. This is more readably written as an \ + span_help_and_lint( + cx, + FOR_LOOP_OVER_OPTION, + arg.span, + &format!( + "for loop over `{0}`, which is an `Option`. This is more readably written as an \ `if let` statement.", - snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", - snippet(cx, pat.span, "_"), - snippet(cx, arg.span, "_"))); + snippet(cx, arg.span, "_") + ), + &format!( + "consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_") + ), + ); } else if match_type(cx, ty, &paths::RESULT) { - span_help_and_lint(cx, - FOR_LOOP_OVER_RESULT, - arg.span, - &format!("for loop over `{0}`, which is a `Result`. This is more readably written as an \ + span_help_and_lint( + cx, + FOR_LOOP_OVER_RESULT, + arg.span, + &format!( + "for loop over `{0}`, which is a `Result`. This is more readably written as an \ `if let` statement.", - snippet(cx, arg.span, "_")), - &format!("consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", - snippet(cx, pat.span, "_"), - snippet(cx, arg.span, "_"))); + snippet(cx, arg.span, "_") + ), + &format!( + "consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`", + snippet(cx, pat.span, "_"), + snippet(cx, arg.span, "_") + ), + ); } } @@ -815,7 +880,7 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, body: &'tcx Expr, - expr: &'tcx Expr + expr: &'tcx Expr, ) { // Look for variables that are incremented once per loop iteration. let mut visitor = IncrementVisitor { @@ -829,10 +894,15 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. let map = &cx.tcx.hir; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| map.get_enclosing_scope(id)); + let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| { + map.get_enclosing_scope(id) + }); if let Some(parent_id) = parent_scope { if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) { + for (id, _) in visitor.states.iter().filter( + |&(_, v)| *v == VarState::IncrOnce, + ) + { let mut visitor2 = InitializeVisitor { cx: cx, end_expr: expr, @@ -846,13 +916,17 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( if visitor2.state == VarState::Warn { if let Some(name) = visitor2.name { - span_lint(cx, - EXPLICIT_COUNTER_LOOP, - expr.span, - &format!("the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ + span_lint( + cx, + EXPLICIT_COUNTER_LOOP, + expr.span, + &format!( + "the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ item) in {1}.enumerate()` or similar iterators", - name, - snippet(cx, arg.span, "_"))); + name, + snippet(cx, arg.span, "_") + ), + ); } } } @@ -866,7 +940,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( pat: &'tcx Pat, arg: &'tcx Expr, body: &'tcx Expr, - expr: &'tcx Expr + expr: &'tcx Expr, ) { let pat_span = pat.span; @@ -929,7 +1003,7 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool { fn match_var(expr: &Expr, var: Name) -> bool { if let ExprPath(QPath::Resolved(None, ref path)) = expr.node { if path.segments.len() == 1 && path.segments[0].name == var { - return true + return true; } } false @@ -964,7 +1038,8 @@ struct VarVisitor<'a, 'tcx: 'a> { /// Any names that are used outside an index operation. /// Used to detect things like `&mut vec` used together with `vec[i]` referenced: HashSet<Name>, - /// has the loop variable been used in expressions other than the index of an index op? + /// has the loop variable been used in expressions other than the index of + /// an index op? nonindex: bool, } @@ -1095,7 +1170,8 @@ fn is_iterable_array(ty: Ty) -> bool { } } -/// If a block begins with a statement (possibly a `let` binding) and has an expression, return it. +/// If a block begins with a statement (possibly a `let` binding) and has an +/// expression, return it. fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { if block.stmts.is_empty() { return None; @@ -1302,7 +1378,9 @@ fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let ExprPath(ref qpath) = expr.node { let path_res = cx.tables.qpath_def(qpath, expr.id); if let Def::Local(def_id) = path_res { - let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("That DefId should be valid"); + let node_id = cx.tcx.hir.as_local_node_id(def_id).expect( + "That DefId should be valid", + ); return Some(node_id); } } @@ -1348,17 +1426,18 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool match cx.tcx.hir.find(parent) { Some(NodeExpr(expr)) => { match expr.node { - ExprLoop(..) | - ExprWhile(..) => { return true; }, - _ => () + ExprLoop(..) | ExprWhile(..) => { + return true; + }, + _ => (), } }, Some(NodeBlock(block)) => { let mut block_visitor = LoopNestVisitor { - id: id, - iterator: iter_name, - nesting: Unknown - }; + id: id, + iterator: iter_name, + nesting: Unknown, + }; walk_block(&mut block_visitor, block); if block_visitor.nesting == RuledOut { return false; @@ -1367,7 +1446,7 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool Some(NodeStmt(_)) => (), _ => { return false; - } + }, } id = parent; } @@ -1377,7 +1456,7 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool enum Nesting { Unknown, // no nesting detected yet RuledOut, // the iterator is initialized or assigned within scope - LookFurther // no nesting detected, no further walk required + LookFurther, // no nesting detected, no further walk required } use self::Nesting::{Unknown, RuledOut, LookFurther}; @@ -1385,7 +1464,7 @@ use self::Nesting::{Unknown, RuledOut, LookFurther}; struct LoopNestVisitor { id: NodeId, iterator: Name, - nesting: Nesting + nesting: Nesting, } impl<'tcx> Visitor<'tcx> for LoopNestVisitor { @@ -1398,22 +1477,28 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } fn visit_expr(&mut self, expr: &'tcx Expr) { - if self.nesting != Unknown { return; } + if self.nesting != Unknown { + return; + } if expr.id == self.id { self.nesting = LookFurther; return; } match expr.node { ExprAssign(ref path, _) | - ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) { - self.nesting = RuledOut; + ExprAssignOp(_, ref path, _) => { + if match_var(path, self.iterator) { + self.nesting = RuledOut; + } }, - _ => walk_expr(self, expr) + _ => walk_expr(self, expr), } } fn visit_pat(&mut self, pat: &'tcx Pat) { - if self.nesting != Unknown { return; } + if self.nesting != Unknown { + return; + } if let PatKind::Binding(_, _, span_name, _) = pat.node { if self.iterator == span_name.node { self.nesting = RuledOut; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1661c71167e..457c6cc8d65 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -2,8 +2,8 @@ use rustc::lint::*; use rustc::hir::*; use rustc::ty; use syntax::ast; -use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet, span_help_and_lint, - walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats}; +use utils::{is_adjusted, match_path, match_trait_method, match_type, remove_blocks, paths, snippet, + span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats}; /// **What it does:** Checks for mapping `clone()` over an iterator. /// @@ -76,13 +76,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { 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, - MAP_CLONE, - expr.span, - &format!("you seem to be using .map() to clone the contents of an \ + span_help_and_lint( + cx, + MAP_CLONE, + expr.span, + &format!( + "you seem to be using .map() to clone the contents of an \ {}, consider using `.cloned()`", - type_name), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); + type_name + ), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")), + ); } }, _ => (), @@ -95,10 +99,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { match expr.node { ExprPath(QPath::Resolved(None, ref path)) => { - let arg_segment = [PathSegment { - name: id, - parameters: PathParameters::none(), - }]; + let arg_segment = [ + PathSegment { + name: id, + parameters: PathParameters::none(), + }, + ]; !path.is_global() && path.segments[..] == arg_segment }, _ => false, diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index ec06e72749e..5dba102f6a4 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -150,12 +150,14 @@ 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, - MATCH_WILD_ERR_ARM) + lint_array!( + SINGLE_MATCH, + MATCH_REF_PATS, + MATCH_BOOL, + SINGLE_MATCH_ELSE, + MATCH_OVERLAPPING_ARM, + MATCH_WILD_ERR_ARM + ) } } @@ -212,28 +214,34 @@ fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], SINGLE_MATCH }; let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); - span_lint_and_sugg(cx, - lint, - expr.span, - "you seem to be trying to use match for destructuring a single pattern. Consider using `if \ + span_lint_and_sugg( + cx, + lint, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. Consider using `if \ let`", - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); + "try this", + format!( + "if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str + ), + ); } fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty, els: Option<&Expr>) { // list of candidate Enums we know will never get any more members - let candidates = &[(&paths::COW, "Borrowed"), - (&paths::COW, "Cow::Borrowed"), - (&paths::COW, "Cow::Owned"), - (&paths::COW, "Owned"), - (&paths::OPTION, "None"), - (&paths::RESULT, "Err"), - (&paths::RESULT, "Ok")]; + let candidates = &[ + (&paths::COW, "Borrowed"), + (&paths::COW, "Cow::Borrowed"), + (&paths::COW, "Cow::Owned"), + (&paths::COW, "Owned"), + (&paths::OPTION, "None"), + (&paths::RESULT, "Err"), + (&paths::RESULT, "Ok"), + ]; let path = match arms[1].pats[0].node { PatKind::TupleStruct(ref path, ref inner, _) => { @@ -258,52 +266,60 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { // type of expression == bool if cx.tables.expr_ty(ex).sty == ty::TyBool { - span_lint_and_then(cx, - MATCH_BOOL, - expr.span, - "you seem to be trying to match on a boolean expression", - move |db| { - if arms.len() == 2 && arms[0].pats.len() == 1 { - // no guards - let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pats[0].node { - if let ExprLit(ref lit) = arm_bool.node { - match lit.node { - LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), - LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), - _ => None, + span_lint_and_then( + cx, + MATCH_BOOL, + expr.span, + "you seem to be trying to match on a boolean expression", + move |db| { + if arms.len() == 2 && arms[0].pats.len() == 1 { + // no guards + let exprs = if let PatKind::Lit(ref arm_bool) = arms[0].pats[0].node { + if let ExprLit(ref lit) = arm_bool.node { + match lit.node { + LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)), + LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)), + _ => None, + } + } else { + None } } else { None - } - } else { - None - }; - - if let Some((true_expr, false_expr)) = exprs { - let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => { - Some(format!("if {} {} else {}", - 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, ".."))) - }, - (true, true) => None, }; - if let Some(sugg) = sugg { - db.span_suggestion(expr.span, "consider using an if/else expression", sugg); + if let Some((true_expr, false_expr)) = exprs { + let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => { + Some(format!( + "if {} {} else {}", + 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, ".."))) + }, + (true, true) => None, + }; + + if let Some(sugg) = sugg { + db.span_suggestion(expr.span, "consider using an if/else expression", sugg); + } } } - } - }); + }, + ); } } @@ -313,12 +329,14 @@ fn check_overlapping_arms(cx: &LateContext, ex: &Expr, arms: &[Arm]) { let type_ranges = type_ranges(&ranges); if !type_ranges.is_empty() { if let Some((start, end)) = overlapping(&type_ranges) { - span_note_and_lint(cx, - MATCH_OVERLAPPING_ARM, - start.span, - "some ranges overlap", - end.span, - "overlaps with this"); + span_note_and_lint( + cx, + MATCH_OVERLAPPING_ARM, + start.span, + "some ranges overlap", + end.span, + "overlaps with this", + ); } } } @@ -376,17 +394,21 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match db.span_suggestion(expr.span, "try", template); }); } else { - span_lint_and_then(cx, - MATCH_REF_PATS, - expr.span, - "you don't need to add `&` to all patterns", - |db| { - 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", - template); - }); + span_lint_and_then( + cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to all patterns", + |db| { + 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", + template, + ); + }, + ); } } } @@ -399,13 +421,17 @@ fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &[Arm], id: NodeId) -> let constcx = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables); arms.iter() .flat_map(|arm| { - if let Arm { ref pats, guard: None, .. } = *arm { - pats.iter() - } else { - [].iter() - } - .filter_map(|pat| { - if_let_chain! {[ + if let Arm { + ref pats, + guard: None, + .. + } = *arm + { + pats.iter() + } else { + [].iter() + }.filter_map(|pat| { + if_let_chain! {[ let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node, let Ok(lhs) = constcx.eval(lhs), let Ok(rhs) = constcx.eval(rhs) @@ -417,15 +443,15 @@ fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &[Arm], id: NodeId) -> 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) = constcx.eval(value) ], { return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) }); }} - None - }) + None + }) }) .collect() } @@ -438,10 +464,12 @@ pub struct SpannedRange<T> { type TypedRanges = Vec<SpannedRange<ConstInt>>; -/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway and other types than +/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway +/// and other types than /// `Uint` and `Int` probably don't make sense. fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { - ranges.iter() + ranges + .iter() .filter_map(|range| match range.node { (ConstVal::Integral(start), Bound::Included(ConstVal::Integral(end))) => { Some(SpannedRange { @@ -500,7 +528,8 @@ fn match_template(span: Span, source: MatchSource, expr: &Sugg) -> String { } pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)> - where T: Copy + Ord +where + T: Copy + Ord, { #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Kind<'a, T: 'a> { diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index b43a2473f0d..280b51b2312 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -2,7 +2,8 @@ use rustc::lint::*; use rustc::hir::{Expr, ExprCall, ExprPath}; use utils::{match_def_path, paths, span_lint}; -/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is `Drop`. +/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is +/// `Drop`. /// /// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its /// destructor, possibly causing leaks. @@ -38,7 +39,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget { if match forgot_ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), _ => false, - } { + } + { span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); } } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 1c6f7dd214e..c04fdde772f 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -65,7 +65,8 @@ declare_lint! { /// information) instead of an inherent implementation. /// /// **Why is this bad?** Implementing the traits improve ergonomics for users of -/// the code, often with very little cost. Also people seeing a `mul(...)` method +/// the code, often with very little cost. Also people seeing a `mul(...)` +/// method /// may expect `*` to work equally, so you should have good reason to disappoint /// them. /// @@ -368,7 +369,8 @@ declare_lint! { `_.split(\"x\")`" } -/// **What it does:** Checks for getting the inner pointer of a temporary `CString`. +/// **What it does:** Checks for getting the inner pointer of a temporary +/// `CString`. /// /// **Why is this bad?** The inner pointer of a `CString` is only valid as long /// as the `CString` is alive. @@ -500,7 +502,8 @@ declare_lint! { "using `x.extend(s.chars())` where s is a `&str` or `String`" } -/// **What it does:** Checks for the use of `.cloned().collect()` on slice to create a `Vec`. +/// **What it does:** Checks for the use of `.cloned().collect()` on slice to +/// create a `Vec`. /// /// **Why is this bad?** `.to_vec()` is clearer /// @@ -524,29 +527,31 @@ declare_lint! { impl LintPass for Pass { fn get_lints(&self) -> LintArray { - lint_array!(OPTION_UNWRAP_USED, - RESULT_UNWRAP_USED, - SHOULD_IMPLEMENT_TRAIT, - WRONG_SELF_CONVENTION, - WRONG_PUB_SELF_CONVENTION, - OK_EXPECT, - OPTION_MAP_UNWRAP_OR, - OPTION_MAP_UNWRAP_OR_ELSE, - OR_FUN_CALL, - CHARS_NEXT_CMP, - CLONE_ON_COPY, - CLONE_DOUBLE_REF, - NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN, - SEARCH_IS_SOME, - TEMPORARY_CSTRING_AS_PTR, - FILTER_NEXT, - FILTER_MAP, - ITER_NTH, - ITER_SKIP_NEXT, - GET_UNWRAP, - STRING_EXTEND_CHARS, - ITER_CLONED_COLLECT) + lint_array!( + OPTION_UNWRAP_USED, + RESULT_UNWRAP_USED, + SHOULD_IMPLEMENT_TRAIT, + WRONG_SELF_CONVENTION, + WRONG_PUB_SELF_CONVENTION, + OK_EXPECT, + OPTION_MAP_UNWRAP_OR, + OPTION_MAP_UNWRAP_OR_ELSE, + OR_FUN_CALL, + CHARS_NEXT_CMP, + CLONE_ON_COPY, + CLONE_DOUBLE_REF, + NEW_RET_NO_SELF, + SINGLE_CHAR_PATTERN, + SEARCH_IS_SOME, + TEMPORARY_CSTRING_AS_PTR, + FILTER_NEXT, + FILTER_MAP, + ITER_NTH, + ITER_SKIP_NEXT, + GET_UNWRAP, + STRING_EXTEND_CHARS, + ITER_CLONED_COLLECT + ) } } @@ -706,7 +711,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: self_expr: &hir::Expr, arg: &hir::Expr, or_has_args: bool, - span: Span + span: Span, ) -> bool { if or_has_args { return false; @@ -718,20 +723,22 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: if ["default", "new"].contains(&path) { let arg_ty = cx.tables.expr_ty(arg); - let default_trait_id = if let Some(default_trait_id) = - get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { - default_trait_id - } else { - return false; - }; + let default_trait_id = + if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { + default_trait_id + } else { + return false; + }; if implements_trait(cx, arg_ty, default_trait_id, &[]) { - span_lint_and_sugg(cx, - OR_FUN_CALL, - span, - &format!("use of `{}` followed by a call to `{}`", name, path), - "try this", - format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); + span_lint_and_sugg( + cx, + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a call to `{}`", name, path), + "try this", + format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_")), + ); return true; } } @@ -749,7 +756,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: self_expr: &hir::Expr, arg: &hir::Expr, or_has_args: bool, - span: Span + span: Span, ) { // don't lint for constant values // FIXME: can we `expect` here instead of match? @@ -765,15 +772,18 @@ 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")]; + &[ + (&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.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; @@ -789,12 +799,14 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: (false, true) => snippet(cx, fun_span, ".."), }; - span_lint_and_sugg(cx, - OR_FUN_CALL, - span, - &format!("use of `{}` followed by a function call", name), - "try this", - format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); + span_lint_and_sugg( + cx, + OR_FUN_CALL, + span, + &format!("use of `{}` followed by a function call", name), + "try this", + format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg), + ); } if args.len() == 2 { @@ -818,32 +830,30 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t let ty = cx.tables.expr_ty(expr); if let ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) = arg_ty.sty { if let ty::TyRef(..) = inner.sty { - span_lint_and_then(cx, - CLONE_DOUBLE_REF, - expr.span, - "using `clone` on a double-reference; \ + span_lint_and_then( + cx, + CLONE_DOUBLE_REF, + expr.span, + "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| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { + db.span_suggestion(expr.span, "try dereferencing it", format!("({}).clone()", snip.deref())); + }, + ); return; // don't report clone_on_copy } } if is_copy(cx, ty) { - span_lint_and_then(cx, - CLONE_ON_COPY, - expr.span, - "using `clone` on a `Copy` type", - |db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { - if let ty::TyRef(..) = cx.tables.expr_ty(arg).sty { - db.span_suggestion(expr.span, "try dereferencing it", format!("{}", snip.deref())); - } else { - db.span_suggestion(expr.span, "try removing the `clone` call", format!("{}", snip)); - } - }); + span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| { + if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { + if let ty::TyRef(..) = cx.tables.expr_ty(arg).sty { + db.span_suggestion(expr.span, "try dereferencing it", format!("{}", snip.deref())); + } else { + db.span_suggestion(expr.span, "try removing the `clone` call", format!("{}", snip)); + } + } + }); } } @@ -860,15 +870,19 @@ fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { return; }; - span_lint_and_sugg(cx, - STRING_EXTEND_CHARS, - expr.span, - "calling `.extend(_.chars())`", - "try this", - format!("{}.push_str({}{})", - snippet(cx, args[0].span, "_"), - ref_str, - snippet(cx, target.span, "_"))); + span_lint_and_sugg( + cx, + STRING_EXTEND_CHARS, + expr.span, + "calling `.extend(_.chars())`", + "try this", + format!( + "{}.push_str({}{})", + snippet(cx, args[0].span, "_"), + ref_str, + snippet(cx, target.span, "_") + ), + ); } } @@ -898,12 +912,15 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) { if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) && - derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() { - span_lint(cx, - ITER_CLONED_COLLECT, - expr.span, - "called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable"); + derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() + { + span_lint( + cx, + ITER_CLONED_COLLECT, + expr.span, + "called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ + more readable", + ); } } @@ -919,12 +936,16 @@ fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is 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) { @@ -947,26 +968,34 @@ 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_sugg(cx, - GET_UNWRAP, - expr.span, - &format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", - mut_str, - caller_type), - "try this", - format!("{}{}[{}]", - borrow_str, - snippet(cx, get_args[0].span, "_"), - snippet(cx, get_args[1].span, "_"))); + span_lint_and_sugg( + cx, + GET_UNWRAP, + expr.span, + &format!( + "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", + mut_str, + caller_type + ), + "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) { // 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)`", + ); } } @@ -1017,14 +1046,18 @@ fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &[hir::Expr]) { }; if let Some((lint, kind, none_value)) = mess { - span_lint(cx, - lint, - expr.span, - &format!("used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ + span_lint( + cx, + lint, + expr.span, + &format!( + "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ using expect() to provide a better panic \ message", - kind, - none_value)); + kind, + none_value + ), + ); } } @@ -1035,10 +1068,12 @@ fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &[hir::Expr]) { let result_type = cx.tables.expr_ty(&ok_args[0]); if let Some(error_type) = get_error_type(cx, result_type) { if has_debug_impl(error_type, cx) { - span_lint(cx, - OK_EXPECT, - expr.span, - "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`"); + span_lint( + cx, + OK_EXPECT, + expr.span, + "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`", + ); } } } @@ -1059,14 +1094,18 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr] let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.ctxt == unwrap_args[1].span.ctxt; if same_span && !multiline { - span_note_and_lint(cx, - OPTION_MAP_UNWRAP_OR, - expr.span, - msg, - expr.span, - &format!("replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", - map_snippet, - unwrap_snippet)); + span_note_and_lint( + cx, + OPTION_MAP_UNWRAP_OR, + expr.span, + msg, + expr.span, + &format!( + "replace `map({0}).unwrap_or({1})` with `map_or({1}, {0})`", + map_snippet, + unwrap_snippet + ), + ); } else if same_span && multiline { span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg); }; @@ -1088,14 +1127,18 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &[hir:: let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.ctxt == unwrap_args[1].span.ctxt; if same_span && !multiline { - span_note_and_lint(cx, - OPTION_MAP_UNWRAP_OR_ELSE, - expr.span, - msg, - expr.span, - &format!("replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", - map_snippet, - unwrap_snippet)); + span_note_and_lint( + cx, + OPTION_MAP_UNWRAP_OR_ELSE, + expr.span, + msg, + expr.span, + &format!( + "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", + map_snippet, + unwrap_snippet + ), + ); } else if same_span && multiline { span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg); }; @@ -1111,12 +1154,14 @@ fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &[hir::Expr let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { // add note if not multi-line - span_note_and_lint(cx, - FILTER_NEXT, - expr.span, - msg, - expr.span, - &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet)); + span_note_and_lint( + cx, + FILTER_NEXT, + expr.span, + msg, + expr.span, + &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet), + ); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); } @@ -1171,22 +1216,26 @@ fn lint_search_is_some( expr: &hir::Expr, search_method: &str, search_args: &[hir::Expr], - is_some_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 \ + let msg = format!( + "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ expressed by calling `any()`.", - search_method); + search_method + ); let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // add note if not multi-line - span_note_and_lint(cx, - SEARCH_IS_SOME, - expr.span, - &msg, - expr.span, - &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet)); + span_note_and_lint( + cx, + SEARCH_IS_SOME, + expr.span, + &msg, + expr.span, + &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet), + ); } else { span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); } @@ -1233,11 +1282,13 @@ fn lint_single_char_pattern(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) if let Ok(ConstVal::Str(r)) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) { if r.len() == 1 { let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); - span_lint_and_then(cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - |db| { db.span_suggestion(expr.span, "try using a char instead", hint); }); + span_lint_and_then( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + |db| { db.span_suggestion(expr.span, "try using a char instead", hint); }, + ); } } } @@ -1349,13 +1400,17 @@ impl SelfKind { arg: &hir::Arg, self_ty: &hir::Ty, allow_value_for_ref: bool, - generics: &hir::Generics + generics: &hir::Generics, ) -> bool { - // Self types in the HIR are desugared to explicit self types. So it will always be `self: + // Self types in the HIR are desugared to explicit self types. So it will + // always be `self: // SomeType`, - // where SomeType can be `Self` or an explicit impl self type (e.g. `Foo` if the impl is on `Foo`) - // Thus, we only need to test equality against the impl self type or if it is an explicit - // `Self`. Furthermore, the only possible types for `self: ` are `&Self`, `Self`, `&mut Self`, + // where SomeType can be `Self` or an explicit impl self type (e.g. `Foo` if + // the impl is on `Foo`) + // Thus, we only need to test equality against the impl self type or if it is + // an explicit + // `Self`. Furthermore, the only possible types for `self: ` are `&Self`, + // `Self`, `&mut Self`, // and `Box<Self>`, including the equivalent types with `Foo`. let is_actually_self = |ty| is_self_ty(ty) || ty == self_ty; @@ -1404,18 +1459,22 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener single_segment_ty(ty).map_or(false, |seg| { generics.ty_params.iter().any(|param| { param.name == seg.name && - param.bounds.iter().any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { - let path = &ptr.trait_ref.path; - match_path_old(path, name) && - path.segments.last().map_or(false, |s| if let hir::PathParameters::AngleBracketedParameters(ref data) = - s.parameters { - data.types.len() == 1 && (is_self_ty(&data.types[0]) || is_ty(&*data.types[0], self_ty)) - } else { - false + param.bounds.iter().any(|bound| { + if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { + let path = &ptr.trait_ref.path; + match_path_old(path, name) && + path.segments.last().map_or(false, |s| { + if let hir::PathParameters::AngleBracketedParameters(ref data) = s.parameters { + data.types.len() == 1 && + (is_self_ty(&data.types[0]) || is_ty(&*data.types[0], self_ty)) + } else { + false + } + }) + } else { + false + } }) - } else { - false - }) }) }) } @@ -1424,7 +1483,9 @@ fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool { match (&ty.node, &self_ty.node) { (&hir::TyPath(hir::QPath::Resolved(_, ref ty_path)), &hir::TyPath(hir::QPath::Resolved(_, ref self_ty_path))) => { - ty_path.segments.iter().map(|seg| seg.name).eq(self_ty_path.segments.iter().map(|seg| seg.name)) + ty_path.segments.iter().map(|seg| seg.name).eq( + self_ty_path.segments.iter().map(|seg| seg.name), + ) }, _ => false, } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 70f25e7dff0..67b0b1e167d 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -14,7 +14,8 @@ use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integ use utils::sugg::Sugg; use syntax::ast::{LitKind, CRATE_NODE_ID, FloatTy}; -/// **What it does:** Checks for function arguments and let bindings denoted as `ref`. +/// **What it does:** Checks for function arguments and let bindings denoted as +/// `ref`. /// /// **Why is this bad?** The `ref` declaration makes the function take an owned /// value, but turns the argument into a reference (which means that the value @@ -118,7 +119,8 @@ declare_lint! { /// **What it does:** Checks for patterns in the form `name @ _`. /// -/// **Why is this bad?** It's almost always more readable to just use direct bindings. +/// **Why is this bad?** It's almost always more readable to just use direct +/// bindings. /// /// **Known problems:** None. /// @@ -135,7 +137,8 @@ declare_lint! { "using `name @ _` in a pattern" } -/// **What it does:** Checks for the use of bindings with a single leading underscore. +/// **What it does:** Checks for the use of bindings with a single leading +/// underscore. /// /// **Why is this bad?** A single leading underscore is usually used to indicate /// that a binding will not be used. Using such a binding breaks this @@ -147,7 +150,8 @@ declare_lint! { /// **Example:** /// ```rust /// let _x = 0; -/// let y = _x + 1; // Here we are using `_x`, even though it has a leading underscore. +/// let y = _x + 1; // Here we are using `_x`, even though it has a leading +/// underscore. /// // We should rename `_x` to `x` /// ``` declare_lint! { @@ -156,11 +160,14 @@ declare_lint! { "using a binding which is prefixed with an underscore" } -/// **What it does:** Checks for the use of short circuit boolean conditions as a +/// **What it does:** Checks for the use of short circuit boolean conditions as +/// a /// statement. /// -/// **Why is this bad?** Using a short circuit boolean condition as a statement may -/// hide the fact that the second part is executed or not depending on the outcome of +/// **Why is this bad?** Using a short circuit boolean condition as a statement +/// may +/// hide the fact that the second part is executed or not depending on the +/// outcome of /// the first part. /// /// **Known problems:** None. @@ -198,15 +205,17 @@ 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, - USED_UNDERSCORE_BINDING, - SHORT_CIRCUIT_STATEMENT, - ZERO_PTR) + lint_array!( + TOPLEVEL_REF_ARG, + CMP_NAN, + FLOAT_CMP, + CMP_OWNED, + MODULO_ONE, + REDUNDANT_PATTERN, + USED_UNDERSCORE_BINDING, + SHORT_CIRCUIT_STATEMENT, + ZERO_PTR + ) } } @@ -218,7 +227,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { decl: &'tcx FnDecl, body: &'tcx Body, _: Span, - _: NodeId + _: NodeId, ) { if let FnKind::Closure(_) = k { // Does not apply to closures @@ -228,11 +237,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { match arg.pat.node { PatKind::Binding(BindingAnnotation::Ref, _, _, _) | PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => { - span_lint(cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. Consider using a reference type \ - instead."); + span_lint( + cx, + TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. Consider using a reference type \ + instead.", + ); }, _ => {}, } @@ -316,7 +327,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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; } } @@ -324,9 +336,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { 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_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) { @@ -347,7 +361,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { binding != "_result" && // FIXME: #944 is_used(cx, expr) && // don't lint if the declaration is in a macro - non_macro_local(cx, &cx.tables.qpath_def(qpath, expr.id)) { + non_macro_local(cx, &cx.tables.qpath_def(qpath, expr.id)) + { Some(binding) } else { None @@ -364,22 +379,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { _ => None, }; if let Some(binding) = binding { - span_lint(cx, - USED_UNDERSCORE_BINDING, - expr.span, - &format!("used binding `{}` which is prefixed with an underscore. A leading \ + span_lint( + cx, + 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)); + binding + ), + ); } } 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)); + span_lint( + cx, + REDUNDANT_PATTERN, + pat.span, + &format!("the `{} @ _` pattern can be written as just `{}`", ident.node, ident.node), + ); } } } @@ -388,10 +409,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) { if !in_constant(cx, expr.id) { path.segments.last().map(|seg| if seg.name == "NAN" { - span_lint(cx, - CMP_NAN, - expr.span, - "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead"); + span_lint( + cx, + CMP_NAN, + expr.span, + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead", + ); }); } } @@ -421,7 +444,7 @@ fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { }; 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(neg_infinity) == Ok(Ordering::Equal) }, FloatTy::F64 => { let zero = ConstFloat { @@ -440,7 +463,7 @@ fn is_allowed(cx: &LateContext, expr: &Expr) -> bool { }; 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(neg_infinity) == Ok(Ordering::Equal) }, } } else { @@ -490,37 +513,43 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) { .builtin_deref(true, ty::LvaluePreference::NoPreference) .map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty])) // arg impls PartialEq<other> - && !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty]) { + && !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty]) + { return; } - span_lint_and_then(cx, - CMP_OWNED, - expr.span, - "this creates an owned instance just for comparison", - |db| { - // this is as good as our recursion check can get, we can't prove that the current function is - // called by - // PartialEq::eq, but we can at least ensure that this code is not part of it - let parent_fn = cx.tcx.hir.get_parent(expr.id); - let parent_impl = cx.tcx.hir.get_parent(parent_fn); - if parent_impl != CRATE_NODE_ID { - if let map::NodeItem(item) = cx.tcx.hir.get(parent_impl) { - if let ItemImpl(.., Some(ref trait_ref), _, _) = item.node { - if trait_ref.path.def.def_id() == partial_eq_trait_id { - // we are implementing PartialEq, don't suggest not doing `to_owned`, otherwise we go into - // recursion - db.span_label(expr.span, "try calling implementing the comparison without allocating"); - return; + span_lint_and_then( + cx, + CMP_OWNED, + expr.span, + "this creates an owned instance just for comparison", + |db| { + // this is as good as our recursion check can get, we can't prove that the + // current function is + // called by + // PartialEq::eq, but we can at least ensure that this code is not part of it + let parent_fn = cx.tcx.hir.get_parent(expr.id); + let parent_impl = cx.tcx.hir.get_parent(parent_fn); + if parent_impl != CRATE_NODE_ID { + if let map::NodeItem(item) = cx.tcx.hir.get(parent_impl) { + if let ItemImpl(.., Some(ref trait_ref), _, _) = item.node { + if trait_ref.path.def.def_id() == partial_eq_trait_id { + // we are implementing PartialEq, don't suggest not doing `to_owned`, otherwise + // we go into + // recursion + db.span_label(expr.span, "try calling implementing the comparison without allocating"); + return; + } } } } - } - db.span_suggestion(expr.span, "try", snip.to_string()); - }); + db.span_suggestion(expr.span, "try", snip.to_string()); + }, + ); } -/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea +/// Heuristic to see if an expression is used. Should be compatible with +/// `unused_variables`'s idea /// of what it means for an expression to be "used". fn is_used(cx: &LateContext, expr: &Expr) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { @@ -534,10 +563,14 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { } } -/// Test whether an expression is in a macro expansion (e.g. something generated by +/// Test whether an expression is in a macro expansion (e.g. something +/// generated by /// `#[derive(...)`] or the like). fn in_attributes_expansion(expr: &Expr) -> bool { - expr.span.ctxt.outer().expn_info().map_or(false, |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_))) + expr.span.ctxt.outer().expn_info().map_or( + false, + |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_)), + ) } /// Test whether `def` is a variable defined outside a macro. @@ -545,10 +578,9 @@ fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool { match *def { def::Def::Local(def_id) | def::Def::Upvar(def_id, _, _) => { - let id = cx.tcx - .hir - .as_local_node_id(def_id) - .expect("local variables should be found in the same crate"); + let id = cx.tcx.hir.as_local_node_id(def_id).expect( + "local variables should be found in the same crate", + ); !in_macro(cx.tcx.hir.span(id)) }, _ => false, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index c63dff52ae9..52a97024e44 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -40,9 +40,11 @@ declare_lint! { "function arguments having names which only differ by an underscore" } -/// **What it does:** Detects closures called in the same expression where they are defined. +/// **What it does:** Detects closures called in the same expression where they +/// are defined. /// -/// **Why is this bad?** It is unnecessarily adding to the expression's complexity. +/// **Why is this bad?** It is unnecessarily adding to the expression's +/// complexity. /// /// **Known problems:** None. /// @@ -73,7 +75,8 @@ declare_lint! { "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++" } -/// **What it does:** Warns on hexadecimal literals with mixed-case letter digits. +/// **What it does:** Warns on hexadecimal literals with mixed-case letter +/// digits. /// /// **Why is this bad?** It looks confusing. /// @@ -89,7 +92,8 @@ declare_lint! { "hex literals whose letter digits are not consistently upper- or lowercased" } -/// **What it does:** Warns if literal suffixes are not separated by an underscore. +/// **What it does:** Warns if literal suffixes are not separated by an +/// underscore. /// /// **Why is this bad?** It is much less readable. /// @@ -107,8 +111,10 @@ declare_lint! { /// **What it does:** Warns if an integral constant literal starts with `0`. /// -/// **Why is this bad?** In some languages (including the infamous C language and most of its -/// family), this marks an octal constant. In Rust however, this is a decimal constant. This could +/// **Why is this bad?** In some languages (including the infamous C language +/// and most of its +/// family), this marks an octal constant. In Rust however, this is a decimal +/// constant. This could /// be confusing for both the writer and a reader of the constant. /// /// **Known problems:** None. @@ -167,14 +173,16 @@ 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 + ) } } @@ -183,10 +191,12 @@ impl EarlyLintPass for MiscEarly { for ty in &gen.ty_params { let name = ty.ident.name.as_str(); if constants::BUILTIN_TYPES.contains(&&*name) { - span_lint(cx, - BUILTIN_TYPE_SHADOW, - ty.span, - &format!("This generic shadows the built-in type `{}`", name)); + span_lint( + cx, + BUILTIN_TYPE_SHADOW, + ty.span, + &format!("This generic shadows the built-in type `{}`", name), + ); } } } @@ -194,7 +204,11 @@ impl EarlyLintPass for MiscEarly { fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { let mut wilds = 0; - let type_name = npat.segments.last().expect("A path must have at least one segment").identifier.name; + let type_name = npat.segments + .last() + .expect("A path must have at least one segment") + .identifier + .name; for field in pfields { if field.node.pat.node == PatKind::Wild { @@ -202,11 +216,13 @@ impl EarlyLintPass for MiscEarly { } } if !pfields.is_empty() && wilds == pfields.len() { - span_help_and_lint(cx, - UNNEEDED_FIELD_PATTERN, - pat.span, - "All the struct fields are matched to a wildcard pattern, consider using `..`.", - &format!("Try with `{} {{ .. }}` instead", type_name)); + span_help_and_lint( + cx, + UNNEEDED_FIELD_PATTERN, + pat.span, + "All the struct fields are matched to a wildcard pattern, consider using `..`.", + &format!("Try with `{} {{ .. }}` instead", type_name), + ); return; } if wilds > 0 { @@ -223,19 +239,21 @@ impl EarlyLintPass for MiscEarly { if field.node.pat.node == PatKind::Wild { wilds -= 1; if wilds > 0 { - span_lint(cx, - UNNEEDED_FIELD_PATTERN, - field.span, - "You matched a field with a wildcard pattern. Consider using `..` instead"); + span_lint( + cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` instead", + ); } else { - span_help_and_lint(cx, - UNNEEDED_FIELD_PATTERN, - field.span, - "You matched a field with a wildcard pattern. Consider using `..` \ + span_help_and_lint( + cx, + UNNEEDED_FIELD_PATTERN, + field.span, + "You matched a field with a wildcard pattern. Consider using `..` \ instead", - &format!("Try with `{} {{ {}, .. }}`", - type_name, - normal[..].join(", "))); + &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")), + ); } } } @@ -252,12 +270,16 @@ impl EarlyLintPass for MiscEarly { if arg_name.starts_with('_') { if let Some(correspondence) = registered_names.get(&arg_name[1..]) { - span_lint(cx, - DUPLICATE_UNDERSCORE_ARGUMENT, - *correspondence, - &format!("`{}` already exists, having another argument having almost the same \ + span_lint( + cx, + DUPLICATE_UNDERSCORE_ARGUMENT, + *correspondence, + &format!( + "`{}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult", - arg_name[1..].to_owned()));; + arg_name[1..].to_owned() + ), + );; } } else { registered_names.insert(arg_name, arg.pat.span); @@ -287,10 +309,12 @@ impl EarlyLintPass for MiscEarly { }, ExprKind::Unary(UnOp::Neg, ref inner) => { if let ExprKind::Unary(UnOp::Neg, _) = inner.node { - span_lint(cx, - DOUBLE_NEG, - expr.span, - "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op"); + span_lint( + cx, + DOUBLE_NEG, + expr.span, + "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + ); } }, ExprKind::Lit(ref lit) => self.check_lit(cx, lit), diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index c38402ad29c..17b3ad4d9e2 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -11,12 +11,16 @@ // except according to those terms. // -// Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s +// 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 // @@ -28,10 +32,13 @@ use syntax::attr; use syntax::codemap::Span; use utils::in_macro; -/// **What it does:** Warns if there is missing doc for any documentable item (public or private). +/// **What it does:** Warns if there is missing doc for any documentable item +/// (public or private). /// -/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` allowed-by-default lint for -/// public members, but has no way to enforce documentation of private items. This lint fixes that. +/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS` +/// allowed-by-default lint for +/// public members, but has no way to enforce documentation of private items. +/// This lint fixes that. /// /// **Known problems:** None. declare_lint! { @@ -58,7 +65,9 @@ impl MissingDoc { } fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") + *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) { @@ -77,11 +86,15 @@ impl MissingDoc { return; } - let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name().map_or(false, |n| n == "doc")); + let has_doc = attrs.iter().any(|a| { + a.is_value_str() && a.name().map_or(false, |n| n == "doc") + }); if !has_doc { - cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, - sp, - &format!("missing documentation for {}", desc)); + cx.span_lint( + MISSING_DOCS_IN_PRIVATE_ITEMS, + sp, + &format!("missing documentation for {}", desc), + ); } } } @@ -95,13 +108,13 @@ impl LintPass for MissingDoc { 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"), - } - }); + attrs.iter().any(|attr| { + attr.check_name("doc") && + match attr.meta_item_list() { + None => false, + Some(l) => attr::list_contains_name(&l[..], "hidden"), + } + }); self.doc_hidden_stack.push(doc_hidden); } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index fc3107c3068..e8133050475 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -22,7 +22,7 @@ declare_lint! { "usage of double-mut refs, e.g. `&mut &mut ...`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct MutMut; impl LintPass for MutMut { @@ -64,26 +64,37 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> 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 ty::TyRef(_, ty::TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tables.expr_ty(e).sty { - span_lint(self.cx, - MUT_MUT, - expr.span, - "this expression mutably borrows a mutable reference. Consider reborrowing"); + span_lint( + self.cx, + MUT_MUT, + expr.span, + "this expression mutably borrows a mutable reference. Consider reborrowing", + ); } } } 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 { + 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", + ); } } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 0e2c0412702..0c0c8f4061f 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -24,7 +24,7 @@ declare_lint! { } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct UnnecessaryMutPassed; impl LintPass for UnnecessaryMutPassed { @@ -38,10 +38,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { match e.node { ExprCall(ref fn_expr, ref arguments) => { if let ExprPath(ref path) = fn_expr.node { - check_arguments(cx, - arguments, - cx.tables.expr_ty(fn_expr), - &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))); + check_arguments( + cx, + arguments, + cx.tables.expr_ty(fn_expr), + &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)), + ); } }, ExprMethodCall(ref path, _, ref arguments) => { @@ -64,10 +66,12 @@ fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], typ ty::TyRef(_, ty::TypeAndMut { mutbl: MutImmutable, .. }) | ty::TyRawPtr(ty::TypeAndMut { mutbl: MutImmutable, .. }) => { if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint(cx, - UNNECESSARY_MUT_PASSED, - argument.span, - &format!("The function/method `{}` doesn't need a mutable reference", name)); + span_lint( + cx, + UNNECESSARY_MUT_PASSED, + 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 085067935a0..25a7118ceda 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -28,9 +28,11 @@ declare_lint! { "using a mutex where an atomic value could be used instead" } -/// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral type. +/// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral +/// type. /// -/// **Why is this bad?** Using a mutex just to make access to a plain integer sequential is +/// **Why is this bad?** Using a mutex just to make access to a plain integer +/// sequential is /// shooting flies with cannons. `std::atomic::usize` is leaner and faster. /// /// **Known problems:** This lint cannot detect if the mutex is actually used @@ -61,9 +63,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic { if match_type(cx, ty, &paths::MUTEX) { let mutex_param = subst.type_at(0); if let Some(atomic_name) = get_atomic_name(mutex_param) { - let msg = format!("Consider using an {} instead of a Mutex here. If you just want the locking \ + let msg = format!( + "Consider using an {} instead of a Mutex here. If you just want the locking \ behaviour and not the internal type, consider using Mutex<()>.", - atomic_name); + atomic_name + ); match mutex_param.sty { ty::TyUint(t) if t != ast::UintTy::Us => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), ty::TyInt(t) if t != ast::IntTy::Is => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 4456547c777..52f0df12bcd 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -9,7 +9,8 @@ use syntax::codemap::Spanned; use utils::{span_lint, span_lint_and_sugg, snippet}; use utils::sugg::Sugg; -/// **What it does:** Checks for expressions of the form `if c { true } else { false }` +/// **What it does:** Checks for expressions of the form `if c { true } else { +/// false }` /// (or vice versa) and suggest using the condition directly. /// /// **Why is this bad?** Redundant code. @@ -47,7 +48,7 @@ declare_lint! { "comparing a variable to a boolean, e.g. `if x == true`" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NeedlessBool; impl LintPass for NeedlessBool { @@ -70,28 +71,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { snip.to_string() }; - span_lint_and_sugg(cx, - NEEDLESS_BOOL, - e.span, - "this if-then-else expression returns a bool literal", - "you can reduce it to", - hint); + span_lint_and_sugg( + cx, + NEEDLESS_BOOL, + e.span, + "this if-then-else expression returns a bool literal", + "you can reduce it to", + hint, + ); }; if let ExprBlock(ref then_block) = then_block.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => { - span_lint(cx, - NEEDLESS_BOOL, - e.span, - "this if-then-else expression will always return true"); + span_lint( + cx, + 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"); + 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), @@ -106,7 +113,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { } } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct BoolComparison; impl LintPass for BoolComparison { @@ -122,39 +129,47 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => { let hint = snippet(cx, right_side.span, "..").into_owned(); - span_lint_and_sugg(cx, - BOOL_COMPARISON, - e.span, - "equality checks against true are unnecessary", - "try simplifying it as shown", - hint); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + e.span, + "equality checks against true are unnecessary", + "try simplifying it as shown", + hint, + ); }, (Other, Bool(true)) => { let hint = snippet(cx, left_side.span, "..").into_owned(); - span_lint_and_sugg(cx, - BOOL_COMPARISON, - e.span, - "equality checks against true are unnecessary", - "try simplifying it as shown", - hint); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + e.span, + "equality checks against true are unnecessary", + "try simplifying it as shown", + hint, + ); }, (Bool(false), Other) => { let hint = Sugg::hir(cx, right_side, ".."); - span_lint_and_sugg(cx, - BOOL_COMPARISON, - e.span, - "equality checks against false can be replaced by a negation", - "try simplifying it as shown", - (!hint).to_string()); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + e.span, + "equality checks against false can be replaced by a negation", + "try simplifying it as shown", + (!hint).to_string(), + ); }, (Other, Bool(false)) => { let hint = Sugg::hir(cx, left_side, ".."); - span_lint_and_sugg(cx, - BOOL_COMPARISON, - e.span, - "equality checks against false can be replaced by a negation", - "try simplifying it as shown", - (!hint).to_string()); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + e.span, + "equality checks against false can be replaced by a negation", + "try simplifying it as shown", + (!hint).to_string(), + ); }, _ => (), } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 385fcc86adb..b331d6910a3 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -26,7 +26,7 @@ declare_lint! { "taking a reference that is going to be automatically dereferenced" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NeedlessBorrow; impl LintPass for NeedlessBorrow { diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index bfe52a41214..6f81c811414 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -9,7 +9,8 @@ use utils::{span_lint, in_macro}; /// **What it does:** Checks for useless borrowed references. /// -/// **Why is this bad?** It is completely useless and make the code look more complex than it +/// **Why is this bad?** It is completely useless and make the code look more +/// complex than it /// actually is. /// /// **Known problems:** None. @@ -19,7 +20,8 @@ use utils::{span_lint, in_macro}; /// let mut v = Vec::<String>::new(); /// let _ = v.iter_mut().filter(|&ref a| a.is_empty()); /// ``` -/// This clojure takes a reference on something that has been matched as a reference and +/// This clojure takes a reference on something that has been matched as a +/// reference and /// de-referenced. /// As such, it could just be |a| a.is_empty() declare_lint! { diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 076bf82b687..692fa19f3ba 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -99,7 +99,7 @@ declare_lint! { "`continue` statements that can be replaced by a rearrangement of code" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NeedlessContinue; impl LintPass for NeedlessContinue { @@ -116,59 +116,60 @@ impl EarlyLintPass for NeedlessContinue { } } -/* This lint has to mainly deal with two cases of needless continue statements. - * - * Case 1 [Continue inside else block]: - * - * loop { - * // region A - * if cond { - * // region B - * } else { - * continue; - * } - * // region C - * } - * - * This code can better be written as follows: - * - * loop { - * // region A - * if cond { - * // region B - * // region C - * } - * } - * - * Case 2 [Continue inside then block]: - * - * loop { - * // region A - * if cond { - * continue; - * // potentially more code here. - * } else { - * // region B - * } - * // region C - * } - * - * - * This snippet can be refactored to: - * - * loop { - * // region A - * if !cond { - * // region B - * // region C - * } - * } - * */ +/* This lint has to mainly deal with two cases of needless continue + * statements. */ +// Case 1 [Continue inside else block]: +// +// loop { +// // region A +// if cond { +// // region B +// } else { +// continue; +// } +// // region C +// } +// +// This code can better be written as follows: +// +// loop { +// // region A +// if cond { +// // region B +// // region C +// } +// } +// +// Case 2 [Continue inside then block]: +// +// loop { +// // region A +// if cond { +// continue; +// // potentially more code here. +// } else { +// // region B +// } +// // region C +// } +// +// +// This snippet can be refactored to: +// +// loop { +// // region A +// if !cond { +// // region B +// // region C +// } +// } +// /// Given an expression, returns true if either of the following is true /// /// - The expression is a `continue` node. -/// - The expression node is a block with the first statement being a `continue`. +/// - The expression node is a block with the first statement being a +/// `continue`. /// fn needless_continue_in_else(else_expr: &ast::Expr) -> bool { match else_expr.node { @@ -195,7 +196,8 @@ fn is_first_block_stmt_continue(block: &ast::Block) -> bool { /// If `expr` is a loop expression (while/while let/for/loop), calls `func` with /// the AST object representing the loop block of `expr`. fn with_loop_block<F>(expr: &ast::Expr, mut func: F) - where F: FnMut(&ast::Block) +where + F: FnMut(&ast::Block), { match expr.node { ast::ExprKind::While(_, ref loop_block, _) | @@ -206,7 +208,8 @@ fn with_loop_block<F>(expr: &ast::Expr, mut func: F) } } -/// If `stmt` is an if expression node with an `else` branch, calls func with the +/// If `stmt` is an if expression node with an `else` branch, calls func with +/// the /// following: /// /// - The `if` expression itself, @@ -215,7 +218,8 @@ fn with_loop_block<F>(expr: &ast::Expr, mut func: F) /// - The `else` expression. /// fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F) - where F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr) +where + F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr), { match stmt.node { ast::StmtKind::Semi(ref e) | @@ -271,10 +275,18 @@ fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: L // expr is the expression which the lint warning message refers to. let (snip, message, expr) = match typ { LintType::ContinueInsideElseBlock => { - (suggestion_snippet_for_continue_inside_else(ctx, data, header), MSG_REDUNDANT_ELSE_BLOCK, data.else_expr) + ( + suggestion_snippet_for_continue_inside_else(ctx, data, header), + MSG_REDUNDANT_ELSE_BLOCK, + data.else_expr, + ) }, LintType::ContinueInsideThenBlock => { - (suggestion_snippet_for_continue_inside_if(ctx, data, header), MSG_ELSE_BLOCK_NOT_NEEDED, data.if_expr) + ( + suggestion_snippet_for_continue_inside_if(ctx, data, header), + MSG_ELSE_BLOCK_NOT_NEEDED, + data.if_expr, + ) }, }; span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip); @@ -407,7 +419,8 @@ pub fn erode_from_front(s: &str) -> String { } /// If `s` contains the code for a block, delimited by braces, this function -/// tries to get the contents of the block. If there is no closing brace present, +/// tries to get the contents of the block. If there is no closing brace +/// present, /// an empty string is returned. pub fn erode_block(s: &str) -> String { erode_from_back(&erode_from_front(s)) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 0740ca483f7..e4efaf495a8 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -13,10 +13,12 @@ use utils::{in_macro, is_self, is_copy, implements_trait, get_trait_def_id, matc multispan_sugg, paths}; use std::collections::{HashSet, HashMap}; -/// **What it does:** Checks for functions taking arguments by value, but not consuming them in its +/// **What it does:** Checks for functions taking arguments by value, but not +/// consuming them in its /// body. /// -/// **Why is this bad?** Taking arguments by reference is more flexible and can sometimes avoid +/// **Why is this bad?** Taking arguments by reference is more flexible and can +/// sometimes avoid /// unnecessary allocations. /// /// **Known problems:** Hopefully none. @@ -53,7 +55,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { decl: &'tcx FnDecl, body: &'tcx Body, span: Span, - node_id: NodeId + node_id: NodeId, ) { if in_macro(span) { return; @@ -87,8 +89,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { .collect() }; - // Collect moved variables and spans which will need dereferencings from the function body. - let MovedVariablesCtxt { moved_vars, spans_need_deref, .. } = { + // Collect moved variables and spans which will need dereferencings from the + // function body. + let MovedVariablesCtxt { + moved_vars, + spans_need_deref, + .. + } = { let mut ctx = MovedVariablesCtxt::new(cx); let region_maps = &cx.tcx.region_maps(fn_def_id); euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_maps, cx.tables).consume_body(body); @@ -102,14 +109,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { // Determines whether `ty` implements `Borrow<U>` (U != ty) specifically. // This is needed due to the `Borrow<T> for T` blanket impl. - let implements_borrow_trait = preds.iter() + let implements_borrow_trait = preds + .iter() .filter_map(|pred| if let ty::Predicate::Trait(ref poly_trait_ref) = *pred { Some(poly_trait_ref.skip_binder()) } else { None }) .filter(|tpred| tpred.def_id() == borrow_trait && tpred.self_ty() == ty) - .any(|tpred| tpred.input_types().nth(1).expect("Borrow trait must have an parameter") != ty); + .any(|tpred| { + tpred.input_types().nth(1).expect( + "Borrow trait must have an parameter", + ) != ty + }); if_let_chain! {[ !is_self(arg), @@ -177,7 +189,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { struct MovedVariablesCtxt<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, moved_vars: HashSet<DefId>, - /// Spans which need to be prefixed with `*` for dereferencing the suggested additional + /// Spans which need to be prefixed with `*` for dereferencing the + /// suggested additional /// reference. spans_need_deref: HashMap<DefId, HashSet<Span>>, } diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index da6f635e34e..d6624411e2f 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -36,10 +36,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let ty = cx.tables.expr_ty(expr); if let ty::TyAdt(def, _) = ty.sty { if fields.len() == def.struct_variant().fields.len() { - span_lint(cx, - NEEDLESS_UPDATE, - base.span, - "struct update has no effect, all the fields in the struct have already been specified"); + span_lint( + cx, + NEEDLESS_UPDATE, + base.span, + "struct update has no effect, all the fields in the struct have already been specified", + ); } } } diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index e5644b606f5..c6bd91919f5 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -80,7 +80,7 @@ declare_lint! { "`fn new() -> Self` without `#[derive]`able `Default` implementation" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NewWithoutDefault; impl LintPass for NewWithoutDefault { @@ -97,7 +97,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { decl: &'tcx hir::FnDecl, _: &'tcx hir::Body, span: Span, - id: ast::NodeId + id: ast::NodeId, ) { if in_external_macro(cx, span) { return; @@ -109,13 +109,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { return; } if !sig.generics.ty_params.is_empty() { - // when the result of `new()` depends on a type parameter we should not require an + // when the result of `new()` depends on a type parameter we should not require + // an // impl of `Default` return; } if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) { - let self_ty = cx.tcx - .type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id))); + let self_ty = cx.tcx.type_of( + cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)), + ); if_let_chain!{[ same_tys(cx, self_ty, return_ty(cx, id)), let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index a88662356fb..c57df468f7c 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -62,10 +62,10 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { Expr_::ExprBox(ref inner) => has_no_effect(cx, inner), Expr_::ExprStruct(_, ref fields, ref base) => { fields.iter().all(|field| has_no_effect(cx, &field.expr)) && - match *base { - Some(ref base) => has_no_effect(cx, base), - None => true, - } + match *base { + Some(ref base) => has_no_effect(cx, base), + None => true, + } }, Expr_::ExprCall(ref callee, ref args) => { if let Expr_::ExprPath(ref qpath) = callee.node { @@ -83,11 +83,11 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { }, Expr_::ExprBlock(ref block) => { block.stmts.is_empty() && - if let Some(ref expr) = block.expr { - has_no_effect(cx, expr) - } else { - false - } + if let Some(ref expr) = block.expr { + has_no_effect(cx, expr) + } else { + false + } }, _ => false, } @@ -120,12 +120,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { return; } } - span_lint_and_sugg(cx, - UNNECESSARY_OPERATION, - stmt.span, - "statement can be reduced", - "replace it with", - snippet); + span_lint_and_sugg( + cx, + UNNECESSARY_OPERATION, + stmt.span, + "statement can be reduced", + "replace it with", + snippet, + ); } } } @@ -152,7 +154,14 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprBox(ref inner) => 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()) + Some( + fields + .iter() + .map(|f| &f.expr) + .chain(base) + .map(Deref::deref) + .collect(), + ) }, Expr_::ExprCall(ref callee, ref args) => { if let Expr_::ExprPath(ref qpath) = callee.node { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 6b97ffee6db..fa915e83aed 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -113,7 +113,13 @@ fn whitelisted(interned_name: &str, list: &[&str]) -> bool { return true; } // *_name - if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) { + if interned_name.chars().rev().zip(name.chars().rev()).all( + |(l, + r)| { + l == r + }, + ) + { return true; } } @@ -128,10 +134,12 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } self.0.single_char_names.push(c); if self.0.single_char_names.len() as u64 >= self.0.lint.single_char_binding_names_threshold { - span_lint(self.0.cx, - MANY_SINGLE_CHAR_NAMES, - span, - &format!("{}th binding whose name is just one char", self.0.single_char_names.len())); + span_lint( + self.0.cx, + MANY_SINGLE_CHAR_NAMES, + span, + &format!("{}th binding whose name is just one char", self.0.single_char_names.len()), + ); } } fn check_name(&mut self, span: Span, name: Name) { @@ -166,22 +174,41 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } else { let mut interned_chars = interned_name.chars(); let mut existing_chars = existing_name.interned.chars(); - let first_i = interned_chars.next().expect("we know we have at least one char"); - let first_e = existing_chars.next().expect("we know we have at least one char"); + let first_i = interned_chars.next().expect( + "we know we have at least one char", + ); + let first_e = existing_chars.next().expect( + "we know we have at least one char", + ); let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); if eq_or_numeric(first_i, first_e) { - let last_i = interned_chars.next_back().expect("we know we have at least two chars"); - let last_e = existing_chars.next_back().expect("we know we have at least two chars"); + let last_i = interned_chars.next_back().expect( + "we know we have at least two chars", + ); + let last_e = existing_chars.next_back().expect( + "we know we have at least two chars", + ); if eq_or_numeric(last_i, last_e) { - if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 { + if interned_chars + .zip(existing_chars) + .filter(|&(i, e)| !eq_or_numeric(i, e)) + .count() != 1 + { continue; } } else { - let second_last_i = interned_chars.next_back().expect("we know we have at least three chars"); - let second_last_e = existing_chars.next_back().expect("we know we have at least three chars"); + let second_last_i = interned_chars.next_back().expect( + "we know we have at least three chars", + ); + let second_last_e = existing_chars.next_back().expect( + "we know we have at least three chars", + ); if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + !interned_chars.zip(existing_chars).all(|(i, e)| { + eq_or_numeric(i, e) + }) + { // allowed similarity foo_x, foo_y // or too many chars differ (foo_x, boo_y) or (foox, booy) continue; @@ -189,10 +216,17 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); } } else { - let second_i = interned_chars.next().expect("we know we have at least two chars"); - let second_e = existing_chars.next().expect("we know we have at least two chars"); + let second_i = interned_chars.next().expect( + "we know we have at least two chars", + ); + let second_e = existing_chars.next().expect( + "we know we have at least two chars", + ); if !eq_or_numeric(second_i, second_e) || second_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) { + !interned_chars.zip(existing_chars).all(|(i, e)| { + eq_or_numeric(i, e) + }) + { // allowed similarity x_foo, y_foo // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) continue; @@ -200,20 +234,26 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { split_at = interned_name.chars().next().map(|c| c.len_utf8()); } } - span_lint_and_then(self.0.cx, - SIMILAR_NAMES, - span, - "binding's name is too similar to existing binding", - |diag| { - diag.span_note(existing_name.span, "existing binding defined here"); - if let Some(split) = split_at { - diag.span_help(span, - &format!("separate the discriminating character by an \ + span_lint_and_then( + self.0.cx, + SIMILAR_NAMES, + span, + "binding's name is too similar to existing binding", + |diag| { + diag.span_note(existing_name.span, "existing binding defined here"); + if let Some(split) = split_at { + 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; } self.0.names.push(ExistingName { @@ -241,7 +281,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { 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 + // add the pattern after the expression because the bindings aren't available + // yet in the init // expression SimilarNamesNameVisitor(self).visit_pat(&*local.pat); } diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index a831e9bd9b7..ee55ea882b0 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -4,7 +4,8 @@ use utils::{paths, method_chain_args, span_help_and_lint, match_type, snippet}; /// **What it does:*** Checks for unnecessary `ok()` in if let. /// -/// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match on `Ok(pat)` +/// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match +/// on `Ok(pat)` /// /// **Known problems:** None. /// diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 429d02d068b..e67c1f4d148 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -23,7 +23,7 @@ declare_lint! { } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct NonSensical; impl LintPass for NonSensical { @@ -109,16 +109,19 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], 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); - // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. + // This code is almost duplicated (oh, the irony), but I haven't found a way to + // unify it. for option in options { match *option { (OpenOption::Create, arg) => { if create { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"create\" is called more than once"); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"create\" is called more than once", + ); } else { create = true } @@ -126,10 +129,12 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span }, (OpenOption::Append, arg) => { if append { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"append\" is called more than once"); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"append\" is called more than once", + ); } else { append = true } @@ -137,10 +142,12 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span }, (OpenOption::Truncate, arg) => { if truncate { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"truncate\" is called more than once"); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"truncate\" is called more than once", + ); } else { truncate = true } @@ -148,10 +155,12 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span }, (OpenOption::Read, arg) => { if read { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"read\" is called more than once"); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"read\" is called more than once", + ); } else { read = true } @@ -159,10 +168,12 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span }, (OpenOption::Write, arg) => { if write { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "the method \"write\" is called more than once"); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "the method \"write\" is called more than once", + ); } else { write = true } @@ -175,9 +186,11 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\""); } if append && truncate && append_arg && truncate_arg { - span_lint(cx, - NONSENSICAL_OPEN_OPTIONS, - span, - "file opened with \"append\" and \"truncate\""); + span_lint( + cx, + NONSENSICAL_OPEN_OPTIONS, + span, + "file opened with \"append\" and \"truncate\"", + ); } } diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index e7b34136891..f5a6833b4b0 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -5,8 +5,10 @@ use utils::{span_lint_and_sugg, snippet}; /// **What it does:** Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: -/// * mixed usage of arithmetic and bit shifting/combining operators without parentheses -/// * a "negative" numeric literal (which is really a unary `-` followed by a numeric literal) +/// * mixed usage of arithmetic and bit shifting/combining operators without +/// parentheses +/// * a "negative" numeric literal (which is really a unary `-` followed by a +/// numeric literal) /// followed by a method call /// /// **Why is this bad?** Not everyone knows the precedence of those operators by @@ -24,7 +26,7 @@ declare_lint! { "operations where precedence may be unclear" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Precedence; impl LintPass for Precedence { @@ -37,12 +39,14 @@ impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { let span_sugg = |expr: &Expr, sugg| { - span_lint_and_sugg(cx, - PRECEDENCE, - expr.span, - "operator precedence can trip the unwary", - "consider parenthesizing your expression", - sugg); + span_lint_and_sugg( + cx, + PRECEDENCE, + expr.span, + "operator precedence can trip the unwary", + "consider parenthesizing your expression", + sugg, + ); }; if !is_bit_op(op) { @@ -50,24 +54,30 @@ impl EarlyLintPass for Precedence { } match (is_arith_expr(left), is_arith_expr(right)) { (true, true) => { - let sugg = format!("({}) {} ({})", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, "..")); + let sugg = format!( + "({}) {} ({})", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, "..") + ); span_sugg(expr, sugg); }, (true, false) => { - let sugg = format!("({}) {} {}", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, "..")); + let sugg = format!( + "({}) {} {}", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, "..") + ); span_sugg(expr, sugg); }, (false, true) => { - let sugg = format!("{} {} ({})", - snippet(cx, left.span, ".."), - op.to_string(), - snippet(cx, right.span, "..")); + let sugg = format!( + "{} {} ({})", + snippet(cx, left.span, ".."), + op.to_string(), + snippet(cx, right.span, "..") + ); span_sugg(expr, sugg); }, (false, false) => (), @@ -82,12 +92,14 @@ impl EarlyLintPass for Precedence { LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { - span_lint_and_sugg(cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!("-({})", snippet(cx, rhs.span, ".."))); + span_lint_and_sugg( + cx, + PRECEDENCE, + expr.span, + "unary minus has lower precedence than method call", + "consider adding parentheses to clarify your intent", + format!("-({})", snippet(cx, rhs.span, "..")), + ); }, _ => (), } diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index a7f498af5c2..bf734cc9c0e 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -5,10 +5,12 @@ use utils::paths; 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 +/// **What it does:** This lint warns when you using `print!()` with a format +/// string that /// ends in a newline. /// -/// **Why is this bad?** You should use `println!()` instead, which appends the newline. +/// **Why is this bad?** You should use `println!()` instead, which appends the +/// newline. /// /// **Known problems:** None. /// diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index f7017dfc5c3..5b5c63c1aca 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -9,11 +9,14 @@ use syntax::codemap::Span; use syntax_pos::MultiSpan; use utils::{match_path, match_type, paths, span_lint, span_lint_and_then}; -/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless +/// **What it does:** This lint checks for function arguments of type `&String` +/// or `&Vec` unless /// the references are mutable. /// -/// **Why is this bad?** Requiring the argument to be of the specific size makes the function less -/// useful for no benefit; slices in the form of `&[T]` or `&str` usually suffice and can be +/// **Why is this bad?** Requiring the argument to be of the specific size +/// makes the function less +/// useful for no benefit; slices in the form of `&[T]` or `&str` usually +/// suffice and can be /// obtained from other types, too. /// /// **Known problems:** None. @@ -31,7 +34,8 @@ declare_lint! { /// **What it does:** This lint checks for equality comparisons with `ptr::null` /// -/// **Why is this bad?** It's easier and more readable to use the inherent `.is_null()` +/// **Why is this bad?** It's easier and more readable to use the inherent +/// `.is_null()` /// method instead /// /// **Known problems:** None. @@ -46,15 +50,20 @@ declare_lint! { "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead." } -/// **What it does:** This lint checks for functions that take immutable references and return +/// **What it does:** This lint checks for functions that take immutable +/// references and return /// mutable ones. /// -/// **Why is this bad?** This is trivially unsound, as one can create two mutable references -/// from the same (immutable!) source. This [error](https://github.com/rust-lang/rust/issues/39465) +/// **Why is this bad?** This is trivially unsound, as one can create two +/// mutable references +/// from the same (immutable!) source. This +/// [error](https://github.com/rust-lang/rust/issues/39465) /// actually lead to an interim Rust release 1.15.1. /// -/// **Known problems:** To be on the conservative side, if there's at least one mutable reference -/// with the output lifetime, this lint will not trigger. In practice, this case is unlikely anyway. +/// **Known problems:** To be on the conservative side, if there's at least one +/// mutable reference +/// with the output lifetime, this lint will not trigger. In practice, this +/// case is unlikely anyway. /// /// **Example:** /// ```rust @@ -66,7 +75,7 @@ declare_lint! { "fns that create mutable refs from immutable ref args" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct PointerPass; impl LintPass for PointerPass { @@ -102,10 +111,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { 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, - CMP_NULL, - expr.span, - "Comparing with null is better expressed by the .is_null() method"); + span_lint( + cx, + CMP_NULL, + expr.span, + "Comparing with null is better expressed by the .is_null() method", + ); } } } @@ -117,19 +128,28 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { let fn_ty = sig.skip_binder(); for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) { - if let ty::TyRef(_, ty::TypeAndMut { ty, mutbl: MutImmutable }) = ty.sty { + if let ty::TyRef(_, + ty::TypeAndMut { + ty, + mutbl: MutImmutable, + }) = ty.sty + { if match_type(cx, ty, &paths::VEC) { - span_lint(cx, - PTR_ARG, - arg.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices. Consider changing the type to `&[...]`"); + span_lint( + cx, + PTR_ARG, + arg.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ + with non-Vec-based slices. Consider changing the type to `&[...]`", + ); } else if match_type(cx, ty, &paths::STRING) { - span_lint(cx, - PTR_ARG, - arg.span, - "writing `&String` instead of `&str` involves a new object where a slice will do. \ - Consider changing the type to `&str`"); + span_lint( + cx, + PTR_ARG, + arg.span, + "writing `&String` instead of `&str` involves a new object where a slice will do. \ + Consider changing the type to `&str`", + ); } } } @@ -138,10 +158,10 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { if let Some((out, MutMutable, _)) = get_rptr_lm(ty) { let mut immutables = vec![]; for (_, ref mutbl, ref argspan) in - decl.inputs - .iter() - .filter_map(|ty| get_rptr_lm(ty)) - .filter(|&(lt, _, _)| lt.name == out.name) { + decl.inputs.iter().filter_map(|ty| get_rptr_lm(ty)).filter( + |&(lt, _, _)| lt.name == out.name, + ) + { if *mutbl == MutMutable { return; } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 037ebf8ba2c..aa43fb6b620 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -21,7 +21,8 @@ declare_lint! { "using `Iterator::step_by(0)`, which produces an infinite iterator" } -/// **What it does:** Checks for zipping a collection with the range of `0.._.len()`. +/// **What it does:** Checks for zipping a collection with the range of +/// `0.._.len()`. /// /// **Why is this bad?** The code is better expressed with `.enumerate()`. /// @@ -37,7 +38,7 @@ declare_lint! { "zipping iterator with a range when `enumerate()` would do" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct StepByZero; impl LintPass for StepByZero { @@ -57,10 +58,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero { use rustc_const_math::ConstInt::Usize; if let Some((Constant::Int(Usize(us)), _)) = constant(cx, &args[1]) { if us.as_u64(cx.sess().target.uint_type) == 0 { - span_lint(cx, - ITERATOR_STEP_BY_ZERO, - expr.span, - "Iterator::step_by(0) will panic at runtime"); + span_lint( + cx, + ITERATOR_STEP_BY_ZERO, + expr.span, + "Iterator::step_by(0) will panic at runtime", + ); } } } else if name == "zip" && args.len() == 2 { diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index a148d99aca8..a8360c71f91 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -40,12 +40,14 @@ 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_sugg(cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try this", - format!("{}", snippet(cx, addrof_target.span, "_"))); + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try this", + format!("{}", snippet(cx, addrof_target.span, "_")), + ); } } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f0225591571..4feeb6d0939 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -178,7 +178,8 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { }, 3 => { if let (&Expr::StartText, &Expr::Literal { .. }, &Expr::EndText) = - (&exprs[0], &exprs[1], &exprs[2]) { + (&exprs[0], &exprs[1], &exprs[2]) + { Some("consider using `==` on `str`s") } else { None @@ -211,18 +212,22 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { match builder.parse(r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, - TRIVIAL_REGEX, - expr.span, - "trivial regex", - &format!("consider using {}", repl)); + span_help_and_lint( + cx, + TRIVIAL_REGEX, + expr.span, + "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())); + span_lint( + cx, + INVALID_REGEX, + str_span(expr.span, r, e.position()), + &format!("regex syntax error: {}", e.description()), + ); }, } } @@ -230,18 +235,22 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { match builder.parse(&r) { Ok(r) => { if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint(cx, - TRIVIAL_REGEX, - expr.span, - "trivial regex", - &format!("consider using {}", repl)); + span_help_and_lint( + cx, + TRIVIAL_REGEX, + expr.span, + "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())); + span_lint( + cx, + INVALID_REGEX, + expr.span, + &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 41601a80890..b9fcb62de73 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -23,7 +23,8 @@ declare_lint! { "using a return statement like `return expr;` where an expression would suffice" } -/// **What it does:** Checks for `let`-bindings, which are subsequently returned. +/// **What it does:** Checks for `let`-bindings, which are subsequently +/// returned. /// /// **Why is this bad?** It is just extraneous code. Remove it to make your code /// more rusty. @@ -93,13 +94,11 @@ impl ReturnPass { if in_external_macro(cx, inner_span) || in_macro(inner_span) { return; } - span_lint_and_then(cx, - NEEDLESS_RETURN, - ret_span, - "unneeded return statement", - |db| if let Some(snippet) = snippet_opt(cx, inner_span) { - db.span_suggestion(ret_span, "remove `return` as shown", snippet); - }); + span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| { + if let Some(snippet) = snippet_opt(cx, inner_span) { + db.span_suggestion(ret_span, "remove `return` as shown", snippet); + } + }); } // Check for "let x = EXPR; x" diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index df803473a2a..4feaaa19287 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -9,7 +9,8 @@ use utils::{span_lint, get_trait_def_id, paths}; /// /// **Known problems:** None. /// -/// **Example:** Implementing `Visitor::visit_string` but not `Visitor::visit_str`. +/// **Example:** Implementing `Visitor::visit_string` but not +/// `Visitor::visit_str`. declare_lint! { pub SERDE_API_MISUSE, Warn, @@ -43,10 +44,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde { } if let Some(span) = seen_string { if seen_str.is_none() { - span_lint(cx, - SERDE_API_MISUSE, - span, - "you should not implement `visit_string` without also implementing `visit_str`"); + span_lint( + cx, + SERDE_API_MISUSE, + span, + "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 8a6b950327b..e80636ca347 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { decl: &'tcx FnDecl, body: &'tcx Body, _: Span, - _: NodeId + _: NodeId, ) { if in_external_macro(cx, body.value.span) { return; @@ -129,7 +129,13 @@ fn check_decl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl, bindings: return; } if let DeclLocal(ref local) = decl.node { - let Local { ref pat, ref ty, ref init, span, .. } = **local; + let Local { + ref pat, + ref ty, + ref init, + span, + .. + } = **local; if let Some(ref t) = *ty { check_ty(cx, t, bindings) } @@ -155,7 +161,7 @@ fn check_pat<'a, 'tcx>( pat: &'tcx Pat, init: Option<&'tcx Expr>, span: Span, - bindings: &mut Vec<(Name, Span)> + bindings: &mut Vec<(Name, Span)>, ) { // TODO: match more stuff / destructuring match pat.node { @@ -184,9 +190,9 @@ fn check_pat<'a, 'tcx>( 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); + let efield = efields.iter().find(|f| f.name.node == name).map( + |f| &*f.expr, + ); check_pat(cx, &field.node.pat, efield, span, bindings); } } else { @@ -240,39 +246,51 @@ fn lint_shadow<'a, 'tcx: 'a>( span: Span, pattern_span: Span, init: Option<&'tcx Expr>, - prev_span: Span + prev_span: Span, ) { if let Some(expr) = init { if is_self_shadow(name, expr) { - span_lint_and_then(cx, - SHADOW_SAME, - 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"); }); + span_lint_and_then( + cx, + SHADOW_SAME, + 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) { - span_lint_and_then(cx, - SHADOW_REUSE, - pattern_span, - &format!("`{}` is shadowed by `{}` which reuses the original value", - 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"); - }); + span_lint_and_then( + cx, + SHADOW_REUSE, + pattern_span, + &format!( + "`{}` is shadowed by `{}` which reuses the original value", + 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"); + }, + ); } else { - span_lint_and_then(cx, - SHADOW_UNRELATED, - pattern_span, - &format!("`{}` is shadowed by `{}`", - 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"); - }); + span_lint_and_then( + cx, + SHADOW_UNRELATED, + pattern_span, + &format!( + "`{}` is shadowed by `{}`", + 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"); + }, + ); } } else { @@ -357,7 +375,11 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { ExprBox(ref inner) | 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)) + 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(QPath::Resolved(_, ref path)) => path_eq_name(name, path), diff --git a/clippy_lints/src/should_assert_eq.rs b/clippy_lints/src/should_assert_eq.rs index ea79a77877a..ecb2c9c3162 100644 --- a/clippy_lints/src/should_assert_eq.rs +++ b/clippy_lints/src/should_assert_eq.rs @@ -2,10 +2,12 @@ use rustc::lint::*; use rustc::hir::*; use utils::{is_direct_expn_of, is_expn_of, implements_trait, span_lint}; -/// **What it does:** Checks for `assert!(x == y)` or `assert!(x != y)` which can be better written +/// **What it does:** Checks for `assert!(x == y)` or `assert!(x != y)` which +/// can be better written /// using `assert_eq` or `assert_ne` if `x` and `y` implement `Debug` trait. /// -/// **Why is this bad?** `assert_eq` and `assert_ne` provide better assertion failure reporting. +/// **Why is this bad?** `assert_eq` and `assert_ne` provide better assertion +/// failure reporting. /// /// **Known problems:** Hopefully none. /// @@ -14,7 +16,8 @@ use utils::{is_direct_expn_of, is_expn_of, implements_trait, span_lint}; /// let (x, y) = (1, 2); /// /// assert!(x == y); // assertion failed: x == y -/// assert_eq!(x, y); // assertion failed: `(left == right)` (left: `1`, right: `2`) +/// assert_eq!(x, y); // assertion failed: `(left == right)` (left: `1`, right: +/// `2`) /// ``` declare_lint! { pub SHOULD_ASSERT_EQ, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 043d1dff8e5..9b61f902c49 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -96,18 +96,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { } } } - span_lint(cx, - STRING_ADD, - e.span, - "you added something to a string. Consider using `String::push_str()` instead"); + span_lint( + cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead", + ); } } else if let ExprAssign(ref target, ref src) = e.node { if is_string(cx, target) && is_add(cx, src, target) { - span_lint(cx, - STRING_ADD_ASSIGN, - e.span, - "you assigned the result of adding something to this string. Consider using \ - `String::push_str()` instead"); + span_lint( + cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ + `String::push_str()` instead", + ); } } } @@ -121,7 +125,11 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { 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)) + block.stmts.is_empty() && + block.expr.as_ref().map_or( + false, + |expr| is_add(cx, expr, target), + ) }, _ => false, } @@ -147,12 +155,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { if let ExprLit(ref lit) = args[0].node { if let LitKind::Str(ref lit_content, _) = lit.node { if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) { - span_lint_and_sugg(cx, - STRING_LIT_AS_BYTES, - e.span, - "calling `as_bytes()` on a string literal", - "consider using a byte string literal instead", - format!("b{}", snippet(cx, args[0].span, r#""foo""#))); + span_lint_and_sugg( + cx, + STRING_LIT_AS_BYTES, + e.span, + "calling `as_bytes()` on a string literal", + "consider using a byte string literal instead", + format!("b{}", snippet(cx, args[0].span, r#""foo""#)), + ); } } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index b2c56fe8bf3..e17170db192 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -41,7 +41,7 @@ declare_lint! { "`foo = bar; bar = foo` sequence" } -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Swap; impl LintPass for Swap { diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 1d67e06f811..13555e3bb05 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -49,7 +49,8 @@ declare_lint! { /// /// **Example:** /// ```rust -/// core::intrinsics::transmute(t)` // where the result type is the same as `*t` or `&t`'s +/// core::intrinsics::transmute(t)` // where the result type is the same as +/// `*t` or `&t`'s /// ``` declare_lint! { pub CROSSPOINTER_TRANSMUTE, @@ -79,7 +80,7 @@ pub struct Transmute; impl LintPass for Transmute { fn get_lints(&self) -> LintArray { - lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE] + lint_array!(CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE) } } @@ -95,87 +96,101 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { 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)) + span_lint( + cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty), + ) }, (&ty::TyRef(_, rty), &ty::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) - } else { - arg.as_ty(cx.tcx.mk_ptr(rty)).as_ty(to_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) + } else { + arg.as_ty(cx.tcx.mk_ptr(rty)).as_ty(to_ty) + }; - db.span_suggestion(e.span, "try", sugg.to_string()); - }) + db.span_suggestion(e.span, "try", sugg.to_string()); + }, + ) }, (&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::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()); - }) + 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(_), &ty::TyRef(..)) | (&ty::TyFloat(_), &ty::TyRawPtr(_)) | (&ty::TyChar, &ty::TyRef(..)) | (&ty::TyChar, &ty::TyRawPtr(_)) => { - span_lint(cx, - WRONG_TRANSMUTE, - e.span, - &format!("transmute from a `{}` to a pointer", from_ty)) + span_lint( + cx, + WRONG_TRANSMUTE, + e.span, + &format!("transmute from a `{}` to a pointer", from_ty), + ) }, (&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)) + span_lint( + cx, + CROSSPOINTER_TRANSMUTE, + e.span, + &format!( + "transmute from a type (`{}`) to the type that it points to (`{}`)", + from_ty, + to_ty + ), + ) }, (_, &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)) + span_lint( + cx, + CROSSPOINTER_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty), + ) }, (&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_rty)) => { - span_lint_and_then(cx, - TRANSMUTE_PTR_TO_REF, - e.span, - &format!("transmute from a pointer type (`{}`) to a reference type \ + 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") - } else { - ("&*", "*const") - }; + from_ty, + to_ty + ), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable { + ("&mut *", "*mut") + } else { + ("&*", "*const") + }; - let arg = if from_pty.ty == to_rty.ty { - arg - } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_rty.ty))) - }; + let arg = if from_pty.ty == to_rty.ty { + arg + } else { + 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()); - }) + db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string()); + }, + ) }, _ => return, }; @@ -185,8 +200,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } } -/// Get the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is not available , use -/// the type's `ToString` implementation. In weird cases it could lead to types with invalid `'_` +/// Get the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is +/// not available , use +/// the type's `ToString` implementation. In weird cases it could lead to types +/// with invalid `'_` /// lifetime, but it should be rare. fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: Ty) -> String { let seg = last_path_segment(path); diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 66cb5671c77..44e33d40a38 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -42,14 +42,21 @@ declare_lint! { /// /// **Why is this bad?** Gankro says: /// -/// > The TL;DR of `LinkedList` is that it's built on a massive amount of pointers and indirection. -/// > It wastes memory, it has terrible cache locality, and is all-around slow. `RingBuf`, while -/// > "only" amortized for push/pop, should be faster in the general case for almost every possible -/// > workload, and isn't even amortized at all if you can predict the capacity you need. +/// > The TL;DR of `LinkedList` is that it's built on a massive amount of +/// pointers and indirection. +/// > It wastes memory, it has terrible cache locality, and is all-around slow. +/// `RingBuf`, while +/// > "only" amortized for push/pop, should be faster in the general case for +/// almost every possible +/// > workload, and isn't even amortized at all if you can predict the capacity +/// you need. /// > -/// > `LinkedList`s are only really good if you're doing a lot of merging or splitting of lists. -/// > This is because they can just mangle some pointers instead of actually copying the data. Even -/// > if you're doing a lot of insertion in the middle of the list, `RingBuf` can still be better +/// > `LinkedList`s are only really good if you're doing a lot of merging or +/// splitting of lists. +/// > This is because they can just mangle some pointers instead of actually +/// copying the data. Even +/// > if you're doing a lot of insertion in the middle of the list, `RingBuf` +/// can still be better /// > because of how expensive it is to seek to the middle of a `LinkedList`. /// /// **Known problems:** False positives – the instances where using a @@ -68,7 +75,8 @@ declare_lint! { /// **What it does:** Checks for use of `&Box<T>` anywhere in the code. /// -/// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more general. +/// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more +/// general. /// /// **Known problems:** None. /// @@ -161,11 +169,13 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { return; // don't recurse into the type }} } else if match_def_path(cx.tcx, 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"); + 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 } } @@ -268,11 +278,15 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) { if higher::is_from_for_desugar(decl) { return; } - span_lint(cx, - LET_UNIT_VALUE, - decl.span, - &format!("this let-binding has unit value. Consider omitting `let {} =`", - snippet(cx, local.pat.span, ".."))); + span_lint( + cx, + LET_UNIT_VALUE, + decl.span, + &format!( + "this let-binding has unit value. Consider omitting `let {} =`", + snippet(cx, local.pat.span, "..") + ), + ); }, _ => (), } @@ -336,12 +350,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp { BiEq | BiLe | BiGe => "true", _ => "false", }; - span_lint(cx, - UNIT_CMP, - expr.span, - &format!("{}-comparison of unit values detected. This will always be {}", - op.as_str(), - result)); + span_lint( + cx, + UNIT_CMP, + expr.span, + &format!( + "{}-comparison of unit values detected. This will always be {}", + op.as_str(), + result + ), + ); }, _ => (), } @@ -493,20 +511,24 @@ fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_t } else { int_ty_to_nbits(cast_from).to_string() }; - span_lint(cx, - CAST_PRECISION_LOSS, - expr.span, - &format!("casting {0} to {1} causes a loss of precision {2}({0} is {3} bits wide, but {1}'s mantissa \ + span_lint( + cx, + CAST_PRECISION_LOSS, + expr.span, + &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 arch_dependent { - arch_dependent_str - } else { - "" - }, - from_nbits_str, - mantissa_nbits)); + cast_from, + if cast_to_f64 { "f64" } else { "f32" }, + if arch_dependent { + arch_dependent_str + } else { + "" + }, + from_nbits_str, + mantissa_nbits + ), + ); } enum ArchSuffix { @@ -520,70 +542,86 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: Ty, c let arch_32_suffix = " on targets with 32-bit wide pointers"; let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); let (from_nbits, to_nbits) = (int_ty_to_nbits(cast_from), int_ty_to_nbits(cast_to)); - let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), - is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => { - (to_nbits < from_nbits, - 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 - }, - 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 - }) - }, - }; + let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = + match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => { + ( + to_nbits < from_nbits, + 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 + }, + 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 + }, + ) + }, + }; if span_truncation { - span_lint(cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - &format!("casting {} to {} may truncate the value{}", - cast_from, - cast_to, - match suffix_truncation { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "", - })); + span_lint( + cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + &format!( + "casting {} to {} may truncate the value{}", + cast_from, + cast_to, + match suffix_truncation { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + } + ), + ); } if span_wrap { - span_lint(cx, - CAST_POSSIBLE_WRAP, - expr.span, - &format!("casting {} to {} may wrap around the value{}", - cast_from, - cast_to, - match suffix_wrap { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "", - })); + span_lint( + cx, + CAST_POSSIBLE_WRAP, + expr.span, + &format!( + "casting {} to {} may wrap around the value{}", + cast_from, + cast_to, + match suffix_wrap { + ArchSuffix::_32 => arch_32_suffix, + ArchSuffix::_64 => arch_64_suffix, + ArchSuffix::None => "", + } + ), + ); } } impl LintPass for CastPass { fn get_lints(&self) -> LintArray { - lint_array!(CAST_PRECISION_LOSS, - CAST_SIGN_LOSS, - CAST_POSSIBLE_TRUNCATION, - CAST_POSSIBLE_WRAP, - UNNECESSARY_CAST) + lint_array!( + CAST_PRECISION_LOSS, + CAST_SIGN_LOSS, + CAST_POSSIBLE_TRUNCATION, + CAST_POSSIBLE_WRAP, + UNNECESSARY_CAST + ) } } @@ -598,12 +636,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { LitKind::FloatUnsuffixed(_) => {}, _ => { if cast_from.sty == cast_to.sty && !in_external_macro(cx, expr.span) { - span_lint(cx, - UNNECESSARY_CAST, - expr.span, - &format!("casting to the same type is unnecessary (`{}` -> `{}`)", - cast_from, - cast_to)); + span_lint( + cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting to the same type is unnecessary (`{}` -> `{}`)", cast_from, cast_to), + ); } }, } @@ -622,33 +660,42 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { } }, (false, true) => { - span_lint(cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - &format!("casting {} to {} may truncate the value", cast_from, cast_to)); + span_lint( + cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + &format!("casting {} to {} may truncate the value", cast_from, cast_to), + ); if !cast_to.is_signed() { - span_lint(cx, - CAST_SIGN_LOSS, - expr.span, - &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); + span_lint( + cx, + CAST_SIGN_LOSS, + 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, - CAST_SIGN_LOSS, - expr.span, - &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); + span_lint( + cx, + CAST_SIGN_LOSS, + expr.span, + &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) { - span_lint(cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - "casting f64 to f32 may truncate the value"); + (&cast_from.sty, &cast_to.sty) + { + span_lint( + cx, + CAST_POSSIBLE_TRUNCATION, + expr.span, + "casting f64 to f32 may truncate the value", + ); } }, } @@ -700,7 +747,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { decl: &'tcx FnDecl, _: &'tcx Body, _: Span, - _: NodeId + _: NodeId, ) { self.check_fndecl(cx, decl); } @@ -760,19 +807,18 @@ impl<'a, 'tcx> TypeComplexityPass { return; } let score = { - let mut visitor = TypeComplexityVisitor { - score: 0, - nest: 1, - }; + let mut visitor = TypeComplexityVisitor { score: 0, nest: 1 }; visitor.visit_ty(ty); visitor.score }; if score > self.threshold { - span_lint(cx, - TYPE_COMPLEXITY, - ty.span, - "very complex type used. Consider factoring parts into `type` definitions"); + span_lint( + cx, + TYPE_COMPLEXITY, + ty.span, + "very complex type used. Consider factoring parts into `type` definitions", + ); } } } @@ -798,8 +844,9 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyBareFn(..) => (50 * self.nest, 1), TyTraitObject(ref param_bounds, _) => { - let has_lifetime_parameters = param_bounds.iter() - .any(|bound| !bound.bound_lifetimes.is_empty()); + let has_lifetime_parameters = param_bounds.iter().any( + |bound| !bound.bound_lifetimes.is_empty(), + ); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> (50 * self.nest, 1) @@ -922,7 +969,7 @@ fn detect_absurd_comparison<'a>( cx: &LateContext, op: BinOp_, lhs: &'a Expr, - rhs: &'a Expr + rhs: &'a Expr, ) -> Option<(ExtremeExpr<'a>, AbsurdComparisonResult)> { use types::ExtremeType::*; use types::AbsurdComparisonResult::*; @@ -1042,20 +1089,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { AlwaysFalse => "this comparison is always false".to_owned(), AlwaysTrue => "this comparison is always true".to_owned(), InequalityImpossible => { - format!("the case where the two sides are not equal never occurs, consider using {} == {} \ + format!( + "the case where the two sides are not equal never occurs, consider using {} == {} \ instead", - snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs")) + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs") + ) }, }; - let help = format!("because {} is the {} value for this type, {}", - snippet(cx, culprit.expr.span, "x"), - match culprit.which { - Minimum => "minimum", - Maximum => "maximum", - }, - conclusion); + let help = format!( + "because {} is the {} value for this type, {}", + snippet(cx, culprit.expr.span, "x"), + match culprit.which { + Minimum => "minimum", + Maximum => "maximum", + }, + conclusion + ); span_help_and_lint(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, &help); } @@ -1113,7 +1164,9 @@ impl FullInt { impl PartialEq for FullInt { fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal + self.partial_cmp(other).expect( + "partial_cmp only returns Some(_)", + ) == Ordering::Equal } } @@ -1129,7 +1182,9 @@ impl PartialOrd for FullInt { } impl Ord for FullInt { fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).expect("partial_cmp for FullInt can never return None") + self.partial_cmp(other).expect( + "partial_cmp for FullInt can never return None", + ) } } @@ -1198,14 +1253,16 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { fn err_upcast_comparison(cx: &LateContext, span: &Span, expr: &Expr, always: bool) { if let ExprCast(ref cast_val, _) = expr.node { - span_lint(cx, - INVALID_UPCAST_COMPARISONS, - *span, - &format!( + span_lint( + cx, + INVALID_UPCAST_COMPARISONS, + *span, + &format!( "because of the numeric bounds on `{}` prior to casting, this expression is always {}", snippet(cx, cast_val.span, "the expression"), if always { "true" } else { "false" }, - )); + ), + ); } } @@ -1216,7 +1273,7 @@ fn upcast_comparison_bounds_err( lhs_bounds: Option<(FullInt, FullInt)>, lhs: &Expr, rhs: &Expr, - invert: bool + invert: bool, ) { use utils::comparisons::*; @@ -1227,40 +1284,42 @@ fn upcast_comparison_bounds_err( err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); } } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val < lb - } else { - ub < norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val <= lb - } else { - ub <= norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } { + Rel::Lt => { + if invert { + norm_rhs_val < lb + } 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) } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val >= ub - } else { - lb >= norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val > ub - } else { - lb > norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } { + Rel::Lt => { + if invert { + norm_rhs_val >= ub + } 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) } } diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 1d5ab7db346..ace8ea7558d 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -12,7 +12,8 @@ use utils::{snippet, span_help_and_lint}; /// /// **Known problems:** None. /// -/// **Example:** You don't see it, but there may be a zero-width space somewhere in this text. +/// **Example:** You don't see it, but there may be a zero-width space +/// somewhere in this text. declare_lint! { pub ZERO_WIDTH_SPACE, Deny, @@ -95,30 +96,40 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String { fn check_str(cx: &LateContext, span: Span) { let string = snippet(cx, span, ""); if string.contains('\u{200B}') { - span_help_and_lint(cx, - ZERO_WIDTH_SPACE, - span, - "zero-width space detected", - &format!("Consider replacing the string with:\n\"{}\"", - string.replace("\u{200B}", "\\u{200B}"))); + span_help_and_lint( + cx, + ZERO_WIDTH_SPACE, + span, + "zero-width space detected", + &format!( + "Consider replacing the string with:\n\"{}\"", + string.replace("\u{200B}", "\\u{200B}") + ), + ); } if string.chars().any(|c| c as u32 > 0x7F) { - span_help_and_lint(cx, - NON_ASCII_LITERAL, - span, - "literal non-ASCII character detected", - &format!("Consider replacing the string with:\n\"{}\"", - if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { - escape(string.chars()) - } else { - escape(string.nfc()) - })); + span_help_and_lint( + cx, + NON_ASCII_LITERAL, + span, + "literal non-ASCII character detected", + &format!( + "Consider replacing the string with:\n\"{}\"", + if cx.current_level(UNICODE_NOT_NFC) == Level::Allow { + escape(string.chars()) + } else { + escape(string.nfc()) + } + ), + ); } if cx.current_level(NON_ASCII_LITERAL) == Level::Allow && string.chars().zip(string.nfc()).any(|(a, b)| a != b) { - span_help_and_lint(cx, - UNICODE_NOT_NFC, - span, - "non-nfc unicode sequence detected", - &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>())); + span_help_and_lint( + cx, + UNICODE_NOT_NFC, + span, + "non-nfc unicode sequence detected", + &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>()), + ); } } diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 07afc55ae7f..036e6f0f0e6 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -38,13 +38,15 @@ impl EarlyLintPass for UnsafeNameRemoval { 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") - .identifier, - *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() { @@ -64,10 +66,12 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext, spa 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)); + span_lint( + cx, + UNSAFE_REMOVED_FROM_NAME, + *span, + &format!("removed \"unsafe\" from the name of `{}` in use as `{}`", old_str, new_str), + ); } } diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 5a97254f3ad..ff2148c88a9 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -4,9 +4,12 @@ use utils::{span_lint, match_path, match_trait_method, is_try, paths}; /// **What it does:** Checks for unused written/read amount. /// -/// **Why is this bad?** `io::Write::write` and `io::Read::read` are not guaranteed to -/// process the entire buffer. They return how many bytes were processed, which might be smaller -/// than a given buffer's length. If you don't need to deal with partial-write/read, use +/// **Why is this bad?** `io::Write::write` and `io::Read::read` are not +/// guaranteed to +/// process the entire buffer. They return how many bytes were processed, which +/// might be smaller +/// than a given buffer's length. If you don't need to deal with +/// partial-write/read, use /// `write_all`/`read_exact` instead. /// /// **Known problems:** Detects only common patterns. @@ -73,15 +76,19 @@ fn check_method_call(cx: &LateContext, call: &hir::Expr, expr: &hir::Expr) { if let hir::ExprMethodCall(ref path, _, _) = call.node { let symbol = &*path.name.as_str(); if match_trait_method(cx, call, &paths::IO_READ) && symbol == "read" { - span_lint(cx, - UNUSED_IO_AMOUNT, - expr.span, - "handle read amount returned or use `Read::read_exact` instead"); + span_lint( + cx, + UNUSED_IO_AMOUNT, + expr.span, + "handle read amount returned or use `Read::read_exact` instead", + ); } else if match_trait_method(cx, call, &paths::IO_WRITE) && symbol == "write" { - span_lint(cx, - UNUSED_IO_AMOUNT, - expr.span, - "handle written amount returned or use `Write::write_all` instead"); + span_lint( + cx, + UNUSED_IO_AMOUNT, + expr.span, + "handle written amount returned or use `Write::write_all` instead", + ); } } } diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index 15f327fb5c2..8a8afe8a377 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { decl: &'tcx hir::FnDecl, body: &'tcx hir::Body, span: Span, - fn_id: ast::NodeId + fn_id: ast::NodeId, ) { if in_macro(span) { return; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index af92589b4d2..7466ee9080b 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -7,7 +7,7 @@ use rustc::lint::*; use rustc::hir; use rustc::hir::{Expr, QPath, Expr_}; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use syntax::ast::{Attribute, NodeId, LitKind, DUMMY_NODE_ID, self}; +use syntax::ast::{self, Attribute, NodeId, LitKind, DUMMY_NODE_ID}; use syntax::codemap::Span; use std::collections::HashMap; @@ -166,13 +166,14 @@ impl PrintVisitor { Vacant(vac) => { vac.insert(0); s.to_owned() - } + }, } } } struct PrintVisitor { - /// Fields are the current index that needs to be appended to pattern binding names + /// Fields are the current index that needs to be appended to pattern + /// binding names ids: HashMap<&'static str, usize>, /// the name that needs to be destructured current: String, @@ -254,7 +255,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!(" {}.as_str() == {:?}", str_pat, &*text.as_str()) }, } - } + }, Expr_::ExprCast(ref expr, ref _ty) => { let cast_pat = self.next("expr"); println!("Cast(ref {}, _) = {},", cast_pat, current); @@ -282,7 +283,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.visit_expr(cond); self.current = then_pat; self.visit_expr(then); - } + }, Expr_::ExprWhile(ref _cond, ref _body, ref _opt_label) => { println!("While(ref cond, ref body, ref opt_label) = {},", current); println!(" // unimplemented: `ExprWhile` is not further destructured at the moment"); @@ -398,7 +399,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { let fields_pat = self.next("fields"); if let Some(ref base) = *opt_base { let base_pat = self.next("base"); - println!("Struct(ref {}, ref {}, Some(ref {})) = {},", path_pat, fields_pat, base_pat, current); + println!( + "Struct(ref {}, ref {}, Some(ref {})) = {},", + path_pat, + fields_pat, + base_pat, + current + ); self.current = base_pat; self.visit_expr(base); } else { @@ -433,24 +440,27 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { fn has_attr(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { attr.check_name("clippy") && - attr.meta_item_list().map_or(false, |list| { - list.len() == 1 && match list[0].node { - ast::NestedMetaItemKind::MetaItem(ref it) => it.name == "author", - ast::NestedMetaItemKind::Literal(_) => false, - } - }) + attr.meta_item_list().map_or(false, |list| { + list.len() == 1 && + match list[0].node { + ast::NestedMetaItemKind::MetaItem(ref it) => it.name == "author", + ast::NestedMetaItemKind::Literal(_) => false, + } + }) }) } fn print_path(path: &QPath, first: &mut bool) { match *path { - QPath::Resolved(_, ref path) => for segment in &path.segments { - if *first { - *first = false; - } else { - print!(", "); + QPath::Resolved(_, ref path) => { + for segment in &path.segments { + if *first { + *first = false; + } else { + print!(", "); + } + print!("{:?}", segment.name.as_str()); } - print!("{:?}", segment.name.as_str()); }, QPath::TypeRelative(ref ty, ref segment) => { match ty.node { diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index f973c2afd27..5cb9b50a79d 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -17,7 +17,8 @@ pub enum Rel { Ne, } -/// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`. +/// 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)> { match op { BinOp_::BiLt => Some((Rel::Lt, lhs, rhs)), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0e6f8856382..ad9e7e20176 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -9,8 +9,9 @@ use toml; use std::sync::Mutex; /// Get the configuration file from arguments. -pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) - -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> { +pub fn file_from_args( + args: &[codemap::Spanned<ast::NestedMetaItemKind>], +) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> { for arg in args.iter().filter_map(|a| a.meta_item()) { if arg.name() == "conf_file" { return match arg.node { @@ -38,12 +39,14 @@ pub enum Error { /// Not valid toml or doesn't fit the expected conf format Toml(String), /// 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), } @@ -234,11 +237,25 @@ pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) { Err(err) => return default(vec![err.into()]), }; - assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty()); + assert!( + ERRORS + .lock() + .expect("no threading -> mutex always safe") + .is_empty() + ); match toml::from_str(&file) { - Ok(toml) => (toml, ERRORS.lock().expect("no threading -> mutex always safe").split_off(0)), + Ok(toml) => ( + toml, + ERRORS + .lock() + .expect("no threading -> mutex always safe") + .split_off(0), + ), Err(e) => { - let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0); + let mut errors = ERRORS + .lock() + .expect("no threading -> mutex always safe") + .split_off(0); errors.push(Error::Toml(e.to_string())); default(errors) }, diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs index 87008307c5f..d47fbd5a043 100644 --- a/clippy_lints/src/utils/constants.rs +++ b/clippy_lints/src/utils/constants.rs @@ -7,5 +7,20 @@ /// 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 d25f8e7df2b..593cbf69f5b 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,4 +1,5 @@ -//! This module contains functions for retrieve the original AST from lowered `hir`. +//! This module contains functions for retrieve the original AST from lowered +//! `hir`. #![deny(missing_docs_in_private_items)] @@ -44,9 +45,11 @@ pub struct Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. pub fn range(expr: &hir::Expr) -> Option<Range> { - /// Find the field named `name` in the field. Always return `Some` for convenience. + /// 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() + let expr = &fields + .iter() .find(|field| field.name.node == name) .unwrap_or_else(|| panic!("missing {} field for range", name)) .expr; @@ -54,7 +57,8 @@ pub fn range(expr: &hir::Expr) -> Option<Range> { Some(expr) } - // The range syntax is expanded to literal paths starting with `core` or `std` depending on + // 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 expr.node { @@ -147,7 +151,8 @@ pub enum VecArgs<'a> { Vec(&'a [hir::Expr]), } -/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. +/// Returns the arguments of the `vec!` macro if this expression was expanded +/// from `vec!`. pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e>> { if_let_chain!{[ let hir::ExprCall(ref fun, ref args) = expr.node, diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 3b943b83bb0..658a07ca146 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -7,14 +7,17 @@ use syntax::ast::Name; use syntax::ptr::P; use utils::differing_macro_contexts; -/// Type used to check whether two ast are the same. This is different from the operator -/// `==` on ast types as this operator would compare true equality with ID and span. +/// Type used to check whether two ast are the same. This is different from the +/// operator +/// `==` on ast types as this operator would compare true equality with ID and +/// span. /// /// Note that some expressions kinds are not considered but could be added. pub struct SpanlessEq<'a, 'tcx: 'a> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'a, 'tcx>, - /// If is true, never consider as equal expressions containing function calls. + /// If is true, never consider as equal expressions containing function + /// calls. ignore_fn: bool, } @@ -52,7 +55,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { /// Check whether two blocks are the same. pub fn eq_block(&self, left: &Block, right: &Block) -> bool { over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && - both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) + both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) } pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { @@ -78,13 +81,13 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&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) - }) + 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.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str()) && - both(le, re, |l, r| self.eq_expr(l, r)) + 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)) => { @@ -105,23 +108,23 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { }, (&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)) - }) + 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_path, _, ref l_args), &ExprMethodCall(ref r_path, _, ref r_args)) => { !self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args) }, (&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => { self.eq_expr(le, re) && - self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) + self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) }, (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), (&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r), (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => { 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)) + 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), @@ -167,7 +170,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&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)) + both(li, ri, |l, r| self.eq_pat(l, r)) }, (&PatKind::Wild, &PatKind::Wild) => true, _ => false, @@ -188,19 +191,19 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { fn eq_path(&self, left: &Path, right: &Path) -> bool { left.is_global() == right.is_global() && - over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) + over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) } fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool { match (left, right) { (&AngleBracketedParameters(ref left), &AngleBracketedParameters(ref right)) => { 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)) + 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)) + both(&left.output, &right.output, |l, r| self.eq_ty(l, r)) }, (&AngleBracketedParameters(_), &ParenthesizedParameters(_)) | (&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => false, @@ -218,7 +221,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { (&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => { self.eq_ty(lt, rt) && - self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) + self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) }, (&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty), (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => { @@ -247,22 +250,28 @@ fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_ } } -/// Check if the two `Option`s are both `None` or some equal values as per `eq_fn`. +/// Check if the two `Option`s are both `None` or some equal values as per +/// `eq_fn`. fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool +where + F: FnMut(&X, &X) -> bool, { - l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) + l.as_ref().map_or_else(|| r.is_none(), |x| { + r.as_ref().map_or(false, |y| eq_fn(x, y)) + }) } /// Check if two slices are equal as per `eq_fn`. fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool - where F: FnMut(&X, &X) -> bool +where + F: FnMut(&X, &X) -> bool, { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } -/// Type used to hash an ast element. This is different from the `Hash` trait on ast types as this +/// Type used to hash an ast element. This is different from the `Hash` trait +/// on ast types as this /// trait would consider IDs and spans. /// /// All expressions kind are hashed, but some might have a weaker hash. diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 9962eca5075..ccb2cb7c67f 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -8,7 +8,8 @@ use rustc::hir::print; use syntax::ast::Attribute; use syntax::attr; -/// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]` attribute +/// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]` +/// attribute /// /// **Example:** /// ```rust @@ -54,8 +55,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { hir::Visibility::Public => println!("public"), hir::Visibility::Crate => println!("visible crate wide"), hir::Visibility::Restricted { ref path, .. } => { - println!("visible in module `{}`", - print::to_string(print::NO_ANN, |s| s.print_path(path, false))) + println!( + "visible in module `{}`", + print::to_string(print::NO_ANN, |s| s.print_path(path, false)) + ) }, hir::Visibility::Inherited => println!("visibility inherited from outer item"), } @@ -71,20 +74,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { hir::ImplItemKind::Type(_) => println!("associated type"), } } - // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { + // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx + // hir::TraitItem) { // if !has_attr(&item.attrs) { // return; // } // } // - // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: + // 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) { + // fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx + // hir::StructField) { // if !has_attr(&field.attrs) { // return; // } @@ -123,7 +129,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { hir::StmtSemi(ref e, _) => print_expr(cx, e, 0), } } - // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) { + // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx + // hir::ForeignItem) { // if !has_attr(&item.attrs) { // return; // } @@ -345,8 +352,10 @@ fn print_item(cx: &LateContext, item: &hir::Item) { hir::Visibility::Public => println!("public"), hir::Visibility::Crate => println!("visible crate wide"), hir::Visibility::Restricted { ref path, .. } => { - println!("visible in module `{}`", - print::to_string(print::NO_ANN, |s| s.print_path(path, false))) + println!( + "visible in module `{}`", + print::to_string(print::NO_ANN, |s| s.print_path(path, false)) + ) }, hir::Visibility::Inherited => println!("visibility inherited from outer item"), } @@ -422,9 +431,11 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) { }, hir::PatKind::Struct(ref path, ref fields, ignore) => { println!("{}Struct", ind); - println!("{}name: {}", - ind, - print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))); + println!( + "{}name: {}", + ind, + print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)) + ); println!("{}ignore leftover fields: {}", ind, ignore); println!("{}fields:", ind); for field in fields { @@ -437,9 +448,11 @@ fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) { }, hir::PatKind::TupleStruct(ref path, ref fields, opt_dots_position) => { println!("{}TupleStruct", ind); - println!("{}path: {}", - ind, - print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))); + println!( + "{}path: {}", + ind, + print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)) + ); if let Some(dot_position) = opt_dots_position { println!("{}dot position: {}", ind, dot_position); } diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 038dfc01d13..f81aff24338 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -63,20 +63,28 @@ impl LintPass for Clippy { impl EarlyLintPass for Clippy { fn check_crate(&mut self, cx: &EarlyContext, krate: &AstCrate) { - if let Some(utils) = krate.module.items.iter().find(|item| item.ident.name == "utils") { + if let Some(utils) = krate.module.items.iter().find( + |item| item.ident.name == "utils", + ) + { if let ItemKind::Mod(ref utils_mod) = utils.node { - if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name == "paths") { + if let Some(paths) = utils_mod.items.iter().find( + |item| item.ident.name == "paths", + ) + { if let ItemKind::Mod(ref paths_mod) = paths.node { let mut last_name: Option<InternedString> = None; for item in &paths_mod.items { let name = item.ident.name.as_str(); if let Some(ref last_name) = last_name { if **last_name > *name { - span_lint(cx, - CLIPPY_LINTS_INTERNAL, - item.span, - "this constant should be before the previous constant due to lexical \ - ordering"); + span_lint( + cx, + CLIPPY_LINTS_INTERNAL, + item.span, + "this constant should be before the previous constant due to lexical \ + ordering", + ); } } last_name = Some(name); @@ -128,13 +136,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { // not able to capture the error. // Therefore, we need to climb the macro expansion tree and find the // actual span that invoked `declare_lint!`: - let lint_span = lint_span.ctxt.outer().expn_info().map(|ei| ei.call_site).expect("unable to get call_site"); + let lint_span = lint_span + .ctxt + .outer() + .expn_info() + .map(|ei| ei.call_site) + .expect("unable to get call_site"); if !self.registered_lints.contains(lint_name) { - span_lint(cx, - LINT_WITHOUT_LINT_PASS, - lint_span, - &format!("the lint `{}` is not added to any `LintPass`", lint_name)); + span_lint( + cx, + LINT_WITHOUT_LINT_PASS, + lint_span, + &format!("the lint `{}` is not added to any `LintPass`", lint_name), + ); } } } @@ -142,7 +157,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { fn is_lint_ref_type(ty: &Ty) -> bool { - if let TyRptr(ref lt, MutTy { ty: ref inner, mutbl: MutImmutable }) = ty.node { + if let TyRptr(ref lt, + MutTy { + ty: ref inner, + mutbl: MutImmutable, + }) = ty.node + { if lt.is_elided() { return false; } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index cdce1108be2..43c0eb68d69 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -93,7 +93,8 @@ macro_rules! if_let_chain { pub mod higher; -/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one +/// Returns true if the two spans come from differing expansions (i.e. one is +/// from a macro and one /// isn't). pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt != lhs.ctxt @@ -119,10 +120,12 @@ pub fn in_macro(span: Span) -> bool { }) } -/// Returns true if the macro that expanded the crate was outside of the current crate or was a +/// 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<'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 + /// 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<'a, T: LintContext<'a>>(cx: &T, info: &ExpnInfo) -> bool { // no ExpnInfo = no macro @@ -133,11 +136,18 @@ pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { // no span for the callee = external macro info.callee.span.map_or(true, |span| { // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or(true, |code| !code.starts_with("macro_rules")) + cx.sess().codemap().span_to_snippet(span).ok().map_or( + true, + |code| { + !code.starts_with("macro_rules") + }, + ) }) } - span.ctxt.outer().expn_info().map_or(false, |info| in_macro_ext(cx, &info)) + span.ctxt.outer().expn_info().map_or(false, |info| { + in_macro_ext(cx, &info) + }) } /// Check if a `DefId`'s path matches the given absolute type path usage. @@ -170,7 +180,10 @@ pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool { tcx.push_item_path(&mut apb, def_id); - apb.names.len() == path.len() && apb.names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b) + apb.names.len() == path.len() && + apb.names.into_iter().zip(path.iter()).all( + |(a, &b)| *a == *b, + ) } /// Check if type is struct, enum or union type with given def path. @@ -206,9 +219,9 @@ 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") + path.segments.last().expect( + "A path must have at least one segment", + ) }, QPath::TypeRelative(_, ref seg) => seg, } @@ -235,7 +248,7 @@ pub fn match_path(path: &QPath, segments: &[&str]) -> bool { match ty.node { TyPath(ref inner_path) => { !segments.is_empty() && match_path(inner_path, &segments[..(segments.len() - 1)]) && - segment.name == segments[segments.len() - 1] + segment.name == segments[segments.len() - 1] }, _ => false, } @@ -244,7 +257,9 @@ pub fn match_path(path: &QPath, segments: &[&str]) -> bool { } pub fn match_path_old(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.name == *b) + 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. @@ -254,7 +269,9 @@ pub fn match_path_old(path: &Path, segments: &[&str]) -> bool { /// match_path(path, &["std", "rt", "begin_unwind"]) /// ``` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all(|(a, b)| a.identifier.name == *b) + path.segments.iter().rev().zip(segments.iter().rev()).all( + |(a, b)| a.identifier.name == *b, + ) } /// Get the definition associated to a path. @@ -262,7 +279,9 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { let cstore = &cx.tcx.sess.cstore; let crates = cstore.crates(); - let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); + let krate = crates.iter().find( + |&&krate| cstore.crate_name(krate) == path[0], + ); if let Some(krate) = krate { let krate = DefId { krate: *krate, @@ -312,14 +331,20 @@ pub fn implements_trait<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, trait_id: DefId, - ty_params: &[Ty<'tcx>] + ty_params: &[Ty<'tcx>], ) -> bool { let ty = cx.tcx.erase_regions(&ty); - let obligation = cx.tcx - .predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params); - cx.tcx - .infer_ctxt() - .enter(|infcx| traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)) + let obligation = cx.tcx.predicate_for_trait_def( + cx.param_env, + traits::ObligationCause::dummy(), + trait_id, + 0, + ty, + ty_params, + ); + cx.tcx.infer_ctxt().enter(|infcx| { + traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) + }) } /// Resolve the definition of a node from its `NodeId`. @@ -330,7 +355,8 @@ pub fn resolve_node(cx: &LateContext, qpath: &QPath, id: NodeId) -> def::Def { /// Match an `Expr` against a chain of methods, and return the matched `Expr`s. /// /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, -/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` containing the `Expr`s for +/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` +/// containing the `Expr`s for /// `.bar()` and `.baz()` pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a [Expr]>> { let mut current = expr; @@ -382,8 +408,10 @@ pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> cx.sess().codemap().span_to_snippet(span).ok() } -/// Convert a span (from a block) to a code snippet if available, otherwise use default. -/// This trims the code of indentation, except for the first line. Use it for blocks or block-like +/// Convert a span (from a block) to a code snippet if available, otherwise use +/// default. +/// This trims the code of indentation, except for the first line. Use it for +/// blocks or block-like /// things which need to be printed as such. /// /// # Example @@ -401,7 +429,7 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>( cx: &T, expr: &Expr, option: Option<String>, - default: &'a str + default: &'a str, ) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.unwrap_or_default(); @@ -414,7 +442,8 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>( } } -/// Trim indentation from a multiline string with possibility of ignoring the first line. +/// Trim indentation from a multiline string with possibility of ignoring the +/// first line. pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { let s_space = trim_multiline_inner(s, ignore_first, ' '); let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); @@ -429,24 +458,28 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { None } else { // ignore empty lines - Some(l.char_indices() - .find(|&(_, x)| x != ch) - .unwrap_or((l.len(), ch)) - .0) + 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::<Vec<_>>() - .join("\n")) + Cow::Owned( + s.lines() + .enumerate() + .map(|(i, l)| if (ignore_first && i == 0) || l.is_empty() { + l + } else { + l.split_at(x).1 + }) + .collect::<Vec<_>>() + .join("\n"), + ) } else { s } @@ -460,17 +493,22 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if node_id == parent_id { return None; } - map.find(parent_id).and_then(|node| if let Node::NodeExpr(parent) = node { - Some(parent) - } else { - None - }) + map.find(parent_id).and_then( + |node| if let Node::NodeExpr(parent) = + node + { + Some(parent) + } else { + None + }, + ) } pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { let map = &cx.tcx.hir; - let enclosing_node = map.get_enclosing_scope(node) - .and_then(|enclosing_id| map.find(enclosing_id)); + let enclosing_node = map.get_enclosing_scope(node).and_then(|enclosing_id| { + map.find(enclosing_id) + }); if let Some(node) = enclosing_node { match node { Node::NodeBlock(block) => Some(block), @@ -498,8 +536,10 @@ impl<'a> Drop for DiagnosticWrapper<'a> { 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())); + self.0.help(&format!( + "for further information visit https://github.com/Manishearth/rust-clippy/wiki#{}", + lint.name_lower() + )); } } } @@ -516,7 +556,7 @@ pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>( lint: &'static Lint, span: Span, msg: &str, - help: &str + help: &str, ) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { @@ -531,7 +571,7 @@ pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>( span: Span, msg: &str, note_span: Span, - note: &str + note: &str, ) { let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); if cx.current_level(lint) != Level::Allow { @@ -549,8 +589,9 @@ pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>( lint: &'static Lint, sp: Span, msg: &str, - f: F -) where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>) + 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 { @@ -565,15 +606,17 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>( sp: Span, msg: &str, help: &str, - sugg: String + sugg: String, ) { span_lint_and_then(cx, lint, sp, msg, |db| { db.span_suggestion(sp, help, sugg); }); } /// Create a suggestion made from several `span → replacement`. /// -/// Note: in the JSON format (used by `compiletest_rs`), the help message will appear once per -/// replacement. In human-readable format though, it only appears once before the whole suggestion. +/// Note: in the JSON format (used by `compiletest_rs`), the help message will +/// appear once per +/// replacement. In human-readable format though, it only appears once before +/// the whole suggestion. pub fn multispan_sugg(db: &mut DiagnosticBuilder, help_msg: String, sugg: Vec<(Span, String)>) { let sugg = rustc_errors::CodeSuggestion { substitution_parts: sugg.into_iter() @@ -598,7 +641,8 @@ pub fn walk_ptrs_ty(ty: Ty) -> Ty { } } -/// Return the base type for references and raw pointers, and count reference depth. +/// Return the base type for references and raw pointers, and count reference +/// depth. pub fn walk_ptrs_ty_depth(ty: Ty) -> (Ty, usize) { fn inner(ty: Ty, depth: usize) -> (Ty, usize) { match ty.sty { @@ -639,7 +683,9 @@ impl LimitStack { LimitStack { stack: vec![limit] } } pub fn limit(&self) -> u64 { - *self.stack.last().expect("there should always be a value in the stack") + *self.stack.last().expect( + "there should always be a value in the stack", + ) } pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { let stack = &mut self.stack; @@ -669,14 +715,14 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' } } -/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. +/// Return the pre-expansion span if is this comes from an expansion of the +/// macro `name`. /// See also `is_direct_expn_of`. pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { loop { - let span_name_span = span.ctxt - .outer() - .expn_info() - .map(|ei| (ei.callee.name(), ei.call_site)); + let span_name_span = span.ctxt.outer().expn_info().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), @@ -686,18 +732,19 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { } } -/// Return the pre-expansion span if is this directly comes from an expansion of the macro `name`. +/// Return the pre-expansion span if is this directly comes from an expansion +/// of the macro `name`. /// The difference with `is_expn_of` is that in /// ```rust,ignore /// foo!(bar!(42)); /// ``` -/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only +/// `bar!` by /// `is_direct_expn_of`. pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { - let span_name_span = span.ctxt - .outer() - .expn_info() - .map(|ei| (ei.callee.name(), ei.call_site)); + let span_name_span = span.ctxt.outer().expn_info().map(|ei| { + (ei.callee.name(), ei.call_site) + }); match span_name_span { Some((mac_name, new_span)) if mac_name == name => Some(new_span), @@ -705,7 +752,8 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { } } -/// Return the index of the character after the first camel-case component of `s`. +/// Return the index of the character after the first camel-case component of +/// `s`. pub fn camel_case_until(s: &str) -> usize { let mut iter = s.char_indices(); if let Some((_, first)) = iter.next() { @@ -771,10 +819,13 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Ty<'t } /// Check if two types are the same. -// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but +// 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<'tcx>, b: Ty<'tcx>) -> bool { - cx.tcx.infer_ctxt().enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok()) + cx.tcx.infer_ctxt().enter(|infcx| { + infcx.can_eq(cx.param_env, a, b).is_ok() + }) } /// Return whether the given type is an `unsafe` function. @@ -792,8 +843,10 @@ pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { /// Return whether a pattern is refutable. pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool { fn is_enum_variant(cx: &LateContext, qpath: &QPath, did: NodeId) -> bool { - matches!(cx.tables.qpath_def(qpath, did), - def::Def::Variant(..) | def::Def::VariantCtor(..)) + matches!( + cx.tables.qpath_def(qpath, did), + def::Def::Variant(..) | def::Def::VariantCtor(..) + ) } fn are_refutable<'a, I: Iterator<Item = &'a Pat>>(cx: &LateContext, mut i: I) -> bool { @@ -824,19 +877,26 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool { } }, PatKind::Slice(ref head, ref middle, ref tail) => { - are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) + are_refutable( + cx, + head.iter().chain(middle).chain(tail.iter()).map( + |pat| &**pat, + ), + ) }, } } -/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have. +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d +/// implementations have. pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { attr::contains_name(attrs, "automatically_derived") } /// Remove blocks around an expression. /// -/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return themselves. +/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return +/// themselves. pub fn remove_blocks(expr: &Expr) -> &Expr { if let ExprBlock(ref block) = expr.node { if block.stmts.is_empty() { @@ -948,5 +1008,7 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> { } pub fn type_size<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<u64> { - ty.layout(cx.tcx, cx.param_env).ok().map(|layout| layout.size(cx.tcx).bytes()) + ty.layout(cx.tcx, cx.param_env).ok().map(|layout| { + layout.size(cx.tcx).bytes() + }) } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index f423274711a..675d708781c 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -1,4 +1,5 @@ -//! This module contains paths to types and functions Clippy needs to know about. +//! This module contains paths to types and functions Clippy needs to know +//! about. pub const ASMUT_TRAIT: [&'static str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&'static str; 3] = ["core", "convert", "AsRef"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 07872673b42..d46a6526395 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -20,7 +20,8 @@ pub enum Sugg<'a> { NonParen(Cow<'a, str>), /// An expression that does not fit in other variants. MaybeParen(Cow<'a, str>), - /// A binary operator expression, including `as`-casts and explicit type coercion. + /// A binary operator expression, including `as`-casts and explicit type + /// coercion. BinOp(AssocOp, Cow<'a, str>), } @@ -77,7 +78,8 @@ impl<'a> Sugg<'a> { }) } - /// Convenience function around `hir_opt` for suggestions with a default text. + /// Convenience function around `hir_opt` for suggestions with a default + /// text. pub fn hir(cx: &LateContext, expr: &hir::Expr, default: &'a str) -> Sugg<'a> { Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) } @@ -156,7 +158,8 @@ impl<'a> Sugg<'a> { make_unop("*", self) } - /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>` suggestion. + /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>` + /// suggestion. pub fn range(self, end: Self, limit: ast::RangeLimits) -> Sugg<'static> { match limit { ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, &end), @@ -164,7 +167,8 @@ impl<'a> Sugg<'a> { } } - /// Add parenthesis to any expression that might need them. Suitable to the `self` argument of + /// Add parenthesis to any expression that might need them. Suitable to the + /// `self` argument of /// a method call (eg. to build `bar.foo()` or `(1 + 2).foo()`). pub fn maybe_par(self) -> Self { match self { @@ -233,7 +237,8 @@ impl<T: Display> Display for ParenHelper<T> { /// Build the string for `<op><expr>` adding parenthesis when necessary. /// -/// For convenience, the operator is taken as a string because all unary operators have the same +/// For convenience, the operator is taken as a string because all unary +/// operators have the same /// precedence. pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> { Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into()) @@ -241,7 +246,8 @@ pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> { /// Build the string for `<lhs> <op> <rhs>` adding parenthesis when necessary. /// -/// Precedence of shift operator relative to other arithmetic operation is often confusing so +/// Precedence of shift operator relative to other arithmetic operation is +/// often confusing so /// parenthesis will always be added for a mix of these. pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { /// Whether the operator is a shift operator `<<` or `>>`. @@ -251,18 +257,21 @@ 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 + /// 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 { @@ -316,11 +325,13 @@ enum Associativity { Right, } -/// Return the associativity/fixity of an operator. The difference with `AssocOp::fixity` is that +/// Return the associativity/fixity of an operator. The difference with +/// `AssocOp::fixity` is that /// an operator can be both left and right associative (such as `+`: /// `a + b + c == (a + b) + c == a + (b + c)`. /// -/// Chained `as` and explicit `:` type coercion never need inner parenthesis so they are considered +/// Chained `as` and explicit `:` type coercion never need inner parenthesis so +/// they are considered /// associative. fn associativity(op: &AssocOp) -> Associativity { use syntax::util::parser::AssocOp::*; @@ -374,10 +385,14 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { }) } -/// Return the indentation before `span` if there are nothing but `[ \t]` before it on its line. +/// Return the indentation before `span` if there are nothing but `[ \t]` +/// before it on its line. fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> { let lo = cx.sess().codemap().lookup_char_pos(span.lo); - if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) { + if let Some(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') { // we can mix char and byte positions here because we only consider `[ \t]` if lo.col == CharPos(pos) { @@ -424,7 +439,10 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> { impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> { fn suggest_item_with_attr<D: Display + ?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D) { if let Some(indent) = indentation(cx, item) { - let span = Span { hi: item.lo, ..item }; + let span = Span { + hi: item.lo, + ..item + }; self.span_suggestion(span, msg, format!("{}\n{}", attr, indent)); } @@ -432,10 +450,14 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error 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() + let new_item = new_item + .lines() .map(|l| if first { first = false; format!("{}\n", l) diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 059f4e36a03..c864c9d2aeb 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -63,7 +63,10 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { let parent_item = cx.tcx.hir.get_parent(len.id); let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - if ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(len).is_ok() { + if ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables) + .eval(len) + .is_ok() + { format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() } else { return; @@ -84,12 +87,14 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { }, }; - span_lint_and_sugg(cx, - USELESS_VEC, - span, - "useless use of `vec!`", - "you can use a slice directly", - snippet); + span_lint_and_sugg( + cx, + USELESS_VEC, + span, + "useless use of `vec!`", + "you can use a slice directly", + snippet, + ); } /// Return the item type of the vector (ie. the `T` in `Vec<T>`). diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index b00d23d6fba..888cd339096 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -5,7 +5,8 @@ use utils::span_help_and_lint; /// **What it does:** Checks for `0.0 / 0.0`. /// -/// **Why is this bad?** It's less readable than `std::f32::NAN` or `std::f64::NAN`. +/// **Why is this bad?** It's less readable than `std::f32::NAN` or +/// `std::f64::NAN`. /// /// **Known problems:** None. /// diff --git a/src/main.rs b/src/main.rs index 266c1373ff2..8e92eb55ff0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,8 +46,13 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType, ) -> Compilation { - self.default - .early_callback(matches, sopts, cfg, descriptions, output) + self.default.early_callback( + matches, + sopts, + cfg, + descriptions, + output, + ) } fn no_input( &mut self, @@ -58,8 +63,14 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry, ) -> Option<(Input, Option<PathBuf>)> { - self.default - .no_input(matches, sopts, cfg, odir, ofile, descriptions) + self.default.no_input( + matches, + sopts, + cfg, + odir, + ofile, + descriptions, + ) } fn late_callback( &mut self, @@ -69,8 +80,13 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { odir: &Option<PathBuf>, ofile: &Option<PathBuf>, ) -> Compilation { - self.default - .late_callback(matches, sess, input, odir, ofile) + self.default.late_callback( + matches, + sess, + input, + odir, + ofile, + ) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); @@ -79,13 +95,17 @@ 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); @@ -179,9 +199,9 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - let manifest_path_arg = std::env::args() - .skip(2) - .find(|val| val.starts_with("--manifest-path=")); + let manifest_path_arg = std::env::args().skip(2).find(|val| { + val.starts_with("--manifest-path=") + }); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { @@ -191,55 +211,59 @@ pub fn main() { process::exit(101); }; - let manifest_path = manifest_path_arg.map(|arg| Path::new(&arg["--manifest-path=".len()..]) - .canonicalize().expect("manifest path could not be canonicalized")); + let manifest_path = manifest_path_arg.map(|arg| { + Path::new(&arg["--manifest-path=".len()..]) + .canonicalize() + .expect("manifest path could not be canonicalized") + }); let package_index = { - if let Some(manifest_path) = manifest_path { - metadata.packages.iter().position(|package| { + if let Some(manifest_path) = manifest_path { + metadata.packages.iter().position(|package| { + let package_manifest_path = Path::new(&package.manifest_path).canonicalize().expect( + "package manifest path could not be canonicalized", + ); + package_manifest_path == manifest_path + }) + } else { + let package_manifest_paths: HashMap<_, _> = metadata + .packages + .iter() + .enumerate() + .map(|(i, package)| { let package_manifest_path = Path::new(&package.manifest_path) - .canonicalize().expect("package manifest path could not be canonicalized"); - package_manifest_path == manifest_path + .parent() + .expect("could not find parent directory of package manifest") + .canonicalize() + .expect("package directory cannot be canonicalized"); + (package_manifest_path, i) }) - } else { - let package_manifest_paths: HashMap<_, _> = - metadata.packages.iter() - .enumerate() - .map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path) - .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - (package_manifest_path, i) - }) - .collect(); - - let current_dir = std::env::current_dir() - .expect("could not read current directory") - .canonicalize() - .expect("current directory cannot be canonicalized"); - - let mut current_path: &Path = ¤t_dir; - - // This gets the most-recent parent (the one that takes the fewest `cd ..`s to - // reach). - loop { - if let Some(&package_index) = package_manifest_paths.get(current_path) { - break Some(package_index); - } - else { - // We'll never reach the filesystem root, because to get to this point in the code - // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to - // unwrap the current path's parent. - current_path = current_path - .parent() - .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); - } + .collect(); + + let current_dir = std::env::current_dir() + .expect("could not read current directory") + .canonicalize() + .expect("current directory cannot be canonicalized"); + + let mut current_path: &Path = ¤t_dir; + + // This gets the most-recent parent (the one that takes the fewest `cd ..`s to + // reach). + loop { + if let Some(&package_index) = package_manifest_paths.get(current_path) { + break Some(package_index); + } else { + // We'll never reach the filesystem root, because to get to this point in the + // code + // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to + // unwrap the current path's parent. + current_path = current_path.parent().unwrap_or_else(|| { + panic!("could not find parent of path {}", current_path.display()) + }); } } } - .expect("could not find matching package"); + }.expect("could not find matching package"); let package = metadata.packages.remove(package_index); for target in package.targets { @@ -250,9 +274,12 @@ 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)) { + if let Err(code) = process( + vec![format!("--{}", first), target.name] + .into_iter() + .chain(args), + ) + { std::process::exit(code); } } @@ -280,7 +307,9 @@ pub fn main() { .and_then(|out| String::from_utf8(out.stdout).ok()) .map(|s| s.trim().to_owned()) }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") + .expect( + "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", + ) }; rustc_driver::in_rustc_thread(|| { @@ -310,13 +339,13 @@ pub fn main() { if let Err(CompileIncomplete::Errored(_)) = result { std::process::exit(1); } - }) - .expect("rustc_thread failed"); + }).expect("rustc_thread failed"); } } fn process<I>(old_args: I) -> Result<(), i32> - where I: Iterator<Item = String> +where + I: Iterator<Item = String>, { let mut args = vec!["rustc".to_owned()]; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index f7d0c69afb0..363eeced8a2 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -29,8 +29,6 @@ fn compile_test() { prepare_env(); run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); - #[cfg(target_os = "windows")] - run_mode("ui-windows", "ui"); - #[cfg(not(target_os = "windows"))] - run_mode("ui-posix", "ui"); + #[cfg(target_os = "windows")] run_mode("ui-windows", "ui"); + #[cfg(not(target_os = "windows"))] run_mode("ui-posix", "ui"); } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 7a2f6701501..378d14972aa 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -24,7 +24,9 @@ fn dogfood() { let mut s = String::new(); s.push_str(" -L target/debug/"); s.push_str(" -L target/debug/deps"); - s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal"); + s.push_str( + " -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal", + ); config.target_rustcflags = Some(s); if let Ok(name) = var("TESTNAME") { config.filter = Some(name.to_owned()) diff --git a/tests/issue-825.rs b/tests/issue-825.rs index 2d6c8ea384b..685715a111c 100644 --- a/tests/issue-825.rs +++ b/tests/issue-825.rs @@ -6,9 +6,10 @@ // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { 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[..] { + "u32" == &name[..] || "f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || + "i16" == &name[..] || "i32" == &name[..] || + "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..] + { unreachable!(); } } diff --git a/tests/matches.rs b/tests/matches.rs index ade8db2aa27..2f9a61ed768 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -19,14 +19,28 @@ fn test_overlapping() { assert_eq!(None, overlapping::<u8>(&[])); assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))])); assert_eq!(None, overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])); - assert_eq!(None, - overlapping(&[sp(1, Bound::Included(4)), - sp(5, Bound::Included(6)), - sp(10, Bound::Included(11))])); - assert_eq!(Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))), - overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])); - assert_eq!(Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))), - overlapping(&[sp(1, Bound::Included(4)), - sp(5, Bound::Included(6)), - sp(6, Bound::Included(11))])); + assert_eq!( + None, + overlapping( + &[ + sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(10, Bound::Included(11)), + ], + ) + ); + assert_eq!( + Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))), + overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))]) + ); + assert_eq!( + Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))), + overlapping( + &[ + sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(6, Bound::Included(11)), + ], + ) + ); } diff --git a/tests/needless_continue_helpers.rs b/tests/needless_continue_helpers.rs index 0fcef518030..a669b6f9477 100644 --- a/tests/needless_continue_helpers.rs +++ b/tests/needless_continue_helpers.rs @@ -86,4 +86,3 @@ fn test_erode_block() { println!("input: {}\nexpected:\n{}\ngot:\n{}", input, expected, got); assert_eq!(expected, got); } - -- cgit 1.4.1-3-g733a5 From 0e4c49b145a686c83fb669dabb39b9d13a9c6a97 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 9 Aug 2017 09:59:38 +0200 Subject: Handfix dogfood issues with the rustfmt changes --- clippy_lints/src/lifetimes.rs | 6 ++--- clippy_lints/src/missing_doc.rs | 1 + clippy_lints/src/non_expressive_names.rs | 41 +++++++------------------------- src/lib.rs | 15 ++++++------ 4 files changed, 20 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index dd721db0f09..21b8bf6b5f5 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -192,10 +192,10 @@ fn could_use_elision<'a, 'tcx: 'a>( // no output lifetimes, check distinctness of input lifetimes // only unnamed and static, ok - if input_lts.iter().all(|lt| { + let unnamed_and_static = input_lts.iter().all(|lt| { *lt == RefLt::Unnamed || *lt == RefLt::Static - }) - { + }); + if unnamed_and_static { return false; } // we have no output reference, so we only need all distinct lifetimes diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 17b3ad4d9e2..8f62494109f 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -21,6 +21,7 @@ // // // +// // rs#L246 // diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index fa915e83aed..a28dc42a8f0 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -104,26 +104,7 @@ fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { } fn whitelisted(interned_name: &str, list: &[&str]) -> bool { - if list.iter().any(|&name| interned_name == name) { - return true; - } - for name in list { - // name_* - if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) { - return true; - } - // *_name - if interned_name.chars().rev().zip(name.chars().rev()).all( - |(l, - r)| { - l == r - }, - ) - { - return true; - } - } - false + list.iter().any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name)) } impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { @@ -180,19 +161,19 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let first_e = existing_chars.next().expect( "we know we have at least one char", ); - let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric(); + let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); - if eq_or_numeric(first_i, first_e) { + if eq_or_numeric((first_i, first_e)) { let last_i = interned_chars.next_back().expect( "we know we have at least two chars", ); let last_e = existing_chars.next_back().expect( "we know we have at least two chars", ); - if eq_or_numeric(last_i, last_e) { + if eq_or_numeric((last_i, last_e)) { if interned_chars .zip(existing_chars) - .filter(|&(i, e)| !eq_or_numeric(i, e)) + .filter(|&ie| !eq_or_numeric(ie)) .count() != 1 { continue; @@ -204,10 +185,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let second_last_e = existing_chars.next_back().expect( "we know we have at least three chars", ); - if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| { - eq_or_numeric(i, e) - }) + if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' || + !interned_chars.zip(existing_chars).all(eq_or_numeric) { // allowed similarity foo_x, foo_y // or too many chars differ (foo_x, boo_y) or (foox, booy) @@ -222,10 +201,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let second_e = existing_chars.next().expect( "we know we have at least two chars", ); - if !eq_or_numeric(second_i, second_e) || second_i == '_' || - !interned_chars.zip(existing_chars).all(|(i, e)| { - eq_or_numeric(i, e) - }) + if !eq_or_numeric((second_i, second_e)) || second_i == '_' || + !interned_chars.zip(existing_chars).all(eq_or_numeric) { // allowed similarity x_foo, y_foo // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) diff --git a/src/lib.rs b/src/lib.rs index a1e18ecc9b4..df692b7e60c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,14 +12,13 @@ extern crate clippy_lints; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { 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; + for (lint, _, _) in lint_store.get_lint_groups() { + if lint == "clippy" { + reg.sess + .struct_warn("running cargo clippy on a crate that also imports the clippy plugin") + .emit(); + return; + } } } -- cgit 1.4.1-3-g733a5 From 1265b4647873932ede92cf06d6f2effc2f4f73b3 Mon Sep 17 00:00:00 2001 From: Benjamin Gill <git@bgill.eu> Date: Fri, 18 Aug 2017 17:57:33 +0100 Subject: Basic implementation of `cargo clippy --all` This implements workspace support for `cargo clippy` by running clippy over all packages in the workspace (in serial). This should probably be parallelised in future (as `cargo build --all`). --- src/main.rs | 138 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 8e92eb55ff0..2f4d782f78e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -152,6 +152,7 @@ Common options: -h, --help Print this message --features Features to compile for the package -V, --version Print version info and exit + --all @@@ something sensible here (copy from cargo-edit?) Other options are the same as `cargo rustc`. @@ -217,74 +218,85 @@ pub fn main() { .expect("manifest path could not be canonicalized") }); - let package_index = { - if let Some(manifest_path) = manifest_path { - metadata.packages.iter().position(|package| { - let package_manifest_path = Path::new(&package.manifest_path).canonicalize().expect( - "package manifest path could not be canonicalized", - ); - package_manifest_path == manifest_path - }) - } else { - let package_manifest_paths: HashMap<_, _> = metadata - .packages - .iter() - .enumerate() - .map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path) - .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - (package_manifest_path, i) + let packages = if std::env::args().any(|a| a == "--all" ) { + metadata.packages + } else { + let package_index = { + if let Some(manifest_path) = manifest_path { + metadata.packages.iter().position(|package| { + let package_manifest_path = Path::new(&package.manifest_path).canonicalize().expect( + "package manifest path could not be canonicalized", + ); + package_manifest_path == manifest_path }) - .collect(); - - let current_dir = std::env::current_dir() - .expect("could not read current directory") - .canonicalize() - .expect("current directory cannot be canonicalized"); - - let mut current_path: &Path = ¤t_dir; - - // This gets the most-recent parent (the one that takes the fewest `cd ..`s to - // reach). - loop { - if let Some(&package_index) = package_manifest_paths.get(current_path) { - break Some(package_index); - } else { - // We'll never reach the filesystem root, because to get to this point in the - // code - // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to - // unwrap the current path's parent. - current_path = current_path.parent().unwrap_or_else(|| { - panic!("could not find parent of path {}", current_path.display()) - }); + } else { + let package_manifest_paths: HashMap<_, _> = metadata + .packages + .iter() + .enumerate() + .map(|(i, package)| { + let package_manifest_path = Path::new(&package.manifest_path) + .parent() + .expect("could not find parent directory of package manifest") + .canonicalize() + .expect("package directory cannot be canonicalized"); + (package_manifest_path, i) + }) + .collect(); + + let current_dir = std::env::current_dir() + .expect("could not read current directory") + .canonicalize() + .expect("current directory cannot be canonicalized"); + + let mut current_path: &Path = ¤t_dir; + + // This gets the most-recent parent (the one that takes the fewest `cd ..`s to + // reach). + loop { + if let Some(&package_index) = package_manifest_paths.get(current_path) { + break Some(package_index); + } else { + // We'll never reach the filesystem root, because to get to this point in the + // code + // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to + // unwrap the current path's parent. + current_path = current_path.parent().unwrap_or_else(|| { + panic!("could not find parent of path {}", current_path.display()) + }); + } } } - } - }.expect("could not find matching package"); - - let package = metadata.packages.remove(package_index); - for target in package.targets { - let args = std::env::args().skip(2); - if let Some(first) = target.kind.get(0) { - if target.kind.len() > 1 || first.ends_with("lib") { - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { - 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), - ) - { - std::process::exit(code); + }.expect("could not find matching package"); + + vec![metadata.packages.remove(package_index)] + }; + + for package in packages { + let manifest_path = package.manifest_path; + + for target in package.targets { + let args = std::env::args().skip(2).filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); + + let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); + if let Some(first) = target.kind.get(0) { + if target.kind.len() > 1 || first.ends_with("lib") { + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { + 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), + ) + { + std::process::exit(code); + } } + } else { + panic!("badly formatted cargo metadata: target::kind is an empty array"); } - } else { - panic!("badly formatted cargo metadata: target::kind is an empty array"); } } } else { -- cgit 1.4.1-3-g733a5 From 5d72cc9b08db57030d29ed46783793c05cbee7dd Mon Sep 17 00:00:00 2001 From: Benjamin Gill <git@bgill.eu> Date: Fri, 18 Aug 2017 18:11:15 +0100 Subject: Run Rustfmt-nightly --- src/main.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 2f4d782f78e..d559ad14c33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] - #![allow(unknown_lints, missing_docs_in_private_items)] extern crate clippy_lints; @@ -12,9 +11,9 @@ extern crate rustc_errors; extern crate rustc_plugin; extern crate syntax; -use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation}; -use rustc::session::{config, Session, CompileIncomplete}; -use rustc::session::config::{Input, ErrorOutputType}; +use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; +use rustc::session::{config, CompileIncomplete, Session}; +use rustc::session::config::{ErrorOutputType, Input}; use std::collections::HashMap; use std::path::PathBuf; use std::process::{self, Command}; @@ -200,9 +199,9 @@ pub fn main() { if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is executed on the initial call to `cargo clippy` - let manifest_path_arg = std::env::args().skip(2).find(|val| { - val.starts_with("--manifest-path=") - }); + let manifest_path_arg = std::env::args() + .skip(2) + .find(|val| val.starts_with("--manifest-path=")); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { @@ -218,15 +217,15 @@ pub fn main() { .expect("manifest path could not be canonicalized") }); - let packages = if std::env::args().any(|a| a == "--all" ) { + let packages = if std::env::args().any(|a| a == "--all") { metadata.packages } else { let package_index = { if let Some(manifest_path) = manifest_path { metadata.packages.iter().position(|package| { - let package_manifest_path = Path::new(&package.manifest_path).canonicalize().expect( - "package manifest path could not be canonicalized", - ); + let package_manifest_path = Path::new(&package.manifest_path) + .canonicalize() + .expect("package manifest path could not be canonicalized"); package_manifest_path == manifest_path }) } else { @@ -261,9 +260,9 @@ pub fn main() { // code // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to // unwrap the current path's parent. - current_path = current_path.parent().unwrap_or_else(|| { - panic!("could not find parent of path {}", current_path.display()) - }); + current_path = current_path + .parent() + .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); } } } @@ -276,7 +275,9 @@ pub fn main() { let manifest_path = package.manifest_path; for target in package.targets { - let args = std::env::args().skip(2).filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); + let args = std::env::args() + .skip(2) + .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); if let Some(first) = target.kind.get(0) { @@ -289,8 +290,7 @@ pub fn main() { vec![format!("--{}", first), target.name] .into_iter() .chain(args), - ) - { + ) { std::process::exit(code); } } -- cgit 1.4.1-3-g733a5 From 6c665893d521b88f04bdfa010161760f489a225d Mon Sep 17 00:00:00 2001 From: Benjamin Gill <git@bgill.eu> Date: Sun, 20 Aug 2017 05:10:13 +0100 Subject: Add help text for `--all` --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index d559ad14c33..41909477bbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -151,7 +151,7 @@ Common options: -h, --help Print this message --features Features to compile for the package -V, --version Print version info and exit - --all @@@ something sensible here (copy from cargo-edit?) + --all Run over all packages in the current workspace Other options are the same as `cargo rustc`. -- cgit 1.4.1-3-g733a5 From 56068b1b671f6490c1be9ea3834784e89a0a4ba7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 21 Aug 2017 12:57:33 +0200 Subject: Fix ICE #1969 --- clippy_lints/src/functions.rs | 8 ++++++-- src/main.rs | 2 +- tests/run-pass/ice-1969.rs | 13 +++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/ice-1969.rs (limited to 'src') diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 1bb8780ea4a..9d9bf38c397 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,6 +1,7 @@ use rustc::hir::intravisit; use rustc::hir; use rustc::lint::*; +use rustc::ty; use std::collections::HashSet; use syntax::ast; use syntax::abi::Abi; @@ -150,9 +151,11 @@ impl<'a, 'tcx> Functions { .collect::<HashSet<_>>(); if !raw_ptrs.is_empty() { + let tables = cx.tcx.body_tables(body.id()); let mut v = DerefVisitor { cx: cx, ptrs: raw_ptrs, + tables, }; hir::intravisit::walk_expr(&mut v, expr); @@ -172,13 +175,14 @@ fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<hir::def_id::DefId> { struct DerefVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, ptrs: HashSet<hir::def_id::DefId>, + tables: &'a ty::TypeckTables<'tcx>, } 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.tables.expr_ty(f); + let ty = self.tables.expr_ty(f); if type_is_unsafe_function(self.cx, ty) { for arg in args { @@ -187,7 +191,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } }, hir::ExprMethodCall(_, _, ref args) => { - let def_id = self.cx.tables.type_dependent_defs()[expr.hir_id].def_id(); + let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id(); let base_type = self.cx.tcx.type_of(def_id); if type_is_unsafe_function(self.cx, base_type) { diff --git a/src/main.rs b/src/main.rs index 8e92eb55ff0..8e8ed032c1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ struct ClippyCompilerCalls { impl ClippyCompilerCalls { fn new(run_lints: bool) -> Self { - ClippyCompilerCalls { + Self { default: RustcDefaultCalls, run_lints: run_lints, } diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs new file mode 100644 index 00000000000..23a002a5cde --- /dev/null +++ b/tests/run-pass/ice-1969.rs @@ -0,0 +1,13 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(clippy)] + +fn main() { } + +pub trait Convert { + type Action: From<*const f64>; + + fn convert(val: *const f64) -> Self::Action { + val.into() + } +} -- cgit 1.4.1-3-g733a5 From e4524ac4de5327a4c25a3ba8f0fcdd0ccfc7523d Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 5 Sep 2017 11:33:04 +0200 Subject: Run nightly rustfmt --- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/arithmetic.rs | 15 +- clippy_lints/src/array_indexing.rs | 46 ++- clippy_lints/src/assign_ops.rs | 40 ++- clippy_lints/src/attrs.rs | 31 +- clippy_lints/src/bit_mask.rs | 202 ++++++------ clippy_lints/src/blacklisted_name.rs | 4 +- clippy_lints/src/block_in_if_condition.rs | 20 +- clippy_lints/src/booleans.rs | 112 +++---- clippy_lints/src/bytecount.rs | 17 +- clippy_lints/src/collapsible_if.rs | 15 +- clippy_lints/src/consts.rs | 72 ++--- clippy_lints/src/copies.rs | 42 +-- clippy_lints/src/cyclomatic_complexity.rs | 30 +- clippy_lints/src/derive.rs | 42 +-- clippy_lints/src/doc.rs | 20 +- clippy_lints/src/double_parens.rs | 35 +- clippy_lints/src/drop_forget_ref.rs | 10 +- clippy_lints/src/empty_enum.rs | 5 +- clippy_lints/src/entry.rs | 13 +- clippy_lints/src/enum_clike.rs | 7 +- clippy_lints/src/enum_glob_use.rs | 2 +- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/eq_op.rs | 5 +- clippy_lints/src/escape.rs | 1 - clippy_lints/src/eta_reduction.rs | 9 +- clippy_lints/src/eval_order_dependence.rs | 56 ++-- clippy_lints/src/format.rs | 8 +- clippy_lints/src/formatting.rs | 17 +- clippy_lints/src/functions.rs | 6 +- clippy_lints/src/identity_op.rs | 13 +- .../src/if_let_redundant_pattern_matching.rs | 28 +- clippy_lints/src/infinite_iter.rs | 70 ++-- clippy_lints/src/is_unit_expr.rs | 25 +- clippy_lints/src/items_after_statements.rs | 9 +- clippy_lints/src/large_enum_variant.rs | 19 +- clippy_lints/src/len_zero.rs | 66 ++-- clippy_lints/src/lib.rs | 15 +- clippy_lints/src/lifetimes.rs | 45 +-- clippy_lints/src/literal_digit_grouping.rs | 50 ++- clippy_lints/src/loops.rs | 307 +++++++++--------- clippy_lints/src/map_clone.rs | 32 +- clippy_lints/src/matches.rs | 118 +++---- clippy_lints/src/mem_forget.rs | 3 +- clippy_lints/src/methods.rs | 92 +++--- clippy_lints/src/minmax.rs | 8 +- clippy_lints/src/misc.rs | 48 ++- clippy_lints/src/misc_early.rs | 42 ++- clippy_lints/src/missing_doc.rs | 38 ++- clippy_lints/src/mut_mut.rs | 31 +- clippy_lints/src/mut_reference.rs | 43 +-- clippy_lints/src/mutex_atomic.rs | 4 +- clippy_lints/src/needless_bool.rs | 38 +-- clippy_lints/src/needless_borrow.rs | 34 +- clippy_lints/src/needless_borrowed_ref.rs | 4 +- clippy_lints/src/needless_continue.rs | 41 +-- clippy_lints/src/needless_pass_by_value.rs | 35 +- clippy_lints/src/new_without_default.rs | 61 ++-- clippy_lints/src/no_effect.rs | 99 +++--- clippy_lints/src/non_expressive_names.rs | 67 ++-- clippy_lints/src/ok_if_let.rs | 2 +- clippy_lints/src/open_options.rs | 15 +- clippy_lints/src/panic.rs | 2 +- clippy_lints/src/precedence.rs | 6 +- clippy_lints/src/print.rs | 4 +- clippy_lints/src/ptr.rs | 24 +- clippy_lints/src/ranges.rs | 4 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/regex.rs | 72 ++--- clippy_lints/src/returns.rs | 14 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/shadow.rs | 116 +++---- clippy_lints/src/should_assert_eq.rs | 2 +- clippy_lints/src/strings.rs | 14 +- clippy_lints/src/temporary_assignment.rs | 7 +- clippy_lints/src/transmute.rs | 169 +++++----- clippy_lints/src/types.rs | 354 +++++++++------------ clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unsafe_removed_from_name.rs | 12 +- clippy_lints/src/unused_io_amount.rs | 17 +- clippy_lints/src/unused_label.rs | 12 +- clippy_lints/src/use_self.rs | 6 +- clippy_lints/src/utils/author.rs | 66 ++-- clippy_lints/src/utils/conf.rs | 23 +- clippy_lints/src/utils/higher.rs | 72 ++--- clippy_lints/src/utils/hir_utils.rs | 19 +- clippy_lints/src/utils/inspector.rs | 23 +- clippy_lints/src/utils/internal_lints.rs | 37 ++- clippy_lints/src/utils/mod.rs | 201 ++++++------ clippy_lints/src/utils/sugg.rs | 58 ++-- clippy_lints/src/vec.rs | 12 +- clippy_lints/src/zero_div_zero.rs | 2 +- mini-macro/src/lib.rs | 7 +- src/main.rs | 45 +-- tests/compile-test.rs | 6 +- tests/dogfood.rs | 2 +- tests/issue-825.rs | 8 +- tests/matches.rs | 24 +- tests/needless_continue_helpers.rs | 3 +- 99 files changed, 1791 insertions(+), 2048 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index cbe12e58119..9d5d87dc4b3 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::hir::*; use std::f64::consts as f64; -use syntax::ast::{Lit, LitKind, FloatTy}; +use syntax::ast::{FloatTy, Lit, LitKind}; use syntax::symbol; use utils::span_lint; @@ -91,7 +91,7 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &symbol::Symbol, module: &s e.span, &format!( "approximate value of `{}::consts::{}` found. \ - Consider using it directly", + Consider using it directly", module, &name ), diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 8c370213f80..a551ebf046b 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -55,8 +55,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { match expr.node { hir::ExprBinary(ref op, ref l, ref r) => { match op.node { - hir::BiAnd | hir::BiOr | hir::BiBitAnd | hir::BiBitOr | hir::BiBitXor | hir::BiShl | - hir::BiShr | hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => return, + hir::BiAnd | + hir::BiOr | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiBitXor | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => return, _ => (), } let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r)); diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index 422935fa067..5815f645686 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -3,7 +3,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty; use rustc::ty::subst::Substs; use rustc_const_eval::ConstContext; -use rustc_const_math::{ConstUsize, ConstIsize, ConstInt}; +use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc::hir; use syntax::ast::RangeLimits; use utils::{self, higher}; @@ -124,29 +124,27 @@ fn to_const_range( }; let end = match *end { - Some(Some(ConstVal::Integral(x))) => { - if limits == RangeLimits::Closed { - match x { - ConstInt::U8(_) => (x + ConstInt::U8(1)), - ConstInt::U16(_) => (x + ConstInt::U16(1)), - ConstInt::U32(_) => (x + ConstInt::U32(1)), - ConstInt::U64(_) => (x + ConstInt::U64(1)), - ConstInt::U128(_) => (x + ConstInt::U128(1)), - ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))), - ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))), - ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))), - ConstInt::I8(_) => (x + ConstInt::I8(1)), - ConstInt::I16(_) => (x + ConstInt::I16(1)), - ConstInt::I32(_) => (x + ConstInt::I32(1)), - ConstInt::I64(_) => (x + ConstInt::I64(1)), - ConstInt::I128(_) => (x + ConstInt::I128(1)), - ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))), - ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))), - ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))), - }.expect("such a big array is not realistic") - } else { - x - } + Some(Some(ConstVal::Integral(x))) => if limits == RangeLimits::Closed { + match x { + ConstInt::U8(_) => (x + ConstInt::U8(1)), + ConstInt::U16(_) => (x + ConstInt::U16(1)), + ConstInt::U32(_) => (x + ConstInt::U32(1)), + ConstInt::U64(_) => (x + ConstInt::U64(1)), + ConstInt::U128(_) => (x + ConstInt::U128(1)), + ConstInt::Usize(ConstUsize::Us16(_)) => (x + ConstInt::Usize(ConstUsize::Us16(1))), + ConstInt::Usize(ConstUsize::Us32(_)) => (x + ConstInt::Usize(ConstUsize::Us32(1))), + ConstInt::Usize(ConstUsize::Us64(_)) => (x + ConstInt::Usize(ConstUsize::Us64(1))), + ConstInt::I8(_) => (x + ConstInt::I8(1)), + ConstInt::I16(_) => (x + ConstInt::I16(1)), + ConstInt::I32(_) => (x + ConstInt::I32(1)), + ConstInt::I64(_) => (x + ConstInt::I64(1)), + ConstInt::I128(_) => (x + ConstInt::I128(1)), + ConstInt::Isize(ConstIsize::Is16(_)) => (x + ConstInt::Isize(ConstIsize::Is16(1))), + ConstInt::Isize(ConstIsize::Is32(_)) => (x + ConstInt::Isize(ConstIsize::Is32(1))), + ConstInt::Isize(ConstIsize::Is64(_)) => (x + ConstInt::Isize(ConstIsize::Is64(1))), + }.expect("such a big array is not realistic") + } 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 759bb9f12ec..33a1d94f420 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,7 +1,7 @@ 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::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq}; use utils::{higher, sugg}; /// **What it does:** Checks for compound assignment operations (`+=` and @@ -88,19 +88,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { if let hir::ExprBinary(binop, ref l, ref r) = rhs.node { if op.node == binop.node { let lint = |assignee: &hir::Expr, rhs: &hir::Expr| { - span_lint_and_then(cx, - MISREFACTORED_ASSIGN_OP, - 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)); - }); + span_lint_and_then( + cx, + MISREFACTORED_ASSIGN_OP, + 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), + ); + }, + ); }; // lhs op= l op r if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) { @@ -167,8 +169,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { BitXor: BiBitXor, Shr: BiShr, Shl: BiShl - ) - { + ) { span_lint_and_then( cx, ASSIGN_OP_PATTERN, @@ -193,7 +194,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { // a = b commutative_op a if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { match op.node { - hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd | + hir::BiAdd | + hir::BiMul | + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | hir::BiBitOr => { lint(assignee, l); }, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 86d72226601..12339c039d9 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt}; use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use syntax::codemap::Span; -use utils::{in_macro, match_def_path, paths, span_lint, span_lint_and_then, snippet_opt}; +use utils::{in_macro, match_def_path, paths, snippet_opt, span_lint, span_lint_and_then}; /// **What it does:** Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. @@ -110,8 +110,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { check_attrs(cx, item.span, &item.name, &item.attrs) } match item.node { - ItemExternCrate(_) | - ItemUse(_, _) => { + ItemExternCrate(_) | ItemUse(_, _) => { for attr in &item.attrs { if let Some(ref lint_list) = attr.meta_item_list() { if let Some(name) = attr.name() { @@ -196,14 +195,13 @@ fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> b if let Some(stmt) = block.stmts.first() { match stmt.node { StmtDecl(_, _) => true, - StmtExpr(ref expr, _) | - StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr), + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr), } } else { - block.expr.as_ref().map_or( - false, - |e| is_relevant_expr(tcx, tables, e), - ) + block + .expr + .as_ref() + .map_or(false, |e| is_relevant_expr(tcx, tables, e)) } } @@ -211,15 +209,12 @@ fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool match expr.node { ExprBlock(ref block) => is_relevant_block(tcx, tables, block), ExprRet(Some(ref e)) => is_relevant_expr(tcx, tables, e), - ExprRet(None) | - ExprBreak(_, None) => false, - ExprCall(ref path_expr, _) => { - if let ExprPath(ref qpath) = path_expr.node { - let fun_id = tables.qpath_def(qpath, path_expr.hir_id).def_id(); - !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC) - } else { - true - } + ExprRet(None) | ExprBreak(_, None) => false, + ExprCall(ref path_expr, _) => if let ExprPath(ref qpath) = path_expr.node { + let fun_id = tables.qpath_def(qpath, path_expr.hir_id).def_id(); + !match_def_path(tcx, 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 6e5a18240cb..ecb12b60a16 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -158,118 +158,100 @@ fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u12 fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u128, cmp_value: u128, span: &Span) { match cmp_op { - BiEq | BiNe => { - match bit_op { - BiBitAnd => { - if mask_value & cmp_value != cmp_value { - if cmp_value != 0 { - span_lint( - cx, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ & {}` can never be equal to `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ | {}` can never be equal to `{}`", - mask_value, - cmp_value - ), - ); - } - }, - _ => (), - } + BiEq | BiNe => match bit_op { + BiBitAnd => if mask_value & cmp_value != cmp_value { + if cmp_value != 0 { + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` can never be equal to `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` can never be equal to `{}`", + mask_value, + cmp_value + ), + ); + }, + _ => (), }, - BiLt | BiGe => { - match bit_op { - BiBitAnd => { - if mask_value < cmp_value { - span_lint( - cx, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ & {}` will always be lower than `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ | {}` will never be lower than `{}`", - mask_value, - cmp_value - ), - ); - } else { - check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); - } - }, - BiBitXor => check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"), - _ => (), - } + BiLt | BiGe => match bit_op { + BiBitAnd => if mask_value < cmp_value { + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` will always be lower than `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` will never be lower than `{}`", + mask_value, + cmp_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 => { - if mask_value <= cmp_value { - span_lint( - cx, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ & {}` will never be higher than `{}`", - mask_value, - cmp_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, - BAD_BIT_MASK, - *span, - &format!( - "incompatible bit mask: `_ | {}` will always be higher than `{}`", - mask_value, - cmp_value - ), - ); - } else { - check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); - } - }, - BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), - _ => (), - } + BiLe | BiGt => match bit_op { + BiBitAnd => if mask_value <= cmp_value { + span_lint( + cx, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ & {}` will never be higher than `{}`", + mask_value, + cmp_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, + BAD_BIT_MASK, + *span, + &format!( + "incompatible bit mask: `_ | {}` will always be higher than `{}`", + mask_value, + cmp_value + ), + ); + } else { + check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); + }, + BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), + _ => (), }, _ => (), } diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index e46d8e4855f..114ba5fa782 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -27,7 +27,9 @@ pub struct BlackListedName { impl BlackListedName { pub fn new(blacklist: Vec<String>) -> Self { - Self { blacklist: blacklist } + Self { + blacklist: blacklist, + } } } diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 82a3eb00ab7..d67a1a5394e 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::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use utils::*; /// **What it does:** Checks for `if` conditions that use blocks to contain an @@ -93,15 +93,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { check.span, BRACED_EXPR_MESSAGE, &format!("try\nif {} {} ... ", - snippet_block(cx, ex.span, ".."), - snippet_block(cx, then.span, "..")), + snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, "..")), ); } } else { - let span = block.expr.as_ref().map_or_else( - || block.stmts[0].span, - |e| e.span, - ); + let span = block + .expr + .as_ref() + .map_or_else(|| block.stmts[0].span, |e| e.span); if in_macro(span) || differing_macro_contexts(expr.span, span) { return; } @@ -112,8 +112,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { check.span, COMPLEX_BLOCK_MESSAGE, &format!("try\nlet res = {};\nif res {} ... ", - snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, "..")), + snippet_block(cx, block.span, ".."), + snippet_block(cx, then.span, "..")), ); } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 7c7dbe80883..2587937616c 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::*; use rustc::hir::intravisit::*; -use syntax::ast::{LitKind, DUMMY_NODE_ID, NodeId}; -use syntax::codemap::{DUMMY_SP, dummy_spanned, Span}; +use syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID}; +use syntax::codemap::{dummy_spanned, Span, DUMMY_SP}; use syntax::util::ThinVec; -use utils::{span_lint_and_then, in_macro, snippet_opt, SpanlessEq}; +use utils::{in_macro, snippet_opt, span_lint_and_then, SpanlessEq}; /// **What it does:** Checks for boolean expressions that can be written more /// concisely. @@ -96,26 +96,23 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { if !in_macro(e.span) { match e.node { ExprUnary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)), - ExprBinary(binop, ref lhs, ref rhs) => { - match binop.node { - BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), - BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)), - _ => (), - } + ExprBinary(binop, ref lhs, ref rhs) => match binop.node { + BiOr => return Ok(Bool::Or(self.extract(BiOr, &[lhs, rhs], Vec::new())?)), + 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), - _ => (), - } + ExprLit(ref lit) => match lit.node { + LitKind::Bool(true) => return Ok(Bool::True), + LitKind::Bool(false) => return Ok(Bool::False), + _ => (), }, _ => (), } } for (n, expr) in self.terminals.iter().enumerate() { if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { - #[allow(cast_possible_truncation)] return Ok(Bool::Term(n as u8)); + #[allow(cast_possible_truncation)] + return Ok(Bool::Term(n as u8)); } let negated = match e.node { ExprBinary(binop, ref lhs, ref rhs) => { @@ -141,13 +138,15 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => continue, }; if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { - #[allow(cast_possible_truncation)] return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); + #[allow(cast_possible_truncation)] + return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); } } let n = self.terminals.len(); self.terminals.push(e); if n < 32 { - #[allow(cast_possible_truncation)] Ok(Bool::Term(n as u8)) + #[allow(cast_possible_truncation)] + Ok(Bool::Term(n as u8)) } else { Err("too many literals".to_owned()) } @@ -167,40 +166,36 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String { 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 { - BiEq => " != ", - BiNe => " == ", - BiLt => " >= ", - BiGt => " <= ", - BiLe => " > ", - BiGe => " < ", - _ => { - s.push('!'); - return recurse(true, cx, inner, terminals, s); - }, - }; - s.push_str(&snip(lhs)); - s.push_str(op); - s.push_str(&snip(rhs)); - s - } else { + 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 { + BiEq => " != ", + BiNe => " == ", + BiLt => " >= ", + BiGt => " <= ", + BiLe => " > ", + BiGe => " < ", + _ => { s.push('!'); - recurse(false, cx, inner, terminals, s) - } - }, - _ => { - s.push('!'); - recurse(false, cx, inner, terminals, s) - }, - } + return recurse(true, cx, inner, terminals, s); + }, + }; + s.push_str(&snip(lhs)); + s.push_str(op); + s.push_str(&snip(rhs)); + s + } else { + s.push('!'); + recurse(false, cx, inner, terminals, s) + }, + _ => { + s.push('!'); + recurse(false, cx, inner, terminals, s) + }, }, And(ref v) => { if brackets { @@ -319,7 +314,6 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { cx: self.cx, }; if let Ok(expr) = h2q.run(e) { - if h2q.terminals.len() > 8 { // QMC has exponentially slow behavior as the number of terminals increases // 8 is reasonable, it takes approximately 0.2 seconds. @@ -360,7 +354,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { db.span_help( h2q.terminals[i].span, "this expression can be optimized out by applying boolean operations to the \ - outer expression", + outer expression", ); db.span_suggestion( e.span, @@ -411,12 +405,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } match e.node { ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e), - ExprUnary(UnNot, ref inner) => { - if self.cx.tables.node_types()[inner.hir_id].is_bool() { - self.bool_expr(e); - } else { - walk_expr(self, e); - } + ExprUnary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() { + self.bool_expr(e); + } else { + walk_expr(self, e); }, _ => walk_expr(self, e), } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 1d7afbe084d..447214c70f8 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -97,23 +97,18 @@ fn get_pat_name(pat: &Pat) -> Option<Name> { match pat.node { PatKind::Binding(_, _, ref spname, _) => Some(spname.node), PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.name), - PatKind::Box(ref p) | - PatKind::Ref(ref p, _) => get_pat_name(&*p), + PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p), _ => None, } } fn get_path_name(expr: &Expr) -> Option<Name> { match expr.node { - ExprBox(ref e) | - ExprAddrOf(_, ref e) | - ExprUnary(UnOp::UnDeref, ref e) => get_path_name(e), - ExprBlock(ref b) => { - if b.stmts.is_empty() { - b.expr.as_ref().and_then(|p| get_path_name(p)) - } else { - None - } + ExprBox(ref e) | ExprAddrOf(_, ref e) | ExprUnary(UnOp::UnDeref, ref e) => get_path_name(e), + ExprBlock(ref b) => if b.stmts.is_empty() { + b.expr.as_ref().and_then(|p| get_path_name(p)) + } else { + None }, ExprPath(ref qpath) => single_segment_path(qpath).map(|ps| ps.name), _ => None, diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 1914b83e898..fb0ff23cc63 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -15,7 +15,7 @@ use rustc::lint::*; use syntax::ast; -use utils::{in_macro, snippet_block, span_lint_and_then, span_lint_and_sugg}; +use utils::{in_macro, snippet_block, span_lint_and_sugg, span_lint_and_then}; use utils::sugg::Sugg; /// **What it does:** Checks for nested `if` statements which can be collapsed @@ -87,12 +87,10 @@ impl EarlyLintPass for CollapsibleIf { fn check_if(cx: &EarlyContext, expr: &ast::Expr) { match expr.node { - ast::ExprKind::If(ref check, ref then, ref else_) => { - if let Some(ref else_) = *else_ { - check_collapsible_maybe_if_let(cx, else_); - } else { - check_collapsible_no_if_let(cx, expr, check, then); - } + ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ { + check_collapsible_maybe_if_let(cx, else_); + } else { + check_collapsible_no_if_let(cx, expr, check, then); }, ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => { check_collapsible_maybe_if_let(cx, else_); @@ -147,8 +145,7 @@ fn expr_block(block: &ast::Block) -> Option<&ast::Expr> { 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 0a76b95931d..de62990afd5 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -5,8 +5,8 @@ use rustc::hir::def::Def; use rustc_const_eval::lookup_const_by_id; use rustc_const_math::ConstInt; use rustc::hir::*; -use rustc::ty::{self, TyCtxt, Ty}; -use rustc::ty::subst::{Substs, Subst}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Subst, Substs}; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; @@ -76,7 +76,7 @@ impl PartialEq for Constant { (&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, (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, - _ => false, //TODO: Are there inter-type equalities? + _ => false, // TODO: Are there inter-type equalities? } } } @@ -110,8 +110,7 @@ impl Hash for Constant { Constant::Bool(b) => { b.hash(state); }, - Constant::Vec(ref v) | - Constant::Tuple(ref v) => { + Constant::Vec(ref v) | Constant::Tuple(ref v) => { v.hash(state); }, Constant::Repeat(ref c, l) => { @@ -125,12 +124,10 @@ impl Hash for Constant { impl PartialOrd for Constant { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { match (self, other) { - (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => { - if l_sty == r_sty { - Some(ls.cmp(rs)) - } else { - None - } + (&Constant::Str(ref ls, ref l_sty), &Constant::Str(ref rs, ref r_sty)) => if l_sty == r_sty { + Some(ls.cmp(rs)) + } else { + None }, (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), (&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)), @@ -147,15 +144,14 @@ impl PartialOrd for Constant { } }, (&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), - (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => { - match lv.partial_cmp(rv) { - Some(Equal) => Some(ls.cmp(rs)), - x => x, - } + (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Vec(ref l), &Constant::Vec(ref r)) => { + l.partial_cmp(r) + }, + (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => match lv.partial_cmp(rv) { + Some(Equal) => Some(ls.cmp(rs)), + x => x, }, - _ => None, //TODO: Are there any useful inter-type orderings? + _ => None, // TODO: Are there any useful inter-type orderings? } } } @@ -177,18 +173,14 @@ pub fn lit_to_constant<'a, 'tcx>(lit: &LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut LitKind::Byte(b) => Constant::Int(ConstInt::U8(b)), LitKind::ByteStr(ref s) => Constant::Binary(s.clone()), LitKind::Char(c) => Constant::Char(c), - LitKind::Int(n, hint) => { - match (&ty.sty, hint) { - (&ty::TyInt(ity), _) | - (_, Signed(ity)) => { - Constant::Int(ConstInt::new_signed_truncating(n as i128, ity, tcx.sess.target.int_type)) - }, - (&ty::TyUint(uty), _) | - (_, Unsigned(uty)) => { - Constant::Int(ConstInt::new_unsigned_truncating(n as u128, uty, tcx.sess.target.uint_type)) - }, - _ => bug!(), - } + LitKind::Int(n, hint) => match (&ty.sty, hint) { + (&ty::TyInt(ity), _) | (_, Signed(ity)) => { + Constant::Int(ConstInt::new_signed_truncating(n as i128, ity, tcx.sess.target.int_type)) + }, + (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { + Constant::Int(ConstInt::new_unsigned_truncating(n as u128, uty, tcx.sess.target.uint_type)) + }, + _ => bug!(), }, LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), @@ -262,13 +254,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { }; self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) }, - ExprUnary(op, ref operand) => { - self.expr(operand).and_then(|o| match op { - UnNot => constant_not(&o), - UnNeg => constant_negate(o), - UnDeref => Some(o), - }) - }, + ExprUnary(op, ref operand) => self.expr(operand).and_then(|o| match op { + UnNot => constant_not(&o), + UnNeg => constant_negate(o), + UnDeref => Some(o), + }), ExprBinary(op, ref left, ref right) => self.binop(op, left, right), // TODO: add other expressions _ => None, @@ -287,8 +277,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { fn fetch_path(&mut self, qpath: &QPath, id: HirId) -> Option<Constant> { let def = self.tables.qpath_def(qpath, id); match def { - Def::Const(def_id) | - Def::AssociatedConst(def_id) => { + Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); let substs = if self.substs.is_empty() { substs @@ -358,8 +347,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { (BiRem, Constant::Int(l), Some(Constant::Int(r))) => (l % r).ok().map(Constant::Int), (BiAnd, Constant::Bool(false), _) => Some(Constant::Bool(false)), (BiOr, Constant::Bool(true), _) => Some(Constant::Bool(true)), - (BiAnd, Constant::Bool(true), Some(r)) | - (BiOr, Constant::Bool(false), Some(r)) => Some(r), + (BiAnd, Constant::Bool(true), Some(r)) | (BiOr, Constant::Bool(false), Some(r)) => Some(r), (BiBitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), (BiBitXor, Constant::Int(l), Some(Constant::Int(r))) => (l ^ r).ok().map(Constant::Int), (BiBitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f9e11d06882..862272456ea 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -6,7 +6,7 @@ use std::collections::hash_map::Entry; use syntax::symbol::InternedString; use syntax::util::small_vector::SmallVector; use utils::{SpanlessEq, SpanlessHash}; -use utils::{get_parent_expr, in_macro, span_lint_and_then, span_note_and_lint, snippet}; +use utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint}; /// **What it does:** Checks for consecutive `if`s with the same condition. /// @@ -114,7 +114,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if !in_macro(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) { + if let Some(&Expr { + node: ExprIf(_, _, Some(ref else_expr)), + .. + }) = get_parent_expr(cx, expr) + { if else_expr.id == expr.id { return; } @@ -267,12 +271,9 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) { fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<InternedString, Ty<'tcx>> { fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<InternedString, Ty<'tcx>>) { match pat.node { - PatKind::Box(ref pat) | - PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), - PatKind::TupleStruct(_, ref pats, _) => { - for pat in pats { - bindings_impl(cx, pat, map); - } + PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), + PatKind::TupleStruct(_, ref pats, _) => for pat in pats { + bindings_impl(cx, pat, map); }, PatKind::Binding(_, _, ref ident, ref as_pat) => { if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { @@ -282,15 +283,11 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned bindings_impl(cx, as_pat, map); } }, - PatKind::Struct(_, ref fields, _) => { - for pat in fields { - bindings_impl(cx, &pat.node.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::Tuple(ref fields, _) => for pat in fields { + bindings_impl(cx, pat, map); }, PatKind::Slice(ref lhs, ref mid, ref rhs) => { for pat in lhs { @@ -303,10 +300,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned bindings_impl(cx, pat, map); } }, - PatKind::Lit(..) | - PatKind::Range(..) | - PatKind::Wild | - PatKind::Path(..) => (), + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (), } } @@ -335,11 +329,9 @@ where for expr in exprs { match map.entry(hash(expr)) { - Entry::Occupied(o) => { - for o in o.get() { - if eq(o, expr) { - return Some((o, expr)); - } + Entry::Occupied(o) => for o in o.get() { + if eq(o, expr) { + return Some((o, expr)); } }, Entry::Vacant(v) => { diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index edfa5e0fb61..ede9dcb1fbd 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -4,11 +4,11 @@ use rustc::cfg::CFG; use rustc::lint::*; use rustc::hir::*; use rustc::ty; -use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use syntax::ast::{Attribute, NodeId}; use syntax::codemap::Span; -use utils::{in_macro, LimitStack, span_help_and_lint, paths, match_type, is_allowed}; +use utils::{in_macro, is_allowed, match_type, paths, span_help_and_lint, LimitStack}; /// **What it does:** Checks for methods with high cyclomatic complexity. /// @@ -31,7 +31,9 @@ pub struct CyclomaticComplexity { impl CyclomaticComplexity { pub fn new(limit: u64) -> Self { - Self { limit: LimitStack::new(limit) } + Self { + limit: LimitStack::new(limit), + } } } @@ -125,18 +127,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity { } fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { - self.limit.push_attrs( - cx.sess(), - attrs, - "cyclomatic_complexity", - ); + self.limit + .push_attrs(cx.sess(), attrs, "cyclomatic_complexity"); } fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { - self.limit.pop_attrs( - cx.sess(), - attrs, - "cyclomatic_complexity", - ); + self.limit + .pop_attrs(cx.sess(), attrs, "cyclomatic_complexity"); } } @@ -194,7 +190,7 @@ fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, re span_bug!( span, "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ - div = {}, shorts = {}, returns = {}. Please file a bug report.", + div = {}, shorts = {}, returns = {}. Please file a bug report.", cc, narms, div, @@ -210,9 +206,9 @@ fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, r span, &format!( "Clippy encountered a bug calculating cyclomatic complexity \ - (hide this message with `#[allow(cyclomatic_complexity)]`): \ - cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \ - Please file a bug report.", + (hide this message with `#[allow(cyclomatic_complexity)]`): \ + cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \ + Please file a bug report.", cc, narms, div, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 36576365eac..b70e591f995 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -3,7 +3,7 @@ use rustc::ty::{self, Ty}; use rustc::hir::*; use syntax::codemap::Span; use utils::paths; -use utils::{is_automatically_derived, span_lint_and_then, match_path, is_copy}; +use utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` /// explicitly. @@ -141,31 +141,31 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref ty::TyAdt(def, _) if def.is_union() => return, // Some types are not Clone by default but could be cloned “by hand” if necessary - ty::TyAdt(def, substs) => { - for variant in &def.variants { - for field in &variant.fields { - match field.ty(cx.tcx, substs).sty { - ty::TyArray(_, size) if size > 32 => { - return; - }, - ty::TyFnPtr(..) => { - return; - }, - ty::TyTuple(tys, _) if tys.len() > 12 => { - return; - }, - _ => (), - } + ty::TyAdt(def, substs) => for variant in &def.variants { + for field in &variant.fields { + match field.ty(cx.tcx, substs).sty { + ty::TyArray(_, size) if size > 32 => { + return; + }, + ty::TyFnPtr(..) => { + return; + }, + ty::TyTuple(tys, _) if tys.len() > 12 => { + return; + }, + _ => (), } } }, _ => (), } - span_lint_and_then(cx, - EXPL_IMPL_CLONE_ON_COPY, - item.span, - "you are implementing `Clone` explicitly on a `Copy` type", - |db| { db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); }); + span_lint_and_then( + cx, + EXPL_IMPL_CLONE_ON_COPY, + item.span, + "you are implementing `Clone` explicitly on a `Copy` type", + |db| { 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 8977ea437d1..170ca5cf007 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -2,7 +2,7 @@ use itertools::Itertools; use pulldown_cmark; use rustc::lint::*; use syntax::ast; -use syntax::codemap::{Span, BytePos}; +use syntax::codemap::{BytePos, Span}; use syntax_pos::Pos; use utils::span_lint; @@ -37,7 +37,9 @@ pub struct Doc { impl Doc { pub fn new(valid_idents: Vec<String>) -> Self { - Self { valid_idents: valid_idents } + Self { + valid_idents: valid_idents, + } } } @@ -196,17 +198,13 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( for (offset, event) in docs { match event { - Start(CodeBlock(_)) | - Start(Code) => in_code = true, - End(CodeBlock(_)) | - End(Code) => in_code = false, - Start(_tag) | End(_tag) => (), // We don't care about other tags - Html(_html) | - InlineHtml(_html) => (), // HTML is weird, just ignore it + Start(CodeBlock(_)) | Start(Code) => in_code = true, + End(CodeBlock(_)) | End(Code) => in_code = false, + Start(_tag) | End(_tag) => (), // We don't care about other tags + Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it SoftBreak => (), HardBreak => (), - FootnoteReference(text) | - Text(text) => { + FootnoteReference(text) | Text(text) => { if !in_code { let index = match spans.binary_search_by(|c| c.0.cmp(&offset)) { Ok(o) => o, diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 5ef16638878..be5e056d5df 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,5 +1,5 @@ use syntax::ast::*; -use rustc::lint::{EarlyContext, LintContext, LintArray, LintPass, EarlyLintPass}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; /// **What it does:** Checks for unnecessary double parentheses. /// @@ -31,29 +31,22 @@ impl LintPass for DoubleParens { impl EarlyLintPass for DoubleParens { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { match expr.node { - ExprKind::Paren(ref in_paren) => { - match in_paren.node { - ExprKind::Paren(_) | - ExprKind::Tup(_) => { - cx.span_lint(DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses"); - }, - _ => {}, - } + ExprKind::Paren(ref in_paren) => match in_paren.node { + ExprKind::Paren(_) | ExprKind::Tup(_) => { + cx.span_lint(DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses"); + }, + _ => {}, }, - ExprKind::Call(_, ref params) => { - if params.len() == 1 { - let param = ¶ms[0]; - if let ExprKind::Paren(_) = param.node { - cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); - } + ExprKind::Call(_, ref params) => if params.len() == 1 { + let param = ¶ms[0]; + if let ExprKind::Paren(_) = param.node { + cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); } }, - ExprKind::MethodCall(_, ref params) => { - if params.len() == 2 { - let param = ¶ms[1]; - if let ExprKind::Paren(_) = param.node { - cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); - } + ExprKind::MethodCall(_, ref params) => if params.len() == 2 { + let param = ¶ms[1]; + if let ExprKind::Paren(_) = param.node { + cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); } }, _ => {}, diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index dfa8ddbab6c..6ca04d40067 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use utils::{match_def_path, paths, span_note_and_lint, is_copy}; +use utils::{is_copy, match_def_path, paths, span_note_and_lint}; /// **What it does:** Checks for calls to `std::mem::drop` with a reference /// instead of an owned value. @@ -96,13 +96,13 @@ declare_lint! { } const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \ - Dropping a reference does nothing."; + Dropping a reference does nothing."; const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \ - Forgetting a reference does nothing."; + Forgetting a reference does nothing."; const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements Copy. \ - Dropping a copy leaves the original intact."; + Dropping a copy leaves the original intact."; const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements Copy. \ - Forgetting a copy leaves the original intact."; + Forgetting a copy leaves the original intact."; #[allow(missing_copy_implementations)] pub struct Pass; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 7845c85b687..67a4b8d4030 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -36,9 +36,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { let did = cx.tcx.hir.local_def_id(item.id); if let ItemEnum(..) = item.node { let ty = cx.tcx.type_of(did); - let adt = ty.ty_adt_def().expect( - "already checked whether this is an enum", - ); + let adt = ty.ty_adt_def() + .expect("already checked whether this is an enum"); if adt.variants.is_empty() { span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| { db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it"); diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 80288ff2268..a3558a189e2 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, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc::lint::*; use syntax::codemap::Span; use utils::SpanlessEq; @@ -47,12 +47,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` // we can give a better error message let sole_expr = { - else_block.is_none() && - if let ExprBlock(ref then_block) = then_block.node { - (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 - } else { - true - } + else_block.is_none() && if let ExprBlock(ref then_block) = then_block.node { + (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 + } else { + true + } }; let mut visitor = InsertVisitor { diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index e95c37b0aee..c776681d51c 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -51,9 +51,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { let did = cx.tcx.hir.body_owner_def_id(body_id); let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did); - let bad = match cx.tcx.at(expr.span).const_eval( - param_env.and((did, substs)), - ) { + let bad = match cx.tcx + .at(expr.span) + .const_eval(param_env.and((did, substs))) + { Ok(ConstVal::Integral(Usize(Us64(i)))) => u64::from(i as u32) != i, Ok(ConstVal::Integral(Isize(Is64(i)))) => i64::from(i as i32) != i, _ => false, diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 6738f5bb63b..9aa43653ab5 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -1,7 +1,7 @@ //! lint on `use`ing all variants of an enum use rustc::hir::*; -use rustc::lint::{LateLintPass, LintPass, LateContext, LintArray}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::span_lint; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index eee4e2a7ee1..c4f7f39003e 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -204,7 +204,7 @@ fn check_variant( &format!("All variants have the same {}fix: `{}`", what, value), &format!( "remove the {}fixes and use full paths to \ - the variants instead of glob imports", + the variants instead of glob imports", what ), ); diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 84a54dd215b..2c268c18835 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,6 +1,6 @@ use rustc::hir::*; use rustc::lint::*; -use utils::{SpanlessEq, span_lint, span_lint_and_then, multispan_sugg, snippet, implements_trait, is_copy}; +use utils::{implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq}; /// **What it does:** Checks for equal operands to comparison, logical and /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, @@ -82,8 +82,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { #[allow(match_same_arms)] match (&left.node, &right.node) { // do not suggest to dereference literals - (&ExprLit(..), _) | - (_, &ExprLit(..)) => {}, + (&ExprLit(..), _) | (_, &ExprLit(..)) => {}, // &foo == &bar (&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => { let lty = cx.tables.expr_ty(l); diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index c6183948ef3..beb96f333cb 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -133,7 +133,6 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { self.set.remove(&lid); } } - } fn borrow(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, loan_cause: LoanCause) { if let Categorization::Local(lid) = cmt.cat { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 42524da7ffc..0710689c3d4 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use utils::{snippet_opt, span_lint_and_then, is_adjusted, iter_input_pats}; +use utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then}; #[allow(missing_copy_implementations)] pub struct EtaPass; @@ -37,11 +37,8 @@ impl LintPass for EtaPass { 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) - } + ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => for arg in args { + check_closure(cx, arg) }, _ => (), } diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index db952cd5d98..621438b9a87 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,9 +1,9 @@ use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc::hir::*; use rustc::ty; use rustc::lint::*; -use utils::{get_parent_expr, span_note_and_lint, span_lint}; +use utils::{get_parent_expr, span_lint, span_note_and_lint}; /// **What it does:** Checks for a read and a write to the same variable where /// whether the read occurs before or after the write depends on the evaluation @@ -62,20 +62,17 @@ 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(ref qpath) = lhs.node { - if let QPath::Resolved(_, ref path) = *qpath { - if path.segments.len() == 1 { - let var = cx.tables.qpath_def(qpath, lhs.hir_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.tables.qpath_def(qpath, lhs.hir_id).def_id(); + let mut visitor = ReadVisitor { + cx: cx, + var: var, + write_expr: expr, + last_expr: expr, + }; + check_for_unsequenced_reads(&mut visitor); } } }, @@ -84,13 +81,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence { } fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { match stmt.node { - 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: cx }.visit_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: cx }.visit_expr(e); } }, } @@ -230,8 +227,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St ExprStruct(_, _, _) => { walk_expr(vis, expr); }, - ExprBinary(op, _, _) | - ExprAssignOp(op, _, _) => { + ExprBinary(op, _, _) | ExprAssignOp(op, _, _) => { if op.node == BiAnd || op.node == BiOr { // x && y and x || y always evaluate x first, so these are // strictly sequenced. @@ -265,8 +261,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St 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), + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => check_expr(vis, expr), StmtDecl(ref decl, _) => { // If the declaration is of a local variable, check its initializer // expression if it has one. Otherwise, keep going. @@ -274,10 +269,9 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> St DeclLocal(ref local) => Some(local), _ => None, }; - local.and_then(|local| local.init.as_ref()).map_or( - StopEarly::KeepGoing, - |expr| check_expr(vis, expr), - ) + local + .and_then(|local| local.init.as_ref()) + .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)) }, } } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index fb2e04a3662..2577e2908a8 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -57,11 +57,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { }} }, // `format!("foo")` expansion contains `match () { () => [], }` - ExprMatch(ref matchee, _, _) => { - if let ExprTup(ref tup) = matchee.node { - if tup.is_empty() { - span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); - } + ExprMatch(ref matchee, _, _) => if let ExprTup(ref tup) = matchee.node { + if tup.is_empty() { + span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); } }, _ => (), diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index e3b3bb408b3..7d712942986 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -117,7 +117,7 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { eqop_span, &format!( "this looks like you are trying to use `.. {op}= ..`, but you \ - really are doing `.. = ({op} ..)`", + really are doing `.. = ({op} ..)`", op = op ), eqop_span, @@ -142,9 +142,9 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { // the snippet should look like " else \n " with maybe comments anywhere // it’s bad when there is a ‘\n’ after the “else” if let Some(else_snippet) = snippet_opt(cx, else_span) { - let else_pos = else_snippet.find("else").expect( - "there must be a `else` here", - ); + let else_pos = else_snippet + .find("else") + .expect("there must be a `else` here"); if else_snippet[else_pos..].contains('\n') { span_note_and_lint( @@ -154,7 +154,7 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { "this is an `else if` but the formatting might hide it", else_span, "to remove this lint, remove the `else` or remove the new line between `else` \ - and `if`", + and `if`", ); } } @@ -205,7 +205,7 @@ fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Exp "this looks like an `else if` but the `else` is missing", else_span, "to remove this lint, add the missing `else` or add a new line before the second \ - `if`", + `if`", ); } } @@ -215,8 +215,9 @@ fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Exp /// Match `if` or `if let` expressions and return the `then` and `else` block. fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> { match expr.node { - ast::ExprKind::If(_, ref then, ref else_) | - ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), + ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::IfLet(_, _, ref then, ref else_) => { + Some((then, else_)) + }, _ => None, } } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 70ff96d36d4..869e621eab6 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; use syntax::ast; use syntax::abi::Abi; use syntax::codemap::Span; -use utils::{span_lint, type_is_unsafe_function, iter_input_pats}; +use utils::{iter_input_pats, span_lint, type_is_unsafe_function}; /// **What it does:** Checks for functions with too many parameters. /// @@ -60,7 +60,9 @@ pub struct Functions { impl Functions { pub fn new(threshold: u64) -> Self { - Self { threshold: threshold } + Self { + threshold: threshold, + } } } diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index a7c254e1e46..a409f4c7d65 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -2,7 +2,7 @@ use consts::{constant_simple, Constant}; use rustc::lint::*; use rustc::hir::*; use syntax::codemap::Span; -use utils::{span_lint, snippet, in_macro}; +use utils::{in_macro, snippet, span_lint}; use syntax::attr::IntType::{SignedInt, UnsignedInt}; /// **What it does:** Checks for identity operations, e.g. `x + 0`. @@ -63,16 +63,13 @@ fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, e) { if match m { 0 => v.to_u128_unchecked() == 0, - -1 => { - match v.int_type() { - SignedInt(_) => (v.to_u128_unchecked() as i128 == -1), - UnsignedInt(_) => false, - } + -1 => match v.int_type() { + SignedInt(_) => (v.to_u128_unchecked() as i128 == -1), + UnsignedInt(_) => false, }, 1 => v.to_u128_unchecked() == 1, _ => unreachable!(), - } - { + } { span_lint( cx, IDENTITY_OP, diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs index 36411b73a62..27f41c0e698 100644 --- a/clippy_lints/src/if_let_redundant_pattern_matching.rs +++ b/clippy_lints/src/if_let_redundant_pattern_matching.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{paths, span_lint_and_then, match_qpath, snippet}; +use utils::{match_qpath, paths, snippet, span_lint_and_then}; /// **What it does:*** Lint for redundant pattern matching over `Result` or /// `Option` @@ -45,11 +45,8 @@ impl LintPass for Pass { 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 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 => { if match_qpath(path, &paths::RESULT_OK) { @@ -68,16 +65,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { _ => return, }; - span_lint_and_then(cx, - IF_LET_REDUNDANT_PATTERN_MATCHING, - arms[0].pats[0].span, - &format!("redundant pattern matching, consider using `{}`", good_method), - |db| { - let span = expr.span.with_hi(op.span.hi()); - db.span_suggestion(span, "try this", format!("if {}.{}", snippet(cx, op.span, "_"), good_method)); - }); + span_lint_and_then( + cx, + IF_LET_REDUNDANT_PATTERN_MATCHING, + arms[0].pats[0].span, + &format!("redundant pattern matching, consider using `{}`", good_method), + |db| { + let span = expr.span.with_hi(op.span.hi()); + db.span_suggestion( + span, + "try this", + format!("if {}.{}", snippet(cx, op.span, "_"), good_method), + ); + }, + ); } - } } } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index d542ddb029f..3a5bcdc78d4 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use rustc::hir::*; use rustc::lint::*; -use utils::{get_trait_def_id, implements_trait, higher, match_qpath, paths, span_lint}; +use utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint}; /// **What it does:** Checks for iteration that is guaranteed to be infinite. /// @@ -66,14 +66,13 @@ enum Finiteness { Finite, } -use self::Finiteness::{Infinite, MaybeInfinite, Finite}; +use self::Finiteness::{Finite, Infinite, MaybeInfinite}; impl Finiteness { fn and(self, b: Self) -> Self { match (self, b) { (Finite, _) | (_, Finite) => Finite, - (MaybeInfinite, _) | - (_, MaybeInfinite) => MaybeInfinite, + (MaybeInfinite, _) | (_, MaybeInfinite) => MaybeInfinite, _ => Infinite, } } @@ -81,8 +80,7 @@ impl Finiteness { fn or(self, b: Self) -> Self { match (self, b) { (Infinite, _) | (_, Infinite) => Infinite, - (MaybeInfinite, _) | - (_, MaybeInfinite) => MaybeInfinite, + (MaybeInfinite, _) | (_, MaybeInfinite) => MaybeInfinite, _ => Finite, } } @@ -90,7 +88,11 @@ impl Finiteness { impl From<bool> for Finiteness { fn from(b: bool) -> Self { - if b { Infinite } else { Finite } + if b { + Infinite + } else { + Finite + } } } @@ -108,7 +110,7 @@ enum Heuristic { All, } -use self::Heuristic::{Always, First, Any, All}; +use self::Heuristic::{All, Always, Any, First}; /// a slice of (method name, number of args, heuristic, bounds) tuples /// that will be used to determine whether the method in question @@ -143,11 +145,11 @@ fn is_infinite(cx: &LateContext, expr: &Expr) -> Finiteness { for &(name, len, heuristic, cap) in HEURISTICS.iter() { if method.name == name && args.len() == len { return (match heuristic { - Always => Infinite, - First => is_infinite(cx, &args[0]), - Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])), - All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])), - }).and(cap); + Always => Infinite, + First => is_infinite(cx, &args[0]), + Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])), + All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])), + }).and(cap); } } if method.name == "flat_map" && args.len() == 2 { @@ -159,20 +161,15 @@ fn is_infinite(cx: &LateContext, expr: &Expr) -> Finiteness { Finite }, ExprBlock(ref block) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), - ExprBox(ref e) | - ExprAddrOf(_, ref e) => is_infinite(cx, e), - ExprCall(ref path, _) => { - if let ExprPath(ref qpath) = path.node { - match_qpath(qpath, &paths::REPEAT).into() - } else { - Finite - } - }, - ExprStruct(..) => { - higher::range(expr) - .map_or(false, |r| r.end.is_none()) - .into() + ExprBox(ref e) | ExprAddrOf(_, ref e) => is_infinite(cx, e), + ExprCall(ref path, _) => if let ExprPath(ref qpath) = path.node { + match_qpath(qpath, &paths::REPEAT).into() + } else { + Finite }, + ExprStruct(..) => higher::range(expr) + .map_or(false, |r| r.end.is_none()) + .into(), _ => Finite, } } @@ -220,23 +217,18 @@ fn complete_infinite_iter(cx: &LateContext, expr: &Expr) -> Finiteness { } } if method.name == "last" && args.len() == 1 { - let not_double_ended = get_trait_def_id(cx, - &paths::DOUBLE_ENDED_ITERATOR) - .map_or(false, |id| { - !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[]) - }); + let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR) + .map_or(false, |id| !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[])); if not_double_ended { - return is_infinite(cx, &args[0]); + return is_infinite(cx, &args[0]); } } }, - ExprBinary(op, ref l, ref r) => { - if op.node.is_comparison() { - return is_infinite(cx, l).and(is_infinite(cx, r)).and( - MaybeInfinite, - ); - } - }, //TODO: ExprLoop + Match + ExprBinary(op, ref l, ref r) => if op.node.is_comparison() { + return is_infinite(cx, l) + .and(is_infinite(cx, r)) + .and(MaybeInfinite); + }, // TODO: ExprLoop + Match _ => (), } Finite diff --git a/clippy_lints/src/is_unit_expr.rs b/clippy_lints/src/is_unit_expr.rs index 5939cd36bf8..152612bd8ff 100644 --- a/clippy_lints/src/is_unit_expr.rs +++ b/clippy_lints/src/is_unit_expr.rs @@ -100,12 +100,10 @@ impl EarlyLintPass for UnitExpr { } fn is_unit_expr(expr: &Expr) -> Option<Span> { match expr.node { - ExprKind::Block(ref block) => { - if check_last_stmt_in_block(block) { - Some(block.stmts[block.stmts.len() - 1].span) - } else { - None - } + ExprKind::Block(ref block) => if check_last_stmt_in_block(block) { + Some(block.stmts[block.stmts.len() - 1].span) + } else { + None }, ExprKind::If(_, ref then, ref else_) => { let check_then = check_last_stmt_in_block(then); @@ -115,7 +113,11 @@ fn is_unit_expr(expr: &Expr) -> Option<Span> { return Some(*expr_else); } } - if check_then { Some(expr.span) } else { None } + if check_then { + Some(expr.span) + } else { + None + } }, ExprKind::Match(ref _pattern, ref arms) => { for arm in arms { @@ -137,12 +139,9 @@ fn check_last_stmt_in_block(block: &Block) -> bool { // like `panic!()` match final_stmt.node { StmtKind::Expr(_) => false, - StmtKind::Semi(ref expr) => { - match expr.node { - ExprKind::Break(_, _) | - ExprKind::Ret(_) => false, - _ => true, - } + StmtKind::Semi(ref expr) => match expr.node { + ExprKind::Break(_, _) | ExprKind::Ret(_) => false, + _ => true, }, _ => true, } diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index f14c70dc4dd..2aabecabff0 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 { @@ -66,7 +67,7 @@ impl EarlyLintPass for ItemsAfterStatements { ITEMS_AFTER_STATEMENTS, it.span, "adding items after statements is confusing, since items exist from the \ - start of the scope", + start of the scope", ); } } diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 917e0b77370..ceb0cbd6688 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{span_lint_and_then, snippet_opt, type_size}; +use utils::{snippet_opt, span_lint_and_then, type_size}; use rustc::ty::TypeFoldable; /// **What it does:** Checks for large size differences between variants on @@ -34,7 +34,9 @@ pub struct LargeEnumVariant { impl LargeEnumVariant { pub fn new(maximum_size_difference_allowed: u64) -> Self { - Self { maximum_size_difference_allowed: maximum_size_difference_allowed } + Self { + maximum_size_difference_allowed: maximum_size_difference_allowed, + } } } @@ -49,9 +51,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { let did = cx.tcx.hir.local_def_id(item.id); if let ItemEnum(ref def, _) = item.node { let ty = cx.tcx.type_of(did); - let adt = ty.ty_adt_def().expect( - "already checked whether this is an enum", - ); + let adt = ty.ty_adt_def() + .expect("already checked whether this is an enum"); let mut smallest_variant: Option<(_, _)> = None; let mut largest_variant: Option<(_, _)> = None; @@ -90,15 +91,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { |db| { if variant.fields.len() == 1 { let span = match def.variants[i].node.data { - VariantData::Struct(ref fields, _) | - VariantData::Tuple(ref fields, _) => fields[0].ty.span, + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => { + fields[0].ty.span + }, VariantData::Unit(_) => unreachable!(), }; if let Some(snip) = snippet_opt(cx, span) { db.span_suggestion( span, "consider boxing the large fields to reduce the total size of the \ - enum", + enum", format!("Box<{}>", snip), ); return; @@ -112,7 +114,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { ); } } - } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e862240da59..9b14a44f2c0 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -91,16 +91,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[TraitItemRef]) { fn is_named_self(cx: &LateContext, item: &TraitItemRef, name: &str) -> bool { - item.name == name && - if let AssociatedItemKind::Method { has_self } = item.kind { - has_self && - { - let did = cx.tcx.hir.local_def_id(item.id.node_id); - cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 - } - } else { - false + item.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { + has_self && { + let did = cx.tcx.hir.local_def_id(item.id.node_id); + cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 } + } else { + false + } } // fill the set with current and super traits @@ -121,10 +119,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai .iter() .flat_map(|&i| cx.tcx.associated_items(i)) .any(|i| { - i.kind == ty::AssociatedKind::Method && - i.method_has_self_argument && - i.name == "is_empty" && - cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 + i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" && + cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 }); if !is_empty_method_found { @@ -143,16 +139,14 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool { - item.name == name && - if let AssociatedItemKind::Method { has_self } = item.kind { - has_self && - { - let did = cx.tcx.hir.local_def_id(item.id.node_id); - cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 - } - } else { - false + item.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { + has_self && { + let did = cx.tcx.hir.local_def_id(item.id.node_id); + cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 } + } else { + false + } } let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) { @@ -197,7 +191,11 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str) } fn check_len_zero(cx: &LateContext, span: Span, name: Name, args: &[Expr], lit: &Lit, op: &str) { - if let Spanned { node: LitKind::Int(0, _), .. } = *lit { + if let Spanned { + node: LitKind::Int(0, _), + .. + } = *lit + { if name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { span_lint_and_sugg( cx, @@ -231,25 +229,19 @@ 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(id).iter().any(|imp| { - cx.tcx.associated_items(*imp).any( - |item| is_is_empty(cx, &item), - ) + cx.tcx + .associated_items(*imp) + .any(|item| is_is_empty(cx, &item)) }) } let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr)); match ty.sty { - ty::TyDynamic(..) => { - cx.tcx - .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::TyDynamic(..) => cx.tcx + .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::TySlice(..) | ty::TyStr => true, _ => false, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 95d45bed133..41ca62b470c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -8,39 +8,42 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(conservative_impl_trait)] - #![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)] -extern crate syntax; -extern crate syntax_pos; #[macro_use] extern crate rustc; +extern crate syntax; +extern crate syntax_pos; extern crate toml; // for unicode nfc normalization + extern crate unicode_normalization; // for semver check in attrs.rs + extern crate semver; // for regex checking + extern crate regex_syntax; // for finding minimal boolean expressions + extern crate quine_mc_cluskey; -extern crate rustc_errors; -extern crate rustc_plugin; extern crate rustc_const_eval; extern crate rustc_const_math; +extern crate rustc_errors; +extern crate rustc_plugin; #[macro_use] extern crate matches as matches_macro; +extern crate serde; #[macro_use] extern crate serde_derive; -extern crate serde; #[macro_use] extern crate lazy_static; diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 4cb386471c9..9e7e19a8df5 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, NestedVisitorMap}; -use std::collections::{HashSet, HashMap}; +use rustc::hir::intravisit::{walk_fn_decl, walk_generics, walk_ty, walk_ty_param_bound, NestedVisitorMap, Visitor}; +use std::collections::{HashMap, HashSet}; use syntax::codemap::Span; -use utils::{in_external_macro, span_lint, last_path_segment}; +use utils::{in_external_macro, last_path_segment, span_lint}; use syntax::symbol::keywords; /// **What it does:** Checks for lifetime annotations which can be removed by @@ -171,7 +171,9 @@ fn could_use_elision<'a, 'tcx: 'a>( }; if let Some(body_id) = body { - let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false }; + let mut checker = BodyLifetimeChecker { + lifetimes_used_in_body: false, + }; checker.visit_expr(&cx.tcx.hir.body(body_id).value); if checker.lifetimes_used_in_body { return false; @@ -192,9 +194,9 @@ fn could_use_elision<'a, 'tcx: 'a>( // no output lifetimes, check distinctness of input lifetimes // only unnamed and static, ok - let unnamed_and_static = input_lts.iter().all(|lt| { - *lt == RefLt::Unnamed || *lt == RefLt::Static - }); + let unnamed_and_static = input_lts + .iter() + .all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static); if unnamed_and_static { return false; } @@ -210,8 +212,8 @@ fn could_use_elision<'a, 'tcx: 'a>( match (&input_lts[0], &output_lts[0]) { (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true, (&RefLt::Named(_), &RefLt::Unnamed) => true, - _ => false, // already elided, different named lifetimes - // or something static going on + _ => false, /* already elided, different named lifetimes + * or something static going on */ } } else { false @@ -277,7 +279,11 @@ impl<'v, 't> RefVisitor<'v, 't> { } fn into_vec(self) -> Option<Vec<RefLt>> { - if self.abort { None } else { Some(self.lts) } + if self.abort { + None + } else { + Some(self.lts) + } } fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) { @@ -285,8 +291,7 @@ impl<'v, 't> RefVisitor<'v, 't> { if !last_path_segment.parenthesized && last_path_segment.lifetimes.is_empty() { let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id); match self.cx.tables.qpath_def(qpath, hir_id) { - Def::TyAlias(def_id) | - Def::Struct(def_id) => { + Def::TyAlias(def_id) | Def::Struct(def_id) => { let generics = self.cx.tcx.generics_of(def_id); for _ in generics.regions.as_slice() { self.record(&None); @@ -318,11 +323,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { TyPath(ref path) => { self.collect_anonymous_lifetimes(path, ty); }, - TyImplTrait(ref param_bounds) => { - for bound in param_bounds { - if let RegionTyParamBound(_) = *bound { - self.record(&None); - } + TyImplTrait(ref param_bounds) => for bound in param_bounds { + if let RegionTyParamBound(_) = *bound { + self.record(&None); } }, TyTraitObject(ref bounds, ref lt) => { @@ -366,11 +369,9 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: & // and check that all lifetimes are allowed match visitor.into_vec() { None => return false, - Some(lts) => { - for lt in lts { - if !allowed_lts.contains(<) { - return true; - } + Some(lts) => for lt in lts { + if !allowed_lts.contains(<) { + return true; } }, } diff --git a/clippy_lints/src/literal_digit_grouping.rs b/clippy_lints/src/literal_digit_grouping.rs index dbb1a7a9b86..1cd539eac39 100644 --- a/clippy_lints/src/literal_digit_grouping.rs +++ b/clippy_lints/src/literal_digit_grouping.rs @@ -4,7 +4,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax_pos; -use utils::{span_help_and_lint, snippet_opt, in_external_macro}; +use utils::{in_external_macro, snippet_opt, span_help_and_lint}; /// **What it does:** Warns if a long integral or floating-point constant does /// not contain underscores. @@ -195,33 +195,27 @@ enum WarningType { impl WarningType { pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: &syntax_pos::Span) { match *self { - WarningType::UnreadableLiteral => { - span_help_and_lint( - cx, - UNREADABLE_LITERAL, - *span, - "long literal lacking separators", - &format!("consider: {}", grouping_hint), - ) - }, - WarningType::LargeDigitGroups => { - span_help_and_lint( - cx, - LARGE_DIGIT_GROUPS, - *span, - "digit groups should be smaller", - &format!("consider: {}", grouping_hint), - ) - }, - WarningType::InconsistentDigitGrouping => { - span_help_and_lint( - cx, - INCONSISTENT_DIGIT_GROUPING, - *span, - "digits grouped inconsistently by underscores", - &format!("consider: {}", grouping_hint), - ) - }, + WarningType::UnreadableLiteral => span_help_and_lint( + cx, + UNREADABLE_LITERAL, + *span, + "long literal lacking separators", + &format!("consider: {}", grouping_hint), + ), + WarningType::LargeDigitGroups => span_help_and_lint( + cx, + LARGE_DIGIT_GROUPS, + *span, + "digit groups should be smaller", + &format!("consider: {}", grouping_hint), + ), + WarningType::InconsistentDigitGrouping => span_help_and_lint( + cx, + INCONSISTENT_DIGIT_GROUPING, + *span, + "digits grouped inconsistently by underscores", + &format!("consider: {}", grouping_hint), + ), }; } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 7a5f7b49278..2f87fe0f396 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, walk_pat, walk_stmt, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt}; use rustc::lint::*; use rustc::middle::const_val::ConstVal; @@ -14,9 +14,9 @@ use std::collections::{HashMap, HashSet}; 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, - last_path_segment, span_lint_and_sugg}; +use utils::{get_enclosing_block, get_parent_expr, higher, in_external_macro, is_integer_literal, is_refutable, + last_path_segment, match_trait_method, match_type, multispan_sugg, snippet, span_help_and_lint, span_lint, + span_lint_and_sugg, span_lint_and_then}; use utils::paths; /// **What it does:** Checks for looping over the range of `0..len` of some @@ -340,11 +340,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // check for never_loop match expr.node { - ExprWhile(_, ref block, _) | - ExprLoop(ref block, _, _) => { - if never_loop(block, &expr.id) { - span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"); - } + ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => if never_loop(block, &expr.id) { + span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"); }, _ => (), } @@ -360,7 +357,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { EMPTY_LOOP, expr.span, "empty `loop {}` detected. You may want to either use `panic!()` or add \ - `std::thread::sleep(..);` to the loop body.", + `std::thread::sleep(..);` to the loop body.", ); } @@ -371,8 +368,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // ensure "if let" compatible match structure match *source { - MatchSource::Normal | - MatchSource::IfLetDesugar { .. } => { + MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { 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) @@ -407,8 +403,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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 qpath, ref pat_args, _), - &ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node) + if let ( + &PatKind::TupleStruct(ref qpath, ref pat_args, _), + &ExprMethodCall(ref method_path, _, ref method_args), + ) = (pat, &match_expr.node) { let iter_expr = &method_args[0]; let lhs_constructor = last_path_segment(qpath); @@ -441,7 +439,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { UNUSED_COLLECT, expr.span, "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator", + Consider using an explicit for loop to exhaust the iterator", ); } } @@ -455,28 +453,25 @@ fn never_loop(block: &Block, id: &NodeId) -> bool { fn contains_continue_block(block: &Block, dest: &NodeId) -> bool { block.stmts.iter().any(|e| contains_continue_stmt(e, dest)) || - block.expr.as_ref().map_or( - false, - |e| contains_continue_expr(e, dest), - ) + block + .expr + .as_ref() + .map_or(false, |e| contains_continue_expr(e, dest)) } fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool { match stmt.node { - StmtSemi(ref e, _) | - StmtExpr(ref e, _) => contains_continue_expr(e, dest), + StmtSemi(ref e, _) | StmtExpr(ref e, _) => contains_continue_expr(e, dest), StmtDecl(ref d, _) => contains_continue_decl(d, dest), } } fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool { match decl.node { - DeclLocal(ref local) => { - local.init.as_ref().map_or( - false, - |e| contains_continue_expr(e, dest), - ) - }, + DeclLocal(ref local) => local + .init + .as_ref() + .map_or(false, |e| contains_continue_expr(e, dest)), _ => false, } } @@ -492,9 +487,9 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool { ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprRepeat(ref e, _) => contains_continue_expr(e, dest), - ExprArray(ref es) | - ExprMethodCall(_, _, ref es) | - ExprTup(ref es) => es.iter().any(|e| contains_continue_expr(e, dest)), + ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => { + es.iter().any(|e| contains_continue_expr(e, dest)) + }, ExprCall(ref e, ref es) => { contains_continue_expr(e, dest) || es.iter().any(|e| contains_continue_expr(e, dest)) }, @@ -502,22 +497,17 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool { ExprAssign(ref e1, ref e2) | ExprAssignOp(_, ref e1, ref e2) | ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| contains_continue_expr(e, dest)), - ExprIf(ref e, ref e2, ref e3) => { - [e, e2].iter().chain(e3.as_ref().iter()).any(|e| { - contains_continue_expr(e, dest) - }) - }, + ExprIf(ref e, ref e2, ref e3) => [e, e2] + .iter() + .chain(e3.as_ref().iter()) + .any(|e| contains_continue_expr(e, dest)), ExprWhile(ref e, ref b, _) => contains_continue_expr(e, dest) || contains_continue_block(b, dest), ExprMatch(ref e, ref arms, _) => { contains_continue_expr(e, dest) || arms.iter().any(|a| contains_continue_expr(&a.body, dest)) }, ExprBlock(ref block) => contains_continue_block(block, dest), - ExprStruct(_, _, ref base) => { - base.as_ref().map_or( - false, - |e| contains_continue_expr(e, dest), - ) - }, + ExprStruct(_, _, ref base) => base.as_ref() + .map_or(false, |e| contains_continue_expr(e, dest)), ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| id == *dest), _ => false, } @@ -529,8 +519,7 @@ fn loop_exit_block(block: &Block) -> bool { fn loop_exit_stmt(stmt: &Stmt) -> bool { match stmt.node { - StmtSemi(ref e, _) | - StmtExpr(ref e, _) => loop_exit_expr(e), + StmtSemi(ref e, _) | StmtExpr(ref e, _) => loop_exit_expr(e), StmtDecl(ref d, _) => loop_exit_decl(d), } } @@ -552,9 +541,7 @@ fn loop_exit_expr(expr: &Expr) -> bool { ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprRepeat(ref e, _) => loop_exit_expr(e), - ExprArray(ref es) | - ExprMethodCall(_, _, ref es) | - ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e)), + ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e)), ExprCall(ref e, ref es) => loop_exit_expr(e) || es.iter().any(|e| loop_exit_expr(e)), ExprBinary(_, ref e1, ref e2) | ExprAssign(ref e1, ref e2) | @@ -595,10 +582,10 @@ fn check_for_loop_range<'a, 'tcx>( expr: &'tcx Expr, ) { if let Some(higher::Range { - start: Some(start), - ref end, - limits, - }) = higher::range(arg) + start: Some(start), + ref end, + limits, + }) = higher::range(arg) { // the var must be a single name if let PatKind::Binding(_, def_id, ref ident, _) = pat.node { @@ -613,9 +600,11 @@ fn check_for_loop_range<'a, 'tcx>( // linting condition: we only indexed one variable if visitor.indexed.len() == 1 { - let (indexed, indexed_extent) = visitor.indexed.into_iter().next().expect( - "already checked that we have exactly 1 element", - ); + let (indexed, indexed_extent) = visitor + .indexed + .into_iter() + .next() + .expect("already checked that we have exactly 1 element"); // ensure that the indexed variable was declared before the loop, see #601 if let Some(indexed_extent) = indexed_extent { @@ -659,16 +648,22 @@ fn check_for_loop_range<'a, 'tcx>( }; if visitor.nonindex { - span_lint_and_then(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is used to index `{}`", ident.node, indexed), - |db| { - multispan_sugg(db, - "consider using an iterator".to_string(), - vec![(pat.span, format!("({}, <item>)", ident.node)), - (arg.span, format!("{}.iter().enumerate(){}{}", indexed, take, skip))]); - }); + span_lint_and_then( + cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is used to index `{}`", ident.node, indexed), + |db| { + multispan_sugg( + db, + "consider using an iterator".to_string(), + vec![ + (pat.span, format!("({}, <item>)", ident.node)), + (arg.span, format!("{}.iter().enumerate(){}{}", indexed, take, skip)), + ], + ); + }, + ); } else { let repl = if starts_at_zero && take.is_empty() { format!("&{}", indexed) @@ -676,17 +671,19 @@ fn check_for_loop_range<'a, 'tcx>( format!("{}.iter(){}{}", indexed, take, skip) }; - span_lint_and_then(cx, - NEEDLESS_RANGE_LOOP, - expr.span, - &format!("the loop variable `{}` is only used to index `{}`.", - ident.node, - indexed), - |db| { - multispan_sugg(db, - "consider using an iterator".to_string(), - vec![(pat.span, "<item>".to_string()), (arg.span, repl)]); - }); + span_lint_and_then( + cx, + NEEDLESS_RANGE_LOOP, + expr.span, + &format!("the loop variable `{}` is only used to index `{}`.", ident.node, indexed), + |db| { + multispan_sugg( + db, + "consider using an iterator".to_string(), + vec![(pat.span, "<item>".to_string()), (arg.span, repl)], + ); + }, + ); } } } @@ -711,10 +708,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { // if this for loop is iterating over a two-sided range... if let Some(higher::Range { - start: Some(start), - end: Some(end), - limits, - }) = higher::range(arg) + start: Some(start), + end: Some(end), + limits, + }) = higher::range(arg) { // ...and both sides are compile-time constant integers... let parent_item = cx.tcx.hir.get_parent(arg.id); @@ -743,19 +740,25 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) { ".." }; - span_lint_and_then(cx, - REVERSE_RANGE_LOOP, - 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)); - }); + span_lint_and_then( + cx, + REVERSE_RANGE_LOOP, + 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 + ), + ); + }, + ); } else if eq && limits != ast::RangeLimits::Closed { // if they are equal, it's also problematic - this loop // will never run. @@ -783,7 +786,7 @@ fn lint_iter_method(cx: &LateContext, args: &[Expr], arg: &Expr, method_name: &s EXPLICIT_ITER_LOOP, arg.span, "it is more idiomatic to loop over references to containers instead of using explicit \ - iteration methods", + iteration methods", "to write this more concisely, try", format!("&{}{}", muta, object), ) @@ -816,7 +819,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { EXPLICIT_INTO_ITER_LOOP, arg.span, "it is more idiomatic to loop over containers instead of using explicit \ - iteration methods`", + iteration methods`", "to write this more concisely, try", object.to_string(), ); @@ -827,7 +830,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { ITER_NEXT_LOOP, expr.span, "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ - probably not what you want", + probably not what you want", ); next_loop_linted = true; } @@ -848,7 +851,7 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { arg.span, &format!( "for loop over `{0}`, which is an `Option`. This is more readably written as an \ - `if let` statement.", + `if let` statement.", snippet(cx, arg.span, "_") ), &format!( @@ -864,7 +867,7 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { arg.span, &format!( "for loop over `{0}`, which is a `Result`. This is more readably written as an \ - `if let` statement.", + `if let` statement.", snippet(cx, arg.span, "_") ), &format!( @@ -894,14 +897,14 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. let map = &cx.tcx.hir; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| { - map.get_enclosing_scope(id) - }); + let parent_scope = map.get_enclosing_scope(expr.id) + .and_then(|id| map.get_enclosing_scope(id)); if let Some(parent_id) = parent_scope { if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter( - |&(_, v)| *v == VarState::IncrOnce, - ) + for (id, _) in visitor + .states + .iter() + .filter(|&(_, v)| *v == VarState::IncrOnce) { let mut visitor2 = InitializeVisitor { cx: cx, @@ -922,7 +925,7 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( expr.span, &format!( "the variable `{0}` is used as a loop counter. Consider using `for ({0}, \ - item) in {1}.enumerate()` or similar iterators", + item) in {1}.enumerate()` or similar iterators", name, snippet(cx, arg.span, "_") ), @@ -948,12 +951,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( if pat.len() == 2 { let arg_span = arg.span; let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty { - ty::TyRef(_, ref tam) => { - match (&pat[0].node, &pat[1].node) { - (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl), - (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable), - _ => return, - } + ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) { + (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl), + (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable), + _ => return, }, _ => return, }; @@ -967,21 +968,26 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( }; if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) { - span_lint_and_then(cx, - FOR_KV_MAP, - expr.span, - &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(), - vec![(pat_span, snippet(cx, new_pat_span, kind).into_owned()), - (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl))]); - }); + span_lint_and_then( + cx, + FOR_KV_MAP, + expr.span, + &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(), + vec![ + (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)), + ], + ); + }, + ); } } } - } /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. @@ -1011,7 +1017,7 @@ fn match_var(expr: &Expr, var: Name) -> bool { struct UsedVisitor { var: ast::Name, // var to look for - used: bool, // has the var been used otherwise? + used: bool, // has the var been used otherwise? } impl<'tcx> Visitor<'tcx> for UsedVisitor { @@ -1196,12 +1202,9 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { fn extract_first_expr(block: &Block) -> Option<&Expr> { match block.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), - StmtDecl(..) => None, - } + None if !block.stmts.is_empty() => match block.stmts[0].node { + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), + StmtDecl(..) => None, }, _ => None, } @@ -1211,11 +1214,9 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> { fn is_break_expr(expr: &Expr) -> bool { match expr.node { ExprBreak(dest, _) if dest.ident.is_none() => true, - ExprBlock(ref b) => { - match extract_first_expr(b) { - Some(subexpr) => is_break_expr(subexpr), - None => false, - } + ExprBlock(ref b) => match extract_first_expr(b) { + Some(subexpr) => is_break_expr(subexpr), + None => false, }, _ => false, } @@ -1226,7 +1227,7 @@ fn is_break_expr(expr: &Expr) -> bool { // at the start of the loop. #[derive(PartialEq)] enum VarState { - Initial, // Not examined yet + Initial, // Not examined yet IncrOnce, // Incremented exactly once, may be a loop counter Declared, // Declared but not (yet) initialized to zero Warn, @@ -1235,9 +1236,9 @@ enum VarState { /// Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx>, // context reference + cx: &'a LateContext<'a, 'tcx>, // context reference states: HashMap<NodeId, VarState>, // incremented variables - depth: u32, // depth of conditional expressions + depth: u32, // depth of conditional expressions done: bool, } @@ -1291,7 +1292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { /// Check whether a variable is initialized to zero at the start of a loop. struct InitializeVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, // context reference - end_expr: &'tcx Expr, // the for loop. Stop scanning here. + end_expr: &'tcx Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, name: Option<Name>, @@ -1379,9 +1380,10 @@ fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { if let ExprPath(ref qpath) = expr.node { let path_res = cx.tables.qpath_def(qpath, expr.hir_id); if let Def::Local(def_id) = path_res { - let node_id = cx.tcx.hir.as_local_node_id(def_id).expect( - "That DefId should be valid", - ); + let node_id = cx.tcx + .hir + .as_local_node_id(def_id) + .expect("That DefId should be valid"); return Some(node_id); } } @@ -1425,13 +1427,11 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool return false; } match cx.tcx.hir.find(parent) { - Some(NodeExpr(expr)) => { - match expr.node { - ExprLoop(..) | ExprWhile(..) => { - return true; - }, - _ => (), - } + Some(NodeExpr(expr)) => match expr.node { + ExprLoop(..) | ExprWhile(..) => { + return true; + }, + _ => (), }, Some(NodeBlock(block)) => { let mut block_visitor = LoopNestVisitor { @@ -1455,12 +1455,12 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool #[derive(PartialEq, Eq)] enum Nesting { - Unknown, // no nesting detected yet - RuledOut, // the iterator is initialized or assigned within scope + Unknown, // no nesting detected yet + RuledOut, // the iterator is initialized or assigned within scope LookFurther, // no nesting detected, no further walk required } -use self::Nesting::{Unknown, RuledOut, LookFurther}; +use self::Nesting::{LookFurther, RuledOut, Unknown}; struct LoopNestVisitor { id: NodeId, @@ -1486,11 +1486,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } match expr.node { - ExprAssign(ref path, _) | - ExprAssignOp(_, ref path, _) => { - if match_var(path, self.iterator) { - self.nesting = RuledOut; - } + ExprAssign(ref path, _) | ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) { + self.nesting = RuledOut; }, _ => walk_expr(self, expr), } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index f0e19a3b577..733022f1703 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -2,8 +2,8 @@ use rustc::lint::*; use rustc::hir::*; use rustc::ty; use syntax::ast; -use utils::{is_adjusted, match_qpath, match_trait_method, match_type, remove_blocks, paths, snippet, - span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, iter_input_pats}; +use utils::{is_adjusted, iter_input_pats, match_qpath, match_trait_method, match_type, paths, remove_blocks, snippet, + span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; /// **What it does:** Checks for mapping `clone()` over an iterator. /// @@ -73,21 +73,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } }} }, - ExprPath(ref path) => { - if match_qpath(path, &paths::CLONE) { - let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); - span_help_and_lint( - cx, - MAP_CLONE, - expr.span, - &format!( - "you seem to be using .map() to clone the contents of an \ - {}, consider using `.cloned()`", - type_name - ), - &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")), - ); - } + ExprPath(ref path) => if match_qpath(path, &paths::CLONE) { + let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); + span_help_and_lint( + cx, + MAP_CLONE, + expr.span, + &format!( + "you seem to be using .map() to clone the contents of an \ + {}, consider using `.cloned()`", + type_name + ), + &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")), + ); }, _ => (), } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 77050a0e299..b9a4507c5d7 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -11,8 +11,8 @@ use syntax::ast::LitKind; use syntax::ast::NodeId; use syntax::codemap::Span; use utils::paths; -use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, span_lint_and_sugg, in_external_macro, - expr_block, walk_ptrs_ty, is_expn_of, remove_blocks, is_allowed}; +use utils::{expr_block, in_external_macro, is_allowed, is_expn_of, match_type, remove_blocks, snippet, + span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty}; use utils::sugg::Sugg; /// **What it does:** Checks for matches with a single arm where an `if let` @@ -219,7 +219,7 @@ fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], lint, expr.span, "you seem to be trying to use match for destructuring a single pattern. Consider using `if \ - let`", + let`", "try this", format!( "if let {} = {} {}{}", @@ -290,21 +290,17 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if let Some((true_expr, false_expr)) = exprs { let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => { - Some(format!( - "if {} {} else {}", - 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, "..") - )) - }, + (false, false) => Some(format!( + "if {} {} else {}", + 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, ".."))) @@ -317,7 +313,6 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } } } - }, ); } @@ -384,15 +379,17 @@ fn is_panic_block(block: &Block) -> bool { fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: MatchSource, expr: &Expr) { if has_only_ref_pats(arms) { if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node { - span_lint_and_then(cx, - MATCH_REF_PATS, - expr.span, - "you don't need to add `&` to both the expression and the patterns", - |db| { - let inner = Sugg::hir(cx, inner, ".."); - let template = match_template(expr.span, source, &inner); - db.span_suggestion(expr.span, "try", template); - }); + span_lint_and_then( + cx, + MATCH_REF_PATS, + expr.span, + "you don't need to add `&` to both the expression and the patterns", + |db| { + let inner = Sugg::hir(cx, inner, ".."); + let template = match_template(expr.span, source, &inner); + db.span_suggestion(expr.span, "try", template); + }, + ); } else { span_lint_and_then( cx, @@ -471,24 +468,18 @@ fn type_ranges(ranges: &[SpannedRange<ConstVal>]) -> TypedRanges { ranges .iter() .filter_map(|range| match range.node { - (ConstVal::Integral(start), Bound::Included(ConstVal::Integral(end))) => { - Some(SpannedRange { - span: range.span, - node: (start, Bound::Included(end)), - }) - }, - (ConstVal::Integral(start), Bound::Excluded(ConstVal::Integral(end))) => { - Some(SpannedRange { - span: range.span, - node: (start, Bound::Excluded(end)), - }) - }, - (ConstVal::Integral(start), Bound::Unbounded) => { - Some(SpannedRange { - span: range.span, - node: (start, Bound::Unbounded), - }) - }, + (ConstVal::Integral(start), Bound::Included(ConstVal::Integral(end))) => Some(SpannedRange { + span: range.span, + node: (start, Bound::Included(end)), + }), + (ConstVal::Integral(start), Bound::Excluded(ConstVal::Integral(end))) => Some(SpannedRange { + span: range.span, + node: (start, Bound::Excluded(end)), + }), + (ConstVal::Integral(start), Bound::Unbounded) => Some(SpannedRange { + span: range.span, + node: (start, Bound::Unbounded), + }), _ => None, }) .collect() @@ -507,9 +498,9 @@ fn has_only_ref_pats(arms: &[Arm]) -> bool { .flat_map(|a| &a.pats) .map(|p| { match p.node { - PatKind::Ref(..) => Some(true), // &-patterns + PatKind::Ref(..) => Some(true), // &-patterns PatKind::Wild => Some(false), // an "anything" wildcard is also fine - _ => None, // any other pattern is not fine + _ => None, // any other pattern is not fine } }) .collect::<Option<Vec<bool>>>(); @@ -540,8 +531,7 @@ where impl<'a, T: Copy> Kind<'a, T> { fn range(&self) -> &'a SpannedRange<T> { match *self { - Kind::Start(_, r) | - Kind::End(_, r) => r, + Kind::Start(_, r) | Kind::End(_, r) => r, } } @@ -562,22 +552,16 @@ where impl<'a, T: Copy + Ord> Ord for Kind<'a, T> { fn cmp(&self, other: &Self) -> Ordering { match (self.value(), other.value()) { - (Bound::Included(a), Bound::Included(b)) | - (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b), + (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b), // Range patterns cannot be unbounded (yet) - (Bound::Unbounded, _) | - (_, Bound::Unbounded) => unimplemented!(), - (Bound::Included(a), Bound::Excluded(b)) => { - match a.cmp(&b) { - Ordering::Equal => Ordering::Greater, - other => other, - } + (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(), + (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) { + Ordering::Equal => Ordering::Greater, + other => other, }, - (Bound::Excluded(a), Bound::Included(b)) => { - match a.cmp(&b) { - Ordering::Equal => Ordering::Less, - other => other, - } + (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) { + Ordering::Equal => Ordering::Less, + other => other, }, } } @@ -594,10 +578,8 @@ where for (a, b) in values.iter().zip(values.iter().skip(1)) { match (a, b) { - (&Kind::Start(_, ra), &Kind::End(_, rb)) => { - if ra.node != rb.node { - return Some((ra, rb)); - } + (&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node { + return Some((ra, rb)); }, (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (), _ => return Some((a.range(), b.range())), diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index edf477720d5..9058d0d102d 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -39,8 +39,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget { if match forgot_ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), _ => false, - } - { + } { span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type"); } } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index cfaa9f698e0..84c213023a2 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -8,10 +8,10 @@ use rustc_const_eval::ConstContext; 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_qpath, match_trait_method, - match_type, method_chain_args, return_ty, same_tys, snippet, span_lint, span_lint_and_then, - span_lint_and_sugg, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, last_path_segment, - single_segment_path, match_def_path, is_self, is_self_ty, iter_input_pats, match_path}; +use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, is_self, is_self_ty, + iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, + match_type, method_chain_args, return_ty, same_tys, single_segment_path, snippet, span_lint, + span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth}; use utils::paths; use utils::sugg; @@ -618,11 +618,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } match self_ty.sty { - ty::TyRef(_, ty) if ty.ty.sty == ty::TyStr => { - for &(method, pos) in &PATTERN_METHODS { - if method_call.name == method && args.len() > pos { - lint_single_char_pattern(cx, expr, &args[pos]); - } + ty::TyRef(_, ty) if ty.ty.sty == ty::TyStr => for &(method, pos) in &PATTERN_METHODS { + if method_call.name == method && args.len() > pos { + lint_single_char_pattern(cx, expr, &args[pos]); } }, _ => (), @@ -723,12 +721,11 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: if ["default", "new"].contains(&path) { let arg_ty = cx.tables.expr_ty(arg); - let default_trait_id = - if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { - default_trait_id - } else { - return false; - }; + let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { + default_trait_id + } else { + return false; + }; if implements_trait(cx, arg_ty, default_trait_id, &[]) { span_lint_and_sugg( @@ -771,13 +768,12 @@ 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.tables.expr_ty(self_expr); @@ -835,7 +831,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t CLONE_DOUBLE_REF, expr.span, "using `clone` on a double-reference; \ - this will copy the reference instead of cloning the inner type", + 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())); }, @@ -919,7 +915,7 @@ fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir ITER_CLONED_COLLECT, expr.span, "called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", + more readable", ); } } @@ -1021,12 +1017,10 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: Ty) -> Option<sugg::S match ty.sty { ty::TySlice(_) => sugg::Sugg::hir_opt(cx, expr), ty::TyAdt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr), - ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) => { - if may_slice(cx, inner) { - sugg::Sugg::hir_opt(cx, expr) - } else { - None - } + ty::TyRef(_, ty::TypeAndMut { ty: inner, .. }) => if may_slice(cx, inner) { + sugg::Sugg::hir_opt(cx, expr) + } else { + None }, _ => None, } @@ -1052,8 +1046,8 @@ fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &[hir::Expr]) { expr.span, &format!( "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ - using expect() to provide a better panic \ - message", + using expect() to provide a better panic \ + message", kind, none_value ), @@ -1222,7 +1216,7 @@ fn lint_search_is_some( 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()`.", + expressed by calling `any()`.", search_method ); let search_snippet = snippet(cx, search_args[1].span, ".."); @@ -1459,35 +1453,37 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener single_segment_ty(ty).map_or(false, |seg| { generics.ty_params.iter().any(|param| { param.name == seg.name && - param.bounds.iter().any(|bound| { - if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { + param + .bounds + .iter() + .any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { let path = &ptr.trait_ref.path; match_path(path, name) && - path.segments.last().map_or( - false, - |s| if s.parameters.parenthesized { + path.segments + .last() + .map_or(false, |s| if s.parameters.parenthesized { false } else { s.parameters.types.len() == 1 && (is_self_ty(&s.parameters.types[0]) || is_ty(&*s.parameters.types[0], self_ty)) - }, - ) + }) } else { false - } - }) + }) }) }) } fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool { match (&ty.node, &self_ty.node) { - (&hir::TyPath(hir::QPath::Resolved(_, ref ty_path)), - &hir::TyPath(hir::QPath::Resolved(_, ref self_ty_path))) => { - ty_path.segments.iter().map(|seg| seg.name).eq( - self_ty_path.segments.iter().map(|seg| seg.name), - ) - }, + ( + &hir::TyPath(hir::QPath::Resolved(_, ref ty_path)), + &hir::TyPath(hir::QPath::Resolved(_, ref self_ty_path)), + ) => ty_path + .segments + .iter() + .map(|seg| seg.name) + .eq(self_ty_path.segments.iter().map(|seg| seg.name)), _ => false, } } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index a86b2b300e5..aea92311763 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,7 +1,7 @@ -use consts::{Constant, constant_simple}; +use consts::{constant_simple, Constant}; use rustc::lint::*; use rustc::hir::*; -use std::cmp::{PartialOrd, Ordering}; +use std::cmp::{Ordering, PartialOrd}; use utils::{match_def_path, paths, span_lint}; /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are @@ -41,9 +41,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass { return; } match (outer_max, outer_c.partial_cmp(&inner_c)) { - (_, None) | - (MinMax::Max, Some(Ordering::Less)) | - (MinMax::Min, Some(Ordering::Greater)) => (), + (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), _ => { span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); }, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e7c3fb895fb..da6919da93d 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -7,12 +7,12 @@ use rustc::ty; use rustc::ty::subst::Substs; use rustc_const_eval::ConstContext; use rustc_const_math::ConstFloat; -use syntax::codemap::{Span, ExpnFormat}; -use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_qpath, snippet, - span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment, iter_input_pats, in_constant, - match_trait_method, paths}; +use syntax::codemap::{ExpnFormat, Span}; +use utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, + iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, + span_lint_and_then, walk_ptrs_ty}; use utils::sugg::Sugg; -use syntax::ast::{LitKind, CRATE_NODE_ID, FloatTy}; +use syntax::ast::{FloatTy, LitKind, CRATE_NODE_ID}; /// **What it does:** Checks for function arguments and let bindings denoted as /// `ref`. @@ -242,7 +242,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { TOPLEVEL_REF_ARG, arg.pat.span, "`ref` directly on a function argument is ignored. Consider using a reference type \ - instead.", + instead.", ); }, _ => {}, @@ -385,7 +385,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { expr.span, &format!( "used binding `{}` which is prefixed with an underscore. A leading \ - underscore signals that a binding will not be used.", + underscore signals that a binding will not be used.", binding ), ); @@ -484,16 +484,14 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) { return; } }, - ExprCall(ref path, ref v) if v.len() == 1 => { - if let ExprPath(ref path) = path.node { - if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { - (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, "..")) - } else { - return; - } + ExprCall(ref path, ref v) if v.len() == 1 => if let ExprPath(ref path) = path.node { + if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { + (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, "..")) } else { return; } + } else { + return; }, _ => return, }; @@ -554,8 +552,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) { fn is_used(cx: &LateContext, expr: &Expr) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { match parent.node { - ExprAssign(_, ref rhs) | - ExprAssignOp(_, _, ref rhs) => **rhs == *expr, + ExprAssign(_, ref rhs) | ExprAssignOp(_, _, ref rhs) => **rhs == *expr, _ => is_used(cx, parent), } } else { @@ -567,20 +564,21 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool { /// generated by /// `#[derive(...)`] or the like). fn in_attributes_expansion(expr: &Expr) -> bool { - expr.span.ctxt().outer().expn_info().map_or( - false, - |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_)), - ) + expr.span + .ctxt() + .outer() + .expn_info() + .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(def_id) | - def::Def::Upvar(def_id, _, _) => { - let id = cx.tcx.hir.as_local_node_id(def_id).expect( - "local variables should be found in the same crate", - ); + def::Def::Local(def_id) | def::Def::Upvar(def_id, _, _) => { + let id = cx.tcx + .hir + .as_local_node_id(def_id) + .expect("local variables should be found in the same crate"); !in_macro(cx.tcx.hir.span(id)) }, _ => false, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 52a97024e44..bf4df6e2873 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -4,7 +4,7 @@ use std::char; use syntax::ast::*; use syntax::codemap::Span; use syntax::visit::FnKind; -use utils::{constants, span_lint, span_help_and_lint, snippet, snippet_opt, span_lint_and_then, in_external_macro}; +use utils::{constants, in_external_macro, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then}; /// **What it does:** Checks for structure field patterns bound to wildcards. /// @@ -251,7 +251,7 @@ impl EarlyLintPass for MiscEarly { UNNEEDED_FIELD_PATTERN, field.span, "You matched a field with a wildcard pattern. Consider using `..` \ - instead", + instead", &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")), ); } @@ -276,7 +276,7 @@ impl EarlyLintPass for MiscEarly { *correspondence, &format!( "`{}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult", + name makes code comprehension and documentation more difficult", arg_name[1..].to_owned() ), );; @@ -293,30 +293,28 @@ impl EarlyLintPass for MiscEarly { return; } match expr.node { - ExprKind::Call(ref paren, _) => { - if let ExprKind::Paren(ref closure) = paren.node { - if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node { - span_lint_and_then(cx, - REDUNDANT_CLOSURE_CALL, - 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); - }); - } - } - }, - ExprKind::Unary(UnOp::Neg, ref inner) => { - if let ExprKind::Unary(UnOp::Neg, _) = inner.node { - span_lint( + ExprKind::Call(ref paren, _) => if let ExprKind::Paren(ref closure) = paren.node { + if let ExprKind::Closure(_, ref decl, ref block, _) = closure.node { + span_lint_and_then( cx, - DOUBLE_NEG, + REDUNDANT_CLOSURE_CALL, expr.span, - "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + "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); + }, ); } }, + ExprKind::Unary(UnOp::Neg, ref inner) => if let ExprKind::Unary(UnOp::Neg, _) = inner.node { + span_lint( + cx, + DOUBLE_NEG, + expr.span, + "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + ); + }, ExprKind::Lit(ref lit) => self.check_lit(cx, lit), _ => (), } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 9ce7df474a3..81a8b4ffb2e 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -18,7 +18,7 @@ // [`missing_doc`]: // https://github. // com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin. -// +// // // // @@ -64,13 +64,15 @@ impl ::std::default::Default for MissingDoc { impl MissingDoc { pub fn new() -> Self { - Self { doc_hidden_stack: vec![false] } + Self { + doc_hidden_stack: vec![false], + } } fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect( - "empty doc_hidden_stack", - ) + *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) { @@ -89,9 +91,9 @@ impl MissingDoc { return; } - let has_doc = attrs.iter().any(|a| { - a.is_value_str() && a.name().map_or(false, |n| n == "doc") - }); + let has_doc = attrs + .iter() + .any(|a| a.is_value_str() && a.name().map_or(false, |n| n == "doc")); if !has_doc { cx.span_lint( MISSING_DOCS_IN_PRIVATE_ITEMS, @@ -110,14 +112,12 @@ impl LintPass for MissingDoc { 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"), - } - }); + 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"), + } + }); self.doc_hidden_stack.push(doc_hidden); } @@ -166,10 +166,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { let def_id = cx.tcx.hir.local_def_id(impl_item.id); match cx.tcx.associated_item(def_id).container { ty::TraitContainer(_) => return, - ty::ImplContainer(cid) => { - if cx.tcx.impl_trait_ref(cid).is_some() { - return; - } + ty::ImplContainer(cid) => if cx.tcx.impl_trait_ref(cid).is_some() { + return; }, } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index e8133050475..c12d3dde2be 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -70,7 +70,14 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { expr.span, "generally you want to avoid `&mut &mut _` if possible", ); - } else if let ty::TyRef(_, ty::TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tables.expr_ty(e).sty { + } else if let ty::TyRef( + _, + ty::TypeAndMut { + mutbl: hir::MutMutable, + .. + }, + ) = self.cx.tables.expr_ty(e).sty + { span_lint( self.cx, MUT_MUT, @@ -82,13 +89,22 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { } 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 { + ty: ref pty, + mutbl: hir::MutMutable, + }, + ) = ty.node { - if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node { + if let hir::TyRptr( + _, + hir::MutTy { + mutbl: hir::MutMutable, + .. + }, + ) = pty.node + { span_lint( self.cx, MUT_MUT, @@ -96,7 +112,6 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { "generally you want to avoid `&mut &mut _` if possible", ); } - } intravisit::walk_ty(self, ty); diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 6a7b45bfbfb..63ccc77a03d 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -36,15 +36,13 @@ impl LintPass for UnnecessaryMutPassed { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { match e.node { - ExprCall(ref fn_expr, ref arguments) => { - if let ExprPath(ref path) = fn_expr.node { - check_arguments( - cx, - arguments, - cx.tables.expr_ty(fn_expr), - &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)), - ); - } + ExprCall(ref fn_expr, ref arguments) => if let ExprPath(ref path) = fn_expr.node { + check_arguments( + cx, + arguments, + cx.tables.expr_ty(fn_expr), + &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)), + ); }, ExprMethodCall(ref path, _, ref arguments) => { let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id(); @@ -63,16 +61,23 @@ fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], typ let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in arguments.iter().zip(parameters.iter()) { match parameter.sty { - ty::TyRef(_, ty::TypeAndMut { mutbl: MutImmutable, .. }) | - ty::TyRawPtr(ty::TypeAndMut { mutbl: MutImmutable, .. }) => { - if let ExprAddrOf(MutMutable, _) = argument.node { - span_lint( - cx, - UNNECESSARY_MUT_PASSED, - argument.span, - &format!("The function/method `{}` doesn't need a mutable reference", name), - ); - } + ty::TyRef( + _, + ty::TypeAndMut { + mutbl: MutImmutable, + .. + }, + ) | + ty::TyRawPtr(ty::TypeAndMut { + mutbl: MutImmutable, + .. + }) => if let ExprAddrOf(MutMutable, _) = argument.node { + span_lint( + cx, + UNNECESSARY_MUT_PASSED, + argument.span, + &format!("The function/method `{}` doesn't need a mutable reference", name), + ); }, _ => (), } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 25a7118ceda..6fe365fd255 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -2,7 +2,7 @@ //! //! This lint is **warn** by default -use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::ty::{self, Ty}; use rustc::hir::Expr; use syntax::ast; @@ -65,7 +65,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic { if let Some(atomic_name) = get_atomic_name(mutex_param) { let msg = format!( "Consider using an {} instead of a Mutex here. If you just want the locking \ - behaviour and not the internal type, consider using Mutex<()>.", + behaviour and not the internal type, consider using Mutex<()>.", atomic_name ); match mutex_param.sty { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 52f0df12bcd..bc93190cd09 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,7 +6,7 @@ use rustc::lint::*; use rustc::hir::*; use syntax::ast::LitKind; use syntax::codemap::Spanned; -use utils::{span_lint, span_lint_and_sugg, snippet}; +use utils::{snippet, span_lint, span_lint_and_sugg}; use utils::sugg::Sugg; /// **What it does:** Checks for expressions of the form `if c { true } else { @@ -82,8 +82,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { }; if let ExprBlock(ref then_block) = then_block.node { match (fetch_bool_block(then_block), fetch_bool_expr(else_expr)) { - (RetBool(true), RetBool(true)) | - (Bool(true), Bool(true)) => { + (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => { span_lint( cx, NEEDLESS_BOOL, @@ -91,8 +90,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { "this if-then-else expression will always return true", ); }, - (RetBool(false), RetBool(false)) | - (Bool(false), Bool(false)) => { + (RetBool(false), RetBool(false)) | (Bool(false), Bool(false)) => { span_lint( cx, NEEDLESS_BOOL, @@ -186,16 +184,14 @@ enum Expression { fn fetch_bool_block(block: &Block) -> Expression { match (&*block.stmts, block.expr.as_ref()) { (&[], Some(e)) => fetch_bool_expr(&**e), - (&[ref e], None) => { - if let StmtSemi(ref e, _) = e.node { - if let ExprRet(_) = e.node { - fetch_bool_expr(&**e) - } else { - Expression::Other - } + (&[ref e], None) => if let StmtSemi(ref e, _) = e.node { + if let ExprRet(_) = e.node { + fetch_bool_expr(&**e) } else { Expression::Other } + } else { + Expression::Other }, _ => Expression::Other, } @@ -204,18 +200,14 @@ fn fetch_bool_block(block: &Block) -> Expression { fn fetch_bool_expr(expr: &Expr) -> Expression { match expr.node { ExprBlock(ref block) => fetch_bool_block(block), - ExprLit(ref lit_ptr) => { - if let LitKind::Bool(value) = lit_ptr.node { - Expression::Bool(value) - } else { - Expression::Other - } + ExprLit(ref lit_ptr) => if let LitKind::Bool(value) = lit_ptr.node { + Expression::Bool(value) + } else { + Expression::Other }, - ExprRet(Some(ref expr)) => { - match fetch_bool_expr(expr) { - Expression::Bool(value) => Expression::RetBool(value), - _ => 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 b331d6910a3..7dd42bca3ab 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -3,10 +3,10 @@ //! This lint is **warn** by default use rustc::lint::*; -use rustc::hir::{ExprAddrOf, Expr, MutImmutable, Pat, PatKind, BindingAnnotation}; +use rustc::hir::{BindingAnnotation, Expr, ExprAddrOf, MutImmutable, Pat, PatKind}; use rustc::ty; -use rustc::ty::adjustment::{Adjustment, Adjust}; -use utils::{span_lint, in_macro}; +use rustc::ty::adjustment::{Adjust, Adjustment}; +use utils::{in_macro, span_lint}; /// **What it does:** Checks for address of operations (`&`) that are going to /// be dereferenced immediately by the compiler. @@ -43,16 +43,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { if let ExprAddrOf(MutImmutable, ref inner) = e.node { if let ty::TyRef(..) = cx.tables.expr_ty(inner).sty { for adj3 in cx.tables.expr_adjustments(e).windows(3) { - if let [ - Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Borrow(_), .. } - ] = *adj3 { - span_lint(cx, - NEEDLESS_BORROW, - e.span, - "this expression borrows a reference that is immediately dereferenced by the \ - compiler"); + if let [Adjustment { + kind: Adjust::Deref(_), + .. + }, Adjustment { + kind: Adjust::Deref(_), + .. + }, Adjustment { + kind: Adjust::Borrow(_), + .. + }] = *adj3 + { + span_lint( + cx, + NEEDLESS_BORROW, + e.span, + "this expression borrows a reference that is immediately dereferenced by the \ + compiler", + ); } } } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 0aa741db076..1c00263cbc2 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -3,8 +3,8 @@ //! This lint is **warn** by default use rustc::lint::*; -use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation}; -use utils::{span_lint_and_then, in_macro, snippet}; +use rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind}; +use utils::{in_macro, snippet, span_lint_and_then}; /// **What it does:** Checks for useless borrowed references. /// diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 692fa19f3ba..b369d8b570b 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -32,7 +32,7 @@ use syntax::ast; use syntax::codemap::{original_sp, DUMMY_SP}; use std::borrow::Cow; -use utils::{in_macro, span_help_and_lint, snippet_block, snippet, trim_multiline}; +use utils::{in_macro, snippet, snippet_block, span_help_and_lint, trim_multiline}; /// **What it does:** The lint checks for `if`-statements appearing in loops /// that contain a `continue` statement in either their main blocks or their @@ -181,13 +181,10 @@ fn needless_continue_in_else(else_expr: &ast::Expr) -> bool { fn is_first_block_stmt_continue(block: &ast::Block) -> bool { block.stmts.get(0).map_or(false, |stmt| match stmt.node { - ast::StmtKind::Semi(ref e) | - ast::StmtKind::Expr(ref e) => { - if let ast::ExprKind::Continue(_) = e.node { - true - } else { - false - } + ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => if let ast::ExprKind::Continue(_) = e.node { + true + } else { + false }, _ => false, }) @@ -222,8 +219,7 @@ where F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr), { match stmt.node { - ast::StmtKind::Semi(ref e) | - ast::StmtKind::Expr(ref e) => { + ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::If(ref cond, ref if_block, Some(ref else_expr)) = e.node { func(e, cond, if_block, else_expr); } @@ -269,25 +265,20 @@ const DROP_ELSE_BLOCK_MSG: &'static str = "Consider dropping the else clause, an fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: LintType) { - // snip is the whole *help* message that appears after the warning. // message is the warning message. // expr is the expression which the lint warning message refers to. let (snip, message, expr) = match typ { - LintType::ContinueInsideElseBlock => { - ( - suggestion_snippet_for_continue_inside_else(ctx, data, header), - MSG_REDUNDANT_ELSE_BLOCK, - data.else_expr, - ) - }, - LintType::ContinueInsideThenBlock => { - ( - suggestion_snippet_for_continue_inside_if(ctx, data, header), - MSG_ELSE_BLOCK_NOT_NEEDED, - data.if_expr, - ) - }, + LintType::ContinueInsideElseBlock => ( + suggestion_snippet_for_continue_inside_else(ctx, data, header), + MSG_REDUNDANT_ELSE_BLOCK, + data.else_expr, + ), + LintType::ContinueInsideThenBlock => ( + suggestion_snippet_for_continue_inside_if(ctx, data, header), + MSG_ELSE_BLOCK_NOT_NEEDED, + data.if_expr, + ), }; span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip); } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 89ef4ff67f3..f53e8521076 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -9,9 +9,9 @@ use rustc::middle::mem_categorization as mc; use syntax::ast::NodeId; use syntax_pos::Span; use syntax::errors::DiagnosticBuilder; -use utils::{in_macro, is_self, is_copy, implements_trait, get_trait_def_id, match_type, snippet, span_lint_and_then, - multispan_sugg, paths}; -use std::collections::{HashSet, HashMap}; +use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths, + snippet, span_lint_and_then}; +use std::collections::{HashMap, HashSet}; /// **What it does:** Checks for functions taking arguments by value, but not /// consuming them in its @@ -62,16 +62,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { } match kind { - FnKind::ItemFn(.., attrs) => { - for a in attrs { - if_let_chain!{[ - a.meta_item_list().is_some(), - let Some(name) = a.name(), - name == "proc_macro_derive", - ], { - return; - }} - } + FnKind::ItemFn(.., attrs) => for a in attrs { + if_let_chain!{[ + a.meta_item_list().is_some(), + let Some(name) = a.name(), + name == "proc_macro_derive", + ], { + return; + }} }, _ => return, } @@ -106,7 +104,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig); for ((input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) { - // Determines whether `ty` implements `Borrow<U>` (U != ty) specifically. // This is needed due to the `Borrow<T> for T` blanket impl. let implements_borrow_trait = preds @@ -118,9 +115,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { }) .filter(|tpred| tpred.def_id() == borrow_trait && tpred.self_ty() == ty) .any(|tpred| { - tpred.input_types().nth(1).expect( - "Borrow trait must have an parameter", - ) != ty + tpred + .input_types() + .nth(1) + .expect("Borrow trait must have an parameter") != ty }); if_let_chain! {[ @@ -299,8 +297,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> { fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt { loop { match cmt.cat.clone() { - mc::Categorization::Downcast(c, _) | - mc::Categorization::Interior(c, _) => { + mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => { cmt = c; }, _ => return cmt, diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index c6bd91919f5..1c5524af68e 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -115,43 +115,42 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { return; } if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) { - let self_ty = cx.tcx.type_of( - cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)), - ); + let self_ty = cx.tcx + .type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id))); if_let_chain!{[ - same_tys(cx, self_ty, return_ty(cx, id)), - let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), - !implements_trait(cx, self_ty, default_trait_id, &[]) - ], { - if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { - span_lint_and_then(cx, - NEW_WITHOUT_DEFAULT_DERIVE, span, - &format!("you should consider deriving a \ - `Default` implementation for `{}`", - self_ty), - |db| { - db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]"); - }); - } else { - span_lint_and_then(cx, - NEW_WITHOUT_DEFAULT, span, - &format!("you should consider adding a \ - `Default` implementation for `{}`", - self_ty), - |db| { - db.suggest_prepend_item(cx, - span, - "try this", - &format!( + same_tys(cx, self_ty, return_ty(cx, id)), + let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT), + !implements_trait(cx, self_ty, default_trait_id, &[]) + ], { + if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { + span_lint_and_then(cx, + NEW_WITHOUT_DEFAULT_DERIVE, span, + &format!("you should consider deriving a \ + `Default` implementation for `{}`", + self_ty), + |db| { + db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]"); + }); + } else { + span_lint_and_then(cx, + NEW_WITHOUT_DEFAULT, span, + &format!("you should consider adding a \ + `Default` implementation for `{}`", + self_ty), + |db| { + db.suggest_prepend_item(cx, + span, + "try this", + &format!( "impl Default for {} {{ fn default() -> Self {{ Self::new() }} }}", - self_ty)); - }); - } - }} + self_ty)); + }); + } + }} } } } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 971309adb33..1d5e51187bb 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,7 +1,7 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::def::Def; -use rustc::hir::{Expr, Expr_, Stmt, StmtSemi, BlockCheckMode, UnsafeSource, BiAnd, BiOr}; -use utils::{in_macro, span_lint, snippet_opt, span_lint_and_sugg}; +use rustc::hir::{BiAnd, BiOr, BlockCheckMode, Expr, Expr_, Stmt, StmtSemi, UnsafeSource}; +use utils::{in_macro, snippet_opt, span_lint, span_lint_and_sugg}; use std::ops::Deref; /// **What it does:** Checks for statements which have no effect. @@ -45,13 +45,11 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { return false; } match expr.node { - Expr_::ExprLit(..) | - Expr_::ExprClosure(.., _) | - Expr_::ExprPath(..) => true, - Expr_::ExprIndex(ref a, ref b) | - Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b), - Expr_::ExprArray(ref v) | - Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), + Expr_::ExprLit(..) | Expr_::ExprClosure(.., _) | Expr_::ExprPath(..) => true, + Expr_::ExprIndex(ref a, ref b) | Expr_::ExprBinary(_, ref a, ref b) => { + has_no_effect(cx, a) && has_no_effect(cx, b) + }, + Expr_::ExprArray(ref v) | Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), Expr_::ExprRepeat(ref inner, _) | Expr_::ExprCast(ref inner, _) | Expr_::ExprType(ref inner, _) | @@ -61,33 +59,28 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprBox(ref inner) => has_no_effect(cx, inner), Expr_::ExprStruct(_, ref fields, ref base) => { - fields.iter().all(|field| has_no_effect(cx, &field.expr)) && - match *base { - Some(ref base) => has_no_effect(cx, base), - None => true, - } + fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base { + Some(ref base) => has_no_effect(cx, base), + None => true, + } }, - Expr_::ExprCall(ref callee, ref args) => { - if let Expr_::ExprPath(ref qpath) = callee.node { - let def = cx.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Struct(..) | - Def::Variant(..) | - Def::StructCtor(..) | - Def::VariantCtor(..) => args.iter().all(|arg| has_no_effect(cx, arg)), - _ => false, - } - } else { - false + Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node { + let def = cx.tables.qpath_def(qpath, callee.hir_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 { - has_no_effect(cx, expr) - } else { - false - } + block.stmts.is_empty() && if let Some(ref expr) = block.expr { + has_no_effect(cx, expr) + } else { + false + } }, _ => false, } @@ -143,8 +136,7 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp Expr_::ExprBinary(ref binop, ref a, ref b) if binop.node != BiAnd && binop.node != BiOr => { Some(vec![&**a, &**b]) }, - Expr_::ExprArray(ref v) | - Expr_::ExprTup(ref v) => Some(v.iter().collect()), + Expr_::ExprArray(ref v) | Expr_::ExprTup(ref v) => Some(v.iter().collect()), Expr_::ExprRepeat(ref inner, _) | Expr_::ExprCast(ref inner, _) | Expr_::ExprType(ref inner, _) | @@ -153,29 +145,24 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp Expr_::ExprTupField(ref inner, _) | Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprBox(ref inner) => 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) => { - if let Expr_::ExprPath(ref qpath) = callee.node { - let def = cx.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Struct(..) | - Def::Variant(..) | - Def::StructCtor(..) | - Def::VariantCtor(..) => Some(args.iter().collect()), - _ => None, - } - } else { - None + 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) => if let Expr_::ExprPath(ref qpath) = callee.node { + let def = cx.tables.qpath_def(qpath, callee.hir_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() { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index c584e3b1a9e..d36054eacf4 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -3,8 +3,8 @@ use syntax::codemap::Span; use syntax::symbol::InternedString; use syntax::ast::*; use syntax::attr; -use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr}; -use utils::{span_lint_and_then, in_macro, span_lint}; +use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; +use utils::{in_macro, span_lint, span_lint_and_then}; /// **What it does:** Checks for names that are very similar and thus confusing. /// @@ -82,11 +82,9 @@ 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, _) => { - for field in fields { - if !field.node.is_shorthand { - self.visit_pat(&field.node.pat); - } + PatKind::Struct(_, ref fields, _) => for field in fields { + if !field.node.is_shorthand { + self.visit_pat(&field.node.pat); } }, _ => walk_pat(self, pat), @@ -104,9 +102,8 @@ fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { } fn whitelisted(interned_name: &str, list: &[&str]) -> bool { - list.iter().any(|&name| { - interned_name.starts_with(name) || interned_name.ends_with(name) - }) + list.iter() + .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name)) } impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { @@ -157,21 +154,21 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } else { let mut interned_chars = interned_name.chars(); let mut existing_chars = existing_name.interned.chars(); - let first_i = interned_chars.next().expect( - "we know we have at least one char", - ); - let first_e = existing_chars.next().expect( - "we know we have at least one char", - ); + let first_i = interned_chars + .next() + .expect("we know we have at least one char"); + let first_e = existing_chars + .next() + .expect("we know we have at least one char"); let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); if eq_or_numeric((first_i, first_e)) { - let last_i = interned_chars.next_back().expect( - "we know we have at least two chars", - ); - let last_e = existing_chars.next_back().expect( - "we know we have at least two chars", - ); + let last_i = interned_chars + .next_back() + .expect("we know we have at least two chars"); + let last_e = existing_chars + .next_back() + .expect("we know we have at least two chars"); if eq_or_numeric((last_i, last_e)) { if interned_chars .zip(existing_chars) @@ -181,12 +178,12 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { continue; } } else { - let second_last_i = interned_chars.next_back().expect( - "we know we have at least three chars", - ); - let second_last_e = existing_chars.next_back().expect( - "we know we have at least three chars", - ); + let second_last_i = interned_chars + .next_back() + .expect("we know we have at least three chars"); + let second_last_e = existing_chars + .next_back() + .expect("we know we have at least three chars"); if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' || !interned_chars.zip(existing_chars).all(eq_or_numeric) { @@ -197,12 +194,12 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); } } else { - let second_i = interned_chars.next().expect( - "we know we have at least two chars", - ); - let second_e = existing_chars.next().expect( - "we know we have at least two chars", - ); + let second_i = interned_chars + .next() + .expect("we know we have at least two chars"); + let second_e = existing_chars + .next() + .expect("we know we have at least two chars"); if !eq_or_numeric((second_i, second_e)) || second_i == '_' || !interned_chars.zip(existing_chars).all(eq_or_numeric) { @@ -225,7 +222,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { span, &format!( "separate the discriminating character by an \ - underscore like: `{}_{}`", + underscore like: `{}_{}`", &interned_name[..split], &interned_name[split..] ), diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index ee55ea882b0..67d39333ff9 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{paths, method_chain_args, span_help_and_lint, match_type, snippet}; +use utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint}; /// **What it does:*** Checks for unnecessary `ok()` in if let. /// diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index e67c1f4d148..62760888933 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,4 +1,4 @@ -use rustc::hir::{Expr, ExprMethodCall, ExprLit}; +use rustc::hir::{Expr, ExprLit, ExprMethodCall}; use rustc::lint::*; use syntax::ast::LitKind; use syntax::codemap::{Span, Spanned}; @@ -67,11 +67,18 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp // Only proceed if this is a call on some object of type std::fs::OpenOptions if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { - 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 let Spanned { + node: LitKind::Bool(lit), + .. + } = **span + { + 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 diff --git a/clippy_lints/src/panic.rs b/clippy_lints/src/panic.rs index 70ee7de7b4d..a050873187d 100644 --- a/clippy_lints/src/panic.rs +++ b/clippy_lints/src/panic.rs @@ -1,7 +1,7 @@ use rustc::hir::*; use rustc::lint::*; use syntax::ast::LitKind; -use utils::{is_direct_expn_of, match_def_path, resolve_node, paths, span_lint}; +use utils::{is_direct_expn_of, match_def_path, paths, resolve_node, span_lint}; /// **What it does:** Checks for missing parameters in `panic!`. /// diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index f5a6833b4b0..e06c571b6f6 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use syntax::ast::*; use syntax::codemap::Spanned; -use utils::{span_lint_and_sugg, snippet}; +use utils::{snippet, span_lint_and_sugg}; /// **What it does:** Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: @@ -89,9 +89,7 @@ impl EarlyLintPass for Precedence { if let Some(slf) = args.first() { if let ExprKind::Lit(ref lit) = slf.node { match lit.node { - LitKind::Int(..) | - LitKind::Float(..) | - LitKind::FloatUnsuffixed(..) => { + LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { span_lint_and_sugg( cx, PRECEDENCE, diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index 982b46e20d3..9aca7543396 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -1,8 +1,8 @@ use rustc::hir::*; -use rustc::hir::map::Node::{NodeItem, NodeImplItem}; +use rustc::hir::map::Node::{NodeImplItem, NodeItem}; use rustc::lint::*; use utils::paths; -use utils::{is_expn_of, match_def_path, resolve_node, span_lint, match_path}; +use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint}; use format::get_argument_fmtstr_parts; /// **What it does:** This lint warns when you using `print!()` with a format diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index a21142a257d..f12ec039f73 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -128,11 +128,13 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { let fn_ty = sig.skip_binder(); for (arg, ty) in decl.inputs.iter().zip(fn_ty.inputs()) { - if let ty::TyRef(_, - ty::TypeAndMut { - ty, - mutbl: MutImmutable, - }) = ty.sty + if let ty::TyRef( + _, + ty::TypeAndMut { + ty, + mutbl: MutImmutable, + }, + ) = ty.sty { if match_type(cx, ty, &paths::VEC) { span_lint( @@ -140,7 +142,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { PTR_ARG, arg.span, "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices. Consider changing the type to `&[...]`", + with non-Vec-based slices. Consider changing the type to `&[...]`", ); } else if match_type(cx, ty, &paths::STRING) { span_lint( @@ -148,7 +150,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { PTR_ARG, arg.span, "writing `&String` instead of `&str` involves a new object where a slice will do. \ - Consider changing the type to `&str`", + Consider changing the type to `&str`", ); } } @@ -157,10 +159,10 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) { if let FunctionRetTy::Return(ref ty) = decl.output { if let Some((out, MutMutable, _)) = get_rptr_lm(ty) { let mut immutables = vec![]; - for (_, ref mutbl, ref argspan) in - decl.inputs.iter().filter_map(|ty| get_rptr_lm(ty)).filter( - |&(lt, _, _)| lt.name == out.name, - ) + for (_, ref mutbl, ref argspan) in decl.inputs + .iter() + .filter_map(|ty| get_rptr_lm(ty)) + .filter(|&(lt, _, _)| lt.name == out.name) { if *mutbl == MutMutable { return; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index aa43fb6b620..44c909810ea 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::hir::*; use utils::{is_integer_literal, paths, snippet, span_lint}; -use utils::{higher, implements_trait, get_trait_def_id}; +use utils::{get_trait_def_id, higher, implements_trait}; /// **What it does:** Checks for calling `.step_by(0)` on iterators, /// which never terminates. @@ -54,7 +54,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero { // Range with step_by(0). if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) { - use consts::{Constant, constant}; + use consts::{constant, Constant}; use rustc_const_math::ConstInt::Usize; if let Some((Constant::Int(Usize(us)), _)) = constant(cx, &args[1]) { if us.as_u64(cx.sess().target.uint_type) == 0 { diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index a8360c71f91..fce3c6ad285 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,6 +1,6 @@ use syntax::ast::{Expr, ExprKind, UnOp}; use rustc::lint::*; -use utils::{span_lint_and_sugg, snippet}; +use utils::{snippet, span_lint_and_sugg}; /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. /// diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index c1011168c52..8b5dedfccd4 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -7,9 +7,9 @@ use rustc::ty::subst::Substs; use std::collections::HashSet; use std::error::Error; use syntax::ast::{LitKind, NodeId}; -use syntax::codemap::{Span, BytePos}; +use syntax::codemap::{BytePos, Span}; use syntax::symbol::InternedString; -use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint}; +use utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint}; /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct @@ -161,27 +161,19 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { match *s { Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), Expr::Literal { .. } => Some("consider using `str::contains`"), - Expr::Concat(ref exprs) => { - match exprs.len() { - 2 => { - match (&exprs[0], &exprs[1]) { - (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), - (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), - (&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]) - { - Some("consider using `==` on `str`s") - } else { - None - } - }, + Expr::Concat(ref exprs) => match exprs.len() { + 2 => match (&exprs[0], &exprs[1]) { + (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), + (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), + (&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]) { + Some("consider using `==` on `str`s") + } else { + None + }, + _ => None, }, _ => None, } @@ -205,16 +197,14 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { if let LitKind::Str(ref r, _) = lit.node { let r = &r.as_str(); match builder.parse(r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint( - cx, - TRIVIAL_REGEX, - expr.span, - "trivial regex", - &format!("consider using {}", repl), - ); - } + Ok(r) => if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint( + cx, + TRIVIAL_REGEX, + expr.span, + "trivial regex", + &format!("consider using {}", repl), + ); }, Err(e) => { span_lint( @@ -228,16 +218,14 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) { } } else if let Some(r) = const_str(cx, expr) { match builder.parse(&r) { - Ok(r) => { - if let Some(repl) = is_trivial_regex(&r) { - span_help_and_lint( - cx, - TRIVIAL_REGEX, - expr.span, - "trivial regex", - &format!("consider using {}", repl), - ); - } + Ok(r) => if let Some(repl) = is_trivial_regex(&r) { + span_help_and_lint( + cx, + TRIVIAL_REGEX, + expr.span, + "trivial regex", + &format!("consider using {}", repl), + ); }, Err(e) => { span_lint( diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index b9fcb62de73..0884ebbf5cf 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -3,7 +3,7 @@ use syntax::ast; use syntax::codemap::{Span, Spanned}; use syntax::visit::FnKind; -use utils::{span_note_and_lint, span_lint_and_then, snippet_opt, match_path_ast, in_macro, in_external_macro}; +use utils::{in_external_macro, in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint}; /// **What it does:** Checks for return statements at the end of a block. /// @@ -50,8 +50,7 @@ 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)); }, _ => (), @@ -81,10 +80,8 @@ impl ReturnPass { 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)); - } + ast::ExprKind::Match(_, ref arms) => for arm in arms { + self.check_final_expr(cx, &arm.body, Some(arm.body.span)); }, _ => (), } @@ -140,8 +137,7 @@ 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, Some(body.span)), } } diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 4feaaa19287..0ea24a33393 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{span_lint, get_trait_def_id, paths}; +use utils::{get_trait_def_id, paths, span_lint}; /// **What it does:** Checks for mis-uses of the serde API. /// diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 5649847b334..f6461b2d438 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -4,7 +4,7 @@ use rustc::hir::*; use rustc::hir::intravisit::FnKind; use rustc::ty; use syntax::codemap::Span; -use utils::{contains_name, higher, in_external_macro, snippet, span_lint_and_then, iter_input_pats}; +use utils::{contains_name, higher, in_external_macro, iter_input_pats, snippet, span_lint_and_then}; /// **What it does:** Checks for bindings that shadow other bindings already in /// scope, while just changing reference level or mutability. @@ -111,8 +111,7 @@ fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, binding for stmt in &block.stmts { match stmt.node { StmtDecl(ref decl, _) => check_decl(cx, decl, bindings), - StmtExpr(ref e, _) | - StmtSemi(ref e, _) => check_expr(cx, e, bindings), + StmtExpr(ref e, _) | StmtSemi(ref e, _) => check_expr(cx, e, bindings), } } if let Some(ref o) = block.expr { @@ -185,54 +184,49 @@ fn check_pat<'a, 'tcx>( check_pat(cx, p, init, span, bindings); } }, - PatKind::Struct(_, ref pfields, _) => { - 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); - } - } else { - for field in pfields { - check_pat(cx, &field.node.pat, init, span, bindings); - } + PatKind::Struct(_, ref pfields, _) => 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); } } else { for field in pfields { - check_pat(cx, &field.node.pat, None, span, bindings); + check_pat(cx, &field.node.pat, init, span, bindings); } } + } else { + for field in pfields { + check_pat(cx, &field.node.pat, None, span, bindings); + } }, - PatKind::Tuple(ref inner, _) => { - 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); - } - } else { - for p in inner { - check_pat(cx, p, init, span, bindings); - } + PatKind::Tuple(ref inner, _) => 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); } } else { for p in inner { - check_pat(cx, p, None, span, bindings); + check_pat(cx, p, init, span, bindings); } } + } else { + for p in inner { + check_pat(cx, p, None, span, bindings); + } }, - PatKind::Box(ref inner) => { - if let Some(initp) = init { - if let ExprBox(ref inner_init) = initp.node { - check_pat(cx, inner, Some(&**inner_init), span, bindings); - } else { - check_pat(cx, inner, init, span, bindings); - } + PatKind::Box(ref inner) => if let Some(initp) = init { + if let ExprBox(ref inner_init) = initp.node { + 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<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), @@ -292,13 +286,14 @@ fn lint_shadow<'a, 'tcx: 'a>( }, ); } - } else { - span_lint_and_then(cx, - SHADOW_UNRELATED, - span, - &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), - |db| { db.span_note(prev_span, "previous binding is here"); }); + span_lint_and_then( + cx, + SHADOW_UNRELATED, + span, + &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), + |db| { db.span_note(prev_span, "previous binding is here"); }, + ); } } @@ -307,19 +302,14 @@ fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings: return; } match expr.node { - ExprUnary(_, ref e) | - ExprField(ref e, _) | - ExprTupField(ref e, _) | - ExprAddrOf(_, ref e) | - ExprBox(ref e) => check_expr(cx, e, bindings), - ExprBlock(ref block) | - ExprLoop(ref block, _, _) => check_block(cx, block, bindings), + ExprUnary(_, ref e) | ExprField(ref e, _) | ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(ref e) => { + check_expr(cx, e, bindings) + }, + ExprBlock(ref block) | ExprLoop(ref block, _, _) => check_block(cx, block, bindings), // ExprCall // ExprMethodCall - ExprArray(ref v) | ExprTup(ref v) => { - for e in v { - check_expr(cx, e, bindings) - } + ExprArray(ref v) | ExprTup(ref v) => for e in v { + check_expr(cx, e, bindings) }, ExprIf(ref cond, ref then, ref otherwise) => { check_expr(cx, cond, bindings); @@ -358,12 +348,9 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut V check_ty(cx, fty, bindings); check_expr(cx, &cx.tcx.hir.body(body_id).value, bindings); }, - TyPtr(MutTy { ty: ref mty, .. }) | - TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings), - TyTup(ref tup) => { - for t in tup { - check_ty(cx, t, 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(body_id) => check_expr(cx, &cx.tcx.hir.body(body_id).value, bindings), _ => (), @@ -372,14 +359,13 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut V fn is_self_shadow(name: Name, expr: &Expr) -> bool { match expr.node { - ExprBox(ref inner) | - ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), + ExprBox(ref inner) | 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), - ) + 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(QPath::Resolved(_, ref path)) => path_eq_name(name, path), diff --git a/clippy_lints/src/should_assert_eq.rs b/clippy_lints/src/should_assert_eq.rs index ecb2c9c3162..b8cc6873adc 100644 --- a/clippy_lints/src/should_assert_eq.rs +++ b/clippy_lints/src/should_assert_eq.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{is_direct_expn_of, is_expn_of, implements_trait, span_lint}; +use utils::{implements_trait, is_direct_expn_of, is_expn_of, span_lint}; /// **What it does:** Checks for `assert!(x == y)` or `assert!(x != y)` which /// can be better written diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 587ad38c9e5..0365322ef68 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -2,7 +2,7 @@ use rustc::hir::*; use rustc::lint::*; use syntax::codemap::Spanned; use utils::SpanlessEq; -use utils::{match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty, get_parent_expr, is_allowed}; +use utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; /// **What it does:** Checks for string appends of the form `x = x + y` (without /// `let`!). @@ -108,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { STRING_ADD_ASSIGN, e.span, "you assigned the result of adding something to this string. Consider using \ - `String::push_str()` instead", + `String::push_str()` instead", ); } } @@ -124,10 +124,10 @@ 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), - ) + block + .expr + .as_ref() + .map_or(false, |expr| is_add(cx, expr, target)) }, _ => false, } @@ -146,7 +146,7 @@ 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}; + use utils::{in_macro, snippet}; if let ExprMethodCall(ref path, _, ref args) = e.node { if path.name == "as_bytes" { diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 1669b2d6557..877321255c1 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -41,11 +41,8 @@ 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, _) | - ExprTupField(ref base, _) => { - if is_temporary(base) && !is_adjusted(cx, base) { - span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); - } + ExprField(ref base, _) | ExprTupField(ref base, _) => 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 83e212c36d1..a590bf744bf 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty::{self, Ty}; use rustc::hir::*; -use utils::{match_def_path, paths, span_lint, span_lint_and_then, snippet, last_path_segment}; +use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; use utils::sugg; /// **What it does:** Checks for transmutes that can't ever be correct on any @@ -95,103 +95,88 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { let to_ty = cx.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), - ) - }, - (&ty::TyRef(_, rty), &ty::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) - } else { - arg.as_ty(cx.tcx.mk_ptr(rty)).as_ty(to_ty) - }; + _ if from_ty == to_ty => span_lint( + cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty), + ), + (&ty::TyRef(_, rty), &ty::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) + } else { + arg.as_ty(cx.tcx.mk_ptr(rty)).as_ty(to_ty) + }; - db.span_suggestion(e.span, "try", sugg.to_string()); - }, - ) - }, - (&ty::TyInt(_), &ty::TyRawPtr(_)) | - (&ty::TyUint(_), &ty::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()); - }, - ) - }, + db.span_suggestion(e.span, "try", sugg.to_string()); + }, + ), + (&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::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(_), &ty::TyRef(..)) | (&ty::TyFloat(_), &ty::TyRawPtr(_)) | (&ty::TyChar, &ty::TyRef(..)) | - (&ty::TyChar, &ty::TyRawPtr(_)) => { - span_lint( - cx, - WRONG_TRANSMUTE, - e.span, - &format!("transmute from a `{}` to a pointer", from_ty), - ) - }, - (&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 - ), - ) - }, - (_, &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), - ) - }, - (&ty::TyRawPtr(from_pty), &ty::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") - } else { - ("&*", "*const") - }; + (&ty::TyChar, &ty::TyRawPtr(_)) => span_lint( + cx, + WRONG_TRANSMUTE, + e.span, + &format!("transmute from a `{}` to a pointer", from_ty), + ), + (&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 + ), + ), + (_, &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), + ), + (&ty::TyRawPtr(from_pty), &ty::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") + } else { + ("&*", "*const") + }; - let arg = if from_pty.ty == to_rty.ty { - arg - } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_rty.ty))) - }; + let arg = if from_pty.ty == to_rty.ty { + arg + } else { + 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()); - }, - ) - }, + db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string()); + }, + ), _ => return, }; } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 05a498ff262..78e06fa80dd 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,16 +1,16 @@ use reexport::*; use rustc::hir; use rustc::hir::*; -use rustc::hir::intravisit::{FnKind, Visitor, walk_ty, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc::lint::*; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use std::cmp::Ordering; -use syntax::ast::{IntTy, UintTy, FloatTy}; +use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr::IntType; use syntax::codemap::Span; -use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint, - span_lint_and_sugg, opt_def_id, last_path_segment, type_size, match_path}; +use utils::{comparisons, higher, in_external_macro, in_macro, last_path_segment, match_def_path, match_path, + opt_def_id, snippet, span_help_and_lint, span_lint, span_lint_and_sugg, type_size}; use utils::paths; /// Handles all the linting of funky types @@ -114,8 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { match item.node { - TraitItemKind::Const(ref ty, _) | - TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false), + TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false), TraitItemKind::Method(ref sig, _) => check_fn_decl(cx, &sig.decl), _ => (), } @@ -182,20 +181,18 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { match *qpath { QPath::Resolved(Some(ref ty), ref p) => { check_ty(cx, ty, is_local); - for ty in p.segments.iter().flat_map( - |seg| seg.parameters.types.iter(), - ) + for ty in p.segments + .iter() + .flat_map(|seg| seg.parameters.types.iter()) { check_ty(cx, ty, is_local); } }, - QPath::Resolved(None, ref p) => { - for ty in p.segments.iter().flat_map( - |seg| seg.parameters.types.iter(), - ) - { - check_ty(cx, ty, is_local); - } + QPath::Resolved(None, ref p) => for ty in p.segments + .iter() + .flat_map(|seg| seg.parameters.types.iter()) + { + check_ty(cx, ty, is_local); }, QPath::TypeRelative(ref ty, ref seg) => { check_ty(cx, ty, is_local); @@ -248,13 +245,9 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { } }, // recurse - TySlice(ref ty) | - TyArray(ref ty, _) | - TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local), - TyTup(ref tys) => { - for ty in tys { - check_ty(cx, ty, is_local); - } + TySlice(ref ty) | TyArray(ref ty, _) | TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local), + TyTup(ref tys) => for ty in tys { + check_ty(cx, ty, is_local); }, _ => {}, } @@ -529,25 +522,21 @@ declare_lint! { /// Will return 0 if the type is not an int or uint variant fn int_ty_to_nbits(typ: Ty, tcx: TyCtxt) -> u64 { match typ.sty { - ty::TyInt(i) => { - match i { - IntTy::Is => tcx.data_layout.pointer_size.bits(), - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - } + ty::TyInt(i) => match i { + IntTy::Is => tcx.data_layout.pointer_size.bits(), + IntTy::I8 => 8, + IntTy::I16 => 16, + IntTy::I32 => 32, + IntTy::I64 => 64, + IntTy::I128 => 128, }, - ty::TyUint(i) => { - match i { - UintTy::Us => tcx.data_layout.pointer_size.bits(), - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - } + ty::TyUint(i) => match i { + UintTy::Us => tcx.data_layout.pointer_size.bits(), + UintTy::U8 => 8, + UintTy::U16 => 16, + UintTy::U32 => 32, + UintTy::U64 => 64, + UintTy::U128 => 128, }, _ => 0, } @@ -555,8 +544,7 @@ fn int_ty_to_nbits(typ: Ty, tcx: TyCtxt) -> u64 { fn is_isize_or_usize(typ: Ty) -> bool { match typ.sty { - ty::TyInt(IntTy::Is) | - ty::TyUint(UintTy::Us) => true, + ty::TyInt(IntTy::Is) | ty::TyUint(UintTy::Us) => true, _ => false, } } @@ -578,7 +566,7 @@ fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_t expr.span, &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)", + is only {4} bits wide)", cast_from, if cast_to_f64 { "f64" } else { "f32" }, if arch_dependent { @@ -617,38 +605,32 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: Ty, c let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => { - ( - to_nbits < from_nbits, - 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 - }, - 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 - }, - ) - }, + (true, true) | (false, false) => ( + to_nbits < from_nbits, + 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 + }, + 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 + }, + ), }; if span_truncation { span_lint( @@ -690,8 +672,7 @@ fn check_lossless(cx: &LateContext, expr: &Expr, op: &Expr, cast_from: Ty, cast_ let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed(); let from_nbits = int_ty_to_nbits(cast_from, cx.tcx); let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); - if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && - !cast_signed_to_unsigned + if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned { span_lossless_lint(cx, expr, op, cast_from, cast_to); } @@ -715,19 +696,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { if let ExprCast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr)); if let ExprLit(ref lit) = ex.node { - use syntax::ast::{LitKind, LitIntType}; + use syntax::ast::{LitIntType, LitKind}; match lit.node { - LitKind::Int(_, LitIntType::Unsuffixed) | - LitKind::FloatUnsuffixed(_) => {}, - _ => { - if cast_from.sty == cast_to.sty && !in_external_macro(cx, expr.span) { - span_lint( - cx, - UNNECESSARY_CAST, - expr.span, - &format!("casting to the same type is unnecessary (`{}` -> `{}`)", cast_from, cast_to), - ); - } + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(_) => {}, + _ => if cast_from.sty == cast_to.sty && !in_external_macro(cx, expr.span) { + span_lint( + cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting to the same type is unnecessary (`{}` -> `{}`)", cast_from, cast_to), + ); }, } } @@ -776,8 +754,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { check_lossless(cx, expr, ex, 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, @@ -786,8 +763,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { "casting f64 to f32 may truncate the value", ); } - if let (&ty::TyFloat(FloatTy::F32), &ty::TyFloat(FloatTy::F64)) = - (&cast_from.sty, &cast_to.sty) + if let (&ty::TyFloat(FloatTy::F32), &ty::TyFloat(FloatTy::F64)) = (&cast_from.sty, &cast_to.sty) { span_lossless_lint(cx, expr, ex, cast_from, cast_to); } @@ -823,7 +799,9 @@ pub struct TypeComplexityPass { impl TypeComplexityPass { pub fn new(threshold: u64) -> Self { - Self { threshold: threshold } + Self { + threshold: threshold, + } } } @@ -853,8 +831,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { 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), + ItemStatic(ref ty, _, _) | ItemConst(ref ty, _) => self.check_type(cx, ty), // functions, enums, structs, impls and traits are covered _ => (), } @@ -862,8 +839,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { match item.node { - TraitItemKind::Const(ref ty, _) | - TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty), + TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => self.check_type(cx, ty), TraitItemKind::Method(MethodSig { ref decl, .. }, TraitMethod::Required(_)) => self.check_fndecl(cx, decl), // methods with default impl are covered by check_fn _ => (), @@ -872,8 +848,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { 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), + ImplItemKind::Const(ref ty, _) | ImplItemKind::Type(ref ty) => self.check_type(cx, ty), // methods are covered by check_fn _ => (), } @@ -938,9 +913,9 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { TyBareFn(..) => (50 * self.nest, 1), TyTraitObject(ref param_bounds, _) => { - let has_lifetime_parameters = param_bounds.iter().any( - |bound| !bound.bound_lifetimes.is_empty(), - ); + let has_lifetime_parameters = param_bounds + .iter() + .any(|bound| !bound.bound_lifetimes.is_empty()); if has_lifetime_parameters { // complex trait bounds like A<'a, 'b> (50 * self.nest, 1) @@ -1101,7 +1076,7 @@ fn detect_absurd_comparison<'a>( Rel::Le => { match (lx, rx) { (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x - (Some(l @ ExtremeExpr { which: Maximum, .. }), _) => (l, InequalityImpossible), //max <= 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, @@ -1187,14 +1162,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { let conclusion = match result { AlwaysFalse => "this comparison is always false".to_owned(), AlwaysTrue => "this comparison is always true".to_owned(), - InequalityImpossible => { - format!( - "the case where the two sides are not equal never occurs, consider using {} == {} \ - instead", - snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs") - ) - }, + InequalityImpossible => format!( + "the case where the two sides are not equal never occurs, consider using {} == {} \ + instead", + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs") + ), }; let help = format!( @@ -1264,9 +1237,8 @@ impl FullInt { impl PartialEq for FullInt { fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect( - "partial_cmp only returns Some(_)", - ) == Ordering::Equal + self.partial_cmp(other) + .expect("partial_cmp only returns Some(_)") == Ordering::Equal } } @@ -1282,9 +1254,8 @@ impl PartialOrd for FullInt { } impl Ord for FullInt { fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).expect( - "partial_cmp for FullInt can never return None", - ) + self.partial_cmp(other) + .expect("partial_cmp for FullInt can never return None") } } @@ -1301,44 +1272,40 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<( return None; } match pre_cast_ty.sty { - ty::TyInt(int_ty) => { - Some(match int_ty { - IntTy::I8 => (FullInt::S(i128::from(i8::min_value())), FullInt::S(i128::from(i8::max_value()))), - IntTy::I16 => ( - FullInt::S(i128::from(i16::min_value())), - FullInt::S(i128::from(i16::max_value())), - ), - IntTy::I32 => ( - FullInt::S(i128::from(i32::min_value())), - FullInt::S(i128::from(i32::max_value())), - ), - IntTy::I64 => ( - FullInt::S(i128::from(i64::min_value())), - FullInt::S(i128::from(i64::max_value())), - ), - IntTy::I128 => (FullInt::S(i128::min_value() as i128), FullInt::S(i128::max_value() as i128)), - IntTy::Is => (FullInt::S(isize::min_value() as i128), FullInt::S(isize::max_value() as i128)), - }) - }, - ty::TyUint(uint_ty) => { - Some(match uint_ty { - UintTy::U8 => (FullInt::U(u128::from(u8::min_value())), FullInt::U(u128::from(u8::max_value()))), - UintTy::U16 => ( - FullInt::U(u128::from(u16::min_value())), - FullInt::U(u128::from(u16::max_value())), - ), - UintTy::U32 => ( - FullInt::U(u128::from(u32::min_value())), - FullInt::U(u128::from(u32::max_value())), - ), - UintTy::U64 => ( - FullInt::U(u128::from(u64::min_value())), - FullInt::U(u128::from(u64::max_value())), - ), - UintTy::U128 => (FullInt::U(u128::min_value() as u128), FullInt::U(u128::max_value() as u128)), - UintTy::Us => (FullInt::U(usize::min_value() as u128), FullInt::U(usize::max_value() as u128)), - }) - }, + ty::TyInt(int_ty) => Some(match int_ty { + IntTy::I8 => (FullInt::S(i128::from(i8::min_value())), FullInt::S(i128::from(i8::max_value()))), + IntTy::I16 => ( + FullInt::S(i128::from(i16::min_value())), + FullInt::S(i128::from(i16::max_value())), + ), + IntTy::I32 => ( + FullInt::S(i128::from(i32::min_value())), + FullInt::S(i128::from(i32::max_value())), + ), + IntTy::I64 => ( + FullInt::S(i128::from(i64::min_value())), + FullInt::S(i128::from(i64::max_value())), + ), + IntTy::I128 => (FullInt::S(i128::min_value() as i128), FullInt::S(i128::max_value() as i128)), + IntTy::Is => (FullInt::S(isize::min_value() as i128), FullInt::S(isize::max_value() as i128)), + }), + ty::TyUint(uint_ty) => Some(match uint_ty { + UintTy::U8 => (FullInt::U(u128::from(u8::min_value())), FullInt::U(u128::from(u8::max_value()))), + UintTy::U16 => ( + FullInt::U(u128::from(u16::min_value())), + FullInt::U(u128::from(u16::max_value())), + ), + UintTy::U32 => ( + FullInt::U(u128::from(u32::min_value())), + FullInt::U(u128::from(u32::max_value())), + ), + UintTy::U64 => ( + FullInt::U(u128::from(u64::min_value())), + FullInt::U(u128::from(u64::max_value())), + ), + UintTy::U128 => (FullInt::U(u128::min_value() as u128), FullInt::U(u128::max_value() as u128)), + UintTy::Us => (FullInt::U(usize::min_value() as u128), FullInt::U(usize::max_value() as u128)), + }), _ => None, } } else { @@ -1355,15 +1322,13 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> { let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr) { - Ok(val) => { - if let Integral(const_int) = val { - match const_int.int_type() { - IntType::SignedInt(_) => Some(FullInt::S(const_int.to_u128_unchecked() as i128)), - IntType::UnsignedInt(_) => Some(FullInt::U(const_int.to_u128_unchecked())), - } - } else { - None + Ok(val) => if let Integral(const_int) = val { + match const_int.int_type() { + IntType::SignedInt(_) => Some(FullInt::S(const_int.to_u128_unchecked() as i128)), + IntType::UnsignedInt(_) => Some(FullInt::U(const_int.to_u128_unchecked())), } + } else { + None }, Err(_) => None, } @@ -1402,42 +1367,32 @@ fn upcast_comparison_bounds_err( err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); } } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val < lb - } else { - ub < norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val <= lb - } else { - ub <= norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } - { + Rel::Lt => if invert { + norm_rhs_val < lb + } 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) } else if match rel { - Rel::Lt => { - if invert { - norm_rhs_val >= ub - } else { - lb >= norm_rhs_val - } - }, - Rel::Le => { - if invert { - norm_rhs_val > ub - } else { - lb > norm_rhs_val - } - }, - Rel::Eq | Rel::Ne => unreachable!(), - } - { + Rel::Lt => if invert { + norm_rhs_val >= ub + } 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) } } @@ -1447,7 +1402,6 @@ fn upcast_comparison_bounds_err( 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); let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { val diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 14d6323de47..c045c870810 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -3,7 +3,7 @@ use rustc::hir::*; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::Span; use unicode_normalization::UnicodeNormalization; -use utils::{snippet, span_help_and_lint, is_allowed}; +use utils::{is_allowed, snippet, span_help_and_lint}; /// **What it does:** Checks for the Unicode zero-width space in the code. /// diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 036e6f0f0e6..1c9bf70429d 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -48,13 +48,11 @@ impl EarlyLintPass for UnsafeNameRemoval { &item.span, ); }, - ViewPath_::ViewPathList(_, ref path_list_items) => { - for path_list_item in path_list_items.iter() { - let plid = path_list_item.node; - if let Some(rename) = plid.rename { - unsafe_to_safe_check(plid.name, rename, cx, &item.span); - }; - } + ViewPath_::ViewPathList(_, ref path_list_items) => for path_list_item in path_list_items.iter() { + let plid = path_list_item.node; + if let Some(rename) = plid.rename { + unsafe_to_safe_check(plid.name, rename, cx, &item.span); + }; }, ViewPath_::ViewPathGlob(_) => {}, } diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 1ac775ce7c1..1af63c56107 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir; -use utils::{span_lint, match_qpath, match_trait_method, is_try, paths}; +use utils::{is_try, match_qpath, match_trait_method, paths, span_lint}; /// **What it does:** Checks for unused written/read amount. /// @@ -40,8 +40,7 @@ impl LintPass for UnusedIoAmount { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { let expr = match s.node { - hir::StmtSemi(ref expr, _) | - hir::StmtExpr(ref expr, _) => &**expr, + hir::StmtSemi(ref expr, _) | hir::StmtExpr(ref expr, _) => &**expr, _ => return, }; @@ -58,13 +57,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { } }, - hir::ExprMethodCall(ref path, _, ref args) => { - match &*path.name.as_str() { - "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { - check_method_call(cx, &args[0], expr); - }, - _ => (), - } + hir::ExprMethodCall(ref path, _, ref args) => match &*path.name.as_str() { + "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { + check_method_call(cx, &args[0], expr); + }, + _ => (), }, _ => (), diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index 8a8afe8a377..6f91b873a48 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, NestedVisitorMap}; +use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use std::collections::HashMap; use syntax::ast; use syntax::codemap::Span; @@ -69,14 +69,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { - hir::ExprBreak(destination, _) | - hir::ExprAgain(destination) => { - if let Some(label) = destination.ident { - self.labels.remove(&label.node.name.as_str()); - } + hir::ExprBreak(destination, _) | hir::ExprAgain(destination) => if let Some(label) = destination.ident { + self.labels.remove(&label.node.name.as_str()); }, - hir::ExprLoop(_, Some(label), _) | - hir::ExprWhile(_, _, Some(label)) => { + hir::ExprLoop(_, Some(label), _) | hir::ExprWhile(_, _, Some(label)) => { self.labels.insert(label.node.as_str(), expr.span); }, _ => (), diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 9f75ed2717b..bb5f6075d0d 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_path, NestedVisitorMap}; -use utils::{span_lint_and_then, in_macro}; +use rustc::hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; +use utils::{in_macro, span_lint_and_then}; use syntax::ast::NodeId; use syntax_pos::symbol::keywords::SelfType; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index dfac7366553..fafb6d12d1f 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -5,9 +5,9 @@ use rustc::lint::*; use rustc::hir; -use rustc::hir::{Expr, QPath, Expr_}; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use syntax::ast::{self, Attribute, NodeId, LitKind, DUMMY_NODE_ID}; +use rustc::hir::{Expr, Expr_, QPath}; +use rustc::hir::intravisit::{NestedVisitorMap, Visitor}; +use syntax::ast::{self, Attribute, LitKind, NodeId, DUMMY_NODE_ID}; use syntax::codemap::Span; use std::collections::HashMap; @@ -386,15 +386,13 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!("Again(ref {}) = {},", destination_pat, current); // FIXME: implement label printing }, - Expr_::ExprRet(ref opt_value) => { - if let Some(ref value) = *opt_value { - let value_pat = self.next("value"); - println!("Ret(Some(ref {})) = {},", value_pat, current); - self.current = value_pat; - self.visit_expr(value); - } else { - println!("Ret(None) = {},", current); - } + Expr_::ExprRet(ref opt_value) => if let Some(ref value) = *opt_value { + let value_pat = self.next("value"); + println!("Ret(Some(ref {})) = {},", value_pat, current); + self.current = value_pat; + self.visit_expr(value); + } else { + println!("Ret(None) = {},", current); }, Expr_::ExprInlineAsm(_, ref _input, ref _output) => { println!("InlineAsm(_, ref input, ref output) = {},", current); @@ -445,42 +443,36 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { fn has_attr(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { - attr.check_name("clippy") && - attr.meta_item_list().map_or(false, |list| { - list.len() == 1 && - match list[0].node { - ast::NestedMetaItemKind::MetaItem(ref it) => it.name == "author", - ast::NestedMetaItemKind::Literal(_) => false, - } - }) + attr.check_name("clippy") && attr.meta_item_list().map_or(false, |list| { + list.len() == 1 && match list[0].node { + ast::NestedMetaItemKind::MetaItem(ref it) => it.name == "author", + ast::NestedMetaItemKind::Literal(_) => false, + } + }) }) } fn print_path(path: &QPath, first: &mut bool) { match *path { - QPath::Resolved(_, ref path) => { - for segment in &path.segments { + QPath::Resolved(_, ref path) => for segment in &path.segments { + if *first { + *first = false; + } else { + print!(", "); + } + print!("{:?}", segment.name.as_str()); + }, + QPath::TypeRelative(ref ty, ref segment) => match ty.node { + hir::Ty_::TyPath(ref inner_path) => { + print_path(inner_path, first); if *first { *first = false; } else { print!(", "); } print!("{:?}", segment.name.as_str()); - } - }, - QPath::TypeRelative(ref ty, ref segment) => { - match ty.node { - hir::Ty_::TyPath(ref inner_path) => { - print_path(inner_path, first); - if *first { - *first = false; - } else { - print!(", "); - } - print!("{:?}", segment.name.as_str()); - }, - ref other => print!("/* unimplemented: {:?}*/", other), - } + }, + ref other => print!("/* unimplemented: {:?}*/", other), }, } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index ad9e7e20176..7251538c09a 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -15,14 +15,13 @@ pub fn file_from_args( 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::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)) - } + ast::MetaItemKind::Word | 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)) }, }; } @@ -45,7 +44,7 @@ pub enum Error { /// The expected type. &'static str, /// The type we got instead. - &'static str + &'static str, ), /// There is an unknown key is the file. UnknownKey(String), @@ -191,10 +190,8 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> { Ok(ref md) if md.is_file() => return Ok(Some(config_file)), // Return the error if it's something other than `NotFound`; otherwise we didn't // find the project file yet, and continue searching. - Err(e) => { - if e.kind() != io::ErrorKind::NotFound { - return Err(e); - } + Err(e) => if e.kind() != io::ErrorKind::NotFound { + return Err(e); }, _ => (), } diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index d9a454aaf7e..09e40aea80d 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -6,7 +6,7 @@ use rustc::hir; use rustc::lint::LateContext; use syntax::ast; -use utils::{is_expn_of, match_qpath, match_def_path, resolve_node, paths}; +use utils::{is_expn_of, match_def_path, match_qpath, paths, resolve_node}; /// Convert a hir binary operator to the corresponding `ast` type. pub fn binop(op: hir::BinOp_) -> ast::BinOpKind { @@ -73,42 +73,40 @@ pub fn range(expr: &hir::Expr) -> Option<Range> { None } }, - hir::ExprStruct(ref path, ref fields, None) => { - if match_qpath(path, &paths::RANGE_FROM_STD) || match_qpath(path, &paths::RANGE_FROM) { - Some(Range { - start: get_field("start", fields), - end: None, - limits: ast::RangeLimits::HalfOpen, - }) - } else if match_qpath(path, &paths::RANGE_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_INCLUSIVE) { - Some(Range { - start: get_field("start", fields), - end: get_field("end", fields), - limits: ast::RangeLimits::Closed, - }) - } else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) { - Some(Range { - start: get_field("start", fields), - end: get_field("end", fields), - limits: ast::RangeLimits::HalfOpen, - }) - } else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || - match_qpath(path, &paths::RANGE_TO_INCLUSIVE) - { - Some(Range { - start: None, - end: get_field("end", fields), - limits: ast::RangeLimits::Closed, - }) - } else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) { - Some(Range { - start: None, - end: get_field("end", fields), - limits: ast::RangeLimits::HalfOpen, - }) - } else { - None - } + hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD) || + match_qpath(path, &paths::RANGE_FROM) + { + Some(Range { + start: get_field("start", fields), + end: None, + limits: ast::RangeLimits::HalfOpen, + }) + } else if match_qpath(path, &paths::RANGE_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_INCLUSIVE) { + Some(Range { + start: get_field("start", fields), + end: get_field("end", fields), + limits: ast::RangeLimits::Closed, + }) + } else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) { + Some(Range { + start: get_field("start", fields), + end: get_field("end", fields), + limits: ast::RangeLimits::HalfOpen, + }) + } else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_TO_INCLUSIVE) { + Some(Range { + start: None, + end: get_field("end", fields), + limits: ast::RangeLimits::Closed, + }) + } else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) { + Some(Range { + start: None, + end: get_field("end", fields), + limits: ast::RangeLimits::HalfOpen, + }) + } else { + None }, _ => None, } diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 0b3f409adf4..2d3d5874d82 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -46,8 +46,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { false } }, - (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | - (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), + (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => { + self.eq_expr(l, r) + }, _ => false, } } @@ -107,11 +108,10 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { 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)) - }) + 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_path, _, ref l_args), &ExprMethodCall(ref r_path, _, ref r_args)) => { !self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args) @@ -257,9 +257,8 @@ fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool, { - l.as_ref().map_or_else(|| r.is_none(), |x| { - r.as_ref().map_or(false, |y| eq_fn(x, y)) - }) + l.as_ref() + .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) } /// Check if two slices are equal as per `eq_fn`. diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 315f4987071..cdc8ce509b4 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -54,12 +54,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { match item.vis { hir::Visibility::Public => println!("public"), hir::Visibility::Crate => println!("visible crate wide"), - hir::Visibility::Restricted { ref path, .. } => { - println!( - "visible in module `{}`", - print::to_string(print::NO_ANN, |s| s.print_path(path, false)) - ) - }, + hir::Visibility::Restricted { ref path, .. } => println!( + "visible in module `{}`", + print::to_string(print::NO_ANN, |s| s.print_path(path, false)) + ), hir::Visibility::Inherited => println!("visibility inherited from outer item"), } if item.defaultness.is_default() { @@ -125,8 +123,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } 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<'a, 'tcx>, item: &'tcx @@ -355,12 +352,10 @@ fn print_item(cx: &LateContext, item: &hir::Item) { match item.vis { hir::Visibility::Public => println!("public"), hir::Visibility::Crate => println!("visible crate wide"), - hir::Visibility::Restricted { ref path, .. } => { - println!( - "visible in module `{}`", - print::to_string(print::NO_ANN, |s| s.print_path(path, false)) - ) - }, + hir::Visibility::Restricted { ref path, .. } => println!( + "visible in module `{}`", + print::to_string(print::NO_ANN, |s| s.print_path(path, false)) + ), hir::Visibility::Inherited => println!("visibility inherited from outer item"), } match item.node { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index a2832ef7af2..a35b034d791 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,11 +1,11 @@ use rustc::lint::*; use rustc::hir::*; -use rustc::hir::intravisit::{Visitor, walk_expr, NestedVisitorMap}; -use utils::{paths, match_qpath, span_lint}; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use utils::{match_qpath, paths, span_lint}; use syntax::symbol::InternedString; -use syntax::ast::{Name, NodeId, ItemKind, Crate as AstCrate}; +use syntax::ast::{Crate as AstCrate, ItemKind, Name, NodeId}; use syntax::codemap::Span; -use std::collections::{HashSet, HashMap}; +use std::collections::{HashMap, HashSet}; /// **What it does:** Checks for various things we like to keep tidy in clippy. @@ -63,14 +63,17 @@ impl LintPass for Clippy { impl EarlyLintPass for Clippy { fn check_crate(&mut self, cx: &EarlyContext, krate: &AstCrate) { - if let Some(utils) = krate.module.items.iter().find( - |item| item.ident.name == "utils", - ) + if let Some(utils) = krate + .module + .items + .iter() + .find(|item| item.ident.name == "utils") { if let ItemKind::Mod(ref utils_mod) = utils.node { - if let Some(paths) = utils_mod.items.iter().find( - |item| item.ident.name == "paths", - ) + if let Some(paths) = utils_mod + .items + .iter() + .find(|item| item.ident.name == "paths") { if let ItemKind::Mod(ref paths_mod) = paths.node { let mut last_name: Option<InternedString> = None; @@ -83,7 +86,7 @@ impl EarlyLintPass for Clippy { CLIPPY_LINTS_INTERNAL, item.span, "this constant should be before the previous constant due to lexical \ - ordering", + ordering", ); } } @@ -157,11 +160,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { fn is_lint_ref_type(ty: &Ty) -> bool { - if let TyRptr(ref lt, - MutTy { - ty: ref inner, - mutbl: MutImmutable, - }) = ty.node + if let TyRptr( + ref lt, + MutTy { + ty: ref inner, + mutbl: MutImmutable, + }, + ) = ty.node { if lt.is_elided() { return false; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 8828a32512b..29fddeaa052 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -5,10 +5,10 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::hir::def::Def; use rustc::hir::intravisit::{NestedVisitorMap, Visitor}; use rustc::hir::map::Node; -use rustc::lint::{LintContext, Level, LateContext, Lint}; +use rustc::lint::{LateContext, Level, Lint, LintContext}; use rustc::session::Session; use rustc::traits; -use rustc::ty::{self, TyCtxt, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::transform::MirSource; use rustc_errors; use std::borrow::Cow; @@ -104,18 +104,16 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { pub fn in_constant(cx: &LateContext, id: NodeId) -> bool { let parent_id = cx.tcx.hir.get_parent(id); match MirSource::from_node(cx.tcx, parent_id) { - MirSource::GeneratorDrop(_) | - MirSource::Fn(_) => false, - MirSource::Const(_) | - MirSource::Static(..) | - MirSource::Promoted(..) => true, + MirSource::GeneratorDrop(_) | MirSource::Fn(_) => false, + MirSource::Const(_) | MirSource::Static(..) | MirSource::Promoted(..) => true, } } /// Returns true if this `expn_info` was expanded by any macro. pub fn in_macro(span: Span) -> bool { span.ctxt().outer().expn_info().map_or(false, |info| { - match info.callee.format {// don't treat range expressions desugared to structs as "in_macro" + match info.callee.format { + // don't treat range expressions desugared to structs as "in_macro" ExpnFormat::CompilerDesugaring(kind) => kind != CompilerDesugaringKind::DotFill, _ => true, } @@ -138,18 +136,18 @@ pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { // no span for the callee = external macro info.callee.span.map_or(true, |span| { // no snippet = external macro or compiler-builtin expansion - cx.sess().codemap().span_to_snippet(span).ok().map_or( - true, - |code| { - !code.starts_with("macro_rules") - }, - ) + cx.sess() + .codemap() + .span_to_snippet(span) + .ok() + .map_or(true, |code| !code.starts_with("macro_rules")) }) } - span.ctxt().outer().expn_info().map_or(false, |info| { - in_macro_ext(cx, &info) - }) + span.ctxt() + .outer() + .expn_info() + .map_or(false, |info| in_macro_ext(cx, &info)) } /// Check if a `DefId`'s path matches the given absolute type path usage. @@ -183,9 +181,10 @@ pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool { tcx.push_item_path(&mut apb, def_id); apb.names.len() == path.len() && - apb.names.into_iter().zip(path.iter()).all( - |(a, &b)| *a == *b, - ) + apb.names + .into_iter() + .zip(path.iter()) + .all(|(a, &b)| *a == *b) } /// Check if type is struct, enum or union type with given def path. @@ -220,11 +219,9 @@ 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::Resolved(_, ref path) => path.segments + .last() + .expect("A path must have at least one segment"), QPath::TypeRelative(_, ref seg) => seg, } } @@ -246,22 +243,22 @@ pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> { pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool { match *path { QPath::Resolved(_, ref path) => match_path(path, segments), - QPath::TypeRelative(ref ty, ref segment) => { - match ty.node { - TyPath(ref inner_path) => { - !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) && - segment.name == segments[segments.len() - 1] - }, - _ => false, - } + QPath::TypeRelative(ref ty, ref segment) => match ty.node { + TyPath(ref inner_path) => { + !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) && + segment.name == segments[segments.len() - 1] + }, + _ => false, }, } } pub fn match_path(path: &Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a, b)| a.name == *b, - ) + 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. @@ -271,9 +268,11 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { /// match_qpath(path, &["std", "rt", "begin_unwind"]) /// ``` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { - path.segments.iter().rev().zip(segments.iter().rev()).all( - |(a, b)| a.identifier.name == *b, - ) + path.segments + .iter() + .rev() + .zip(segments.iter().rev()) + .all(|(a, b)| a.identifier.name == *b) } /// Get the definition associated to a path. @@ -281,9 +280,9 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { let cstore = &cx.tcx.sess.cstore; let crates = cstore.crates(); - let krate = crates.iter().find( - |&&krate| cstore.crate_name(krate) == path[0], - ); + let krate = crates + .iter() + .find(|&&krate| cstore.crate_name(krate) == path[0]); if let Some(krate) = krate { let krate = DefId { krate: *krate, @@ -336,14 +335,9 @@ pub fn implements_trait<'a, 'tcx>( ty_params: &[Ty<'tcx>], ) -> bool { let ty = cx.tcx.erase_regions(&ty); - let obligation = cx.tcx.predicate_for_trait_def( - cx.param_env, - traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params, - ); + let obligation = + cx.tcx + .predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params); cx.tcx.infer_ctxt().enter(|infcx| { traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) }) @@ -522,30 +516,27 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if node_id == parent_id { return None; } - map.find(parent_id).and_then( - |node| if let Node::NodeExpr(parent) = - node - { + map.find(parent_id) + .and_then(|node| if let Node::NodeExpr(parent) = node { Some(parent) } else { None - }, - ) + }) } pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { let map = &cx.tcx.hir; - let enclosing_node = map.get_enclosing_scope(node).and_then(|enclosing_id| { - map.find(enclosing_id) - }); + let enclosing_node = map.get_enclosing_scope(node) + .and_then(|enclosing_id| map.find(enclosing_id)); if let Some(node) = enclosing_node { match node { Node::NodeBlock(block) => Some(block), - Node::NodeItem(&Item { node: ItemFn(_, _, _, _, _, eid), .. }) => { - match cx.tcx.hir.body(eid).value.node { - ExprBlock(ref block) => Some(block), - _ => None, - } + Node::NodeItem(&Item { + node: ItemFn(_, _, _, _, _, eid), + .. + }) => match cx.tcx.hir.body(eid).value.node { + ExprBlock(ref block) => Some(block), + _ => None, }, _ => None, } @@ -704,9 +695,9 @@ impl LimitStack { Self { stack: vec![limit] } } pub fn limit(&self) -> u64 { - *self.stack.last().expect( - "there should always be a value in the stack", - ) + *self.stack + .last() + .expect("there should always be a value in the stack") } pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { let stack = &mut self.stack; @@ -741,9 +732,10 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' /// See also `is_direct_expn_of`. pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { loop { - let span_name_span = span.ctxt().outer().expn_info().map(|ei| { - (ei.callee.name(), ei.call_site) - }); + let span_name_span = span.ctxt() + .outer() + .expn_info() + .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), @@ -763,9 +755,10 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { /// `bar!` by /// `is_direct_expn_of`. pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { - let span_name_span = span.ctxt().outer().expn_info().map(|ei| { - (ei.callee.name(), ei.call_site) - }); + let span_name_span = span.ctxt() + .outer() + .expn_info() + .map(|ei| (ei.callee.name(), ei.call_site)); match span_name_span { Some((mac_name, new_span)) if mac_name == name => Some(new_span), @@ -800,7 +793,11 @@ 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`. @@ -844,9 +841,9 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Ty<'t // <'b> Foo<'b>` but // not for type parameters. pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - cx.tcx.infer_ctxt().enter(|infcx| { - infcx.can_eq(cx.param_env, a, b).is_ok() - }) + cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok()) } /// Return whether the given type is an `unsafe` function. @@ -875,36 +872,28 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool { } 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::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.hir_id), PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), - PatKind::Struct(ref qpath, ref fields, _) => { - if is_enum_variant(cx, qpath, pat.hir_id) { - true - } else { - are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) - } - }, - PatKind::TupleStruct(ref qpath, ref pats, _) => { - if is_enum_variant(cx, qpath, pat.hir_id) { - true - } else { - are_refutable(cx, pats.iter().map(|pat| &**pat)) - } + PatKind::Struct(ref qpath, ref fields, _) => if is_enum_variant(cx, qpath, pat.hir_id) { + true + } else { + are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) }, - PatKind::Slice(ref head, ref middle, ref tail) => { - are_refutable( - cx, - head.iter().chain(middle).chain(tail.iter()).map( - |pat| &**pat, - ), - ) + PatKind::TupleStruct(ref qpath, ref pats, _) => if is_enum_variant(cx, qpath, pat.hir_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), + ), } } @@ -1029,9 +1018,9 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> { } pub fn type_size<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<u64> { - ty.layout(cx.tcx, cx.param_env).ok().map(|layout| { - layout.size(cx.tcx).bytes() - }) + ty.layout(cx.tcx, cx.param_env) + .ok() + .map(|layout| layout.size(cx.tcx).bytes()) } /// Returns true if the lint is allowed in the current context diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 4dc2314accb..ec0a351b8b0 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -33,9 +33,7 @@ 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), } } } @@ -178,12 +176,10 @@ 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()), } @@ -273,8 +269,8 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { 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))) || + ((op != other && associativity(op) != dir) || + (op == other && associativity(op) != Associativity::Both))) || is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op) } @@ -293,12 +289,24 @@ 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, token_to_string(&token::BinOp(op)), rhs), @@ -343,7 +351,16 @@ 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 | + Divide | + Equal | + Greater | + GreaterEqual | + Less | + LessEqual | + Modulus | + NotEqual | + ShiftLeft | + ShiftRight | Subtract => Associativity::Left, DotDot | DotDotDot => Associativity::None, } @@ -393,9 +410,8 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { /// before it on its line. fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> { let lo = cx.sess().codemap().lookup_char_pos(span.lo()); - if let Some(line) = lo.file.get_line( - lo.line - 1, /* line numbers in `Loc` are 1-based */ - ) + if let Some(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') { // we can mix char and byte positions here because we only consider `[ \t]` diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 95f3c913dac..71f53a3e051 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -72,14 +72,12 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) { return; } }, - higher::VecArgs::Vec(args) => { - if let Some(last) = args.iter().last() { - let span = args[0].span.to(last.span); + higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() { + let span = args[0].span.to(last.span); - format!("&[{}]", snippet(cx, span, "..")).into() - } else { - "&[]".into() - } + format!("&[{}]", snippet(cx, span, "..")).into() + } else { + "&[]".into() }, }; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 888cd339096..5ff9fb9ffd5 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,4 +1,4 @@ -use consts::{Constant, constant_simple, FloatWidth}; +use consts::{constant_simple, Constant, FloatWidth}; use rustc::lint::*; use rustc::hir::*; use utils::span_help_and_lint; diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index 4b0c5ea5afd..fda167b69c7 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -1,13 +1,12 @@ #![feature(plugin_registrar, rustc_private)] -extern crate syntax; -extern crate rustc; extern crate rustc_plugin; +extern crate syntax; use syntax::codemap::Span; use syntax::tokenstream::TokenTree; -use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; -use syntax::ext::build::AstBuilder; // trait for expr_usize +use syntax::ext::base::{ExtCtxt, MacEager, MacResult}; +use syntax::ext::build::AstBuilder; // trait for expr_usize use rustc_plugin::Registry; fn expand_macro(cx: &mut ExtCtxt, sp: Span, _: &[TokenTree]) -> Box<MacResult + 'static> { diff --git a/src/main.rs b/src/main.rs index 054ceae94e3..89de07115c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,13 +45,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType, ) -> Compilation { - self.default.early_callback( - matches, - sopts, - cfg, - descriptions, - output, - ) + self.default + .early_callback(matches, sopts, cfg, descriptions, output) } fn no_input( &mut self, @@ -62,14 +57,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry, ) -> Option<(Input, Option<PathBuf>)> { - self.default.no_input( - matches, - sopts, - cfg, - odir, - ofile, - descriptions, - ) + self.default + .no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback( &mut self, @@ -79,13 +68,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { odir: &Option<PathBuf>, ofile: &Option<PathBuf>, ) -> Compilation { - self.default.late_callback( - matches, - sess, - input, - odir, - ofile, - ) + self.default + .late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); @@ -101,7 +85,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { .as_ref() .expect( "at this compilation stage \ - the krate must be parsed", + the krate must be parsed", ) .span, ); @@ -203,13 +187,13 @@ pub fn main() { .skip(2) .find(|val| val.starts_with("--manifest-path=")); - let mut metadata = - if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { - metadata - } else { - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); - process::exit(101); - }; + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) + { + metadata + } else { + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); + process::exit(101); + }; let manifest_path = manifest_path_arg.map(|arg| { Path::new(&arg["--manifest-path=".len()..]) @@ -359,7 +343,6 @@ fn process<I>(old_args: I) -> Result<(), i32> where I: Iterator<Item = String>, { - let mut args = vec!["rustc".to_owned()]; let mut found_dashes = false; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index a5d55978d09..8fa0d440ee7 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -29,6 +29,8 @@ fn compile_test() { prepare_env(); run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); - #[cfg(target_os = "windows")] run_mode("ui-windows", "ui"); - #[cfg(not(target_os = "windows"))] run_mode("ui-posix", "ui"); + #[cfg(target_os = "windows")] + run_mode("ui-windows", "ui"); + #[cfg(not(target_os = "windows"))] + run_mode("ui-posix", "ui"); } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 378d14972aa..aa2c4d03bd5 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -5,7 +5,7 @@ extern crate compiletest_rs as compiletest; extern crate test; -use std::env::{var, set_var}; +use std::env::{set_var, var}; use std::path::PathBuf; use test::TestPaths; diff --git a/tests/issue-825.rs b/tests/issue-825.rs index 685715a111c..50de10b936c 100644 --- a/tests/issue-825.rs +++ b/tests/issue-825.rs @@ -1,14 +1,12 @@ #![feature(plugin)] #![plugin(clippy)] - #![allow(warnings)] // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { - 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/matches.rs b/tests/matches.rs index 2f9a61ed768..42d1154bf1a 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -21,13 +21,11 @@ fn test_overlapping() { assert_eq!(None, overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])); assert_eq!( None, - overlapping( - &[ - sp(1, Bound::Included(4)), - sp(5, Bound::Included(6)), - sp(10, Bound::Included(11)), - ], - ) + overlapping(&[ + sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(10, Bound::Included(11)) + ],) ); assert_eq!( Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))), @@ -35,12 +33,10 @@ fn test_overlapping() { ); assert_eq!( Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))), - overlapping( - &[ - sp(1, Bound::Included(4)), - sp(5, Bound::Included(6)), - sp(6, Bound::Included(11)), - ], - ) + overlapping(&[ + sp(1, Bound::Included(4)), + sp(5, Bound::Included(6)), + sp(6, Bound::Included(11)) + ],) ); } diff --git a/tests/needless_continue_helpers.rs b/tests/needless_continue_helpers.rs index a669b6f9477..853f64b4698 100644 --- a/tests/needless_continue_helpers.rs +++ b/tests/needless_continue_helpers.rs @@ -1,7 +1,8 @@ // Tests for the various helper functions used by the needless_continue // lint that don't belong in utils. + extern crate clippy_lints; -use clippy_lints::needless_continue::{erode_from_back, erode_block, erode_from_front}; +use clippy_lints::needless_continue::{erode_block, erode_from_back, erode_from_front}; #[test] #[cfg_attr(rustfmt, rustfmt_skip)] -- cgit 1.4.1-3-g733a5 From 86e178e7864ff89624f011421f42fc3252f3ce94 Mon Sep 17 00:00:00 2001 From: topecongiro <seuchida@gmail.com> Date: Thu, 14 Sep 2017 13:18:08 +0900 Subject: Add a missing argument --- src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 89de07115c5..f4945998fde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,12 +64,13 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { &mut self, matches: &getopts::Matches, sess: &Session, + crate_stores: &rustc::middle::cstore::CrateStore, input: &Input, odir: &Option<PathBuf>, ofile: &Option<PathBuf>, ) -> Compilation { self.default - .late_callback(matches, sess, input, odir, ofile) + .late_callback(matches, sess, crate_stores, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); -- cgit 1.4.1-3-g733a5 From 4da0aeb40e2459a86bda60a1883b21690943d130 Mon Sep 17 00:00:00 2001 From: Aaron Hill <aa1ronham@gmail.com> Date: Wed, 27 Sep 2017 14:17:08 -0400 Subject: Set RUSTC_WRAPPER instead of RUSTC when invoking Cargo Some build scripts rely on the RUSTC binary being the actual compiler (e.g. parsing the output of 'RUSTC --version'). To prevent clippy from breaking these build scripts, this commit sets RUSTC_WRAPPER instead. This will cause Cargo to leave RUSTC unchanged, making the use of clippy transparent to build scripts. --- src/main.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index f4945998fde..f21cd7bd28c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,7 +181,7 @@ pub fn main() { return; } - if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + if "clippy" == std::env::args().nth(1).as_ref().expect("cargo-clippy should be called with at least one argument!") { // this arm is executed on the initial call to `cargo clippy` let manifest_path_arg = std::env::args() @@ -285,7 +285,7 @@ pub fn main() { } } } else { - // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` + // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC_WRAPPER` // env var set to itself let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -310,13 +310,17 @@ pub fn main() { }; rustc_driver::in_rustc_thread(|| { + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programatically, so we ignore this/ + let orig_args: Vec<String> = env::args().skip(1).collect(); + // this conditional check for the --sysroot flag is there so users can call // `cargo-clippy` directly // without having to pass --sysroot or anything - let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") { - env::args().collect() + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() } else { - env::args() + orig_args.clone().into_iter() .chain(Some("--sysroot".to_owned())) .chain(Some(sys_root)) .collect() @@ -325,7 +329,7 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::args().any(|s| s == "--emit=metadata"); + let clippy_enabled = orig_args.iter().any(|s| s == "--emit=metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); @@ -361,7 +365,7 @@ where let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = std::process::Command::new("cargo") .args(&args) - .env("RUSTC", path) + .env("RUSTC_WRAPPER", path) .spawn() .expect("could not run cargo") .wait() -- cgit 1.4.1-3-g733a5 From 50ffaca4c9686af96ab86a8ec201f5b31dd62a32 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 18 Sep 2017 12:47:33 +0200 Subject: Reduce the hackiness of cargo-clippy --- .travis.yml | 1 + Cargo.toml | 6 + build.rs | 8 + src/driver.rs | 198 ++++++++++++ src/main.rs | 353 ++++++---------------- tests/compile-test.rs | 15 +- tests/conf_whitelisted.rs | 3 + tests/run-pass/associated-constant-ice.rs | 4 +- tests/run-pass/conf_whitelisted.rs | 4 - tests/run-pass/enum-glob-import-crate.rs | 4 +- tests/run-pass/ice-1588.rs | 4 +- tests/run-pass/ice-1969.rs | 4 +- tests/run-pass/ice-700.rs | 4 +- tests/run-pass/mut_mut_macro.rs | 4 +- tests/run-pass/needless_lifetimes_impl_trait.rs | 4 +- tests/run-pass/procedural_macro.rs | 2 +- tests/run-pass/regressions.rs | 4 +- tests/run-pass/single-match-else.rs | 4 +- tests/ui-posix/conf_non_existant.rs | 6 - tests/ui-posix/conf_non_existant.stderr | 4 - tests/ui-posix/update-all-references.sh | 28 -- tests/ui-posix/update-references.sh | 50 --- tests/ui-windows/conf_non_existant.rs | 6 - tests/ui-windows/conf_non_existant.stderr | 4 - tests/ui-windows/update-all-references.sh | 28 -- tests/ui-windows/update-references.sh | 50 --- tests/ui/absurd-extreme-comparisons.rs | 4 +- tests/ui/absurd-extreme-comparisons.stderr | 2 - tests/ui/approx_const.rs | 4 +- tests/ui/approx_const.stderr | 2 - tests/ui/arithmetic.rs | 4 +- tests/ui/arithmetic.stderr | 2 - tests/ui/array_indexing.rs | 2 +- tests/ui/array_indexing.stderr | 2 - tests/ui/assign_ops.rs | 4 +- tests/ui/assign_ops.stderr | 2 - tests/ui/assign_ops2.rs | 4 +- tests/ui/assign_ops2.stderr | 2 - tests/ui/attrs.rs | 4 +- tests/ui/attrs.stderr | 2 - tests/ui/bit_masks.rs | 4 +- tests/ui/bit_masks.stderr | 2 - tests/ui/blacklisted_name.rs | 4 +- tests/ui/blacklisted_name.stderr | 2 - tests/ui/block_in_if_condition.rs | 4 +- tests/ui/block_in_if_condition.stderr | 2 - tests/ui/bool_comparison.rs | 4 +- tests/ui/bool_comparison.stderr | 2 - tests/ui/booleans.rs | 4 +- tests/ui/booleans.stderr | 2 - tests/ui/borrow_box.rs | 4 +- tests/ui/borrow_box.stderr | 2 - tests/ui/box_vec.rs | 4 +- tests/ui/box_vec.stderr | 2 - tests/ui/builtin-type-shadow.rs | 4 +- tests/ui/builtin-type-shadow.stderr | 2 - tests/ui/bytecount.rs | 4 +- tests/ui/bytecount.stderr | 2 - tests/ui/cast.rs | 4 +- tests/ui/cast.stderr | 2 - tests/ui/char_lit_as_u8.rs | 4 +- tests/ui/char_lit_as_u8.stderr | 2 - tests/ui/cmp_nan.rs | 4 +- tests/ui/cmp_nan.stderr | 2 - tests/ui/cmp_null.rs | 4 +- tests/ui/cmp_null.stderr | 2 - tests/ui/cmp_owned.rs | 4 +- tests/ui/cmp_owned.stderr | 2 - tests/ui/collapsible_if.rs | 4 +- tests/ui/collapsible_if.stderr | 2 - tests/ui/complex_types.rs | 4 +- tests/ui/complex_types.stderr | 2 - tests/ui/conf_bad_arg.rs | 2 +- tests/ui/conf_bad_arg.stderr | 14 +- tests/ui/conf_bad_toml.rs | 2 +- tests/ui/conf_bad_toml.stderr | 10 +- tests/ui/conf_bad_type.rs | 2 +- tests/ui/conf_bad_type.stderr | 10 +- tests/ui/conf_french_blacklisted_name.rs | 2 +- tests/ui/conf_french_blacklisted_name.stderr | 48 +-- tests/ui/conf_path_non_string.rs | 2 +- tests/ui/conf_path_non_string.stderr | 14 +- tests/ui/conf_unknown_key.rs | 2 +- tests/ui/conf_unknown_key.stderr | 10 +- tests/ui/copies.rs | 3 +- tests/ui/copies.stderr | 18 +- tests/ui/cyclomatic_complexity.rs | 2 +- tests/ui/cyclomatic_complexity.stderr | 2 - tests/ui/cyclomatic_complexity_attr_used.rs | 2 +- tests/ui/cyclomatic_complexity_attr_used.stderr | 2 - tests/ui/deprecated.rs | 4 +- tests/ui/deprecated.stderr | 2 - tests/ui/derive.rs | 4 +- tests/ui/derive.stderr | 2 - tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/diverging_sub_expression.stderr | 2 - tests/ui/dlist.rs | 2 +- tests/ui/dlist.stderr | 2 - tests/ui/doc.rs | 4 +- tests/ui/doc.stderr | 2 - tests/ui/double_neg.rs | 4 +- tests/ui/double_neg.stderr | 2 - tests/ui/double_parens.rs | 4 +- tests/ui/double_parens.stderr | 2 - tests/ui/drop_forget_copy.rs | 4 +- tests/ui/drop_forget_copy.stderr | 2 - tests/ui/drop_forget_ref.rs | 4 +- tests/ui/drop_forget_ref.stderr | 2 - tests/ui/duplicate_underscore_argument.rs | 4 +- tests/ui/duplicate_underscore_argument.stderr | 2 - tests/ui/empty_enum.rs | 4 +- tests/ui/empty_enum.stderr | 2 - tests/ui/entry.rs | 4 +- tests/ui/entry.stderr | 2 - tests/ui/enum_glob_use.rs | 4 +- tests/ui/enum_glob_use.stderr | 2 - tests/ui/enum_variants.rs | 2 +- tests/ui/enum_variants.stderr | 2 - tests/ui/enums_clike.rs | 4 +- tests/ui/enums_clike.stderr | 2 - tests/ui/eq_op.rs | 4 +- tests/ui/eq_op.stderr | 2 - tests/ui/escape_analysis.rs | 2 +- tests/ui/eta.rs | 4 +- tests/ui/eta.stderr | 2 - tests/ui/eval_order_dependence.rs | 4 +- tests/ui/eval_order_dependence.stderr | 2 - tests/ui/filter_methods.rs | 4 +- tests/ui/filter_methods.stderr | 2 - tests/ui/float_cmp.rs | 4 +- tests/ui/float_cmp.stderr | 2 - tests/ui/for_loop.rs | 2 +- tests/ui/for_loop.stderr | 2 - tests/ui/format.rs | 4 +- tests/ui/format.stderr | 2 - tests/ui/formatting.rs | 4 +- tests/ui/formatting.stderr | 2 - tests/ui/functions.rs | 4 +- tests/ui/functions.stderr | 2 - tests/ui/ices.rs | 5 - tests/ui/ices.stderr | 8 - tests/ui/identity_op.rs | 4 +- tests/ui/identity_op.stderr | 2 - tests/ui/if_let_redundant_pattern_matching.rs | 4 +- tests/ui/if_let_redundant_pattern_matching.stderr | 2 - tests/ui/if_not_else.rs | 4 +- tests/ui/if_not_else.stderr | 2 - tests/ui/inconsistent_digit_grouping.rs | 4 +- tests/ui/inconsistent_digit_grouping.stderr | 2 - tests/ui/infinite_iter.rs | 4 +- tests/ui/infinite_iter.stderr | 2 - tests/ui/int_plus_one.stderr | 4 +- tests/ui/invalid_ref.stderr | 4 +- tests/ui/invalid_upcast_comparisons.rs | 4 +- tests/ui/invalid_upcast_comparisons.stderr | 2 - tests/ui/is_unit_expr.rs | 4 +- tests/ui/is_unit_expr.stderr | 2 - tests/ui/item_after_statement.rs | 4 +- tests/ui/item_after_statement.stderr | 2 - tests/ui/large_digit_groups.rs | 4 +- tests/ui/large_digit_groups.stderr | 2 - tests/ui/large_enum_variant.rs | 4 +- tests/ui/large_enum_variant.stderr | 2 - tests/ui/len_zero.rs | 4 +- tests/ui/len_zero.stderr | 2 - tests/ui/let_if_seq.rs | 4 +- tests/ui/let_if_seq.stderr | 2 - tests/ui/let_return.rs | 4 +- tests/ui/let_return.stderr | 2 - tests/ui/let_unit.rs | 4 +- tests/ui/let_unit.stderr | 2 - tests/ui/lifetimes.rs | 4 +- tests/ui/lifetimes.stderr | 2 - tests/ui/lint_pass.rs | 4 +- tests/ui/lint_pass.stderr | 2 - tests/ui/literals.rs | 4 +- tests/ui/literals.stderr | 2 - tests/ui/map_clone.rs | 4 +- tests/ui/map_clone.stderr | 2 - tests/ui/matches.rs | 4 +- tests/ui/matches.stderr | 2 - tests/ui/mem_forget.rs | 4 +- tests/ui/mem_forget.stderr | 2 - tests/ui/methods.rs | 4 +- tests/ui/methods.stderr | 2 - tests/ui/min_max.rs | 4 +- tests/ui/min_max.stderr | 2 - tests/ui/missing-doc.rs | 4 +- tests/ui/missing-doc.stderr | 2 - tests/ui/module_inception.rs | 4 +- tests/ui/module_inception.stderr | 2 - tests/ui/modulo_one.rs | 4 +- tests/ui/modulo_one.stderr | 2 - tests/ui/mut_from_ref.rs | 4 +- tests/ui/mut_from_ref.stderr | 2 - tests/ui/mut_mut.rs | 4 +- tests/ui/mut_mut.stderr | 2 - tests/ui/mut_range_bound.stderr | 4 +- tests/ui/mut_reference.rs | 4 +- tests/ui/mut_reference.stderr | 2 - tests/ui/mutex_atomic.rs | 4 +- tests/ui/mutex_atomic.stderr | 2 - tests/ui/needless_bool.rs | 4 +- tests/ui/needless_bool.stderr | 2 - tests/ui/needless_borrow.rs | 4 +- tests/ui/needless_borrow.stderr | 2 - tests/ui/needless_borrowed_ref.rs | 4 +- tests/ui/needless_borrowed_ref.stderr | 2 - tests/ui/needless_continue.rs | 4 +- tests/ui/needless_continue.stderr | 2 - tests/ui/needless_pass_by_value.rs | 4 +- tests/ui/needless_pass_by_value.stderr | 2 - tests/ui/needless_pass_by_value_proc_macro.rs | 4 +- tests/ui/needless_return.rs | 4 +- tests/ui/needless_return.stderr | 2 - tests/ui/needless_update.rs | 4 +- tests/ui/needless_update.stderr | 2 - tests/ui/neg_multiply.rs | 4 +- tests/ui/neg_multiply.stderr | 2 - tests/ui/never_loop.rs | 4 +- tests/ui/never_loop.stderr | 2 - tests/ui/new_without_default.rs | 2 +- tests/ui/new_without_default.stderr | 2 - tests/ui/no_effect.rs | 2 +- tests/ui/no_effect.stderr | 2 - tests/ui/non_expressive_names.rs | 4 +- tests/ui/non_expressive_names.stderr | 2 - tests/ui/ok_if_let.rs | 4 +- tests/ui/ok_if_let.stderr | 2 - tests/ui/op_ref.rs | 6 +- tests/ui/op_ref.stderr | 2 - tests/ui/open_options.rs | 4 +- tests/ui/open_options.stderr | 2 - tests/ui/overflow_check_conditional.rs | 4 +- tests/ui/overflow_check_conditional.stderr | 2 - tests/ui/panic.rs | 4 +- tests/ui/panic.stderr | 2 - tests/ui/partialeq_ne_impl.rs | 4 +- tests/ui/partialeq_ne_impl.stderr | 2 - tests/ui/patterns.rs | 4 +- tests/ui/patterns.stderr | 2 - tests/ui/precedence.rs | 4 +- tests/ui/precedence.stderr | 2 - tests/ui/print.rs | 4 +- tests/ui/print.stderr | 2 - tests/ui/print_with_newline.rs | 4 +- tests/ui/print_with_newline.stderr | 2 - tests/ui/ptr_arg.rs | 4 +- tests/ui/ptr_arg.stderr | 2 - tests/ui/range.rs | 4 +- tests/ui/range.stderr | 2 - tests/ui/redundant_closure_call.rs | 4 +- tests/ui/redundant_closure_call.stderr | 2 - tests/ui/reference.rs | 4 +- tests/ui/reference.stderr | 2 - tests/ui/regex.rs | 4 +- tests/ui/regex.stderr | 2 - tests/ui/serde.rs | 4 +- tests/ui/serde.stderr | 2 - tests/ui/shadow.rs | 4 +- tests/ui/shadow.stderr | 2 - tests/ui/short_circuit_statement.rs | 4 +- tests/ui/short_circuit_statement.stderr | 2 - tests/ui/should_assert_eq.rs | 4 +- tests/ui/should_assert_eq.stderr | 2 - tests/ui/strings.rs | 4 +- tests/ui/strings.stderr | 2 - tests/ui/stutter.rs | 4 +- tests/ui/stutter.stderr | 2 - tests/ui/swap.rs | 4 +- tests/ui/swap.stderr | 2 - tests/ui/temporary_assignment.rs | 4 +- tests/ui/temporary_assignment.stderr | 2 - tests/ui/toplevel_ref_arg.rs | 4 +- tests/ui/toplevel_ref_arg.stderr | 2 - tests/ui/trailing_zeros.rs | 2 +- tests/ui/trailing_zeros.stderr | 2 - tests/ui/transmute.rs | 4 +- tests/ui/transmute.stderr | 2 - tests/ui/transmute_32bit.rs | 4 +- tests/ui/transmute_64bit.rs | 4 +- tests/ui/transmute_64bit.stderr | 2 - tests/ui/unicode.rs | 4 +- tests/ui/unicode.stderr | 2 - tests/ui/unit_cmp.rs | 4 +- tests/ui/unit_cmp.stderr | 2 - tests/ui/unneeded_field_pattern.rs | 4 +- tests/ui/unneeded_field_pattern.stderr | 2 - tests/ui/unreadable_literal.rs | 4 +- tests/ui/unreadable_literal.stderr | 2 - tests/ui/unsafe_removed_from_name.rs | 4 +- tests/ui/unsafe_removed_from_name.stderr | 2 - tests/ui/unused_io_amount.rs | 4 +- tests/ui/unused_io_amount.stderr | 2 - tests/ui/unused_labels.rs | 4 +- tests/ui/unused_labels.stderr | 2 - tests/ui/unused_lt.rs | 4 +- tests/ui/unused_lt.stderr | 2 - tests/ui/use_self.rs | 4 +- tests/ui/use_self.stderr | 2 - tests/ui/used_underscore_binding.rs | 4 +- tests/ui/used_underscore_binding.stderr | 2 - tests/ui/useless_attribute.rs | 4 +- tests/ui/useless_attribute.stderr | 2 - tests/ui/vec.rs | 4 +- tests/ui/vec.stderr | 2 - tests/ui/while_loop.rs | 4 +- tests/ui/while_loop.stderr | 2 - tests/ui/wrong_self_convention.rs | 4 +- tests/ui/wrong_self_convention.stderr | 2 - tests/ui/zero_div_zero.rs | 4 +- tests/ui/zero_div_zero.stderr | 2 - tests/ui/zero_ptr.rs | 4 +- tests/ui/zero_ptr.stderr | 2 - 314 files changed, 652 insertions(+), 1104 deletions(-) create mode 100644 build.rs create mode 100644 src/driver.rs create mode 100644 tests/conf_whitelisted.rs delete mode 100644 tests/run-pass/conf_whitelisted.rs delete mode 100644 tests/ui-posix/conf_non_existant.rs delete mode 100644 tests/ui-posix/conf_non_existant.stderr delete mode 100755 tests/ui-posix/update-all-references.sh delete mode 100755 tests/ui-posix/update-references.sh delete mode 100644 tests/ui-windows/conf_non_existant.rs delete mode 100644 tests/ui-windows/conf_non_existant.stderr delete mode 100755 tests/ui-windows/update-all-references.sh delete mode 100755 tests/ui-windows/update-references.sh delete mode 100644 tests/ui/ices.rs delete mode 100644 tests/ui/ices.stderr (limited to 'src') diff --git a/.travis.yml b/.travis.yml index 2664a01ea47..8fe1be2ddfa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ script: - cargo test --features debugging - mkdir -p ~/rust/cargo/bin - cp target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy + - cp target/debug/clippy-driver ~/rust/cargo/bin/clippy-driver - PATH=$PATH:~/rust/cargo/bin cargo clippy --all -- -D clippy - cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd .. - cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. diff --git a/Cargo.toml b/Cargo.toml index f9c3fd0fd67..3d3b8abaa76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ readme = "README.md" license = "MPL-2.0" keywords = ["clippy", "lint", "plugin"] categories = ["development-tools", "development-tools::cargo-plugins"] +build = "build.rs" [badges] travis-ci = { repository = "rust-lang-nursery/rust-clippy" } @@ -29,6 +30,11 @@ name = "cargo-clippy" test = false path = "src/main.rs" +[[bin]] +name = "clippy-driver" +test = false +path = "src/driver.rs" + [dependencies] # begin automatic update clippy_lints = { version = "0.0.165", path = "clippy_lints" } diff --git a/build.rs b/build.rs new file mode 100644 index 00000000000..1c930c1b2c9 --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +use std::env; + +fn main() { + // Forward the profile to the main compilation + println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); + // Don't rebuild even if nothing changed + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/driver.rs b/src/driver.rs new file mode 100644 index 00000000000..ab5e90141a9 --- /dev/null +++ b/src/driver.rs @@ -0,0 +1,198 @@ +// error-pattern:yummy +#![feature(box_syntax)] +#![feature(rustc_private)] +#![allow(unknown_lints, missing_docs_in_private_items)] + +extern crate clippy_lints; +extern crate getopts; +extern crate rustc; +extern crate rustc_driver; +extern crate rustc_errors; +extern crate rustc_plugin; +extern crate syntax; + +use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; +use rustc::session::{config, CompileIncomplete, Session}; +use rustc::session::config::{ErrorOutputType, Input}; +use std::path::PathBuf; +use std::process::Command; +use syntax::ast; + +struct ClippyCompilerCalls { + default: RustcDefaultCalls, + run_lints: bool, +} + +impl ClippyCompilerCalls { + fn new(run_lints: bool) -> Self { + Self { + default: RustcDefaultCalls, + run_lints: run_lints, + } + } +} + +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 { + 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<PathBuf>, + ofile: &Option<PathBuf>, + descriptions: &rustc_errors::registry::Registry, + ) -> Option<(Input, Option<PathBuf>)> { + self.default + .no_input(matches, sopts, cfg, odir, ofile, descriptions) + } + fn late_callback( + &mut self, + matches: &getopts::Matches, + sess: &Session, + crate_stores: &rustc::middle::cstore::CrateStore, + input: &Input, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, + ) -> Compilation { + self.default + .late_callback(matches, sess, crate_stores, input, odir, ofile) + } + fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { + let mut control = self.default.build_controller(sess, matches); + + if self.run_lints { + 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, + ); + registry.args_hidden = Some(Vec::new()); + clippy_lints::register_plugins(&mut registry); + + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + } + old(state); + }); + } + + control + } +} + +#[allow(print_stdout)] +fn show_version() { + println!("{}", env!("CARGO_PKG_VERSION")); +} + +pub fn main() { + use std::env; + + if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + panic!("yummy"); + } + + if std::env::args().any(|a| a == "--version" || a == "-V") { + show_version(); + return; + } + + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect( + "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", + ) + }; + + rustc_driver::in_rustc_thread(|| { + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programatically, so we ignore this/ + let mut orig_args: Vec<String> = env::args().collect(); + if orig_args[1] == "rustc" { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args.clone().into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") || + orig_args.iter().any(|s| s == "--emit=metadata"); + + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } + + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if let Err(CompileIncomplete::Errored(_)) = result { + std::process::exit(1); + } + }).expect("rustc_thread failed"); +} diff --git a/src/main.rs b/src/main.rs index f21cd7bd28c..69f416e2092 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,128 +3,12 @@ #![feature(rustc_private)] #![allow(unknown_lints, missing_docs_in_private_items)] -extern crate clippy_lints; -extern crate getopts; -extern crate rustc; -extern crate rustc_driver; -extern crate rustc_errors; -extern crate rustc_plugin; -extern crate syntax; - -use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc::session::{config, CompileIncomplete, Session}; -use rustc::session::config::{ErrorOutputType, Input}; use std::collections::HashMap; -use std::path::PathBuf; -use std::process::{self, Command}; -use syntax::ast; +use std::process; use std::io::{self, Write}; extern crate cargo_metadata; -struct ClippyCompilerCalls { - default: RustcDefaultCalls, - run_lints: bool, -} - -impl ClippyCompilerCalls { - fn new(run_lints: bool) -> Self { - Self { - default: RustcDefaultCalls, - run_lints: run_lints, - } - } -} - -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 { - 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<PathBuf>, - ofile: &Option<PathBuf>, - descriptions: &rustc_errors::registry::Registry, - ) -> Option<(Input, Option<PathBuf>)> { - self.default - .no_input(matches, sopts, cfg, odir, ofile, descriptions) - } - fn late_callback( - &mut self, - matches: &getopts::Matches, - sess: &Session, - crate_stores: &rustc::middle::cstore::CrateStore, - input: &Input, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>, - ) -> Compilation { - self.default - .late_callback(matches, sess, crate_stores, input, odir, ofile) - } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); - - if self.run_lints { - 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, - ); - registry.args_hidden = Some(Vec::new()); - clippy_lints::register_plugins(&mut registry); - - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - } - old(state); - }); - } - - control - } -} - use std::path::Path; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -181,166 +65,105 @@ pub fn main() { return; } - if "clippy" == std::env::args().nth(1).as_ref().expect("cargo-clippy should be called with at least one argument!") { - // this arm is executed on the initial call to `cargo clippy` - - let manifest_path_arg = std::env::args() - .skip(2) - .find(|val| val.starts_with("--manifest-path=")); - - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) - { - metadata - } else { - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); - process::exit(101); - }; + let manifest_path_arg = std::env::args() + .skip(2) + .find(|val| val.starts_with("--manifest-path=")); - let manifest_path = manifest_path_arg.map(|arg| { - Path::new(&arg["--manifest-path=".len()..]) - .canonicalize() - .expect("manifest path could not be canonicalized") - }); - - let packages = if std::env::args().any(|a| a == "--all") { - metadata.packages - } else { - let package_index = { - if let Some(manifest_path) = manifest_path { - metadata.packages.iter().position(|package| { + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) + { + metadata + } else { + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); + process::exit(101); + }; + + let manifest_path = manifest_path_arg.map(|arg| { + Path::new(&arg["--manifest-path=".len()..]) + .canonicalize() + .expect("manifest path could not be canonicalized") + }); + + let packages = if std::env::args().any(|a| a == "--all") { + metadata.packages + } else { + let package_index = { + if let Some(manifest_path) = manifest_path { + metadata.packages.iter().position(|package| { + let package_manifest_path = Path::new(&package.manifest_path) + .canonicalize() + .expect("package manifest path could not be canonicalized"); + package_manifest_path == manifest_path + }) + } else { + let package_manifest_paths: HashMap<_, _> = metadata + .packages + .iter() + .enumerate() + .map(|(i, package)| { let package_manifest_path = Path::new(&package.manifest_path) + .parent() + .expect("could not find parent directory of package manifest") .canonicalize() - .expect("package manifest path could not be canonicalized"); - package_manifest_path == manifest_path + .expect("package directory cannot be canonicalized"); + (package_manifest_path, i) }) - } else { - let package_manifest_paths: HashMap<_, _> = metadata - .packages - .iter() - .enumerate() - .map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path) - .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - (package_manifest_path, i) - }) - .collect(); - - let current_dir = std::env::current_dir() - .expect("could not read current directory") - .canonicalize() - .expect("current directory cannot be canonicalized"); - - let mut current_path: &Path = ¤t_dir; - - // This gets the most-recent parent (the one that takes the fewest `cd ..`s to - // reach). - loop { - if let Some(&package_index) = package_manifest_paths.get(current_path) { - break Some(package_index); - } else { - // We'll never reach the filesystem root, because to get to this point in the - // code - // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to - // unwrap the current path's parent. - current_path = current_path - .parent() - .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); - } + .collect(); + + let current_dir = std::env::current_dir() + .expect("could not read current directory") + .canonicalize() + .expect("current directory cannot be canonicalized"); + + let mut current_path: &Path = ¤t_dir; + + // This gets the most-recent parent (the one that takes the fewest `cd ..`s to + // reach). + loop { + if let Some(&package_index) = package_manifest_paths.get(current_path) { + break Some(package_index); + } else { + // We'll never reach the filesystem root, because to get to this point in the + // code + // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to + // unwrap the current path's parent. + current_path = current_path + .parent() + .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); } } - }.expect("could not find matching package"); + } + }.expect("could not find matching package"); - vec![metadata.packages.remove(package_index)] - }; + vec![metadata.packages.remove(package_index)] + }; - for package in packages { - let manifest_path = package.manifest_path; + for package in packages { + let manifest_path = package.manifest_path; - for target in package.targets { - let args = std::env::args() - .skip(2) - .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); + for target in package.targets { + let args = std::env::args() + .skip(2) + .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); - let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); - if let Some(first) = target.kind.get(0) { - if target.kind.len() > 1 || first.ends_with("lib") { - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { - 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), - ) { - std::process::exit(code); - } + let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); + if let Some(first) = target.kind.get(0) { + if target.kind.len() > 1 || first.ends_with("lib") { + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { + 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), + ) { + std::process::exit(code); } - } else { - panic!("badly formatted cargo metadata: target::kind is an empty array"); } - } - } - } else { - // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC_WRAPPER` - // env var set to itself - - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect( - "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", - ) - }; - - rustc_driver::in_rustc_thread(|| { - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programatically, so we ignore this/ - let orig_args: Vec<String> = env::args().skip(1).collect(); - - // this conditional check for the --sysroot flag is there so users can call - // `cargo-clippy` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() } else { - orig_args.clone().into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - - // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built - let clippy_enabled = orig_args.iter().any(|s| s == "--emit=metadata"); - - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + panic!("badly formatted cargo metadata: target::kind is an empty array"); } - - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(CompileIncomplete::Errored(_)) = result { - std::process::exit(1); - } - }).expect("rustc_thread failed"); + } } } @@ -362,7 +185,9 @@ where args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); - let path = std::env::current_exe().expect("current executable path invalid"); + let path = std::env::current_exe() + .expect("current executable path invalid") + .with_file_name("clippy-driver"); let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 8fa0d440ee7..be8793215dc 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -3,6 +3,14 @@ extern crate compiletest_rs as compiletest; use std::path::PathBuf; use std::env::{set_var, var}; +fn clippy_driver_path() -> PathBuf { + if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { + PathBuf::from(path) + } else { + PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver")) + } +} + fn run_mode(dir: &'static str, mode: &'static str) { let mut config = compiletest::Config::default(); @@ -16,12 +24,15 @@ fn run_mode(dir: &'static str, mode: &'static str) { config.mode = cfg_mode; config.build_base = PathBuf::from("target/debug/test_build_base"); config.src_base = PathBuf::from(format!("tests/{}", dir)); + config.rustc_path = clippy_driver_path(); compiletest::run_tests(&config); } fn prepare_env() { set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + set_var("CLIPPY_TESTS", "true"); + set_var("RUST_BACKTRACE", "0"); } #[test] @@ -29,8 +40,4 @@ fn compile_test() { prepare_env(); run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); - #[cfg(target_os = "windows")] - run_mode("ui-windows", "ui"); - #[cfg(not(target_os = "windows"))] - run_mode("ui-posix", "ui"); } diff --git a/tests/conf_whitelisted.rs b/tests/conf_whitelisted.rs new file mode 100644 index 00000000000..198bf465bd5 --- /dev/null +++ b/tests/conf_whitelisted.rs @@ -0,0 +1,3 @@ +#![feature(plugin)] +#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))] + diff --git a/tests/run-pass/associated-constant-ice.rs b/tests/run-pass/associated-constant-ice.rs index 8fb55fa2272..744de9bcf38 100644 --- a/tests/run-pass/associated-constant-ice.rs +++ b/tests/run-pass/associated-constant-ice.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + pub trait Trait { const CONSTANT: u8; diff --git a/tests/run-pass/conf_whitelisted.rs b/tests/run-pass/conf_whitelisted.rs deleted file mode 100644 index 1c82a010b3d..00000000000 --- a/tests/run-pass/conf_whitelisted.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))] - -fn main() {} diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs index e08a00d26e2..21ed2dbf991 100644 --- a/tests/run-pass/enum-glob-import-crate.rs +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(clippy)] #![allow(unused_imports)] diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs index d53d3a1cc75..780df523511 100644 --- a/tests/run-pass/ice-1588.rs +++ b/tests/run-pass/ice-1588.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(clippy)] fn main() { diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs index 23a002a5cde..29633982848 100644 --- a/tests/run-pass/ice-1969.rs +++ b/tests/run-pass/ice-1969.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(clippy)] fn main() { } diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs index a7ff78eac14..a1e3a6756e9 100644 --- a/tests/run-pass/ice-700.rs +++ b/tests/run-pass/ice-700.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(clippy)] fn core() {} diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs index a6473b0f909..adc308626b1 100644 --- a/tests/run-pass/mut_mut_macro.rs +++ b/tests/run-pass/mut_mut_macro.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(mut_mut, zero_ptr, cmp_nan)] #![allow(dead_code)] diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs index 8edb444f936..0ebc1bf3c6c 100644 --- a/tests/run-pass/needless_lifetimes_impl_trait.rs +++ b/tests/run-pass/needless_lifetimes_impl_trait.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![feature(conservative_impl_trait)] #![deny(needless_lifetimes)] #![allow(dead_code)] diff --git a/tests/run-pass/procedural_macro.rs b/tests/run-pass/procedural_macro.rs index 91269726172..b185f6dc427 100644 --- a/tests/run-pass/procedural_macro.rs +++ b/tests/run-pass/procedural_macro.rs @@ -1,5 +1,5 @@ #![feature(plugin)] -#![plugin(clippy, clippy_mini_macro_test)] +#![plugin(clippy_mini_macro_test)] #[deny(warnings)] fn main() { diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs index 442b01d35f8..d5e343c56c2 100644 --- a/tests/run-pass/regressions.rs +++ b/tests/run-pass/regressions.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(blacklisted_name)] pub fn foo(bar: *const u8) { diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs index fe3cf1ce71f..b8fa7294dcd 100644 --- a/tests/run-pass/single-match-else.rs +++ b/tests/run-pass/single-match-else.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(single_match_else)] fn main() { diff --git a/tests/ui-posix/conf_non_existant.rs b/tests/ui-posix/conf_non_existant.rs deleted file mode 100644 index e287f7e02af..00000000000 --- a/tests/ui-posix/conf_non_existant.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file - -#![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))] - -fn main() {} diff --git a/tests/ui-posix/conf_non_existant.stderr b/tests/ui-posix/conf_non_existant.stderr deleted file mode 100644 index 7920bd35589..00000000000 --- a/tests/ui-posix/conf_non_existant.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: error reading Clippy's configuration file: No such file or directory (os error 2) - -error: aborting due to previous error - diff --git a/tests/ui-posix/update-all-references.sh b/tests/ui-posix/update-all-references.sh deleted file mode 100755 index d6aa69c7e8d..00000000000 --- a/tests/ui-posix/update-all-references.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname $0) -cd $MY_DIR -find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR diff --git a/tests/ui-posix/update-references.sh b/tests/ui-posix/update-references.sh deleted file mode 100755 index aa99d35f7aa..00000000000 --- a/tests/ui-posix/update-references.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 <build-directory> <relative-path-to-rs-files>" - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname $0) - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then - echo updating $MYDIR/$STDOUT_NAME - cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME - fi - if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then - echo updating $MYDIR/$STDERR_NAME - cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME - fi -done - - diff --git a/tests/ui-windows/conf_non_existant.rs b/tests/ui-windows/conf_non_existant.rs deleted file mode 100644 index e287f7e02af..00000000000 --- a/tests/ui-windows/conf_non_existant.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file - -#![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))] - -fn main() {} diff --git a/tests/ui-windows/conf_non_existant.stderr b/tests/ui-windows/conf_non_existant.stderr deleted file mode 100644 index f21ae524f5e..00000000000 --- a/tests/ui-windows/conf_non_existant.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: error reading Clippy's configuration file: The system cannot find the file specified. (os error 2) - -error: aborting due to previous error - diff --git a/tests/ui-windows/update-all-references.sh b/tests/ui-windows/update-all-references.sh deleted file mode 100755 index d6aa69c7e8d..00000000000 --- a/tests/ui-windows/update-all-references.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname $0) -cd $MY_DIR -find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR diff --git a/tests/ui-windows/update-references.sh b/tests/ui-windows/update-references.sh deleted file mode 100755 index aa99d35f7aa..00000000000 --- a/tests/ui-windows/update-references.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 <build-directory> <relative-path-to-rs-files>" - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname $0) - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then - echo updating $MYDIR/$STDOUT_NAME - cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME - fi - if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then - echo updating $MYDIR/$STDERR_NAME - cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME - fi -done - - diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index ad381c6cd49..1f88d94bd2b 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(absurd_extreme_comparisons)] #![allow(unused, eq_op, no_effect, unnecessary_operation, needless_pass_by_value)] diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr index 2b1e9ad66fe..a4b8839797c 100644 --- a/tests/ui/absurd-extreme-comparisons.stderr +++ b/tests/ui/absurd-extreme-comparisons.stderr @@ -143,5 +143,3 @@ error: <-comparison of unit values detected. This will always be false | = note: `-D unit-cmp` implied by `-D warnings` -error: aborting due to 18 previous errors - diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index eb66a633f9e..f2239ecb467 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(approx_constant)] #[allow(unused, shadow_unrelated, similar_names)] diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr index dda28433d7a..f102dc5b5dc 100644 --- a/tests/ui/approx_const.stderr +++ b/tests/ui/approx_const.stderr @@ -114,5 +114,3 @@ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it 55 | let my_sq2 = 1.4142; | ^^^^^^ -error: aborting due to 19 previous errors - diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index b281c239f36..7ed71b59707 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(integer_arithmetic, float_arithmetic)] #![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)] diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr index ad4a02e2190..ea32a005219 100644 --- a/tests/ui/arithmetic.stderr +++ b/tests/ui/arithmetic.stderr @@ -69,5 +69,3 @@ error: floating-point arithmetic detected 29 | -f; | ^^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/array_indexing.rs b/tests/ui/array_indexing.rs index c38342daf68..faafa9a7a0d 100644 --- a/tests/ui/array_indexing.rs +++ b/tests/ui/array_indexing.rs @@ -1,5 +1,5 @@ #![feature(inclusive_range_syntax, plugin)] -#![plugin(clippy)] + #![warn(indexing_slicing)] #![warn(out_of_bounds_indexing)] diff --git a/tests/ui/array_indexing.stderr b/tests/ui/array_indexing.stderr index d730b012932..dd11247243c 100644 --- a/tests/ui/array_indexing.stderr +++ b/tests/ui/array_indexing.stderr @@ -116,5 +116,3 @@ error: range is out of bounds 44 | &empty[..4]; | ^^^^^^^^^^ -error: aborting due to 19 previous errors - diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index f92f2252114..2b49f2146ba 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(assign_ops)] #[allow(unused_assignments)] diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 2123507e2ef..c1cc5d24426 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -134,5 +134,3 @@ error: manual implementation of an assign operation 40 | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` -error: aborting due to 22 previous errors - diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index b5de5b712ff..8d6ef827f52 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_assignments)] #[warn(misrefactored_assign_op)] diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 0ff211259c0..47528c315d4 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -48,5 +48,3 @@ error: variable appears on both sides of an assignment operation 15 | a &= a & 1; | ^^^^^^^^^^ help: replace it with: `a &= 1` -error: aborting due to 8 previous errors - diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 1ff5edcd630..eb27b833ade 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(inline_always, deprecated_semver)] diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index f743399a606..9e4ac3d1283 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -20,5 +20,3 @@ error: the since field must contain a semver-compliant version 30 | #[deprecated(since = "1")] | ^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/bit_masks.rs b/tests/ui/bit_masks.rs index c211b85d7e2..4843b4eba0d 100644 --- a/tests/ui/bit_masks.rs +++ b/tests/ui/bit_masks.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index 40aa585d124..9f2c2d0a2c4 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -92,5 +92,3 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared 55 | x | 1 >= 8; | ^^^^^^^^^^ -error: aborting due to 15 previous errors - diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index dabce55883b..7baeb7bb75c 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code, similar_names, single_match, toplevel_ref_arg, unused_mut, unused_variables)] #![warn(blacklisted_name)] diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr index 68fbe27a01e..a08a5326894 100644 --- a/tests/ui/blacklisted_name.stderr +++ b/tests/ui/blacklisted_name.stderr @@ -84,5 +84,3 @@ error: use of a blacklisted/placeholder name `baz` 35 | if let Some(ref mut baz) = Some(42) {} | ^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index 08e510317d9..9e65a127af2 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(block_in_if_condition_expr)] #![warn(block_in_if_condition_stmt)] diff --git a/tests/ui/block_in_if_condition.stderr b/tests/ui/block_in_if_condition.stderr index 4b7d12598ec..86a289c19a8 100644 --- a/tests/ui/block_in_if_condition.stderr +++ b/tests/ui/block_in_if_condition.stderr @@ -50,5 +50,3 @@ error: this boolean expression can be simplified | = note: `-D nonminimal-bool` implied by `-D warnings` -error: aborting due to 5 previous errors - diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 9b32ed7304b..f05b9894fea 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(bool_comparison)] fn main() { diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index 4436980bc11..e5e062e0246 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -24,5 +24,3 @@ error: equality checks against false can be replaced by a negation 10 | if false == x { "yes" } else { "no" }; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` -error: aborting due to 4 previous errors - diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index ac60bf5e345..0434285a523 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(nonminimal_bool, logic_bug)] #[allow(unused, many_single_char_names)] diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index a76eb7a5cc0..0311e95a4f1 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -130,5 +130,3 @@ help: try 39 | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors - diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index b5543da6e35..394b810ed86 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(borrowed_box)] #![allow(blacklisted_name)] diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 2cf0ea79626..74134f4f2b1 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -28,5 +28,3 @@ error: you seem to be trying to use `&Box<T>`. Consider using just `&T` 22 | fn test4(a: &Box<bool>); | ^^^^^^^^^^ help: try: `&bool` -error: aborting due to 4 previous errors - diff --git a/tests/ui/box_vec.rs b/tests/ui/box_vec.rs index f8c5a80c59d..75b3b62643e 100644 --- a/tests/ui/box_vec.rs +++ b/tests/ui/box_vec.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(boxed_local, needless_pass_by_value)] diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index 254d0771386..c1badd0dc9b 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -7,5 +7,3 @@ error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>` = note: `-D box-vec` implied by `-D warnings` = help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation. -error: aborting due to previous error - diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin-type-shadow.rs index a3609cfe104..4c4f5cbd3fe 100644 --- a/tests/ui/builtin-type-shadow.rs +++ b/tests/ui/builtin-type-shadow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(builtin_type_shadow)] fn foo<u32>(a: u32) -> u32 { diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr index eb4c73b65c6..058813356cd 100644 --- a/tests/ui/builtin-type-shadow.stderr +++ b/tests/ui/builtin-type-shadow.stderr @@ -17,5 +17,3 @@ error[E0308]: mismatched types = note: expected type `u32` found type `{integer}` -error: aborting due to 2 previous errors - diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 8fc27c49f34..fc94667d968 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[deny(naive_bytecount)] fn main() { diff --git a/tests/ui/bytecount.stderr b/tests/ui/bytecount.stderr index 307edecfde1..c4f6b65a21e 100644 --- a/tests/ui/bytecount.stderr +++ b/tests/ui/bytecount.stderr @@ -22,5 +22,3 @@ error: You appear to be counting bytes the naive way 22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)` -error: aborting due to 3 previous errors - diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 82427c128e4..1ad4630989d 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap, cast_lossless)] #[allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 8787083b429..5e7ed6fae99 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -460,5 +460,3 @@ error: casting to the same type is unnecessary (`bool` -> `bool`) 88 | false as bool; | ^^^^^^^^^^^^^ -error: aborting due to 75 previous errors - diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index 6f07b60fb10..c69181c7649 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(char_lit_as_u8)] #![allow(unused_variables)] diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index fcf038fe002..4e7c1866a9a 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -8,5 +8,3 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so cas = help: Consider using a byte literal instead: b'a' -error: aborting due to previous error - diff --git a/tests/ui/cmp_nan.rs b/tests/ui/cmp_nan.rs index e8639273485..71dfdd43da7 100644 --- a/tests/ui/cmp_nan.rs +++ b/tests/ui/cmp_nan.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cmp_nan)] #[allow(float_cmp, no_effect, unnecessary_operation)] diff --git a/tests/ui/cmp_nan.stderr b/tests/ui/cmp_nan.stderr index 46f3d3d57e0..9ea1a29d29d 100644 --- a/tests/ui/cmp_nan.stderr +++ b/tests/ui/cmp_nan.stderr @@ -72,5 +72,3 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead 21 | y >= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 47ecacd5558..0f463bcfc30 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(cmp_null)] #![allow(unused_mut)] diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 481a4d0f942..51c0ceea4b1 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -12,5 +12,3 @@ error: Comparing with null is better expressed by the .is_null() method 16 | if m == ptr::null_mut() { | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 4b9b6434ebc..36d3140d246 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cmp_owned)] #[allow(unnecessary_operation)] diff --git a/tests/ui/cmp_owned.stderr b/tests/ui/cmp_owned.stderr index d40fb4b8add..e6996244664 100644 --- a/tests/ui/cmp_owned.stderr +++ b/tests/ui/cmp_owned.stderr @@ -36,5 +36,3 @@ error: this creates an owned instance just for comparison 30 | self.to_owned() == *other | ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating -error: aborting due to 6 previous errors - diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index d03a1ee1980..3c5c38525fe 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(collapsible_if)] fn main() { diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 940749d3f40..e726a36282b 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -252,5 +252,3 @@ help: try 112 | } | -error: aborting due to 13 previous errors - diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index 481a6a82cf5..7719a7a8632 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused, needless_pass_by_value)] #![feature(associated_type_defaults)] diff --git a/tests/ui/complex_types.stderr b/tests/ui/complex_types.stderr index 829a22c233f..8ce63652f0b 100644 --- a/tests/ui/complex_types.stderr +++ b/tests/ui/complex_types.stderr @@ -90,5 +90,3 @@ error: very complex type used. Consider factoring parts into `type` definitions 40 | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors - diff --git a/tests/ui/conf_bad_arg.rs b/tests/ui/conf_bad_arg.rs index 68b902719f6..b988fdb1385 100644 --- a/tests/ui/conf_bad_arg.rs +++ b/tests/ui/conf_bad_arg.rs @@ -1,6 +1,6 @@ // error-pattern: `conf_file` must be a named value -#![feature(plugin)] + #![plugin(clippy(conf_file))] fn main() {} diff --git a/tests/ui/conf_bad_arg.stderr b/tests/ui/conf_bad_arg.stderr index 92b3c82d458..d91729039b1 100644 --- a/tests/ui/conf_bad_arg.stderr +++ b/tests/ui/conf_bad_arg.stderr @@ -1,14 +1,8 @@ -error: `conf_file` must be a named value - --> $DIR/conf_bad_arg.rs:4:18 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_arg.rs:4:1 | 4 | #![plugin(clippy(conf_file))] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: Clippy will use default configuration - --> $DIR/conf_bad_arg.rs:4:18 - | -4 | #![plugin(clippy(conf_file))] - | ^^^^^^^^^ - -error: aborting due to previous error + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_bad_toml.rs b/tests/ui/conf_bad_toml.rs index 22cbfca759e..4de2cf6ae73 100644 --- a/tests/ui/conf_bad_toml.rs +++ b/tests/ui/conf_bad_toml.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/ui/conf_bad_toml.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_toml.stderr b/tests/ui/conf_bad_toml.stderr index 8ee392f8924..5ddf8c14f70 100644 --- a/tests/ui/conf_bad_toml.stderr +++ b/tests/ui/conf_bad_toml.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: expected an equals, found an identifier at line 1 - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_toml.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_toml.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_bad_type.rs b/tests/ui/conf_bad_type.rs index d5cca60a301..4cb21b91582 100644 --- a/tests/ui/conf_bad_type.rs +++ b/tests/ui/conf_bad_type.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/ui/conf_bad_type.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_type.stderr b/tests/ui/conf_bad_type.stderr index 5cb4d05afef..961df381c99 100644 --- a/tests/ui/conf_bad_type.stderr +++ b/tests/ui/conf_bad_type.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: invalid type: integer `42`, expected a sequence - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_type.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_type.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_french_blacklisted_name.rs b/tests/ui/conf_french_blacklisted_name.rs index 5bf1e896f5d..9f22ff659f2 100644 --- a/tests/ui/conf_french_blacklisted_name.rs +++ b/tests/ui/conf_french_blacklisted_name.rs @@ -1,4 +1,4 @@ -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] #![allow(dead_code)] diff --git a/tests/ui/conf_french_blacklisted_name.stderr b/tests/ui/conf_french_blacklisted_name.stderr index b2b0f26b140..c98adb6029f 100644 --- a/tests/ui/conf_french_blacklisted_name.stderr +++ b/tests/ui/conf_french_blacklisted_name.stderr @@ -1,46 +1,8 @@ -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_french_blacklisted_name.rs:2:1 | -9 | fn test(toto: ()) {} - | ^^^^ +2 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:12:9 - | -12 | let toto = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:13:9 - | -13 | let tata = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:14:9 - | -14 | let titi = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:20:10 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:20:21 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:20:28 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: aborting due to 7 previous errors + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_path_non_string.rs b/tests/ui/conf_path_non_string.rs index f6f40513be8..8d1f01358fc 100644 --- a/tests/ui/conf_path_non_string.rs +++ b/tests/ui/conf_path_non_string.rs @@ -1,5 +1,5 @@ #![feature(attr_literals)] -#![feature(plugin)] + #![plugin(clippy(conf_file=42))] fn main() {} diff --git a/tests/ui/conf_path_non_string.stderr b/tests/ui/conf_path_non_string.stderr index 3bf53f10cce..4b15b5d0e17 100644 --- a/tests/ui/conf_path_non_string.stderr +++ b/tests/ui/conf_path_non_string.stderr @@ -1,14 +1,8 @@ -error: `conf_file` value must be a string - --> $DIR/conf_path_non_string.rs:3:28 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_path_non_string.rs:3:1 | 3 | #![plugin(clippy(conf_file=42))] - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: Clippy will use default configuration - --> $DIR/conf_path_non_string.rs:3:28 - | -3 | #![plugin(clippy(conf_file=42))] - | ^^ - -error: aborting due to previous error + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_unknown_key.rs b/tests/ui/conf_unknown_key.rs index b5c1b240e4d..aec2c883367 100644 --- a/tests/ui/conf_unknown_key.rs +++ b/tests/ui/conf_unknown_key.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: unknown key `foobar` -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] fn main() {} diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr index 8de3cd93370..9fc7dbea563 100644 --- a/tests/ui/conf_unknown_key.stderr +++ b/tests/ui/conf_unknown_key.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `third-party` - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_unknown_key.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index 652afac6c68..4c4050c014f 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -1,5 +1,4 @@ -#![feature(plugin, dotdoteq_in_patterns, inclusive_range_syntax)] -#![plugin(clippy)] +#![feature(dotdoteq_in_patterns, inclusive_range_syntax)] #![allow(dead_code, no_effect, unnecessary_operation)] #![allow(let_and_return)] diff --git a/tests/ui/copies.stderr b/tests/ui/copies.stderr index bf9e8ed577d..4457e2b7d73 100644 --- a/tests/ui/copies.stderr +++ b/tests/ui/copies.stderr @@ -1,11 +1,11 @@ error: This else block is redundant. - --> $DIR/copies.rs:121:20 + --> $DIR/copies.rs:120:20 | -121 | } else { +120 | } else { | ____________________^ -122 | | continue; -123 | | } +121 | | continue; +122 | | } | |_____________^ | = note: `-D needless-continue` implied by `-D warnings` @@ -18,12 +18,12 @@ error: This else block is redundant. error: This else block is redundant. - --> $DIR/copies.rs:131:20 + --> $DIR/copies.rs:130:20 | -131 | } else { +130 | } else { | ____________________^ -132 | | continue; -133 | | } +131 | | continue; +132 | | } | |_____________^ | = help: Consider dropping the else clause and merging the code that follows (in the loop) with the if block, like so: @@ -33,5 +33,3 @@ error: This else block is redundant. } -error: aborting due to 2 previous errors - diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index a236d6e869f..0f5726e1ad7 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute)] -#![plugin(clippy)] + #![allow(clippy)] #![warn(cyclomatic_complexity)] #![allow(unused)] diff --git a/tests/ui/cyclomatic_complexity.stderr b/tests/ui/cyclomatic_complexity.stderr index 43676762d6c..62fd5313ccb 100644 --- a/tests/ui/cyclomatic_complexity.stderr +++ b/tests/ui/cyclomatic_complexity.stderr @@ -269,5 +269,3 @@ error: the function has a cyclomatic complexity of 8 | = help: you could split it up into multiple smaller functions -error: aborting due to 20 previous errors - diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index 48ae12bc2d8..5284d60a524 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute)] -#![plugin(clippy)] + #![warn(cyclomatic_complexity)] #![warn(unused)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.stderr b/tests/ui/cyclomatic_complexity_attr_used.stderr index e671b34393b..a9cefe93e32 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.stderr +++ b/tests/ui/cyclomatic_complexity_attr_used.stderr @@ -13,5 +13,3 @@ error: the function has a cyclomatic complexity of 3 = note: `-D cyclomatic-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions -error: aborting due to previous error - diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index e0c856e3d7c..0598e174e50 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(str_to_string)] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 7d5d594cfa1..4255959675a 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -24,5 +24,3 @@ error: lint unstable_as_mut_slice has been removed: `Vec::as_mut_slice` has been 10 | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 11cade0dc8e..6440f73f31b 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![feature(untagged_unions)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index ffeed948ba5..f336dc3a8e1 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -106,5 +106,3 @@ note: consider deriving `Clone` or removing `Copy` 87 | | } | |_^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 7ae531cc6f2..d2aea93a77d 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,5 @@ #![feature(plugin, never_type)] -#![plugin(clippy)] + #![warn(diverging_sub_expression)] #![allow(match_same_arms, logic_bug)] diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 0d7b1ca6fd6..b39d1ae07e5 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -36,5 +36,3 @@ error: sub-expression diverges 37 | _ => true || break, | ^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index 5e4e1cb2a64..217a564742c 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -1,7 +1,7 @@ #![feature(plugin, alloc)] #![feature(associated_type_defaults)] -#![plugin(clippy)] + #![warn(clippy)] #![allow(dead_code, needless_pass_by_value)] diff --git a/tests/ui/dlist.stderr b/tests/ui/dlist.stderr index de0422e17ed..95872c02994 100644 --- a/tests/ui/dlist.stderr +++ b/tests/ui/dlist.stderr @@ -47,5 +47,3 @@ error: I see you're using a LinkedList! Perhaps you meant some other data struct | = help: a VecDeque might work -error: aborting due to 6 previous errors - diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 70009d76f5d..45e25409b12 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -1,7 +1,7 @@ //! This file tests for the DOC_MARKDOWN lint -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(doc_markdown)] diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index f38678e89aa..fc036d01b86 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -180,5 +180,3 @@ error: you should put bare URLs between `<`/`>` or make a proper Markdown link 168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors - diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index d462e6f4ab6..641e334fd16 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(double_neg)] fn main() { diff --git a/tests/ui/double_neg.stderr b/tests/ui/double_neg.stderr index fd4da8820a2..8c64eb37e15 100644 --- a/tests/ui/double_neg.stderr +++ b/tests/ui/double_neg.stderr @@ -6,5 +6,3 @@ error: `--x` could be misinterpreted as pre-decrement by C programmers, is usual | = note: `-D double-neg` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 8b57619edb0..19d17732867 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(double_parens)] #![allow(dead_code)] diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr index a77b08528c4..ab3e844d7a7 100644 --- a/tests/ui/double_parens.stderr +++ b/tests/ui/double_parens.stderr @@ -30,5 +30,3 @@ error: Consider removing unnecessary double parentheses 32 | (()) | ^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index 4e48a89b659..9fef06b0ede 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(drop_copy, forget_copy)] #![allow(toplevel_ref_arg, drop_ref, forget_ref, unused_mut)] diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 3ea7bf9735a..f399c5a125f 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -72,5 +72,3 @@ note: argument has type SomeStruct 42 | forget(s4); | ^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/drop_forget_ref.rs b/tests/ui/drop_forget_ref.rs index 48811f03b6f..e8ab6a0d5d1 100644 --- a/tests/ui/drop_forget_ref.rs +++ b/tests/ui/drop_forget_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(drop_ref, forget_ref)] #![allow(toplevel_ref_arg, similar_names, needless_pass_by_value)] diff --git a/tests/ui/drop_forget_ref.stderr b/tests/ui/drop_forget_ref.stderr index 1654fdd2861..6058b89c70f 100644 --- a/tests/ui/drop_forget_ref.stderr +++ b/tests/ui/drop_forget_ref.stderr @@ -216,5 +216,3 @@ note: argument has type &SomeStruct 59 | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ -error: aborting due to 18 previous errors - diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index 893cc43f364..df00f56aa62 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(duplicate_underscore_argument)] #[allow(dead_code, unused)] diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index c926f57f154..de9e6f1e056 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -6,5 +6,3 @@ error: `darth` already exists, having another argument having almost the same na | = note: `-D duplicate-underscore-argument` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/empty_enum.rs b/tests/ui/empty_enum.rs index 98138add0de..c6e6946de86 100644 --- a/tests/ui/empty_enum.rs +++ b/tests/ui/empty_enum.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(empty_enum)] diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index ca377cee822..a0d491b6f96 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -11,5 +11,3 @@ help: consider using the uninhabited type `!` or a wrapper around it 7 | enum Empty {} | ^^^^^^^^^^^^^ -error: aborting due to previous error - diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 1ae39689d8b..ccbc7038f13 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, needless_pass_by_value)] #![warn(map_entry)] diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 09c4a882280..e60c158d7c0 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -42,5 +42,3 @@ error: usage of `contains_key` followed by `insert` on a `BTreeMap` 37 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` -error: aborting due to 7 previous errors - diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index 514ef47c566..76d0d29bb53 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(unused_imports, dead_code, missing_docs_in_private_items)] diff --git a/tests/ui/enum_glob_use.stderr b/tests/ui/enum_glob_use.stderr index 2d53618c1b1..1e0fffb9ac4 100644 --- a/tests/ui/enum_glob_use.stderr +++ b/tests/ui/enum_glob_use.stderr @@ -12,5 +12,3 @@ error: don't use glob imports for enum variants 12 | use self::Enum::*; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index a12eb3fd344..9901baf9e12 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -1,5 +1,5 @@ #![feature(plugin, non_ascii_idents)] -#![plugin(clippy)] + #![warn(clippy, pub_enum_variant_names)] enum FakeCallType { diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index e33e29ec78e..7e2716b8ea2 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -97,5 +97,3 @@ error: All variants have the same prefix: `With` = note: `-D pub-enum-variant-names` implied by `-D warnings` = help: remove the prefixes and use full paths to the variants instead of glob imports -error: aborting due to 10 previous errors - diff --git a/tests/ui/enums_clike.rs b/tests/ui/enums_clike.rs index fd2240353dd..618603683e8 100644 --- a/tests/ui/enums_clike.rs +++ b/tests/ui/enums_clike.rs @@ -1,6 +1,6 @@ // ignore-x86 -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused)] diff --git a/tests/ui/enums_clike.stderr b/tests/ui/enums_clike.stderr index d6a137c6fe4..e0555bb0239 100644 --- a/tests/ui/enums_clike.stderr +++ b/tests/ui/enums_clike.stderr @@ -48,5 +48,3 @@ error: Clike enum variant discriminant is not portable to 32-bit targets 37 | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 12d62042dca..89d85d1b3e9 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(eq_op)] #[allow(identity_op, double_parens, many_single_char_names)] diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index 46c0ac108cd..914a85719d0 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -204,5 +204,3 @@ error: taken reference of right operand | = note: `-D op-ref` implied by `-D warnings` -error: aborting due to 33 previous errors - diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index b4793198b7a..b99534d05e1 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -1,5 +1,5 @@ #![feature(plugin, box_syntax)] -#![plugin(clippy)] + #![allow(warnings, clippy)] #![warn(boxed_local)] diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 46ac0ec8c73..0ff02a0b2cc 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unknown_lints, unused, no_effect, redundant_closure_call, many_single_char_names, needless_pass_by_value)] #![warn(redundant_closure)] diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 5dca265c2a4..34a6217cd70 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -32,5 +32,3 @@ error: redundant closure found 18 | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` -error: aborting due to 5 previous errors - diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index 853c61af2f2..e7ccb190d2c 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(eval_order_dependence)] #[allow(unused_assignments, unused_variables, many_single_char_names, no_effect, dead_code, blacklisted_name)] diff --git a/tests/ui/eval_order_dependence.stderr b/tests/ui/eval_order_dependence.stderr index 2e01a167c01..e9bdc3b51d9 100644 --- a/tests/ui/eval_order_dependence.stderr +++ b/tests/ui/eval_order_dependence.stderr @@ -47,5 +47,3 @@ note: whether read occurs before this write depends on evaluation order 21 | x += { x = 20; 2 }; | ^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index 77ebe9d12dd..29230c48ea3 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(missing_docs_in_private_items)] diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index cec03a47bfd..8f1853c3952 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -36,5 +36,3 @@ error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly e 25 | | .map(|x| x.checked_mul(2)) | |__________________________________________________________^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index f3f66f3c9c5..9dd9ea9b04d 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(float_cmp)] #![allow(unused, no_effect, unnecessary_operation, cast_lossless)] diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index a764403d039..d2903f501f5 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -95,5 +95,3 @@ note: std::f32::EPSILON and std::f64::EPSILON are available. 57 | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index 95d15776a36..083e6f9a6e5 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -1,5 +1,5 @@ #![feature(plugin, inclusive_range_syntax)] -#![plugin(clippy)] + use std::collections::*; use std::rc::Rc; diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index 09c4deb492a..620c32b6ab5 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -586,5 +586,3 @@ error: it looks like you're manually copying between slices 549 | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` -error: aborting due to 59 previous errors - diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 377bcc7ca8d..e9379d0a05b 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_format)] fn main() { diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index d2c9f393831..67d97f295d8 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -18,5 +18,3 @@ error: useless use of `format!` 15 | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index 7e2691776bf..20b1c1655a7 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused_variables)] diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index 266de262ea0..d121929d0c2 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -86,5 +86,3 @@ error: possibly missing a comma here | = note: to remove this lint, add a comma or write the expr in a single line -error: aborting due to 10 previous errors - diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 13d116542ac..5688c471d86 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(dead_code)] diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index 0a97748954f..c8b4db35245 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -75,5 +75,3 @@ error: this public function dereferences a raw pointer but is not marked `unsafe 63 | unsafe { std::ptr::read(p) }; | ^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/ices.rs b/tests/ui/ices.rs deleted file mode 100644 index 9c5129654e4..00000000000 --- a/tests/ui/ices.rs +++ /dev/null @@ -1,5 +0,0 @@ - -// this used to ICE -fubar!(); - -fn main() {} diff --git a/tests/ui/ices.stderr b/tests/ui/ices.stderr deleted file mode 100644 index cadd7cd417d..00000000000 --- a/tests/ui/ices.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot find macro `fubar!` in this scope - --> $DIR/ices.rs:3:1 - | -3 | fubar!(); - | ^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index e6ebb972643..b474344977c 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + const ONE : i64 = 1; const NEG_ONE : i64 = -1; diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 94b9b727a51..30367c989ec 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -42,5 +42,3 @@ error: the operation is ineffective. Consider reducing it to `x` 29 | -1 & x; | ^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/if_let_redundant_pattern_matching.rs b/tests/ui/if_let_redundant_pattern_matching.rs index 6444bd8ef68..0963caa62e2 100644 --- a/tests/ui/if_let_redundant_pattern_matching.rs +++ b/tests/ui/if_let_redundant_pattern_matching.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(if_let_redundant_pattern_matching)] diff --git a/tests/ui/if_let_redundant_pattern_matching.stderr b/tests/ui/if_let_redundant_pattern_matching.stderr index e7bfd0275d8..b15d17e372e 100644 --- a/tests/ui/if_let_redundant_pattern_matching.stderr +++ b/tests/ui/if_let_redundant_pattern_matching.stderr @@ -24,5 +24,3 @@ error: redundant pattern matching, consider using `is_some()` 17 | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` -error: aborting due to 4 previous errors - diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 7b838560ed1..9436af70cb8 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(if_not_else)] diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index b920ef3b625..f9462f422ea 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -23,5 +23,3 @@ error: Unnecessary `!=` operation | = help: change to `==` and swap the blocks of the if/else -error: aborting due to 2 previous errors - diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index 06e8996deb7..ed6dc06edb1 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(inconsistent_digit_grouping)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/inconsistent_digit_grouping.stderr b/tests/ui/inconsistent_digit_grouping.stderr index 12d9e3cf0fd..2725d5f4ef7 100644 --- a/tests/ui/inconsistent_digit_grouping.stderr +++ b/tests/ui/inconsistent_digit_grouping.stderr @@ -39,5 +39,3 @@ error: digits grouped inconsistently by underscores | = help: consider: 1.234_567_8_f32 -error: aborting due to 5 previous errors - diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index deb5c5edd8c..08596ff2016 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] +#![feature(iterator_for_each)] + use std::iter::repeat; fn square_is_lower_64(x: &u32) -> bool { x * x < 64 } diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index f79db778488..87b7ca49322 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -96,5 +96,3 @@ error: possible infinite iteration detected 30 | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 6f69ba9d714..92b012bd104 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:10:5 | @@ -43,5 +45,3 @@ help: change `>= y + 1` to `> y` as shown 14 | y < x; | ^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index 420fed01744..18064c91a01 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: reference to zeroed memory --> $DIR/invalid_ref.rs:27:24 | @@ -47,5 +49,3 @@ error: reference to uninitialized memory | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html -error: aborting due to 6 previous errors - diff --git a/tests/ui/invalid_upcast_comparisons.rs b/tests/ui/invalid_upcast_comparisons.rs index 8d8e7bd8de1..5bf0bfdcb98 100644 --- a/tests/ui/invalid_upcast_comparisons.rs +++ b/tests/ui/invalid_upcast_comparisons.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(invalid_upcast_comparisons)] #![allow(unused, eq_op, no_effect, unnecessary_operation, cast_lossless)] diff --git a/tests/ui/invalid_upcast_comparisons.stderr b/tests/ui/invalid_upcast_comparisons.stderr index eb46802899e..3f11c373074 100644 --- a/tests/ui/invalid_upcast_comparisons.stderr +++ b/tests/ui/invalid_upcast_comparisons.stderr @@ -162,5 +162,3 @@ error: because of the numeric bounds on `u8` prior to casting, this expression i 78 | -5 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors - diff --git a/tests/ui/is_unit_expr.rs b/tests/ui/is_unit_expr.rs index 164e391ff24..24a2587dc53 100644 --- a/tests/ui/is_unit_expr.rs +++ b/tests/ui/is_unit_expr.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unit_expr)] #[allow(unused_variables)] diff --git a/tests/ui/is_unit_expr.stderr b/tests/ui/is_unit_expr.stderr index 2d9fcfff74f..5524f866488 100644 --- a/tests/ui/is_unit_expr.stderr +++ b/tests/ui/is_unit_expr.stderr @@ -51,5 +51,3 @@ note: Consider removing the trailing semicolon 42 | x; | ^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index e3e4a4c7578..710a1adca56 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(items_after_statements)] fn ok() { diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index ec1296caf83..e98e7ee129d 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -12,5 +12,3 @@ error: adding items after statements is confusing, since items exist from the st 17 | fn foo() { println!("foo"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index 65bcdc7435e..5d0fb11dbea 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(large_digit_groups)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/large_digit_groups.stderr b/tests/ui/large_digit_groups.stderr index 6fc285274a0..db49ded1d8a 100644 --- a/tests/ui/large_digit_groups.stderr +++ b/tests/ui/large_digit_groups.stderr @@ -47,5 +47,3 @@ error: digit groups should be smaller | = help: consider: 123_456.123_456_f32 -error: aborting due to 6 previous errors - diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 31a7760aa19..aaf3e2924b3 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index bb889087095..899a84edeaa 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -68,5 +68,3 @@ help: consider boxing the large fields to reduce the total size of the enum 49 | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 9c66d5a8148..aba1dd3055a 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(len_without_is_empty, len_zero)] #![allow(dead_code, unused)] diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index 6e3cf1b3ca1..d23a972dddc 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -94,5 +94,3 @@ error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_e 191 | | } | |_^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 2d3ab7da996..564a67d2c8e 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables, unused_assignments, similar_names, blacklisted_name)] #![warn(useless_let_if_seq)] diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index b912373f95c..39686a9dd07 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -46,5 +46,3 @@ error: `if _ { .. } else { .. }` is an expression | = note: you might not need `mut` at all -error: aborting due to 4 previous errors - diff --git a/tests/ui/let_return.rs b/tests/ui/let_return.rs index 6aab70dbd8a..1083603b2d6 100644 --- a/tests/ui/let_return.rs +++ b/tests/ui/let_return.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(let_and_return)] diff --git a/tests/ui/let_return.stderr b/tests/ui/let_return.stderr index 459b2eafa26..b38c9ab2e91 100644 --- a/tests/ui/let_return.stderr +++ b/tests/ui/let_return.stderr @@ -23,5 +23,3 @@ note: this expression can be directly returned 15 | let x = 5; | ^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index d07cf8ede2f..032dc85f2cd 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(let_unit_value)] #![allow(unused_variables)] diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index da579ec80f3..196afc0570c 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -12,5 +12,3 @@ error: this let-binding has unit value. Consider omitting `let _a =` 18 | let _a = (); | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index 5f3c3604d80..dce9c23da68 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_lifetimes, unused_lifetimes)] #![allow(dead_code, needless_pass_by_value)] diff --git a/tests/ui/lifetimes.stderr b/tests/ui/lifetimes.stderr index 23b353d13d2..744e1ce21ec 100644 --- a/tests/ui/lifetimes.stderr +++ b/tests/ui/lifetimes.stderr @@ -86,5 +86,3 @@ error: explicit lifetimes given in parameter types where they could be elided 120 | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/lint_pass.rs b/tests/ui/lint_pass.rs index 5ecbeb7f11a..1990e137e67 100644 --- a/tests/ui/lint_pass.rs +++ b/tests/ui/lint_pass.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] + #![feature(rustc_private)] -#![plugin(clippy)] + #![warn(lint_without_lint_pass)] diff --git a/tests/ui/lint_pass.stderr b/tests/ui/lint_pass.stderr index 2f9a6813b96..66f2d62ed24 100644 --- a/tests/ui/lint_pass.stderr +++ b/tests/ui/lint_pass.stderr @@ -6,5 +6,3 @@ error: the lint `MISSING_LINT` is not added to any `LintPass` | = note: `-D lint-without-lint-pass` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index e8105a74b5c..c11adc0b090 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(mixed_case_hex_literals)] #![warn(unseparated_literal_suffix)] #![warn(zero_prefixed_literal)] diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 17210b6b275..82c651e6290 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -87,5 +87,3 @@ help: if you mean to use an octal constant, use `0o` 30 | let fail8 = 0o123; | ^^^^^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 81e298390f5..f11d21d2dfa 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(map_clone)] #![allow(clone_on_copy, unused)] diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index c29f3791851..272b868a278 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -98,5 +98,3 @@ error: you seem to be using .map() to clone the contents of an Option, consider = help: try x.as_ref().cloned() -error: aborting due to 11 previous errors - diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index be1ca72aece..f97038ca1f0 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -1,7 +1,7 @@ -#![feature(plugin)] + #![feature(exclusive_range_pattern)] -#![plugin(clippy)] + #![warn(clippy)] #![allow(unused, if_let_redundant_pattern_matching)] #![warn(single_match_else)] diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index 2f55428cca7..1c2452c46ce 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -392,5 +392,3 @@ note: consider refactoring into `Ok(3) | Ok(_)` | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate -error: aborting due to 33 previous errors - diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index 7854a373968..991a402e207 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + use std::sync::Arc; diff --git a/tests/ui/mem_forget.stderr b/tests/ui/mem_forget.stderr index 6e7a44694e1..c79afa829fe 100644 --- a/tests/ui/mem_forget.stderr +++ b/tests/ui/mem_forget.stderr @@ -18,5 +18,3 @@ error: usage of mem::forget on Drop type 24 | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 48132cc662c..08ff4771420 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] + #![feature(const_fn)] -#![plugin(clippy)] + #![warn(clippy, clippy_pedantic)] #![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 7f3d505a3cd..c5fab711fe1 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -836,5 +836,3 @@ error: you should use the `ends_with` method 578 | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` -error: aborting due to 123 previous errors - diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 9a077eae4d9..1199206e42c 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] use std::cmp::{min, max}; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index de4c4e16fa0..e9225f93b5e 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -42,5 +42,3 @@ error: this min/max combination leads to constant result 30 | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index 596cec886f4..cbd6439d47e 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -11,8 +11,8 @@ * except according to those terms. */ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing-doc.stderr index e25edb64181..55eab4f5d69 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing-doc.stderr @@ -270,5 +270,3 @@ error: missing documentation for a function 202 | fn main() {} | ^^^^^^^^^^^^ -error: aborting due to 40 previous errors - diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index e934c64023b..77bd446c569 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(module_inception)] mod foo { diff --git a/tests/ui/module_inception.stderr b/tests/ui/module_inception.stderr index c9d3319db1b..cb6ea951a17 100644 --- a/tests/ui/module_inception.stderr +++ b/tests/ui/module_inception.stderr @@ -16,5 +16,3 @@ error: module has the same name as its containing module 14 | | } | |_____^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index cda3f190f1e..847ea1d9ab6 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(modulo_one)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index ccfca7154e0..48cfe6c38cc 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -6,5 +6,3 @@ error: any number modulo 1 will be 0 | = note: `-D modulo-one` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 55498bad759..9e757155260 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(mut_from_ref)] diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index a7cbc0b7a09..eacda70ce07 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -59,5 +59,3 @@ note: immutable borrow here 32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 766276bc417..54176cd6d55 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, no_effect, unnecessary_operation)] #![warn(mut_mut)] diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 7a7bb840ba9..31f9178aa27 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -81,5 +81,3 @@ error: generally you want to avoid `&mut &mut _` if possible 35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ -error: aborting due to 13 previous errors - diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index d7be7ae1e6f..f516ec9d95e 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: attempt to mutate range bound within loop; note that the range of the loop is unchanged --> $DIR/mut_range_bound.rs:18:21 | @@ -30,5 +32,3 @@ error: attempt to mutate range bound within loop; note that the range of the loo 40 | let n = &mut m; // warning | ^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index d746fc5e529..ac40bf2a186 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables)] diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index 73df19bf158..6708bca8b2e 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -18,5 +18,3 @@ error: The function/method `takes_an_immutable_reference` doesn't need a mutable 28 | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index b84ece497eb..96502738456 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(mutex_integer)] diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 354f9891c17..d46c713164a 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -44,5 +44,3 @@ error: Consider using an AtomicIsize instead of a Mutex here. If you just want t 16 | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/needless_bool.rs b/tests/ui/needless_bool.rs index bd44332a170..1213539c827 100644 --- a/tests/ui/needless_bool.rs +++ b/tests/ui/needless_bool.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_bool)] #[allow(if_same_then_else)] diff --git a/tests/ui/needless_bool.stderr b/tests/ui/needless_bool.stderr index 63e0632445f..a25b34bfaaf 100644 --- a/tests/ui/needless_bool.stderr +++ b/tests/ui/needless_bool.stderr @@ -66,5 +66,3 @@ error: this if-then-else expression returns a bool literal 50 | if x && y { return false } else { return true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !(x && y)` -error: aborting due to 11 previous errors - diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 23d935e7df8..78c1a125c94 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + fn x(y: &i32) -> i32 { *y diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index fde38508b32..16962bb48f1 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -38,5 +38,3 @@ error: this pattern creates a reference to a reference 50 | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^ help: change this to: `a` -error: aborting due to 6 previous errors - diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 4e9986561bc..75ffa211180 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(needless_borrowed_reference)] #[allow(unused_variables)] diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 2a8cf4348d3..c85bf9f5a7c 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -24,5 +24,3 @@ error: this pattern takes a reference on something that is being de-referenced 42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` -error: aborting due to 4 previous errors - diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 6710867077d..3574b0fb3fd 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + macro_rules! zero { ($x:expr) => ($x == 0); diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 3e0368892a4..f63f120fcc7 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -55,5 +55,3 @@ error: There is no need for an explicit `else` block for this `if` expression println!("Jabber"); ... -error: aborting due to 2 previous errors - diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index ea97e875ff7..6218bfb0920 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_pass_by_value)] #![allow(dead_code, single_match, if_let_redundant_pattern_matching, many_single_char_names)] diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 02293c9cb3c..c081574127a 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -56,5 +56,3 @@ help: consider taking a reference instead 56 | let Wrapper(_) = *y; // still not moved | -error: aborting due to 7 previous errors - diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index 0d5bc4172d8..652e11fee9d 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![crate_type = "proc-macro"] #![warn(needless_pass_by_value)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 403e5b8342e..4739ded7b7e 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_return)] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 42dc6e6594c..68c2654c863 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -48,5 +48,3 @@ error: unneeded return statement 39 | let _ = || return true; | ^^^^^^^^^^^ help: remove `return` as shown: `true` -error: aborting due to 8 previous errors - diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index 99876121ae7..35d5730dda1 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_update)] #![allow(no_effect)] diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr index 3e509870d00..978fd8e625b 100644 --- a/tests/ui/needless_update.stderr +++ b/tests/ui/needless_update.stderr @@ -6,5 +6,3 @@ error: struct update has no effect, all the fields in the struct have already be | = note: `-D needless-update` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 75dc7c381fd..367d2d5edfb 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(neg_multiply)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/neg_multiply.stderr b/tests/ui/neg_multiply.stderr index 1d52ba16eae..6ed31d384a0 100644 --- a/tests/ui/neg_multiply.stderr +++ b/tests/ui/neg_multiply.stderr @@ -12,5 +12,3 @@ error: Negation by multiplying with -1 32 | -1 * x; | ^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index ff0126704b5..4866db1a541 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(single_match, unused_assignments, unused_variables)] fn test1() { diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index dace2b7e261..1ecdb5030f9 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -68,5 +68,3 @@ error: this loop never actually loops 103 | | } | |_____^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index a10db135c5e..9fd0fea137c 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,5 +1,5 @@ #![feature(plugin, const_fn)] -#![plugin(clippy)] + #![allow(dead_code)] #![warn(new_without_default, new_without_default_derive)] diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 91e437a6eb5..0ced183b1e0 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -38,5 +38,3 @@ help: try this 69 | ... -error: aborting due to 3 previous errors - diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 5c3a1a041c2..ba7826d653e 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,5 +1,5 @@ #![feature(plugin, box_syntax, inclusive_range_syntax)] -#![plugin(clippy)] + #![warn(no_effect, unnecessary_operation)] #![allow(dead_code)] diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index b6db8e7498e..43e7fbb3609 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -266,5 +266,3 @@ error: statement can be reduced 83 | {get_number()}; | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` -error: aborting due to 44 previous errors - diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index f32dad2080f..9eb3e5a82a7 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy,similar_names)] #![allow(unused)] diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 780d7d8aec9..014d4599271 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -129,5 +129,3 @@ error: 5th binding whose name is just one char 129 | e => panic!(), | ^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index dda38fec287..fdc01bcc7bc 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(if_let_some_result)] diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr index e1371d924eb..b696672d2fd 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/ok_if_let.stderr @@ -11,5 +11,3 @@ error: Matching on `Some` with `ok()` is redundant = note: `-D if-let-some-result` implied by `-D warnings` = help: Consider matching on `Ok(y)` and removing the call to `ok` instead -error: aborting due to previous error - diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index 315e6535ef6..9eb697571b6 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables, blacklisted_name)] @@ -21,4 +21,4 @@ fn main() { if b < &a { println!("OK"); } -} \ No newline at end of file +} diff --git a/tests/ui/op_ref.stderr b/tests/ui/op_ref.stderr index 715c7378e0c..dbe53933fd5 100644 --- a/tests/ui/op_ref.stderr +++ b/tests/ui/op_ref.stderr @@ -10,5 +10,3 @@ help: use the values directly 13 | let foo = 5 - 6; | ^ -error: aborting due to previous error - diff --git a/tests/ui/open_options.rs b/tests/ui/open_options.rs index c409aa564f8..514808d41f1 100644 --- a/tests/ui/open_options.rs +++ b/tests/ui/open_options.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + use std::fs::OpenOptions; #[allow(unused_must_use)] diff --git a/tests/ui/open_options.stderr b/tests/ui/open_options.stderr index f0d41904152..2f4070c2868 100644 --- a/tests/ui/open_options.stderr +++ b/tests/ui/open_options.stderr @@ -42,5 +42,3 @@ error: the method "truncate" is called more than once 15 | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index a669f741f29..889c339c8fd 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(many_single_char_names)] #![warn(overflow_check_conditional)] diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 8a80dbedaeb..9f23e96c065 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -48,5 +48,3 @@ error: You are trying to use classic C underflow conditions that will fail in Ru 32 | if a < a - b { | ^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/panic.rs b/tests/ui/panic.rs index 03d3c3dc2d9..f621a5f636d 100644 --- a/tests/ui/panic.rs +++ b/tests/ui/panic.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(panic_params)] diff --git a/tests/ui/panic.stderr b/tests/ui/panic.stderr index 25113ed80b6..f2480dfea6e 100644 --- a/tests/ui/panic.stderr +++ b/tests/ui/panic.stderr @@ -18,5 +18,3 @@ error: you probably are missing some parameter in your format string 12 | assert!(true, "here be missing values: {}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/partialeq_ne_impl.rs b/tests/ui/partialeq_ne_impl.rs index 41772700109..36dd4df8a6e 100644 --- a/tests/ui/partialeq_ne_impl.rs +++ b/tests/ui/partialeq_ne_impl.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] diff --git a/tests/ui/partialeq_ne_impl.stderr b/tests/ui/partialeq_ne_impl.stderr index 5e536cc51d2..c332ce53c1a 100644 --- a/tests/ui/partialeq_ne_impl.stderr +++ b/tests/ui/partialeq_ne_impl.stderr @@ -6,5 +6,3 @@ error: re-implementing `PartialEq::ne` is unnecessary | = note: `-D partialeq-ne-impl` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 793b2b111d6..65e319e2f88 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(clippy)] diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index 59bce3a9a8f..9a246c483b2 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -6,5 +6,3 @@ error: the `y @ _` pattern can be written as just `y` | = note: `-D redundant-pattern` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index c6865632cf7..720637c94b5 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(precedence)] #[allow(identity_op)] diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 9f0e53ffca2..26fbd75164d 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -54,5 +54,3 @@ error: unary minus has lower precedence than method call 16 | -1f32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` -error: aborting due to 9 previous errors - diff --git a/tests/ui/print.rs b/tests/ui/print.rs index f1fb3cba8c1..91304d961a7 100644 --- a/tests/ui/print.rs +++ b/tests/ui/print.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(print_stdout, use_debug)] use std::fmt::{Debug, Display, Formatter, Result}; diff --git a/tests/ui/print.stderr b/tests/ui/print.stderr index 789e1218b78..fa547949bdb 100644 --- a/tests/ui/print.stderr +++ b/tests/ui/print.stderr @@ -50,5 +50,3 @@ error: use of `Debug`-based formatting 31 | print!("Hello {:#?}", "#orld"); | ^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index d852e375ded..5cc50dea810 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(print_with_newline)] fn main() { diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 1bacc40bfb4..2ade3ae4ef5 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -24,5 +24,3 @@ error: using `print!()` with a format string that ends in a newline, consider us 9 | print!("{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 127ae703702..14b26e16847 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, many_single_char_names)] #![warn(ptr_arg)] diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index e9ada9f8aaa..13be68d4cd4 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -79,5 +79,3 @@ help: change `y.as_str()` to 62 | let c = y; | ^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/range.rs b/tests/ui/range.rs index bb1a04cfcf3..71f2f2b219b 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,7 +1,7 @@ #![feature(iterator_step_by)] #![feature(inclusive_range_syntax)] -#![feature(plugin)] -#![plugin(clippy)] + + struct NotARange; impl NotARange { diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index fc51f1a07f0..4098d32d08e 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -38,5 +38,3 @@ error: Iterator::step_by(0) will panic at runtime 33 | let _ = v1.iter().step_by(2/3); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index 2c079273b7b..ab3897bc315 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(redundant_closure_call)] diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call.stderr index e2865edc870..d8ec72fda92 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call.stderr @@ -30,5 +30,3 @@ error: Try not to call a closure in the expression where it is declared. 12 | k = (|a,b| a*b)(1,5); | ^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs index 9451e19e336..0bd000082e8 100644 --- a/tests/ui/reference.rs +++ b/tests/ui/reference.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + fn get_number() -> usize { 10 diff --git a/tests/ui/reference.stderr b/tests/ui/reference.stderr index 741c0cc1038..2e6b23f6dc0 100644 --- a/tests/ui/reference.stderr +++ b/tests/ui/reference.stderr @@ -66,5 +66,3 @@ error: immediately dereferencing a reference 53 | let y = **&mut &mut x; | ^^^^^^^^^^^^ help: try this: `&mut x` -error: aborting due to 11 previous errors - diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 56539c5468f..3dd1f64202c 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(invalid_regex, trivial_regex, regex_macro)] diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 1c3a47b82be..1c244c1df12 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -149,5 +149,3 @@ error: trivial regex | = help: consider using consider using `str::is_empty` -error: aborting due to 21 previous errors - diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index 61c691c01c1..792ebc9b0ea 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(serde_api_misuse)] #![allow(dead_code)] diff --git a/tests/ui/serde.stderr b/tests/ui/serde.stderr index 58667e0f820..da0a96b2a3d 100644 --- a/tests/ui/serde.stderr +++ b/tests/ui/serde.stderr @@ -10,5 +10,3 @@ error: you should not implement `visit_string` without also implementing `visit_ | = note: `-D serde-api-misuse` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index e1f2ffacf49..fbe695a7657 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(unused_parens, unused_variables, missing_docs_in_private_items)] diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 3fc2b7234f7..50f41627acb 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -134,5 +134,3 @@ note: previous binding is here 21 | let x = y; | ^ -error: aborting due to 9 previous errors - diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index e783c6e5e69..0f5773623be 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(short_circuit_statement)] diff --git a/tests/ui/short_circuit_statement.stderr b/tests/ui/short_circuit_statement.stderr index 7697cbd1c64..d7a02d7b9c3 100644 --- a/tests/ui/short_circuit_statement.stderr +++ b/tests/ui/short_circuit_statement.stderr @@ -18,5 +18,3 @@ error: boolean short circuit operator in statement may be clearer using an expli 9 | 1 == 2 || g(); | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` -error: aborting due to 3 previous errors - diff --git a/tests/ui/should_assert_eq.rs b/tests/ui/should_assert_eq.rs index ac5fca8dd0b..5814e997753 100644 --- a/tests/ui/should_assert_eq.rs +++ b/tests/ui/should_assert_eq.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(needless_pass_by_value)] #![warn(should_assert_eq)] diff --git a/tests/ui/should_assert_eq.stderr b/tests/ui/should_assert_eq.stderr index 57abf800498..5b393e1dbe8 100644 --- a/tests/ui/should_assert_eq.stderr +++ b/tests/ui/should_assert_eq.stderr @@ -55,5 +55,3 @@ error: use `assert_ne` for better reporting | = note: this error originates in a macro outside of the current crate -error: aborting due to 7 previous errors - diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 1cb5619dd1d..66d24a3c070 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(string_add)] #[allow(string_add_assign)] diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index d098ce9df5e..a8fd59e12b2 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -72,5 +72,3 @@ error: manual implementation of an assign operation 65 | ; x = x + 1; | ^^^^^^^^^ help: replace it with: `x += 1` -error: aborting due to 11 previous errors - diff --git a/tests/ui/stutter.rs b/tests/ui/stutter.rs index 3fd410c08af..24612fd3b3e 100644 --- a/tests/ui/stutter.rs +++ b/tests/ui/stutter.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(stutter)] #![allow(dead_code)] diff --git a/tests/ui/stutter.stderr b/tests/ui/stutter.stderr index b68f561b483..38cbcaa32f5 100644 --- a/tests/ui/stutter.stderr +++ b/tests/ui/stutter.stderr @@ -24,5 +24,3 @@ error: item name ends with its containing module's name 11 | pub enum CakeFoo {} | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index abcafac4b9d..d1d12641c46 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(blacklisted_name, unused_assignments)] diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index a01ec375e63..0bda9bc8d2b 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -65,5 +65,3 @@ error: this looks like you are trying to swap `c.0` and `a` | = note: or maybe you should use `std::mem::replace`? -error: aborting due to 7 previous errors - diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index 4a12d38285c..8f25aad72bb 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(temporary_assignment)] diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 979720c914d..73a4818ba16 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -12,5 +12,3 @@ error: assignment to temporary 30 | (0, 0).0 = 1; | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 7be52580c6f..a0d6dd2dabd 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused)] diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index f360e85329f..525b181bf91 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -30,5 +30,3 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `& 24 | let ref mut z = 1 + 2; | ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);` -error: aborting due to 5 previous errors - diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 9fc71506ffe..6a7b6b05e70 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute, stmt_expr_attributes)] -#![plugin(clippy)] + #![allow(unused_parens)] fn main() { diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr index 91e4d59da98..0a4b5361d86 100644 --- a/tests/ui/trailing_zeros.stderr +++ b/tests/ui/trailing_zeros.stderr @@ -12,5 +12,3 @@ error: bit mask could be simplified with a call to `trailing_zeros` 8 | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` -error: aborting due to 2 previous errors - diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index a83e5194736..31cd8304eba 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index a571fed24f0..0c5aff11b0c 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -154,5 +154,3 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) 117 | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 25 previous errors - diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index 4f9555297ff..08866c63ec6 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,6 +1,6 @@ //ignore-x86_64 -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 9be1e37b13e..65240c80a48 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,7 +1,7 @@ //ignore-x86 //no-ignore-x86_64 -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.stderr b/tests/ui/transmute_64bit.stderr index 3a6a6e73f57..b679b913877 100644 --- a/tests/ui/transmute_64bit.stderr +++ b/tests/ui/transmute_64bit.stderr @@ -12,5 +12,3 @@ error: transmute from a `f64` to a pointer 11 | let _: *mut usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 55dd0862700..5bb0e7edfed 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(zero_width_space)] fn zero() { diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 8a173daec9d..73599235ea8 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -28,5 +28,3 @@ error: literal non-ASCII character detected = help: Consider replacing the string with: ""/u{dc}ben!"" -error: aborting due to 3 previous errors - diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index ff57d2822cb..2b6d757845f 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unit_cmp)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 51ad3fca947..a85e4150a3e 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -12,5 +12,3 @@ error: >-comparison of unit values detected. This will always be false 19 | if { true; } > { false; } { | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index c2f5b11e24c..8c960602264 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unneeded_field_pattern)] #[allow(dead_code, unused)] diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index 7e4c3a6cb9c..ef1a8d75732 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -15,5 +15,3 @@ error: All the struct fields are matched to a wildcard pattern, consider using ` | = help: Try with `Foo { .. }` instead -error: aborting due to 2 previous errors - diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 45daf70b171..327fea254a8 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(unreadable_literal)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 72cb160fafc..81b69937a6d 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -31,5 +31,3 @@ error: long literal lacking separators | = help: consider: 1.234_56_f32 -error: aborting due to 4 previous errors - diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index 8e90964da8c..29f34d31a8e 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_imports)] #![allow(dead_code)] #![warn(unsafe_removed_from_name)] diff --git a/tests/ui/unsafe_removed_from_name.stderr b/tests/ui/unsafe_removed_from_name.stderr index 93f2ddd533f..7d455d31bce 100644 --- a/tests/ui/unsafe_removed_from_name.stderr +++ b/tests/ui/unsafe_removed_from_name.stderr @@ -18,5 +18,3 @@ error: removed "unsafe" from the name of `Unsafe` in use as `LieAboutModSafety` 23 | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 9beec63a6f0..ea72c1b1b70 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(unused_io_amount)] diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 0ce6887f5f2..8739ac245a7 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -39,5 +39,3 @@ error: handle read amount returned or use `Read::read_exact` instead 27 | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs index 6d1e8c2a31c..115121dc275 100644 --- a/tests/ui/unused_labels.rs +++ b/tests/ui/unused_labels.rs @@ -1,5 +1,5 @@ -#![plugin(clippy)] -#![feature(plugin)] + + #![allow(dead_code, items_after_statements, never_loop)] #![warn(unused_label)] diff --git a/tests/ui/unused_labels.stderr b/tests/ui/unused_labels.stderr index 19c91e2a6a3..338eb2f1551 100644 --- a/tests/ui/unused_labels.stderr +++ b/tests/ui/unused_labels.stderr @@ -22,5 +22,3 @@ error: unused label `'same_label_in_two_fns` 34 | | } | |_____^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/unused_lt.rs b/tests/ui/unused_lt.rs index 722e19e6217..91bca47eb12 100644 --- a/tests/ui/unused_lt.rs +++ b/tests/ui/unused_lt.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, dead_code, needless_lifetimes, needless_pass_by_value)] #![warn(unused_lifetimes)] diff --git a/tests/ui/unused_lt.stderr b/tests/ui/unused_lt.stderr index b1fcebe6eed..a4f01de18f7 100644 --- a/tests/ui/unused_lt.stderr +++ b/tests/ui/unused_lt.stderr @@ -18,5 +18,3 @@ error: this lifetime isn't used in the function definition 50 | fn x<'a>(&self) {} | ^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 14e31aae8ee..b12900b7691 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(use_self)] #![allow(dead_code)] #![allow(should_implement_trait)] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index bfd334335d8..9d316dd3e08 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -36,5 +36,3 @@ error: unnecessary structure name repetition 24 | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` -error: aborting due to 6 previous errors - diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index d8fc7c7cbca..60a2c4e8b4c 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(blacklisted_name)] diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 712f81c1b6f..388a3491477 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -30,5 +30,3 @@ error: used binding `_underscore_field` which is prefixed with an underscore. A 36 | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index cd2636a5b6f..4c2fb221af8 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_attribute)] #[allow(dead_code, unused_extern_crates)] diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index 707a11d55cc..0bb87f8c538 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -6,5 +6,3 @@ error: useless lint attribute | = note: `-D useless-attribute` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 1845b509af0..23e43872454 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_vec)] diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 6a47eb5b064..a1555bc7907 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -36,5 +36,3 @@ error: useless use of `vec!` 49 | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` -error: aborting due to 6 previous errors - diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index 9bae1bc48e6..b7ef39da817 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(while_let_loop, empty_loop, while_let_on_iterator)] #![allow(dead_code, never_loop, unused, cyclomatic_complexity)] diff --git a/tests/ui/while_loop.stderr b/tests/ui/while_loop.stderr index 689c92d6fb6..edc88405c40 100644 --- a/tests/ui/while_loop.stderr +++ b/tests/ui/while_loop.stderr @@ -110,5 +110,3 @@ error: this loop could be written as a `for` loop 184 | | } | |_________^ help: try: `for v in y { .. }` -error: aborting due to 11 previous errors - diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 91b60c8faaa..bef87e2bb01 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(wrong_self_convention)] #![warn(wrong_pub_self_convention)] diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 216fd0bb82b..e57ffc3266b 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -72,5 +72,3 @@ error: methods called `from_*` usually take no self; consider choosing a less am 54 | pub fn from_i64(self) {} | ^^^^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index af61e1c8429..65e1e239980 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_variables)] #[warn(zero_divided_by_zero)] diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index b81e59c07f1..697432af408 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -57,5 +57,3 @@ error: constant division of 0.0 with 0.0 will always result in NaN | = help: Consider using `std::f64::NAN` if you would like a constant representing NaN -error: aborting due to 8 previous errors - diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index a72223ef54c..4a6010f4bd0 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_variables)] fn main() { diff --git a/tests/ui/zero_ptr.stderr b/tests/ui/zero_ptr.stderr index 5155dc401bd..fb87a47536e 100644 --- a/tests/ui/zero_ptr.stderr +++ b/tests/ui/zero_ptr.stderr @@ -12,5 +12,3 @@ error: `0 as *mut _` detected. Consider using `ptr::null_mut()` 7 | let y = 0 as *mut f64; | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - -- cgit 1.4.1-3-g733a5 From c526c51923b30d6c372c5a45a27f4caded53060d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Mon, 30 Oct 2017 18:21:23 -0700 Subject: Update clippy for rustc 1.23.0-nightly (f0fe716db 2017-10-30) --- clippy_lints/src/lib.rs | 1 + src/lib.rs | 1 + tests/ui/lint_pass.rs | 1 + 3 files changed, 3 insertions(+) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 18361f54d64..fdd02ba54e8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -9,6 +9,7 @@ #![feature(stmt_expr_attributes)] #![feature(conservative_impl_trait)] #![feature(inclusive_range_syntax, range_contains)] +#![feature(macro_vis_matcher)] #![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)] #![recursion_limit="256"] diff --git a/src/lib.rs b/src/lib.rs index df692b7e60c..8f0c6a63207 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] +#![feature(macro_vis_matcher)] #![allow(unknown_lints)] #![allow(missing_docs_in_private_items)] diff --git a/tests/ui/lint_pass.rs b/tests/ui/lint_pass.rs index 1990e137e67..b576f72e8e7 100644 --- a/tests/ui/lint_pass.rs +++ b/tests/ui/lint_pass.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] +#![feature(macro_vis_matcher)] #![warn(lint_without_lint_pass)] -- cgit 1.4.1-3-g733a5 From 7bce43b66b1028ae1402e3f9bfd8225400912586 Mon Sep 17 00:00:00 2001 From: Martin Lindhe <martin-commit@ubique.se> Date: Tue, 31 Oct 2017 08:34:27 +0100 Subject: fix some typos --- CHANGELOG.md | 2 +- clippy_lints/src/const_static_lifetime.rs | 2 +- clippy_lints/src/doc.rs | 2 +- src/driver.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c744796681..b6ce809f2de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,7 +72,7 @@ All notable changes to this project will be documented in this file. ## 0.0.148 * Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)* -* New lints: [`unreadable_literal`], [`inconsisten_digit_grouping`], [`large_digit_groups`] +* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`] ## 0.0.147 * Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)* diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index 4801f788856..03771f0375b 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -37,7 +37,7 @@ impl StaticConst { // Recursively visit types fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext) { match ty.node { - // Be carefull of nested structures (arrays and tuples) + // Be careful of nested structures (arrays and tuples) TyKind::Array(ref ty, _) => { self.visit_type(&*ty, cx); }, diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index abe9897ba4d..9ed09d96e1b 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -224,7 +224,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( let (begin, span) = spans[index]; - // Adjust for the begining of the current `Event` + // Adjust for the beginning of the current `Event` let span = span.with_lo(span.lo() + BytePos::from_usize(offset - begin)); check_text(cx, valid_idents, &text, span); diff --git a/src/driver.rs b/src/driver.rs index ab5e90141a9..ec5c10d4c6d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -82,7 +82,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { .as_ref() .expect( "at this compilation stage \ - the krate must be parsed", + the crate must be parsed", ) .span, ); -- cgit 1.4.1-3-g733a5 From 1326accdcfbc8123e06d6331ebd276f73b005991 Mon Sep 17 00:00:00 2001 From: topecongiro <seuchida@gmail.com> Date: Thu, 2 Nov 2017 07:09:46 +0900 Subject: Use is_ok() --- src/driver.rs | 2 +- src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index ab5e90141a9..df0ff4c3f1f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -129,7 +129,7 @@ fn show_version() { pub fn main() { use std::env; - if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + if env::var("CLIPPY_DOGFOOD").is_ok() { panic!("yummy"); } diff --git a/src/main.rs b/src/main.rs index 69f416e2092..11ae135bfa9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ fn show_version() { pub fn main() { use std::env; - if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + if env::var("CLIPPY_DOGFOOD").is_ok() { panic!("yummy"); } -- cgit 1.4.1-3-g733a5 From 49392fce53f938fda5b34673c98001ac7fea5d0f Mon Sep 17 00:00:00 2001 From: topecongiro <seuchida@gmail.com> Date: Thu, 2 Nov 2017 07:13:14 +0900 Subject: Avoid panicking when no arg is given to clippy_driver --- src/driver.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index df0ff4c3f1f..8e4114bac1b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -163,6 +163,9 @@ pub fn main() { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programatically, so we ignore this/ let mut orig_args: Vec<String> = env::args().collect(); + if orig_args.len() <= 1 { + std::process::exit(1); + } if orig_args[1] == "rustc" { // we still want to be able to invoke it normally though orig_args.remove(1); -- cgit 1.4.1-3-g733a5 From 6fc9fe2eba79958672a859497f75a689fa3e87f6 Mon Sep 17 00:00:00 2001 From: topecongiro <seuchida@gmail.com> Date: Thu, 2 Nov 2017 07:18:34 +0900 Subject: Fix a typo --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 8e4114bac1b..7bc5a109d5c 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -161,7 +161,7 @@ pub fn main() { rustc_driver::in_rustc_thread(|| { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programatically, so we ignore this/ + // We're invoking the compiler programmatically, so we ignore this/ let mut orig_args: Vec<String> = env::args().collect(); if orig_args.len() <= 1 { std::process::exit(1); -- cgit 1.4.1-3-g733a5 From 7a06d312fd4d900946f8dba8bae5baaf877e5103 Mon Sep 17 00:00:00 2001 From: topecongiro <seuchida@gmail.com> Date: Sun, 5 Nov 2017 04:55:56 +0900 Subject: Cargo fmt --- clippy_lints/src/array_indexing.rs | 10 +- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/block_in_if_condition.rs | 18 +- clippy_lints/src/booleans.rs | 6 +- clippy_lints/src/bytecount.rs | 4 +- clippy_lints/src/const_static_lifetime.rs | 28 +-- clippy_lints/src/derive.rs | 12 +- clippy_lints/src/doc.rs | 16 +- clippy_lints/src/drop_forget_ref.rs | 4 +- clippy_lints/src/entry.rs | 6 +- clippy_lints/src/enum_clike.rs | 10 +- clippy_lints/src/enum_variants.rs | 7 +- clippy_lints/src/fallible_impl_from.rs | 8 +- clippy_lints/src/format.rs | 4 +- clippy_lints/src/formatting.rs | 4 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/int_plus_one.rs | 75 +++++--- clippy_lints/src/invalid_ref.rs | 13 +- clippy_lints/src/is_unit_expr.rs | 10 +- clippy_lints/src/len_zero.rs | 4 +- clippy_lints/src/let_if_seq.rs | 14 +- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/literal_digit_grouping.rs | 2 +- clippy_lints/src/loops.rs | 276 +++++++++++++++-------------- clippy_lints/src/matches.rs | 36 +++- clippy_lints/src/mem_forget.rs | 2 +- clippy_lints/src/methods.rs | 152 +++++++++------- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 38 ++-- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/needless_continue.rs | 40 +++-- clippy_lints/src/needless_pass_by_value.rs | 14 +- clippy_lints/src/new_without_default.rs | 14 +- clippy_lints/src/no_effect.rs | 29 +-- clippy_lints/src/non_expressive_names.rs | 8 +- clippy_lints/src/ok_if_let.rs | 2 +- clippy_lints/src/open_options.rs | 4 +- clippy_lints/src/panic.rs | 2 +- clippy_lints/src/print.rs | 8 +- clippy_lints/src/ptr.rs | 45 +++-- clippy_lints/src/ranges.rs | 21 +-- clippy_lints/src/regex.rs | 7 +- clippy_lints/src/shadow.rs | 12 +- clippy_lints/src/strings.rs | 4 +- clippy_lints/src/swap.rs | 16 +- clippy_lints/src/transmute.rs | 110 +++++++----- clippy_lints/src/types.rs | 4 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/author.rs | 4 +- clippy_lints/src/utils/higher.rs | 13 +- clippy_lints/src/utils/hir_utils.rs | 48 ++--- clippy_lints/src/utils/mod.rs | 43 +++-- clippy_lints/src/utils/sugg.rs | 22 +-- src/driver.rs | 14 +- src/main.rs | 3 +- tests/conf_whitelisted.rs | 3 +- tests/dogfood.rs | 4 +- tests/issue-825.rs | 6 +- 59 files changed, 716 insertions(+), 558 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index aa2d6db6853..8949e4cc387 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -120,13 +120,19 @@ fn to_const_range( array_size: ConstInt, ) -> Option<(ConstInt, ConstInt)> { let start = match *start { - Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => x, + Some(Some(&ty::Const { + val: ConstVal::Integral(x), + .. + })) => x, Some(_) => return None, None => ConstInt::U8(0), }; let end = match *end { - Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => if limits == RangeLimits::Closed { + Some(Some(&ty::Const { + val: ConstVal::Integral(x), + .. + })) => if limits == RangeLimits::Closed { match x { ConstInt::U8(_) => (x + ConstInt::U8(1)), ConstInt::U16(_) => (x + ConstInt::U16(1)), diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 8baff551910..da7fff2ed93 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt}; use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use syntax::codemap::Span; -use utils::{in_macro, match_def_path, paths, snippet_opt, span_lint, span_lint_and_then, opt_def_id}; +use utils::{in_macro, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then}; /// **What it does:** Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index af99b77163b..a89959d9506 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> { const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; const COMPLEX_BLOCK_MESSAGE: &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'"; + instead, move the block or closure higher and bind it with a 'let'"; impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { @@ -92,9 +92,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { BLOCK_IN_IF_CONDITION_EXPR, check.span, BRACED_EXPR_MESSAGE, - &format!("try\nif {} {} ... ", - snippet_block(cx, ex.span, ".."), - snippet_block(cx, then.span, "..")), + &format!( + "try\nif {} {} ... ", + snippet_block(cx, ex.span, ".."), + snippet_block(cx, then.span, "..") + ), ); } } else { @@ -111,9 +113,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { BLOCK_IN_IF_CONDITION_STMT, check.span, COMPLEX_BLOCK_MESSAGE, - &format!("try\nlet res = {};\nif res {} ... ", - snippet_block(cx, block.span, ".."), - snippet_block(cx, then.span, "..")), + &format!( + "try\nlet res = {};\nif res {} ... ", + snippet_block(cx, block.span, ".."), + snippet_block(cx, then.span, "..") + ), ); } } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2587937616c..ca3fb4017df 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -368,9 +368,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } // if the number of occurrences of a terminal decreases or any of the stats // decreases while none increases - improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || - (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || - (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); + improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) + || (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) + || (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); } if improvement { improvements.push(suggestion); diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index e0ce4bbc93b..886834e3981 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -2,8 +2,8 @@ use rustc::hir::*; use rustc::lint::*; use rustc::ty; use syntax::ast::{Name, UintTy}; -use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, - snippet, span_lint_and_sugg, walk_ptrs_ty}; +use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg, + walk_ptrs_ty}; /// **What it does:** Checks for naive byte counts /// diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index 03771f0375b..6ee4dad7db4 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -1,6 +1,6 @@ -use syntax::ast::{Item, ItemKind, TyKind, Ty}; -use rustc::lint::{LintPass, EarlyLintPass, LintArray, EarlyContext}; -use utils::{span_lint_and_then, in_macro}; +use syntax::ast::{Item, ItemKind, Ty, TyKind}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use utils::{in_macro, span_lint_and_then}; /// **What it does:** Checks for constants with an explicit `'static` lifetime. /// @@ -20,7 +20,7 @@ use utils::{span_lint_and_then, in_macro}; /// ``` declare_lint! { - pub CONST_STATIC_LIFETIME, + pub CONST_STATIC_LIFETIME, Warn, "Using explicit `'static` lifetime for constants when elision rules would allow omitting them." } @@ -41,10 +41,8 @@ impl StaticConst { TyKind::Array(ref ty, _) => { self.visit_type(&*ty, cx); }, - TyKind::Tup(ref tup) => { - for tup_ty in tup { - self.visit_type(&*tup_ty, cx); - } + TyKind::Tup(ref tup) => for tup_ty in tup { + self.visit_type(&*tup_ty, cx); }, // This is what we are looking for ! TyKind::Rptr(ref optional_lifetime, ref borrow_type) => { @@ -54,11 +52,15 @@ impl StaticConst { // Verify that the path is a str if lifetime.ident.name == "'static" { let mut sug: String = String::new(); - span_lint_and_then(cx, - CONST_STATIC_LIFETIME, - lifetime.span, - "Constants have by default a `'static` lifetime", - |db| {db.span_suggestion(lifetime.span,"consider removing `'static`",sug);}); + span_lint_and_then( + cx, + CONST_STATIC_LIFETIME, + lifetime.span, + "Constants have by default a `'static` lifetime", + |db| { + db.span_suggestion(lifetime.span, "consider removing `'static`", sug); + }, + ); } } } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 2c45aaf6ac9..6ce67a9b05c 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -98,13 +98,13 @@ fn check_hash_peq<'a, 'tcx>( // Look for the PartialEq implementations for `ty` cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id)); - + if peq_is_automatically_derived == hash_is_automatically_derived { return; } - + let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); - + // Only care about `impl PartialEq<Foo> for Foo` // For `impl PartialEq<B> for A, input_types is [A, B] if trait_ref.substs.type_at(1) == ty { @@ -113,7 +113,7 @@ fn check_hash_peq<'a, 'tcx>( } else { "you are deriving `Hash` but have implemented `PartialEq` explicitly" }; - + span_lint_and_then( cx, DERIVE_HASH_XOR_EQ, span, mess, @@ -157,7 +157,9 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref EXPL_IMPL_CLONE_ON_COPY, item.span, "you are implementing `Clone` explicitly on a `Copy` type", - |db| { db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); }, + |db| { + 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 9ed09d96e1b..b6542b2ebca 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -204,7 +204,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( End(CodeBlock(_)) | End(Code) => in_code = false, Start(Link(link, _)) => in_link = Some(link), End(Link(_, _)) => in_link = None, - Start(_tag) | End(_tag) => (), // We don't care about other tags + Start(_tag) | End(_tag) => (), // We don't care about other tags Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it SoftBreak => (), HardBreak => (), @@ -273,8 +273,8 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { s }; - 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 + 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 } fn has_underscore(s: &str) -> bool { @@ -284,10 +284,12 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { if let Ok(url) = Url::parse(word) { // try to get around the fact that `foo::bar` parses as a valid URL if !url.cannot_be_a_base() { - span_lint(cx, - DOC_MARKDOWN, - span, - "you should put bare URLs between `<`/`>` or make a proper Markdown link"); + span_lint( + cx, + DOC_MARKDOWN, + span, + "you should put bare URLs between `<`/`>` or make a proper Markdown link", + ); return; } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 1601c276e2b..c523c569a68 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,7 +1,7 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use utils::{is_copy, match_def_path, paths, span_note_and_lint, opt_def_id}; +use utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint}; /// **What it does:** Checks for calls to `std::mem::drop` with a reference /// instead of an owned value. @@ -125,7 +125,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let msg; let arg = &args[0]; let arg_ty = cx.tables.expr_ty(arg); - + if let ty::TyRef(..) = arg_ty.sty { if match_def_path(cx.tcx, def_id, &paths::DROP) { lint = DROP_REF; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 6c7a5fec03c..b86a4a43fb1 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -95,7 +95,7 @@ fn check_cond<'a, 'tcx, 'b>( then { let map = ¶ms[0]; let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map)); - + return if match_type(cx, obj_ty, &paths::BTREEMAP) { Some(("BTreeMap", map, key)) } @@ -136,14 +136,14 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> { snippet(self.cx, self.map.span, "map"), snippet(self.cx, params[1].span, ".."), snippet(self.cx, params[2].span, "..")); - + db.span_suggestion(self.span, "consider using", help); } else { let help = format!("{}.entry({})", snippet(self.cx, self.map.span, "map"), snippet(self.cx, params[1].span, "..")); - + db.span_suggestion(self.span, "consider using", help); } }); diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index c019ab0b385..c65cf92590a 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -55,8 +55,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { .at(expr.span) .const_eval(param_env.and((did, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(Usize(Us64(i))), .. }) => u64::from(i as u32) != i, - Ok(&ty::Const { val: ConstVal::Integral(Isize(Is64(i))), .. }) => i64::from(i as i32) != i, + Ok(&ty::Const { + val: ConstVal::Integral(Usize(Us64(i))), + .. + }) => u64::from(i as u32) != i, + Ok(&ty::Const { + val: ConstVal::Integral(Isize(Is64(i))), + .. + }) => i64::from(i as i32) != i, _ => false, }; if bad { diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 6dc6f122eba..ea7a378de22 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -159,8 +159,11 @@ fn check_variant( } for var in &def.variants { let name = var2str(var); - if partial_match(item_name, &name) == item_name_chars && - name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) { + if partial_match(item_name, &name) == item_name_chars + && name.chars() + .nth(item_name_chars) + .map_or(false, |c| !c.is_lowercase()) + { span_lint(cx, lint, var.span, "Variant name starts with the enum's name"); } if partial_rmatch(item_name, &name) == item_name_chars { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index e6efd41e6fb..0c91d0cd97c 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -2,7 +2,7 @@ use rustc::lint::*; use rustc::hir; use rustc::ty; use syntax_pos::Span; -use utils::{method_chain_args, match_def_path, span_lint_and_then, walk_ptrs_ty}; +use utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty}; use utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT}; /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` @@ -74,9 +74,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0])); - if match_type(self.tcx, reciever_ty, &OPTION) || - match_type(self.tcx, reciever_ty, &RESULT) - { + if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) { self.result.push(expr.span); } } @@ -105,7 +103,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it result: Vec::new(), }; fpu.visit_expr(&body.value); - + // if we've found one, lint if !fpu.result.is_empty() { span_lint_and_then( diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8004dc17083..dcafbc50d0c 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use rustc::ty; use syntax::ast::LitKind; use utils::paths; -use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id}; +use utils::{is_expn_of, match_def_path, match_type, opt_def_id, resolve_node, span_lint, walk_ptrs_ty}; /// **What it does:** Checks for the use of `format!("string literal with no /// argument")` and `format!("{}", foo)` where `foo` is a string. @@ -109,7 +109,7 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool { if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD); then { let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0])); - + return ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING); } } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 7d712942986..e016fa3d595 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -190,8 +190,8 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { - if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() && - unsugar_if(second).is_some() + if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() + && unsugar_if(second).is_some() { // where the else would be let else_span = first.span.between(second.span); diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 85dfb6b4ad0..e1d84a07439 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -70,7 +70,7 @@ fn all_ones(v: &ConstInt) -> bool { ConstInt::U32(i) => i == !0, ConstInt::U64(i) => i == !0, ConstInt::U128(i) => i == !0, - _ => false + _ => false, } } diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 3cdffbf82ae..d7d98351647 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -4,7 +4,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::{span_help_and_lint, in_external_macro}; +use utils::{in_external_macro, span_help_and_lint}; /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an /// else branch. diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 396b06524d0..6e74547b75f 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::{span_lint_and_then, snippet_opt}; +use utils::{snippet_opt, span_lint_and_then}; /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// @@ -55,7 +55,7 @@ impl IntPlusOne { #[allow(cast_sign_loss)] fn check_lit(&self, lit: &Lit, target_value: i128) -> bool { if let LitKind::Int(value, ..) = lit.node { - return value == (target_value as u128) + return value == (target_value as u128); } false } @@ -66,49 +66,76 @@ impl IntPlusOne { (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { match (lhskind.node, &lhslhs.node, &lhsrhs.node) { // `-1 + x` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS), + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => { + self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) + }, // `x - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), - _ => None + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) + }, + _ => None, } }, // case where `... >= y + 1` or `... >= 1 + y` - (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => { + (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) + if rhskind.node == BinOpKind::Add => + { match (&rhslhs.node, &rhsrhs.node) { // `y + 1` and `1 + y` - (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS), - (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), - _ => None + (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) + }, + (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) + }, + _ => None, } - }, + } // case where `x + 1 <= ...` or `1 + x <= ...` - (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => { + (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) + if lhskind.node == BinOpKind::Add => + { match (&lhslhs.node, &lhsrhs.node) { // `1 + x` and `x + 1` - (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS), - (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), - _ => None + (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) + }, + (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) + }, + _ => None, } - }, + } // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.node, &rhsrhs.node) { // `-1 + y` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS), + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => { + self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) + }, // `y - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), - _ => None + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { + self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) + }, + _ => None, } }, - _ => None + _ => None, } } - fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option<String> { + fn generate_recommendation( + &self, + cx: &EarlyContext, + binop: BinOpKind, + node: &Expr, + other_side: &Expr, + side: Side, + ) -> Option<String> { let binop_string = match binop { BinOpKind::Ge => ">", BinOpKind::Le => "<", - _ => return None + _ => return None, }; if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { @@ -123,11 +150,7 @@ impl IntPlusOne { } fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) { - span_lint_and_then(cx, - INT_PLUS_ONE, - block.span, - "Unnecessary `>= y + 1` or `x - 1 >=`", - |db| { + span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| { db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation); }); } diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index 649e1f7ac78..8cc12323fd5 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -1,13 +1,13 @@ use rustc::lint::*; use rustc::ty; use rustc::hir::*; -use utils::{match_def_path, paths, span_help_and_lint, opt_def_id}; +use utils::{match_def_path, opt_def_id, paths, span_help_and_lint}; /// **What it does:** Checks for creation of references to zeroed or uninitialized memory. /// /// **Why is this bad?** Creation of null references is undefined behavior. /// -/// **Known problems:** None. +/// **Known problems:** None. /// /// **Example:** /// ```rust @@ -22,9 +22,10 @@ declare_lint! { const ZERO_REF_SUMMARY: &str = "reference to zeroed memory"; const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory"; -const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html"; +const HELP: &str = + "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html"; -pub struct InvalidRef; +pub struct InvalidRef; impl LintPass for InvalidRef { fn get_lints(&self) -> LintArray { @@ -38,7 +39,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef { if let ExprCall(ref path, ref args) = expr.node; if let ExprPath(ref qpath) = path.node; if args.len() == 0; - if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty; + if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty; if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)); then { let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) { @@ -50,7 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef { }; span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP); } - } + } return; } } diff --git a/clippy_lints/src/is_unit_expr.rs b/clippy_lints/src/is_unit_expr.rs index 734ef1ecb76..3f94178e524 100644 --- a/clippy_lints/src/is_unit_expr.rs +++ b/clippy_lints/src/is_unit_expr.rs @@ -139,13 +139,9 @@ fn check_last_stmt_in_block(block: &Block) -> bool { // like `panic!()` match final_stmt.node { StmtKind::Expr(_) => false, - StmtKind::Semi(ref expr) => { - match expr.node { - ExprKind::Break(_, _) | - ExprKind::Continue(_) | - ExprKind::Ret(_) => false, - _ => true, - } + StmtKind::Semi(ref expr) => match expr.node { + ExprKind::Break(_, _) | ExprKind::Continue(_) | ExprKind::Ret(_) => false, + _ => true, }, _ => true, } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 9b14a44f2c0..967688e4f46 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -119,8 +119,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai .iter() .flat_map(|&i| cx.tcx.associated_items(i)) .any(|i| { - i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" && - cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 + i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" + && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 }); if !is_empty_method_found { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 931b872e036..34863208fde 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq { if !used_in_expr(cx, canonical_id, value); then { let span = stmt.span.to(if_.span); - + 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, canonical_id, else_) { @@ -94,15 +94,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq { } else { continue; }; - + let mutability = match mode { BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ", _ => "", }; - + // FIXME: this should not suggest `mut` if we can detect that the variable is not // use mutably after the `if` - + let sug = format!( "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", mut=mutability, @@ -174,15 +174,15 @@ fn check_assign<'a, 'tcx>( id: decl, used: false, }; - + for s in block.stmts.iter().take(block.stmts.len()-1) { hir::intravisit::walk_stmt(&mut v, s); - + if v.used { return None; } } - + return Some(value); } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5549c98aaf3..0f8f4610871 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -11,8 +11,7 @@ #![feature(inclusive_range_syntax, range_contains)] #![feature(macro_vis_matcher)] #![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)] - -#![recursion_limit="256"] +#![recursion_limit = "256"] #[macro_use] extern crate rustc; diff --git a/clippy_lints/src/literal_digit_grouping.rs b/clippy_lints/src/literal_digit_grouping.rs index 91e4c567488..011b5ec1d5e 100644 --- a/clippy_lints/src/literal_digit_grouping.rs +++ b/clippy_lints/src/literal_digit_grouping.rs @@ -270,7 +270,7 @@ impl LiteralDigitGrouping { .digits .split_terminator('.') .collect(); - + // Lint integral and fractional parts separately, and then check consistency of digit // groups if both pass. let _ = Self::do_lint(parts[0]) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2e6835b7f68..2d994d468c6 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -16,7 +16,7 @@ use rustc::ty::{self, Ty}; use rustc::ty::subst::{Subst, Substs}; use rustc_const_eval::ConstContext; use std::collections::{HashMap, HashSet}; -use std::iter::{Iterator, once}; +use std::iter::{once, Iterator}; use syntax::ast; use syntax::codemap::Span; use utils::sugg; @@ -377,8 +377,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // check for never_loop match expr.node { - ExprWhile(_, ref block, _) | - ExprLoop(ref block, _, _) => { + ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => { let mut state = NeverLoopState { breaks: HashSet::new(), continues: HashSet::new(), @@ -413,11 +412,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node { // ensure "if let" compatible match structure match *source { - MatchSource::Normal | - MatchSource::IfLetDesugar { .. } => { - 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_simple_break_expr(&arms[1].body) + MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { + 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_simple_break_expr(&arms[1].body) { if in_external_macro(cx, expr.span) { return; @@ -449,15 +447,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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 qpath, ref pat_args, _), - &ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node) + if let ( + &PatKind::TupleStruct(ref qpath, ref pat_args, _), + &ExprMethodCall(ref method_path, _, ref method_args), + ) = (pat, &match_expr.node) { let iter_expr = &method_args[0]; let lhs_constructor = last_path_segment(qpath); - if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) && - lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) && - !is_iterator_used_after_while_let(cx, iter_expr) && - !is_nested(cx, expr, &method_args[0]) + if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) + && lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) + && !is_iterator_used_after_while_let(cx, iter_expr) + && !is_nested(cx, expr, &method_args[0]) { let iterator = snippet(cx, method_args[0].span, "_"); let loop_var = snippet(cx, pat_args[0].span, "_"); @@ -505,8 +505,7 @@ fn never_loop_block(block: &Block, state: &mut NeverLoopState) -> bool { fn stmt_to_expr(stmt: &Stmt) -> Option<&Expr> { match stmt.node { - StmtSemi(ref e, ..) | - StmtExpr(ref e, ..) => Some(e), + StmtSemi(ref e, ..) | StmtExpr(ref e, ..) => Some(e), StmtDecl(ref d, ..) => decl_to_expr(d), } } @@ -528,9 +527,9 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool { ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprRepeat(ref e, _) => never_loop_expr(e, state), - ExprArray(ref es) | - ExprMethodCall(_, _, ref es) | - ExprTup(ref es) => never_loop_expr_seq(&mut es.iter(), state), + ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => { + never_loop_expr_seq(&mut es.iter(), state) + }, ExprCall(ref e, ref es) => never_loop_expr_seq(&mut once(&**e).chain(es.iter()), state), ExprBinary(_, ref e1, ref e2) | ExprAssign(ref e1, ref e2) | @@ -567,12 +566,16 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool { }, ExprBlock(ref b) => never_loop_block(b, state), ExprAgain(d) => { - let id = d.target_id.opt_id().expect("target id can only be missing in the presence of compilation errors"); + let id = d.target_id + .opt_id() + .expect("target id can only be missing in the presence of compilation errors"); state.continues.insert(id); false }, ExprBreak(d, _) => { - let id = d.target_id.opt_id().expect("target id can only be missing in the presence of compilation errors"); + let id = d.target_id + .opt_id() + .expect("target id can only be missing in the presence of compilation errors"); state.breaks.insert(id); false }, @@ -586,12 +589,14 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool { } } -fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, state: &mut NeverLoopState) -> bool { - es.map(|e| never_loop_expr(e, state)).fold(true, |a, b| a && b) +fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, state: &mut NeverLoopState) -> bool { + es.map(|e| never_loop_expr(e, state)) + .fold(true, |a, b| a && b) } -fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, state: &mut NeverLoopState) -> bool { - e.map(|e| never_loop_expr(e, state)).fold(false, |a, b| a || b) +fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, state: &mut NeverLoopState) -> bool { + e.map(|e| never_loop_expr(e, state)) + .fold(false, |a, b| a || b) } fn check_for_loop<'a, 'tcx>( @@ -665,11 +670,9 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty) -> bool { fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> Option<FixedOffsetVar> { fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::NodeId) -> Option<String> { match e.node { - ExprLit(ref l) => { - match l.node { - ast::LitKind::Int(x, _ty) => Some(x.to_string()), - _ => None, - } + ExprLit(ref l) => match l.node { + ast::LitKind::Int(x, _ty) => Some(x.to_string()), + _ => None, }, ExprPath(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())), _ => None, @@ -683,29 +686,25 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: } let offset = match idx.node { - ExprBinary(op, ref lhs, ref rhs) => { - match op.node { - BinOp_::BiAdd => { - let offset_opt = if same_var(cx, lhs, var) { - extract_offset(cx, rhs, var) - } else if same_var(cx, rhs, var) { - extract_offset(cx, lhs, var) - } else { - None - }; + ExprBinary(op, ref lhs, ref rhs) => match op.node { + BinOp_::BiAdd => { + let offset_opt = if same_var(cx, lhs, var) { + extract_offset(cx, rhs, var) + } else if same_var(cx, rhs, var) { + extract_offset(cx, lhs, var) + } else { + None + }; - offset_opt.map(Offset::positive) - }, - BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), - _ => None, - } + offset_opt.map(Offset::positive) + }, + BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), + _ => None, }, - ExprPath(..) => { - if same_var(cx, idx, var) { - Some(Offset::positive("0".into())) - } else { - None - } + ExprPath(..) => if same_var(cx, idx, var) { + Some(Offset::positive("0".into())) + } else { + None }, _ => None, }; @@ -777,12 +776,13 @@ fn get_indexed_assignments<'a, 'tcx>( .iter() .map(|stmt| match stmt.node { Stmt_::StmtDecl(..) => None, - Stmt_::StmtExpr(ref e, _node_id) | - Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)), + Stmt_::StmtExpr(ref e, _node_id) | Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)), }) - .chain(expr.as_ref().into_iter().map(|e| { - Some(get_assignment(cx, &*e, var)) - })) + .chain( + expr.as_ref() + .into_iter() + .map(|e| Some(get_assignment(cx, &*e, var))), + ) .filter_map(|op| op) .collect::<Option<Vec<_>>>() .unwrap_or_else(|| vec![]) @@ -801,20 +801,18 @@ fn detect_manual_memcpy<'a, 'tcx>( expr: &'tcx Expr, ) { if let Some(higher::Range { - start: Some(start), - ref end, - limits, - }) = higher::range(arg) + start: Some(start), + ref end, + limits, + }) = higher::range(arg) { // the var must be a single name if let PatKind::Binding(_, canonical_id, _, _) = pat.node { let print_sum = |arg1: &Offset, arg2: &Offset| -> String { match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) { ("0", _, "0", _) => "".into(), - ("0", _, x, false) | - (x, false, "0", false) => x.into(), - ("0", _, x, true) | - (x, false, "0", true) => format!("-{}", x), + ("0", _, x, false) | (x, false, "0", false) => x.into(), + ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x), (x, false, y, false) => format!("({} + {})", x, y), (x, false, y, true) => format!("({} - {})", x, y), (x, true, y, false) => format!("({} - {})", y, x), @@ -897,10 +895,10 @@ fn check_for_loop_range<'a, 'tcx>( expr: &'tcx Expr, ) { if let Some(higher::Range { - start: Some(start), - ref end, - limits, - }) = higher::range(arg) + start: Some(start), + ref end, + limits, + }) = higher::range(arg) { // the var must be a single name if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node { @@ -917,9 +915,11 @@ fn check_for_loop_range<'a, 'tcx>( // linting condition: we only indexed one variable, and indexed it directly // (`indexed_directly` is subset of `indexed`) if visitor.indexed.len() == 1 && visitor.indexed_directly.len() == 1 { - let (indexed, indexed_extent) = visitor.indexed_directly.into_iter().next().expect( - "already checked that we have exactly 1 element", - ); + let (indexed, indexed_extent) = visitor + .indexed_directly + .into_iter() + .next() + .expect("already checked that we have exactly 1 element"); // ensure that the indexed variable was declared before the loop, see #601 if let Some(indexed_extent) = indexed_extent { @@ -1024,10 +1024,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool { fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, expr: &'tcx Expr) { // if this for loop is iterating over a two-sided range... if let Some(higher::Range { - start: Some(start), - end: Some(end), - limits, - }) = higher::range(arg) + start: Some(start), + end: Some(end), + limits, + }) = higher::range(arg) { // ...and both sides are compile-time constant integers... let parent_item = cx.tcx.hir.get_parent(arg.id); @@ -1041,10 +1041,16 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx // who think that this will iterate from the larger value to the // smaller value. let (sup, eq) = match (start_idx, end_idx) { - (&ty::Const { val: ConstVal::Integral(start_idx), .. }, - &ty::Const { val: ConstVal::Integral(end_idx), .. }) => { - (start_idx > end_idx, start_idx == end_idx) - }, + ( + &ty::Const { + val: ConstVal::Integral(start_idx), + .. + }, + &ty::Const { + val: ConstVal::Integral(end_idx), + .. + }, + ) => (start_idx > end_idx, start_idx == end_idx), _ => (false, false), }; @@ -1132,7 +1138,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { // If the length is greater than 32 no traits are implemented for array and // therefore we cannot use `&`. ty::TypeVariants::TyArray(_, size) if const_to_u64(size) > 32 => (), - _ => lint_iter_method(cx, args, arg, method_name) + _ => lint_iter_method(cx, args, arg, method_name), }; } else { let object = snippet(cx, args[0].span, "_"); @@ -1219,14 +1225,14 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( // For each candidate, check the parent block to see if // it's initialized to zero at the start of the loop. let map = &cx.tcx.hir; - let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| { - map.get_enclosing_scope(id) - }); + let parent_scope = map.get_enclosing_scope(expr.id) + .and_then(|id| map.get_enclosing_scope(id)); if let Some(parent_id) = parent_scope { if let NodeBlock(block) = map.get(parent_id) { - for (id, _) in visitor.states.iter().filter( - |&(_, v)| *v == VarState::IncrOnce, - ) + for (id, _) in visitor + .states + .iter() + .filter(|&(_, v)| *v == VarState::IncrOnce) { let mut visitor2 = InitializeVisitor { cx: cx, @@ -1273,12 +1279,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( if pat.len() == 2 { let arg_span = arg.span; let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty { - ty::TyRef(_, ref tam) => { - match (&pat[0].node, &pat[1].node) { - (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl), - (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable), - _ => return, - } + ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) { + (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl), + (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable), + _ => return, }, _ => return, }; @@ -1322,14 +1326,11 @@ struct MutateDelegate { } impl<'tcx> Delegate<'tcx> for MutateDelegate { - fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) { - } + fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {} - fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) { - } + fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {} - fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) { - } + fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {} fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) { if let ty::BorrowKind::MutBorrow = bk { @@ -1355,8 +1356,7 @@ impl<'tcx> Delegate<'tcx> for MutateDelegate { } } - fn decl_without_init(&mut self, _: NodeId, _: Span) { - } + fn decl_without_init(&mut self, _: NodeId, _: Span) {} } impl<'tcx> MutateDelegate { @@ -1366,8 +1366,16 @@ impl<'tcx> MutateDelegate { } fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) { - let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; + if let Some(higher::Range { + start: Some(start), + end: Some(end), + .. + }) = higher::range(arg) + { + let mut_ids = vec![ + check_for_mutability(cx, start), + check_for_mutability(cx, end), + ]; if mut_ids[0].is_some() || mut_ids[1].is_some() { let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids); mut_warn_with_span(cx, span_low); @@ -1378,7 +1386,12 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) { if let Some(sp) = span { - span_lint(cx, MUT_RANGE_BOUND, sp, "attempt to mutate range bound within loop; note that the range of the loop is unchanged"); + span_lint( + cx, + MUT_RANGE_BOUND, + sp, + "attempt to mutate range bound within loop; note that the range of the loop is unchanged", + ); } } @@ -1405,7 +1418,12 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> { } fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) { - let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; + let mut delegate = MutateDelegate { + node_id_low: bound_ids[0], + node_id_high: bound_ids[1], + span_low: None, + span_high: None, + }; let def_id = def_id::DefId::local(body.hir_id.owner); let region_scope_tree = &cx.tcx.region_scope_tree(def_id); ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(body); @@ -1430,7 +1448,7 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool { struct UsedVisitor { var: ast::Name, // var to look for - used: bool, // has the var been used otherwise? + used: bool, // has the var been used otherwise? } impl<'tcx> Visitor<'tcx> for UsedVisitor { @@ -1652,12 +1670,9 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> { fn extract_first_expr(block: &Block) -> Option<&Expr> { match block.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), - StmtDecl(..) => None, - } + None if !block.stmts.is_empty() => match block.stmts[0].node { + StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), + StmtDecl(..) => None, }, _ => None, } @@ -1669,11 +1684,9 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> { fn is_simple_break_expr(expr: &Expr) -> bool { match expr.node { ExprBreak(dest, ref passed_expr) if dest.ident.is_none() && passed_expr.is_none() => true, - ExprBlock(ref b) => { - match extract_first_expr(b) { - Some(subexpr) => is_simple_break_expr(subexpr), - None => false, - } + ExprBlock(ref b) => match extract_first_expr(b) { + Some(subexpr) => is_simple_break_expr(subexpr), + None => false, }, _ => false, } @@ -1684,7 +1697,7 @@ fn is_simple_break_expr(expr: &Expr) -> bool { // at the start of the loop. #[derive(PartialEq)] enum VarState { - Initial, // Not examined yet + Initial, // Not examined yet IncrOnce, // Incremented exactly once, may be a loop counter Declared, // Declared but not (yet) initialized to zero Warn, @@ -1693,9 +1706,9 @@ enum VarState { /// Scan a for loop for variables that are incremented exactly once. struct IncrementVisitor<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx>, // context reference + cx: &'a LateContext<'a, 'tcx>, // context reference states: HashMap<NodeId, VarState>, // incremented variables - depth: u32, // depth of conditional expressions + depth: u32, // depth of conditional expressions done: bool, } @@ -1749,7 +1762,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { /// Check whether a variable is initialized to zero at the start of a loop. struct InitializeVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, // context reference - end_expr: &'tcx Expr, // the for loop. Stop scanning here. + end_expr: &'tcx Expr, // the for loop. Stop scanning here. var_id: NodeId, state: VarState, name: Option<Name>, @@ -1881,13 +1894,11 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool return false; } match cx.tcx.hir.find(parent) { - Some(NodeExpr(expr)) => { - match expr.node { - ExprLoop(..) | ExprWhile(..) => { - return true; - }, - _ => (), - } + Some(NodeExpr(expr)) => match expr.node { + ExprLoop(..) | ExprWhile(..) => { + return true; + }, + _ => (), }, Some(NodeBlock(block)) => { let mut block_visitor = LoopNestVisitor { @@ -1911,8 +1922,8 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool #[derive(PartialEq, Eq)] enum Nesting { - Unknown, // no nesting detected yet - RuledOut, // the iterator is initialized or assigned within scope + Unknown, // no nesting detected yet + RuledOut, // the iterator is initialized or assigned within scope LookFurther, // no nesting detected, no further walk required } @@ -1942,11 +1953,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } match expr.node { - ExprAssign(ref path, _) | - ExprAssignOp(_, ref path, _) => { - if match_var(path, self.iterator) { - self.nesting = RuledOut; - } + ExprAssign(ref path, _) | ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) { + self.nesting = RuledOut; }, _ => walk_expr(self, expr), } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 18ba34f8621..dd3b2f00b7d 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -412,7 +412,11 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match } /// Get all arms that are unbounded `PatRange`s. -fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm], id: NodeId) -> Vec<SpannedRange<&'tcx ty::Const<'tcx>>> { +fn all_ranges<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + arms: &'tcx [Arm], + id: NodeId, +) -> Vec<SpannedRange<&'tcx ty::Const<'tcx>>> { let parent_item = cx.tcx.hir.get_parent(id); let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); @@ -471,15 +475,39 @@ fn type_ranges(ranges: &[SpannedRange<&ty::Const>]) -> TypedRanges { ranges .iter() .filter_map(|range| match range.node { - (&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Included(&ty::Const { val: ConstVal::Integral(end), .. })) => Some(SpannedRange { + ( + &ty::Const { + val: ConstVal::Integral(start), + .. + }, + Bound::Included(&ty::Const { + val: ConstVal::Integral(end), + .. + }), + ) => Some(SpannedRange { span: range.span, node: (start, Bound::Included(end)), }), - (&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Excluded(&ty::Const { val: ConstVal::Integral(end), .. })) => Some(SpannedRange { + ( + &ty::Const { + val: ConstVal::Integral(start), + .. + }, + Bound::Excluded(&ty::Const { + val: ConstVal::Integral(end), + .. + }), + ) => Some(SpannedRange { span: range.span, node: (start, Bound::Excluded(end)), }), - (&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Unbounded) => Some(SpannedRange { + ( + &ty::Const { + val: ConstVal::Integral(start), + .. + }, + Bound::Unbounded, + ) => Some(SpannedRange { span: range.span, node: (start, Bound::Unbounded), }), diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 43409eaea50..103dbb72229 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,6 +1,6 @@ use rustc::lint::*; use rustc::hir::{Expr, ExprCall, ExprPath}; -use utils::{match_def_path, paths, span_lint, opt_def_id}; +use utils::{match_def_path, opt_def_id, paths, span_lint}; /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is /// `Drop`. diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 4f55162e57f..547caf46082 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -652,7 +652,8 @@ impl LintPass for Pass { GET_UNWRAP, STRING_EXTEND_CHARS, ITER_CLONED_COLLECT, - USELESS_ASREF) + USELESS_ASREF + ) } } @@ -773,7 +774,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } } - + // check conventions w.r.t. conversion method names and predicates let def_id = cx.tcx.hir.local_def_id(item.id); let ty = cx.tcx.type_of(def_id); @@ -801,7 +802,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } } - + let ret_ty = return_ty(cx, implitem.id); if name == "new" && !ret_ty.walk().any(|t| same_tys(cx, t, ty)) { @@ -887,9 +888,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir: // don't lint for constant values // FIXME: can we `expect` here instead of match? let owner_def = cx.tcx.hir.get_parent_did(arg.id); - let promotable = cx.tcx - .rvalue_promotable_map(owner_def) - [&arg.hir_id.local_id]; + let promotable = cx.tcx.rvalue_promotable_map(owner_def)[&arg.hir_id.local_id]; if promotable { return; } @@ -991,12 +990,8 @@ fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { expr.span, "using '.clone()' on a ref-counted pointer", "try this", - format!("{}::clone(&{})", - caller_type, - snippet(cx, arg.span, "_") - ) + format!("{}::clone(&{})", caller_type, snippet(cx, arg.span, "_")), ); - } @@ -1055,8 +1050,8 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr } fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) { - if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) && - derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() + if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) + && derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() { span_lint( cx, @@ -1231,8 +1226,16 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr] // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. - let arg = if unwrap_snippet == "None" { "None" } else { "a" }; - let suggest = if unwrap_snippet == "None" { "and_then(f)" } else { "map_or(a, f)" }; + let arg = if unwrap_snippet == "None" { + "None" + } else { + "a" + }; + let suggest = if unwrap_snippet == "None" { + "and_then(f)" + } else { + "map_or(a, f)" + }; let msg = &format!( "called `map(f).unwrap_or({})` on an Option value. \ This can be done more directly by calling `{}` instead", @@ -1276,10 +1279,10 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( // lint message let msg = if is_option { "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ - `map_or_else(g, f)` instead" + `map_or_else(g, f)` instead" } else { "called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \ - `ok().map_or_else(g, f)` instead" + `ok().map_or_else(g, f)` instead" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); @@ -1323,7 +1326,6 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( /// lint use of `_.map_or(None, _)` for `Option`s fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) { - if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) { // check if the first non-self argument to map_or() is None let map_or_arg_is_none = if let hir::Expr_::ExprPath(ref qpath) = map_or_args[1].node { @@ -1339,13 +1341,9 @@ fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, let map_or_self_snippet = snippet(cx, map_or_args[0].span, ".."); let map_or_func_snippet = snippet(cx, map_or_args[2].span, ".."); let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet); - span_lint_and_then( - cx, - OPTION_MAP_OR_NONE, - expr.span, - msg, - |db| { db.span_suggestion(expr.span, "try using and_then instead", hint); }, - ); + span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| { + db.span_suggestion(expr.span, "try using and_then instead", hint); + }); } } } @@ -1374,7 +1372,12 @@ fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, } /// lint use of `filter().map()` for `Iterators` -fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) { +fn lint_filter_map<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr, + _filter_args: &'tcx [hir::Expr], + _map_args: &'tcx [hir::Expr], +) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter(p).map(q)` on an `Iterator`. \ @@ -1384,7 +1387,12 @@ fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, } /// lint use of `filter().map()` for `Iterators` -fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) { +fn lint_filter_map_map<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr, + _filter_args: &'tcx [hir::Expr], + _map_args: &'tcx [hir::Expr], +) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter_map(p).map(q)` on an `Iterator`. \ @@ -1394,7 +1402,12 @@ fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Ex } /// lint use of `filter().flat_map()` for `Iterators` -fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) { +fn lint_filter_flat_map<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr, + _filter_args: &'tcx [hir::Expr], + _map_args: &'tcx [hir::Expr], +) { // lint if caller of `.filter().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \ @@ -1405,7 +1418,12 @@ fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::E } /// lint use of `filter_map().flat_map()` for `Iterators` -fn lint_filter_map_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) { +fn lint_filter_map_flat_map<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr, + _filter_args: &'tcx [hir::Expr], + _map_args: &'tcx [hir::Expr], +) { // lint if caller of `.filter_map().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \ @@ -1476,7 +1494,13 @@ fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, i } /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints. -fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool { +fn lint_chars_cmp<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + info: &BinaryExprInfo, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); if let hir::ExprCall(ref fun, ref arg_char) = info.other.node; @@ -1486,11 +1510,11 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c if segment.name == "Some"; then { let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0])); - + if self_ty.sty != ty::TyStr { return false; } - + span_lint_and_sugg(cx, lint, info.expr.span, @@ -1501,7 +1525,7 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c snippet(cx, args[0][0].span, "_"), suggest, snippet(cx, arg_char[0].span, "_"))); - + return true; } } @@ -1524,7 +1548,13 @@ fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprIn } /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. -fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool { +fn lint_chars_cmp_with_unwrap<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + info: &BinaryExprInfo, + chain_methods: &[&str], + lint: &'static Lint, + suggest: &str, +) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); if let hir::ExprLit(ref lit) = info.other.node; @@ -1542,7 +1572,7 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &Binar suggest, c) ); - + return true; } } @@ -1569,7 +1599,11 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi let parent_item = cx.tcx.hir.get_parent(arg.id); let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - if let Ok(&ty::Const { val: ConstVal::Str(r), .. }) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) { + if let Ok(&ty::Const { + val: ConstVal::Str(r), + .. + }) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) + { if r.len() == 1 { let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); span_lint_and_then( @@ -1577,7 +1611,9 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi SINGLE_CHAR_PATTERN, arg.span, "single-character string constant used as pattern", - |db| { db.span_suggestion(expr.span, "try using a char instead", hint); }, + |db| { + db.span_suggestion(expr.span, "try using a char instead", hint); + }, ); } } @@ -1772,31 +1808,25 @@ impl SelfKind { fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool { single_segment_ty(ty).map_or(false, |seg| { generics.ty_params.iter().any(|param| { - param.name == seg.name && - param - .bounds - .iter() - .any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { - let path = &ptr.trait_ref.path; - match_path(path, name) && - path.segments - .last() - .map_or(false, |s| { - if let Some(ref params) = s.parameters { - if params.parenthesized { - false - } else { - params.types.len() == 1 && - (is_self_ty(¶ms.types[0]) - || is_ty(&*params.types[0], self_ty)) - } - } else { - false - } - }) - } else { - false + param.name == seg.name && param.bounds.iter().any(|bound| { + if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { + let path = &ptr.trait_ref.path; + match_path(path, name) && path.segments.last().map_or(false, |s| { + if let Some(ref params) = s.parameters { + if params.parenthesized { + false + } else { + params.types.len() == 1 + && (is_self_ty(¶ms.types[0]) || is_ty(&*params.types[0], self_ty)) + } + } else { + false + } }) + } else { + false + } + }) }) }) } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index bcdbd738ee1..b5b844e199e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -2,7 +2,7 @@ use consts::{constant_simple, Constant}; use rustc::lint::*; use rustc::hir::*; use std::cmp::{Ordering, PartialOrd}; -use utils::{match_def_path, paths, span_lint, opt_def_id}; +use utils::{match_def_path, opt_def_id, paths, span_lint}; /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are /// used to clamp values, but switched so that the result is constant. diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 18d7f7230a8..e1d350a9ad2 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -328,8 +328,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> 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") + if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") + || name.ends_with("_eq") { return; } @@ -410,13 +410,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) { if !in_constant(cx, expr.id) { - path.segments.last().map(|seg| if seg.name == "NAN" { - span_lint( - cx, - CMP_NAN, - expr.span, - "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead", - ); + path.segments.last().map(|seg| { + if seg.name == "NAN" { + span_lint( + cx, + CMP_NAN, + expr.span, + "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead", + ); + } }); } } @@ -426,7 +428,11 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool { let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); let res = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr); - if let Ok(&ty::Const { val: ConstVal::Float(val), .. }) = res { + if let Ok(&ty::Const { + val: ConstVal::Float(val), + .. + }) = res + { use std::cmp::Ordering; match val.ty { FloatTy::F32 => { @@ -445,8 +451,8 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool { bits: u128::from(::std::f32::NEG_INFINITY.to_bits()), }; - 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) }, FloatTy::F64 => { let zero = ConstFloat { @@ -464,8 +470,8 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool { bits: u128::from(::std::f64::NEG_INFINITY.to_bits()), }; - 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 { @@ -576,9 +582,7 @@ fn in_attributes_expansion(expr: &Expr) -> bool { /// Test whether `def` is a variable defined outside a macro. fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool { match *def { - def::Def::Local(id) | def::Def::Upvar(id, _, _) => { - !in_macro(cx.tcx.hir.span(id)) - }, + def::Def::Local(id) | def::Def::Upvar(id, _, _) => !in_macro(cx.tcx.hir.span(id)), _ => false, } } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index be1fd1dc525..b1388864bdc 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { if let Some(snippet) = snippet_opt(cx, inner.span) { db.span_suggestion(e.span, "change this to", snippet); } - } + }, ); } } diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 00d7a945595..ccf9c62d93c 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -255,13 +255,13 @@ struct LintData<'a> { const MSG_REDUNDANT_ELSE_BLOCK: &str = "This else block is redundant.\n"; const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "There is no need for an explicit `else` block for this `if` \ - expression\n"; + expression\n"; const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the else clause and merging the code that \ - follows (in the loop) with the if block, like so:\n"; + follows (in the loop) with the if block, like so:\n"; const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \ - block, like so:\n"; + block, like so:\n"; fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: LintType) { @@ -332,22 +332,24 @@ fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext, data: &'a } fn check_and_warn<'a>(ctx: &EarlyContext, expr: &'a ast::Expr) { - with_loop_block(expr, |loop_block| for (i, stmt) in loop_block.stmts.iter().enumerate() { - with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { - let data = &LintData { - stmt_idx: i, - if_expr: if_expr, - if_cond: cond, - if_block: then_block, - else_expr: else_expr, - block_stmts: &loop_block.stmts, - }; - if needless_continue_in_else(else_expr) { - emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock); - } else if is_first_block_stmt_continue(then_block) { - emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock); - } - }); + with_loop_block(expr, |loop_block| { + for (i, stmt) in loop_block.stmts.iter().enumerate() { + with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { + let data = &LintData { + stmt_idx: i, + if_expr: if_expr, + if_cond: cond, + if_block: then_block, + else_expr: else_expr, + block_stmts: &loop_block.stmts, + }; + if needless_continue_in_else(else_expr) { + emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock); + } else if is_first_block_stmt_continue(then_block) { + emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock); + } + }); + } }); } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ac965a59bd5..5675d38af06 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -106,13 +106,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec()) .filter(|p| !p.is_global()) - .filter_map(|pred| if let ty::Predicate::Trait(poly_trait_ref) = pred { - if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() { - return None; + .filter_map(|pred| { + if let ty::Predicate::Trait(poly_trait_ref) = pred { + if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() { + return None; + } + Some(poly_trait_ref) + } else { + None } - Some(poly_trait_ref) - } else { - None }) .collect::<Vec<_>>(); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 74465b64051..b09fb107b07 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -108,11 +108,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { // can't be implemented by default return; } - if !cx.generics.expect("method must have generics").ty_params.is_empty() { - // when the result of `new()` depends on a type parameter we should not require - // an - // impl of `Default` - return; + if !cx.generics + .expect("method must have generics") + .ty_params + .is_empty() + { + // when the result of `new()` depends on a type parameter we should not require + // an + // impl of `Default` + return; } if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) { let self_ty = cx.tcx diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index f5543821949..a1139ff7464 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,7 +1,7 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::hir::def::Def; use rustc::hir::{BiAnd, BiOr, BlockCheckMode, Expr, Expr_, Stmt, StmtSemi, UnsafeSource}; -use utils::{in_macro, snippet_opt, span_lint, span_lint_and_sugg, has_drop}; +use utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg}; use std::ops::Deref; /// **What it does:** Checks for statements which have no effect. @@ -146,23 +146,24 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp Expr_::ExprTupField(ref inner, _) | Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), - Expr_::ExprStruct(_, ref fields, ref base) => { - if has_drop(cx, expr) { - None - } else { - Some( - fields - .iter() - .map(|f| &f.expr) - .chain(base) - .map(Deref::deref) - .collect()) - } + Expr_::ExprStruct(_, ref fields, ref base) => if has_drop(cx, expr) { + None + } else { + Some( + fields + .iter() + .map(|f| &f.expr) + .chain(base) + .map(Deref::deref) + .collect(), + ) }, Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node { let def = cx.tables.qpath_def(qpath, callee.hir_id); match def { - Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) if !has_drop(cx, expr) => { + Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) + if !has_drop(cx, expr) => + { Some(args.iter().collect()) }, _ => None, diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 6cbeea8214d..d0bbb10fb4d 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -187,8 +187,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let second_last_e = existing_chars .next_back() .expect("we know we have at least three chars"); - if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' || - !interned_chars.zip(existing_chars).all(eq_or_numeric) + if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' + || !interned_chars.zip(existing_chars).all(eq_or_numeric) { // allowed similarity foo_x, foo_y // or too many chars differ (foo_x, boo_y) or (foox, booy) @@ -203,8 +203,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let second_e = existing_chars .next() .expect("we know we have at least two chars"); - if !eq_or_numeric((second_i, second_e)) || second_i == '_' || - !interned_chars.zip(existing_chars).all(eq_or_numeric) + if !eq_or_numeric((second_i, second_e)) || second_i == '_' + || !interned_chars.zip(existing_chars).all(eq_or_numeric) { // allowed similarity x_foo, y_foo // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index e6fe0631a63..b79e90f910b 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprMethodCall(_, _, ref result_types) = op.node; //check is expr.ok() has type Result<T,E>.ok() if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - + then { let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); let some_expr_string = snippet(cx, y[0].span, ""); diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 62760888933..673f428eb07 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -81,8 +81,8 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp } } else { return; // The function is called with a literal - // which is not a boolean literal. This is theoretically - // possible, but not very likely. + // which is not a boolean literal. This is theoretically + // possible, but not very likely. } }, _ => Argument::Unknown, diff --git a/clippy_lints/src/panic.rs b/clippy_lints/src/panic.rs index 1a14a0bc45d..9430e59ac86 100644 --- a/clippy_lints/src/panic.rs +++ b/clippy_lints/src/panic.rs @@ -1,7 +1,7 @@ use rustc::hir::*; use rustc::lint::*; use syntax::ast::LitKind; -use utils::{is_direct_expn_of, match_def_path, paths, resolve_node, span_lint, opt_def_id}; +use utils::{is_direct_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint}; /// **What it does:** Checks for missing parameters in `panic!`. /// diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index ce6b96108a4..61ed8d5ac25 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -6,7 +6,7 @@ use syntax::ast::LitKind; use syntax::symbol::InternedString; use syntax_pos::Span; use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint}; -use utils::{paths, opt_def_id}; +use utils::{opt_def_id, paths}; /// **What it does:** This lint warns when you using `println!("")` to /// print a newline. @@ -94,7 +94,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if let ExprPath(ref qpath) = fun.node; if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)); then { - + // Search for `std::io::_print(..)` which is unique in a // `print!` expansion. if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) { @@ -104,9 +104,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { Some(span) => (span, "println"), None => (span, "print"), }; - + span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); - + if_chain! { // ensure we're calling Arguments::new_v1 if args.len() == 1; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 916132daeff..a6a3690202f 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -8,8 +8,7 @@ use rustc::ty; use syntax::ast::NodeId; use syntax::codemap::Span; use syntax_pos::MultiSpan; -use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, - walk_ptrs_hir_ty}; +use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty}; use utils::ptr::get_spans; /// **What it does:** This lint checks for function arguments of type `&String` @@ -121,7 +120,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) { if let TraitItemKind::Method(ref sig, ref trait_method) = item.node { - let body_id = if let TraitMethod::Provided(b) = *trait_method { Some(b) } else { None }; + let body_id = if let TraitMethod::Provided(b) = *trait_method { + Some(b) + } else { + None + }; check_fn(cx, &sig.decl, item.id, body_id); } } @@ -173,17 +176,19 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option< with non-Vec-based slices.", |db| { if let Some(ref snippet) = ty_snippet { - db.span_suggestion(arg.span, - "change this to", - format!("&[{}]", snippet)); + db.span_suggestion(arg.span, "change this to", format!("&[{}]", snippet)); } for (clonespan, suggestion) in spans { - db.span_suggestion(clonespan, - &snippet_opt(cx, clonespan).map_or("change the call to".into(), - |x| Cow::Owned(format!("change `{}` to", x))), - suggestion.into()); + db.span_suggestion( + clonespan, + &snippet_opt(cx, clonespan).map_or( + "change the call to".into(), + |x| Cow::Owned(format!("change `{}` to", x)), + ), + suggestion.into(), + ); } - } + }, ); } } else if match_type(cx, ty, &paths::STRING) { @@ -194,16 +199,18 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option< arg.span, "writing `&String` instead of `&str` involves a new object where a slice will do.", |db| { - db.span_suggestion(arg.span, - "change this to", - "&str".into()); + db.span_suggestion(arg.span, "change this to", "&str".into()); for (clonespan, suggestion) in spans { - db.span_suggestion_short(clonespan, - &snippet_opt(cx, clonespan).map_or("change the call to".into(), - |x| Cow::Owned(format!("change `{}` to", x))), - suggestion.into()); + db.span_suggestion_short( + clonespan, + &snippet_opt(cx, clonespan).map_or( + "change the call to".into(), + |x| Cow::Owned(format!("change `{}` to", x)), + ), + suggestion.into(), + ); } - } + }, ); } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 6e9bebca757..39252ceed1c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -82,12 +82,7 @@ pub struct Pass; impl LintPass for Pass { fn get_lints(&self) -> LintArray { - lint_array!( - ITERATOR_STEP_BY_ZERO, - RANGE_ZIP_WITH_LEN, - RANGE_PLUS_ONE, - RANGE_MINUS_ONE - ) + lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE) } } @@ -192,14 +187,12 @@ fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { fn y_plus_one(expr: &Expr) -> Option<&Expr> { match expr.node { - ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => { - if is_integer_literal(lhs, 1) { - Some(rhs) - } else if is_integer_literal(rhs, 1) { - Some(lhs) - } else { - None - } + ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) { + Some(rhs) + } else if is_integer_literal(rhs, 1) { + Some(lhs) + } else { + None }, _ => None, } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 0c125825d8a..beb24a3dbe4 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -10,7 +10,7 @@ use std::error::Error; use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{BytePos, Span}; use syntax::symbol::InternedString; -use utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint, opt_def_id}; +use utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint}; /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct @@ -151,7 +151,10 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Inte let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let substs = Substs::identity_for_item(cx.tcx, parent_def_id); match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(e) { - Ok(&ty::Const { val: ConstVal::Str(r), .. }) => Some(r), + Ok(&ty::Const { + val: ConstVal::Str(r), + .. + }) => Some(r), _ => None, } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index f6461b2d438..92ac65b5abc 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -253,7 +253,9 @@ fn lint_shadow<'a, 'tcx: 'a>( snippet(cx, pattern_span, "_"), snippet(cx, expr.span, "..") ), - |db| { db.span_note(prev_span, "previous binding is here"); }, + |db| { + db.span_note(prev_span, "previous binding is here"); + }, ); } else if contains_name(name, expr) { span_lint_and_then( @@ -292,7 +294,9 @@ fn lint_shadow<'a, 'tcx: 'a>( 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"); + }, ); } } @@ -361,8 +365,8 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool { match expr.node { ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprBlock(ref block) => { - block.stmts.is_empty() && - block + block.stmts.is_empty() + && block .expr .as_ref() .map_or(false, |e| is_self_shadow(name, e)) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 0365322ef68..17514d9d658 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -123,8 +123,8 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { match src.node { ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), ExprBlock(ref block) => { - block.stmts.is_empty() && - block + block.stmts.is_empty() + && block .expr .as_ref() .map_or(false, |expr| is_add(cx, expr, target)) diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 6497bb9b443..22722c919a2 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -89,7 +89,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { if let ExprIndex(ref lhs2, ref idx2) = lhs2.node { if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) { let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1)); - + if matches!(ty.sty, ty::TySlice(_)) || matches!(ty.sty, ty::TyArray(_, _)) || match_type(cx, ty, &paths::VEC) || @@ -99,10 +99,10 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { } } } - + None } - + let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) { if let Some(slice) = Sugg::hir_opt(cx, slice) { (false, @@ -120,9 +120,9 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { } else { (true, "".to_owned(), "".to_owned()) }; - + let span = w[0].span.to(second.span); - + span_lint_and_then(cx, MANUAL_SWAP, span, @@ -130,7 +130,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { |db| { if !sugg.is_empty() { db.span_suggestion(span, "try", sugg); - + if replace { db.note("or maybe you should use `std::mem::replace`?"); } @@ -160,9 +160,9 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) { } else { ("".to_owned(), "".to_owned(), "".to_owned()) }; - + let span = first.span.to(second.span); - + span_lint_and_then(cx, ALMOST_SWAPPED, span, diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index d01a63f0494..1028381e20a 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -4,7 +4,7 @@ use rustc::hir::*; use std::borrow::Cow; use syntax::ast; use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; -use utils::{sugg, opt_def_id}; +use utils::{opt_def_id, sugg}; /// **What it does:** Checks for transmutes that can't ever be correct on any /// architecture. @@ -190,7 +190,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { if let ExprCall(ref path_expr, ref args) = e.node { if let ExprPath(ref qpath) = path_expr.node { if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) { - if match_def_path(cx.tcx, def_id, &paths::TRANSMUTE) { let from_ty = cx.tables.expr_ty(&args[0]); let to_ty = cx.tables.expr_ty(e); @@ -217,15 +216,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { db.span_suggestion(e.span, "try", sugg.to_string()); }, ), - (&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::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::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::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(_), &ty::TyRef(..)) | (&ty::TyFloat(_), &ty::TyRawPtr(_)) | (&ty::TyChar, &ty::TyRef(..)) | @@ -249,7 +250,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty), + &format!( + "transmute from a type (`{}`) to a pointer to that type (`{}`)", + from_ty, + to_ty + ), ), (&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_ref_ty)) => span_lint_and_then( cx, @@ -257,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { e.span, &format!( "transmute from a pointer type (`{}`) to a reference type \ - (`{}`)", + (`{}`)", from_ty, to_ty ), @@ -291,8 +296,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } else { arg }; - db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({}).unwrap()", arg.to_string())); - } + db.span_suggestion( + e.span, + "consider using", + format!("std::char::from_u32({}).unwrap()", arg.to_string()), + ); + }, ), (&ty::TyRef(_, ref ref_from), &ty::TyRef(_, ref ref_to)) => { if_chain! { @@ -326,34 +335,49 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } } }, - (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | - (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then( - cx, - TRANSMUTE_INT_TO_BOOL, - e.span, - &format!("transmute from a `{}` to a `bool`", from_ty), - |db| { - let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let zero = sugg::Sugg::NonParen(Cow::from("0")); - db.span_suggestion(e.span, "consider using", sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string()); - } - ), - (&ty::TyInt(_), &ty::TyFloat(_)) | - (&ty::TyUint(_), &ty::TyFloat(_)) => span_lint_and_then( - cx, - TRANSMUTE_INT_TO_FLOAT, - e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), - |db| { - let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let arg = if let ty::TyInt(int_ty) = from_ty.sty { - arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()))) - } else { - arg - }; - db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string())); - } - ), + (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => { + span_lint_and_then( + cx, + TRANSMUTE_INT_TO_BOOL, + e.span, + &format!("transmute from a `{}` to a `bool`", from_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let zero = sugg::Sugg::NonParen(Cow::from("0")); + db.span_suggestion( + e.span, + "consider using", + sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(), + ); + }, + ) + }, + (&ty::TyInt(_), &ty::TyFloat(_)) | (&ty::TyUint(_), &ty::TyFloat(_)) => { + span_lint_and_then( + cx, + TRANSMUTE_INT_TO_FLOAT, + e.span, + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let arg = if let ty::TyInt(int_ty) = from_ty.sty { + arg.as_ty(format!( + "u{}", + int_ty + .bit_width() + .map_or_else(|| "size".to_string(), |v| v.to_string()) + )) + } else { + arg + }; + db.span_suggestion( + e.span, + "consider using", + format!("{}::from_bits({})", to_ty, arg.to_string()), + ); + }, + ) + }, _ => return, }; } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 96caea5c17d..cb472789099 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -241,7 +241,7 @@ fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifeti // Ignore `Box<Any>` types, see #1884 for details. return; } - + let ltopt = if lt.is_elided() { "".to_owned() } else { @@ -1730,7 +1730,7 @@ impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<' if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) { return; } - + if match_path(ty_path, &paths::HASHMAP) { if method.name == "new" { self.suggestions diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 985b52b4f53..8203377e465 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf { then { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters; let should_check = if let Some(ref params) = *parameters { - !params.parenthesized && params.lifetimes.len() == 0 + !params.parenthesized && params.lifetimes.len() == 0 } else { true }; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index a4bdcd15290..eadc672e56b 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -245,7 +245,9 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { // FIXME: also check int type LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat), LitKind::Float(..) => println!(" if let LitKind::Float(..) = {}.node;", lit_pat), - LitKind::FloatUnsuffixed(_) => println!(" if let LitKind::FloatUnsuffixed(_) = {}.node;", lit_pat), + LitKind::FloatUnsuffixed(_) => { + println!(" if let LitKind::FloatUnsuffixed(_) = {}.node;", lit_pat) + }, LitKind::ByteStr(ref vec) => { let vec_pat = self.next("vec"); println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat); diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 93afb449cf6..091261ffbec 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -6,7 +6,7 @@ use rustc::hir; use rustc::lint::LateContext; use syntax::ast; -use utils::{is_expn_of, match_def_path, match_qpath, paths, resolve_node, opt_def_id}; +use utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node}; /// Convert a hir binary operator to the corresponding `ast` type. pub fn binop(op: hir::BinOp_) -> ast::BinOpKind { @@ -48,10 +48,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> { /// 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)? - .expr; + let expr = &fields.iter().find(|field| field.name.node == name)?.expr; Some(expr) } @@ -72,8 +69,8 @@ pub fn range(expr: &hir::Expr) -> Option<Range> { None } }, - hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD) || - match_qpath(path, &paths::RANGE_FROM) + hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD) + || match_qpath(path, &paths::RANGE_FROM) { Some(Range { start: Some(get_field("start", fields)?), @@ -198,7 +195,7 @@ pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e return Some(VecArgs::Vec(&*args)); } } - + None } else { diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index f7867dfd0bd..397b925a566 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -55,8 +55,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { /// Check whether two blocks are the same. pub fn eq_block(&self, left: &Block, right: &Block) -> bool { - over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && - both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) + over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) + && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) } pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { @@ -81,14 +81,14 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { }, (&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.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.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str()) && - both(le, re, |l, r| self.eq_expr(l, r)) + both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.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)) => { @@ -109,22 +109,22 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { }, (&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)) + 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_path, _, ref l_args), &ExprMethodCall(ref r_path, _, ref r_args)) => { !self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args) }, (&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => { - self.eq_expr(le, re) && - self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) + self.eq_expr(le, re) + && self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) }, (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), (&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r), (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => { - 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)) + 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), @@ -169,8 +169,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { }, (&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)) + 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, @@ -190,18 +190,18 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } fn eq_path(&self, left: &Path, right: &Path) -> bool { - left.is_global() == right.is_global() && - over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) + left.is_global() == right.is_global() + && over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) } fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool { if !(left.parenthesized || right.parenthesized) { - 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)) + 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)) } else if left.parenthesized && right.parenthesized { - over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) && - both( + over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) + && both( &Some(&left.bindings[0].ty), &Some(&right.bindings[0].ty), |l, r| self.eq_ty(l, r), @@ -220,7 +220,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.parameters, &right.parameters) { (&None, &None) => true, (&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r), - _ => false + _ => false, } } @@ -228,8 +228,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { match (&left.node, &right.node) { (&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => { - self.eq_ty(lt, rt) && - self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) + self.eq_ty(lt, rt) + && self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value) }, (&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty), (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index a3b0e928aa2..c557e856bf4 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -125,8 +125,8 @@ pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool { tcx.push_item_path(&mut apb, def_id); - apb.names.len() == path.len() && - apb.names + apb.names.len() == path.len() + && apb.names .into_iter() .zip(path.iter()) .all(|(a, &b)| *a == *b) @@ -201,8 +201,8 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool { QPath::Resolved(_, ref path) => match_path(path, segments), QPath::TypeRelative(ref ty, ref segment) => match ty.node { TyPath(ref inner_path) => { - !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) && - segment.name == segments[segments.len() - 1] + !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) + && segment.name == segments[segments.len() - 1] }, _ => false, }, @@ -233,7 +233,6 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { /// Get the definition associated to a path. pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { - let crates = cx.tcx.crates(); let krate = crates .iter() @@ -269,7 +268,11 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { } pub fn const_to_u64(c: &ty::Const) -> u64 { - c.val.to_const_int().expect("eddyb says this works").to_u64().expect("see previous expect") + c.val + .to_const_int() + .expect("eddyb says this works") + .to_u64() + .expect("see previous expect") } /// Convenience function to get the `DefId` of a trait by path. @@ -473,10 +476,12 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { Cow::Owned( s.lines() .enumerate() - .map(|(i, l)| if (ignore_first && i == 0) || l.is_empty() { - l - } else { - l.split_at(x).1 + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l + } else { + l.split_at(x).1 + } }) .collect::<Vec<_>>() .join("\n"), @@ -494,12 +499,13 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { if node_id == parent_id { return None; } - map.find(parent_id) - .and_then(|node| if let Node::NodeExpr(parent) = node { + map.find(parent_id).and_then(|node| { + if let Node::NodeExpr(parent) = node { Some(parent) } else { None - }) + } + }) } pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { @@ -598,7 +604,9 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>( help: &str, sugg: String, ) { - span_lint_and_then(cx, lint, sp, msg, |db| { db.span_suggestion(sp, help, sugg); }); + span_lint_and_then(cx, lint, sp, msg, |db| { + db.span_suggestion(sp, help, sugg); + }); } /// Create a suggestion made from several `span → replacement`. @@ -609,7 +617,7 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>( /// the whole suggestion. pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I) where - I: IntoIterator<Item=(Span, String)>, + I: IntoIterator<Item = (Span, String)>, { let sugg = rustc_errors::CodeSuggestion { substitution_parts: sugg.into_iter() @@ -629,9 +637,8 @@ where /// Return the base type for HIR references and pointers. pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty { match ty.node { - TyPtr(ref mut_ty) | - TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), - _ => ty + TyPtr(ref mut_ty) | TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), + _ => ty, } } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 3fd372052f6..c680e3eeb5b 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -267,11 +267,11 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { /// 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() + || (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 { @@ -472,11 +472,13 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error let mut first = true; let new_item = new_item .lines() - .map(|l| if first { - first = false; - format!("{}\n", l) - } else { - format!("{}{}\n", indent, l) + .map(|l| { + if first { + first = false; + format!("{}\n", l) + } else { + format!("{}{}\n", indent, l) + } }) .collect::<String>(); diff --git a/src/driver.rs b/src/driver.rs index 4e367406bcc..8e88cc2e346 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -154,9 +154,7 @@ pub fn main() { .and_then(|out| String::from_utf8(out.stdout).ok()) .map(|s| s.trim().to_owned()) }) - .expect( - "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", - ) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") }; rustc_driver::in_rustc_thread(|| { @@ -176,7 +174,9 @@ pub fn main() { let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { orig_args.clone() } else { - orig_args.clone().into_iter() + orig_args + .clone() + .into_iter() .chain(Some("--sysroot".to_owned())) .chain(Some(sys_root)) .collect() @@ -185,8 +185,10 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") || - orig_args.iter().any(|s| s == "--emit=metadata"); + let clippy_enabled = env::var("CLIPPY_TESTS") + .ok() + .map_or(false, |val| val == "true") + || orig_args.iter().any(|s| s == "--emit=metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); diff --git a/src/main.rs b/src/main.rs index 11ae135bfa9..10c0360a267 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,8 +69,7 @@ pub fn main() { .skip(2) .find(|val| val.starts_with("--manifest-path=")); - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) - { + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata } else { let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); diff --git a/tests/conf_whitelisted.rs b/tests/conf_whitelisted.rs index 198bf465bd5..5ada775560e 100644 --- a/tests/conf_whitelisted.rs +++ b/tests/conf_whitelisted.rs @@ -1,3 +1,2 @@ #![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))] - +#![plugin(clippy(conf_file = "./tests/auxiliary/conf_whitelisted.toml"))] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index aa2c4d03bd5..4870bd285b4 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -24,9 +24,7 @@ fn dogfood() { let mut s = String::new(); s.push_str(" -L target/debug/"); s.push_str(" -L target/debug/deps"); - s.push_str( - " -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal", - ); + s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal"); config.target_rustcflags = Some(s); if let Ok(name) = var("TESTNAME") { config.filter = Some(name.to_owned()) diff --git a/tests/issue-825.rs b/tests/issue-825.rs index 50de10b936c..f806c2c6fde 100644 --- a/tests/issue-825.rs +++ b/tests/issue-825.rs @@ -4,9 +4,9 @@ // this should compile in a reasonable amount of time fn rust_type_id(name: &str) { - 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!(); } -- cgit 1.4.1-3-g733a5 From 127c41f700a719cc60594382d7ae0409ba238d0b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 14 Nov 2017 14:56:00 +0100 Subject: Apply changes that were required for running in the rustc test suite --- Cargo.toml | 2 +- clippy_lints/src/lib.rs | 15 ++++++-- src/driver.rs | 40 ++++++++++----------- src/main.rs | 6 ---- tests/compile-test.rs | 53 +++++++++++++++++++++++++--- tests/conf_whitelisted.rs | 2 +- tests/dogfood.rs | 49 ------------------------- tests/ui/conf_bad_toml.rs | 2 +- tests/ui/conf_bad_toml.stderr | 4 +-- tests/ui/conf_bad_type.rs | 2 +- tests/ui/conf_bad_type.stderr | 4 +-- tests/ui/conf_french_blacklisted_name.rs | 2 +- tests/ui/conf_french_blacklisted_name.stderr | 4 +-- tests/ui/conf_unknown_key.rs | 2 +- tests/ui/conf_unknown_key.stderr | 4 +-- tests/ui/format.stderr | 12 ------- tests/ui/implicit_hasher.rs | 2 +- tests/ui/int_plus_one.rs | 4 +-- tests/ui/int_plus_one.stderr | 2 -- tests/ui/invalid_ref.rs | 4 +-- tests/ui/invalid_ref.stderr | 2 -- tests/ui/mut_range_bound.rs | 4 +-- tests/ui/mut_range_bound.stderr | 2 -- tests/ui/print_with_newline.stderr | 18 ---------- 24 files changed, 101 insertions(+), 140 deletions(-) delete mode 100644 tests/dogfood.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 157a0d18a99..38fcae19354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,12 +40,12 @@ path = "src/driver.rs" clippy_lints = { version = "0.0.170", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" +regex = "0.2" [dev-dependencies] compiletest_rs = "0.3" duct = "0.8.2" lazy_static = "0.2" -regex = "0.2" serde_derive = "1.0" clippy-mini-macro-test = { version = "0.1", path = "mini-macro" } serde = "1.0" diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 275508a372a..b53b34b3b2b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -183,17 +183,28 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { match utils::conf::lookup_conf_file() { Ok(path) => path, Err(error) => { - reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit(); + reg.sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)).emit(); None } } }; + let file_name = file_name.map(|file_name| if file_name.is_relative() { + reg.sess + .local_crate_source_file + .as_ref() + .and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf)) + .unwrap_or_default() + .join(file_name) + } else { + file_name + }); + let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref())); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit(); + reg.sess.struct_err(&format!("error reading Clippy's configuration file `{}`: {}", file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), error)).emit(); } conf diff --git a/src/driver.rs b/src/driver.rs index 8e88cc2e346..090e69cf027 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -129,33 +129,29 @@ fn show_version() { pub fn main() { use std::env; - if env::var("CLIPPY_DOGFOOD").is_ok() { - panic!("yummy"); - } - if std::env::args().any(|a| a == "--version" || a == "-V") { show_version(); return; } - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - }; + let sys_root = option_env!("SYSROOT") + .map(String::from) + .or_else(|| std::env::var("SYSROOT").ok()) + .or_else(|| { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) + }) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); rustc_driver::in_rustc_thread(|| { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. diff --git a/src/main.rs b/src/main.rs index 10c0360a267..c613f029b16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,12 +49,6 @@ fn show_version() { } pub fn main() { - use std::env; - - if env::var("CLIPPY_DOGFOOD").is_ok() { - 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(); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index bd968cc6009..51ab6aee3a4 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,6 +1,9 @@ +#![feature(test)] + extern crate compiletest_rs as compiletest; +extern crate test; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use std::env::{set_var, var}; fn clippy_driver_path() -> PathBuf { @@ -11,16 +14,37 @@ fn clippy_driver_path() -> PathBuf { } } -fn run_mode(dir: &'static str, mode: &'static str) { +fn host_libs() -> PathBuf { + if let Some(path) = option_env!("HOST_LIBS") { + PathBuf::from(path) + } else { + Path::new("target").join(env!("PROFILE")) + } +} + +fn rustc_test_suite() -> Option<PathBuf> { + option_env!("RUSTC_TEST_SUITE").map(PathBuf::from) +} + +fn rustc_lib_path() -> PathBuf { + option_env!("RUSTC_LIB_PATH").unwrap().into() +} + +fn config(dir: &'static str, mode: &'static str) -> compiletest::Config { let mut config = compiletest::Config::default(); let cfg_mode = mode.parse().expect("Invalid mode"); - config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps -Dwarnings".to_owned()); if let Ok(name) = var::<&str>("TESTNAME") { let s: String = name.to_owned(); config.filter = Some(s) } + if rustc_test_suite().is_some() { + config.run_lib_path = rustc_lib_path(); + config.compile_lib_path = rustc_lib_path(); + } + config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display())); + config.mode = cfg_mode; config.build_base = { let mut path = std::env::current_dir().unwrap(); @@ -29,8 +53,11 @@ fn run_mode(dir: &'static str, mode: &'static str) { }; config.src_base = PathBuf::from(format!("tests/{}", dir)); config.rustc_path = clippy_driver_path(); + config +} - compiletest::run_tests(&config); +fn run_mode(dir: &'static str, mode: &'static str) { + compiletest::run_tests(&config(dir, mode)); } fn prepare_env() { @@ -45,3 +72,21 @@ fn compile_test() { run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); } + +#[test] +fn dogfood() { + prepare_env(); + let files = ["src/main.rs", "src/driver.rs", "src/lib.rs", "clippy_lints/src/lib.rs"]; + let mut config = config("dogfood", "ui"); + config.target_rustcflags = config.target_rustcflags.map(|flags| format!("{} -Dclippy -Dclippy_pedantic -Dclippy_internal", flags)); + + for file in &files { + let paths = test::TestPaths { + base: PathBuf::new(), + file: PathBuf::from(file), + relative_dir: PathBuf::new(), + }; + + compiletest::runtest::run(config.clone(), &paths); + } +} diff --git a/tests/conf_whitelisted.rs b/tests/conf_whitelisted.rs index 5ada775560e..10a7d3e72d7 100644 --- a/tests/conf_whitelisted.rs +++ b/tests/conf_whitelisted.rs @@ -1,2 +1,2 @@ #![feature(plugin)] -#![plugin(clippy(conf_file = "./tests/auxiliary/conf_whitelisted.toml"))] +#![plugin(clippy(conf_file = "./auxiliary/conf_whitelisted.toml"))] diff --git a/tests/dogfood.rs b/tests/dogfood.rs deleted file mode 100644 index 4870bd285b4..00000000000 --- a/tests/dogfood.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![feature(test, plugin)] -#![plugin(clippy)] -#![deny(clippy, clippy_pedantic)] - -extern crate compiletest_rs as compiletest; -extern crate test; - -use std::env::{set_var, var}; -use std::path::PathBuf; -use test::TestPaths; - -#[test] -fn dogfood() { - // don't run dogfood on travis, cargo-clippy already runs clippy on itself - if let Ok(travis) = var("TRAVIS") { - if travis == "true" { - return; - } - } - - let mut config = compiletest::Config::default(); - - let cfg_mode = "run-fail".parse().expect("Invalid mode"); - let mut s = String::new(); - s.push_str(" -L target/debug/"); - s.push_str(" -L target/debug/deps"); - s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal"); - config.target_rustcflags = Some(s); - if let Ok(name) = var("TESTNAME") { - config.filter = Some(name.to_owned()) - } - - config.mode = cfg_mode; - config.verbose = true; - - let files = ["src/main.rs", "src/lib.rs", "clippy_lints/src/lib.rs"]; - - for file in &files { - let paths = TestPaths { - base: PathBuf::new(), - file: PathBuf::from(file), - relative_dir: PathBuf::new(), - }; - - set_var("CLIPPY_DOGFOOD", "tastes like chicken"); - - compiletest::runtest::run(config.clone(), &paths); - } -} diff --git a/tests/ui/conf_bad_toml.rs b/tests/ui/conf_bad_toml.rs index 4de2cf6ae73..a2ce7ecc519 100644 --- a/tests/ui/conf_bad_toml.rs +++ b/tests/ui/conf_bad_toml.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file -#![plugin(clippy(conf_file="./tests/ui/conf_bad_toml.toml"))] +#![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_toml.stderr b/tests/ui/conf_bad_toml.stderr index 5ddf8c14f70..45477ff0855 100644 --- a/tests/ui/conf_bad_toml.stderr +++ b/tests/ui/conf_bad_toml.stderr @@ -1,8 +1,8 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597) --> $DIR/conf_bad_toml.rs:4:1 | -4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_toml.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +4 | #![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_bad_type.rs b/tests/ui/conf_bad_type.rs index 4cb21b91582..cb18bfb8c90 100644 --- a/tests/ui/conf_bad_type.rs +++ b/tests/ui/conf_bad_type.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` -#![plugin(clippy(conf_file="./tests/ui/conf_bad_type.toml"))] +#![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_type.stderr b/tests/ui/conf_bad_type.stderr index 961df381c99..0fa40cfca9b 100644 --- a/tests/ui/conf_bad_type.stderr +++ b/tests/ui/conf_bad_type.stderr @@ -1,8 +1,8 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597) --> $DIR/conf_bad_type.rs:4:1 | -4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_type.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +4 | #![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_french_blacklisted_name.rs b/tests/ui/conf_french_blacklisted_name.rs index 9f22ff659f2..dbe6d85e5d2 100644 --- a/tests/ui/conf_french_blacklisted_name.rs +++ b/tests/ui/conf_french_blacklisted_name.rs @@ -1,5 +1,5 @@ -#![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] +#![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))] #![allow(dead_code)] #![allow(single_match)] diff --git a/tests/ui/conf_french_blacklisted_name.stderr b/tests/ui/conf_french_blacklisted_name.stderr index c98adb6029f..f7eb174f9a6 100644 --- a/tests/ui/conf_french_blacklisted_name.stderr +++ b/tests/ui/conf_french_blacklisted_name.stderr @@ -1,8 +1,8 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597) --> $DIR/conf_french_blacklisted_name.rs:2:1 | -2 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 | #![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_unknown_key.rs b/tests/ui/conf_unknown_key.rs index aec2c883367..437d0f9d8b0 100644 --- a/tests/ui/conf_unknown_key.rs +++ b/tests/ui/conf_unknown_key.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: unknown key `foobar` -#![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] +#![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))] fn main() {} diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr index 9fc7dbea563..c525366c129 100644 --- a/tests/ui/conf_unknown_key.stderr +++ b/tests/ui/conf_unknown_key.stderr @@ -1,8 +1,8 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597) --> $DIR/conf_unknown_key.rs:4:1 | -4 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +4 | #![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 67d97f295d8..558e9e83c33 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -6,15 +6,3 @@ error: useless use of `format!` | = note: `-D useless-format` implied by `-D warnings` -error: useless use of `format!` - --> $DIR/format.rs:8:5 - | -8 | format!("{}", "foo"); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: useless use of `format!` - --> $DIR/format.rs:15:5 - | -15 | format!("{}", arg); - | ^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index 32ca0f56d77..c93f858b5ca 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,5 +1,5 @@ #![allow(unused)] -//#![feature(plugin)]#![plugin(clippy)] + use std::collections::{HashMap, HashSet}; use std::cmp::Eq; use std::hash::{Hash, BuildHasher}; diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index 90375dad555..a9e059f4a3e 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(no_effect, unnecessary_operation)] #[warn(int_plus_one)] diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 92b012bd104..5d42ebb8986 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,5 +1,3 @@ -warning: running cargo clippy on a crate that also imports the clippy plugin - error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:10:5 | diff --git a/tests/ui/invalid_ref.rs b/tests/ui/invalid_ref.rs index 2b8f04c9781..ce2596c0c1a 100644 --- a/tests/ui/invalid_ref.rs +++ b/tests/ui/invalid_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![feature(core_intrinsics)] diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index 18064c91a01..c018bdf6dd3 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,5 +1,3 @@ -warning: running cargo clippy on a crate that also imports the clippy plugin - error: reference to zeroed memory --> $DIR/invalid_ref.rs:27:24 | diff --git a/tests/ui/mut_range_bound.rs b/tests/ui/mut_range_bound.rs index 835ceeedc94..0e397c7ae8c 100644 --- a/tests/ui/mut_range_bound.rs +++ b/tests/ui/mut_range_bound.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index f516ec9d95e..20dbb6511d7 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -1,5 +1,3 @@ -warning: running cargo clippy on a crate that also imports the clippy plugin - error: attempt to mutate range bound within loop; note that the range of the loop is unchanged --> $DIR/mut_range_bound.rs:18:21 | diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 2ade3ae4ef5..0148a470e0d 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -6,21 +6,3 @@ error: using `print!()` with a format string that ends in a newline, consider us | = note: `-D print-with-newline` implied by `-D warnings` -error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:7:5 - | -7 | print!("Hello {}/n", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:8:5 - | -8 | print!("Hello {} {}/n/n", "world", "#2"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:9:5 - | -9 | print!("{}/n", 1265); - | ^^^^^^^^^^^^^^^^^^^^^ - -- cgit 1.4.1-3-g733a5 From 8ddcb81a15d6d186a71e7954d709ac94cbb7b718 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Fri, 15 Dec 2017 10:02:39 +0100 Subject: Rustup and lazy_static version mismatch fix fixes #2274 --- CHANGELOG.md | 3 +++ Cargo.toml | 6 +++--- clippy_lints/Cargo.toml | 4 ++-- clippy_lints/src/missing_doc.rs | 1 + clippy_lints/src/utils/inspector.rs | 3 +++ clippy_lints/src/utils/mod.rs | 1 + src/main.rs | 2 ++ tests/compile-test.rs | 18 ------------------ tests/dogfood.rs | 17 +++++++++++++++++ tests/mut_mut_macro.rs | 31 +++++++++++++++++++++++++++++++ tests/run-pass/mut_mut_macro.rs | 31 ------------------------------- 11 files changed, 63 insertions(+), 54 deletions(-) create mode 100644 tests/dogfood.rs create mode 100644 tests/mut_mut_macro.rs delete mode 100644 tests/run-pass/mut_mut_macro.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 6093bc0b5b0..90ea18f5f6f 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.176 +* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)* + ## 0.0.175 * Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)* diff --git a/Cargo.toml b/Cargo.toml index 5101ae05d32..75e57b6889a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.175" +version = "0.0.176" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", @@ -37,7 +37,7 @@ path = "src/driver.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.175", path = "clippy_lints" } +clippy_lints = { version = "0.0.176", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" regex = "0.2" @@ -45,7 +45,7 @@ regex = "0.2" [dev-dependencies] compiletest_rs = "0.3" duct = "0.8.2" -lazy_static = "0.2" +lazy_static = "1.0" serde_derive = "1.0" clippy-mini-macro-test = { version = "0.1", path = "mini-macro" } serde = "1.0" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index cbf40240a7f..00416d24d64 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.175" +version = "0.0.176" # end automatic update authors = [ "Manish Goregaokar <manishsmail@gmail.com>", @@ -17,7 +17,7 @@ keywords = ["clippy", "lint", "plugin"] [dependencies] itertools = "0.6.0" -lazy_static = "0.2.8" +lazy_static = "1.0" matches = "0.1.2" quine-mc_cluskey = "0.2.2" regex-syntax = "0.4.0" diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 768e6cc3ec6..2a3a4e365a5 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -129,6 +129,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { hir::ItemStatic(..) => "a static", hir::ItemStruct(..) => "a struct", hir::ItemTrait(..) => "a trait", + hir::ItemTraitAlias(..) => "a trait alias", hir::ItemGlobalAsm(..) => "an assembly blob", hir::ItemTy(..) => "a type alias", hir::ItemUnion(..) => "a union", diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index ae1d9462b7c..fa6681ef078 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -403,6 +403,9 @@ fn print_item(cx: &LateContext, item: &hir::Item) { println!("trait is not auto"); } }, + hir::ItemTraitAlias(..) => { + println!("trait alias"); + } hir::ItemAutoImpl(_, ref _trait_ref) => { println!("auto impl"); }, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 77c70922dba..0c1b10f05c8 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -940,6 +940,7 @@ pub fn opt_def_id(def: Def) -> Option<DefId> { Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | + Def::TraitAlias(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | diff --git a/src/main.rs b/src/main.rs index c613f029b16..8affe549348 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,10 +141,12 @@ pub fn main() { let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); if let Some(first) = target.kind.get(0) { if target.kind.len() > 1 || first.ends_with("lib") { + println!("lib: {}", target.name); if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { std::process::exit(code); } } else if ["bin", "example", "test", "bench"].contains(&&**first) { + println!("{}: {}", first, target.name); if let Err(code) = process( vec![format!("--{}", first), target.name] .into_iter() diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 51ab6aee3a4..d532d4e5a59 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -72,21 +72,3 @@ fn compile_test() { run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); } - -#[test] -fn dogfood() { - prepare_env(); - let files = ["src/main.rs", "src/driver.rs", "src/lib.rs", "clippy_lints/src/lib.rs"]; - let mut config = config("dogfood", "ui"); - config.target_rustcflags = config.target_rustcflags.map(|flags| format!("{} -Dclippy -Dclippy_pedantic -Dclippy_internal", flags)); - - for file in &files { - let paths = test::TestPaths { - base: PathBuf::new(), - file: PathBuf::from(file), - relative_dir: PathBuf::new(), - }; - - compiletest::runtest::run(config.clone(), &paths); - } -} diff --git a/tests/dogfood.rs b/tests/dogfood.rs new file mode 100644 index 00000000000..1514383e6de --- /dev/null +++ b/tests/dogfood.rs @@ -0,0 +1,17 @@ +#[test] +fn dogfood() { + let root_dir = std::env::current_dir().unwrap(); + for d in &[".", "clippy_lints"] { + std::env::set_current_dir(root_dir.join(d)).unwrap(); + let output = std::process::Command::new("cargo") + .arg("run") + .arg("--bin").arg("cargo-clippy") + .arg("--manifest-path").arg(root_dir.join("Cargo.toml")) + .output().unwrap(); + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); + } +} diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs new file mode 100644 index 00000000000..adc308626b1 --- /dev/null +++ b/tests/mut_mut_macro.rs @@ -0,0 +1,31 @@ + + +#![deny(mut_mut, zero_ptr, cmp_nan)] +#![allow(dead_code)] + +#[macro_use] +extern crate lazy_static; + +use std::collections::HashMap; + +// ensure that we don't suggest `is_nan` and `is_null` inside constants +// FIXME: once const fn is stable, suggest these functions again in constants +const BAA: *const i32 = 0 as *const i32; +static mut BAR: *const i32 = BAA; +static mut FOO: *const i32 = 0 as *const i32; +static mut BUH: bool = 42.0 < std::f32::NAN; + +#[allow(unused_variables, unused_mut)] +fn main() { + lazy_static! { + static ref MUT_MAP : HashMap<usize, &'static str> = { + let mut m = HashMap::new(); + m.insert(0, "zero"); + m + }; + static ref MUT_COUNT : usize = MUT_MAP.len(); + } + assert_eq!(*MUT_COUNT, 1); + // FIXME: don't lint in array length, requires `check_body` + //let _ = [""; (42.0 < std::f32::NAN) as usize]; +} diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs deleted file mode 100644 index adc308626b1..00000000000 --- a/tests/run-pass/mut_mut_macro.rs +++ /dev/null @@ -1,31 +0,0 @@ - - -#![deny(mut_mut, zero_ptr, cmp_nan)] -#![allow(dead_code)] - -#[macro_use] -extern crate lazy_static; - -use std::collections::HashMap; - -// ensure that we don't suggest `is_nan` and `is_null` inside constants -// FIXME: once const fn is stable, suggest these functions again in constants -const BAA: *const i32 = 0 as *const i32; -static mut BAR: *const i32 = BAA; -static mut FOO: *const i32 = 0 as *const i32; -static mut BUH: bool = 42.0 < std::f32::NAN; - -#[allow(unused_variables, unused_mut)] -fn main() { - lazy_static! { - static ref MUT_MAP : HashMap<usize, &'static str> = { - let mut m = HashMap::new(); - m.insert(0, "zero"); - m - }; - static ref MUT_COUNT : usize = MUT_MAP.len(); - } - assert_eq!(*MUT_COUNT, 1); - // FIXME: don't lint in array length, requires `check_body` - //let _ = [""; (42.0 < std::f32::NAN) as usize]; -} -- cgit 1.4.1-3-g733a5 From 3c4f5bfae23ea80e4a09e6887c94d14139106bdf Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Thu, 28 Dec 2017 17:34:11 +0530 Subject: Use rustc_driver::run (fixes #2303) This internally uses monitor() which catches panics and stuff --- src/driver.rs | 83 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 090e69cf027..bc766496cfb 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -12,7 +12,7 @@ extern crate rustc_plugin; extern crate syntax; use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc::session::{config, CompileIncomplete, Session}; +use rustc::session::{config, Session}; use rustc::session::config::{ErrorOutputType, Input}; use std::path::PathBuf; use std::process::Command; @@ -153,47 +153,44 @@ pub fn main() { }) .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - rustc_driver::in_rustc_thread(|| { - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programmatically, so we ignore this/ - let mut orig_args: Vec<String> = env::args().collect(); - if orig_args.len() <= 1 { - std::process::exit(1); - } - if orig_args[1] == "rustc" { - // we still want to be able to invoke it normally though - orig_args.remove(1); - } - // this conditional check for the --sysroot flag is there so users can call - // `clippy_driver` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() - } else { - orig_args - .clone() - .into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - - // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS") - .ok() - .map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=metadata"); - - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - } + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programmatically, so we ignore this/ + let mut orig_args: Vec<String> = env::args().collect(); + if orig_args.len() <= 1 { + std::process::exit(1); + } + if orig_args[1] == "rustc" { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args + .clone() + .into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS") + .ok() + .map_or(false, |val| val == "true") + || orig_args.iter().any(|s| s == "--emit=metadata"); + + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(CompileIncomplete::Errored(_)) = result { - std::process::exit(1); - } - }).expect("rustc_thread failed"); + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + rustc_driver::run(move || { + rustc_driver::run_compiler(&args, &mut ccc, None, None) + }); } -- cgit 1.4.1-3-g733a5 From 26f83d621889b2a7474cd0542c63c77a5a15c02e Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git1984941651981@oli-obk.de> Date: Wed, 17 Jan 2018 08:52:41 +0100 Subject: Readd the .exe extension on windows --- src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 8affe549348..8fd485b9efa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,9 +180,12 @@ where args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); - let path = std::env::current_exe() + let mut path = std::env::current_exe() .expect("current executable path invalid") .with_file_name("clippy-driver"); + if cfg!(windows) { + path.set_extension("exe"); + } let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) -- cgit 1.4.1-3-g733a5 From a2fec0e3e3a43554ea83977cb8d99f10cd56759d Mon Sep 17 00:00:00 2001 From: Seiichi Uchida <seuchida@gmail.com> Date: Mon, 22 Jan 2018 13:23:57 +0900 Subject: Rustup to rustc 1.25.0-nightly (97520ccb1 2018-01-21) --- src/driver.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index bc766496cfb..7e0a82188f9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -9,9 +9,11 @@ extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_plugin; +extern crate rustc_trans_utils; extern crate syntax; use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; +use rustc_trans_utils::trans_crate::TransCrate; use rustc::session::{config, Session}; use rustc::session::config::{ErrorOutputType, Input}; use std::path::PathBuf; @@ -58,6 +60,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { } fn late_callback( &mut self, + trans_crate: &TransCrate, matches: &getopts::Matches, sess: &Session, crate_stores: &rustc::middle::cstore::CrateStore, @@ -66,7 +69,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { ofile: &Option<PathBuf>, ) -> Compilation { self.default - .late_callback(matches, sess, crate_stores, input, odir, ofile) + .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { let mut control = self.default.build_controller(sess, matches); -- cgit 1.4.1-3-g733a5 From 42120141bd8e9684143dd61e6d37da8541a94d0f Mon Sep 17 00:00:00 2001 From: TomasKralCZ <tomas@kral.hk> Date: Sun, 11 Feb 2018 10:50:19 +0100 Subject: Suggestion fixed, simplified lint logic. --- clippy_lints/src/redundant_field_names.rs | 38 +++++++++++-------------------- src/driver.rs | 2 +- tests/ui/redundant_field_names.rs | 4 +++- tests/ui/redundant_field_names.stderr | 12 +++++----- 4 files changed, 23 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index d6164e21152..e4d113bd3de 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,9 +1,9 @@ use rustc::lint::*; use rustc::hir::*; -use utils::{span_lint_and_sugg}; +use utils::{span_lint_and_sugg, match_var}; -/// **What it does:** Checks for redundnat field names where shorthands -/// can be used. +/// **What it does:** Checks for fields in struct literals where shorthands +/// could be used. /// /// **Why is this bad?** If the field and variable names are the same, /// the field name is redundant. @@ -23,7 +23,7 @@ use utils::{span_lint_and_sugg}; declare_lint! { pub REDUNDANT_FIELD_NAMES, Warn, - "using same name for field and variable ,where shorthand can be used" + "checks for fields in struct literals where shorthands could be used" } pub struct RedundantFieldNames; @@ -39,28 +39,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantFieldNames { if let ExprStruct(_, ref fields, _) = expr.node { for field in fields { let name = field.name.node; - if let ExprPath(ref qpath) = field.expr.node { - if let &QPath::Resolved(_, ref path) = qpath { - let segments = &path.segments; - if segments.len() == 1 { - let expr_name = segments[0].name; - - if name == expr_name { - span_lint_and_sugg( - cx, - REDUNDANT_FIELD_NAMES, - path.span, - "redundant field names in struct initialization", - &format!( - "replace '{0}: {0}' with '{0}'", - name, - ), - "".to_string() - ); - } - } - } + if match_var(&field.expr, name) && !field.is_shorthand { + span_lint_and_sugg ( + cx, + REDUNDANT_FIELD_NAMES, + field.span, + "redundant field names in struct initialization", + "replace it with", + name.to_string() + ); } } } diff --git a/src/driver.rs b/src/driver.rs index 7e0a82188f9..7b7167cef70 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -29,7 +29,7 @@ impl ClippyCompilerCalls { fn new(run_lints: bool) -> Self { Self { default: RustcDefaultCalls, - run_lints: run_lints, + run_lints, } } } diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index d562fa44f83..0eb9bef45b5 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -8,7 +8,7 @@ mod foo { struct Person { gender: u8, age: u8, - + name: u8, buzz: u64, foo: u8, } @@ -17,11 +17,13 @@ fn main() { let gender: u8 = 42; let age = 0; let fizz: u64 = 0; + let name: u8 = 0; let me = Person { gender: gender, age: age, + name, //should be ok buzz: fizz, //should be ok foo: foo::BAR, //should be ok }; diff --git a/tests/ui/redundant_field_names.stderr b/tests/ui/redundant_field_names.stderr index 594282d2309..d6d752b93a3 100644 --- a/tests/ui/redundant_field_names.stderr +++ b/tests/ui/redundant_field_names.stderr @@ -1,16 +1,16 @@ error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:22:17 + --> $DIR/redundant_field_names.rs:23:9 | -22 | gender: gender, - | ^^^^^^ help: replace 'gender: gender' with 'gender' +23 | gender: gender, + | ^^^^^^^^^^^^^^ help: replace it with: `gender` | = note: `-D redundant-field-names` implied by `-D warnings` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:23:14 + --> $DIR/redundant_field_names.rs:24:9 | -23 | age: age, - | ^^^ help: replace 'age: age' with 'age' +24 | age: age, + | ^^^^^^^^ help: replace it with: `age` error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From 21f387d27810edd4ec135cc307dccc6d8e55d48b Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 13 Mar 2018 15:02:40 +0100 Subject: Update dependencies --- .gitignore | 1 + Cargo.toml | 3 +- clippy_lints/Cargo.toml | 10 ++--- clippy_lints/src/regex.rs | 109 ++++++++++++++++++++++++++++++---------------- src/main.rs | 8 ++-- tests/compile-test.rs | 2 +- tests/ui/regex.stderr | 64 +++++++++++++++------------ tests/versioncheck.rs | 4 +- 8 files changed, 123 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index 43552238725..6f472c418d2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ out Cargo.lock /target /clippy_lints/target +/clippy_workspace_tests/target # Generated by dogfood /target_recur/ diff --git a/Cargo.toml b/Cargo.toml index efaa00acd66..a256be6085b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,9 @@ path = "src/driver.rs" # begin automatic update clippy_lints = { version = "0.0.187", path = "clippy_lints" } # end automatic update -cargo_metadata = "0.2" +cargo_metadata = "0.5" regex = "0.2" +semver = "0.9" [dev-dependencies] compiletest_rs = "0.3.7" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index cee48c1514d..f8c93c9d7ed 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -16,18 +16,18 @@ license = "MPL-2.0" keywords = ["clippy", "lint", "plugin"] [dependencies] -itertools = "0.6.0" +itertools = "0.7" lazy_static = "1.0" matches = "0.1.2" quine-mc_cluskey = "0.2.2" -regex-syntax = "0.4.0" -semver = "0.6.0" +regex-syntax = "0.5.0" +semver = "0.9.0" serde = "1.0" serde_derive = "1.0" toml = "0.4" unicode-normalization = "0.1" -pulldown-cmark = "0.0.15" -url = "1.5.0" +pulldown-cmark = "0.1" +url = "1.7.0" if_chain = "0.1" [features] diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index bbb70e0cdea..f2c08944f50 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -6,7 +6,6 @@ use rustc::middle::const_val::ConstVal; use rustc_const_eval::ConstContext; use rustc::ty::subst::Substs; use std::collections::HashSet; -use std::error::Error; use syntax::ast::{LitKind, NodeId, StrStyle}; use syntax::codemap::{BytePos, Span}; use syntax::symbol::InternedString; @@ -134,16 +133,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -#[allow(cast_possible_truncation)] -fn str_span(base: Span, s: &str, c: usize) -> Span { - let mut si = s.char_indices().skip(c); - - match (si.next(), si.next()) { - (Some((l, _)), Some((h, _))) => { - Span::new(base.lo() + BytePos(l as u32), base.lo() + BytePos(h as u32), base.ctxt()) - }, - _ => base, - } +fn str_span(base: Span, c: regex_syntax::ast::Span, offset: usize) -> Span { + let offset = offset as u32; + let end = base.lo() + BytePos(c.end.offset as u32 + offset); + let start = base.lo() + BytePos(c.start.offset as u32 + offset); + assert!(start <= end); + Span::new(start, end, base.ctxt()) } fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<InternedString> { @@ -159,24 +154,30 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Inte } } -fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { - use regex_syntax::Expr; - - match *s { - Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"), - Expr::Literal { .. } => Some("consider using `str::contains`"), - Expr::Concat(ref exprs) => match exprs.len() { - 2 => match (&exprs[0], &exprs[1]) { - (&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"), - (&Expr::StartText, &Expr::Literal { .. }) => Some("consider using `str::starts_with`"), - (&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]) { - Some("consider using `==` on `str`s") - } else { - None - }, +fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { + use regex_syntax::hir::HirKind::*; + use regex_syntax::hir::Anchor::*; + + let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| match *e.kind() { + Literal(_) => true, + _ => false, + }); + + match *s.kind() { + Empty | + Anchor(_) => Some("the regex is unlikely to be useful as it is"), + Literal(_) => Some("consider using `str::contains`"), + Alternation(ref exprs) => if exprs.iter().all(|e| e.kind().is_empty()) { + Some("the regex is unlikely to be useful as it is") + } else { + None + }, + Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) { + (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => Some("consider using `str::is_empty`"), + (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => Some("consider using `==` on `str`s"), + (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"), + (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => Some("consider using `str::ends_with`"), + _ if is_literal(exprs) => Some("consider using `str::contains`"), _ => None, }, _ => None, @@ -196,41 +197,73 @@ fn check_set<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: bool) } fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: bool) { - let builder = regex_syntax::ExprBuilder::new().unicode(utf8); + let mut parser = regex_syntax::ParserBuilder::new().unicode(utf8).build(); if let ExprLit(ref lit) = expr.node { if let LitKind::Str(ref r, style) = lit.node { let r = &r.as_str(); - let offset = if let StrStyle::Raw(n) = style { 1 + n } else { 0 }; - match builder.parse(r) { + let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 }; + match parser.parse(r) { Ok(r) => if let Some(repl) = is_trivial_regex(&r) { span_help_and_lint( cx, TRIVIAL_REGEX, expr.span, "trivial regex", - &format!("consider using {}", repl), + repl, + ); + }, + Err(regex_syntax::Error::Parse(e)) => { + span_lint( + cx, + INVALID_REGEX, + str_span(expr.span, *e.span(), offset), + &format!("regex syntax error: {}", e.kind()), + ); + }, + Err(regex_syntax::Error::Translate(e)) => { + span_lint( + cx, + INVALID_REGEX, + str_span(expr.span, *e.span(), offset), + &format!("regex syntax error: {}", e.kind()), ); }, Err(e) => { span_lint( cx, INVALID_REGEX, - str_span(expr.span, r, e.position() + offset), - &format!("regex syntax error: {}", e.description()), + expr.span, + &format!("regex syntax error: {}", e), ); }, } } } else if let Some(r) = const_str(cx, expr) { - match builder.parse(&r) { + match parser.parse(&r) { Ok(r) => if let Some(repl) = is_trivial_regex(&r) { span_help_and_lint( cx, TRIVIAL_REGEX, expr.span, "trivial regex", - &format!("consider using {}", repl), + repl, + ); + }, + Err(regex_syntax::Error::Parse(e)) => { + span_lint( + cx, + INVALID_REGEX, + expr.span, + &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()), + ); + }, + Err(regex_syntax::Error::Translate(e)) => { + span_lint( + cx, + INVALID_REGEX, + expr.span, + &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()), ); }, Err(e) => { @@ -238,7 +271,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: boo cx, INVALID_REGEX, expr.span, - &format!("regex syntax error on position {}: {}", e.position(), e.description()), + &format!("regex syntax error: {}", e), ); }, } diff --git a/src/main.rs b/src/main.rs index 8fd485b9efa..ab2b3b9a4a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use std::io::{self, Write}; extern crate cargo_metadata; -use std::path::Path; +use std::path::{Path, PathBuf}; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -61,17 +61,19 @@ pub fn main() { let manifest_path_arg = std::env::args() .skip(2) - .find(|val| val.starts_with("--manifest-path=")); + .find(|val| val.starts_with("--manifest-path=")) + .map(|val| val["--manifest-path=".len()..].to_owned()); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata } else { + println!("{:?}", cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))); let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); process::exit(101); }; let manifest_path = manifest_path_arg.map(|arg| { - Path::new(&arg["--manifest-path=".len()..]) + PathBuf::from(arg) .canonicalize() .expect("manifest path could not be canonicalized") }); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 5bf1bd5d13b..5e059084da8 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -68,7 +68,7 @@ fn run_mode(dir: &'static str, mode: &'static str) { fn prepare_env() { set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); set_var("CLIPPY_TESTS", "true"); - set_var("RUST_BACKTRACE", "0"); + //set_var("RUST_BACKTRACE", "0"); } #[test] diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 58c6e47afb7..45b2b7a2280 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -1,60 +1,67 @@ -error: regex syntax error: empty alternate +error: trivial regex --> $DIR/regex.rs:16:45 | 16 | let pipe_in_wrong_position = Regex::new("|"); | ^^^ | - = note: `-D invalid-regex` implied by `-D warnings` + = note: `-D trivial-regex` implied by `-D warnings` + = help: the regex is unlikely to be useful as it is -error: regex syntax error: empty alternate +error: trivial regex --> $DIR/regex.rs:17:60 | 17 | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); | ^^^ + | + = help: the regex is unlikely to be useful as it is -error: regex syntax error: invalid character class range - --> $DIR/regex.rs:18:40 +error: regex syntax error: invalid character class range, the start must be <= the end + --> $DIR/regex.rs:18:42 | 18 | let wrong_char_ranice = Regex::new("[z-a]"); - | ^^^^^^^ + | ^^^ + | + = note: `-D invalid-regex` implied by `-D warnings` -error: regex syntax error: invalid character class range - --> $DIR/regex.rs:19:35 +error: regex syntax error: invalid character class range, the start must be <= the end + --> $DIR/regex.rs:19:37 | 19 | let some_unicode = Regex::new("[é-è]"); - | ^^^^^^^ + | ^^^ -error: regex syntax error on position 0: unclosed parenthesis +error: regex syntax error on position 0: unclosed group --> $DIR/regex.rs:21:33 | 21 | let some_regex = Regex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ -error: regex syntax error: empty alternate +error: trivial regex --> $DIR/regex.rs:23:53 | 23 | let binary_pipe_in_wrong_position = BRegex::new("|"); | ^^^ + | + = help: the regex is unlikely to be useful as it is -error: regex syntax error on position 0: unclosed parenthesis +error: regex syntax error on position 0: unclosed group --> $DIR/regex.rs:24:41 | 24 | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed parenthesis +error: regex syntax error on position 0: unclosed group --> $DIR/regex.rs:25:56 | 25 | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed parenthesis +error: regex syntax error on position 0: unclosed group --> $DIR/regex.rs:40:9 | 40 | OPENING_PAREN, | ^^^^^^^^^^^^^ -error: regex syntax error on position 0: unclosed parenthesis +error: regex syntax error on position 0: unclosed group --> $DIR/regex.rs:44:9 | 44 | OPENING_PAREN, @@ -64,13 +71,13 @@ error: regex syntax error: unrecognized escape sequence --> $DIR/regex.rs:48:45 | 48 | let raw_string_error = Regex::new(r"[...//...]"); - | ^ + | ^^ error: regex syntax error: unrecognized escape sequence --> $DIR/regex.rs:49:46 | 49 | let raw_string_error = Regex::new(r#"[...//...]"#); - | ^ + | ^^ error: trivial regex --> $DIR/regex.rs:53:33 @@ -78,8 +85,7 @@ error: trivial regex 53 | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ | - = note: `-D trivial-regex` implied by `-D warnings` - = help: consider using consider using `==` on `str`s + = help: consider using `==` on `str`s error: trivial regex --> $DIR/regex.rs:55:48 @@ -87,7 +93,7 @@ error: trivial regex 55 | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ | - = help: consider using consider using `==` on `str`s + = help: consider using `==` on `str`s error: trivial regex --> $DIR/regex.rs:57:42 @@ -95,7 +101,7 @@ error: trivial regex 57 | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ | - = help: consider using consider using `str::starts_with` + = help: consider using `str::starts_with` error: trivial regex --> $DIR/regex.rs:59:40 @@ -103,7 +109,7 @@ error: trivial regex 59 | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ | - = help: consider using consider using `str::ends_with` + = help: consider using `str::ends_with` error: trivial regex --> $DIR/regex.rs:61:39 @@ -111,7 +117,7 @@ error: trivial regex 61 | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ | - = help: consider using consider using `str::contains` + = help: consider using `str::contains` error: trivial regex --> $DIR/regex.rs:63:39 @@ -119,7 +125,7 @@ error: trivial regex 63 | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ | - = help: consider using consider using `str::contains` + = help: consider using `str::contains` error: trivial regex --> $DIR/regex.rs:65:40 @@ -127,7 +133,7 @@ error: trivial regex 65 | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ | - = help: consider using consider using `str::contains` + = help: consider using `str::contains` error: trivial regex --> $DIR/regex.rs:68:36 @@ -135,7 +141,7 @@ error: trivial regex 68 | let trivial_empty = Regex::new(""); | ^^ | - = help: consider using the regex is unlikely to be useful as it is + = help: the regex is unlikely to be useful as it is error: trivial regex --> $DIR/regex.rs:70:36 @@ -143,7 +149,7 @@ error: trivial regex 70 | let trivial_empty = Regex::new("^"); | ^^^ | - = help: consider using the regex is unlikely to be useful as it is + = help: the regex is unlikely to be useful as it is error: trivial regex --> $DIR/regex.rs:72:36 @@ -151,7 +157,7 @@ error: trivial regex 72 | let trivial_empty = Regex::new("^$"); | ^^^^ | - = help: consider using consider using `str::is_empty` + = help: consider using `str::is_empty` error: trivial regex --> $DIR/regex.rs:74:44 @@ -159,7 +165,7 @@ error: trivial regex 74 | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | - = help: consider using consider using `str::is_empty` + = help: consider using `str::is_empty` error: aborting due to 23 previous errors diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index beea9ab7e64..6fe82ac792e 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -1,4 +1,6 @@ extern crate cargo_metadata; +extern crate semver; +use semver::VersionReq; #[test] fn check_that_clippy_lints_has_the_same_version_as_clippy() { @@ -8,7 +10,7 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() { assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { - assert_eq!(clippy_lints_meta.packages[0].version, package.req[1..]); + assert_eq!(VersionReq::parse(&clippy_lints_meta.packages[0].version).unwrap(), package.req); return; } } -- cgit 1.4.1-3-g733a5 From 23bfa396a05564fb8e16db26bf5eb3c8d7e909b8 Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <mati865@gmail.com> Date: Thu, 15 Mar 2018 16:08:49 +0100 Subject: Format code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mateusz Mikuła <mati865@gmail.com> --- src/driver.rs | 4 +--- src/main.rs | 5 ++++- tests/compile-test.rs | 7 +++++-- tests/dogfood.rs | 9 ++++++--- tests/matches.rs | 13 +++++++------ tests/needless_continue_helpers.rs | 1 - tests/versioncheck.rs | 10 ++++++++-- 7 files changed, 31 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 7b7167cef70..78bccb74ab9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -193,7 +193,5 @@ pub fn main() { } let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - rustc_driver::run(move || { - rustc_driver::run_compiler(&args, &mut ccc, None, None) - }); + rustc_driver::run(move || rustc_driver::run_compiler(&args, &mut ccc, None, None)); } diff --git a/src/main.rs b/src/main.rs index ab2b3b9a4a0..95e1fc0c28c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,7 +67,10 @@ pub fn main() { let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata } else { - println!("{:?}", cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))); + println!( + "{:?}", + cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) + ); let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); process::exit(101); }; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 5e059084da8..9b9820f2b52 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -3,7 +3,7 @@ extern crate compiletest_rs as compiletest; extern crate test; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use std::env::{set_var, var}; fn clippy_driver_path() -> PathBuf { @@ -43,7 +43,10 @@ fn config(dir: &'static str, mode: &'static str) -> compiletest::Config { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display())); + config.target_rustcflags = Some(format!( + "-L {0} -L {0}/deps -Dwarnings", + host_libs().display() + )); config.mode = cfg_mode; config.build_base = if rustc_test_suite().is_some() { diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 590027f8491..ed6451a3eb6 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -11,9 +11,12 @@ fn dogfood() { std::env::set_current_dir(root_dir.join(d)).unwrap(); let output = std::process::Command::new("cargo") .arg("run") - .arg("--bin").arg("cargo-clippy") - .arg("--manifest-path").arg(root_dir.join("Cargo.toml")) - .output().unwrap(); + .arg("--bin") + .arg("cargo-clippy") + .arg("--manifest-path") + .arg(root_dir.join("Cargo.toml")) + .output() + .unwrap(); println!("status: {}", output.status); println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); diff --git a/tests/matches.rs b/tests/matches.rs index 42d1154bf1a..8dfb8e42d6f 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -9,16 +9,17 @@ fn test_overlapping() { use clippy_lints::matches::overlapping; use syntax::codemap::DUMMY_SP; - let sp = |s, e| { - clippy_lints::matches::SpannedRange { - span: DUMMY_SP, - node: (s, e), - } + let sp = |s, e| clippy_lints::matches::SpannedRange { + span: DUMMY_SP, + node: (s, e), }; assert_eq!(None, overlapping::<u8>(&[])); assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))])); - assert_eq!(None, overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])); + assert_eq!( + None, + overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))]) + ); assert_eq!( None, overlapping(&[ diff --git a/tests/needless_continue_helpers.rs b/tests/needless_continue_helpers.rs index 853f64b4698..588dc741d03 100644 --- a/tests/needless_continue_helpers.rs +++ b/tests/needless_continue_helpers.rs @@ -69,7 +69,6 @@ fn test_erode_from_front_no_brace() { assert_eq!(expected, got); } - #[test] #[cfg_attr(rustfmt, rustfmt_skip)] fn test_erode_block() { diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 6fe82ac792e..ff4af08a8a0 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -7,10 +7,16 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() { let clippy_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); let clippy_lints_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); - assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); + assert_eq!( + clippy_lints_meta.packages[0].version, + clippy_meta.packages[0].version + ); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { - assert_eq!(VersionReq::parse(&clippy_lints_meta.packages[0].version).unwrap(), package.req); + assert_eq!( + VersionReq::parse(&clippy_lints_meta.packages[0].version).unwrap(), + package.req + ); return; } } -- cgit 1.4.1-3-g733a5 From 47a706682cb5fd47b61fd8451c1a781c4f16c81e Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 19 Mar 2018 09:26:05 +0100 Subject: Version bump --- CHANGELOG.md | 3 +++ Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- src/main.rs | 16 ++++++++++++---- 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 970b458e2a8..452a08f6ed4 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.189 +* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)* + ## 0.0.188 * Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)* * New lint: [`while_immutable_condition`] diff --git a/Cargo.toml b/Cargo.toml index 09eb34bf5fd..65714e60746 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.188" +version = "0.0.189" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", @@ -37,7 +37,7 @@ path = "src/driver.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.188", path = "clippy_lints" } +clippy_lints = { version = "0.0.189", path = "clippy_lints" } # end automatic update cargo_metadata = "0.5" regex = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 38b4a0ea18c..8a155957ed2 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.188" +version = "0.0.189" # end automatic update authors = [ "Manish Goregaokar <manishsmail@gmail.com>", diff --git a/src/main.rs b/src/main.rs index 95e1fc0c28c..81933d5769a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,10 +59,18 @@ pub fn main() { return; } - let manifest_path_arg = std::env::args() + let mut manifest_path_arg = std::env::args() .skip(2) - .find(|val| val.starts_with("--manifest-path=")) - .map(|val| val["--manifest-path=".len()..].to_owned()); + .skip_while(|val| !val.starts_with("--manifest-path")); + let manifest_path_arg = manifest_path_arg.next().and_then(|val| { + if val == "--manifest-path" { + manifest_path_arg.next() + } else if val.starts_with("--manifest-path=") { + Some(val["--manifest-path=".len()..].to_owned()) + } else { + None + } + }); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata @@ -140,7 +148,7 @@ pub fn main() { for target in package.targets { let args = std::env::args() - .skip(2) + .skip(1) .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); -- cgit 1.4.1-3-g733a5 From bef1afac5b4e0c36c335fc804aebb8de00f3cff5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <oli-obk@users.noreply.github.com> Date: Sun, 25 Mar 2018 08:52:00 +0200 Subject: Undo a temporary fix for a cargo bug Fixes #2566 --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 81933d5769a..ff75388030e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -148,7 +148,7 @@ pub fn main() { for target in package.targets { let args = std::env::args() - .skip(1) + .skip(2) .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); -- cgit 1.4.1-3-g733a5 From 96d5af36f87c9b4ca09a9aec4a49154404264501 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de> Date: Tue, 27 Mar 2018 12:14:46 +0200 Subject: Version bump --- CHANGELOG.md | 3 +++ Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/utils/conf.rs | 2 +- src/main.rs | 6 +++--- 5 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 452a08f6ed4..f8c91e6903d 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.190 +* Fix a bunch of intermittent cargo bugs + ## 0.0.189 * Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)* diff --git a/Cargo.toml b/Cargo.toml index 65714e60746..24b3ff975b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.189" +version = "0.0.190" authors = [ "Manish Goregaokar <manishsmail@gmail.com>", "Andre Bogus <bogusandre@gmail.com>", @@ -37,7 +37,7 @@ path = "src/driver.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.189", path = "clippy_lints" } +clippy_lints = { version = "0.0.190", path = "clippy_lints" } # end automatic update cargo_metadata = "0.5" regex = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 8a155957ed2..e8d08082d4d 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.189" +version = "0.0.190" # end automatic update authors = [ "Manish Goregaokar <manishsmail@gmail.com>", diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 9f40713f6e4..58e71705011 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -186,7 +186,7 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> { /// Possible filename to search for. const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; - let mut current = try!(env::current_dir()); + let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set")); loop { for config_file_name in &CONFIG_FILE_NAMES { diff --git a/src/main.rs b/src/main.rs index ff75388030e..e5d78c35d0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,10 +115,10 @@ pub fn main() { }) .collect(); - let current_dir = std::env::current_dir() - .expect("could not read current directory") + let current_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR") + .expect("CARGO_MANIFEST_DIR not set")) .canonicalize() - .expect("current directory cannot be canonicalized"); + .expect("manifest directory cannot be canonicalized"); let mut current_path: &Path = ¤t_dir; -- cgit 1.4.1-3-g733a5 From 9b10c4be8cb5850fbb52b55f876e9095ca61e088 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de> Date: Tue, 27 Mar 2018 13:00:02 +0200 Subject: Undo current_dir -> CARGO_MANIFEST_DIR move --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index e5d78c35d0b..98201af7e27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,8 +115,8 @@ pub fn main() { }) .collect(); - let current_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR") - .expect("CARGO_MANIFEST_DIR not set")) + let current_dir = std::env::current_dir() + .expect("CARGO_MANIFEST_DIR not set") .canonicalize() .expect("manifest directory cannot be canonicalized"); -- cgit 1.4.1-3-g733a5 From 66a98d2658997ad8ede2939e68222bd4df626718 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de> Date: Wed, 28 Mar 2018 11:50:17 +0200 Subject: Use cargo check instead of cargo rustc --- src/driver.rs | 5 ++++- src/main.rs | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 78bccb74ab9..73746798601 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -186,10 +186,13 @@ pub fn main() { let clippy_enabled = env::var("CLIPPY_TESTS") .ok() .map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=metadata"); + || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + if let Ok(extra_args) = env::var("CLIPPY_ARGS") { + args.extend(extra_args.split("__CLIPPY_HACKERY__").filter(|s| !s.is_empty()).map(str::to_owned)); + } } let mut ccc = ClippyCompilerCalls::new(clippy_enabled); diff --git a/src/main.rs b/src/main.rs index 98201af7e27..598d129dec2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -175,23 +175,22 @@ pub fn main() { } } -fn process<I>(old_args: I) -> Result<(), i32> +fn process<I>(mut old_args: I) -> Result<(), i32> where I: Iterator<Item = String>, { - let mut args = vec!["rustc".to_owned()]; + let mut args = vec!["check".to_owned()]; let mut found_dashes = false; - for arg in old_args { + for arg in old_args.by_ref() { found_dashes |= arg == "--"; + if found_dashes { + break; + } args.push(arg); } - if !found_dashes { - args.push("--".to_owned()); - } - args.push("--emit=metadata".to_owned()); - args.push("--cfg".to_owned()); - args.push(r#"feature="cargo-clippy""#.to_owned()); + + let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect(); let mut path = std::env::current_exe() .expect("current executable path invalid") @@ -202,6 +201,7 @@ where let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) + .env("CLIPPY_ARGS", clippy_args) .spawn() .expect("could not run cargo") .wait() -- cgit 1.4.1-3-g733a5 From 8db845c189ebce88f4f29d426fb6cb6ae8478b64 Mon Sep 17 00:00:00 2001 From: Benjamin Gill <git@bgill.eu> Date: Wed, 28 Mar 2018 23:17:48 +0100 Subject: Delete all code for handling manifest path Now that we're using cargo check, we can stop needing to find out the manifest path ourselves. Instead, we can delegate to cargo check, which is perfectly capable of working out for itself what needs to be built. This fixes #1707 and #2518. Note that this PR will change the output. We will no longer output `bin: foo` before each crate. This a bit unfortunate. However, given that we're now going to be building in parallel (which is *much* faster), I think this is acceptable - we'll be no worse than cargo itself. --- Cargo.toml | 2 +- src/main.rs | 127 ++---------------------------------------------------------- 2 files changed, 4 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 24b3ff975b1..a28e5c50929 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,11 @@ path = "src/driver.rs" # begin automatic update clippy_lints = { version = "0.0.190", path = "clippy_lints" } # end automatic update -cargo_metadata = "0.5" regex = "0.2" semver = "0.9" [dev-dependencies] +cargo_metadata = "0.5" compiletest_rs = "0.3.7" lazy_static = "1.0" serde_derive = "1.0" diff --git a/src/main.rs b/src/main.rs index 598d129dec2..5bdbaf1bc80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,14 +3,6 @@ #![feature(rustc_private)] #![allow(unknown_lints, missing_docs_in_private_items)] -use std::collections::HashMap; -use std::process; -use std::io::{self, Write}; - -extern crate cargo_metadata; - -use std::path::{Path, PathBuf}; - const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. Usage: @@ -18,11 +10,9 @@ Usage: Common options: -h, --help Print this message - --features Features to compile for the package -V, --version Print version info and exit - --all Run over all packages in the current workspace -Other options are the same as `cargo rustc`. +Other options are the same as `cargo check`. To allow or deny a lint from the command line you can use `cargo clippy --` with: @@ -59,119 +49,8 @@ pub fn main() { return; } - let mut manifest_path_arg = std::env::args() - .skip(2) - .skip_while(|val| !val.starts_with("--manifest-path")); - let manifest_path_arg = manifest_path_arg.next().and_then(|val| { - if val == "--manifest-path" { - manifest_path_arg.next() - } else if val.starts_with("--manifest-path=") { - Some(val["--manifest-path=".len()..].to_owned()) - } else { - None - } - }); - - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { - metadata - } else { - println!( - "{:?}", - cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) - ); - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); - process::exit(101); - }; - - let manifest_path = manifest_path_arg.map(|arg| { - PathBuf::from(arg) - .canonicalize() - .expect("manifest path could not be canonicalized") - }); - - let packages = if std::env::args().any(|a| a == "--all") { - metadata.packages - } else { - let package_index = { - if let Some(manifest_path) = manifest_path { - metadata.packages.iter().position(|package| { - let package_manifest_path = Path::new(&package.manifest_path) - .canonicalize() - .expect("package manifest path could not be canonicalized"); - package_manifest_path == manifest_path - }) - } else { - let package_manifest_paths: HashMap<_, _> = metadata - .packages - .iter() - .enumerate() - .map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path) - .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - (package_manifest_path, i) - }) - .collect(); - - let current_dir = std::env::current_dir() - .expect("CARGO_MANIFEST_DIR not set") - .canonicalize() - .expect("manifest directory cannot be canonicalized"); - - let mut current_path: &Path = ¤t_dir; - - // This gets the most-recent parent (the one that takes the fewest `cd ..`s to - // reach). - loop { - if let Some(&package_index) = package_manifest_paths.get(current_path) { - break Some(package_index); - } else { - // We'll never reach the filesystem root, because to get to this point in the - // code - // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to - // unwrap the current path's parent. - current_path = current_path - .parent() - .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); - } - } - } - }.expect("could not find matching package"); - - vec![metadata.packages.remove(package_index)] - }; - - for package in packages { - let manifest_path = package.manifest_path; - - for target in package.targets { - let args = std::env::args() - .skip(2) - .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); - - let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); - if let Some(first) = target.kind.get(0) { - if target.kind.len() > 1 || first.ends_with("lib") { - println!("lib: {}", target.name); - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { - std::process::exit(code); - } - } else if ["bin", "example", "test", "bench"].contains(&&**first) { - println!("{}: {}", first, target.name); - if let Err(code) = process( - vec![format!("--{}", first), target.name] - .into_iter() - .chain(args), - ) { - std::process::exit(code); - } - } - } else { - panic!("badly formatted cargo metadata: target::kind is an empty array"); - } - } + if let Err(code) = process(std::env::args().skip(2)) { + std::process::exit(code); } } -- cgit 1.4.1-3-g733a5 From 1ab96db7915f36bae5e1ad645861ef910b79904d Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Sun, 1 Apr 2018 09:28:53 +0200 Subject: Make dogfood test output to seperate directory This commit makes `cargo clippy` output the build artifacts to a separate directory if the `CLIPPY_DOGFOOD` env var is set. This should prevent dogfood builds from interfering with regular builds. This should help with issue #2595. --- src/main.rs | 17 +++++++++++++++++ tests/dogfood.rs | 1 + 2 files changed, 18 insertions(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 5bdbaf1bc80..0baeab7338e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,10 +77,27 @@ where if cfg!(windows) { path.set_extension("exe"); } + + let mut extra_envs = vec![]; + if let Ok(_) = std::env::var("CLIPPY_DOGFOOD") { + let target_dir = std::env::var("CARGO_MANIFEST_DIR") + .map(|m| { + std::path::PathBuf::from(m) + .join("target") + .join("dogfood") + .to_string_lossy() + .into_owned() + }) + .unwrap_or("clippy_dogfood".to_string()); + + extra_envs.push(("CARGO_TARGET_DIR", target_dir)); + }; + let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) .env("CLIPPY_ARGS", clippy_args) + .envs(extra_envs) .spawn() .expect("could not run cargo") .wait() diff --git a/tests/dogfood.rs b/tests/dogfood.rs index ed6451a3eb6..a2d4da9a1ca 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -15,6 +15,7 @@ fn dogfood() { .arg("cargo-clippy") .arg("--manifest-path") .arg(root_dir.join("Cargo.toml")) + .env("CLIPPY_DOGFOOD", "true") .output() .unwrap(); println!("status: {}", output.status); -- cgit 1.4.1-3-g733a5 From 609dd47410cac010a9a73e96a4b7237793d73ad5 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Sun, 1 Apr 2018 10:17:48 +0200 Subject: Fix clippy warnings from last commit --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 0baeab7338e..5cc6fd674eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,7 +79,7 @@ where } let mut extra_envs = vec![]; - if let Ok(_) = std::env::var("CLIPPY_DOGFOOD") { + if std::env::var("CLIPPY_DOGFOOD").is_ok() { let target_dir = std::env::var("CARGO_MANIFEST_DIR") .map(|m| { std::path::PathBuf::from(m) @@ -88,7 +88,7 @@ where .to_string_lossy() .into_owned() }) - .unwrap_or("clippy_dogfood".to_string()); + .unwrap_or_else(|_| "clippy_dogfood".to_string()); extra_envs.push(("CARGO_TARGET_DIR", target_dir)); }; -- cgit 1.4.1-3-g733a5 From add4434ee37d8ee87df63852cf86f02d4c3992a1 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Mon, 2 Apr 2018 09:28:08 +0200 Subject: Support non-unicode paths for dogfood test --- src/main.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 5cc6fd674eb..aac5e97f311 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,26 +78,29 @@ where path.set_extension("exe"); } - let mut extra_envs = vec![]; - if std::env::var("CLIPPY_DOGFOOD").is_ok() { - let target_dir = std::env::var("CARGO_MANIFEST_DIR") - .map(|m| { - std::path::PathBuf::from(m) - .join("target") - .join("dogfood") - .to_string_lossy() - .into_owned() - }) - .unwrap_or_else(|_| "clippy_dogfood".to_string()); - - extra_envs.push(("CARGO_TARGET_DIR", target_dir)); - }; + let target_dir = std::env::var_os("CLIPPY_DOGFOOD") + .map(|_| { + std::env::var_os("CARGO_MANIFEST_DIR").map_or_else( + || { + let mut fallback = std::ffi::OsString::new(); + fallback.push("clippy_dogfood"); + fallback + }, + |d| { + std::path::PathBuf::from(d) + .join("target") + .join("dogfood") + .into_os_string() + }, + ) + }) + .map(|p| ("CARGO_TARGET_DIR", p)); let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) .env("CLIPPY_ARGS", clippy_args) - .envs(extra_envs) + .envs(target_dir) .spawn() .expect("could not run cargo") .wait() -- cgit 1.4.1-3-g733a5 From a8bb8925cbb8a3374e5a58dc988e7010583a6e91 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Wed, 4 Apr 2018 07:08:35 +0200 Subject: Fix clippy warning --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index aac5e97f311..057a585e3d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ fn show_help() { #[allow(print_stdout)] fn show_version() { - println!("{}", env!("CARGO_PKG_VERSION")); + println!(env!("CARGO_PKG_VERSION")); } pub fn main() { -- cgit 1.4.1-3-g733a5 From ab281184497fcf79508e6c19c4214f8ebada20cb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 4 Apr 2018 18:56:21 -0700 Subject: Fix driver dogfood bug --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 73746798601..711b2e6fbd9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -126,7 +126,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { #[allow(print_stdout)] fn show_version() { - println!("{}", env!("CARGO_PKG_VERSION")); + println!(env!("CARGO_PKG_VERSION"); } pub fn main() { -- cgit 1.4.1-3-g733a5 From 399488079b1930c7cb9a779230d6e87e07f686da Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Wed, 4 Apr 2018 19:15:21 -0700 Subject: argh --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 711b2e6fbd9..4e3852d416a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -126,7 +126,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { #[allow(print_stdout)] fn show_version() { - println!(env!("CARGO_PKG_VERSION"); + println!(env!("CARGO_PKG_VERSION")); } pub fn main() { -- cgit 1.4.1-3-g733a5 From a854874e6a089f67a658a4f5bb4b0d7150535573 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Wed, 18 Apr 2018 20:25:43 +0200 Subject: Fix latest nightly breakage I'm not sure if there are better ways to use the RwLock API, though. But it seems to work. --- clippy_lints/src/loops.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index cfef1e85b94..515bd8976b9 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1798,7 +1798,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { fn is_iterable_array(ty: Ty) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { - ty::TyArray(_, n) => (0..=32).contains(n.val.to_raw_bits().expect("array length")), + ty::TyArray(_, n) => (0..=32).contains(&n.val.to_raw_bits().expect("array length")), _ => false, } } diff --git a/src/lib.rs b/src/lib.rs index 8f0c6a63207..f8682884a50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ extern crate clippy_lints; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - if let Ok(lint_store) = reg.sess.lint_store.try_borrow() { + reg.sess.lint_store.with_read_lock(|lint_store| { for (lint, _, _) in lint_store.get_lint_groups() { if lint == "clippy" { reg.sess @@ -21,7 +21,7 @@ pub fn plugin_registrar(reg: &mut Registry) { return; } } - } + }); clippy_lints::register_plugins(reg); } -- cgit 1.4.1-3-g733a5 From fd8a1d20ccad8a2dd7b95a9a9a6fe94048a74d5f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de> Date: Fri, 11 May 2018 13:20:39 +0200 Subject: Remove all mention and testing of #[plugin(clippy)] and warn if used --- CONTRIBUTING.md | 8 +----- README.md | 2 +- src/lib.rs | 7 +++-- tests/auxiliary/conf_french_blacklisted_name.toml | 1 - tests/auxiliary/conf_unknown_key.toml | 6 ---- tests/auxiliary/conf_whitelisted.toml | 3 -- tests/cc_seme.rs | 28 ------------------- tests/conf_whitelisted.rs | 2 -- tests/ice_exacte_size.rs | 17 ------------ tests/issue-825.rs | 15 ---------- tests/mut_mut_macro.rs | 31 --------------------- tests/run-pass/cc_seme.rs | 27 ++++++++++++++++++ tests/run-pass/ice_exacte_size.rs | 17 ++++++++++++ tests/run-pass/issue-825.rs | 13 +++++++++ tests/run-pass/mut_mut_macro.rs | 32 ++++++++++++++++++++++ tests/run-pass/used_underscore_binding_macro.rs | 20 ++++++++++++++ tests/run-pass/whitelist/clippy.toml | 3 ++ tests/run-pass/whitelist/conf_whitelisted.rs | 1 + tests/ui/bad_toml/clippy.toml | 2 ++ tests/ui/bad_toml/conf_bad_toml.rs | 6 ++++ tests/ui/bad_toml/conf_bad_toml.stderr | 0 tests/ui/bad_toml_type/clippy.toml | 1 + tests/ui/bad_toml_type/conf_bad_type.rs | 6 ++++ tests/ui/bad_toml_type/conf_bad_type.stderr | 0 tests/ui/conf_bad_arg.rs | 6 ---- tests/ui/conf_bad_arg.stderr | 11 -------- tests/ui/conf_bad_toml.rs | 6 ---- tests/ui/conf_bad_toml.stderr | 11 -------- tests/ui/conf_bad_toml.toml | 2 -- tests/ui/conf_bad_type.rs | 6 ---- tests/ui/conf_bad_type.stderr | 11 -------- tests/ui/conf_bad_type.toml | 1 - tests/ui/conf_french_blacklisted_name.rs | 23 ---------------- tests/ui/conf_french_blacklisted_name.stderr | 11 -------- tests/ui/conf_path_non_string.rs | 5 ---- tests/ui/conf_path_non_string.stderr | 11 -------- tests/ui/conf_unknown_key.rs | 6 ---- tests/ui/conf_unknown_key.stderr | 11 -------- tests/ui/cyclomatic_complexity.rs | 2 +- tests/ui/cyclomatic_complexity_attr_used.rs | 2 +- tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/dlist.rs | 2 +- tests/ui/enum_variants.rs | 2 +- tests/ui/escape_analysis.rs | 2 +- tests/ui/excessive_precision.rs | 2 +- tests/ui/for_loop.rs | 2 +- tests/ui/mut_mut.rs | 4 +-- tests/ui/new_without_default.rs | 2 +- tests/ui/no_effect.rs | 2 +- tests/ui/toml_blacklist/clippy.toml | 1 + .../toml_blacklist/conf_french_blacklisted_name.rs | 23 ++++++++++++++++ .../conf_french_blacklisted_name.stderr | 0 tests/ui/toml_unknown_key/clippy.toml | 6 ++++ tests/ui/toml_unknown_key/conf_unknown_key.rs | 6 ++++ tests/ui/toml_unknown_key/conf_unknown_key.stderr | 0 tests/ui/trailing_zeros.rs | 2 +- tests/used_underscore_binding_macro.rs | 18 ------------ 57 files changed, 183 insertions(+), 266 deletions(-) delete mode 100644 tests/auxiliary/conf_french_blacklisted_name.toml delete mode 100644 tests/auxiliary/conf_unknown_key.toml delete mode 100644 tests/auxiliary/conf_whitelisted.toml delete mode 100644 tests/cc_seme.rs delete mode 100644 tests/conf_whitelisted.rs delete mode 100644 tests/ice_exacte_size.rs delete mode 100644 tests/issue-825.rs delete mode 100644 tests/mut_mut_macro.rs create mode 100644 tests/run-pass/cc_seme.rs create mode 100644 tests/run-pass/ice_exacte_size.rs create mode 100644 tests/run-pass/issue-825.rs create mode 100644 tests/run-pass/mut_mut_macro.rs create mode 100644 tests/run-pass/used_underscore_binding_macro.rs create mode 100644 tests/run-pass/whitelist/clippy.toml create mode 100644 tests/run-pass/whitelist/conf_whitelisted.rs create mode 100644 tests/ui/bad_toml/clippy.toml create mode 100644 tests/ui/bad_toml/conf_bad_toml.rs create mode 100644 tests/ui/bad_toml/conf_bad_toml.stderr create mode 100644 tests/ui/bad_toml_type/clippy.toml create mode 100644 tests/ui/bad_toml_type/conf_bad_type.rs create mode 100644 tests/ui/bad_toml_type/conf_bad_type.stderr delete mode 100644 tests/ui/conf_bad_arg.rs delete mode 100644 tests/ui/conf_bad_arg.stderr delete mode 100644 tests/ui/conf_bad_toml.rs delete mode 100644 tests/ui/conf_bad_toml.stderr delete mode 100644 tests/ui/conf_bad_toml.toml delete mode 100644 tests/ui/conf_bad_type.rs delete mode 100644 tests/ui/conf_bad_type.stderr delete mode 100644 tests/ui/conf_bad_type.toml delete mode 100644 tests/ui/conf_french_blacklisted_name.rs delete mode 100644 tests/ui/conf_french_blacklisted_name.stderr delete mode 100644 tests/ui/conf_path_non_string.rs delete mode 100644 tests/ui/conf_path_non_string.stderr delete mode 100644 tests/ui/conf_unknown_key.rs delete mode 100644 tests/ui/conf_unknown_key.stderr create mode 100644 tests/ui/toml_blacklist/clippy.toml create mode 100644 tests/ui/toml_blacklist/conf_french_blacklisted_name.rs create mode 100644 tests/ui/toml_blacklist/conf_french_blacklisted_name.stderr create mode 100644 tests/ui/toml_unknown_key/clippy.toml create mode 100644 tests/ui/toml_unknown_key/conf_unknown_key.rs create mode 100644 tests/ui/toml_unknown_key/conf_unknown_key.stderr delete mode 100644 tests/used_underscore_binding_macro.rs (limited to 'src') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d8089675ead..41812c89f9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -151,13 +151,7 @@ Therefore you should use `tests/ui/update-all-references.sh` (after running Manually testing against an example file is useful if you have added some `println!`s and test suite output becomes unreadable. To try clippy with your local modifications, run `cargo run --bin clippy-driver -- -L ./target/debug input.rs` from the -working copy root. Your test file, here `input.rs`, needs to have clippy -enabled as a plugin: - -```rust -#![feature(plugin)] -#![plugin(clippy)] -``` +working copy root. ### How Clippy works diff --git a/README.md b/README.md index 3263b74b5a9..9472156ec98 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ SYSROOT=/path/to/rustc/sysroot cargo install clippy ### Running clippy from the command line without installing it -To have cargo compile your crate with clippy without clippy installation and without needing `#![plugin(clippy)]` +To have cargo compile your crate with clippy without clippy installation in your code, you can use: ```terminal diff --git a/src/lib.rs b/src/lib.rs index f8682884a50..e69323255e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,11 @@ extern crate clippy_lints; pub fn plugin_registrar(reg: &mut Registry) { reg.sess.lint_store.with_read_lock(|lint_store| { for (lint, _, _) in lint_store.get_lint_groups() { + reg.sess + .struct_warn("the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature") + .emit(); if lint == "clippy" { - reg.sess - .struct_warn("running cargo clippy on a crate that also imports the clippy plugin") - .emit(); + // cargo clippy run on a crate that also uses the plugin return; } } diff --git a/tests/auxiliary/conf_french_blacklisted_name.toml b/tests/auxiliary/conf_french_blacklisted_name.toml deleted file mode 100644 index 6abe5a3bbc2..00000000000 --- a/tests/auxiliary/conf_french_blacklisted_name.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["toto", "tata", "titi"] diff --git a/tests/auxiliary/conf_unknown_key.toml b/tests/auxiliary/conf_unknown_key.toml deleted file mode 100644 index 554b87cc50b..00000000000 --- a/tests/auxiliary/conf_unknown_key.toml +++ /dev/null @@ -1,6 +0,0 @@ -# that one is an error -foobar = 42 - -# that one is white-listed -[third-party] -clippy-feature = "nightly" diff --git a/tests/auxiliary/conf_whitelisted.toml b/tests/auxiliary/conf_whitelisted.toml deleted file mode 100644 index 9f87de20baf..00000000000 --- a/tests/auxiliary/conf_whitelisted.toml +++ /dev/null @@ -1,3 +0,0 @@ -# this is ignored by Clippy, but allowed for other tools like clippy-service -[third-party] -clippy-feature = "nightly" diff --git a/tests/cc_seme.rs b/tests/cc_seme.rs deleted file mode 100644 index c81b32c54bc..00000000000 --- a/tests/cc_seme.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -#[allow(dead_code)] -enum Baz { - One, - Two, -} - -struct Test { - t: Option<usize>, - b: Baz, -} - -fn main() { - use Baz::*; - let x = Test { t: Some(0), b: One }; - - match x { - Test { t: Some(_), b: One } => unreachable!(), - Test { - t: Some(42), - b: Two, - } => unreachable!(), - Test { t: None, .. } => unreachable!(), - Test { .. } => unreachable!(), - } -} diff --git a/tests/conf_whitelisted.rs b/tests/conf_whitelisted.rs deleted file mode 100644 index 10a7d3e72d7..00000000000 --- a/tests/conf_whitelisted.rs +++ /dev/null @@ -1,2 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy(conf_file = "./auxiliary/conf_whitelisted.toml"))] diff --git a/tests/ice_exacte_size.rs b/tests/ice_exacte_size.rs deleted file mode 100644 index eeab3a2bec5..00000000000 --- a/tests/ice_exacte_size.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] -#![deny(clippy)] - -#[allow(dead_code)] -struct Foo; - -impl Iterator for Foo { - type Item = (); - - fn next(&mut self) -> Option<()> { - let _ = self.len() == 0; - unimplemented!() - } -} - -impl ExactSizeIterator for Foo {} diff --git a/tests/issue-825.rs b/tests/issue-825.rs deleted file mode 100644 index f806c2c6fde..00000000000 --- a/tests/issue-825.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] -#![allow(warnings)] - -// this should compile in a reasonable amount of time -fn rust_type_id(name: &str) { - 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!(); - } -} - -fn main() {} diff --git a/tests/mut_mut_macro.rs b/tests/mut_mut_macro.rs deleted file mode 100644 index a6473b0f909..00000000000 --- a/tests/mut_mut_macro.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] -#![deny(mut_mut, zero_ptr, cmp_nan)] -#![allow(dead_code)] - -#[macro_use] -extern crate lazy_static; - -use std::collections::HashMap; - -// ensure that we don't suggest `is_nan` and `is_null` inside constants -// FIXME: once const fn is stable, suggest these functions again in constants -const BAA: *const i32 = 0 as *const i32; -static mut BAR: *const i32 = BAA; -static mut FOO: *const i32 = 0 as *const i32; -static mut BUH: bool = 42.0 < std::f32::NAN; - -#[allow(unused_variables, unused_mut)] -fn main() { - lazy_static! { - static ref MUT_MAP : HashMap<usize, &'static str> = { - let mut m = HashMap::new(); - m.insert(0, "zero"); - m - }; - static ref MUT_COUNT : usize = MUT_MAP.len(); - } - assert_eq!(*MUT_COUNT, 1); - // FIXME: don't lint in array length, requires `check_body` - //let _ = [""; (42.0 < std::f32::NAN) as usize]; -} diff --git a/tests/run-pass/cc_seme.rs b/tests/run-pass/cc_seme.rs new file mode 100644 index 00000000000..1539d3c61bc --- /dev/null +++ b/tests/run-pass/cc_seme.rs @@ -0,0 +1,27 @@ +#[allow(dead_code)] +enum Baz { + One, + Two, +} + +struct Test { + t: Option<usize>, + b: Baz, +} + +fn main() { } + +pub fn foo() { + use Baz::*; + let x = Test { t: Some(0), b: One }; + + match x { + Test { t: Some(_), b: One } => unreachable!(), + Test { + t: Some(42), + b: Two, + } => unreachable!(), + Test { t: None, .. } => unreachable!(), + Test { .. } => unreachable!(), + } +} diff --git a/tests/run-pass/ice_exacte_size.rs b/tests/run-pass/ice_exacte_size.rs new file mode 100644 index 00000000000..914153c64ff --- /dev/null +++ b/tests/run-pass/ice_exacte_size.rs @@ -0,0 +1,17 @@ +#![deny(clippy)] + +#[allow(dead_code)] +struct Foo; + +impl Iterator for Foo { + type Item = (); + + fn next(&mut self) -> Option<()> { + let _ = self.len() == 0; + unimplemented!() + } +} + +impl ExactSizeIterator for Foo {} + +fn main() {} diff --git a/tests/run-pass/issue-825.rs b/tests/run-pass/issue-825.rs new file mode 100644 index 00000000000..79df259eadb --- /dev/null +++ b/tests/run-pass/issue-825.rs @@ -0,0 +1,13 @@ +#![allow(warnings)] + +// this should compile in a reasonable amount of time +fn rust_type_id(name: &str) { + 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!(); + } +} + +fn main() {} diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs new file mode 100644 index 00000000000..2b916c025d3 --- /dev/null +++ b/tests/run-pass/mut_mut_macro.rs @@ -0,0 +1,32 @@ +#![deny(mut_mut, zero_ptr, cmp_nan)] +#![allow(dead_code)] + +// compiletest + extern crates doesn't work together +//#[macro_use] +//extern crate lazy_static; + +//use std::collections::HashMap; + +// ensure that we don't suggest `is_nan` and `is_null` inside constants +// FIXME: once const fn is stable, suggest these functions again in constants +const BAA: *const i32 = 0 as *const i32; +static mut BAR: *const i32 = BAA; +static mut FOO: *const i32 = 0 as *const i32; +static mut BUH: bool = 42.0 < std::f32::NAN; + +#[allow(unused_variables, unused_mut)] +fn main() { + /* + lazy_static! { + static ref MUT_MAP : HashMap<usize, &'static str> = { + let mut m = HashMap::new(); + m.insert(0, "zero"); + m + }; + static ref MUT_COUNT : usize = MUT_MAP.len(); + } + assert_eq!(*MUT_COUNT, 1); + */ + // FIXME: don't lint in array length, requires `check_body` + //let _ = [""; (42.0 < std::f32::NAN) as usize]; +} diff --git a/tests/run-pass/used_underscore_binding_macro.rs b/tests/run-pass/used_underscore_binding_macro.rs new file mode 100644 index 00000000000..c9c77257c0e --- /dev/null +++ b/tests/run-pass/used_underscore_binding_macro.rs @@ -0,0 +1,20 @@ + + + +#[macro_use] +extern crate serde_derive; + +/// Test that we do not lint for unused underscores in a `MacroAttribute` +/// expansion +#[deny(used_underscore_binding)] +#[derive(Deserialize)] +struct MacroAttributesTest { + _foo: u32, +} + +#[test] +fn macro_attributes_test() { + let _ = MacroAttributesTest { _foo: 0 }; +} + +fn main() {} diff --git a/tests/run-pass/whitelist/clippy.toml b/tests/run-pass/whitelist/clippy.toml new file mode 100644 index 00000000000..9f87de20baf --- /dev/null +++ b/tests/run-pass/whitelist/clippy.toml @@ -0,0 +1,3 @@ +# this is ignored by Clippy, but allowed for other tools like clippy-service +[third-party] +clippy-feature = "nightly" diff --git a/tests/run-pass/whitelist/conf_whitelisted.rs b/tests/run-pass/whitelist/conf_whitelisted.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-pass/whitelist/conf_whitelisted.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/ui/bad_toml/clippy.toml b/tests/ui/bad_toml/clippy.toml new file mode 100644 index 00000000000..823e01a33b9 --- /dev/null +++ b/tests/ui/bad_toml/clippy.toml @@ -0,0 +1,2 @@ +fn this_is_obviously(not: a, toml: file) { +} diff --git a/tests/ui/bad_toml/conf_bad_toml.rs b/tests/ui/bad_toml/conf_bad_toml.rs new file mode 100644 index 00000000000..325688ac7da --- /dev/null +++ b/tests/ui/bad_toml/conf_bad_toml.rs @@ -0,0 +1,6 @@ +// error-pattern: error reading Clippy's configuration file + + + + +fn main() {} diff --git a/tests/ui/bad_toml/conf_bad_toml.stderr b/tests/ui/bad_toml/conf_bad_toml.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/bad_toml_type/clippy.toml b/tests/ui/bad_toml_type/clippy.toml new file mode 100644 index 00000000000..168675394d7 --- /dev/null +++ b/tests/ui/bad_toml_type/clippy.toml @@ -0,0 +1 @@ +blacklisted-names = 42 diff --git a/tests/ui/bad_toml_type/conf_bad_type.rs b/tests/ui/bad_toml_type/conf_bad_type.rs new file mode 100644 index 00000000000..f97f5802b13 --- /dev/null +++ b/tests/ui/bad_toml_type/conf_bad_type.rs @@ -0,0 +1,6 @@ +// error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` + + + + +fn main() {} diff --git a/tests/ui/bad_toml_type/conf_bad_type.stderr b/tests/ui/bad_toml_type/conf_bad_type.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/conf_bad_arg.rs b/tests/ui/conf_bad_arg.rs deleted file mode 100644 index b988fdb1385..00000000000 --- a/tests/ui/conf_bad_arg.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: `conf_file` must be a named value - - -#![plugin(clippy(conf_file))] - -fn main() {} diff --git a/tests/ui/conf_bad_arg.stderr b/tests/ui/conf_bad_arg.stderr deleted file mode 100644 index 094b7d49cb5..00000000000 --- a/tests/ui/conf_bad_arg.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_bad_arg.rs:4:1 - | -4 | #![plugin(clippy(conf_file))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_bad_toml.rs b/tests/ui/conf_bad_toml.rs deleted file mode 100644 index a2ce7ecc519..00000000000 --- a/tests/ui/conf_bad_toml.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file - - -#![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))] - -fn main() {} diff --git a/tests/ui/conf_bad_toml.stderr b/tests/ui/conf_bad_toml.stderr deleted file mode 100644 index 640b1c5e610..00000000000 --- a/tests/ui/conf_bad_toml.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_bad_toml.rs:4:1 - | -4 | #![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_bad_toml.toml b/tests/ui/conf_bad_toml.toml deleted file mode 100644 index 823e01a33b9..00000000000 --- a/tests/ui/conf_bad_toml.toml +++ /dev/null @@ -1,2 +0,0 @@ -fn this_is_obviously(not: a, toml: file) { -} diff --git a/tests/ui/conf_bad_type.rs b/tests/ui/conf_bad_type.rs deleted file mode 100644 index cb18bfb8c90..00000000000 --- a/tests/ui/conf_bad_type.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` - - -#![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))] - -fn main() {} diff --git a/tests/ui/conf_bad_type.stderr b/tests/ui/conf_bad_type.stderr deleted file mode 100644 index f92b52ec032..00000000000 --- a/tests/ui/conf_bad_type.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_bad_type.rs:4:1 - | -4 | #![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_bad_type.toml b/tests/ui/conf_bad_type.toml deleted file mode 100644 index 168675394d7..00000000000 --- a/tests/ui/conf_bad_type.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = 42 diff --git a/tests/ui/conf_french_blacklisted_name.rs b/tests/ui/conf_french_blacklisted_name.rs deleted file mode 100644 index dbe6d85e5d2..00000000000 --- a/tests/ui/conf_french_blacklisted_name.rs +++ /dev/null @@ -1,23 +0,0 @@ - -#![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))] - -#![allow(dead_code)] -#![allow(single_match)] -#![allow(unused_variables)] -#![warn(blacklisted_name)] - -fn test(toto: ()) {} - -fn main() { - let toto = 42; - let tata = 42; - let titi = 42; - - let tatab = 42; - let tatatataic = 42; - - match (42, Some(1337), Some(0)) { - (toto, Some(tata), titi @ Some(_)) => (), - _ => (), - } -} diff --git a/tests/ui/conf_french_blacklisted_name.stderr b/tests/ui/conf_french_blacklisted_name.stderr deleted file mode 100644 index 214226ac2f9..00000000000 --- a/tests/ui/conf_french_blacklisted_name.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_french_blacklisted_name.rs:2:1 - | -2 | #![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_path_non_string.rs b/tests/ui/conf_path_non_string.rs deleted file mode 100644 index 8d1f01358fc..00000000000 --- a/tests/ui/conf_path_non_string.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(attr_literals)] - -#![plugin(clippy(conf_file=42))] - -fn main() {} diff --git a/tests/ui/conf_path_non_string.stderr b/tests/ui/conf_path_non_string.stderr deleted file mode 100644 index 10b007b0de0..00000000000 --- a/tests/ui/conf_path_non_string.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_path_non_string.rs:3:1 - | -3 | #![plugin(clippy(conf_file=42))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/conf_unknown_key.rs b/tests/ui/conf_unknown_key.rs deleted file mode 100644 index 437d0f9d8b0..00000000000 --- a/tests/ui/conf_unknown_key.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file: unknown key `foobar` - - -#![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))] - -fn main() {} diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr deleted file mode 100644 index d7ac055c517..00000000000 --- a/tests/ui/conf_unknown_key.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) - --> $DIR/conf_unknown_key.rs:4:1 - | -4 | #![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(plugin)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index 0f5726e1ad7..1afae69c186 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -1,4 +1,4 @@ -#![feature(plugin, custom_attribute)] +#![feature(custom_attribute)] #![allow(clippy)] #![warn(cyclomatic_complexity)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index 5284d60a524..f3895c7e3ab 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -1,4 +1,4 @@ -#![feature(plugin, custom_attribute)] +#![feature(custom_attribute)] #![warn(cyclomatic_complexity)] #![warn(unused)] diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index d2aea93a77d..b89a2f1bcaf 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,4 +1,4 @@ -#![feature(plugin, never_type)] +#![feature(never_type)] #![warn(diverging_sub_expression)] #![allow(match_same_arms, logic_bug)] diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index 59f0d3fe39b..a4fab5735e2 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -1,4 +1,4 @@ -#![feature(plugin, alloc)] +#![feature(alloc)] #![feature(associated_type_defaults)] diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index 3be01427134..222c76c25b7 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -1,4 +1,4 @@ -#![feature(plugin, non_ascii_idents)] +#![feature(non_ascii_idents)] #![warn(clippy, pub_enum_variant_names)] diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index b99534d05e1..7a888f01914 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -1,4 +1,4 @@ -#![feature(plugin, box_syntax)] +#![feature(box_syntax)] #![allow(warnings, clippy)] diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 47e73aa0bcd..25b6555715f 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,4 +1,4 @@ -#![feature(plugin, custom_attribute)] +#![feature(custom_attribute)] #![warn(excessive_precision)] #![allow(print_literal)] diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index 0a8be4d938b..1f879c5843e 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -1,4 +1,4 @@ -#![feature(plugin, custom_attribute)] +#![feature(custom_attribute)] use std::collections::*; diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 54176cd6d55..658ae18466f 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -4,8 +4,8 @@ #![allow(unused, no_effect, unnecessary_operation)] #![warn(mut_mut)] -//#![plugin(regex_macros)] -//extern crate regex; + + fn fun(x : &mut &mut u32) -> bool { **x > 0 diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index e618bf1c231..c06c9f9e962 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,4 +1,4 @@ -#![feature(plugin, const_fn)] +#![feature(const_fn)] #![allow(dead_code)] diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index d1e4bf2a2c7..54028cd8b2b 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,4 +1,4 @@ -#![feature(plugin, box_syntax)] +#![feature(box_syntax)] #![warn(no_effect, unnecessary_operation)] diff --git a/tests/ui/toml_blacklist/clippy.toml b/tests/ui/toml_blacklist/clippy.toml new file mode 100644 index 00000000000..6abe5a3bbc2 --- /dev/null +++ b/tests/ui/toml_blacklist/clippy.toml @@ -0,0 +1 @@ +blacklisted-names = ["toto", "tata", "titi"] diff --git a/tests/ui/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui/toml_blacklist/conf_french_blacklisted_name.rs new file mode 100644 index 00000000000..1f1a8ee91a1 --- /dev/null +++ b/tests/ui/toml_blacklist/conf_french_blacklisted_name.rs @@ -0,0 +1,23 @@ + + + +#![allow(dead_code)] +#![allow(single_match)] +#![allow(unused_variables)] +#![warn(blacklisted_name)] + +fn test(toto: ()) {} + +fn main() { + let toto = 42; + let tata = 42; + let titi = 42; + + let tatab = 42; + let tatatataic = 42; + + match (42, Some(1337), Some(0)) { + (toto, Some(tata), titi @ Some(_)) => (), + _ => (), + } +} diff --git a/tests/ui/toml_blacklist/conf_french_blacklisted_name.stderr b/tests/ui/toml_blacklist/conf_french_blacklisted_name.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/toml_unknown_key/clippy.toml b/tests/ui/toml_unknown_key/clippy.toml new file mode 100644 index 00000000000..554b87cc50b --- /dev/null +++ b/tests/ui/toml_unknown_key/clippy.toml @@ -0,0 +1,6 @@ +# that one is an error +foobar = 42 + +# that one is white-listed +[third-party] +clippy-feature = "nightly" diff --git a/tests/ui/toml_unknown_key/conf_unknown_key.rs b/tests/ui/toml_unknown_key/conf_unknown_key.rs new file mode 100644 index 00000000000..bfa804558bb --- /dev/null +++ b/tests/ui/toml_unknown_key/conf_unknown_key.rs @@ -0,0 +1,6 @@ +// error-pattern: error reading Clippy's configuration file: unknown key `foobar` + + + + +fn main() {} diff --git a/tests/ui/toml_unknown_key/conf_unknown_key.stderr b/tests/ui/toml_unknown_key/conf_unknown_key.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 6a7b6b05e70..d915a0bed09 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,4 +1,4 @@ -#![feature(plugin, custom_attribute, stmt_expr_attributes)] +#![feature(custom_attribute, stmt_expr_attributes)] #![allow(unused_parens)] diff --git a/tests/used_underscore_binding_macro.rs b/tests/used_underscore_binding_macro.rs deleted file mode 100644 index b323cb5d25b..00000000000 --- a/tests/used_underscore_binding_macro.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -#[macro_use] -extern crate serde_derive; - -/// Test that we do not lint for unused underscores in a `MacroAttribute` -/// expansion -#[deny(used_underscore_binding)] -#[derive(Deserialize)] -struct MacroAttributesTest { - _foo: u32, -} - -#[test] -fn macro_attributes_test() { - let _ = MacroAttributesTest { _foo: 0 }; -} -- cgit 1.4.1-3-g733a5 From df1b7c5f198b569b7da37511b635994758380320 Mon Sep 17 00:00:00 2001 From: utam0k <k0ma@utam0k.jp> Date: Sat, 19 May 2018 14:29:20 +0900 Subject: Rename trans to codegen --- src/driver.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 4e3852d416a..2be29df5a54 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -9,11 +9,11 @@ extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_plugin; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::session::{config, Session}; use rustc::session::config::{ErrorOutputType, Input}; use std::path::PathBuf; @@ -60,7 +60,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { } fn late_callback( &mut self, - trans_crate: &TransCrate, + trans_crate: &CodegenBackend, matches: &getopts::Matches, sess: &Session, crate_stores: &rustc::middle::cstore::CrateStore, -- cgit 1.4.1-3-g733a5 From b60ffa780d0c18c754b03ad8dd745fc3e19f11d6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider <oli-obk@users.noreply.github.com> Date: Sat, 19 May 2018 18:49:57 +0200 Subject: Stop compilation after linting --- src/driver.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 2be29df5a54..61afb6ea2f4 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -118,6 +118,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { } old(state); }); + + control.compilation_done.stop = Compilation::Stop; } control -- cgit 1.4.1-3-g733a5 From 3c6503eb4b24897e9317b4af2faaf6b603be32dd Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <matti@marinelayer.io> Date: Tue, 22 May 2018 10:21:42 +0200 Subject: Format code --- build.rs | 76 ++++++++++++++++++++------------------ clippy_lints/src/approx_const.rs | 5 +-- clippy_lints/src/arithmetic.rs | 26 ++++++------- clippy_lints/src/array_indexing.rs | 6 +-- clippy_lints/src/assign_ops.rs | 74 ++++++++++++++++++++----------------- clippy_lints/src/attrs.rs | 27 +++++++------- src/driver.rs | 27 +++++++------- src/lib.rs | 4 +- tests/compile-test.rs | 7 +--- tests/versioncheck.rs | 5 +-- tests/without_block_comments.rs | 6 +-- 11 files changed, 134 insertions(+), 129 deletions(-) (limited to 'src') diff --git a/build.rs b/build.rs index 913f7b4ee89..1481f460fc3 100644 --- a/build.rs +++ b/build.rs @@ -13,12 +13,12 @@ //! This build script was originally taken from the Rocket web framework: //! https://github.com/SergioBenitez/Rocket -extern crate rustc_version; extern crate ansi_term; +extern crate rustc_version; -use std::env; -use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta}; use ansi_term::Colour::Red; +use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta}; +use std::env; fn main() { check_rustc_version(); @@ -31,42 +31,48 @@ fn main() { fn check_rustc_version() { let string = include_str!("min_version.txt"); - let min_version_meta = version_meta_for(string) - .expect("Could not parse version string in min_version.txt"); - let current_version_meta = version_meta() - .expect("Could not retrieve current rustc version information from ENV"); + let min_version_meta = version_meta_for(string).expect("Could not parse version string in min_version.txt"); + let current_version_meta = version_meta().expect("Could not retrieve current rustc version information from ENV"); let min_version = min_version_meta.clone().semver; - let min_date_str = min_version_meta.clone().commit_date + let min_date_str = min_version_meta + .clone() + .commit_date .expect("min_version.txt does not contain a rustc commit date"); // Dev channel (rustc built from git) does not have any date or commit information in rustc -vV // `current_version_meta.commit_date` would crash, so we return early here. if current_version_meta.channel == Channel::Dev { - return + return; } let current_version = current_version_meta.clone().semver; - let current_date_str = current_version_meta.clone().commit_date + let current_date_str = current_version_meta + .clone() + .commit_date .expect("current rustc version information does not contain a rustc commit date"); let print_version_err = |version: &Version, date: &str| { - eprintln!("> {} {}. {} {}.\n", - "Installed rustc version is:", - format!("{} ({})", version, date), - "Minimum required rustc version:", - format!("{} ({})", min_version, min_date_str)); + eprintln!( + "> {} {}. {} {}.\n", + "Installed rustc version is:", + format!("{} ({})", version, date), + "Minimum required rustc version:", + format!("{} ({})", min_version, min_date_str) + ); }; if !correct_channel(¤t_version_meta) { - eprintln!("\n{} {}", - Red.bold().paint("error:"), - "clippy requires a nightly version of Rust."); + eprintln!( + "\n{} {}", + Red.bold().paint("error:"), + "clippy requires a nightly version of Rust." + ); print_version_err(¤t_version, &*current_date_str); - eprintln!("{}{}{}", - "See the README (", - "https://github.com/rust-lang-nursery/rust-clippy#usage", - ") for more information."); + eprintln!( + "{}{}{}", + "See the README (", "https://github.com/rust-lang-nursery/rust-clippy#usage", ") for more information." + ); panic!("Aborting compilation due to incompatible compiler.") } @@ -74,13 +80,15 @@ fn check_rustc_version() { let min_date = str_to_ymd(&min_date_str).unwrap(); if current_date < min_date { - eprintln!("\n{} {}", - Red.bold().paint("error:"), - "clippy does not support this version of rustc nightly."); - eprintln!("> {}{}{}", - "Use `", - "rustup update", - "` or your preferred method to update Rust."); + eprintln!( + "\n{} {}", + Red.bold().paint("error:"), + "clippy does not support this version of rustc nightly." + ); + eprintln!( + "> {}{}{}", + "Use `", "rustup update", "` or your preferred method to update Rust." + ); print_version_err(¤t_version, &*current_date_str); panic!("Aborting compilation due to incompatible compiler.") } @@ -88,12 +96,8 @@ fn check_rustc_version() { fn correct_channel(version_meta: &VersionMeta) -> bool { match version_meta.channel { - Channel::Stable | Channel::Beta => { - false - }, - Channel::Nightly | Channel::Dev => { - true - } + Channel::Stable | Channel::Beta => false, + Channel::Nightly | Channel::Dev => true, } } @@ -101,7 +105,7 @@ fn correct_channel(version_meta: &VersionMeta) -> bool { fn str_to_ymd(ymd: &str) -> Option<u32> { let ymd: Vec<u32> = ymd.split("-").filter_map(|s| s.parse::<u32>().ok()).collect(); if ymd.len() != 3 { - return None + return None; } let (y, m, d) = (ymd[0], ymd[1], ymd[2]); diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index d15b48ce2d1..20b9c279277 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ -use rustc::lint::*; use rustc::hir::*; +use rustc::lint::*; use std::f64::consts as f64; use syntax::ast::{FloatTy, Lit, LitKind}; use syntax::symbol; @@ -90,8 +90,7 @@ fn check_known_consts(cx: &LateContext, e: &Expr, s: &symbol::Symbol, module: &s &format!( "approximate value of `{}::consts::{}` found. \ Consider using it directly", - module, - &name + module, &name ), ); return; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index 501f49363dd..835555f42f8 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -57,19 +57,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { match expr.node { hir::ExprBinary(ref op, ref l, ref r) => { match op.node { - hir::BiAnd | - hir::BiOr | - hir::BiBitAnd | - hir::BiBitOr | - hir::BiBitXor | - hir::BiShl | - hir::BiShr | - hir::BiEq | - hir::BiLt | - hir::BiLe | - hir::BiNe | - hir::BiGe | - hir::BiGt => return, + hir::BiAnd + | hir::BiOr + | hir::BiBitAnd + | hir::BiBitOr + | hir::BiBitXor + | hir::BiShl + | hir::BiShr + | hir::BiEq + | hir::BiLt + | hir::BiLe + | hir::BiNe + | hir::BiGe + | hir::BiGt => return, _ => (), } let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r)); diff --git a/clippy_lints/src/array_indexing.rs b/clippy_lints/src/array_indexing.rs index b5a42f03e9a..010f07ab8d2 100644 --- a/clippy_lints/src/array_indexing.rs +++ b/clippy_lints/src/array_indexing.rs @@ -1,10 +1,10 @@ +use consts::{constant, Constant}; +use rustc::hir; use rustc::lint::*; use rustc::ty; -use rustc::hir; use syntax::ast::RangeLimits; -use utils::{self, higher}; use utils::higher::Range; -use consts::{constant, Constant}; +use utils::{self, higher}; /// **What it does:** Checks for out of bounds array indexing with a constant /// index. diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index da4b0d6a437..7b4000485bd 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -95,24 +95,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { MISREFACTORED_ASSIGN_OP, 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_other.span)) - { - let a = &sugg::Sugg::hir(cx, assignee, ".."); - let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r)); - db.span_suggestion( - expr.span, - &format!("Did you mean {} = {} {} {} or {}? Consider replacing it with", - snip_a, snip_a, op.node.as_str(), snip_r, - long), - format!("{} {}= {}", snip_a, op.node.as_str(), snip_r) - ); - db.span_suggestion( - expr.span, - "or", - long - ); + |db| { + if let (Some(snip_a), Some(snip_r)) = + (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) + { + let a = &sugg::Sugg::hir(cx, assignee, ".."); + let r = &sugg::Sugg::hir(cx, rhs, ".."); + let long = + format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r)); + db.span_suggestion( + expr.span, + &format!( + "Did you mean {} = {} {} {} or {}? Consider replacing it with", + snip_a, + snip_a, + op.node.as_str(), + snip_r, + long + ), + format!("{} {}= {}", snip_a, op.node.as_str(), snip_r), + ); + db.span_suggestion(expr.span, "or", long); + } }, ); }; @@ -189,14 +193,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { ASSIGN_OP_PATTERN, 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), - ); + |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), + ); + } }, ); } @@ -205,7 +211,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { let mut visitor = ExprVisitor { assignee, counter: 0, - cx + cx, }; walk_expr(&mut visitor, e); @@ -218,13 +224,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { // a = b commutative_op a if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) { match op.node { - hir::BiAdd | - hir::BiMul | - hir::BiAnd | - hir::BiOr | - hir::BiBitXor | - hir::BiBitAnd | - hir::BiBitOr => { + hir::BiAdd + | hir::BiMul + | hir::BiAnd + | hir::BiOr + | hir::BiBitXor + | hir::BiBitAnd + | hir::BiBitOr => { lint(assignee, l); }, _ => {}, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index b1cd096bc13..936b5e75ff6 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,13 +1,16 @@ //! checks for attributes use reexport::*; -use rustc::lint::*; use rustc::hir::*; +use rustc::lint::*; use rustc::ty::{self, TyCtxt}; use semver::Version; -use syntax::ast::{Attribute, AttrStyle, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; +use syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use syntax::codemap::Span; -use utils::{in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then, without_block_comments}; +use utils::{ + in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then, + without_block_comments, +}; /// **What it does:** Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. @@ -118,7 +121,12 @@ pub struct AttrPass; impl LintPass for AttrPass { fn get_lints(&self) -> LintArray { - lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, EMPTY_LINE_AFTER_OUTER_ATTR) + lint_array!( + INLINE_ALWAYS, + DEPRECATED_SEMVER, + USELESS_ATTRIBUTE, + EMPTY_LINE_AFTER_OUTER_ATTR + ) } } @@ -170,11 +178,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { "useless lint attribute", |db| { sugg = sugg.replacen("#[", "#![", 1); - db.span_suggestion( - line_span, - "if you just forgot a `!`, use", - sugg, - ); + db.span_suggestion(line_span, "if you just forgot a `!`, use", sugg); }, ); } @@ -234,10 +238,7 @@ fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> b StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr), } } else { - block - .expr - .as_ref() - .map_or(false, |e| is_relevant_expr(tcx, tables, e)) + block.expr.as_ref().map_or(false, |e| is_relevant_expr(tcx, tables, e)) } } diff --git a/src/driver.rs b/src/driver.rs index 61afb6ea2f4..a88d6e5c26d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -6,16 +6,16 @@ extern crate clippy_lints; extern crate getopts; extern crate rustc; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_plugin; -extern crate rustc_codegen_utils; extern crate syntax; -use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc::session::{config, Session}; use rustc::session::config::{ErrorOutputType, Input}; +use rustc::session::{config, Session}; +use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; use std::path::PathBuf; use std::process::Command; use syntax::ast; @@ -43,8 +43,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType, ) -> Compilation { - self.default - .early_callback(matches, sopts, cfg, descriptions, output) + self.default.early_callback(matches, sopts, cfg, descriptions, output) } fn no_input( &mut self, @@ -55,8 +54,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry, ) -> Option<(Input, Option<PathBuf>)> { - self.default - .no_input(matches, sopts, cfg, odir, ofile, descriptions) + self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback( &mut self, @@ -118,7 +116,7 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { } old(state); }); - + control.compilation_done.stop = Compilation::Stop; } @@ -185,15 +183,18 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS") - .ok() - .map_or(false, |val| val == "true") + let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter(|s| !s.is_empty()).map(str::to_owned)); + args.extend( + extra_args + .split("__CLIPPY_HACKERY__") + .filter(|s| !s.is_empty()) + .map(str::to_owned), + ); } } diff --git a/src/lib.rs b/src/lib.rs index e69323255e8..193be97161f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,9 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.sess.lint_store.with_read_lock(|lint_store| { for (lint, _, _) in lint_store.get_lint_groups() { reg.sess - .struct_warn("the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature") + .struct_warn( + "the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature", + ) .emit(); if lint == "clippy" { // cargo clippy run on a crate that also uses the plugin diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 9b9820f2b52..b965dceb774 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -3,8 +3,8 @@ extern crate compiletest_rs as compiletest; extern crate test; -use std::path::{Path, PathBuf}; use std::env::{set_var, var}; +use std::path::{Path, PathBuf}; fn clippy_driver_path() -> PathBuf { if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { @@ -43,10 +43,7 @@ fn config(dir: &'static str, mode: &'static str) -> compiletest::Config { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - config.target_rustcflags = Some(format!( - "-L {0} -L {0}/deps -Dwarnings", - host_libs().display() - )); + config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display())); config.mode = cfg_mode; config.build_base = if rustc_test_suite().is_some() { diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index ff4af08a8a0..25b0ceefae7 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -7,10 +7,7 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() { let clippy_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap(); let clippy_lints_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata"); - assert_eq!( - clippy_lints_meta.packages[0].version, - clippy_meta.packages[0].version - ); + assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version); for package in &clippy_meta.packages[0].dependencies { if package.name == "clippy_lints" { assert_eq!( diff --git a/tests/without_block_comments.rs b/tests/without_block_comments.rs index 375df057544..730c5cb128f 100644 --- a/tests/without_block_comments.rs +++ b/tests/without_block_comments.rs @@ -7,9 +7,7 @@ fn test_lines_without_block_comments() { println!("result: {:?}", result); assert!(result.is_empty()); - let result = without_block_comments( - vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""] - ); + let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]); assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]); let result = without_block_comments(vec!["/* rust", "", "*/"]); @@ -18,7 +16,7 @@ fn test_lines_without_block_comments() { let result = without_block_comments(vec!["/* one-line comment */"]); assert!(result.is_empty()); - let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); + let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]); assert!(result.is_empty()); let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]); -- cgit 1.4.1-3-g733a5 From 26f3feb9809953740c9883c3cf8ea60734093b06 Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <matti@marinelayer.io> Date: Wed, 30 May 2018 10:05:06 +0200 Subject: Add rust_2018_preview feature and fix rustfmt annotation --- clippy_lints/src/lib.rs | 1 + clippy_lints/src/new_without_default.rs | 2 +- src/lib.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1e75d42dd61..07f66f84b18 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -11,6 +11,7 @@ #![allow(stable_features)] #![feature(iterator_find_map)] #![feature(macro_at_most_once_rep)] +#![feature(rust_2018_preview)] extern crate cargo_metadata; #[macro_use] diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 54b00081973..a6a63e6aa05 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { } fn create_new_without_default_suggest_msg(ty: Ty) -> String { - #[rustfmt_skip] + #[cfg_attr(rustfmt, rustfmt_skip)] format!( "impl Default for {} {{ fn default() -> Self {{ diff --git a/src/lib.rs b/src/lib.rs index 193be97161f..61e5c104bef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] +#![feature(rust_2018_preview)] #![feature(rustc_private)] #![feature(macro_vis_matcher)] #![allow(unknown_lints)] -- cgit 1.4.1-3-g733a5 From 52deb3b0863558315b57b801804820254d4eaa4e Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <mati865@gmail.com> Date: Thu, 7 Jun 2018 19:16:41 +0200 Subject: Prepare for upcoming breakage --- src/driver.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index a88d6e5c26d..217bcca45de 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -21,14 +21,14 @@ use std::process::Command; use syntax::ast; struct ClippyCompilerCalls { - default: RustcDefaultCalls, + default: Box<RustcDefaultCalls>, run_lints: bool, } impl ClippyCompilerCalls { fn new(run_lints: bool) -> Self { Self { - default: RustcDefaultCalls, + default: Box::new(RustcDefaultCalls), run_lints, } } @@ -69,8 +69,8 @@ impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { self.default .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile) } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); + fn build_controller(self: Box<Self>, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { + let mut control = self.default.clone().build_controller(sess, matches); if self.run_lints { let old = std::mem::replace(&mut control.after_parse.callback, box |_| {}); @@ -198,6 +198,6 @@ pub fn main() { } } - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - rustc_driver::run(move || rustc_driver::run_compiler(&args, &mut ccc, None, None)); + let ccc = ClippyCompilerCalls::new(clippy_enabled); + rustc_driver::run(move || rustc_driver::run_compiler(&args, Box::new(ccc), None, None)); } -- cgit 1.4.1-3-g733a5 From b45fb35ec4cff21d027fa25dd31b5045867ccf03 Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <mati865@gmail.com> Date: Thu, 7 Jun 2018 22:03:15 +0200 Subject: Cleanup of driver code --- src/driver.rs | 158 +++++++++++++++++----------------------------------------- 1 file changed, 46 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 217bcca45de..830c8985660 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -12,117 +12,8 @@ extern crate rustc_errors; extern crate rustc_plugin; extern crate syntax; -use rustc::session::config::{ErrorOutputType, Input}; -use rustc::session::{config, Session}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use std::path::PathBuf; +use rustc_driver::{driver::CompileController, Compilation}; use std::process::Command; -use syntax::ast; - -struct ClippyCompilerCalls { - default: Box<RustcDefaultCalls>, - run_lints: bool, -} - -impl ClippyCompilerCalls { - fn new(run_lints: bool) -> Self { - Self { - default: Box::new(RustcDefaultCalls), - run_lints, - } - } -} - -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 { - 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<PathBuf>, - ofile: &Option<PathBuf>, - descriptions: &rustc_errors::registry::Registry, - ) -> Option<(Input, Option<PathBuf>)> { - self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) - } - fn late_callback( - &mut self, - trans_crate: &CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - crate_stores: &rustc::middle::cstore::CrateStore, - input: &Input, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>, - ) -> Compilation { - self.default - .late_callback(trans_crate, matches, sess, crate_stores, input, odir, ofile) - } - fn build_controller(self: Box<Self>, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.default.clone().build_controller(sess, matches); - - if self.run_lints { - 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 crate must be parsed", - ) - .span, - ); - registry.args_hidden = Some(Vec::new()); - clippy_lints::register_plugins(&mut registry); - - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - } - old(state); - }); - - control.compilation_done.stop = Compilation::Stop; - } - - control - } -} #[allow(print_stdout)] fn show_version() { @@ -198,6 +89,49 @@ pub fn main() { } } - let ccc = ClippyCompilerCalls::new(clippy_enabled); - rustc_driver::run(move || rustc_driver::run_compiler(&args, Box::new(ccc), None, None)); + let mut controller = CompileController::basic(); + if clippy_enabled { + controller.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 crate must be parsed", + ) + .span, + ); + registry.args_hidden = Some(Vec::new()); + clippy_lints::register_plugins(&mut registry); + + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + }); + } + controller.compilation_done.stop = Compilation::Stop; + + rustc_driver::run_compiler(&args, Box::new(controller), None, None); } -- cgit 1.4.1-3-g733a5 From 5be00bcd1835145ff71ec3539c2bf849da0e37ed Mon Sep 17 00:00:00 2001 From: Fraser Hutchison <fraser.hutchison@maidsafe.net> Date: Thu, 21 Jun 2018 05:20:14 +0100 Subject: Ensure a non-zero value is returned by clippy if compilation fails --- src/driver.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 830c8985660..419f61f860b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -13,7 +13,7 @@ extern crate rustc_plugin; extern crate syntax; use rustc_driver::{driver::CompileController, Compilation}; -use std::process::Command; +use std::process::{exit, Command}; #[allow(print_stdout)] fn show_version() { @@ -133,5 +133,10 @@ pub fn main() { } controller.compilation_done.stop = Compilation::Stop; - rustc_driver::run_compiler(&args, Box::new(controller), None, None); + if rustc_driver::run_compiler(&args, Box::new(controller), None, None) + .0 + .is_err() + { + exit(101); + } } -- cgit 1.4.1-3-g733a5 From a6601f2d02389dbde250c2538b4482fa4613efab Mon Sep 17 00:00:00 2001 From: Mateusz Mikuła <mati865@gmail.com> Date: Mon, 25 Jun 2018 20:50:20 +0200 Subject: Enable rust_2018_idioms warning --- build.rs | 3 --- clippy_lints/src/copies.rs | 6 ++--- clippy_lints/src/lib.rs | 35 ++++-------------------------- clippy_lints/src/literal_representation.rs | 18 +++++++-------- clippy_lints/src/utils/conf.rs | 11 +++++++++- src/driver.rs | 12 ++-------- src/lib.rs | 4 +--- 7 files changed, 29 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/build.rs b/build.rs index 1481f460fc3..241c8579a48 100644 --- a/build.rs +++ b/build.rs @@ -13,9 +13,6 @@ //! This build script was originally taken from the Rocket web framework: //! https://github.com/SergioBenitez/Rocket -extern crate ansi_term; -extern crate rustc_version; - use ansi_term::Colour::Red; use rustc_version::{version_meta, version_meta_for, Channel, Version, VersionMeta}; use std::env; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index abbc4681166..2e2489cbb4a 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -134,7 +134,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { /// Implementation of `IF_SAME_THEN_ELSE`. fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { - let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; + let eq: &dyn Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same_sequenced(blocks, eq) { span_note_and_lint( @@ -150,13 +150,13 @@ fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { /// Implementation of `IFS_SAME_COND`. fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { - let hash: &Fn(&&Expr) -> u64 = &|expr| -> u64 { + let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 { let mut h = SpanlessHash::new(cx, cx.tables); h.hash_expr(expr); h.finish() }; - let eq: &Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; + let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; if let Some((i, j)) = search_same(conds, hash, eq) { span_note_and_lint( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 34799635884..43fcd786773 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -12,50 +12,23 @@ #![feature(iterator_find_map)] #![feature(macro_at_most_once_rep)] #![feature(rust_2018_preview)] +#![warn(rust_2018_idioms)] -extern crate cargo_metadata; #[macro_use] extern crate rustc; -extern crate rustc_target; -extern crate rustc_typeck; -extern crate syntax; -extern crate syntax_pos; -extern crate toml; - -// for unicode nfc normalization - -extern crate unicode_normalization; - -// for semver check in attrs.rs - -extern crate semver; - -// for regex checking - -extern crate regex_syntax; - -// for finding minimal boolean expressions - -extern crate quine_mc_cluskey; - -extern crate rustc_errors; -extern crate rustc_plugin; +use toml; +use rustc_plugin; #[macro_use] extern crate matches as matches_macro; -extern crate serde; #[macro_use] extern crate serde_derive; #[macro_use] extern crate lazy_static; -extern crate itertools; -extern crate pulldown_cmark; -extern crate url; - #[macro_use] extern crate if_chain; @@ -211,7 +184,7 @@ pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` mod reexport { - pub use syntax::ast::{Name, NodeId}; + crate use syntax::ast::{Name, NodeId}; } #[cfg_attr(rustfmt, rustfmt_skip)] diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 09b66b872e9..9b6c30f7f4c 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -90,7 +90,7 @@ pub(super) enum Radix { impl Radix { /// Return a reasonable digit group size for this radix. - pub fn suggest_grouping(&self) -> usize { + crate fn suggest_grouping(&self) -> usize { match *self { Radix::Binary | Radix::Hexadecimal => 4, Radix::Octal | Radix::Decimal => 3, @@ -101,19 +101,19 @@ impl Radix { #[derive(Debug)] pub(super) struct DigitInfo<'a> { /// Characters of a literal between the radix prefix and type suffix. - pub digits: &'a str, + crate digits: &'a str, /// Which radix the literal was represented in. - pub radix: Radix, + crate radix: Radix, /// The radix prefix, if present. - pub prefix: Option<&'a str>, + crate prefix: Option<&'a str>, /// The type suffix, including preceding underscore if present. - pub suffix: Option<&'a str>, + crate suffix: Option<&'a str>, /// True for floating-point literals. - pub float: bool, + crate float: bool, } impl<'a> DigitInfo<'a> { - pub fn new(lit: &'a str, float: bool) -> Self { + crate fn new(lit: &'a str, float: bool) -> Self { // Determine delimiter for radix prefix, if present, and radix. let radix = if lit.starts_with("0x") { Radix::Hexadecimal @@ -160,7 +160,7 @@ impl<'a> DigitInfo<'a> { } /// Returns digits grouped in a sensible way. - pub fn grouping_hint(&self) -> String { + crate fn grouping_hint(&self) -> String { let group_size = self.radix.suggest_grouping(); if self.digits.contains('.') { let mut parts = self.digits.split('.'); @@ -227,7 +227,7 @@ enum WarningType { } impl WarningType { - pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: syntax_pos::Span) { + crate fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: syntax_pos::Span) { match self { WarningType::UnreadableLiteral => span_lint_and_sugg( cx, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index d3c7d901323..05abdd2f13c 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -76,6 +76,15 @@ lazy_static! { macro_rules! define_Conf { ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => { pub use self::helpers::Conf; + // FIXME(mati865): remove #[allow(rust_2018_idioms)] when it's fixed: + // + // warning: `extern crate` is not idiomatic in the new edition + // --> src/utils/conf.rs:82:22 + // | + // 82 | #[derive(Deserialize)] + // | ^^^^^^^^^^^ help: convert it to a `use` + // + #[allow(rust_2018_idioms)] mod helpers { /// Type used to store lint configuration. #[derive(Deserialize)] @@ -92,7 +101,7 @@ macro_rules! define_Conf { mod $rust_name { use serde; use serde::Deserialize; - pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) + crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<define_Conf!(TY $($ty)+), D::Error> { type T = define_Conf!(TY $($ty)+); Ok(T::deserialize(deserializer).unwrap_or_else(|e| { diff --git a/src/driver.rs b/src/driver.rs index 419f61f860b..585edcd82a6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -3,16 +3,8 @@ #![feature(rustc_private)] #![allow(unknown_lints, missing_docs_in_private_items)] -extern crate clippy_lints; -extern crate getopts; -extern crate rustc; -extern crate rustc_codegen_utils; -extern crate rustc_driver; -extern crate rustc_errors; -extern crate rustc_plugin; -extern crate syntax; - -use rustc_driver::{driver::CompileController, Compilation}; +use rustc_driver::{self, driver::CompileController, Compilation}; +use rustc_plugin; use std::process::{exit, Command}; #[allow(print_stdout)] diff --git a/src/lib.rs b/src/lib.rs index 61e5c104bef..6ff15e2cd89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,12 +5,10 @@ #![feature(macro_vis_matcher)] #![allow(unknown_lints)] #![allow(missing_docs_in_private_items)] +#![warn(rust_2018_idioms)] -extern crate rustc_plugin; use rustc_plugin::Registry; -extern crate clippy_lints; - #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.sess.lint_store.with_read_lock(|lint_store| { -- cgit 1.4.1-3-g733a5 From ff0e5f967fde38242a1f2bf852082d2e105fc29c Mon Sep 17 00:00:00 2001 From: Oliver Schneider <github35764891676564198441@oli-obk.de> Date: Mon, 23 Jul 2018 00:19:07 +0200 Subject: Rewrite the print/write macro checks as a PreExpansionPass --- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/write.rs | 434 +++++++++++------------------------ src/driver.rs | 1 + tests/ui/excessive_precision.rs | 2 +- tests/ui/excessive_precision.stderr | 6 +- tests/ui/matches.stderr | 19 +- tests/ui/non_expressive_names.stderr | 22 +- tests/ui/print.stderr | 30 ++- tests/ui/print_literal.stderr | 28 +-- tests/ui/print_with_newline.stderr | 22 +- tests/ui/println_empty_string.stderr | 2 +- tests/ui/write_literal.stderr | 28 +-- tests/ui/write_with_newline.stderr | 8 +- tests/ui/writeln_empty_string.stderr | 2 +- 14 files changed, 251 insertions(+), 359 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1f31b24b443..53a37f23fa4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -16,6 +16,7 @@ use toml; use rustc_plugin; +use rustc; macro_rules! declare_clippy_lint { @@ -175,6 +176,10 @@ mod reexport { crate use syntax::ast::{Name, NodeId}; } +pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore) { + store.register_pre_expansion_pass(Some(session), box write::Pass); +} + #[cfg_attr(rustfmt, rustfmt_skip)] pub fn register_plugins(reg: &mut rustc_plugin::Registry) { let conf = match utils::conf::file_from_args(reg.args()) { @@ -320,7 +325,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box strings::StringLitAsBytes); reg.register_late_lint_pass(box derive::Derive); reg.register_late_lint_pass(box types::CharLitAsU8); - reg.register_late_lint_pass(box write::Pass); reg.register_late_lint_pass(box vec::Pass); reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold: conf.single_char_binding_names_threshold, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 0f0bd64cb61..c4b5a9ccefc 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,15 +1,9 @@ -use rustc::hir::map::Node::{NodeImplItem, NodeItem}; -use rustc::hir::*; use rustc::lint::*; use rustc::{declare_lint, lint_array}; -use if_chain::if_chain; -use std::ops::Deref; -use syntax::ast::LitKind; -use syntax::ptr; -use syntax::symbol::LocalInternedString; -use syntax_pos::Span; -use crate::utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint, span_lint_and_sugg}; -use crate::utils::{opt_def_id, paths, last_path_segment}; +use syntax::ast::*; +use syntax::tokenstream::{ThinTokenStream, TokenStream}; +use syntax::parse::{token, parser}; +use crate::utils::{span_lint, span_lint_and_sugg}; /// **What it does:** This lint warns when you use `println!("")` to /// print a newline. @@ -173,317 +167,149 @@ impl LintPass for Pass { } } -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - match expr.node { - // print!() - ExprKind::Call(ref fun, ref args) => { - if_chain! { - if let ExprKind::Path(ref qpath) = fun.node; - if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)); - then { - check_print_variants(cx, expr, fun_id, args); - } - } - }, - // write!() - ExprKind::MethodCall(ref fun, _, ref args) => { - if fun.ident.name == "write_fmt" { - check_write_variants(cx, expr, args); - } - }, - _ => (), - } - } -} - -fn check_write_variants<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, write_args: &ptr::P<[Expr]>) { - // `writeln!` uses `write!`. - if let Some(span) = is_expn_of(expr.span, "write") { - let (span, name) = match is_expn_of(span, "writeln") { - Some(span) => (span, "writeln"), - None => (span, "write"), - }; - - if_chain! { - // ensure we're calling Arguments::new_v1 or Arguments::new_v1_formatted - if write_args.len() == 2; - if let ExprKind::Call(ref args_fun, ref args_args) = write_args[1].node; - if let ExprKind::Path(ref qpath) = args_fun.node; - if let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id)); - if match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1) || - match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1FORMATTED); - then { - // Check for literals in the write!/writeln! args - check_fmt_args_for_literal(cx, args_args, |span| { - span_lint(cx, WRITE_LITERAL, span, "writing a literal with an empty format string"); - }); - - if_chain! { - if args_args.len() >= 2; - if let ExprKind::AddrOf(_, ref match_expr) = args_args[1].node; - if let ExprKind::Match(ref args, _, _) = match_expr.node; - if let ExprKind::Tup(ref args) = args.node; - if let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]); - then { - match name { - "write" => if has_newline_end(args, fmtstr, fmtlen) { - span_lint(cx, WRITE_WITH_NEWLINE, span, - "using `write!()` with a format string that ends in a \ - newline, consider using `writeln!()` instead"); - }, - "writeln" => if let Some(final_span) = has_empty_arg(cx, span, fmtstr, fmtlen) { - span_lint_and_sugg( - cx, - WRITE_WITH_NEWLINE, - final_span, - "using `writeln!(v, \"\")`", - "replace it with", - "writeln!(v)".to_string(), - ); - }, - _ => (), - } - } +impl EarlyLintPass for Pass { + fn check_mac(&mut self, cx: &EarlyContext, mac: &Mac) { + if mac.node.path == "println" { + span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`"); + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) { + if fmtstr == "" { + span_lint_and_sugg( + cx, + PRINTLN_EMPTY_STRING, + mac.span, + "using `println!(\"\")`", + "replace it with", + "println!()".to_string(), + ); } } - } - } -} - -fn check_print_variants<'a, 'tcx>( - cx: &LateContext<'a, 'tcx>, - expr: &'tcx Expr, - fun_id: def_id::DefId, - args: &ptr::P<[Expr]>, -) { - // Search for `std::io::_print(..)` which is unique in a - // `print!` expansion. - if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) { - if let Some(span) = is_expn_of(expr.span, "print") { - // `println!` uses `print!`. - let (span, name) = match is_expn_of(span, "println") { - Some(span) => (span, "println"), - None => (span, "print"), - }; - - span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); - if_chain! { - // ensure we're calling Arguments::new_v1 - if args.len() == 1; - if let ExprKind::Call(ref args_fun, ref args_args) = args[0].node; - then { - // Check for literals in the print!/println! args - check_fmt_args_for_literal(cx, args_args, |span| { - span_lint(cx, PRINT_LITERAL, span, "printing a literal with an empty format string"); - }); - - if_chain! { - if let ExprKind::Path(ref qpath) = args_fun.node; - if let Some(const_def_id) = opt_def_id(resolve_node(cx, qpath, args_fun.hir_id)); - if match_def_path(cx.tcx, const_def_id, &paths::FMT_ARGUMENTS_NEWV1); - if args_args.len() == 2; - if let ExprKind::AddrOf(_, ref match_expr) = args_args[1].node; - if let ExprKind::Match(ref args, _, _) = match_expr.node; - if let ExprKind::Tup(ref args) = args.node; - if let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]); - then { - match name { - "print" => - if has_newline_end(args, fmtstr, fmtlen) { - span_lint(cx, PRINT_WITH_NEWLINE, span, - "using `print!()` with a format string that ends in a \ - newline, consider using `println!()` instead"); - }, - "println" => - if let Some(final_span) = has_empty_arg(cx, span, fmtstr, fmtlen) { - span_lint_and_sugg( - cx, - PRINT_WITH_NEWLINE, - final_span, - "using `println!(\"\")`", - "replace it with", - "println!()".to_string(), - ); - }, - _ => (), - } - } - } + } else if mac.node.path == "print" { + span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`"); + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) { + if fmtstr.ends_with("\\n") { + span_lint(cx, PRINT_WITH_NEWLINE, mac.span, + "using `print!()` with a format string that ends in a \ + newline, consider using `println!()` instead"); } } - } - } - // Search for something like - // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` - else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) { - if let ExprKind::Path(ref qpath) = args[1].node { - if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) { - if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) - && is_expn_of(expr.span, "panic").is_none() - { - span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting"); + } else if mac.node.path == "write" { + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) { + if fmtstr.ends_with("\\n") { + span_lint(cx, WRITE_WITH_NEWLINE, mac.span, + "using `write!()` with a format string that ends in a \ + newline, consider using `writeln!()` instead"); } } - } - } -} - -// Check for literals in write!/writeln! and print!/println! args -// ensuring the format string for the literal is `DISPLAY_FMT_METHOD` -// e.g., `writeln!(buf, "... {} ...", "foo")` -// ^ literal in `writeln!` -// e.g., `println!("... {} ...", "foo")` -// ^ literal in `println!` -fn check_fmt_args_for_literal<'a, 'tcx, F>(cx: &LateContext<'a, 'tcx>, args: &HirVec<Expr>, lint_fn: F) -where - F: Fn(Span), -{ - if_chain! { - if args.len() >= 2; - - // the match statement - if let ExprKind::AddrOf(_, ref match_expr) = args[1].node; - if let ExprKind::Match(ref matchee, ref arms, _) = match_expr.node; - if let ExprKind::Tup(ref tup) = matchee.node; - if arms.len() == 1; - if let ExprKind::Array(ref arm_body_exprs) = arms[0].body.node; - then { - // it doesn't matter how many args there are in the `write!`/`writeln!`, - // if there's one literal, we should warn the user - for (idx, tup_arg) in tup.iter().enumerate() { - if_chain! { - // first, make sure we're dealing with a literal (i.e., an ExprKind::Lit) - if let ExprKind::AddrOf(_, ref tup_val) = tup_arg.node; - if let ExprKind::Lit(_) = tup_val.node; - - // next, check the corresponding match arm body to ensure - // this is DISPLAY_FMT_METHOD - if let ExprKind::Call(_, ref body_args) = arm_body_exprs[idx].node; - if body_args.len() == 2; - if let ExprKind::Path(ref body_qpath) = body_args[1].node; - if let Some(fun_def_id) = opt_def_id(resolve_node(cx, body_qpath, body_args[1].hir_id)); - if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD); - then { - if args.len() == 2 { - lint_fn(tup_val.span); - } - - // ensure the format str has no options (e.g., width, precision, alignment, etc.) - // and is just "{}" - if_chain! { - if args.len() == 3; - if let ExprKind::AddrOf(_, ref format_expr) = args[2].node; - if let ExprKind::Array(ref format_exprs) = format_expr.node; - if format_exprs.len() >= 1; - if let ExprKind::Struct(_, ref fields, _) = format_exprs[idx].node; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == "format"); - if check_unformatted(&format_field.expr); - then { - lint_fn(tup_val.span); - } - } - } + } else if mac.node.path == "writeln" { + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) { + if fmtstr == "" { + span_lint_and_sugg( + cx, + WRITELN_EMPTY_STRING, + mac.span, + "using `writeln!(v, \"\")`", + "replace it with", + "writeln!(v)".to_string(), + ); } } } } } -/// Check for fmtstr = "... \n" -fn has_newline_end(args: &HirVec<Expr>, fmtstr: LocalInternedString, fmtlen: usize) -> bool { - if_chain! { - // check the final format string part - if let Some('\n') = fmtstr.chars().last(); - - // "foo{}bar" is made into two strings + one argument, - // if the format string starts with `{}` (eg. "{}foo"), - // the string array is prepended an empty string "". - // We only want to check the last string after any `{}`: - if args.len() < fmtlen; - then { - return true - } +fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Option<String> { + let tts = TokenStream::from(tts.clone()); + let mut parser = parser::Parser::new( + &cx.sess.parse_sess, + tts, + None, + false, + false, + ); + if is_write { + // skip the initial write target + parser.parse_expr().map_err(|mut err| err.cancel()).ok()?; + // might be `writeln!(foo)` + parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?; } - false -} - -/// Check for writeln!(v, "") / println!("") -fn has_empty_arg<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, fmtstr: LocalInternedString, fmtlen: usize) -> Option<Span> { - if_chain! { - // check that the string is empty - if fmtlen == 1; - if fmtstr.deref() == "\n"; - - // check the presence of that string - if let Ok(snippet) = cx.sess().codemap().span_to_snippet(span); - if snippet.contains("\"\""); - then { - if snippet.ends_with(';') { - return Some(cx.sess().codemap().span_until_char(span, ';')); - } - return Some(span) + let fmtstr = parser.parse_str().map_err(|mut err| err.cancel()).ok()?.0.to_string(); + use fmt_macros::*; + let tmp = fmtstr.clone(); + let mut args = vec![]; + let mut fmt_parser = Parser::new(&tmp, None); + while let Some(piece) = fmt_parser.next() { + if !fmt_parser.errors.is_empty() { + return None; } - } - None -} - -/// Returns the slice of format string parts in an `Arguments::new_v1` call. -fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(LocalInternedString, usize)> { - if_chain! { - if let ExprKind::AddrOf(_, ref expr) = expr.node; // &["…", "…", …] - if let ExprKind::Array(ref exprs) = expr.node; - if let Some(expr) = exprs.last(); - if let ExprKind::Lit(ref lit) = expr.node; - if let LitKind::Str(ref lit, _) = lit.node; - then { - return Some((lit.as_str(), exprs.len())); - } - } - None -} - -fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { - let map = &cx.tcx.hir; - - // `fmt` method - if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { - // `Debug` impl - if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) { - if let ItemKind::Impl(_, _, _, _, Some(ref tr), _, _) = item.node { - return match_path(&tr.path, &["Debug"]); + if let Piece::NextArgument(arg) = piece { + if arg.format.ty == "?" { + // FIXME: modify rustc's fmt string parser to give us the current span + span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting"); } + args.push(arg); } } - false -} - -/// Checks if the expression matches -/// ```rust,ignore -/// &[_ { -/// format: _ { -/// width: _::Implied, -/// ... -/// }, -/// ..., -/// }] -/// ``` -pub fn check_unformatted(format_field: &Expr) -> bool { - if_chain! { - if let ExprKind::Struct(_, ref fields, _) = format_field.node; - if let Some(width_field) = fields.iter().find(|f| f.ident.name == "width"); - if let ExprKind::Path(ref qpath) = width_field.expr.node; - if last_path_segment(qpath).ident.name == "Implied"; - if let Some(align_field) = fields.iter().find(|f| f.ident.name == "align"); - if let ExprKind::Path(ref qpath) = align_field.expr.node; - if last_path_segment(qpath).ident.name == "Unknown"; - if let Some(precision_field) = fields.iter().find(|f| f.ident.name == "precision"); - if let ExprKind::Path(ref qpath_precision) = precision_field.expr.node; - if last_path_segment(qpath_precision).ident.name == "Implied"; - then { - return true; + let lint = if is_write { + WRITE_LITERAL + } else { + PRINT_LITERAL + }; + let mut idx = 0; + loop { + if !parser.eat(&token::Comma) { + assert!(parser.eat(&token::Eof)); + return Some(fmtstr); + } + let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?; + const SIMPLE: FormatSpec = FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }; + match &expr.node { + ExprKind::Lit(_) => { + let mut all_simple = true; + let mut seen = false; + for arg in &args { + match arg.position { + | ArgumentImplicitlyIs(n) + | ArgumentIs(n) + => if n == idx { + all_simple &= arg.format == SIMPLE; + seen = true; + }, + ArgumentNamed(_) => {}, + } + } + if all_simple && seen { + span_lint(cx, lint, expr.span, "literal with an empty format string"); + } + idx += 1; + }, + ExprKind::Assign(lhs, rhs) => { + if let ExprKind::Path(_, p) = &lhs.node { + let mut all_simple = true; + let mut seen = false; + for arg in &args { + match arg.position { + | ArgumentImplicitlyIs(_) + | ArgumentIs(_) + => {}, + ArgumentNamed(name) => if *p == name { + seen = true; + all_simple &= arg.format == SIMPLE; + }, + } + } + if all_simple && seen { + span_lint(cx, lint, rhs.span, "literal with an empty format string"); + } + } + }, + _ => idx += 1, } } - - false } diff --git a/src/driver.rs b/src/driver.rs index 585edcd82a6..e9e81bb88e3 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -118,6 +118,7 @@ pub fn main() { for (name, to) in lint_groups { ls.register_group(Some(sess), true, name, to); } + clippy_lints::register_pre_expansion_lints(sess, &mut ls); sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); sess.plugin_attributes.borrow_mut().extend(attributes); diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index c17639aaf04..88f24d27dbc 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -22,7 +22,7 @@ fn main() { const BAD64_3: f64 = 0.100_000_000_000_000_000_1; // Literal as param - println!("{}", 8.888_888_888_888_888_888_888); + println!("{:?}", 8.888_888_888_888_888_888_888); // // TODO add inferred type tests for f32 // Locals diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index a167deac038..295846e9d7e 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -43,10 +43,10 @@ error: float has excessive precision | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:25:20 + --> $DIR/excessive_precision.rs:25:22 | -25 | println!("{}", 8.888_888_888_888_888_888_888); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` +25 | println!("{:?}", 8.888_888_888_888_888_888_888); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` error: float has excessive precision --> $DIR/excessive_precision.rs:36:22 diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index e0afc939b42..6554b6d3449 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -26,6 +26,23 @@ help: instead of prefixing all patterns with `&`, you can dereference the expres 32 | None => println!("none"), | +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/matches.rs:40:5 + | +40 | / match tup { +41 | | &(v, 1) => println!("{}", v), +42 | | _ => println!("none"), +43 | | } + | |_____^ +help: try this + | +40 | if let &(v, 1) = tup { +41 | # [ cfg ( not ( stage0 ) ) ] { +42 | ( $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ) ; } # [ +43 | cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( $ ( $ arg ) * ) ) } } else { +44 | ( $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ) ; } + | + error: you don't need to add `&` to all patterns --> $DIR/matches.rs:40:5 | @@ -350,5 +367,5 @@ error: use as_mut() instead 221 | | }; | |_____^ help: try this: `mut_owned.as_mut()` -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 4b95a1a9e70..c63b493db8d 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,3 +1,23 @@ +error: using `println!("")` + --> $DIR/non_expressive_names.rs:60:14 + | +60 | _ => println!(""), + | ^^^^^^^^^^^^ help: replace it with: `println!()` + | + = note: `-D println-empty-string` implied by `-D warnings` + +error: using `println!("")` + --> $DIR/non_expressive_names.rs:128:18 + | +128 | 1 => println!(""), + | ^^^^^^^^^^^^ help: replace it with: `println!()` + +error: using `println!("")` + --> $DIR/non_expressive_names.rs:132:18 + | +132 | 1 => println!(""), + | ^^^^^^^^^^^^ help: replace it with: `println!()` + error: binding's name is too similar to existing binding --> $DIR/non_expressive_names.rs:18:9 | @@ -167,5 +187,5 @@ error: consider choosing a more descriptive name 151 | let __1___2 = 12; | ^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/print.stderr b/tests/ui/print.stderr index 457ed38a1b5..f2d2afd9bf7 100644 --- a/tests/ui/print.stderr +++ b/tests/ui/print.stderr @@ -1,16 +1,22 @@ error: use of `Debug`-based formatting - --> $DIR/print.rs:13:27 + --> $DIR/print.rs:13:19 | 13 | write!(f, "{:?}", 43.1415) - | ^^^^^^^ + | ^^^^^^ | = note: `-D use-debug` implied by `-D warnings` +error: use of `Debug`-based formatting + --> $DIR/print.rs:20:19 + | +20 | write!(f, "{:?}", 42.718) + | ^^^^^^ + error: use of `println!` --> $DIR/print.rs:25:5 | 25 | println!("Hello"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: `-D print-stdout` implied by `-D warnings` @@ -18,37 +24,37 @@ error: use of `print!` --> $DIR/print.rs:26:5 | 26 | print!("Hello"); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: use of `print!` --> $DIR/print.rs:28:5 | 28 | print!("Hello {}", "World"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `print!` --> $DIR/print.rs:30:5 | 30 | print!("Hello {:?}", "World"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:30:26 + --> $DIR/print.rs:30:12 | 30 | print!("Hello {:?}", "World"); - | ^^^^^^^ + | ^^^^^^^^^^^^ error: use of `print!` --> $DIR/print.rs:32:5 | 32 | print!("Hello {:#?}", "#orld"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:32:27 + --> $DIR/print.rs:32:12 | 32 | print!("Hello {:#?}", "#orld"); - | ^^^^^^^ + | ^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index d1e4b49cbdd..39e0387cb5e 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,4 +1,4 @@ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:23:71 | 23 | println!("{} of {:b} people know binary, the other half doesn't", 1, 2); @@ -6,79 +6,79 @@ error: printing a literal with an empty format string | = note: `-D print-literal` implied by `-D warnings` -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:24:24 | 24 | print!("Hello {}", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:25:36 | 25 | println!("Hello {} {}", world, "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:26:26 | 26 | println!("Hello {}", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:27:30 | 27 | println!("10 / 4 is {}", 2.5); | ^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:28:28 | 28 | println!("2 + 1 = {}", 3); | ^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:33:25 | 33 | println!("{0} {1}", "hello", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:33:34 | 33 | println!("{0} {1}", "hello", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:34:25 | 34 | println!("{1} {0}", "hello", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:34:34 | 34 | println!("{1} {0}", "hello", "world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:37:33 | 37 | println!("{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:37:46 | 37 | println!("{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:38:33 | 38 | println!("{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ -error: printing a literal with an empty format string +error: literal with an empty format string --> $DIR/print_literal.rs:38:46 | 38 | println!("{bar} {foo}", foo="hello", bar="world"); diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 5f2013e728e..181f16b5cb7 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -2,9 +2,27 @@ error: using `print!()` with a format string that ends in a newline, consider us --> $DIR/print_with_newline.rs:7:5 | 7 | print!("Hello/n"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: `-D print-with-newline` implied by `-D warnings` -error: aborting due to previous error +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:8:5 + | +8 | print!("Hello {}/n", "world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:9:5 + | +9 | print!("Hello {} {}/n/n", "world", "#2"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:10:5 + | +10 | print!("{}/n", 1265); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 1148a4496a5..cff3f988052 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -4,7 +4,7 @@ error: using `println!("")` 3 | println!(""); | ^^^^^^^^^^^^ help: replace it with: `println!()` | - = note: `-D print-with-newline` implied by `-D warnings` + = note: `-D println-empty-string` implied by `-D warnings` error: using `println!("")` --> $DIR/println_empty_string.rs:6:14 diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 323a83e244a..70855ef8187 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -1,4 +1,4 @@ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:26:79 | 26 | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2); @@ -6,79 +6,79 @@ error: writing a literal with an empty format string | = note: `-D write-literal` implied by `-D warnings` -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:27:32 | 27 | write!(&mut v, "Hello {}", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:28:44 | 28 | writeln!(&mut v, "Hello {} {}", world, "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:29:34 | 29 | writeln!(&mut v, "Hello {}", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:30:38 | 30 | writeln!(&mut v, "10 / 4 is {}", 2.5); | ^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:31:36 | 31 | writeln!(&mut v, "2 + 1 = {}", 3); | ^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:36:33 | 36 | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:36:42 | 36 | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:37:33 | 37 | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:37:42 | 37 | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:40:41 | 40 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:40:54 | 40 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:41:41 | 41 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ -error: writing a literal with an empty format string +error: literal with an empty format string --> $DIR/write_literal.rs:41:54 | 41 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 37f03afb016..7bb9b99731f 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -2,7 +2,7 @@ error: using `write!()` with a format string that ends in a newline, consider us --> $DIR/write_with_newline.rs:10:5 | 10 | write!(&mut v, "Hello/n"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D write-with-newline` implied by `-D warnings` @@ -10,19 +10,19 @@ error: using `write!()` with a format string that ends in a newline, consider us --> $DIR/write_with_newline.rs:11:5 | 11 | write!(&mut v, "Hello {}/n", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead --> $DIR/write_with_newline.rs:12:5 | 12 | write!(&mut v, "Hello {} {}/n/n", "world", "#2"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead --> $DIR/write_with_newline.rs:13:5 | 13 | write!(&mut v, "{}/n", 1265); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/writeln_empty_string.stderr b/tests/ui/writeln_empty_string.stderr index b4649384865..16a8e0a203d 100644 --- a/tests/ui/writeln_empty_string.stderr +++ b/tests/ui/writeln_empty_string.stderr @@ -4,7 +4,7 @@ error: using `writeln!(v, "")` 9 | writeln!(&mut v, ""); | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)` | - = note: `-D write-with-newline` implied by `-D warnings` + = note: `-D writeln-empty-string` implied by `-D warnings` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From afd91248eda02cf2968e4e02c77b6c10ecd3fd4f Mon Sep 17 00:00:00 2001 From: Oliver Schneider <github35764891676564198441@oli-obk.de> Date: Mon, 23 Jul 2018 13:01:12 +0200 Subject: Rustup --- clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/attrs.rs | 16 +++--- clippy_lints/src/bit_mask.rs | 10 ++-- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/collapsible_if.rs | 8 +-- clippy_lints/src/const_static_lifetime.rs | 4 +- clippy_lints/src/consts.rs | 6 +-- clippy_lints/src/copies.rs | 6 +-- clippy_lints/src/cyclomatic_complexity.rs | 4 +- clippy_lints/src/doc.rs | 12 ++--- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/enum_glob_use.rs | 2 +- clippy_lints/src/enum_variants.rs | 6 +-- clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 4 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/formatting.rs | 12 ++--- clippy_lints/src/functions.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 4 +- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/int_plus_one.rs | 8 +-- clippy_lints/src/items_after_statements.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/len_zero.rs | 20 ++++---- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/literal_representation.rs | 10 ++-- clippy_lints/src/loops.rs | 28 +++++----- clippy_lints/src/map_clone.rs | 6 +-- clippy_lints/src/map_unit_fn.rs | 14 ++--- clippy_lints/src/matches.rs | 16 +++--- clippy_lints/src/methods.rs | 76 ++++++++++++++-------------- clippy_lints/src/minmax.rs | 4 +- clippy_lints/src/misc.rs | 12 ++--- clippy_lints/src/misc_early.rs | 12 ++--- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/multiple_crate_versions.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_continue.rs | 10 ++-- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 2 +- clippy_lints/src/no_effect.rs | 4 +- clippy_lints/src/non_expressive_names.rs | 6 +-- clippy_lints/src/open_options.rs | 4 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/precedence.rs | 2 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/question_mark.rs | 6 +-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/reference.rs | 4 +- clippy_lints/src/returns.rs | 12 ++--- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/strings.rs | 4 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/swap.rs | 6 +-- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/types.rs | 44 ++++++++-------- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unsafe_removed_from_name.rs | 6 +-- clippy_lints/src/unused_io_amount.rs | 4 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/higher.rs | 2 +- clippy_lints/src/utils/inspector.rs | 8 +-- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/utils/mod.rs | 54 ++++++++++---------- clippy_lints/src/utils/ptr.rs | 2 +- clippy_lints/src/utils/sugg.rs | 18 +++---- clippy_lints/src/utils/usage.rs | 4 +- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/write.rs | 4 +- src/lib.rs | 2 +- 81 files changed, 292 insertions(+), 292 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index b9de43762e0..cd2444ff31f 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { +fn check_lit(cx: &LateContext<'_, '_>, lit: &Lit, e: &Expr) { match lit.node { LitKind::Float(s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"), LitKind::Float(s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"), @@ -79,7 +79,7 @@ fn check_lit(cx: &LateContext, lit: &Lit, e: &Expr) { } } -fn check_known_consts(cx: &LateContext, e: &Expr, s: symbol::Symbol, module: &str) { +fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, module: &str) { let s = s.as_str(); if s.parse::<f64>().is_ok() { for &(constant, name, min_digits) in KNOWN_CONSTS { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6d4d333a8cb..3d25f524afd 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -226,7 +226,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { } } -fn is_relevant_item(tcx: TyCtxt, item: &Item) -> bool { +fn is_relevant_item(tcx: TyCtxt<'_, '_, '_>, item: &Item) -> bool { if let ItemKind::Fn(_, _, _, eid) = item.node { is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value) } else { @@ -234,14 +234,14 @@ fn is_relevant_item(tcx: TyCtxt, item: &Item) -> bool { } } -fn is_relevant_impl(tcx: TyCtxt, item: &ImplItem) -> bool { +fn is_relevant_impl(tcx: TyCtxt<'_, '_, '_>, item: &ImplItem) -> bool { match item.node { ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value), _ => false, } } -fn is_relevant_trait(tcx: TyCtxt, item: &TraitItem) -> bool { +fn is_relevant_trait(tcx: TyCtxt<'_, '_, '_>, item: &TraitItem) -> bool { match item.node { TraitItemKind::Method(_, TraitMethod::Required(_)) => true, TraitItemKind::Method(_, TraitMethod::Provided(eid)) => { @@ -251,7 +251,7 @@ fn is_relevant_trait(tcx: TyCtxt, item: &TraitItem) -> bool { } } -fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool { +fn is_relevant_block(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, block: &Block) -> bool { if let Some(stmt) = block.stmts.first() { match stmt.node { StmtKind::Decl(_, _) => true, @@ -262,7 +262,7 @@ fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> b } } -fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool { +fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr: &Expr) -> bool { match expr.node { ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block), ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e), @@ -280,7 +280,7 @@ fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool } } -fn check_attrs(cx: &LateContext, span: Span, name: Name, attrs: &[Attribute]) { +fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attribute]) { if in_macro(span) { return; } @@ -331,7 +331,7 @@ fn check_attrs(cx: &LateContext, span: Span, name: Name, attrs: &[Attribute]) { } } -fn check_semver(cx: &LateContext, span: Span, lit: &Lit) { +fn check_semver(cx: &LateContext<'_, '_>, span: Span, lit: &Lit) { if let LitKind::Str(ref is, _) = lit.node { if Version::parse(&is.as_str()).is_ok() { return; @@ -358,7 +358,7 @@ fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool { // sources that the user has no control over. // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. -fn is_present_in_source(cx: &LateContext, span: Span) -> bool { +fn is_present_in_source(cx: &LateContext<'_, '_>, span: Span) -> bool { if let Some(snippet) = snippet_opt(cx, span) { if snippet.is_empty() { return false; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 2e4e60c412a..249ebbde2f7 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -158,7 +158,7 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind { } -fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) { +fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) { if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node { if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr { return; @@ -169,7 +169,7 @@ fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: } } -fn check_bit_mask(cx: &LateContext, bit_op: BinOpKind, cmp_op: BinOpKind, mask_value: u128, cmp_value: u128, span: Span) { +fn check_bit_mask(cx: &LateContext<'_, '_>, bit_op: BinOpKind, cmp_op: BinOpKind, mask_value: u128, cmp_value: u128, span: Span) { match cmp_op { BinOpKind::Eq | BinOpKind::Ne => match bit_op { BinOpKind::BitAnd => if mask_value & cmp_value != cmp_value { @@ -270,7 +270,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOpKind, cmp_op: BinOpKind, mask_v } } -fn check_ineffective_lt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str) { +fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) { if c.is_power_of_two() && m < c { span_lint( cx, @@ -286,7 +286,7 @@ fn check_ineffective_lt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str } } -fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str) { +fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) { if (c + 1).is_power_of_two() && m <= c { span_lint( cx, @@ -302,7 +302,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str } } -fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> { +fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr) -> Option<u128> { match constant(cx, cx.tables, lit)?.0 { Constant::Int(n) => Some(n), _ => None, diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 7d627f49836..f1596476bfd 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } // The boolean part of the return indicates whether some simplifications have been applied. -fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> (String, bool) { +fn suggest(cx: &LateContext<'_, '_>, suggestion: &Bool, terminals: &[&Expr]) -> (String, bool) { let mut suggest_context = SuggestContext { terminals, cx, diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index f66c376c864..2d4279d3cc1 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -38,7 +38,7 @@ impl LintPass for ByteCount { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount { - fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) { if_chain! { if let ExprKind::MethodCall(ref count, _, ref count_args) = expr.node; if count.ident.name == "count"; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b7793519602..2771006aad3 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -80,14 +80,14 @@ impl LintPass for CollapsibleIf { } impl EarlyLintPass for CollapsibleIf { - fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if !in_macro(expr.span) { check_if(cx, expr) } } } -fn check_if(cx: &EarlyContext, expr: &ast::Expr) { +fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { match expr.node { ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ { check_collapsible_maybe_if_let(cx, else_); @@ -101,7 +101,7 @@ fn check_if(cx: &EarlyContext, expr: &ast::Expr) { } } -fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) { +fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) { if_chain! { if let ast::ExprKind::Block(ref block, _) = else_.node; if let Some(else_) = expr_block(block); @@ -122,7 +122,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_chain! { if let Some(inner) = expr_block(then); if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node; diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index 8bb209a6490..1af0741d67f 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -35,7 +35,7 @@ impl LintPass for StaticConst { impl StaticConst { // Recursively visit types - fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext) { + fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) { match ty.node { // Be careful of nested structures (arrays and tuples) TyKind::Array(ref ty, _) => { @@ -79,7 +79,7 @@ impl StaticConst { } impl EarlyLintPass for StaticConst { - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if !in_macro(item.span) { // Match only constants... if let ItemKind::Const(ref var_type, _) = item.node { diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 878ad276343..84167553a54 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -123,7 +123,7 @@ impl Hash for Constant { } impl Constant { - pub fn partial_cmp(tcx: TyCtxt, cmp_type: &ty::TypeVariants, left: &Self, right: &Self) -> Option<Ordering> { + pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: &ty::TypeVariants<'_>, left: &Self, right: &Self) -> Option<Ordering> { match (left, right) { (&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)), (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), @@ -236,7 +236,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } } - fn constant_not(&self, o: &Constant, ty: ty::Ty) -> Option<Constant> { + fn constant_not(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> { use self::Constant::*; match *o { Bool(b) => Some(Bool(!b)), @@ -252,7 +252,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } } - fn constant_negate(&self, o: &Constant, ty: ty::Ty) -> Option<Constant> { + fn constant_negate(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> { use self::Constant::*; match *o { Int(value) => { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index c0830c5ea31..5709526c600 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -134,7 +134,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { } /// Implementation of `IF_SAME_THEN_ELSE`. -fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { +fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block]) { let eq: &dyn Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) }; if let Some((i, j)) = search_same_sequenced(blocks, eq) { @@ -150,7 +150,7 @@ fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) { } /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { +fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) { let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 { let mut h = SpanlessHash::new(cx, cx.tables); h.hash_expr(expr); @@ -172,7 +172,7 @@ fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) { } /// Implementation of `MATCH_SAME_ARMS`. -fn lint_match_arms(cx: &LateContext, expr: &Expr) { +fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) { if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.node { let hash = |&(_, arm): &(usize, &Arm)| -> u64 { let mut h = SpanlessHash::new(cx, cx.tables); diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index c397ca7824e..d66e6f2849b 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> { #[cfg(feature = "debugging")] #[allow(too_many_arguments)] -fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) { +fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) { span_bug!( span, "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ @@ -201,7 +201,7 @@ fn report_cc_bug(_: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, re } #[cfg(not(feature = "debugging"))] #[allow(too_many_arguments)] -fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) { +fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) { if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) { cx.sess().span_note_without_error( span, diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index a298137976b..2b11e8fa77d 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -52,11 +52,11 @@ impl LintPass for Doc { } impl EarlyLintPass for Doc { - fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { check_attrs(cx, &self.valid_idents, &krate.attrs); } - fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { check_attrs(cx, &self.valid_idents, &item.attrs); } } @@ -139,7 +139,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<( panic!("not a doc-comment: {}", comment); } -pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) { +pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'a [ast::Attribute]) { let mut doc = String::new(); let mut spans = vec![]; @@ -186,7 +186,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [a } fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( - cx: &EarlyContext, + cx: &EarlyContext<'_>, valid_idents: &[String], docs: Events, spans: &[(usize, Span)], @@ -232,7 +232,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>( } } -fn check_text(cx: &EarlyContext, valid_idents: &[String], text: &str, span: Span) { +fn check_text(cx: &EarlyContext<'_>, valid_idents: &[String], text: &str, span: Span) { for word in text.split_whitespace() { // Trim punctuation as in `some comment (see foo::bar).` // ^^ @@ -255,7 +255,7 @@ fn check_text(cx: &EarlyContext, valid_idents: &[String], text: &str, span: Span } } -fn check_word(cx: &EarlyContext, word: &str, span: Span) { +fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) { /// Checks if a string is camel-case, ie. contains at least two uppercase /// letter (`Clippy` is /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 2617eab0aa7..abd5666385d 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -31,7 +31,7 @@ impl LintPass for DoubleParens { } impl EarlyLintPass for DoubleParens { - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { match expr.node { ExprKind::Paren(ref in_paren) => match in_paren.node { ExprKind::Paren(_) | ExprKind::Tup(_) => { diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index b8406904821..d3560434a31 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -49,7 +49,7 @@ impl LintPass for ElseIfWithoutElse { } impl EarlyLintPass for ElseIfWithoutElse { - fn check_expr(&mut self, cx: &EarlyContext, mut item: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) { if in_external_macro(cx, item.span) { return; } diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 803ba34a865..f95ae32d561 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -33,7 +33,7 @@ impl LintPass for EmptyEnum { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { - fn check_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) { let did = cx.tcx.hir.local_def_id(item.id); if let ItemKind::Enum(..) = item.node { let ty = cx.tcx.type_of(did); diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 10cf497725c..6f8afc710de 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { } impl EnumGlobUse { - fn lint_item(&self, cx: &LateContext, item: &Item) { + fn lint_item(&self, cx: &LateContext<'_, '_>, item: &Item) { if item.vis.node.is_pub() { return; // re-exports are fine } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 6a14638057a..16c9212e5db 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -149,7 +149,7 @@ fn partial_rmatch(post: &str, name: &str) -> usize { // FIXME: #600 #[allow(while_let_on_iterator)] fn check_variant( - cx: &EarlyContext, + cx: &EarlyContext<'_>, threshold: u64, def: &EnumDef, item_name: &str, @@ -240,12 +240,12 @@ fn to_camel_case(item_name: &str) -> String { } impl EarlyLintPass for EnumVariantNames { - fn check_item_post(&mut self, _cx: &EarlyContext, _item: &Item) { + fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) { let last = self.modules.pop(); assert!(last.is_some()); } - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { let item_name = item.ident.as_str(); let item_name_chars = item_name.chars().count(); let item_camel = to_camel_case(&item_name); diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 102769a375e..4960a48b3c8 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -50,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp { } } -fn check(cx: &LateContext, e: &Expr, span: Span) { +fn check(cx: &LateContext<'_, '_>, e: &Expr, span: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) { if v == 0 { span_lint( diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index ff5c85b6009..ebbc2c34811 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { "using `Box<T>` where unnecessary" } -fn is_non_trait_box(ty: Ty) -> bool { +fn is_non_trait_box(ty: Ty<'_>) -> bool { ty.is_box() && !ty.boxed_ty().is_trait() } @@ -137,7 +137,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } } - fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region, _: ty::BorrowKind, loan_cause: LoanCause) { + fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, loan_cause: LoanCause) { if let Categorization::Local(lid) = cmt.cat { match loan_cause { // x.foo() diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 7b6623ed29b..2071628a6cf 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass { } } -fn check_closure(cx: &LateContext, expr: &Expr) { +fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) { if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node { let body = cx.tcx.hir.body(eid); let ex = &body.value; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index b0295d2e7d4..7ccf8c31569 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -175,7 +175,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { /// logical operators are considered to have a defined evaluation order. /// /// When such a read is found, the lint is triggered. -fn check_for_unsequenced_reads(vis: &mut ReadVisitor) { +fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { let map = &vis.cx.tcx.hir; let mut cur_id = vis.write_expr.id; loop { @@ -348,7 +348,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { } /// Returns true if `expr` is the LHS of an assignment, like `expr = ...`. -fn is_in_assignment_position(cx: &LateContext, expr: &Expr) -> bool { +fn is_in_assignment_position(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { if let ExprKind::Assign(ref lhs, _) = parent.node { return lhs.id == expr.id; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 18c3d807f1a..3db644911d7 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -128,7 +128,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it } } -fn match_type(tcx: ty::TyCtxt, ty: ty::Ty, path: &[&str]) -> bool { +fn match_type(tcx: ty::TyCtxt<'_, '_, '_>, ty: ty::Ty<'_>, path: &[&str]) -> bool { match ty.sty { ty::TyAdt(adt, _) => match_def_path(tcx, adt.did, path), _ => false, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 668ef3dbf6e..80fc4c3acfe 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -105,7 +105,7 @@ fn check_single_piece(expr: &Expr) -> bool { /// ``` /// and that type of `__arg0` is `&str` or `String` /// then returns the span of first element of the matched tuple -fn get_single_string_arg(cx: &LateContext, expr: &Expr) -> Option<Span> { +fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span> { if_chain! { if let ExprKind::AddrOf(_, ref expr) = expr.node; if let ExprKind::Match(ref match_expr, ref arms, _) = expr.node; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 784461c23ee..60001c792c0 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -83,7 +83,7 @@ impl LintPass for Formatting { } impl EarlyLintPass for Formatting { - fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { for w in block.stmts.windows(2) { match (&w[0].node, &w[1].node) { (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) | @@ -95,7 +95,7 @@ impl EarlyLintPass for Formatting { } } - fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { check_assign(cx, expr); check_else_if(cx, expr); check_array(cx, expr); @@ -103,7 +103,7 @@ impl EarlyLintPass for Formatting { } /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. -fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { +fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) { if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node { if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) { let eq_span = lhs.span.between(rhs.span); @@ -132,7 +132,7 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) { } /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`. -fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { +fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) { if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) { // this will be a span from the closing ‘}’ of the “then” block (excluding) to @@ -164,7 +164,7 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { } /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array -fn check_array(cx: &EarlyContext, expr: &ast::Expr) { +fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) { if let ast::ExprKind::Array(ref array) = expr.node { for element in array { if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node { @@ -190,7 +190,7 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) { } /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. -fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { +fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) { if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() && unsugar_if(second).is_some() { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index d9f50d652d3..8903766c330 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -128,7 +128,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } impl<'a, 'tcx> Functions { - fn check_arg_number(self, cx: &LateContext, decl: &hir::FnDecl, span: Span) { + fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) { let args = decl.inputs.len() as u64; if args > self.threshold { span_lint( diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 3a8a366890a..23b34362171 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { } #[allow(cast_possible_wrap)] -fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) { +fn check(cx: &LateContext<'_, '_>, e: &Expr, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) { let check = match cx.tables.expr_ty(e).sty { ty::TyInt(ity) => unsext(cx.tcx, -1i128, ity), diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index eea83ca6b88..915bc28f751 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -47,7 +47,7 @@ impl LintPass for IfNotElse { } impl EarlyLintPass for IfNotElse { - fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if in_external_macro(cx, item.span) { return; } diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index aaea60f2c05..677f59d32cc 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { /// the range. fn to_const_range<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - range: Range, + range: Range<'_>, array_size: u128, ) -> Option<(u128, u128)> { let s = range diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 3f461a07ab2..eaa93cb62f8 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -140,7 +140,7 @@ static HEURISTICS: &[(&str, usize, Heuristic, Finiteness)] = &[ ("scan", 3, First, MaybeInfinite), ]; -fn is_infinite(cx: &LateContext, expr: &Expr) -> Finiteness { +fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { match expr.node { ExprKind::MethodCall(ref method, _, ref args) => { for &(name, len, heuristic, cap) in HEURISTICS.iter() { @@ -204,7 +204,7 @@ static COMPLETING_METHODS: &[(&str, usize)] = &[ ("product", 1), ]; -fn complete_infinite_iter(cx: &LateContext, expr: &Expr) -> Finiteness { +fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness { match expr.node { ExprKind::MethodCall(ref method, _, ref args) => { for &(name, len) in COMPLETING_METHODS.iter() { diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index b308e3ca81f..70f88a76f45 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn check_attrs(cx: &LateContext, name: Name, attrs: &[Attribute]) { +fn check_attrs(cx: &LateContext<'_, '_>, name: Name, attrs: &[Attribute]) { for attr in attrs { if attr.name() != "inline" { continue; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 490d06f259f..9b6fc579a31 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -61,7 +61,7 @@ impl IntPlusOne { false } - fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> { + fn check_binop(&self, cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> { match (binop, &lhs.node, &rhs.node) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { @@ -127,7 +127,7 @@ impl IntPlusOne { fn generate_recommendation( &self, - cx: &EarlyContext, + cx: &EarlyContext<'_>, binop: BinOpKind, node: &Expr, other_side: &Expr, @@ -150,7 +150,7 @@ impl IntPlusOne { None } - fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) { + fn emit_warning(&self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| { db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation); }); @@ -158,7 +158,7 @@ impl IntPlusOne { } impl EarlyLintPass for IntPlusOne { - fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node { if let Some(ref rec) = self.check_binop(cx, kind.node, lhs, rhs) { self.emit_warning(cx, item, rec.clone()); diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 1d0382748ee..07ef086d694 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -43,7 +43,7 @@ impl LintPass for ItemsAfterStatements { } impl EarlyLintPass for ItemsAfterStatements { - fn check_block(&mut self, cx: &EarlyContext, item: &Block) { + fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { if in_macro(item.span) { return; } diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index f29e5040354..2c03b6b5f68 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -48,7 +48,7 @@ impl LintPass for LargeEnumVariant { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { - fn check_item(&mut self, cx: &LateContext, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) { let did = cx.tcx.hir.local_def_id(item.id); if let ItemKind::Enum(ref def, _) = item.node { let ty = cx.tcx.type_of(did); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e3ff60d30a2..b73f912fad5 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -106,8 +106,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { } } -fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[TraitItemRef]) { - fn is_named_self(cx: &LateContext, item: &TraitItemRef, name: &str) -> bool { +fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) { + fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool { item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { has_self && { let did = cx.tcx.hir.local_def_id(item.id.node_id); @@ -119,7 +119,7 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai } // fill the set with current and super traits - fn fill_trait_set(traitt: DefId, set: &mut HashSet<DefId>, cx: &LateContext) { + fn fill_trait_set(traitt: DefId, set: &mut HashSet<DefId>, cx: &LateContext<'_, '_>) { if set.insert(traitt) { for supertrait in ::rustc::traits::supertrait_def_ids(cx.tcx, traitt) { fill_trait_set(supertrait, set, cx); @@ -154,8 +154,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai } } -fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { - fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool { +fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) { + fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool { item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { has_self && { let did = cx.tcx.hir.local_def_id(item.id.node_id); @@ -194,7 +194,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) { } } -fn check_cmp(cx: &LateContext, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) { +fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) { if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { @@ -207,7 +207,7 @@ fn check_cmp(cx: &LateContext, span: Span, method: &Expr, lit: &Expr, op: &str, } } -fn check_len(cx: &LateContext, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) { +fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) { if let Spanned { node: LitKind::Int(lit, _), .. @@ -232,9 +232,9 @@ fn check_len(cx: &LateContext, span: Span, method_name: Name, args: &[Expr], lit } /// Check if this type has an `is_empty` method. -fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool { +fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`. - fn is_is_empty(cx: &LateContext, item: &ty::AssociatedItem) -> bool { + fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool { if let ty::AssociatedKind::Method = item.kind { if item.ident.name == "is_empty" { let sig = cx.tcx.fn_sig(item.def_id); @@ -249,7 +249,7 @@ 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 { + fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool { cx.tcx.inherent_impls(id).iter().any(|imp| { cx.tcx .associated_items(*imp) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 53a37f23fa4..b08449d2beb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -181,7 +181,7 @@ pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &m } #[cfg_attr(rustfmt, rustfmt_skip)] -pub fn register_plugins(reg: &mut rustc_plugin::Registry) { +pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) { let conf = match utils::conf::file_from_args(reg.args()) { Ok(file_name) => { // if the user specified a file, it must exist, otherwise default to `clippy.toml` but diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index bb5a923eaf9..383bba2d4bd 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -229,7 +229,7 @@ enum WarningType { } impl WarningType { - crate fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: syntax_pos::Span) { + crate fn display(&self, grouping_hint: &str, cx: &EarlyContext<'_>, span: syntax_pos::Span) { match self { WarningType::UnreadableLiteral => span_lint_and_sugg( cx, @@ -281,7 +281,7 @@ impl LintPass for LiteralDigitGrouping { } impl EarlyLintPass for LiteralDigitGrouping { - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } @@ -293,7 +293,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } impl LiteralDigitGrouping { - fn check_lit(self, cx: &EarlyContext, lit: &Lit) { + fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { match lit.node { LitKind::Int(..) => { // Lint integral literals. @@ -421,7 +421,7 @@ impl LintPass for LiteralRepresentation { } impl EarlyLintPass for LiteralRepresentation { - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } @@ -438,7 +438,7 @@ impl LiteralRepresentation { threshold, } } - fn check_lit(self, cx: &EarlyContext, lit: &Lit) { + fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { // Lint integral literals. if_chain! { if let LitKind::Int(..) = lit.node; diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 86580c27cff..23830c566df 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -743,7 +743,7 @@ struct FixedOffsetVar { offset: Offset, } -fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty) -> bool { +fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool { let is_slice = match ty.sty { ty::TyRef(_, subty, _) => is_slice_like(cx, subty), ty::TySlice(..) | ty::TyArray(..) => true, @@ -1185,7 +1185,7 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx } } -fn lint_iter_method(cx: &LateContext, args: &[Expr], arg: &Expr, method_name: &str) { +fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) { let object = snippet(cx, args[0].span, "_"); let muta = if method_name == "iter_mut" { "mut " @@ -1203,7 +1203,7 @@ fn lint_iter_method(cx: &LateContext, args: &[Expr], arg: &Expr, method_name: &s ) } -fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { +fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Expr) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used if let ExprKind::MethodCall(ref method, _, ref args) = arg.node { // just the receiver, no arguments @@ -1258,7 +1258,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) { } /// Check for `for` loops over `Option`s and `Results` -fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) { +fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr) { let ty = cx.tables.expr_ty(arg); if match_type(cx, ty, &paths::OPTION) { span_help_and_lint( @@ -1420,7 +1420,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate { fn consume_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, _: NodeId, sp: Span, cmt: &cmt_<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) { + fn borrow(&mut self, _: NodeId, sp: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) { if let ty::BorrowKind::MutBorrow = bk { if let Categorization::Local(id) = cmt.cat { if Some(id) == self.node_id_low { @@ -1453,7 +1453,7 @@ impl<'tcx> MutatePairDelegate { } } -fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { +fn check_for_mut_range_bound(cx: &LateContext<'_, '_>, arg: &Expr, body: &Expr) { if let Some(higher::Range { start: Some(start), end: Some(end), @@ -1472,7 +1472,7 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { } } -fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) { +fn mut_warn_with_span(cx: &LateContext<'_, '_>, span: Option<Span>) { if let Some(sp) = span { span_lint( cx, @@ -1483,7 +1483,7 @@ fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) { } } -fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> { +fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId> { if_chain! { if let ExprKind::Path(ref qpath) = bound.node; if let QPath::Resolved(None, _) = *qpath; @@ -1505,7 +1505,7 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> { None } -fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) { +fn check_for_mutation(cx: &LateContext<'_, '_>, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) { let mut delegate = MutatePairDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], @@ -1782,7 +1782,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { /// Return true if the type of expr is one that provides `IntoIterator` impls /// for `&T` and `&mut T`, such as `Vec`. #[cfg_attr(rustfmt, rustfmt_skip)] -fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { +fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards let ty = cx.tables.expr_ty(e); @@ -1797,7 +1797,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { match_type(cx, ty, &paths::BTREESET) } -fn is_iterable_array(ty: Ty, cx: &LateContext) -> bool { +fn is_iterable_array(ty: Ty<'_>, cx: &LateContext<'_, '_>) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { ty::TyArray(_, n) => (0..=32).contains(&n.assert_usize(cx.tcx).expect("array length")), @@ -2006,7 +2006,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } -fn var_def_id(cx: &LateContext, expr: &Expr) -> Option<NodeId> { +fn var_def_id(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<NodeId> { if let ExprKind::Path(ref qpath) = expr.node { let path_res = cx.tables.qpath_def(qpath, expr.hir_id); if let Def::Local(node_id) = path_res { @@ -2030,7 +2030,7 @@ fn is_conditional(expr: &Expr) -> bool { } } -fn is_nested(cx: &LateContext, match_expr: &Expr, iter_expr: &Expr) -> bool { +fn is_nested(cx: &LateContext<'_, '_>, match_expr: &Expr, iter_expr: &Expr) -> bool { if_chain! { if let Some(loop_block) = get_enclosing_block(cx, match_expr.id); if let Some(map::Node::NodeExpr(loop_expr)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(loop_block.id)); @@ -2041,7 +2041,7 @@ fn is_nested(cx: &LateContext, match_expr: &Expr, iter_expr: &Expr) -> bool { false } -fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool { +fn is_loop_nested(cx: &LateContext<'_, '_>, loop_expr: &Expr, iter_expr: &Expr) -> bool { let mut id = loop_expr.id; let iter_name = if let Some(name) = path_name(iter_expr) { name diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 0c427c5ffe4..d8b14db605f 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -100,7 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn expr_eq_name(cx: &LateContext, expr: &Expr, id: ast::Ident) -> bool { +fn expr_eq_name(cx: &LateContext<'_, '_>, expr: &Expr, id: ast::Ident) -> bool { match expr.node { ExprKind::Path(QPath::Resolved(None, ref path)) => { let arg_segment = [ @@ -116,7 +116,7 @@ fn expr_eq_name(cx: &LateContext, expr: &Expr, id: ast::Ident) -> bool { } } -fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static str> { +fn get_type_name(cx: &LateContext<'_, '_>, expr: &Expr, arg: &Expr) -> Option<&'static str> { if match_trait_method(cx, expr, &paths::ITERATOR) { Some("iterator") } else if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(arg)), &paths::OPTION) { @@ -126,7 +126,7 @@ fn get_type_name(cx: &LateContext, expr: &Expr, arg: &Expr) -> Option<&'static s } } -fn only_derefs(cx: &LateContext, expr: &Expr, id: ast::Ident) -> bool { +fn only_derefs(cx: &LateContext<'_, '_>, expr: &Expr, id: ast::Ident) -> bool { match expr.node { ExprKind::Unary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id), _ => expr_eq_name(cx, expr, id), diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index bd5613d0b48..6ccf8daa71d 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -84,7 +84,7 @@ impl LintPass for Pass { } } -fn is_unit_type(ty: ty::Ty) -> bool { +fn is_unit_type(ty: ty::Ty<'_>) -> bool { match ty.sty { ty::TyTuple(slice) => slice.is_empty(), ty::TyNever => true, @@ -92,7 +92,7 @@ fn is_unit_type(ty: ty::Ty) -> bool { } } -fn is_unit_function(cx: &LateContext, expr: &hir::Expr) -> bool { +fn is_unit_function(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> bool { let ty = cx.tables.expr_ty(expr); if let ty::TyFnDef(id, _) = ty.sty { @@ -103,7 +103,7 @@ fn is_unit_function(cx: &LateContext, expr: &hir::Expr) -> bool { false } -fn is_unit_expression(cx: &LateContext, expr: &hir::Expr) -> bool { +fn is_unit_expression(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> bool { is_unit_type(cx.tables.expr_ty(expr)) } @@ -111,7 +111,7 @@ fn is_unit_expression(cx: &LateContext, expr: &hir::Expr) -> bool { /// semicolons, which causes problems when generating a suggestion. Given an /// expression that evaluates to '()' or '!', recursively remove useless braces /// and semi-colons until is suitable for including in the suggestion template -fn reduce_unit_expression<'a>(cx: &LateContext, expr: &'a hir::Expr) -> Option<Span> { +fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) -> Option<Span> { if !is_unit_expression(cx, expr) { return None; } @@ -175,7 +175,7 @@ fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Op /// `y` => `_y` /// /// Anything else will return `_`. -fn let_binding_name(cx: &LateContext, var_arg: &hir::Expr) -> String { +fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String { match &var_arg.node { hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"), hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")), @@ -191,7 +191,7 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String { ) } -fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) { +fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) { let var_arg = &map_args[0]; let fn_arg = &map_args[1]; @@ -244,7 +244,7 @@ fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_ar } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_stmt(&mut self, cx: &LateContext, stmt: &hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt) { if in_macro(stmt.span) { return; } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 65c360922b2..10d4d94cb91 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -200,7 +200,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass { } #[cfg_attr(rustfmt, rustfmt_skip)] -fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { +fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && arms[1].guard.is_none() { @@ -222,13 +222,13 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { } } -fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { +fn check_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { if is_wild(&arms[1].pats[0]) { report_single_match_single_pattern(cx, ex, arms, expr, els); } } -fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { +fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { @@ -252,7 +252,7 @@ fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], ); } -fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty, els: Option<&Expr>) { +fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty<'_>, els: Option<&Expr>) { // list of candidate Enums we know will never get any more members let candidates = &[ (&paths::COW, "Borrowed"), @@ -284,7 +284,7 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: } } -fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { +fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) { // type of expression == bool if cx.tables.expr_ty(ex).sty == ty::TyBool { span_lint_and_then( @@ -365,7 +365,7 @@ fn is_wild(pat: &impl std::ops::Deref<Target = Pat>) -> bool { } } -fn check_wild_err_arm(cx: &LateContext, ex: &Expr, arms: &[Arm]) { +fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) { let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex)); if match_type(cx, ex_ty, &paths::RESULT) { for arm in arms { @@ -405,7 +405,7 @@ fn is_panic_block(block: &Block) -> bool { } } -fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { +fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) { if has_only_ref_pats(arms) { let mut suggs = Vec::new(); let (title, msg) = if let ExprKind::AddrOf(Mutability::MutImmutable, ref inner) = ex.node { @@ -436,7 +436,7 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) } } -fn check_match_as_ref(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { +fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && arms[1].guard.is_none() { diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 3ebad1d705b..c1ae61dd271 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -876,10 +876,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } /// Checks for the `OR_FUN_CALL` lint. -fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { +fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. fn check_unwrap_or_default( - cx: &LateContext, + cx: &LateContext<'_, '_>, name: &str, fun: &hir::Expr, self_expr: &hir::Expr, @@ -924,7 +924,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, name: /// Check for `*or(foo())`. #[allow(too_many_arguments)] fn check_general_case( - cx: &LateContext, + cx: &LateContext<'_, '_>, name: &str, method_span: Span, fun_span: Span, @@ -967,7 +967,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, name: return; } - let sugg: Cow<_> = match (fn_has_arguments, !or_has_args) { + let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(), (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(), (false, true) => snippet(cx, fun_span, ".."), @@ -1000,7 +1000,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, name: } /// Checks for the `EXPECT_FUN_CALL` lint. -fn lint_expect_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { +fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { fn extract_format_args(arg: &hir::Expr) -> Option<&hir::HirVec<hir::Expr>> { if let hir::ExprKind::AddrOf(_, ref addr_of) = arg.node { if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = addr_of.node { @@ -1015,7 +1015,7 @@ fn lint_expect_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, n None } - fn generate_format_arg_snippet(cx: &LateContext, a: &hir::Expr) -> String { + fn generate_format_arg_snippet(cx: &LateContext<'_, '_>, a: &hir::Expr) -> String { if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node { if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node { if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node { @@ -1028,7 +1028,7 @@ fn lint_expect_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, n } fn check_general_case( - cx: &LateContext, + cx: &LateContext<'_, '_>, name: &str, method_span: Span, self_expr: &hir::Expr, @@ -1079,7 +1079,7 @@ fn lint_expect_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, n return; } - let sugg: Cow<_> = snippet(cx, arg.span, ".."); + let sugg: Cow<'_, _> = snippet(cx, arg.span, ".."); span_lint_and_sugg( cx, @@ -1100,7 +1100,7 @@ fn lint_expect_fun_call(cx: &LateContext, expr: &hir::Expr, method_span: Span, n } /// Checks for the `CLONE_ON_COPY` lint. -fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty) { +fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'_>) { let ty = cx.tables.expr_ty(expr); if let ty::TyRef(_, inner, _) = arg_ty.sty { if let ty::TyRef(_, innermost, _) = inner.sty { @@ -1168,7 +1168,7 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t } } -fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { +fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr) { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg)); if let ty::TyAdt(_, subst) = obj_ty.sty { @@ -1194,7 +1194,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { } -fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { +fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { let arg = &args[1]; if let Some(arglists) = method_chain_args(arg, &["chars"]) { let target = &arglists[0][0]; @@ -1223,14 +1223,14 @@ fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { } } -fn lint_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { +fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); if match_type(cx, obj_ty, &paths::STRING) { lint_string_extend(cx, expr, args); } } -fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) { +fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) { if_chain! { if let hir::ExprKind::Call(ref fun, ref args) = new.node; if args.len() == 1; @@ -1251,7 +1251,7 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr } } -fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) { +fn lint_iter_cloned_collect(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr]) { if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) && derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() { @@ -1265,7 +1265,7 @@ fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir } } -fn lint_unnecessary_fold(cx: &LateContext, expr: &hir::Expr, fold_args: &[hir::Expr]) { +fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr]) { // Check that this is a call to Iterator::fold rather than just some function called fold if !match_trait_method(cx, expr, &paths::ITERATOR) { return; @@ -1275,7 +1275,7 @@ fn lint_unnecessary_fold(cx: &LateContext, expr: &hir::Expr, fold_args: &[hir::E "Expected fold_args to have three entries - the receiver, the initial value and the closure"); fn check_fold_with_op( - cx: &LateContext, + cx: &LateContext<'_, '_>, fold_args: &[hir::Expr], op: hir::BinOpKind, replacement_method_name: &str, @@ -1353,7 +1353,7 @@ fn lint_unnecessary_fold(cx: &LateContext, expr: &hir::Expr, fold_args: &[hir::E }; } -fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) { +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.tables.expr_ty(&iter_args[0])).is_some() { "slice" @@ -1377,7 +1377,7 @@ fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is ); } -fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) { +fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) { // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap, // because they do not implement `IndexMut` let expr_ty = cx.tables.expr_ty(&get_args[0]); @@ -1416,7 +1416,7 @@ fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], i ); } -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( @@ -1428,8 +1428,8 @@ fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr) { } } -fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: Ty) -> Option<sugg::Sugg<'static>> { - fn may_slice(cx: &LateContext, ty: Ty) -> bool { +fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Option<sugg::Sugg<'static>> { + fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool { match ty.sty { ty::TySlice(_) => true, ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), @@ -1461,7 +1461,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: Ty) -> Option<sugg::S } /// lint use of `unwrap()` for `Option`s and `Result`s -fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &[hir::Expr]) { +fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::Expr]) { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0])); let mess = if match_type(cx, obj_ty, &paths::OPTION) { @@ -1489,7 +1489,7 @@ fn lint_unwrap(cx: &LateContext, expr: &hir::Expr, unwrap_args: &[hir::Expr]) { } /// lint use of `ok().expect()` for `Result`s -fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &[hir::Expr]) { +fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr, ok_args: &[hir::Expr]) { // lint if the caller of `ok()` is a `Result` if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT) { let result_type = cx.tables.expr_ty(&ok_args[0]); @@ -1507,7 +1507,7 @@ fn lint_ok_expect(cx: &LateContext, expr: &hir::Expr, ok_args: &[hir::Expr]) { } /// lint use of `map().unwrap_or()` for `Option`s -fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr], unwrap_args: &[hir::Expr]) { +fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hir::Expr], unwrap_args: &[hir::Expr]) { // lint if the caller of `map()` is an `Option` if match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION) { // get snippets for args to map() and unwrap_or() @@ -1765,7 +1765,7 @@ struct BinaryExprInfo<'a> { } /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. -fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, info: &mut BinaryExprInfo) { +fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut BinaryExprInfo<'_>) { macro_rules! lint_with_both_lhs_and_rhs { ($func:ident, $cx:expr, $info:ident) => { if !$func($cx, $info) { @@ -1784,9 +1784,9 @@ fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, i } /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints. -fn lint_chars_cmp<'a, 'tcx>( - cx: &LateContext<'a, 'tcx>, - info: &BinaryExprInfo, +fn lint_chars_cmp( + cx: &LateContext<'_, '_>, + info: &BinaryExprInfo<'_>, chain_methods: &[&str], lint: &'static Lint, suggest: &str, @@ -1824,12 +1824,12 @@ fn lint_chars_cmp<'a, 'tcx>( } /// Checks for the `CHARS_NEXT_CMP` lint. -fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo) -> bool { +fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with") } /// Checks for the `CHARS_LAST_CMP` lint. -fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo) -> bool { +fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_NEXT_CMP, "ends_with") { true } else { @@ -1840,7 +1840,7 @@ fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprIn /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`. fn lint_chars_cmp_with_unwrap<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - info: &BinaryExprInfo, + info: &BinaryExprInfo<'_>, chain_methods: &[&str], lint: &'static Lint, suggest: &str, @@ -1871,12 +1871,12 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>( } /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`. -fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo) -> bool { +fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with") } /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`. -fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo) -> bool { +fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") { true } else { @@ -1907,7 +1907,7 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi } /// Checks for the `USELESS_ASREF` lint. -fn lint_asref(cx: &LateContext, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) { +fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" // check if the call is to the actual `AsRef` or `AsMut` trait if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) { @@ -1931,7 +1931,7 @@ fn lint_asref(cx: &LateContext, expr: &hir::Expr, call_name: &str, as_ref_args: } /// Given a `Result<T, E>` type, return its error type (`E`). -fn get_error_type<'a>(cx: &LateContext, ty: Ty<'a>) -> Option<Ty<'a>> { +fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> { if let ty::TyAdt(_, substs) = ty.sty { if match_type(cx, ty, &paths::RESULT) { substs.types().nth(1) @@ -2033,7 +2033,7 @@ enum SelfKind { impl SelfKind { fn matches( self, - cx: &LateContext, + cx: &LateContext<'_, '_>, ty: &hir::Ty, arg: &hir::Arg, self_ty: &hir::Ty, @@ -2160,7 +2160,7 @@ impl Convention { } impl fmt::Display for Convention { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { Convention::Eq(this) => this.fmt(f), Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)), @@ -2177,7 +2177,7 @@ enum OutType { } impl OutType { - fn matches(self, cx: &LateContext, ty: &hir::FunctionRetTy) -> bool { + fn matches(self, cx: &LateContext<'_, '_>, ty: &hir::FunctionRetTy) -> bool { let is_unit = |ty: &hir::Ty| SpanlessEq::new(cx).eq_ty_kind(&ty.node, &hir::TyKind::Tup(vec![].into())); match (self, ty) { (OutType::Unit, &hir::DefaultReturn(_)) => true, diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 498f9ef4743..bc573841cc8 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -66,7 +66,7 @@ enum MinMax { Max, } -fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &'a Expr)> { +fn min_max<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(MinMax, Constant, &'a Expr)> { if let ExprKind::Call(ref path, ref args) = expr.node { if let ExprKind::Path(ref qpath) = path.node { opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)).and_then(|def_id| { @@ -86,7 +86,7 @@ fn min_max<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(MinMax, Constant, &' } } -fn fetch_const<'a>(cx: &LateContext, args: &'a [Expr], m: MinMax) -> Option<(MinMax, Constant, &'a Expr)> { +fn fetch_const<'a>(cx: &LateContext<'_, '_>, args: &'a [Expr], m: MinMax) -> Option<(MinMax, Constant, &'a Expr)> { if args.len() != 2 { return None; } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a32c95e9672..b01d24a1ad3 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -433,7 +433,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) { +fn check_nan(cx: &LateContext<'_, '_>, path: &Path, expr: &Expr) { if !in_constant(cx, expr.id) { if let Some(seg) = path.segments.last() { if seg.ident.name == "NAN" { @@ -464,11 +464,11 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool { } } -fn is_float(cx: &LateContext, expr: &Expr) -> bool { +fn is_float(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { matches!(walk_ptrs_ty(cx.tables.expr_ty(expr)).sty, ty::TyFloat(_)) } -fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) { +fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) { let (arg_ty, snip) = match expr.node { ExprKind::MethodCall(.., ref args) if args.len() == 1 => { if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) { @@ -542,7 +542,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr) { /// Heuristic to see if an expression is used. Should be compatible with /// `unused_variables`'s idea /// of what it means for an expression to be "used". -fn is_used(cx: &LateContext, expr: &Expr) -> bool { +fn is_used(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { match parent.node { ExprKind::Assign(_, ref rhs) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr), @@ -565,14 +565,14 @@ fn in_attributes_expansion(expr: &Expr) -> bool { } /// Test whether `def` is a variable defined outside a macro. -fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool { +fn non_macro_local(cx: &LateContext<'_, '_>, def: &def::Def) -> bool { match *def { def::Def::Local(id) | def::Def::Upvar(id, _, _) => !in_macro(cx.tcx.hir.span(id)), _ => false, } } -fn check_cast(cx: &LateContext, span: Span, e: &Expr, ty: &Ty) { +fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr, ty: &Ty) { if_chain! { if let TyKind::Ptr(MutTy { mutbl, .. }) = ty.node; if let ExprKind::Lit(ref lit) = e.node; diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 5bf7d5f3404..5d2b3914f84 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -189,7 +189,7 @@ impl LintPass for MiscEarly { } impl EarlyLintPass for MiscEarly { - fn check_generics(&mut self, cx: &EarlyContext, gen: &Generics) { + fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { for param in &gen.params { if let GenericParamKind::Type { .. } = param.kind { let name = param.ident.as_str(); @@ -205,7 +205,7 @@ impl EarlyLintPass for MiscEarly { } } - fn check_pat(&mut self, cx: &EarlyContext, pat: &Pat) { + fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { let mut wilds = 0; let type_name = npat.segments @@ -266,7 +266,7 @@ impl EarlyLintPass for MiscEarly { } } - fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: Span, _: NodeId) { + fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) { let mut registered_names: HashMap<String, Span> = HashMap::new(); for arg in &decl.inputs { @@ -293,7 +293,7 @@ impl EarlyLintPass for MiscEarly { } } - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if in_external_macro(cx, expr.span) { return; } @@ -325,7 +325,7 @@ impl EarlyLintPass for MiscEarly { } } - fn check_block(&mut self, cx: &EarlyContext, block: &Block) { + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { for w in block.stmts.windows(2) { if_chain! { if let StmtKind::Local(ref local) = w[0].node; @@ -352,7 +352,7 @@ impl EarlyLintPass for MiscEarly { } impl MiscEarly { - fn check_lit(self, cx: &EarlyContext, lit: &Lit) { + fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { if_chain! { if let LitKind::Int(value, ..) = lit.node; if let Some(src) = snippet_opt(cx, lit.span); diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index e921c541be2..fe2bbbdb9af 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -67,7 +67,7 @@ impl MissingDoc { .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 { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index cc57e771064..e19ec4da67e 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -68,7 +68,7 @@ declare_clippy_lint! { pub struct MissingInline; -fn check_missing_inline_attrs(cx: &LateContext, +fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { let has_inline = attrs .iter() diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index b484488b106..d4246045506 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -39,7 +39,7 @@ impl LintPass for Pass { } impl EarlyLintPass for Pass { - fn check_crate(&mut self, cx: &EarlyContext, krate: &Crate) { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { let metadata = match cargo_metadata::metadata_deps(None, true) { Ok(metadata) => metadata, Err(_) => { diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 2448cd84d7c..50ef9f268f2 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic { } } -fn get_atomic_name(ty: Ty) -> Option<(&'static str)> { +fn get_atomic_name(ty: Ty<'_>) -> Option<(&'static str)> { match ty.sty { ty::TyBool => Some("AtomicBool"), ty::TyUint(_) => Some("AtomicUsize"), diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 0b955bbfdff..60ab0eaae02 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -110,7 +110,7 @@ impl LintPass for NeedlessContinue { } impl EarlyLintPass for NeedlessContinue { - fn check_expr(&mut self, ctx: &EarlyContext, expr: &ast::Expr) { + fn check_expr(&mut self, ctx: &EarlyContext<'_>, expr: &ast::Expr) { if !in_macro(expr.span) { check_and_warn(ctx, expr); } @@ -265,7 +265,7 @@ const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving block, like so:\n"; -fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: LintType) { +fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) { // snip is the whole *help* message that appears after the warning. // message is the warning message. // expr is the expression which the lint warning message refers to. @@ -284,7 +284,7 @@ fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: L span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip); } -fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str) -> String { +fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String { let cond_code = snippet(ctx, data.if_cond.span, ".."); let if_code = format!("if {} {{\n continue;\n}}\n", cond_code); @@ -301,7 +301,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext, data: &'a L ret } -fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str) -> String { +fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String { let cond_code = snippet(ctx, data.if_cond.span, ".."); let mut if_code = format!("if {} {{\n", cond_code); @@ -332,7 +332,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext, data: &'a ret } -fn check_and_warn<'a>(ctx: &EarlyContext, expr: &'a ast::Expr) { +fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) { with_loop_block(expr, |loop_block| { for (i, stmt) in loop_block.stmts.iter().enumerate() { with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 7463ea2d9c3..82e85f3453a 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { } // Dereference suggestion - let sugg = |db: &mut DiagnosticBuilder| { + let sugg = |db: &mut DiagnosticBuilder<'_>| { if let ty::TypeVariants::TyAdt(def, ..) = ty.sty { if let Some(span) = cx.tcx.hir.span_if_local(def.did) { if cx.param_env.can_type_implement_copy(cx.tcx, ty).is_ok() { @@ -396,7 +396,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> { } } - fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {} + fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, _: euv::LoanCause) {} fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {} diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 96f2e58f3be..c056ff46178 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply { } } -fn check_mul(cx: &LateContext, span: Span, lit: &Expr, exp: &Expr) { +fn check_mul(cx: &LateContext<'_, '_>, span: Span, lit: &Expr, exp: &Expr) { if_chain! { if let ExprKind::Lit(ref l) = lit.node; if let Constant::Int(val) = consts::lit_to_constant(&l.node, cx.tables.expr_ty(lit)); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index a2192710292..49e4e966e18 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { } } -fn create_new_without_default_suggest_msg(ty: Ty) -> String { +fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String { #[cfg_attr(rustfmt, rustfmt_skip)] format!( "impl Default for {} {{ diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index dc83b29854c..cacb5d6a9ff 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { "outer expressions with no effect" } -fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { +fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { if in_macro(expr.span) { return false; } @@ -128,7 +128,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } -fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Expr>> { +fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec<&'a Expr>> { if in_macro(expr.span) { return None; } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 8f21523f404..e9688262c2a 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -312,13 +312,13 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { } impl EarlyLintPass for NonExpressiveNames { - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::Fn(ref decl, _, _, ref blk) = item.node { do_check(self, cx, &item.attrs, decl, blk); } } - fn check_impl_item(&mut self, cx: &EarlyContext, item: &ImplItem) { + fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &ImplItem) { if let ImplItemKind::Method(ref sig, ref blk) = item.node { do_check(self, cx, &item.attrs, &sig.decl, blk); } @@ -326,7 +326,7 @@ impl EarlyLintPass for NonExpressiveNames { } -fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { +fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { if !attr::contains_name(attrs, "test") { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 06b48b9eeac..effeb88d0cf 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -61,7 +61,7 @@ enum OpenOption { Append, } -fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { +fn get_open_options(cx: &LateContext<'_, '_>, argument: &Expr, options: &mut Vec<(OpenOption, Argument)>) { if let ExprKind::MethodCall(ref path, _, ref arguments) = argument.node { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0])); @@ -112,7 +112,7 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp } } -fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { +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); diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index e8dfca24c57..e603773f7ba 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -86,7 +86,7 @@ fn get_outer_span(expr: &Expr) -> Span { } } -fn match_panic(params: &P<[Expr]>, expr: &Expr, cx: &LateContext) { +fn match_panic(params: &P<[Expr]>, expr: &Expr, cx: &LateContext<'_, '_>) { if_chain! { if let ExprKind::Lit(ref lit) = params[0].node; if is_direct_expn_of(expr.span, "panic").is_some(); diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 76ea9c5ade6..6a0f4f147b7 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -37,7 +37,7 @@ impl LintPass for Precedence { } impl EarlyLintPass for Precedence { - fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if in_macro(expr.span) { return; } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 167ce84f803..ea2d07df455 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { } } -fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<BodyId>) { +fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<BodyId>) { let fn_def_id = cx.tcx.hir.local_def_id(fn_id); let sig = cx.tcx.fn_sig(fn_def_id); let fn_ty = sig.skip_binder(); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b2d53e124ff..630dd1b57be 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -52,7 +52,7 @@ impl QuestionMarkPass { /// ``` /// /// If it matches, it will suggest to use the question mark operator instead - fn check_is_none_and_early_return_none(cx: &LateContext, expr: &Expr) { + fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr) { if_chain! { if let ExprKind::If(ref if_expr, ref body, _) = expr.node; if let ExprKind::MethodCall(ref segment, _, ref args) = if_expr.node; @@ -81,13 +81,13 @@ impl QuestionMarkPass { } } - fn is_option(cx: &LateContext, expression: &Expr) -> bool { + fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool { let expr_ty = cx.tables.expr_ty(expression); match_type(cx, expr_ty, &OPTION) } - fn expression_returns_none(cx: &LateContext, expression: &Expr) -> bool { + fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr) -> bool { match expression.node { ExprKind::Block(ref block, _) => { if let Some(return_expression) = Self::return_expression(block) { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 9525ea014a9..fd303bb6ab4 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -176,7 +176,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn has_step_by(cx: &LateContext, expr: &Expr) -> bool { +fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { // No need for walk_ptrs_ty here because step_by moves self, so it // can't be called on a borrowed range. let ty = cx.tables.expr_ty_adjusted(expr); diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 27aca6f4bf1..f349f46d926 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -39,7 +39,7 @@ fn without_parens(mut e: &Expr) -> &Expr { } impl EarlyLintPass for Pass { - fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node; if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node; @@ -84,7 +84,7 @@ impl LintPass for DerefPass { } impl EarlyLintPass for DerefPass { - fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Field(ref object, ref field_name) = e.node; if let ExprKind::Paren(ref parened) = object.node; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 2bfc1e7d107..e4973cadc61 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -49,7 +49,7 @@ pub struct ReturnPass; impl ReturnPass { // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &EarlyContext, block: &ast::Block) { + 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) => { @@ -61,7 +61,7 @@ impl ReturnPass { } // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr, span: Option<Span>) { + fn check_final_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr, span: Option<Span>) { match expr.node { // simple return is always "bad" ast::ExprKind::Ret(Some(ref inner)) => { @@ -89,7 +89,7 @@ impl ReturnPass { } } - fn emit_return_lint(&mut self, cx: &EarlyContext, ret_span: Span, inner_span: Span) { + fn emit_return_lint(&mut self, cx: &EarlyContext<'_>, ret_span: Span, inner_span: Span) { if in_external_macro(cx, inner_span) || in_macro(inner_span) { return; } @@ -101,7 +101,7 @@ impl ReturnPass { } // Check for "let x = EXPR; x" - fn check_let_return(&mut self, cx: &EarlyContext, block: &ast::Block) { + fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { let mut it = block.stmts.iter(); // we need both a let-binding stmt and an expr @@ -138,14 +138,14 @@ impl LintPass for ReturnPass { } impl EarlyLintPass for ReturnPass { - fn check_fn(&mut self, cx: &EarlyContext, kind: FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { + 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::Closure(body) => self.check_final_expr(cx, body, Some(body.span)), } } - fn check_block(&mut self, cx: &EarlyContext, block: &ast::Block) { + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { self.check_let_return(cx, block); } } diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 563530c1ae7..1b29e53b754 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -148,7 +148,7 @@ fn check_decl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl, bindings: } } -fn is_binding(cx: &LateContext, pat_id: HirId) -> bool { +fn is_binding(cx: &LateContext<'_, '_>, pat_id: HirId) -> bool { let var_ty = cx.tables.node_id_to_type(pat_id); match var_ty.sty { ty::TyAdt(..) => false, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index fa8102308d8..a13f864c5ce 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -117,11 +117,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { } } -fn is_string(cx: &LateContext, e: &Expr) -> bool { +fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool { match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), &paths::STRING) } -fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool { +fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool { match src.node { ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), ExprKind::Block(ref block, _) => { diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index bd0f6dc68dc..b0a8a2d0061 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl { } fn check_binop<'a>( - cx: &LateContext, + cx: &LateContext<'_, '_>, expr: &hir::Expr, binop: hir::BinOpKind, traits: &[&'a str], diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 4278d6d74ac..38369d05676 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap { } /// Implementation of the `MANUAL_SWAP` lint. -fn check_manual_swap(cx: &LateContext, block: &Block) { +fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) { for w in block.stmts.windows(3) { if_chain! { // let t = foo(); @@ -84,7 +84,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2); then { fn check_for_slice<'a>( - cx: &LateContext, + cx: &LateContext<'_, '_>, lhs1: &'a Expr, lhs2: &'a Expr, ) -> Option<(&'a Expr, &'a Expr, &'a Expr)> { @@ -145,7 +145,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) { } /// Implementation of the `ALMOST_SWAPPED` lint. -fn check_suspicious_swap(cx: &LateContext, block: &Block) { +fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) { for w in block.stmts.windows(2) { if_chain! { if let StmtKind::Semi(ref first, _) = w[0].node; diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index aa964e4558f..403aeb47402 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -454,7 +454,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { /// the type's `ToString` implementation. In weird cases it could lead to types /// with invalid `'_` /// lifetime, but it should be rare. -fn get_type_snippet(cx: &LateContext, path: &QPath, to_ref_ty: Ty) -> String { +fn get_type_snippet(cx: &LateContext<'_, '_>, path: &QPath, to_ref_ty: Ty<'_>) -> String { let seg = last_path_segment(path); if_chain! { if let Some(ref params) = seg.args; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 2921b502c1f..d3932f411d1 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -138,7 +138,7 @@ impl LintPass for TypePass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { - fn check_fn(&mut self, cx: &LateContext, _: FnKind, decl: &FnDecl, _: &Body, _: Span, id: NodeId) { + fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _: &Body, _: Span, id: NodeId) { // skip trait implementations, see #605 if let Some(map::NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent(id)) { if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node { @@ -149,11 +149,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { check_fn_decl(cx, decl); } - fn check_struct_field(&mut self, cx: &LateContext, field: &StructField) { + fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &StructField) { check_ty(cx, &field.ty, false); } - fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) { + fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, item: &TraitItem) { match item.node { TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => check_ty(cx, ty, false), TraitItemKind::Method(ref sig, _) => check_fn_decl(cx, &sig.decl), @@ -161,14 +161,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { } } - fn check_local(&mut self, cx: &LateContext, local: &Local) { + fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &Local) { if let Some(ref ty) = local.ty { check_ty(cx, ty, true); } } } -fn check_fn_decl(cx: &LateContext, decl: &FnDecl) { +fn check_fn_decl(cx: &LateContext<'_, '_>, decl: &FnDecl) { for input in &decl.inputs { check_ty(cx, input, false); } @@ -179,7 +179,7 @@ fn check_fn_decl(cx: &LateContext, decl: &FnDecl) { } /// Check if `qpath` has last segment with type parameter matching `path` -fn match_type_parameter(cx: &LateContext, qpath: &QPath, path: &[&str]) -> bool { +fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) -> bool { let last = last_path_segment(qpath); if_chain! { if let Some(ref params) = last.args; @@ -203,7 +203,7 @@ fn match_type_parameter(cx: &LateContext, qpath: &QPath, path: &[&str]) -> bool /// /// The parameter `is_local` distinguishes the context of the type; types from /// local bindings should only be checked for the `BORROWED_BOX` lint. -fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { +fn check_ty(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool) { if in_macro(ast_ty.span) { return; } @@ -294,7 +294,7 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { } } -fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) { +fn check_ty_rptr(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) { match mut_ty.ty.node { TyKind::Path(ref qpath) => { let hir_id = cx.tcx.hir.node_to_hir_id(mut_ty.ty.id); @@ -378,7 +378,7 @@ declare_clippy_lint! { "creating a let binding to a value of unit type, which usually can't be used afterwards" } -fn check_let_unit(cx: &LateContext, decl: &Decl) { +fn check_let_unit(cx: &LateContext<'_, '_>, decl: &Decl) { if let DeclKind::Local(ref local) = decl.node { if is_unit(cx.tables.pat_ty(&local.pat)) { if in_external_macro(cx, decl.span) || in_macro(local.pat.span) { @@ -548,7 +548,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool { } } -fn is_unit(ty: Ty) -> bool { +fn is_unit(ty: Ty<'_>) -> bool { match ty.sty { ty::TyTuple(slice) if slice.is_empty() => true, _ => false, @@ -753,7 +753,7 @@ declare_clippy_lint! { /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant -fn int_ty_to_nbits(typ: Ty, tcx: TyCtxt) -> u64 { +fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 { match typ.sty { ty::TyInt(i) => match i { IntTy::Isize => tcx.data_layout.pointer_size.bits(), @@ -775,14 +775,14 @@ fn int_ty_to_nbits(typ: Ty, tcx: TyCtxt) -> u64 { } } -fn is_isize_or_usize(typ: Ty) -> bool { +fn is_isize_or_usize(typ: Ty<'_>) -> bool { match typ.sty { ty::TyInt(IntTy::Isize) | ty::TyUint(UintTy::Usize) => true, _ => false, } } -fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_to_f64: bool) { +fn span_precision_loss_lint(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty<'_>, cast_to_f64: bool) { let mantissa_nbits = if cast_to_f64 { 52 } else { 23 }; let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; let arch_dependent_str = "on targets with 64-bit wide pointers "; @@ -822,7 +822,7 @@ fn should_strip_parens(op: &Expr, snip: &str) -> bool { false } -fn span_lossless_lint(cx: &LateContext, expr: &Expr, op: &Expr, cast_from: Ty, cast_to: Ty) { +fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). if in_constant(cx, expr.id) { return } // The suggestion is to use a function call, so if the original expression @@ -854,7 +854,7 @@ enum ArchSuffix { None, } -fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: Ty, cast_to: Ty) { +fn check_truncation_and_wrapping(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) { let arch_64_suffix = " on targets with 64-bit wide pointers"; let arch_32_suffix = " on targets with 32-bit wide pointers"; let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); @@ -925,7 +925,7 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: Ty, c } } -fn check_lossless(cx: &LateContext, expr: &Expr, op: &Expr, cast_from: Ty, cast_to: Ty) { +fn check_lossless(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) { let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed(); let from_nbits = int_ty_to_nbits(cast_from, cx.tcx); let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); @@ -1183,7 +1183,7 @@ impl<'a, 'tcx> TypeComplexityPass { } } - fn check_type(&self, cx: &LateContext, ty: &hir::Ty) { + fn check_type(&self, cx: &LateContext<'_, '_>, ty: &hir::Ty) { if in_macro(ty.span) { return; } @@ -1562,7 +1562,7 @@ impl Ord for FullInt { } -fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(FullInt, FullInt)> { +fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(FullInt, FullInt)> { use syntax::ast::{IntTy, UintTy}; use std::*; @@ -1628,7 +1628,7 @@ fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) } } -fn err_upcast_comparison(cx: &LateContext, span: Span, expr: &Expr, always: bool) { +fn err_upcast_comparison(cx: &LateContext<'_, '_>, span: Span, expr: &Expr, always: bool) { if let ExprKind::Cast(ref cast_val, _) = expr.node { span_lint( cx, @@ -1750,11 +1750,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { fn suggestion<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - db: &mut DiagnosticBuilder, + db: &mut DiagnosticBuilder<'_>, generics_span: Span, generics_suggestion_span: Span, - target: &ImplicitHasherType, - vis: ImplicitHasherConstructorVisitor, + target: &ImplicitHasherType<'_>, + vis: ImplicitHasherConstructorVisitor<'_, '_, '_>, ) { let generics_snip = snippet(cx, generics_span, ""); // trim `<` `>` diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index c4a795bfacb..0549e774fb5 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -94,7 +94,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String { result } -fn check_str(cx: &LateContext, span: Span, id: NodeId) { +fn check_str(cx: &LateContext<'_, '_>, span: Span, id: NodeId) { let string = snippet(cx, span, ""); if string.contains('\u{200B}') { span_help_and_lint( diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index a6cab892324..2f8b3ab836d 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -35,14 +35,14 @@ impl LintPass for UnsafeNameRemoval { } impl EarlyLintPass for UnsafeNameRemoval { - fn check_item(&mut self, cx: &EarlyContext, item: &Item) { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::Use(ref use_tree) = item.node { check_use_tree(use_tree, cx, item.span); } } } -fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext, span: Span) { +fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) { match use_tree.kind { UseTreeKind::Simple(Some(new_name), ..) => { let old_name = use_tree @@ -63,7 +63,7 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext, span: Span) { } } -fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext, span: Span) { +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) { diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index e4dac731cf2..a9a7e102ab2 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -39,7 +39,7 @@ impl LintPass for UnusedIoAmount { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { - fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { + fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { let expr = match s.node { hir::StmtKind::Semi(ref expr, _) | hir::StmtKind::Expr(ref expr, _) => &**expr, _ => return, @@ -70,7 +70,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { } } -fn check_method_call(cx: &LateContext, call: &hir::Expr, expr: &hir::Expr) { +fn check_method_call(cx: &LateContext<'_, '_>, call: &hir::Expr, expr: &hir::Expr) { if let hir::ExprKind::MethodCall(ref path, _, _) = call.node { let symbol = &*path.ident.as_str(); if match_trait_method(cx, call, &paths::IO_READ) && symbol == "read" { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 52b34916627..a27013344d8 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -52,7 +52,7 @@ pub enum Error { } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { Error::Io(ref err) => err.fmt(f), Error::Toml(ref err) => err.fmt(f), diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index d63a2dae802..3931f6c55f9 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -212,7 +212,7 @@ pub enum VecArgs<'a> { /// Returns the arguments of the `vec!` macro if this expression was expanded /// from `vec!`. -pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e>> { +pub fn vec_macro<'e>(cx: &LateContext<'_, '_>, expr: &'e hir::Expr) -> Option<VecArgs<'e>> { if_chain! { if let hir::ExprKind::Call(ref fun, ref args) = expr.node; if let hir::ExprKind::Path(ref path) = fun.node; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 55233510495..b6c241a6825 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -141,7 +141,7 @@ fn has_attr(attrs: &[Attribute]) -> bool { get_attr(attrs, "dump").count() > 0 } -fn print_decl(cx: &LateContext, decl: &hir::Decl) { +fn print_decl(cx: &LateContext<'_, '_>, decl: &hir::Decl) { match decl.node { hir::DeclKind::Local(ref local) => { println!("local variable of type {}", cx.tables.node_id_to_type(local.hir_id)); @@ -156,7 +156,7 @@ fn print_decl(cx: &LateContext, decl: &hir::Decl) { } } -fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) { +fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr, indent: usize) { let ind = " ".repeat(indent); println!("{}+", ind); println!("{}ty: {}", ind, cx.tables.expr_ty(expr)); @@ -342,7 +342,7 @@ fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) { } } -fn print_item(cx: &LateContext, item: &hir::Item) { +fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) { let did = cx.tcx.hir.local_def_id(item.id); println!("item `{}`", item.name); match item.vis.node { @@ -414,7 +414,7 @@ fn print_item(cx: &LateContext, item: &hir::Item) { } } -fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) { +fn print_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, indent: usize) { let ind = " ".repeat(indent); println!("{}+", ind); match pat.node { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 3d43d595def..32aee099177 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -64,7 +64,7 @@ impl LintPass for Clippy { } impl EarlyLintPass for Clippy { - fn check_crate(&mut self, cx: &EarlyContext, krate: &AstCrate) { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) { if let Some(utils) = krate .module .items diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index bdf486a45ab..8e83b8d81f2 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -48,7 +48,7 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt() != lhs.ctxt() } -pub fn in_constant(cx: &LateContext, id: NodeId) -> bool { +pub fn in_constant(cx: &LateContext<'_, '_>, id: NodeId) -> bool { let parent_id = cx.tcx.hir.get_parent(id); match cx.tcx.hir.body_owner_kind(parent_id) { hir::BodyOwnerKind::Fn => false, @@ -115,7 +115,7 @@ pub fn in_external_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { /// ``` /// /// See also the `paths` module. -pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool { +pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> bool { use syntax::symbol; struct AbsolutePathBuffer { @@ -145,7 +145,7 @@ pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool { } /// Check if type is struct, enum or union type with given def path. -pub fn match_type(cx: &LateContext, ty: Ty, path: &[&str]) -> bool { +pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool { match ty.sty { ty::TyAdt(adt, _) => match_def_path(cx.tcx, adt.did, path), _ => false, @@ -153,7 +153,7 @@ pub fn match_type(cx: &LateContext, ty: Ty, path: &[&str]) -> bool { } /// Check if the method call given in `expr` belongs to given type. -pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { +pub fn match_impl_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) -> bool { let method_call = cx.tables.type_dependent_defs()[expr.hir_id]; let trt_id = cx.tcx.impl_of_method(method_call.def_id()); if let Some(trt_id) = trt_id { @@ -164,7 +164,7 @@ pub fn match_impl_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { } /// Check if the method call given in `expr` belongs to given trait. -pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool { +pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) -> bool { let method_call = cx.tables.type_dependent_defs()[expr.hir_id]; let trt_id = cx.tcx.trait_of_item(method_call.def_id()); if let Some(trt_id) = trt_id { @@ -244,7 +244,7 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { } /// Get the definition associated to a path. -pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { +pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def> { let crates = cx.tcx.crates(); let krate = crates .iter() @@ -280,7 +280,7 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { } /// Convenience function to get the `DefId` of a trait by path. -pub fn get_trait_def_id(cx: &LateContext, path: &[&str]) -> Option<DefId> { +pub fn get_trait_def_id(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<DefId> { let def = match path_to_def(cx, path) { Some(def) => def, None => return None, @@ -308,7 +308,7 @@ pub fn implements_trait<'a, 'tcx>( } /// Check whether this type implements Drop. -pub fn has_drop(cx: &LateContext, expr: &Expr) -> bool { +pub fn has_drop(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { let struct_ty = cx.tables.expr_ty(expr); match struct_ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), @@ -317,7 +317,7 @@ pub fn has_drop(cx: &LateContext, expr: &Expr) -> bool { } /// Resolve the definition of a node from its `HirId`. -pub fn resolve_node(cx: &LateContext, qpath: &QPath, id: HirId) -> def::Def { +pub fn resolve_node(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> def::Def { cx.tables.qpath_def(qpath, id) } @@ -352,7 +352,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a /// Get the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> { +pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.hir.get_parent(expr.id); match cx.tcx.hir.find(parent_id) { Some(Node::NodeItem(&Item { ref name, .. })) => Some(*name), @@ -458,13 +458,13 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>( /// Trim indentation from a multiline string with possibility of ignoring the /// first line. -pub fn trim_multiline(s: Cow<str>, ignore_first: bool) -> Cow<str> { +pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool) -> Cow<'_, str> { let s_space = trim_multiline_inner(s, ignore_first, ' '); let s_tab = trim_multiline_inner(s_space, ignore_first, '\t'); trim_multiline_inner(s_tab, ignore_first, ' ') } -fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { +fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_, str> { let x = s.lines() .skip(ignore_first as usize) .filter_map(|l| { @@ -502,7 +502,7 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> { } /// Get a parent expressions if any – this is useful to constrain a lint. -pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> { +pub fn get_parent_expr<'c>(cx: &'c LateContext<'_, '_>, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.hir; let node_id: NodeId = e.id; let parent_id: NodeId = map.get_parent_node(node_id); @@ -642,7 +642,7 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I) +pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I) where I: IntoIterator<Item = (Span, String)>, { @@ -675,7 +675,7 @@ pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty { } /// Return the base type for references and raw pointers. -pub fn walk_ptrs_ty(ty: Ty) -> Ty { +pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { match ty.sty { ty::TyRef(_, ty, _) => walk_ptrs_ty(ty), _ => ty, @@ -684,8 +684,8 @@ pub fn walk_ptrs_ty(ty: Ty) -> Ty { /// Return the base type for references and raw pointers, and count reference /// depth. -pub fn walk_ptrs_ty_depth(ty: Ty) -> (Ty, usize) { - fn inner(ty: Ty, depth: usize) -> (Ty, usize) { +pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { + fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { match ty.sty { ty::TyRef(_, ty, _) => inner(ty, depth + 1), _ => (ty, depth), @@ -705,7 +705,7 @@ pub fn is_integer_literal(expr: &Expr, value: u128) -> bool { false } -pub fn is_adjusted(cx: &LateContext, e: &Expr) -> bool { +pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool { cx.tables.adjustments().get(e.hir_id).is_some() } @@ -898,15 +898,15 @@ pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { } /// Return whether a pattern is refutable. -pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool { - fn is_enum_variant(cx: &LateContext, qpath: &QPath, id: HirId) -> bool { +pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat) -> bool { + fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> bool { matches!( cx.tables.qpath_def(qpath, id), def::Def::Variant(..) | def::Def::VariantCtor(..) ) } - fn are_refutable<'a, I: Iterator<Item = &'a Pat>>(cx: &LateContext, mut i: I) -> bool { + fn are_refutable<'a, I: Iterator<Item = &'a Pat>>(cx: &LateContext<'_, '_>, mut i: I) -> bool { i.any(|pat| is_refutable(cx, pat)) } @@ -1065,7 +1065,7 @@ pub fn is_try(expr: &Expr) -> Option<&Expr> { /// Returns true if the lint is allowed in the current context /// /// Useful for skipping long running code when it's unnecessary -pub fn is_allowed(cx: &LateContext, lint: &'static Lint, id: NodeId) -> bool { +pub fn is_allowed(cx: &LateContext<'_, '_>, lint: &'static Lint, id: NodeId) -> bool { cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow } @@ -1085,24 +1085,24 @@ pub fn get_arg_ident(pat: &Pat) -> Option<ast::Ident> { } } -pub fn int_bits(tcx: TyCtxt, ity: ast::IntTy) -> u64 { +pub fn int_bits(tcx: TyCtxt<'_, '_, '_>, ity: ast::IntTy) -> u64 { layout::Integer::from_attr(tcx, attr::IntType::SignedInt(ity)).size().bits() } /// Turn a constant int byte representation into an i128 -pub fn sext(tcx: TyCtxt, u: u128, ity: ast::IntTy) -> i128 { +pub fn sext(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::IntTy) -> i128 { let amt = 128 - int_bits(tcx, ity); ((u as i128) << amt) >> amt } /// clip unused bytes -pub fn unsext(tcx: TyCtxt, u: i128, ity: ast::IntTy) -> u128 { +pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 { let amt = 128 - int_bits(tcx, ity); ((u as u128) << amt) >> amt } /// clip unused bytes -pub fn clip(tcx: TyCtxt, u: u128, ity: ast::UintTy) -> u128 { +pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 { let bits = layout::Integer::from_attr(tcx, attr::IntType::UnsignedInt(ity)).size().bits(); let amt = 128 - bits; (u << amt) >> amt @@ -1141,7 +1141,7 @@ pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> { without } -pub fn any_parent_is_automatically_derived(tcx: TyCtxt, node: NodeId) -> bool { +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_, '_, '_>, node: NodeId) -> bool { let map = &tcx.hir; let mut prev_enclosing_node = None; let mut enclosing_node = node; diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index 4275345d395..1a20eb01015 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -7,7 +7,7 @@ use syntax::codemap::Span; use crate::utils::{get_pat_name, match_var, snippet}; pub fn get_spans( - cx: &LateContext, + cx: &LateContext<'_, '_>, opt_body_id: Option<BodyId>, idx: usize, replacements: &'static [(&'static str, &'static str)], diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index c7e1e59f063..91fd5ec874a 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -32,8 +32,8 @@ pub enum Sugg<'a> { /// Literal constant `1`, for convenience. 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> { +impl Display for Sugg<'_> { + 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), } @@ -43,7 +43,7 @@ impl<'a> Display for Sugg<'a> { #[allow(wrong_self_convention)] // ok, because of the function `as_ty` method impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. - pub fn hir_opt(cx: &LateContext, expr: &hir::Expr) -> Option<Self> { + pub fn hir_opt(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<Self> { snippet_opt(cx, expr.span).map(|snippet| { let snippet = Cow::Owned(snippet); match expr.node { @@ -82,12 +82,12 @@ impl<'a> Sugg<'a> { /// Convenience function around `hir_opt` for suggestions with a default /// text. - pub fn hir(cx: &LateContext, expr: &hir::Expr, default: &'a str) -> Self { + pub fn hir(cx: &LateContext<'_, '_>, expr: &hir::Expr, default: &'a str) -> Self { Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) } /// Prepare a suggestion from an expression. - pub fn ast(cx: &EarlyContext, expr: &ast::Expr, default: &'a str) -> Self { + pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use syntax::ast::RangeLimits; let snippet = snippet(cx, expr.span, default); @@ -241,7 +241,7 @@ impl<T> ParenHelper<T> { } impl<T: Display> Display for ParenHelper<T> { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { if self.paren { write!(f, "({})", self.wrapped) } else { @@ -255,7 +255,7 @@ impl<T: Display> Display for ParenHelper<T> { /// For convenience, the operator is taken as a string because all unary /// operators have the same /// precedence. -pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> { +pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into()) } @@ -264,7 +264,7 @@ pub fn make_unop(op: &str, expr: Sugg) -> Sugg<'static> { /// Precedence of shift operator relative to other arithmetic operation is /// often confusing so /// parenthesis will always be added for a mix of these. -pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { +pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { /// Whether the operator is a shift operator `<<` or `>>`. fn is_shift(op: &AssocOp) -> bool { matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight) @@ -335,7 +335,7 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { } /// Convinience wrapper arround `make_assoc` and `AssocOp::from_ast_binop`. -pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { +pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { make_assoc(AssocOp::from_ast_binop(op), lhs, rhs) } diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 6d75dfb486d..43e492bfb4e 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -44,7 +44,7 @@ struct MutVarsDelegate { } impl<'tcx> MutVarsDelegate { - fn update(&mut self, cat: &'tcx Categorization) { + fn update(&mut self, cat: &'tcx Categorization<'_>) { match *cat { Categorization::Local(id) => { self.used_mutably.insert(id); @@ -68,7 +68,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) { + fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) { if let ty::BorrowKind::MutBorrow = bk { self.update(&cmt.cat) } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index a58d73f86da..cea3307a827 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -94,7 +94,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA } /// Return the item type of the vector (ie. the `T` in `Vec<T>`). -fn vec_type(ty: Ty) -> Ty { +fn vec_type(ty: Ty<'_>) -> Ty<'_> { if let ty::TyAdt(_, substs) = ty.sty { substs.type_at(0) } else { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index c4b5a9ccefc..a019e23a301 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -168,7 +168,7 @@ impl LintPass for Pass { } impl EarlyLintPass for Pass { - fn check_mac(&mut self, cx: &EarlyContext, mac: &Mac) { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) { if mac.node.path == "println" { span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`"); if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) { @@ -261,7 +261,7 @@ fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Op return Some(fmtstr); } let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?; - const SIMPLE: FormatSpec = FormatSpec { + const SIMPLE: FormatSpec<'_> = FormatSpec { fill: None, align: AlignUnknown, flags: 0, diff --git a/src/lib.rs b/src/lib.rs index 6ff15e2cd89..1123c968006 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use rustc_plugin::Registry; #[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { +pub fn plugin_registrar(reg: &mut Registry<'_>) { reg.sess.lint_store.with_read_lock(|lint_store| { for (lint, _, _) in lint_store.get_lint_groups() { reg.sess -- cgit 1.4.1-3-g733a5 From bbd67c9b78f41ddead23fd03ea5d8d613cb96b45 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Wed, 15 Aug 2018 08:11:07 +0200 Subject: Fix #2927 --- clippy_lints/src/lib.rs | 32 +++++++++++++++++------------- clippy_lints/src/non_expressive_names.rs | 9 ++++----- src/driver.rs | 6 ++++-- src/lib.rs | 3 ++- tests/ui/non_expressive_names.rs | 7 ++++++- tests/ui/non_expressive_names.stderr | 34 +++++++------------------------- 6 files changed, 41 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9776287cc75..680ff2c9600 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -173,18 +173,14 @@ pub mod write; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` +use crate::utils::conf::Conf; + mod reexport { crate use syntax::ast::{Name, NodeId}; } -pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore) { - store.register_pre_expansion_pass(Some(session), box write::Pass); - store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames); -} - -#[rustfmt::skip] -pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) { - let conf = match utils::conf::file_from_args(reg.args()) { +pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { + match utils::conf::file_from_args(reg.args()) { Ok(file_name) => { // if the user specified a file, it must exist, otherwise default to `clippy.toml` but // do not require the file to exist @@ -226,8 +222,19 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) { .emit(); toml::from_str("").expect("we never error on empty config files") } - }; + } +} +pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore, conf: &Conf) { + store.register_pre_expansion_pass(Some(session), box write::Pass); + store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames); + store.register_pre_expansion_pass(Some(session), box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold: conf.single_char_binding_names_threshold, + }); +} + +#[rustfmt::skip] +pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { let mut store = reg.sess.lint_store.borrow_mut(); store.register_removed( "should_assert_eq", @@ -329,9 +336,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) { reg.register_late_lint_pass(box derive::Derive); reg.register_late_lint_pass(box types::CharLitAsU8); reg.register_late_lint_pass(box vec::Pass); - reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold: conf.single_char_binding_names_threshold, - }); reg.register_late_lint_pass(box drop_forget_ref::Pass); reg.register_late_lint_pass(box empty_enum::EmptyEnum); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); @@ -347,9 +351,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) { reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); - reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names)); + reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names.clone())); 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_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents.clone())); reg.register_late_lint_pass(box neg_multiply::NegMultiply); reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); reg.register_late_lint_pass(box mem_forget::MemForget); diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 08d10d8e454..3401fbca171 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,7 +5,7 @@ use syntax::symbol::LocalInternedString; use syntax::ast::*; use syntax::attr; use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; -use crate::utils::{in_macro, span_lint, span_lint_and_then}; +use crate::utils::{span_lint, span_lint_and_then}; /// **What it does:** Checks for names that are very similar and thus confusing. /// @@ -147,9 +147,6 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } } fn check_name(&mut self, span: Span, name: Name) { - if in_macro(span) { - return; - } let interned_name = name.as_str(); if interned_name.chars().any(char::is_uppercase) { return; @@ -309,6 +306,9 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { fn visit_item(&mut self, _: &Item) { // do not recurse into inner items } + fn visit_mac(&mut self, _mac: &Mac) { + // do not check macs + } } impl EarlyLintPass for NonExpressiveNames { @@ -323,7 +323,6 @@ impl EarlyLintPass for NonExpressiveNames { do_check(self, cx, &item.attrs, &sig.decl, blk); } } - } fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { diff --git a/src/driver.rs b/src/driver.rs index e9e81bb88e3..659287daed5 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -96,7 +96,9 @@ pub fn main() { .span, ); registry.args_hidden = Some(Vec::new()); - clippy_lints::register_plugins(&mut registry); + + let conf = clippy_lints::read_conf(®istry); + clippy_lints::register_plugins(&mut registry, &conf); let rustc_plugin::registry::Registry { early_lint_passes, @@ -118,7 +120,7 @@ pub fn main() { for (name, to) in lint_groups { ls.register_group(Some(sess), true, name, to); } - clippy_lints::register_pre_expansion_lints(sess, &mut ls); + clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); sess.plugin_attributes.borrow_mut().extend(attributes); diff --git a/src/lib.rs b/src/lib.rs index 1123c968006..c2363fef907 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,8 @@ pub fn plugin_registrar(reg: &mut Registry<'_>) { } }); - clippy_lints::register_plugins(reg); + let conf = clippy_lints::read_conf(reg); + clippy_lints::register_plugins(reg, &conf); } // only exists to let the dogfood integration test works. diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index 19f0889a92c..7149bf8f3e7 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,7 +1,7 @@ #![warn(clippy,similar_names)] -#![allow(unused)] +#![allow(unused, println_empty_string)] struct Foo { @@ -142,6 +142,11 @@ fn underscores_and_numbers() { let _1_ok= 1; } +fn issue2927() { + let args = 1; + format!("{:?}", 2); +} + struct Bar; impl Bar { diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index c63b493db8d..b4927e69e67 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,23 +1,3 @@ -error: using `println!("")` - --> $DIR/non_expressive_names.rs:60:14 - | -60 | _ => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` - | - = note: `-D println-empty-string` implied by `-D warnings` - -error: using `println!("")` - --> $DIR/non_expressive_names.rs:128:18 - | -128 | 1 => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` - -error: using `println!("")` - --> $DIR/non_expressive_names.rs:132:18 - | -132 | 1 => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` - error: binding's name is too similar to existing binding --> $DIR/non_expressive_names.rs:18:9 | @@ -170,22 +150,22 @@ error: consider choosing a more descriptive name | ^^^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:149:13 + --> $DIR/non_expressive_names.rs:154:13 | -149 | let _1 = 1; +154 | let _1 = 1; | ^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:150:13 + --> $DIR/non_expressive_names.rs:155:13 | -150 | let ____1 = 1; +155 | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:151:13 + --> $DIR/non_expressive_names.rs:156:13 | -151 | let __1___2 = 12; +156 | let __1___2 = 12; | ^^^^^^^ -error: aborting due to 20 previous errors +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From a7bea134d30577fa6f1f722cc27e5873c5869962 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sun, 19 Aug 2018 19:07:31 -0700 Subject: Remove implied rust_2018 feature We are already on the edition and this feature is implied. --- clippy_lints/src/lib.rs | 1 - mini-macro/src/lib.rs | 2 +- src/lib.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3de7c6de979..76649d8a145 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -12,7 +12,6 @@ #![feature(iterator_find_map)] #![feature(macro_at_most_once_rep)] #![feature(tool_attributes)] -#![feature(rust_2018_preview)] #![warn(rust_2018_idioms)] use toml; diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index 3417e603c12..8a19dc2c4e5 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(use_extern_macros, proc_macro_quote, proc_macro_non_items)] +#![feature(proc_macro_quote, proc_macro_non_items)] extern crate proc_macro; use proc_macro::{TokenStream, quote}; diff --git a/src/lib.rs b/src/lib.rs index c2363fef907..e6aaff1b2a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] -#![feature(rust_2018_preview)] #![feature(rustc_private)] #![feature(macro_vis_matcher)] #![allow(unknown_lints)] -- cgit 1.4.1-3-g733a5 From 8ab16b678c0473b29d034cad5ab1fccb1b35944e Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Thu, 23 Aug 2018 13:12:27 +0200 Subject: remove macro_vis_matcher feature gate since it is stable now. Warning was: warning: the feature `macro_vis_matcher` has been stable since 1.29.0 and no longer requires an attribute to enable --> src/lib.rs:4:12 | 4 | #![feature(macro_vis_matcher)] | ^^^^^^^^^^^^^^^^^ | = note: #[warn(stable_features)] on by default --- clippy_lints/src/lib.rs | 1 - src/lib.rs | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8e5aabc00a..6064601fd80 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,7 +5,6 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(range_contains)] -#![feature(macro_vis_matcher)] #![allow(unknown_lints, shadow_reuse, missing_docs_in_private_items)] #![recursion_limit = "256"] #![feature(iterator_find_map)] diff --git a/src/lib.rs b/src/lib.rs index e6aaff1b2a9..1525dbda4ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] -#![feature(macro_vis_matcher)] #![allow(unknown_lints)] #![allow(missing_docs_in_private_items)] #![warn(rust_2018_idioms)] -- cgit 1.4.1-3-g733a5 From caa59e2e277128767023cfe867f54dae943af6ca Mon Sep 17 00:00:00 2001 From: Oliver Schneider <github35764891676564198441@oli-obk.de> Date: Sun, 26 Aug 2018 15:49:08 +0200 Subject: Use the compilers exit code computation instead of rolling our own --- src/driver.rs | 216 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 107 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 659287daed5..6854ccbbddc 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -13,125 +13,123 @@ fn show_version() { } pub fn main() { - use std::env; + exit(rustc_driver::run(move || { + use std::env; - if std::env::args().any(|a| a == "--version" || a == "-V") { - show_version(); - return; - } + if std::env::args().any(|a| a == "--version" || a == "-V") { + show_version(); + exit(0); + } - let sys_root = option_env!("SYSROOT") - .map(String::from) - .or_else(|| std::env::var("SYSROOT").ok()) - .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); + let sys_root = option_env!("SYSROOT") + .map(String::from) + .or_else(|| std::env::var("SYSROOT").ok()) + .or_else(|| { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) + }) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programmatically, so we ignore this/ - let mut orig_args: Vec<String> = env::args().collect(); - if orig_args.len() <= 1 { - std::process::exit(1); - } - if orig_args[1] == "rustc" { - // we still want to be able to invoke it normally though - orig_args.remove(1); - } - // this conditional check for the --sysroot flag is there so users can call - // `clippy_driver` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() - } else { - orig_args - .clone() - .into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programmatically, so we ignore this/ + let mut orig_args: Vec<String> = env::args().collect(); + if orig_args.len() <= 1 { + std::process::exit(1); + } + if orig_args[1] == "rustc" { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args + .clone() + .into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; - // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") + || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend( - extra_args - .split("__CLIPPY_HACKERY__") - .filter(|s| !s.is_empty()) - .map(str::to_owned), - ); + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + if let Ok(extra_args) = env::var("CLIPPY_ARGS") { + args.extend( + extra_args + .split("__CLIPPY_HACKERY__") + .filter(|s| !s.is_empty()) + .map(str::to_owned), + ); + } } - } - let mut controller = CompileController::basic(); - if clippy_enabled { - controller.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 crate must be parsed", - ) - .span, - ); - registry.args_hidden = Some(Vec::new()); + let mut controller = CompileController::basic(); + if clippy_enabled { + controller.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 crate must be parsed", + ) + .span, + ); + registry.args_hidden = Some(Vec::new()); - let conf = clippy_lints::read_conf(®istry); - clippy_lints::register_plugins(&mut registry, &conf); + let conf = clippy_lints::read_conf(®istry); + clippy_lints::register_plugins(&mut registry, &conf); - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } - clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - }); - } - controller.compilation_done.stop = Compilation::Stop; + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + }); + } + controller.compilation_done.stop = Compilation::Stop; - if rustc_driver::run_compiler(&args, Box::new(controller), None, None) - .0 - .is_err() - { - exit(101); - } + let args = args; + rustc_driver::run_compiler(&args, Box::new(controller), None, None) + }) as i32) } -- cgit 1.4.1-3-g733a5 From f3bb161f0e634f45ce1c189baaf0d3d6cc651cec Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Wed, 1 Aug 2018 22:48:41 +0200 Subject: Adapt codebase to the tool_lints --- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/booleans.rs | 6 +++--- clippy_lints/src/consts.rs | 3 +-- clippy_lints/src/cyclomatic_complexity.rs | 4 ++-- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/int_plus_one.rs | 2 +- clippy_lints/src/lib.rs | 5 +++-- clippy_lints/src/methods.rs | 4 ++-- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/types.rs | 4 ++-- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/comparisons.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/constants.rs | 2 +- clippy_lints/src/utils/higher.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 2 +- clippy_lints/src/utils/inspector.rs | 2 +- clippy_lints/src/utils/sugg.rs | 6 ++---- src/driver.rs | 5 +++-- src/lib.rs | 3 ++- src/main.rs | 7 ++++--- 25 files changed, 39 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 5a27f6a2c36..9a1808345a5 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { }, hir::ExprKind::Assign(ref assignee, ref e) => { if let hir::ExprKind::Binary(op, ref l, ref r) = e.node { - #[allow(cyclomatic_complexity)] + #[allow(clippy::cyclomatic_complexity)] let lint = |assignee: &hir::Expr, rhs: &hir::Expr| { let ty = cx.tables.expr_ty(assignee); let rty = cx.tables.expr_ty(rhs); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index f867dc56c3c..3d3fa7b5e73 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } for (n, expr) in self.terminals.iter().enumerate() { if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) { - #[allow(cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation)] return Ok(Bool::Term(n as u8)); } let negated = match e.node { @@ -150,14 +150,14 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => continue, }; if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { - #[allow(cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation)] return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); } } let n = self.terminals.len(); self.terminals.push(e); if n < 32 { - #[allow(cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation)] Ok(Bool::Term(n as u8)) } else { Err("too many literals".to_owned()) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index ff189d6e893..b126215c049 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,5 +1,4 @@ -#![allow(cast_possible_truncation)] -#![allow(float_cmp)] +#![allow(clippy::float_cmp)] use rustc::lint::LateContext; use rustc::{span_bug, bug}; diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index 6195db7b482..c975e31cec9 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> { } #[cfg(feature = "debugging")] -#[allow(too_many_arguments)] +#[allow(clippy::too_many_arguments)] fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) { span_bug!( span, @@ -200,7 +200,7 @@ fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: ); } #[cfg(not(feature = "debugging"))] -#[allow(too_many_arguments)] +#[allow(clippy::too_many_arguments)] fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) { if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) { cx.sess().span_note_without_error( diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 2db950b3365..4d603570ebe 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -86,7 +86,7 @@ impl<'a> Iterator for Parser<'a> { /// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we /// need to keep track of /// the spans but this function is inspired from the later. -#[allow(cast_possible_truncation)] +#[allow(clippy::cast_possible_truncation)] pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) { // one-line comments lose their prefix const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 3a7f884b784..0271fee8a3c 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -43,7 +43,7 @@ impl LintPass for UnportableVariant { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { - #[allow(cast_possible_truncation, cast_sign_loss)] + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { if cx.tcx.data_layout.pointer_size.bits() != 64 { return; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 85b133cbd03..56b99aa9449 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -147,7 +147,7 @@ fn partial_rmatch(post: &str, name: &str) -> usize { } // FIXME: #600 -#[allow(while_let_on_iterator)] +#[allow(clippy::while_let_on_iterator)] fn check_variant( cx: &EarlyContext<'_>, threshold: u64, diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index de1b5b77e6e..b6b34204480 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => (cx.tcx.lang_items().ord_trait(), true), }; if let Some(trait_id) = trait_id { - #[allow(match_same_arms)] + #[allow(clippy::match_same_arms)] match (&left.node, &right.node) { // do not suggest to dereference literals (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index bb3741088cf..052275d7a45 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { } } -#[allow(cast_possible_wrap)] +#[allow(clippy::cast_possible_wrap)] fn check(cx: &LateContext<'_, '_>, e: &Expr, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) { let check = match cx.tables.expr_ty(e).sty { diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index b640eff2c5d..f94461b75a5 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -53,7 +53,7 @@ enum Side { } impl IntPlusOne { - #[allow(cast_sign_loss)] + #[allow(clippy::cast_sign_loss)] fn check_lit(&self, lit: &Lit, target_value: i128) -> bool { if let LitKind::Int(value, ..) = lit.node { return value == (target_value as u128); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 32c3dca6357..f1a89c3d46b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -5,9 +5,10 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(range_contains)] -#![allow(unknown_lints, shadow_reuse, missing_docs_in_private_items)] +#![allow(unknown_lints, clippy::shadow_reuse, clippy::missing_docs_in_private_items)] #![recursion_limit = "256"] #![feature(macro_at_most_once_rep)] +#![feature(tool_lints)] #![warn(rust_2018_idioms)] use toml; @@ -933,7 +934,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { // only exists to let the dogfood integration test works. // Don't run clippy as an executable directly -#[allow(dead_code, print_stdout)] +#[allow(dead_code, clippy::print_stdout)] fn main() { panic!("Please use the cargo-clippy executable"); } diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 4f6cb64dd4f..f428a498b4d 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -714,7 +714,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - #[allow(cyclomatic_complexity)] + #[allow(clippy::cyclomatic_complexity)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { if in_macro(expr.span) { return; @@ -922,7 +922,7 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa } /// Check for `*or(foo())`. - #[allow(too_many_arguments)] + #[allow(clippy::too_many_arguments)] fn check_general_case( cx: &LateContext<'_, '_>, name: &str, diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 8df33b1e99a..93a83fe97ba 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -32,7 +32,7 @@ impl LintPass for NegMultiply { } } -#[allow(match_same_arms)] +#[allow(clippy::match_same_arms)] impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref l, ref r) = e.node { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 81842421fa3..400a06c061e 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1525,7 +1525,7 @@ enum FullInt { } impl FullInt { - #[allow(cast_sign_loss)] + #[allow(clippy::cast_sign_loss)] fn cmp_s_u(s: i128, u: u128) -> Ordering { if s < 0 { Ordering::Less @@ -1744,7 +1744,7 @@ impl LintPass for ImplicitHasher { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { - #[allow(cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation)] fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { use syntax_pos::BytePos; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index fe8123d288d..fb131b9086a 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,7 +1,7 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -#![allow(print_stdout, use_debug)] +#![allow(clippy::print_stdout, clippy::use_debug)] use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index 35f41d400ad..31e20f37e20 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -1,6 +1,6 @@ //! Utility functions about comparison operators. -#![deny(missing_docs_in_private_items)] +#![deny(clippy::missing_docs_in_private_items)] use rustc::hir::{BinOpKind, Expr}; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1567bd9ffb6..47b71ae524f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -1,6 +1,6 @@ //! Read configurations files. -#![deny(missing_docs_in_private_items)] +#![deny(clippy::missing_docs_in_private_items)] use lazy_static::lazy_static; use std::{env, fmt, fs, io, path}; diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs index f59716268a0..b63be9b86c8 100644 --- a/clippy_lints/src/utils/constants.rs +++ b/clippy_lints/src/utils/constants.rs @@ -1,6 +1,6 @@ //! This module contains some useful constants. -#![deny(missing_docs_in_private_items)] +#![deny(clippy::missing_docs_in_private_items)] /// List of the built-in types names. /// diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 65d58c4e55b..42b37568a99 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,7 +1,7 @@ //! This module contains functions for retrieve the original AST from lowered //! `hir`. -#![deny(missing_docs_in_private_items)] +#![deny(clippy::missing_docs_in_private_items)] use if_chain::if_chain; use rustc::{hir, ty}; diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 30c6db977f7..93d73ca707e 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { }.hash(&mut self.s); } - #[allow(many_single_char_names)] + #[allow(clippy::many_single_char_names)] pub fn hash_expr(&mut self, e: &Expr) { if let Some(e) = constant_simple(self.cx, self.tables, e) { return e.hash(&mut self.s); diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 12b4f55e432..b9a0435eb35 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -1,4 +1,4 @@ -#![allow(print_stdout, use_debug)] +#![allow(clippy::print_stdout, clippy::use_debug)] //! checks for attributes diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 3d587a72eec..4239b24d817 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -1,7 +1,5 @@ //! Contains utility functions to generate suggestions. -#![deny(missing_docs_in_private_items)] -// currently ignores lifetimes and generics -#![allow(use_self)] +#![deny(clippy::missing_docs_in_private_items)] use matches::matches; use rustc::hir; @@ -40,7 +38,7 @@ impl Display for Sugg<'_> { } } -#[allow(wrong_self_convention)] // ok, because of the function `as_ty` method +#[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. pub fn hir_opt(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<Self> { diff --git a/src/driver.rs b/src/driver.rs index 6854ccbbddc..6885c2aed2b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,13 +1,14 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![allow(unknown_lints, missing_docs_in_private_items)] +#![feature(tool_lints)] +#![allow(unknown_lints, clippy::missing_docs_in_private_items)] use rustc_driver::{self, driver::CompileController, Compilation}; use rustc_plugin; use std::process::{exit, Command}; -#[allow(print_stdout)] +#[allow(clippy::print_stdout)] fn show_version() { println!(env!("CARGO_PKG_VERSION")); } diff --git a/src/lib.rs b/src/lib.rs index 1525dbda4ee..a7167ac10de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] +#![feature(tool_lints)] #![allow(unknown_lints)] -#![allow(missing_docs_in_private_items)] +#![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] use rustc_plugin::Registry; diff --git a/src/main.rs b/src/main.rs index 057a585e3d7..12c07f60a11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![allow(unknown_lints, missing_docs_in_private_items)] +#![feature(tool_lints)] +#![allow(unknown_lints, clippy::missing_docs_in_private_items)] const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -28,12 +29,12 @@ it to allow or deny lints from the code, eg.: #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] "#; -#[allow(print_stdout)] +#[allow(clippy::print_stdout)] fn show_help() { println!("{}", CARGO_CLIPPY_HELP); } -#[allow(print_stdout)] +#[allow(clippy::print_stdout)] fn show_version() { println!(env!("CARGO_PKG_VERSION")); } -- cgit 1.4.1-3-g733a5 From daa4f0ad34f79a91a6ae27fec6d56dd95e6feac2 Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Tue, 28 Aug 2018 14:16:31 +0200 Subject: Implement backwards compatibility changes introduced by rust-lang/rust#53762 --- clippy_lints/src/lib.rs | 20 ++++++++++---------- src/driver.rs | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f1a89c3d46b..19d31d6fc0f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -412,7 +412,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box non_copy_const::NonCopyConst); reg.register_late_lint_pass(box ptr_offset_with_cast::Pass); - reg.register_lint_group("clippy::restriction", vec![ + reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, arithmetic::INTEGER_ARITHMETIC, else_if_without_else::ELSE_IF_WITHOUT_ELSE, @@ -435,7 +435,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { write::USE_DEBUG, ]); - reg.register_lint_group("clippy::pedantic", vec![ + reg.register_lint_group("clippy::pedantic", Some("clippy_pedantic"), vec![ attrs::INLINE_ALWAYS, copies::MATCH_SAME_ARMS, copy_iterator::COPY_ITERATOR, @@ -473,13 +473,13 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { use_self::USE_SELF, ]); - reg.register_lint_group("clippy::internal", vec![ + reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![ utils::internal_lints::CLIPPY_LINTS_INTERNAL, utils::internal_lints::LINT_WITHOUT_LINT_PASS, utils::internal_lints::DEFAULT_HASH_TYPES, ]); - reg.register_lint_group("clippy::all", vec![ + reg.register_lint_group("clippy::all", Some("clippy"), vec![ approx_const::APPROX_CONSTANT, assign_ops::ASSIGN_OP_PATTERN, assign_ops::MISREFACTORED_ASSIGN_OP, @@ -694,7 +694,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); - reg.register_lint_group("clippy::style", vec![ + reg.register_lint_group("clippy::style", Some("clippy_style"), vec![ assign_ops::ASSIGN_OP_PATTERN, bit_mask::VERBOSE_BIT_MASK, blacklisted_name::BLACKLISTED_NAME, @@ -778,7 +778,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { write::WRITELN_EMPTY_STRING, ]); - reg.register_lint_group("clippy::complexity", vec![ + reg.register_lint_group("clippy::complexity", Some("clippy_complexity"), vec![ assign_ops::MISREFACTORED_ASSIGN_OP, booleans::NONMINIMAL_BOOL, cyclomatic_complexity::CYCLOMATIC_COMPLEXITY, @@ -846,7 +846,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); - reg.register_lint_group("clippy::correctness", vec![ + reg.register_lint_group("clippy::correctness", Some("clippy_correctness"), vec![ approx_const::APPROX_CONSTANT, attrs::DEPRECATED_SEMVER, attrs::USELESS_ATTRIBUTE, @@ -900,7 +900,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { unused_io_amount::UNUSED_IO_AMOUNT, ]); - reg.register_lint_group("clippy::perf", vec![ + reg.register_lint_group("clippy::perf", Some("clippy_perf"), vec![ bytecount::NAIVE_BYTECOUNT, entry::MAP_ENTRY, escape::BOXED_LOCAL, @@ -918,11 +918,11 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { vec::USELESS_VEC, ]); - reg.register_lint_group("clippy::cargo", vec![ + reg.register_lint_group("clippy::cargo", Some("clippy_cargo"), vec![ multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, ]); - reg.register_lint_group("clippy::nursery", vec![ + reg.register_lint_group("clippy::nursery", Some("clippy_nursery"), vec![ attrs::EMPTY_LINE_AFTER_OUTER_ATTR, fallible_impl_from::FALLIBLE_IMPL_FROM, mutex_atomic::MUTEX_INTEGER, diff --git a/src/driver.rs b/src/driver.rs index 6885c2aed2b..26ff846177b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -119,8 +119,8 @@ pub fn main() { ls.register_late_pass(Some(sess), true, pass); } - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); + for (name, (to, deprecated_name)) in lint_groups { + ls.register_group(Some(sess), true, name, deprecated_name, to); } clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); -- cgit 1.4.1-3-g733a5 From 4f7a260472d1722c8b2bf0771c875e69f3a2bf48 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Thu, 6 Sep 2018 07:01:56 +0200 Subject: driver: Improve check for rustc arg The rustc arg might not be exactly "rustc". It may be any path to a rustc executable (especially if the RUSTC environment variable is set when executing cargo). Rather check that it is a path with 'rustc' file stem. --- src/driver.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 26ff846177b..267e460ad2e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -6,6 +6,7 @@ use rustc_driver::{self, driver::CompileController, Compilation}; use rustc_plugin; +use std::path::Path; use std::process::{exit, Command}; #[allow(clippy::print_stdout)] @@ -47,7 +48,7 @@ pub fn main() { if orig_args.len() <= 1 { std::process::exit(1); } - if orig_args[1] == "rustc" { + if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { // we still want to be able to invoke it normally though orig_args.remove(1); } -- cgit 1.4.1-3-g733a5 From fa11aad92a20aaf64c1ee4f43015fba9b6d24b62 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Thu, 6 Sep 2018 08:19:47 +0200 Subject: print git commit hash and commit date in version output clippy 0.0.212 (964fcbe0 2018-09-06) --- .gitignore | 1 + Cargo.toml | 4 +++ build.rs | 13 +++++-- ci/base-tests.sh | 2 ++ rustc_tools_util/Cargo.toml | 8 +++++ rustc_tools_util/src/lib.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 9 +++-- 7 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 rustc_tools_util/Cargo.toml create mode 100644 rustc_tools_util/src/lib.rs (limited to 'src') diff --git a/.gitignore b/.gitignore index 5fd7f2fc1a0..166cab60a58 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ Cargo.lock /clippy_lints/target /clippy_workspace_tests/target /clippy_dev/target +/rustc_tools_util/target # Generated by dogfood /target_recur/ diff --git a/Cargo.toml b/Cargo.toml index 52f93820c48..0b9ed1d8610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ clippy_lints = { version = "0.0.212", path = "clippy_lints" } # end automatic update regex = "1" semver = "0.9" +rustc_tools_util = { version = "0.1.0", path = "rustc_tools_util"} [dev-dependencies] clippy_dev = { version = "0.0.1", path = "clippy_dev" } @@ -65,5 +66,8 @@ derive-new = "0.5" # for more information. rustc-workspace-hack = "1.0.0" +[build-dependencies] +rustc_tools_util = { version = "0.1.0", path = "rustc_tools_util"} + [features] debugging = [] diff --git a/build.rs b/build.rs index 1c930c1b2c9..146a8dae745 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,15 @@ -use std::env; - fn main() { // Forward the profile to the main compilation - println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); + println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); // Don't rebuild even if nothing changed println!("cargo:rerun-if-changed=build.rs"); + // forward git repo hashes we build at + println!( + "cargo:rustc-env=GIT_HASH={}", + rustc_tools_util::get_commit_hash().unwrap_or_default() + ); + println!( + "cargo:rustc-env=COMMIT_DATE={}", + rustc_tools_util::get_commit_date().unwrap_or_default() + ); } diff --git a/ci/base-tests.sh b/ci/base-tests.sh index b85ed4fab66..94a810e4ef4 100755 --- a/ci/base-tests.sh +++ b/ci/base-tests.sh @@ -20,6 +20,8 @@ cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy::all && cd ../.. cd clippy_workspace_tests/subcrate/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy::all && cd ../../.. cd clippy_dev && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy::all && cd .. +cd rustc_tools_util/ && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy::all && cd .. + # test --manifest-path PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=clippy_workspace_tests/Cargo.toml -- -D clippy::all cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=../Cargo.toml -- -D clippy::all && cd ../.. diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml new file mode 100644 index 00000000000..01dca0a65b0 --- /dev/null +++ b/rustc_tools_util/Cargo.toml @@ -0,0 +1,8 @@ +cargo-features = ["edition"] + +[package] +name = "rustc_tools_util" +version = "0.1.0" +authors = ["Matthias Krüger <matthias.krueger@famsik.de>"] +edition = "2018" +[dependencies] diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs new file mode 100644 index 00000000000..20b598346f1 --- /dev/null +++ b/rustc_tools_util/src/lib.rs @@ -0,0 +1,82 @@ +#![feature(tool_lints)] + +use std::env; + +#[macro_export] +macro_rules! get_version_info { + () => {{ + let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap(); + let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap(); + let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap(); + + let host_compiler = $crate::get_channel(); + let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string()); + let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string()); + + VersionInfo { + major, + minor, + patch, + host_compiler, + commit_hash, + commit_date, + } + }}; +} + +// some code taken and adapted from RLS and cargo +pub struct VersionInfo { + pub major: u8, + pub minor: u8, + pub patch: u16, + pub host_compiler: Option<String>, + pub commit_hash: Option<String>, + pub commit_date: Option<String>, +} + +impl std::fmt::Display for VersionInfo { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self.commit_hash { + Some(_) => { + write!( + f, + "clippy {}.{}.{} ({} {})", + self.major, + self.minor, + self.patch, + self.commit_hash.clone().unwrap_or_default().trim(), + self.commit_date.clone().unwrap_or_default().trim(), + )?; + }, + None => { + write!(f, "clippy {}.{}.{}", self.major, self.minor, self.patch)?; + }, + }; + Ok(()) + } +} + +pub fn get_channel() -> Option<String> { + if let Ok(channel) = env::var("CFG_RELEASE_CHANNEL") { + Some(channel) + } else { + // we could ask ${RUSTC} -Vv and do some parsing and find out + Some(String::from("nightly")) + } +} + +pub fn get_commit_hash() -> Option<String> { + std::process::Command::new("git") + .args(&["rev-parse", "--short", "HEAD"]) + .output() + .ok() + .and_then(|r| String::from_utf8(r.stdout).ok()) +} + +pub fn get_commit_date() -> Option<String> { + std::process::Command::new("git") + .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) + .output() + .ok() + .and_then(|r| String::from_utf8(r.stdout).ok()) +} diff --git a/src/main.rs b/src/main.rs index 12c07f60a11..cf26549774c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ #![feature(tool_lints)] #![allow(unknown_lints, clippy::missing_docs_in_private_items)] +use rustc_tools_util::*; + const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. Usage: @@ -36,7 +38,8 @@ fn show_help() { #[allow(clippy::print_stdout)] fn show_version() { - println!(env!("CARGO_PKG_VERSION")); + let version_info = rustc_tools_util::get_version_info!(); + println!("{}", version_info); } pub fn main() { @@ -45,6 +48,7 @@ pub fn main() { show_help(); return; } + if std::env::args().any(|a| a == "--version" || a == "-V") { show_version(); return; @@ -94,8 +98,7 @@ where .into_os_string() }, ) - }) - .map(|p| ("CARGO_TARGET_DIR", p)); + }).map(|p| ("CARGO_TARGET_DIR", p)); let exit_status = std::process::Command::new("cargo") .args(&args) -- cgit 1.4.1-3-g733a5 From f49f133cba27ea20ba11a4f0a0cca8473455cecf Mon Sep 17 00:00:00 2001 From: flip1995 <9744647+flip1995@users.noreply.github.com> Date: Fri, 14 Sep 2018 12:56:25 +0200 Subject: Fix pedantic filter_map warnings --- clippy_lints/src/inherent_impl.rs | 7 +++++-- src/driver.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index a78811c31e5..9c4a6bfcb8e 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -78,8 +78,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let mut impl_spans = impls .iter() .filter_map(|impl_def| self.impls.get(impl_def)) - .filter(|(_, generics)| generics.params.len() == 0) - .map(|(span, _)| span); + .filter_map(|(span, generics)| if generics.params.len() == 0 { + Some(span) + } else { + None + }); if let Some(initial_span) = impl_spans.nth(0) { impl_spans.for_each(|additional_span| { span_lint_and_then( diff --git a/src/driver.rs b/src/driver.rs index 267e460ad2e..e85f61e343f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -78,8 +78,11 @@ pub fn main() { args.extend( extra_args .split("__CLIPPY_HACKERY__") - .filter(|s| !s.is_empty()) - .map(str::to_owned), + .filter_map(|s| if s.is_empty() { + None + } else { + Some(s.to_string()) + }) ); } } -- cgit 1.4.1-3-g733a5 From 9219fc6c5c0d4fa2e5b7580448a2acccabc2c988 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu <edy.burt@gmail.com> Date: Sat, 15 Sep 2018 10:21:58 +0300 Subject: Reintroduce `extern crate` for non-Cargo dependencies. --- clippy_lints/src/approx_const.rs | 10 +++--- clippy_lints/src/arithmetic.rs | 8 ++--- clippy_lints/src/assign_ops.rs | 12 ++++---- clippy_lints/src/attrs.rs | 12 ++++---- clippy_lints/src/bit_mask.rs | 10 +++--- clippy_lints/src/blacklisted_name.rs | 6 ++-- clippy_lints/src/block_in_if_condition.rs | 8 ++--- clippy_lints/src/booleans.rs | 14 ++++----- clippy_lints/src/bytecount.rs | 10 +++--- clippy_lints/src/collapsible_if.rs | 6 ++-- clippy_lints/src/const_static_lifetime.rs | 6 ++-- clippy_lints/src/consts.rs | 22 ++++++------- clippy_lints/src/copies.rs | 14 ++++----- clippy_lints/src/copy_iterator.rs | 6 ++-- clippy_lints/src/cyclomatic_complexity.rs | 16 +++++----- clippy_lints/src/default_trait_access.rs | 8 ++--- clippy_lints/src/derive.rs | 10 +++--- clippy_lints/src/doc.rs | 10 +++--- clippy_lints/src/double_comparison.rs | 8 ++--- clippy_lints/src/double_parens.rs | 6 ++-- clippy_lints/src/drop_forget_ref.rs | 8 ++--- clippy_lints/src/duration_subsec.rs | 8 ++--- clippy_lints/src/else_if_without_else.rs | 6 ++-- clippy_lints/src/empty_enum.rs | 6 ++-- clippy_lints/src/entry.rs | 10 +++--- clippy_lints/src/enum_clike.rs | 16 +++++----- clippy_lints/src/enum_glob_use.rs | 12 ++++---- clippy_lints/src/enum_variants.rs | 10 +++--- clippy_lints/src/eq_op.rs | 6 ++-- clippy_lints/src/erasing_op.rs | 8 ++--- clippy_lints/src/escape.rs | 22 ++++++------- clippy_lints/src/eta_reduction.rs | 8 ++--- clippy_lints/src/eval_order_dependence.rs | 12 ++++---- clippy_lints/src/excessive_precision.rs | 12 ++++---- clippy_lints/src/explicit_write.rs | 6 ++-- clippy_lints/src/fallible_impl_from.rs | 14 ++++----- clippy_lints/src/format.rs | 12 ++++---- clippy_lints/src/formatting.rs | 8 ++--- clippy_lints/src/functions.rs | 20 ++++++------ clippy_lints/src/identity_conversion.rs | 8 ++--- clippy_lints/src/identity_op.rs | 10 +++--- .../src/if_let_redundant_pattern_matching.rs | 6 ++-- clippy_lints/src/if_not_else.rs | 6 ++-- clippy_lints/src/indexing_slicing.rs | 10 +++--- clippy_lints/src/infallible_destructuring_match.rs | 6 ++-- clippy_lints/src/infinite_iter.rs | 6 ++-- clippy_lints/src/inherent_impl.rs | 10 +++--- clippy_lints/src/inline_fn_without_body.rs | 8 ++--- clippy_lints/src/int_plus_one.rs | 6 ++-- clippy_lints/src/invalid_ref.rs | 8 ++--- clippy_lints/src/items_after_statements.rs | 6 ++-- clippy_lints/src/large_enum_variant.rs | 8 ++--- clippy_lints/src/len_zero.rs | 18 +++++------ clippy_lints/src/let_if_seq.rs | 12 ++++---- clippy_lints/src/lib.rs | 26 +++++++++++++--- clippy_lints/src/lifetimes.rs | 16 +++++----- clippy_lints/src/literal_representation.rs | 8 ++--- clippy_lints/src/loops.rs | 36 +++++++++++----------- clippy_lints/src/map_clone.rs | 10 +++--- clippy_lints/src/map_unit_fn.rs | 12 ++++---- clippy_lints/src/matches.rs | 12 ++++---- clippy_lints/src/mem_forget.rs | 6 ++-- clippy_lints/src/methods.rs | 14 ++++----- clippy_lints/src/minmax.rs | 6 ++-- clippy_lints/src/misc.rs | 14 ++++----- clippy_lints/src/misc_early.rs | 12 ++++---- clippy_lints/src/missing_doc.rs | 14 ++++----- clippy_lints/src/missing_inline.rs | 14 ++++----- clippy_lints/src/multiple_crate_versions.rs | 6 ++-- clippy_lints/src/mut_mut.rs | 12 ++++---- clippy_lints/src/mut_reference.rs | 10 +++--- clippy_lints/src/mutex_atomic.rs | 10 +++--- clippy_lints/src/needless_bool.rs | 10 +++--- clippy_lints/src/needless_borrow.rs | 10 +++--- clippy_lints/src/needless_borrowed_ref.rs | 6 ++-- clippy_lints/src/needless_continue.rs | 8 ++--- clippy_lints/src/needless_pass_by_value.rs | 26 ++++++++-------- clippy_lints/src/needless_update.rs | 8 ++--- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 6 ++-- clippy_lints/src/neg_multiply.rs | 8 ++--- clippy_lints/src/new_without_default.rs | 12 ++++---- clippy_lints/src/no_effect.rs | 8 ++--- clippy_lints/src/non_copy_const.rs | 18 +++++------ clippy_lints/src/non_expressive_names.rs | 14 ++++----- clippy_lints/src/ok_if_let.rs | 6 ++-- clippy_lints/src/open_options.rs | 10 +++--- clippy_lints/src/overflow_check_conditional.rs | 6 ++-- clippy_lints/src/panic_unimplemented.rs | 12 ++++---- clippy_lints/src/partialeq_ne_impl.rs | 6 ++-- clippy_lints/src/precedence.rs | 12 ++++---- clippy_lints/src/ptr.rs | 16 +++++----- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/question_mark.rs | 10 +++--- clippy_lints/src/ranges.rs | 10 +++--- clippy_lints/src/redundant_field_names.rs | 6 ++-- clippy_lints/src/reference.rs | 6 ++-- clippy_lints/src/regex.rs | 12 ++++---- clippy_lints/src/replace_consts.rs | 8 ++--- clippy_lints/src/returns.rs | 10 +++--- clippy_lints/src/serde_api.rs | 6 ++-- clippy_lints/src/shadow.rs | 12 ++++---- clippy_lints/src/strings.rs | 10 +++--- clippy_lints/src/suspicious_trait_impl.rs | 10 +++--- clippy_lints/src/swap.rs | 8 ++--- clippy_lints/src/temporary_assignment.rs | 6 ++-- clippy_lints/src/transmute.rs | 10 +++--- clippy_lints/src/trivially_copy_pass_by_ref.rs | 22 ++++++------- clippy_lints/src/types.rs | 32 +++++++++---------- clippy_lints/src/unicode.rs | 10 +++--- clippy_lints/src/unsafe_removed_from_name.rs | 10 +++--- clippy_lints/src/unused_io_amount.rs | 6 ++-- clippy_lints/src/unused_label.rs | 16 +++++----- clippy_lints/src/unwrap.rs | 12 ++++---- clippy_lints/src/use_self.rs | 12 ++++---- clippy_lints/src/utils/author.rs | 14 ++++----- clippy_lints/src/utils/comparisons.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/higher.rs | 6 ++-- clippy_lints/src/utils/hir_utils.rs | 10 +++--- clippy_lints/src/utils/inspector.rs | 10 +++--- clippy_lints/src/utils/internal_lints.rs | 18 +++++------ clippy_lints/src/utils/mod.rs | 34 ++++++++++---------- clippy_lints/src/utils/ptr.rs | 10 +++--- clippy_lints/src/utils/sugg.rs | 28 ++++++++--------- clippy_lints/src/utils/usage.rs | 20 ++++++------ clippy_lints/src/vec.rs | 10 +++--- clippy_lints/src/write.rs | 12 ++++---- clippy_lints/src/zero_div_zero.rs | 6 ++-- src/driver.rs | 10 ++++-- src/lib.rs | 6 +++- 130 files changed, 723 insertions(+), 695 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 99b9e79463a..4d921daea8a 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,10 +1,10 @@ use crate::utils::span_lint; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use std::f64::consts as f64; -use syntax::ast::{FloatTy, Lit, LitKind}; -use syntax::symbol; +use crate::syntax::ast::{FloatTy, Lit, LitKind}; +use crate::syntax::symbol; /// **What it does:** Checks for floating point literals that approximate /// constants which are defined in diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index fa48b2b5506..bdf8d237c70 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -1,8 +1,8 @@ use crate::utils::span_lint; -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Span; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Span; /// **What it does:** Checks for plain integer arithmetic. /// diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 9a1808345a5..d50b72b19ac 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,11 +1,11 @@ use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq}; use crate::utils::{higher, sugg}; -use rustc::hir; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast; +use crate::syntax::ast; /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` /// patterns. @@ -220,7 +220,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { } fn is_commutative(op: hir::BinOpKind) -> bool { - use rustc::hir::BinOpKind::*; + use crate::rustc::hir::BinOpKind::*; match op { Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true, Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false, diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 034c2cc241a..3a8514818f6 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,14 +5,14 @@ use crate::utils::{ in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then, without_block_comments, }; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, TyCtxt}; +use crate::rustc::ty::{self, TyCtxt}; use semver::Version; -use syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use syntax::source_map::Span; +use crate::syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; +use crate::syntax::source_map::Span; /// **What it does:** Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index ecac7f8250b..93c6bee03bf 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,9 +1,9 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast::LitKind; -use syntax::source_map::Span; +use crate::syntax::ast::LitKind; +use crate::syntax::source_map::Span; use crate::utils::{span_lint, span_lint_and_then}; use crate::utils::sugg::Sugg; use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 97749e6f997..9d6005cd612 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; use crate::utils::span_lint; /// **What it does:** Checks for usage of blacklisted names for variables, such diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 752d640fa9e..c1b4b4575ab 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,8 +1,8 @@ use matches::matches; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::utils::*; /// **What it does:** Checks for `if` conditions that use blocks to contain an diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 3d3fa7b5e73..b2639330071 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::hir::intravisit::*; -use syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID}; -use syntax::source_map::{dummy_spanned, Span, DUMMY_SP}; -use rustc_data_structures::thin_vec::ThinVec; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::*; +use crate::syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID}; +use crate::syntax::source_map::{dummy_spanned, Span, DUMMY_SP}; +use crate::rustc_data_structures::thin_vec::ThinVec; use crate::utils::{in_macro, paths, match_type, snippet_opt, span_lint_and_then, SpanlessEq, get_trait_def_id, implements_trait}; /// **What it does:** Checks for boolean expressions that can be written more diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index ddc017c27df..7ec556b5d78 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,9 +1,9 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use syntax::ast::{Name, UintTy}; +use crate::rustc::ty; +use crate::syntax::ast::{Name, UintTy}; use crate::utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg, walk_ptrs_ty}; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 55cc94f399f..a24436991e5 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -12,10 +12,10 @@ //! //! This lint is **warn** by default -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast; +use crate::syntax::ast; use crate::utils::{in_macro, snippet_block, span_lint_and_sugg, span_lint_and_then}; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index 83dd4c0509e..6daddb5fe13 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -1,6 +1,6 @@ -use syntax::ast::*; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use crate::utils::{in_macro, snippet, span_lint_and_then}; /// **What it does:** Checks for constants with an explicit `'static` lifetime. diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index bcc85c31376..43796004d0e 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,18 +1,18 @@ #![allow(clippy::float_cmp)] -use rustc::lint::LateContext; -use rustc::{span_bug, bug}; -use rustc::hir::def::Def; -use rustc::hir::*; -use rustc::ty::{self, Ty, TyCtxt, Instance}; -use rustc::ty::subst::{Subst, Substs}; +use crate::rustc::lint::LateContext; +use crate::rustc::{span_bug, bug}; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::*; +use crate::rustc::ty::{self, Ty, TyCtxt, Instance}; +use crate::rustc::ty::subst::{Subst, Substs}; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; use std::hash::{Hash, Hasher}; use std::mem; use std::rc::Rc; -use syntax::ast::{FloatTy, LitKind}; -use syntax::ptr::P; +use crate::syntax::ast::{FloatTy, LitKind}; +use crate::syntax::ptr::P; use crate::utils::{sext, unsext, clip}; /// A `LitKind`-like enum to fold constant `Expr`s into. @@ -139,7 +139,7 @@ impl Constant { /// parse a `LitKind` to a `Constant` pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant { - use syntax::ast::*; + use crate::syntax::ast::*; match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), @@ -279,7 +279,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { instance, promoted: None, }; - use rustc::mir::interpret::GlobalId; + use crate::rustc::mir::interpret::GlobalId; let result = self.tcx.const_eval(self.param_env.and(gid)).ok()?; let ret = miri_to_const(self.tcx, result); if ret.is_some() { @@ -409,7 +409,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option<Constant> { - use rustc::mir::interpret::{Scalar, ScalarMaybeUndef, ConstValue}; + use crate::rustc::mir::interpret::{Scalar, ScalarMaybeUndef, ConstValue}; match result.val { ConstValue::Scalar(Scalar::Bits{ bits: b, ..}) => match result.ty.sty { ty::Bool => Some(Constant::Bool(b == 1)), diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 01063d41ee8..76c8360be62 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,12 +1,12 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty::Ty; -use rustc::hir::*; -use rustc_data_structures::fx::FxHashMap; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty::Ty; +use crate::rustc::hir::*; +use crate::rustc_data_structures::fx::FxHashMap; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; -use syntax::symbol::LocalInternedString; -use rustc_data_structures::small_vec::OneVector; +use crate::syntax::symbol::LocalInternedString; +use crate::rustc_data_structures::small_vec::OneVector; use crate::utils::{SpanlessEq, SpanlessHash}; use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint}; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 596e83bc539..17f32c7bb45 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,7 +1,7 @@ use crate::utils::{is_copy, match_path, paths, span_note_and_lint}; -use rustc::hir::{Item, ItemKind}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::{Item, ItemKind}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; /// **What it does:** Checks for types that implement `Copy` as well as /// `Iterator`. diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index c975e31cec9..db85a3f3fda 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -1,13 +1,13 @@ //! calculate cyclomatic complexity and warn about overly complex functions -use rustc::cfg::CFG; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::ty; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use syntax::ast::{Attribute, NodeId}; -use syntax::source_map::Span; +use crate::rustc::cfg::CFG; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::ty; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::syntax::ast::{Attribute, NodeId}; +use crate::syntax::source_map::Span; use crate::utils::{in_macro, is_allowed, match_type, paths, span_help_and_lint, LimitStack}; diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index e7c90f04188..5f2b1a29dc7 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -1,8 +1,8 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::TyKind; +use crate::rustc::ty::TyKind; use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 2a26cca21ac..21365f60586 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,9 +1,9 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; -use rustc::hir::*; -use syntax::source_map::Span; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::hir::*; +use crate::syntax::source_map::Span; use crate::utils::paths; use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 4d603570ebe..19f2916cc5e 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,10 +1,10 @@ use itertools::Itertools; use pulldown_cmark; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast; -use syntax::source_map::{BytePos, Span}; -use syntax_pos::Pos; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast; +use crate::syntax::source_map::{BytePos, Span}; +use crate::syntax_pos::Pos; use crate::utils::span_lint; use url::Url; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 1f38be4d7b7..c692bffaff6 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,9 +1,9 @@ //! Lint on unnecessary double comparisons. Some examples: -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Span; use crate::utils::{snippet, span_lint_and_sugg, SpanlessEq}; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 42d6720d96c..90aaea90d96 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,6 +1,6 @@ -use syntax::ast::*; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; /// **What it does:** Checks for unnecessary double parentheses. /// diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index be804780ff5..1dbca5ed9ba 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,8 +1,8 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use rustc::hir::*; +use crate::rustc::ty; +use crate::rustc::hir::*; use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint}; /// **What it does:** Checks for calls to `std::mem::drop` with a reference diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 5853983dcf0..8ac34d9daa3 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,8 +1,8 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::source_map::Spanned; +use crate::syntax::source_map::Spanned; use crate::consts::{constant, Constant}; use crate::utils::paths; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 1c026713a5d..21a77e2263f 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,8 +1,8 @@ //! lint on if expressions with an else if, but without a final else branch -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::span_lint_and_sugg; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 195a78a89e5..48c96a0ffad 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,8 +1,8 @@ //! lint when there is an enum with no variants -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; use crate::utils::span_lint_and_then; /// **What it does:** Checks for `enum`s with no variants. diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 8a2fcbaea46..167f5633b2e 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,9 +1,9 @@ -use rustc::hir::*; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::source_map::Span; +use crate::syntax::source_map::Span; use crate::utils::SpanlessEq; use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 0271fee8a3c..b49322dcaf9 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,16 +1,16 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::ty; -use rustc::ty::subst::Substs; -use syntax::ast::{IntTy, UintTy}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::ty; +use crate::rustc::ty::subst::Substs; +use crate::syntax::ast::{IntTy, UintTy}; use crate::utils::span_lint; use crate::consts::{Constant, miri_to_const}; -use rustc::ty::util::IntTypeExt; -use rustc::mir::interpret::GlobalId; +use crate::rustc::ty::util::IntTypeExt; +use crate::rustc::mir::interpret::GlobalId; /// **What it does:** Checks for C-like enumerations that are /// `repr(isize/usize)` and have values that don't fit into an `i32`. diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 042a4765e2b..d594406decf 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -1,11 +1,11 @@ //! lint on `use`ing all variants of an enum -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::NodeId; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::hir::def::Def; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::NodeId; +use crate::syntax::source_map::Span; use crate::utils::span_lint; /// **What it does:** Checks for `use Enum::*`. diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 56b99aa9449..c68439d161b 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,10 +1,10 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, Lint}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; -use syntax::source_map::Span; -use syntax::symbol::LocalInternedString; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, Lint}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; +use crate::syntax::source_map::Span; +use crate::syntax::symbol::LocalInternedString; use crate::utils::{span_help_and_lint, span_lint}; use crate::utils::{camel_case_from, camel_case_until, in_macro}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index b6b34204480..d182faa1e5c 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,6 +1,6 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use crate::utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq}; /// **What it does:** Checks for equal operands to comparison, logical and diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 5b61a9fd883..7e313daffa4 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,8 +1,8 @@ use crate::consts::{constant_simple, Constant}; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Span; use crate::utils::{in_macro, span_lint}; /// **What it does:** Checks for erasing operations, e.g. `x * 0`. diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 282149f81f9..8af232420b1 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,14 +1,14 @@ -use rustc::hir::*; -use rustc::hir::intravisit as visit; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::middle::expr_use_visitor::*; -use rustc::middle::mem_categorization::{cmt_, Categorization}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutOf; -use rustc::util::nodemap::NodeSet; -use syntax::ast::NodeId; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit as visit; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::middle::expr_use_visitor::*; +use crate::rustc::middle::mem_categorization::{cmt_, Categorization}; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::ty::layout::LayoutOf; +use crate::rustc::util::nodemap::NodeSet; +use crate::syntax::ast::NodeId; +use crate::syntax::source_map::Span; use crate::utils::span_lint; pub struct Pass { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index c4ffc70dbfd..e331f6adf3a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::rustc::hir::*; use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then}; #[allow(missing_copy_implementations)] diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index e3ae5607645..068d6fb135f 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,10 +1,10 @@ -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc::hir::*; -use rustc::ty; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc::hir::*; +use crate::rustc::ty; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast; +use crate::syntax::ast; use crate::utils::{get_parent_expr, span_lint, span_note_and_lint}; /// **What it does:** Checks for a read and a write to the same variable where diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index e5809371e83..6df88cdc6c3 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -1,13 +1,13 @@ -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::TyKind; +use crate::rustc::ty::TyKind; use std::f32; use std::f64; use std::fmt; -use syntax::ast::*; -use syntax_pos::symbol::Symbol; +use crate::syntax::ast::*; +use crate::syntax_pos::symbol::Symbol; use crate::utils::span_lint_and_sugg; /// **What it does:** Checks for float literals with a precision greater diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 77c6c1a4ad7..888dca97928 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,6 +1,6 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint}; use crate::utils::opt_def_id; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 88eb880311e..146e2366552 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,9 +1,9 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir; -use rustc::ty; -use syntax_pos::Span; +use crate::rustc::hir; +use crate::rustc::ty; +use crate::syntax_pos::Span; use crate::utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_expn_of, opt_def_id}; use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT}; @@ -52,8 +52,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom { } fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &hir::HirVec<hir::ImplItemRef>) { - use rustc::hir::*; - use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; + use crate::rustc::hir::*; + use crate::rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; struct FindPanicUnwrap<'a, 'tcx: 'a> { tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index c10d554660a..fbc3c750cde 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,10 +1,10 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use syntax::ast::LitKind; -use syntax_pos::Span; +use crate::rustc::ty; +use crate::syntax::ast::LitKind; +use crate::syntax_pos::Span; use crate::utils::paths; use crate::utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty}; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 8b20aeed108..92950706d88 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,8 +1,8 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast; use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; -use syntax::ptr::P; +use crate::syntax::ptr::P; /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` /// operators. diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index ec9aa7a4fd3..d73c0710ba1 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,14 +1,14 @@ use matches::matches; -use rustc::hir::intravisit; -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use rustc::hir::def::Def; -use rustc_data_structures::fx::FxHashSet; -use syntax::ast; -use rustc_target::spec::abi::Abi; -use syntax::source_map::Span; +use crate::rustc::hir::intravisit; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::rustc::hir::def::Def; +use crate::rustc_data_structures::fx::FxHashSet; +use crate::syntax::ast; +use crate::rustc_target::spec::abi::Abi; +use crate::syntax::source_map::Span; use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function}; /// **What it does:** Checks for functions with too many parameters. diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index 6adf2cd6814..24b0d57d098 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use syntax::ast::NodeId; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::syntax::ast::NodeId; use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, span_lint_and_then}; use crate::utils::{opt_def_id, paths, resolve_node}; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 052275d7a45..836e4fafba4 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,10 +1,10 @@ use crate::consts::{constant_simple, Constant}; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Span; use crate::utils::{in_macro, snippet, span_lint, unsext, clip}; -use rustc::ty; +use crate::rustc::ty; /// **What it does:** Checks for identity operations, e.g. `x + 0`. /// diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs index 253d295567c..c996c91b48b 100644 --- a/clippy_lints/src/if_let_redundant_pattern_matching.rs +++ b/clippy_lints/src/if_let_redundant_pattern_matching.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; use crate::utils::{match_qpath, paths, snippet, span_lint_and_then}; /// **What it does:** Lint for redundant pattern matching over `Result` or diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 3bfde1fd20d..954f8543a87 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,9 +1,9 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::span_help_and_lint; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index bca4844aae7..1010b53e09a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -4,11 +4,11 @@ use crate::consts::{constant, Constant}; use crate::utils; use crate::utils::higher; use crate::utils::higher::Range; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use syntax::ast::RangeLimits; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::syntax::ast::RangeLimits; /// **What it does:** Checks for out of bounds array indexing with a constant /// index. diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs index 208f2ec5379..dabc167f37d 100644 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ b/clippy_lints/src/infallible_destructuring_match.rs @@ -1,7 +1,7 @@ use super::utils::{get_arg_name, match_var, remove_blocks, snippet, span_lint_and_sugg}; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; /// **What it does:** Checks for matches being used to destructure a single-variant enum diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index bb33c48fc3f..a15ec8c14bd 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint}; /// **What it does:** Checks for iteration that is guaranteed to be infinite. diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 9c4a6bfcb8e..36336b86398 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,11 +1,11 @@ //! lint on inherent implementations -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc_data_structures::fx::FxHashMap; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_data_structures::fx::FxHashMap; use std::default::Default; -use syntax_pos::Span; +use crate::syntax_pos::Span; use crate::utils::span_lint_and_then; /// **What it does:** Checks for multiple inherent implementations of a struct diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 4dcc4ed473d..29492cf8c43 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,9 +1,9 @@ //! checks for `#[inline]` on trait methods without bodies -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use syntax::ast::{Attribute, Name}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::syntax::ast::{Attribute, Name}; use crate::utils::span_lint_and_then; use crate::utils::sugg::DiagnosticBuilderExt; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index f94461b75a5..023a88e1ffa 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,8 +1,8 @@ //! lint on blocks unnecessarily using >= with a + 1 or - 1 -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::{snippet_opt, span_lint_and_then}; diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index 34a8939e104..55de8998378 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -1,8 +1,8 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use rustc::hir::*; +use crate::rustc::ty; +use crate::rustc::hir::*; use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint}; /// **What it does:** Checks for creation of references to zeroed or uninitialized memory. diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 9fe70882c86..a12c9c400ba 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,9 +1,9 @@ //! lint when items are used after statements use matches::matches; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::{in_macro, span_lint}; /// **What it does:** Checks for items declared after some statement in a block. diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 63201bb2e45..87f9804c1ae 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,10 +1,10 @@ //! lint when there is a large size difference between variants on an enum -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; use crate::utils::{snippet_opt, span_lint_and_then}; -use rustc::ty::layout::LayoutOf; +use crate::rustc::ty::layout::LayoutOf; /// **What it does:** Checks for large size differences between variants on /// `enum`s. diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index a31add18a94..b126b8dbb93 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,11 +1,11 @@ -use rustc::hir::def_id::DefId; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use rustc_data_structures::fx::FxHashSet; -use syntax::ast::{Lit, LitKind, Name}; -use syntax::source_map::{Span, Spanned}; +use crate::rustc::hir::def_id::DefId; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::rustc_data_structures::fx::FxHashSet; +use crate::syntax::ast::{Lit, LitKind, Name}; +use crate::syntax::source_map::{Span, Spanned}; use crate::utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty}; /// **What it does:** Checks for getting the length of something via `.len()` @@ -127,7 +127,7 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items // fill the set with current and super traits fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) { if set.insert(traitt) { - for supertrait in ::rustc::traits::supertrait_def_ids(cx.tcx, traitt) { + for supertrait in crate::rustc::traits::supertrait_def_ids(cx.tcx, traitt) { fill_trait_set(supertrait, set, cx); } } diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 8b4e2b0dec8..10dc3cae8af 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir; -use rustc::hir::BindingAnnotation; -use rustc::hir::def::Def; -use syntax::ast; +use crate::rustc::hir; +use crate::rustc::hir::BindingAnnotation; +use crate::rustc::hir::def::Def; +use crate::syntax::ast; use crate::utils::{snippet, span_lint_and_then}; /// **What it does:** Checks for variable declarations immediately followed by a diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5f001901481..3937e5cb9e9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -12,10 +12,28 @@ #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![feature(crate_visibility_modifier)] -use toml; -use rustc_plugin; -use rustc; +// FIXME: switch to something more ergonomic here, once available. +// (currently there is no way to opt into sysroot crates w/o `extern crate`) +#[allow(unused_extern_crates)] +extern crate fmt_macros; +#[allow(unused_extern_crates)] +extern crate rustc; +#[allow(unused_extern_crates)] +extern crate rustc_data_structures; +#[allow(unused_extern_crates)] +extern crate rustc_errors; +#[allow(unused_extern_crates)] +extern crate rustc_plugin; +#[allow(unused_extern_crates)] +extern crate rustc_target; +#[allow(unused_extern_crates)] +extern crate rustc_typeck; +#[allow(unused_extern_crates)] +extern crate syntax; +#[allow(unused_extern_crates)] +extern crate syntax_pos; +use toml; macro_rules! declare_clippy_lint { { pub $name:tt, style, $description:tt } => { @@ -175,7 +193,7 @@ pub mod zero_div_zero; pub use crate::utils::conf::Conf; mod reexport { - crate use syntax::ast::{Name, NodeId}; + crate use crate::syntax::ast::{Name, NodeId}; } pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore, conf: &Conf) { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5b04b829453..ee8517b76d7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,14 +1,14 @@ use crate::reexport::*; use matches::matches; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::def::Def; -use rustc::hir::*; -use rustc::hir::intravisit::*; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use syntax::source_map::Span; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::*; +use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::syntax::source_map::Span; use crate::utils::{last_path_segment, span_lint}; -use syntax::symbol::keywords; +use crate::syntax::symbol::keywords; /// **What it does:** Checks for lifetime annotations which can be removed by /// relying on lifetime elision. diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 304721886cc..188ca157423 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,11 +1,11 @@ //! Lints concerned with the grouping of digits with underscores in integral or //! floating-point literal expressions. -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast::*; -use syntax_pos; +use crate::syntax::ast::*; +use crate::syntax_pos; use crate::utils::{snippet_opt, span_lint_and_sugg}; /// **What it does:** Warns if a long integral or floating-point constant does diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 7240819646f..7472700ddbc 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,25 +1,25 @@ use itertools::Itertools; use crate::reexport::*; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::def_id; -use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::def_id; +use crate::rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::middle::region; -// use rustc::middle::region::CodeExtent; -use rustc::middle::expr_use_visitor::*; -use rustc::middle::mem_categorization::Categorization; -use rustc::middle::mem_categorization::cmt_; -use rustc::ty::{self, Ty}; -use rustc::ty::subst::Subst; -use rustc_errors::Applicability; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::rustc::middle::region; +// use crate::rustc::middle::region::CodeExtent; +use crate::rustc::middle::expr_use_visitor::*; +use crate::rustc::middle::mem_categorization::Categorization; +use crate::rustc::middle::mem_categorization::cmt_; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::ty::subst::Subst; +use crate::rustc_errors::Applicability; +use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::iter::{once, Iterator}; -use syntax::ast; -use syntax::source_map::Span; -use syntax_pos::BytePos; +use crate::syntax::ast; +use crate::syntax::source_map::Span; +use crate::syntax_pos::BytePos; use crate::utils::{sugg, sext}; use crate::utils::usage::mutated_variables; use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 1a501b39eb5..239602c6db5 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,9 +1,9 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; -use rustc::ty; -use syntax::ast; +use crate::rustc::hir::*; +use crate::rustc::ty; +use crate::syntax::ast; use crate::utils::{get_arg_ident, is_adjusted, iter_input_pats, match_qpath, match_trait_method, match_type, paths, remove_blocks, snippet, span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq}; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 90f149a1c01..096ef46555d 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,10 +1,10 @@ -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use rustc_errors::Applicability; -use syntax::source_map::Span; +use crate::rustc::ty; +use crate::rustc_errors::Applicability; +use crate::syntax::source_map::Span; use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then}; use crate::utils::paths; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 3ecf5d3b5b8..a4c2681e359 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,12 +1,12 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; +use crate::rustc::ty::{self, Ty}; use std::cmp::Ordering; use std::collections::Bound; -use syntax::ast::LitKind; -use syntax::source_map::Span; +use crate::syntax::ast::LitKind; +use crate::syntax::source_map::Span; use crate::utils::paths; use crate::utils::{expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty}; diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 8a56dccad2d..7a07ecbf02c 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::{Expr, ExprKind}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::{Expr, ExprKind}; use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index 3d458343a50..1e03503d313 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -1,15 +1,15 @@ use matches::matches; -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, Lint, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, Lint, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; -use rustc::hir::def::Def; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::hir::def::Def; use std::borrow::Cow; use std::fmt; use std::iter; -use syntax::ast; -use syntax::source_map::{Span, BytePos}; +use crate::syntax::ast; +use crate::syntax::source_map::{Span, BytePos}; use crate::utils::{get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type, method_chain_args, match_var, return_ty, remove_blocks, same_tys, single_segment_path, snippet, diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index bbbc022f08d..293d301ebb4 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,8 +1,8 @@ use crate::consts::{constant_simple, Constant}; use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use std::cmp::Ordering; /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 302af13630b..f52d3ccf5a4 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,17 +1,17 @@ use crate::reexport::*; use matches::matches; -use rustc::hir::*; -use rustc::hir::intravisit::FnKind; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::FnKind; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use syntax::source_map::{ExpnFormat, Span}; +use crate::rustc::ty; +use crate::syntax::source_map::{ExpnFormat, Span}; use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty, SpanlessEq}; use crate::utils::sugg::Sugg; -use syntax::ast::{LitKind, CRATE_NODE_ID}; +use crate::syntax::ast::{LitKind, CRATE_NODE_ID}; use crate::consts::{constant, Constant}; /// **What it does:** Checks for function arguments and let bindings denoted as diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 35a232f7f32..5a509802b61 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,11 +1,11 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro}; -use rustc::{declare_tool_lint, lint_array}; -use rustc_data_structures::fx::FxHashMap; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_data_structures::fx::FxHashMap; use if_chain::if_chain; use std::char; -use syntax::ast::*; -use syntax::source_map::Span; -use syntax::visit::FnKind; +use crate::syntax::ast::*; +use crate::syntax::source_map::Span; +use crate::syntax::visit::FnKind; use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then}; /// **What it does:** Checks for structure field patterns bound to wildcards. diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index f56a8fcd8b5..685f701ef8b 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -18,13 +18,13 @@ // [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 // -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use syntax::ast; -use syntax::attr; -use syntax::source_map::Span; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::syntax::ast; +use crate::syntax::attr; +use crate::syntax::source_map::Span; use crate::utils::{span_lint, in_macro}; /// **What it does:** Warns if there is missing doc for any documentable item diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index bf88caa6ab9..dea3a81e50d 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -9,11 +9,11 @@ // except according to those terms. // -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast; -use syntax::source_map::Span; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast; +use crate::syntax::source_map::Span; use crate::utils::span_lint; /// **What it does:** it lints if an exported function, method, trait method with default impl, @@ -85,7 +85,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, } fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool { - use rustc::session::config::CrateType; + use crate::rustc::session::config::CrateType; cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| { match t { @@ -155,7 +155,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline { } fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) { - use rustc::ty::{TraitContainer, ImplContainer}; + use crate::rustc::ty::{TraitContainer, ImplContainer}; if is_executable(cx) { return; } diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index a2ed6a1dea1..2f6b08c5151 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,8 +1,8 @@ //! lint on multiple versions of a crate being used -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::span_lint; use cargo_metadata; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index ea3d68dfc83..b3607d623b3 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,8 +1,8 @@ -use rustc::hir; -use rustc::hir::intravisit; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; +use crate::rustc::hir; +use crate::rustc::hir::intravisit; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; use crate::utils::{higher, span_lint}; /// **What it does:** Checks for instances of `mut mut` references. @@ -38,7 +38,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut { } fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &'tcx hir::Ty) { - use rustc::hir::intravisit::Visitor; + use crate::rustc::hir::intravisit::Visitor; MutVisitor { cx }.visit_ty(ty); } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 97287aa833f..1bf06b9e20a 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,8 +1,8 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty::{self, Ty}; -use rustc::ty::subst::Subst; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::ty::subst::Subst; +use crate::rustc::hir::*; use crate::utils::span_lint; /// **What it does:** Detects giving a mutable reference to a function that only diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index cb400ee4ee3..f6caddab485 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -2,11 +2,11 @@ //! //! This lint is **warn** by default -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty::{self, Ty}; -use rustc::hir::Expr; -use syntax::ast; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::hir::Expr; +use crate::syntax::ast; use crate::utils::{match_type, paths, span_lint}; /// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do. diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 5b9a479c1fc..74b6647551a 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -2,11 +2,11 @@ //! //! This lint is **warn** by default -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use syntax::ast::LitKind; -use syntax::source_map::Spanned; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::syntax::ast::LitKind; +use crate::syntax::source_map::Spanned; use crate::utils::{snippet, span_lint, span_lint_and_sugg}; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index a194cb2c61b..ec53f76095f 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -2,12 +2,12 @@ //! //! This lint is **warn** by default -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::{BindingAnnotation, Expr, ExprKind, MutImmutable, Pat, PatKind}; -use rustc::ty; -use rustc::ty::adjustment::{Adjust, Adjustment}; +use crate::rustc::hir::{BindingAnnotation, Expr, ExprKind, MutImmutable, Pat, PatKind}; +use crate::rustc::ty; +use crate::rustc::ty::adjustment::{Adjust, Adjustment}; use crate::utils::{in_macro, snippet_opt, span_lint_and_then}; /// **What it does:** Checks for address of operations (`&`) that are going to diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 4905dbc8e6b..2db9b9d165b 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -2,10 +2,10 @@ //! //! This lint is **warn** by default -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind}; +use crate::rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind}; use crate::utils::{in_macro, snippet, span_lint_and_then}; /// **What it does:** Checks for useless borrowed references. diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index e14cd0fea89..0f7ea34f18a 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -27,10 +27,10 @@ //! ``` //! //! This lint is **warn** by default. -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast; -use syntax::source_map::{original_sp, DUMMY_SP}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast; +use crate::syntax::source_map::{original_sp, DUMMY_SP}; use std::borrow::Cow; use crate::utils::{in_macro, snippet, snippet_block, span_help_and_lint, trim_multiline}; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 76eaf0dba24..eb4cbe22f30 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,18 +1,18 @@ use matches::matches; -use rustc::hir::*; -use rustc::hir::intravisit::FnKind; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::FnKind; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, RegionKind, TypeFoldable}; -use rustc::traits; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc_target::spec::abi::Abi; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use syntax::ast::NodeId; -use syntax_pos::Span; -use syntax::errors::DiagnosticBuilder; +use crate::rustc::ty::{self, RegionKind, TypeFoldable}; +use crate::rustc::traits; +use crate::rustc::middle::expr_use_visitor as euv; +use crate::rustc::middle::mem_categorization as mc; +use crate::rustc_target::spec::abi::Abi; +use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::syntax::ast::NodeId; +use crate::syntax_pos::Span; +use crate::syntax::errors::DiagnosticBuilder; use crate::utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths, snippet, snippet_opt, span_lint_and_then}; use crate::utils::ptr::get_spans; diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index dccb7f2e037..7c452bed0a3 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::ty; -use rustc::hir::{Expr, ExprKind}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::ty; +use crate::rustc::hir::{Expr, ExprKind}; use crate::utils::span_lint; /// **What it does:** Checks for needlessly including a base struct on update diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index db61ea375c3..08ad4dd43c9 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,6 +1,6 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; use crate::utils::{self, paths, span_lint}; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 93a83fe97ba..f39cfc8d122 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,8 +1,8 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::source_map::{Span, Spanned}; +use crate::syntax::source_map::{Span, Spanned}; use crate::consts::{self, Constant}; use crate::utils::span_lint; diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 493e8d0f4ce..131f73b7c61 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,10 +1,10 @@ -use rustc::hir::def_id::DefId; -use rustc::hir; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::def_id::DefId; +use crate::rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; -use syntax::source_map::Span; +use crate::rustc::ty::{self, Ty}; +use crate::syntax::source_map::Span; use crate::utils::paths; use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then}; use crate::utils::sugg::DiagnosticBuilderExt; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 09a27330750..5ff0979670d 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::def::Def; -use rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; use crate::utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg}; use std::ops::Deref; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index deb088d3ea4..3b97e9d4a17 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -2,15 +2,15 @@ //! //! This lint is **deny** by default. -use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::ty::{self, TypeFlags}; -use rustc::ty::adjustment::Adjust; -use rustc_errors::Applicability; -use rustc_typeck::hir_ty_to_ty; -use syntax_pos::{DUMMY_SP, Span}; +use crate::rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::def::Def; +use crate::rustc::ty::{self, TypeFlags}; +use crate::rustc::ty::adjustment::Adjust; +use crate::rustc_errors::Applicability; +use crate::rustc_typeck::hir_ty_to_ty; +use crate::syntax_pos::{DUMMY_SP, Span}; use std::ptr; use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then}; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5e106cac967..77642b4727c 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Span; -use syntax::symbol::LocalInternedString; -use syntax::ast::*; -use syntax::attr; -use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; +use crate::rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Span; +use crate::syntax::symbol::LocalInternedString; +use crate::syntax::ast::*; +use crate::syntax::attr; +use crate::syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; use crate::utils::{span_lint, span_lint_and_then}; /// **What it does:** Checks for names that are very similar and thus confusing. diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index 651ed44110f..cd97e485342 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; +use crate::rustc::hir::*; use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint}; /// **What it does:*** Checks for unnecessary `ok()` in if let. diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index b5459059e90..9133192549f 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,8 +1,8 @@ -use rustc::hir::{Expr, ExprKind}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::LitKind; -use syntax::source_map::{Span, Spanned}; +use crate::rustc::hir::{Expr, ExprKind}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::LitKind; +use crate::syntax::source_map::{Span, Spanned}; use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty}; /// **What it does:** Checks for duplicate open options as well as combinations diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index d33ef5e05d6..bdd87ad3a25 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; +use crate::rustc::hir::*; use crate::utils::{span_lint, SpanlessEq}; /// **What it does:** Detects classic underflow/overflow checks. diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 7a7fa3c456d..404f43312e5 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,10 +1,10 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast::LitKind; -use syntax::ptr::P; -use syntax::ext::quote::rt::Span; +use crate::syntax::ast::LitKind; +use crate::syntax::ptr::P; +use crate::syntax::ext::quote::rt::Span; use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint}; /// **What it does:** Checks for missing parameters in `panic!`. diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 8b2e5f9c356..7eb0c089726 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,7 +1,7 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; +use crate::rustc::hir::*; use crate::utils::{is_automatically_derived, span_lint}; /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`. diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 0978a6b7d94..e77a49266ba 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,7 +1,7 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; -use syntax::source_map::Spanned; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; +use crate::syntax::source_map::Spanned; use crate::utils::{in_macro, snippet, span_lint_and_sugg}; /// **What it does:** Checks for operations where precedence may be unclear @@ -121,7 +121,7 @@ fn is_arith_expr(expr: &Expr) -> bool { } fn is_bit_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; + use crate::syntax::ast::BinOpKind::*; match op { BitXor | BitAnd | BitOr | Shl | Shr => true, _ => false, @@ -129,7 +129,7 @@ fn is_bit_op(op: BinOpKind) -> bool { } fn is_arith_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; + use crate::syntax::ast::BinOpKind::*; match op { Add | Sub | Mul | Div | Rem => true, _ => false, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 94bbfb0e5b9..1aefc84cb49 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,15 +1,15 @@ //! Checks for usage of `&Vec[_]` and `&String`. use std::borrow::Cow; -use rustc::hir::*; -use rustc::hir::QPath; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::QPath; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; -use syntax::ast::NodeId; -use syntax::source_map::Span; -use syntax_pos::MultiSpan; +use crate::rustc::ty; +use crate::syntax::ast::NodeId; +use crate::syntax::source_map::Span; +use crate::syntax_pos::MultiSpan; use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty}; use crate::utils::ptr::get_spans; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 250a11dab88..261e5cccbdd 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,4 +1,4 @@ -use rustc::{declare_tool_lint, hir, lint, lint_array}; +use crate::rustc::{declare_tool_lint, hir, lint, lint_array}; use crate::utils; use std::fmt; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 3134f14b194..93ea00cec77 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; -use rustc::hir::def::Def; +use crate::rustc::hir::*; +use crate::rustc::hir::def::Def; use crate::utils::sugg::Sugg; -use syntax::ptr::P; +use crate::syntax::ptr::P; use crate::utils::{match_def_path, match_type, span_lint_and_then}; use crate::utils::paths::*; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index f9cdffea79c..6616099eb9e 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,9 +1,9 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; -use syntax::ast::RangeLimits; -use syntax::source_map::Spanned; +use crate::rustc::hir::*; +use crate::syntax::ast::RangeLimits; +use crate::syntax::source_map::Spanned; use crate::utils::{is_integer_literal, paths, snippet, span_lint, span_lint_and_then, snippet_opt}; use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq}; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 579d2ad1423..38cb4578d9e 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,6 +1,6 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; use crate::utils::{span_lint_and_sugg}; /// **What it does:** Checks for fields in struct literals where shorthands diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 98de8989597..1faacc79df0 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,6 +1,6 @@ -use syntax::ast::{Expr, ExprKind, UnOp}; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::{Expr, ExprKind, UnOp}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; use crate::utils::{snippet, span_lint_and_sugg}; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index b7409bfbc9f..41ff8a4bc0c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,11 +1,11 @@ use regex_syntax; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc_data_structures::fx::FxHashSet; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_data_structures::fx::FxHashSet; use if_chain::if_chain; -use syntax::ast::{LitKind, NodeId, StrStyle}; -use syntax::source_map::{BytePos, Span}; +use crate::syntax::ast::{LitKind, NodeId, StrStyle}; +use crate::syntax::source_map::{BytePos, Span}; use crate::utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint}; use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index aaea8b6dd0e..05cca2ac338 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -1,8 +1,8 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir; -use rustc::hir::def::Def; +use crate::rustc::hir; +use crate::rustc::hir::def::Def; use crate::utils::{match_def_path, span_lint_and_sugg}; /// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index ddc0a9719a8..4aed77f43e1 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,9 +1,9 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use syntax::ast; -use syntax::source_map::Span; -use syntax::visit::FnKind; +use crate::syntax::ast; +use crate::syntax::source_map::Span; +use crate::syntax::visit::FnKind; use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint}; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 0f09988c250..f2cfdf82d5b 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; use crate::utils::{get_trait_def_id, paths, span_lint}; /// **What it does:** Checks for mis-uses of the serde API. diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 1191723ba62..4a989353600 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,10 +1,10 @@ use crate::reexport::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::hir::intravisit::FnKind; -use rustc::ty; -use syntax::source_map::Span; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::FnKind; +use crate::rustc::ty; +use crate::syntax::source_map::Span; use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; /// **What it does:** Checks for bindings that shadow other bindings already in diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 70d90a8fb76..54fced12425 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,7 +1,7 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::source_map::Spanned; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::source_map::Spanned; use crate::utils::SpanlessEq; use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; @@ -145,7 +145,7 @@ impl LintPass for StringLitAsBytes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - use syntax::ast::LitKind; + use crate::syntax::ast::LitKind; use crate::utils::{in_macro, snippet}; if let ExprKind::MethodCall(ref path, _, ref args) = e.node { diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 9f9b279a6c5..78a2c2adeb3 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,9 +1,9 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use syntax::ast; +use crate::rustc::hir; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::syntax::ast; use crate::utils::{get_trait_def_id, span_lint}; /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g. diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 9ae6ec48383..1c409263499 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,9 +1,9 @@ use matches::matches; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty; +use crate::rustc::ty; use crate::utils::{differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq}; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index cb922302964..7cde4eb48f3 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::{Expr, ExprKind}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::{Expr, ExprKind}; use crate::utils::is_adjusted; use crate::utils::span_lint; diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 6e82bee277f..84726e5ded3 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,10 +1,10 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; -use rustc::hir::*; +use crate::rustc::ty::{self, Ty}; +use crate::rustc::hir::*; use std::borrow::Cow; -use syntax::ast; +use crate::syntax::ast; use crate::utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; use crate::utils::{opt_def_id, sugg}; diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 70a93e7f78a..baa9a8c3903 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -1,18 +1,18 @@ use std::cmp; use matches::matches; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::intravisit::FnKind; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::FnKind; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::TyKind; -use rustc::session::config::Config as SessionConfig; -use rustc_target::spec::abi::Abi; -use rustc_target::abi::LayoutOf; -use syntax::ast::NodeId; -use syntax_pos::Span; +use crate::rustc::ty::TyKind; +use crate::rustc::session::config::Config as SessionConfig; +use crate::rustc_target::spec::abi::Abi; +use crate::rustc_target::abi::LayoutOf; +use crate::syntax::ast::NodeId; +use crate::syntax_pos::Span; use crate::utils::{in_macro, is_copy, is_self, span_lint_and_sugg, snippet}; /// **What it does:** Checks for functions taking arguments by reference, where diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index a6cc174f0ad..2766ea58d2d 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,21 +1,21 @@ #![allow(clippy::default_hash_types)] use crate::reexport::*; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty, TyCtxt, TypeckTables}; -use rustc::ty::layout::LayoutOf; -use rustc_typeck::hir_ty_to_ty; +use crate::rustc::ty::{self, Ty, TyCtxt, TypeckTables}; +use crate::rustc::ty::layout::LayoutOf; +use crate::rustc_typeck::hir_ty_to_ty; use std::cmp::Ordering; use std::collections::BTreeMap; use std::borrow::Cow; -use syntax::ast::{FloatTy, IntTy, UintTy}; -use syntax::source_map::Span; -use syntax::errors::DiagnosticBuilder; +use crate::syntax::ast::{FloatTy, IntTy, UintTy}; +use crate::syntax::source_map::Span; +use crate::syntax::errors::DiagnosticBuilder; use crate::utils::{comparisons, differing_macro_contexts, higher, in_constant, in_macro, last_path_segment, match_def_path, match_path, match_type, multispan_sugg, opt_def_id, same_tys, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, clip, unsext, sext, int_bits}; @@ -542,7 +542,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool { - use syntax_pos::hygiene::CompilerDesugaringKind; + use crate::syntax_pos::hygiene::CompilerDesugaringKind; if let ExprKind::Call(ref callee, _) = expr.node { callee.span.is_compiler_desugaring(CompilerDesugaringKind::QuestionMark) } else { @@ -958,7 +958,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass { if let ExprKind::Cast(ref ex, _) = expr.node { let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr)); if let ExprKind::Lit(ref lit) = ex.node { - use syntax::ast::{LitIntType, LitKind}; + use crate::syntax::ast::{LitIntType, LitKind}; match lit.node { LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(_) => {}, _ => if cast_from.sty == cast_to.sty && !in_external_macro(cx.sess(), expr.span) { @@ -1291,7 +1291,7 @@ impl LintPass for CharLitAsU8 { 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}; + use crate::syntax::ast::{LitKind, UintTy}; if let ExprKind::Cast(ref e, _) = expr.node { if let ExprKind::Lit(ref l) = e.node { @@ -1565,7 +1565,7 @@ impl Ord for FullInt { fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(FullInt, FullInt)> { - use syntax::ast::{IntTy, UintTy}; + use crate::syntax::ast::{IntTy, UintTy}; use std::*; if let ExprKind::Cast(ref cast_exp, _) = expr.node { @@ -1748,7 +1748,7 @@ impl LintPass for ImplicitHasher { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { #[allow(clippy::cast_possible_truncation)] fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { - use syntax_pos::BytePos; + use crate::syntax_pos::BytePos; fn suggestion<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 01c4cd83ce0..83f9713b59e 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,8 +1,8 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use syntax::ast::{LitKind, NodeId}; -use syntax::source_map::Span; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::syntax::ast::{LitKind, NodeId}; +use crate::syntax::source_map::Span; use unicode_normalization::UnicodeNormalization; use crate::utils::{is_allowed, snippet, span_help_and_lint}; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 7ef235e9297..e6472eb50bf 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,8 +1,8 @@ -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use syntax::ast::*; -use syntax::source_map::Span; -use syntax::symbol::LocalInternedString; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax::ast::*; +use crate::syntax::source_map::Span; +use crate::syntax::symbol::LocalInternedString; use crate::utils::span_lint; /// **What it does:** Checks for imports that remove "unsafe" from an item's diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index c5507fcaca4..82430a794b1 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,6 +1,6 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint}; /// **What it does:** Checks for unused written/read amount. diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index ababaad294d..a67164becfb 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -1,11 +1,11 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir; -use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; -use rustc_data_structures::fx::FxHashMap; -use syntax::ast; -use syntax::source_map::Span; -use syntax::symbol::LocalInternedString; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; +use crate::rustc_data_structures::fx::FxHashMap; +use crate::syntax::ast; +use crate::syntax::source_map::Span; +use crate::syntax::symbol::LocalInternedString; use crate::utils::{in_macro, span_lint}; /// **What it does:** Checks for unused labels. diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index a1d24f64300..f8fe1b3bdfa 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,12 +1,12 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; use crate::utils::{in_macro, match_type, paths, span_lint_and_then, usage::is_potentially_mutated}; -use rustc::hir::intravisit::*; -use rustc::hir::*; -use syntax::ast::NodeId; -use syntax::source_map::Span; +use crate::rustc::hir::intravisit::*; +use crate::rustc::hir::*; +use crate::syntax::ast::NodeId; +use crate::syntax::source_map::Span; /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail. /// diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 550f88c895e..3b2659a6176 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,11 +1,11 @@ use crate::utils::{in_macro, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor}; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::ty; -use rustc::{declare_tool_lint, lint_array}; -use syntax_pos::symbol::keywords::SelfType; +use crate::rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::ty; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::syntax_pos::symbol::keywords::SelfType; /// **What it does:** Checks for unnecessary repetition of structure name when a /// replacement with `Self` is applicable. diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 541d5353daf..8e8d40e28a9 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -3,13 +3,13 @@ #![allow(clippy::print_stdout, clippy::use_debug)] -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir; -use rustc::hir::{Expr, ExprKind, QPath, TyKind, Pat, PatKind, BindingAnnotation, StmtKind, DeclKind, Stmt}; -use rustc::hir::intravisit::{NestedVisitorMap, Visitor}; -use rustc_data_structures::fx::FxHashMap; -use syntax::ast::{Attribute, LitKind, DUMMY_NODE_ID}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::{Expr, ExprKind, QPath, TyKind, Pat, PatKind, BindingAnnotation, StmtKind, DeclKind, Stmt}; +use crate::rustc::hir::intravisit::{NestedVisitorMap, Visitor}; +use crate::rustc_data_structures::fx::FxHashMap; +use crate::syntax::ast::{Attribute, LitKind, DUMMY_NODE_ID}; use crate::utils::get_attr; /// **What it does:** Generates clippy code that detects the offending pattern diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index 31e20f37e20..bd90fe1bc0a 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -2,7 +2,7 @@ #![deny(clippy::missing_docs_in_private_items)] -use rustc::hir::{BinOpKind, Expr}; +use crate::rustc::hir::{BinOpKind, Expr}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] /// Represent a normalized comparison operator. diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 16e39ff13ea..4a58ac2f760 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -6,7 +6,7 @@ use lazy_static::lazy_static; use std::default::Default; use std::{env, fmt, fs, io, path}; use std::io::Read; -use syntax::{ast, source_map}; +use crate::syntax::{ast, source_map}; use toml; use std::sync::Mutex; diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 42b37568a99..cfedad49f31 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -4,9 +4,9 @@ #![deny(clippy::missing_docs_in_private_items)] use if_chain::if_chain; -use rustc::{hir, ty}; -use rustc::lint::LateContext; -use syntax::ast; +use crate::rustc::{hir, ty}; +use crate::rustc::lint::LateContext; +use crate::syntax::ast; use crate::utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node}; /// Convert a hir binary operator to the corresponding `ast` type. diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index f8e99480ea0..2257fbf7743 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -1,11 +1,11 @@ use crate::consts::{constant_simple, constant_context}; -use rustc::lint::LateContext; -use rustc::hir::*; -use rustc::ty::{TypeckTables}; +use crate::rustc::lint::LateContext; +use crate::rustc::hir::*; +use crate::rustc::ty::{TypeckTables}; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; -use syntax::ast::Name; -use syntax::ptr::P; +use crate::syntax::ast::Name; +use crate::syntax::ptr::P; use crate::utils::differing_macro_contexts; /// Type used to check whether two ast are the same. This is different from the diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 56b76fdc7b0..413c71ab27b 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -2,11 +2,11 @@ //! checks for attributes -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir; -use rustc::hir::print; -use syntax::ast::Attribute; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir; +use crate::rustc::hir::print; +use crate::syntax::ast::Attribute; use crate::utils::get_attr; /// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]` diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index f3b915c7ce1..97a6922d35d 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,13 +1,13 @@ -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, EarlyContext, EarlyLintPass}; -use rustc::{declare_tool_lint, lint_array}; -use rustc::hir::*; -use rustc::hir; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, EarlyContext, EarlyLintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::hir; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::utils::{match_qpath, paths, span_lint, span_lint_and_sugg}; -use syntax::symbol::LocalInternedString; -use syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name}; -use syntax::source_map::Span; +use crate::syntax::symbol::LocalInternedString; +use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name}; +use crate::syntax::source_map::Span; /// **What it does:** Checks for various things we like to keep tidy in clippy. diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4171e583e59..c113dd7e5a3 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,27 +1,27 @@ use crate::reexport::*; use matches::matches; use if_chain::if_chain; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc::hir::def::Def; -use rustc::hir::intravisit::{NestedVisitorMap, Visitor}; -use rustc::hir::Node; -use rustc::lint::{LateContext, Level, Lint, LintContext}; -use rustc::session::Session; -use rustc::traits; -use rustc::ty::{self, Binder, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind}; -use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart}; +use crate::rustc::hir; +use crate::rustc::hir::*; +use crate::rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::intravisit::{NestedVisitorMap, Visitor}; +use crate::rustc::hir::Node; +use crate::rustc::lint::{LateContext, Level, Lint, LintContext}; +use crate::rustc::session::Session; +use crate::rustc::traits; +use crate::rustc::ty::{self, Binder, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind}; +use crate::rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart}; use std::borrow::Cow; use std::env; use std::mem; use std::str::FromStr; use std::rc::Rc; -use syntax::ast::{self, LitKind}; -use syntax::attr; -use syntax::source_map::{Span, DUMMY_SP}; -use syntax::errors::DiagnosticBuilder; -use syntax::symbol::keywords; +use crate::syntax::ast::{self, LitKind}; +use crate::syntax::attr; +use crate::syntax::source_map::{Span, DUMMY_SP}; +use crate::syntax::errors::DiagnosticBuilder; +use crate::syntax::symbol::keywords; mod camel_case; pub use self::camel_case::{camel_case_from, camel_case_until}; @@ -70,7 +70,7 @@ pub fn in_macro(span: Span) -> bool { /// /// See also the `paths` module. pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> bool { - use syntax::symbol; + use crate::syntax::symbol; struct AbsolutePathBuffer { names: Vec<symbol::LocalInternedString>, diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index 16a03f8f99c..a28e1c7fe9d 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; -use rustc::hir::*; -use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc::lint::LateContext; -use syntax::ast::Name; -use syntax::source_map::Span; +use crate::rustc::hir::*; +use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use crate::rustc::lint::LateContext; +use crate::syntax::ast::Name; +use crate::syntax::source_map::Span; use crate::utils::{get_pat_name, match_var, snippet}; pub fn get_spans( diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 8efee6cd964..f849cef093a 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -2,19 +2,19 @@ #![deny(clippy::missing_docs_in_private_items)] use matches::matches; -use rustc::hir; -use rustc::lint::{EarlyContext, LateContext, LintContext}; -use rustc_errors; +use crate::rustc::hir; +use crate::rustc::lint::{EarlyContext, LateContext, LintContext}; +use crate::rustc_errors; use std::borrow::Cow; use std::fmt::Display; use std; -use syntax::source_map::{CharPos, Span}; -use syntax::parse::token; -use syntax::print::pprust::token_to_string; -use syntax::util::parser::AssocOp; -use syntax::ast; +use crate::syntax::source_map::{CharPos, Span}; +use crate::syntax::parse::token; +use crate::syntax::print::pprust::token_to_string; +use crate::syntax::util::parser::AssocOp; +use crate::syntax::ast; use crate::utils::{higher, snippet, snippet_opt}; -use syntax_pos::{BytePos, Pos}; +use crate::syntax_pos::{BytePos, Pos}; /// A helper type to build suggestion correctly handling parenthesis. pub enum Sugg<'a> { @@ -86,7 +86,7 @@ impl<'a> Sugg<'a> { /// Prepare a suggestion from an expression. pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { - use syntax::ast::RangeLimits; + use crate::syntax::ast::RangeLimits; let snippet = snippet(cx, expr.span, default); @@ -360,7 +360,7 @@ enum Associativity { /// they are considered /// associative. fn associativity(op: &AssocOp) -> Associativity { - use syntax::util::parser::AssocOp::*; + use crate::syntax::util::parser::AssocOp::*; match *op { ObsoleteInPlace | Assign | AssignOp(_) => Associativity::Right, @@ -382,7 +382,7 @@ fn associativity(op: &AssocOp) -> Associativity { /// Convert a `hir::BinOp` to the corresponding assigning binary operator. fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { - use syntax::parse::token::BinOpToken::*; + use crate::syntax::parse::token::BinOpToken::*; AssocOp::AssignOp(match op.node { hir::BinOpKind::Add => Plus, @@ -410,8 +410,8 @@ fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { /// Convert an `ast::BinOp` to the corresponding assigning binary operator. fn astbinop2assignop(op: ast::BinOp) -> AssocOp { - use syntax::ast::BinOpKind::*; - use syntax::parse::token::BinOpToken; + use crate::syntax::ast::BinOpKind::*; + use crate::syntax::parse::token::BinOpToken; AssocOp::AssignOp(match op.node { Add => BinOpToken::Plus, diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index ac18d04e454..826ca78e64b 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,14 +1,14 @@ -use rustc::lint::LateContext; +use crate::rustc::lint::LateContext; -use rustc::hir::def::Def; -use rustc::hir::*; -use rustc::middle::expr_use_visitor::*; -use rustc::middle::mem_categorization::cmt_; -use rustc::middle::mem_categorization::Categorization; -use rustc::ty; -use rustc_data_structures::fx::FxHashSet; -use syntax::ast::NodeId; -use syntax::source_map::Span; +use crate::rustc::hir::def::Def; +use crate::rustc::hir::*; +use crate::rustc::middle::expr_use_visitor::*; +use crate::rustc::middle::mem_categorization::cmt_; +use crate::rustc::middle::mem_categorization::Categorization; +use crate::rustc::ty; +use crate::rustc_data_structures::fx::FxHashSet; +use crate::syntax::ast::NodeId; +use crate::syntax::source_map::Span; /// Returns a set of mutated local variable ids or None if mutations could not be determined. pub fn mutated_variables<'a, 'tcx: 'a>(expr: &'tcx Expr, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<NodeId>> { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 4cbefc29b9c..4c6060192cf 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,9 +1,9 @@ -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::hir::*; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; -use syntax::source_map::Span; +use crate::rustc::ty::{self, Ty}; +use crate::syntax::source_map::Span; use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg}; use crate::consts::constant; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 69d99cc60f4..a367a04b2ba 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,10 +1,10 @@ use crate::utils::{snippet, span_lint, span_lint_and_sugg}; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use std::borrow::Cow; -use syntax::ast::*; -use syntax::parse::{parser, token}; -use syntax::tokenstream::{ThinTokenStream, TokenStream}; +use crate::syntax::ast::*; +use crate::syntax::parse::{parser, token}; +use crate::syntax::tokenstream::{ThinTokenStream, TokenStream}; /// **What it does:** This lint warns when you use `println!("")` to /// print a newline. @@ -264,7 +264,7 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) - Ok(token) => token.0.to_string(), Err(_) => return (None, expr), }; - use fmt_macros::*; + use crate::fmt_macros::*; let tmp = fmtstr.clone(); let mut args = vec![]; let mut fmt_parser = Parser::new(&tmp, None); diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 73c9e64d2cb..5ceff6d4aa0 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,8 +1,8 @@ use crate::consts::{constant_simple, Constant}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; -use rustc::hir::*; +use crate::rustc::hir::*; use crate::utils::span_help_and_lint; /// **What it does:** Checks for `0.0 / 0.0`. diff --git a/src/driver.rs b/src/driver.rs index e85f61e343f..99f8bc610ff 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -4,8 +4,14 @@ #![feature(tool_lints)] #![allow(unknown_lints, clippy::missing_docs_in_private_items)] -use rustc_driver::{self, driver::CompileController, Compilation}; -use rustc_plugin; +// FIXME: switch to something more ergonomic here, once available. +// (currently there is no way to opt into sysroot crates w/o `extern crate`) +#[allow(unused_extern_crates)] +extern crate rustc_driver; +#[allow(unused_extern_crates)] +extern crate rustc_plugin; +use self::rustc_driver::{driver::CompileController, Compilation}; + use std::path::Path; use std::process::{exit, Command}; diff --git a/src/lib.rs b/src/lib.rs index a7167ac10de..bfa44d08703 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,11 @@ #![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] -use rustc_plugin::Registry; +// FIXME: switch to something more ergonomic here, once available. +// (currently there is no way to opt into sysroot crates w/o `extern crate`) +#[allow(unused_extern_crates)] +extern crate rustc_plugin; +use self::rustc_plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry<'_>) { -- cgit 1.4.1-3-g733a5 From 8695c2c34bf315f9cf62f1a1e276a8bcb8c693c7 Mon Sep 17 00:00:00 2001 From: O01eg <o01eg@yandex.ru> Date: Wed, 3 Oct 2018 21:41:02 +0300 Subject: Allow to debug rustc_driver via logs. --- src/driver.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 99f8bc610ff..6c442e42d95 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -21,6 +21,7 @@ fn show_version() { } pub fn main() { + rustc_driver::init_rustc_env_logger(); exit(rustc_driver::run(move || { use std::env; -- cgit 1.4.1-3-g733a5 From e9c025ea70f9297836d62e0f0c959b9359a8035a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar <manishsmail@gmail.com> Date: Sat, 6 Oct 2018 09:18:06 -0700 Subject: Add license header to Rust files --- build.rs | 10 + clippy_dev/src/lib.rs | 10 + clippy_dev/src/main.rs | 10 + clippy_dummy/build.rs | 10 + clippy_dummy/src/main.rs | 10 + clippy_lints/src/approx_const.rs | 10 + clippy_lints/src/arithmetic.rs | 10 + clippy_lints/src/assign_ops.rs | 10 + clippy_lints/src/attrs.rs | 10 + clippy_lints/src/bit_mask.rs | 10 + clippy_lints/src/blacklisted_name.rs | 10 + clippy_lints/src/block_in_if_condition.rs | 10 + clippy_lints/src/booleans.rs | 10 + clippy_lints/src/bytecount.rs | 10 + clippy_lints/src/collapsible_if.rs | 10 + clippy_lints/src/const_static_lifetime.rs | 10 + clippy_lints/src/consts.rs | 10 + clippy_lints/src/copies.rs | 10 + clippy_lints/src/copy_iterator.rs | 10 + clippy_lints/src/cyclomatic_complexity.rs | 10 + clippy_lints/src/default_trait_access.rs | 10 + clippy_lints/src/deprecated_lints.rs | 10 + clippy_lints/src/derive.rs | 10 + clippy_lints/src/doc.rs | 10 + clippy_lints/src/double_comparison.rs | 10 + clippy_lints/src/double_parens.rs | 10 + clippy_lints/src/drop_forget_ref.rs | 10 + clippy_lints/src/duration_subsec.rs | 10 + clippy_lints/src/else_if_without_else.rs | 10 + clippy_lints/src/empty_enum.rs | 10 + clippy_lints/src/entry.rs | 10 + clippy_lints/src/enum_clike.rs | 10 + clippy_lints/src/enum_glob_use.rs | 10 + clippy_lints/src/enum_variants.rs | 10 + clippy_lints/src/eq_op.rs | 10 + clippy_lints/src/erasing_op.rs | 10 + clippy_lints/src/escape.rs | 10 + clippy_lints/src/eta_reduction.rs | 10 + clippy_lints/src/eval_order_dependence.rs | 10 + clippy_lints/src/excessive_precision.rs | 10 + clippy_lints/src/explicit_write.rs | 10 + clippy_lints/src/fallible_impl_from.rs | 10 + clippy_lints/src/format.rs | 10 + clippy_lints/src/formatting.rs | 10 + clippy_lints/src/functions.rs | 10 + clippy_lints/src/identity_conversion.rs | 10 + clippy_lints/src/identity_op.rs | 10 + .../src/if_let_redundant_pattern_matching.rs | 10 + clippy_lints/src/if_not_else.rs | 10 + clippy_lints/src/indexing_slicing.rs | 10 + clippy_lints/src/infallible_destructuring_match.rs | 10 + clippy_lints/src/infinite_iter.rs | 10 + clippy_lints/src/inherent_impl.rs | 10 + clippy_lints/src/inline_fn_without_body.rs | 10 + clippy_lints/src/int_plus_one.rs | 10 + clippy_lints/src/invalid_ref.rs | 10 + clippy_lints/src/items_after_statements.rs | 10 + clippy_lints/src/large_enum_variant.rs | 10 + clippy_lints/src/len_zero.rs | 10 + clippy_lints/src/let_if_seq.rs | 10 + clippy_lints/src/lib.rs | 10 + clippy_lints/src/lifetimes.rs | 10 + clippy_lints/src/literal_representation.rs | 10 + clippy_lints/src/loops.rs | 10 + clippy_lints/src/map_clone.rs | 10 + clippy_lints/src/map_unit_fn.rs | 10 + clippy_lints/src/matches.rs | 10 + clippy_lints/src/mem_forget.rs | 10 + clippy_lints/src/mem_replace.rs | 10 + clippy_lints/src/methods/mod.rs | 10 + clippy_lints/src/methods/unnecessary_filter_map.rs | 10 + clippy_lints/src/minmax.rs | 10 + clippy_lints/src/misc.rs | 10 + clippy_lints/src/misc_early.rs | 10 + clippy_lints/src/missing_doc.rs | 10 + clippy_lints/src/missing_inline.rs | 10 + clippy_lints/src/multiple_crate_versions.rs | 10 + clippy_lints/src/mut_mut.rs | 10 + clippy_lints/src/mut_reference.rs | 10 + clippy_lints/src/mutex_atomic.rs | 10 + clippy_lints/src/needless_bool.rs | 10 + clippy_lints/src/needless_borrow.rs | 10 + clippy_lints/src/needless_borrowed_ref.rs | 10 + clippy_lints/src/needless_continue.rs | 10 + clippy_lints/src/needless_pass_by_value.rs | 10 + clippy_lints/src/needless_update.rs | 10 + clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 10 + clippy_lints/src/neg_multiply.rs | 10 + clippy_lints/src/new_without_default.rs | 10 + clippy_lints/src/no_effect.rs | 10 + clippy_lints/src/non_copy_const.rs | 10 + clippy_lints/src/non_expressive_names.rs | 10 + clippy_lints/src/ok_if_let.rs | 10 + clippy_lints/src/open_options.rs | 10 + clippy_lints/src/overflow_check_conditional.rs | 10 + clippy_lints/src/panic_unimplemented.rs | 10 + clippy_lints/src/partialeq_ne_impl.rs | 10 + clippy_lints/src/precedence.rs | 10 + clippy_lints/src/ptr.rs | 10 + clippy_lints/src/ptr_offset_with_cast.rs | 10 + clippy_lints/src/question_mark.rs | 10 + clippy_lints/src/ranges.rs | 10 + clippy_lints/src/redundant_field_names.rs | 10 + clippy_lints/src/reference.rs | 10 + clippy_lints/src/regex.rs | 10 + clippy_lints/src/replace_consts.rs | 10 + clippy_lints/src/returns.rs | 10 + clippy_lints/src/serde_api.rs | 10 + clippy_lints/src/shadow.rs | 10 + clippy_lints/src/strings.rs | 10 + clippy_lints/src/suspicious_trait_impl.rs | 10 + clippy_lints/src/swap.rs | 10 + clippy_lints/src/temporary_assignment.rs | 10 + clippy_lints/src/transmute.rs | 10 + clippy_lints/src/trivially_copy_pass_by_ref.rs | 10 + clippy_lints/src/types.rs | 10 + clippy_lints/src/unicode.rs | 10 + clippy_lints/src/unsafe_removed_from_name.rs | 10 + clippy_lints/src/unused_io_amount.rs | 10 + clippy_lints/src/unused_label.rs | 10 + clippy_lints/src/unwrap.rs | 10 + clippy_lints/src/use_self.rs | 10 + clippy_lints/src/utils/author.rs | 10 + clippy_lints/src/utils/camel_case.rs | 10 + clippy_lints/src/utils/comparisons.rs | 10 + clippy_lints/src/utils/conf.rs | 10 + clippy_lints/src/utils/constants.rs | 10 + clippy_lints/src/utils/higher.rs | 10 + clippy_lints/src/utils/hir_utils.rs | 10 + clippy_lints/src/utils/inspector.rs | 10 + clippy_lints/src/utils/internal_lints.rs | 10 + clippy_lints/src/utils/mod.rs | 10 + clippy_lints/src/utils/paths.rs | 10 + clippy_lints/src/utils/ptr.rs | 10 + clippy_lints/src/utils/sugg.rs | 10 + clippy_lints/src/utils/usage.rs | 10 + clippy_lints/src/vec.rs | 10 + clippy_lints/src/write.rs | 10 + clippy_lints/src/zero_div_zero.rs | 10 + clippy_workspace_tests/src/main.rs | 10 + clippy_workspace_tests/subcrate/src/lib.rs | 10 + mini-macro/src/lib.rs | 10 + rustc_tools_util/src/lib.rs | 10 + src/driver.rs | 10 + src/lib.rs | 10 + src/main.rs | 10 + tests/auxiliary/test_macro.rs | 10 + tests/compile-test.rs | 10 + tests/dogfood.rs | 10 + tests/matches.rs | 10 + tests/needless_continue_helpers.rs | 10 + tests/run-pass/associated-constant-ice.rs | 10 + tests/run-pass/cc_seme.rs | 10 + tests/run-pass/enum-glob-import-crate.rs | 10 + tests/run-pass/ice-1588.rs | 10 + tests/run-pass/ice-1782.rs | 10 + tests/run-pass/ice-1969.rs | 10 + tests/run-pass/ice-2499.rs | 10 + tests/run-pass/ice-2594.rs | 10 + tests/run-pass/ice-2727.rs | 10 + tests/run-pass/ice-2760.rs | 10 + tests/run-pass/ice-2774.rs | 10 + tests/run-pass/ice-2865.rs | 10 + tests/run-pass/ice-3151.rs | 10 + tests/run-pass/ice-700.rs | 10 + tests/run-pass/ice_exacte_size.rs | 10 + tests/run-pass/if_same_then_else.rs | 10 + tests/run-pass/issue-2862.rs | 10 + tests/run-pass/issue-825.rs | 10 + tests/run-pass/issues_loop_mut_cond.rs | 10 + tests/run-pass/match_same_arms_const.rs | 10 + tests/run-pass/mut_mut_macro.rs | 10 + tests/run-pass/needless_borrow_fp.rs | 10 + tests/run-pass/needless_lifetimes_impl_trait.rs | 10 + tests/run-pass/procedural_macro.rs | 10 + tests/run-pass/regressions.rs | 10 + tests/run-pass/returns.rs | 10 + tests/run-pass/single-match-else.rs | 10 + tests/run-pass/used_underscore_binding_macro.rs | 10 + tests/run-pass/whitelist/conf_whitelisted.rs | 10 + tests/ui-toml/bad_toml/conf_bad_toml.rs | 10 + tests/ui-toml/bad_toml_type/conf_bad_type.rs | 10 + .../toml_blacklist/conf_french_blacklisted_name.rs | 10 + .../conf_french_blacklisted_name.stderr | 36 +-- tests/ui-toml/toml_trivially_copy/test.rs | 10 + tests/ui-toml/toml_trivially_copy/test.stderr | 8 +- tests/ui-toml/toml_unknown_key/conf_unknown_key.rs | 10 + tests/ui/absurd-extreme-comparisons.rs | 10 + tests/ui/absurd-extreme-comparisons.stderr | 72 ++--- tests/ui/approx_const.rs | 10 + tests/ui/approx_const.stderr | 88 +++--- tests/ui/arithmetic.rs | 10 + tests/ui/arithmetic.stderr | 58 ++-- tests/ui/assign_ops.rs | 10 + tests/ui/assign_ops.stderr | 52 +-- tests/ui/assign_ops2.rs | 10 + tests/ui/assign_ops2.stderr | 100 +++--- tests/ui/attrs.rs | 10 + tests/ui/attrs.stderr | 20 +- tests/ui/author.rs | 10 + tests/ui/author/call.rs | 10 + tests/ui/author/for_loop.rs | 10 + tests/ui/author/matches.rs | 10 + tests/ui/author/matches.stderr | 20 +- tests/ui/bit_masks.rs | 10 + tests/ui/bit_masks.stderr | 68 ++-- tests/ui/blacklisted_name.rs | 10 + tests/ui/blacklisted_name.stderr | 64 ++-- tests/ui/block_in_if_condition.rs | 10 + tests/ui/block_in_if_condition.stderr | 26 +- tests/ui/bool_comparison.rs | 10 + tests/ui/bool_comparison.stderr | 32 +- tests/ui/booleans.rs | 10 + tests/ui/booleans.stderr | 132 ++++---- tests/ui/borrow_box.rs | 10 + tests/ui/borrow_box.stderr | 30 +- tests/ui/box_vec.rs | 10 + tests/ui/box_vec.stderr | 4 +- tests/ui/builtin-type-shadow.rs | 10 + tests/ui/builtin-type-shadow.stderr | 30 +- tests/ui/bytecount.rs | 10 + tests/ui/bytecount.stderr | 26 +- tests/ui/cast.rs | 10 + tests/ui/cast.stderr | 124 ++++---- tests/ui/cast_alignment.rs | 10 + tests/ui/cast_alignment.stderr | 8 +- tests/ui/cast_lossless_float.rs | 10 + tests/ui/cast_lossless_float.stderr | 56 ++-- tests/ui/cast_lossless_integer.rs | 10 + tests/ui/cast_lossless_integer.stderr | 92 +++--- tests/ui/cast_size.rs | 10 + tests/ui/cast_size.stderr | 96 +++--- tests/ui/char_lit_as_u8.rs | 10 + tests/ui/char_lit_as_u8.stderr | 16 +- tests/ui/checked_unwrap.rs | 10 + tests/ui/checked_unwrap.stderr | 244 +++++++-------- tests/ui/clone_on_copy_impl.rs | 10 + tests/ui/clone_on_copy_mut.rs | 10 + tests/ui/cmp_nan.rs | 10 + tests/ui/cmp_nan.stderr | 60 ++-- tests/ui/cmp_null.rs | 10 + tests/ui/cmp_null.stderr | 8 +- tests/ui/cmp_owned.rs | 10 + tests/ui/cmp_owned.stderr | 32 +- tests/ui/collapsible_if.rs | 10 + tests/ui/collapsible_if.stderr | 286 ++++++++--------- tests/ui/complex_types.rs | 10 + tests/ui/complex_types.stderr | 68 ++-- tests/ui/const_static_lifetime.rs | 10 + tests/ui/const_static_lifetime.stderr | 64 ++-- tests/ui/copies.rs | 10 + tests/ui/copies.stderr | 348 ++++++++++----------- tests/ui/copy_iterator.rs | 10 + tests/ui/copy_iterator.stderr | 14 +- tests/ui/cstring.rs | 10 + tests/ui/cstring.stderr | 22 +- tests/ui/cyclomatic_complexity.rs | 10 + tests/ui/cyclomatic_complexity.stderr | 262 ++++++++-------- tests/ui/cyclomatic_complexity_attr_used.rs | 10 + tests/ui/cyclomatic_complexity_attr_used.stderr | 16 +- tests/ui/decimal_literal_representation.rs | 10 + tests/ui/decimal_literal_representation.stderr | 20 +- tests/ui/default_trait_access.rs | 10 + tests/ui/default_trait_access.stderr | 32 +- tests/ui/deprecated.rs | 10 + tests/ui/deprecated.stderr | 36 +-- tests/ui/derive.rs | 10 + tests/ui/derive.stderr | 92 +++--- tests/ui/diverging_sub_expression.rs | 10 + tests/ui/diverging_sub_expression.stderr | 24 +- tests/ui/dlist.rs | 10 + tests/ui/dlist.stderr | 24 +- tests/ui/doc.rs | 10 + tests/ui/doc.stderr | 128 ++++---- tests/ui/double_comparison.rs | 10 + tests/ui/double_comparison.stderr | 44 +-- tests/ui/double_neg.rs | 10 + tests/ui/double_neg.stderr | 12 +- tests/ui/double_parens.rs | 10 + tests/ui/double_parens.stderr | 24 +- tests/ui/drop_forget_copy.rs | 10 + tests/ui/drop_forget_copy.stderr | 48 +-- tests/ui/drop_forget_ref.rs | 10 + tests/ui/drop_forget_ref.stderr | 144 ++++----- tests/ui/duplicate_underscore_argument.rs | 10 + tests/ui/duplicate_underscore_argument.stderr | 12 +- tests/ui/duration_subsec.rs | 10 + tests/ui/duration_subsec.stderr | 20 +- tests/ui/else_if_without_else.rs | 10 + tests/ui/else_if_without_else.stderr | 16 +- tests/ui/empty_enum.rs | 10 + tests/ui/empty_enum.stderr | 20 +- tests/ui/empty_line_after_outer_attribute.rs | 10 + tests/ui/empty_line_after_outer_attribute.stderr | 60 ++-- tests/ui/entry.rs | 10 + tests/ui/entry.stderr | 28 +- tests/ui/enum_glob_use.rs | 10 + tests/ui/enum_glob_use.stderr | 16 +- tests/ui/enum_variants.rs | 10 + tests/ui/enum_variants.stderr | 106 +++---- tests/ui/enums_clike.rs | 10 + tests/ui/enums_clike.stderr | 32 +- tests/ui/eq_op.rs | 10 + tests/ui/eq_op.stderr | 140 ++++----- tests/ui/erasing_op.rs | 10 + tests/ui/erasing_op.stderr | 20 +- tests/ui/escape_analysis.rs | 10 + tests/ui/eta.rs | 10 + tests/ui/eta.stderr | 36 +-- tests/ui/eval_order_dependence.rs | 10 + tests/ui/eval_order_dependence.stderr | 44 +-- tests/ui/excessive_precision.rs | 10 + tests/ui/excessive_precision.stderr | 72 ++--- tests/ui/explicit_write.rs | 10 + tests/ui/explicit_write.stderr | 24 +- tests/ui/fallible_impl_from.rs | 10 + tests/ui/fallible_impl_from.stderr | 84 ++--- tests/ui/filter_methods.rs | 10 + tests/ui/filter_methods.stderr | 32 +- tests/ui/float_cmp.rs | 10 + tests/ui/float_cmp.stderr | 24 +- tests/ui/float_cmp_const.rs | 10 + tests/ui/float_cmp_const.stderr | 56 ++-- tests/ui/fn_to_numeric_cast.rs | 10 + tests/ui/fn_to_numeric_cast.stderr | 100 +++--- tests/ui/for_loop.rs | 10 + tests/ui/for_loop.stderr | 314 +++++++++---------- tests/ui/format.rs | 10 + tests/ui/format.stderr | 36 +-- tests/ui/formatting.rs | 10 + tests/ui/formatting.stderr | 46 +-- tests/ui/functions.rs | 10 + tests/ui/functions.stderr | 50 +-- tests/ui/fxhash.rs | 10 + tests/ui/fxhash.stderr | 36 +-- tests/ui/get_unwrap.rs | 10 + tests/ui/get_unwrap.stderr | 48 +-- tests/ui/identity_conversion.rs | 10 + tests/ui/identity_conversion.stderr | 54 ++-- tests/ui/identity_op.rs | 10 + tests/ui/identity_op.stderr | 32 +- tests/ui/if_let_redundant_pattern_matching.rs | 10 + tests/ui/if_let_redundant_pattern_matching.stderr | 24 +- tests/ui/if_not_else.rs | 10 + tests/ui/if_not_else.stderr | 24 +- tests/ui/impl.rs | 10 + tests/ui/impl.stderr | 32 +- tests/ui/implicit_hasher.rs | 10 + tests/ui/implicit_hasher.stderr | 78 ++--- tests/ui/inconsistent_digit_grouping.rs | 10 + tests/ui/inconsistent_digit_grouping.stderr | 44 +-- tests/ui/indexing_slicing.rs | 10 + tests/ui/indexing_slicing.stderr | 148 ++++----- tests/ui/infallible_destructuring_match.rs | 10 + tests/ui/infallible_destructuring_match.stderr | 24 +- tests/ui/infinite_iter.rs | 10 + tests/ui/infinite_iter.stderr | 64 ++-- tests/ui/infinite_loop.rs | 10 + tests/ui/infinite_loop.stderr | 40 +-- tests/ui/inline_fn_without_body.rs | 10 + tests/ui/inline_fn_without_body.stderr | 26 +- tests/ui/int_plus_one.rs | 10 + tests/ui/int_plus_one.stderr | 24 +- tests/ui/invalid_ref.rs | 10 + tests/ui/invalid_ref.stderr | 24 +- tests/ui/invalid_upcast_comparisons.rs | 10 + tests/ui/invalid_upcast_comparisons.stderr | 108 +++---- tests/ui/issue-3145.rs | 10 + tests/ui/issue-3145.stderr | 8 +- tests/ui/issue_2356.rs | 10 + tests/ui/issue_2356.stderr | 8 +- tests/ui/item_after_statement.rs | 10 + tests/ui/item_after_statement.stderr | 8 +- tests/ui/large_digit_groups.rs | 10 + tests/ui/large_digit_groups.stderr | 52 +-- tests/ui/large_enum_variant.rs | 10 + tests/ui/large_enum_variant.stderr | 42 +-- tests/ui/len_zero.rs | 10 + tests/ui/len_zero.stderr | 118 +++---- tests/ui/let_if_seq.rs | 10 + tests/ui/let_if_seq.stderr | 48 +-- tests/ui/let_return.rs | 10 + tests/ui/let_return.stderr | 16 +- tests/ui/let_unit.rs | 10 + tests/ui/let_unit.stderr | 8 +- tests/ui/lifetimes.rs | 10 + tests/ui/lifetimes.stderr | 76 ++--- tests/ui/literals.rs | 10 + tests/ui/literals.stderr | 108 +++---- tests/ui/map_clone.rs | 10 + tests/ui/map_clone.stderr | 28 +- tests/ui/map_flatten.rs | 10 + tests/ui/map_flatten.stderr | 12 +- tests/ui/match_bool.rs | 10 + tests/ui/match_bool.stderr | 76 ++--- tests/ui/matches.rs | 10 + tests/ui/matches.stderr | 276 ++++++++-------- tests/ui/mem_forget.rs | 10 + tests/ui/mem_forget.stderr | 12 +- tests/ui/mem_replace.rs | 10 + tests/ui/mem_replace.stderr | 16 +- tests/ui/methods.rs | 10 + tests/ui/methods.stderr | 326 +++++++++---------- tests/ui/min_max.rs | 10 + tests/ui/min_max.stderr | 28 +- tests/ui/missing-doc.rs | 10 + tests/ui/missing-doc.stderr | 226 ++++++------- tests/ui/missing_inline.rs | 10 + tests/ui/missing_inline.stderr | 24 +- tests/ui/module_inception.rs | 10 + tests/ui/module_inception.stderr | 24 +- tests/ui/modulo_one.rs | 10 + tests/ui/modulo_one.stderr | 12 +- tests/ui/mut_from_ref.rs | 10 + tests/ui/mut_from_ref.stderr | 52 +-- tests/ui/mut_mut.rs | 10 + tests/ui/mut_mut.stderr | 38 +-- tests/ui/mut_range_bound.rs | 10 + tests/ui/mut_range_bound.stderr | 20 +- tests/ui/mut_reference.rs | 10 + tests/ui/mut_reference.stderr | 12 +- tests/ui/mutex_atomic.rs | 10 + tests/ui/mutex_atomic.stderr | 36 +-- tests/ui/needless_bool.rs | 10 + tests/ui/needless_bool.stderr | 52 +-- tests/ui/needless_borrow.rs | 10 + tests/ui/needless_borrow.stderr | 24 +- tests/ui/needless_borrowed_ref.rs | 10 + tests/ui/needless_borrowed_ref.stderr | 24 +- tests/ui/needless_collect.rs | 10 + tests/ui/needless_collect.stderr | 24 +- tests/ui/needless_continue.rs | 10 + tests/ui/needless_continue.stderr | 22 +- tests/ui/needless_pass_by_value.rs | 10 + tests/ui/needless_pass_by_value.stderr | 140 ++++----- tests/ui/needless_pass_by_value_proc_macro.rs | 10 + tests/ui/needless_range_loop.rs | 10 + tests/ui/needless_range_loop.stderr | 30 +- tests/ui/needless_return.rs | 10 + tests/ui/needless_return.stderr | 32 +- tests/ui/needless_update.rs | 10 + tests/ui/needless_update.stderr | 4 +- tests/ui/neg_cmp_op_on_partial_ord.rs | 10 + tests/ui/neg_cmp_op_on_partial_ord.stderr | 16 +- tests/ui/neg_multiply.rs | 10 + tests/ui/neg_multiply.stderr | 8 +- tests/ui/never_loop.rs | 10 + tests/ui/never_loop.stderr | 106 +++---- tests/ui/new_without_default.rs | 10 + tests/ui/new_without_default.stderr | 26 +- tests/ui/no_effect.rs | 10 + tests/ui/no_effect.stderr | 188 +++++------ tests/ui/non_copy_const.rs | 10 + tests/ui/non_copy_const.stderr | 188 +++++------ tests/ui/non_expressive_names.rs | 10 + tests/ui/non_expressive_names.stderr | 112 +++---- tests/ui/ok_expect.rs | 10 + tests/ui/ok_expect.stderr | 20 +- tests/ui/ok_if_let.rs | 10 + tests/ui/ok_if_let.stderr | 12 +- tests/ui/op_ref.rs | 10 + tests/ui/op_ref.stderr | 10 +- tests/ui/open_options.rs | 10 + tests/ui/open_options.stderr | 40 +-- tests/ui/option_map_unit_fn.rs | 10 + tests/ui/option_map_unit_fn.stderr | 138 ++++---- tests/ui/option_option.rs | 10 + tests/ui/option_option.stderr | 52 +-- tests/ui/overflow_check_conditional.rs | 10 + tests/ui/overflow_check_conditional.stderr | 32 +- tests/ui/panic_unimplemented.rs | 10 + tests/ui/panic_unimplemented.stderr | 28 +- tests/ui/partialeq_ne_impl.rs | 10 + tests/ui/partialeq_ne_impl.stderr | 4 +- tests/ui/patterns.rs | 10 + tests/ui/patterns.stderr | 4 +- tests/ui/precedence.rs | 10 + tests/ui/precedence.stderr | 36 +-- tests/ui/print.rs | 10 + tests/ui/print.stderr | 36 +-- tests/ui/print_literal.rs | 10 + tests/ui/print_literal.stderr | 56 ++-- tests/ui/print_with_newline.rs | 10 + tests/ui/print_with_newline.stderr | 32 +- tests/ui/println_empty_string.rs | 10 + tests/ui/println_empty_string.stderr | 20 +- tests/ui/ptr_arg.rs | 10 + tests/ui/ptr_arg.stderr | 56 ++-- tests/ui/ptr_offset_with_cast.rs | 10 + tests/ui/ptr_offset_with_cast.stderr | 8 +- tests/ui/question_mark.rs | 10 + tests/ui/question_mark.stderr | 26 +- tests/ui/range.rs | 10 + tests/ui/range.stderr | 24 +- tests/ui/range_plus_minus_one.rs | 10 + tests/ui/range_plus_minus_one.stderr | 32 +- tests/ui/redundant_closure_call.rs | 10 + tests/ui/redundant_closure_call.stderr | 24 +- tests/ui/redundant_field_names.rs | 10 + tests/ui/redundant_field_names.stderr | 28 +- tests/ui/reference.rs | 10 + tests/ui/reference.stderr | 44 +-- tests/ui/regex.rs | 10 + tests/ui/regex.stderr | 92 +++--- tests/ui/replace_consts.rs | 10 + tests/ui/replace_consts.stderr | 144 ++++----- tests/ui/result_map_unit_fn.rs | 10 + tests/ui/result_map_unit_fn.stderr | 114 +++---- tests/ui/serde.rs | 10 + tests/ui/serde.stderr | 12 +- tests/ui/shadow.rs | 10 + tests/ui/shadow.stderr | 92 +++--- tests/ui/short_circuit_statement.rs | 10 + tests/ui/short_circuit_statement.stderr | 28 +- tests/ui/single_char_pattern.rs | 10 + tests/ui/single_char_pattern.stderr | 88 +++--- tests/ui/single_match.rs | 10 + tests/ui/single_match.stderr | 50 +-- tests/ui/starts_ends_with.rs | 10 + tests/ui/starts_ends_with.stderr | 56 ++-- tests/ui/string_extend.rs | 10 + tests/ui/string_extend.stderr | 12 +- tests/ui/strings.rs | 10 + tests/ui/strings.stderr | 44 +-- tests/ui/stutter.rs | 10 + tests/ui/stutter.stderr | 32 +- tests/ui/suspicious_arithmetic_impl.rs | 10 + tests/ui/suspicious_arithmetic_impl.stderr | 8 +- tests/ui/swap.rs | 10 + tests/ui/swap.stderr | 52 +-- tests/ui/temporary_assignment.rs | 10 + tests/ui/temporary_assignment.stderr | 8 +- tests/ui/toplevel_ref_arg.rs | 10 + tests/ui/toplevel_ref_arg.stderr | 28 +- tests/ui/trailing_zeros.rs | 10 + tests/ui/trailing_zeros.stderr | 20 +- tests/ui/transmute.rs | 10 + tests/ui/transmute.stderr | 160 +++++----- tests/ui/transmute_32bit.rs | 10 + tests/ui/transmute_64bit.rs | 10 + tests/ui/transmute_64bit.stderr | 8 +- tests/ui/trivially_copy_pass_by_ref.rs | 10 + tests/ui/trivially_copy_pass_by_ref.stderr | 52 +-- tests/ui/ty_fn_sig.rs | 10 + tests/ui/types.rs | 10 + tests/ui/types.stderr | 12 +- tests/ui/unicode.rs | 10 + tests/ui/unicode.stderr | 24 +- tests/ui/unit_arg.rs | 10 + tests/ui/unit_arg.stderr | 42 +-- tests/ui/unit_cmp.rs | 10 + tests/ui/unit_cmp.stderr | 8 +- tests/ui/unnecessary_clone.rs | 10 + tests/ui/unnecessary_clone.stderr | 48 +-- tests/ui/unnecessary_filter_map.rs | 10 + tests/ui/unnecessary_filter_map.stderr | 44 +-- tests/ui/unnecessary_fold.rs | 10 + tests/ui/unnecessary_fold.stderr | 36 +-- tests/ui/unnecessary_ref.rs | 10 + tests/ui/unnecessary_ref.stderr | 8 +- tests/ui/unneeded_field_pattern.rs | 10 + tests/ui/unneeded_field_pattern.stderr | 8 +- tests/ui/unreadable_literal.rs | 10 + tests/ui/unreadable_literal.stderr | 44 +-- tests/ui/unsafe_removed_from_name.rs | 10 + tests/ui/unsafe_removed_from_name.stderr | 24 +- tests/ui/unused_io_amount.rs | 10 + tests/ui/unused_io_amount.stderr | 24 +- tests/ui/unused_labels.rs | 10 + tests/ui/unused_labels.stderr | 20 +- tests/ui/unused_lt.rs | 10 + tests/ui/unused_lt.stderr | 12 +- tests/ui/unwrap_or.rs | 10 + tests/ui/unwrap_or.stderr | 16 +- tests/ui/use_self.rs | 10 + tests/ui/use_self.stderr | 104 +++--- tests/ui/used_underscore_binding.rs | 10 + tests/ui/used_underscore_binding.stderr | 20 +- tests/ui/useless_asref.rs | 10 + tests/ui/useless_asref.stderr | 48 +-- tests/ui/useless_attribute.rs | 10 + tests/ui/useless_attribute.stderr | 20 +- tests/ui/vec.rs | 10 + tests/ui/vec.stderr | 24 +- tests/ui/while_loop.rs | 10 + tests/ui/while_loop.stderr | 112 +++---- tests/ui/write_literal.rs | 10 + tests/ui/write_literal.stderr | 56 ++-- tests/ui/write_with_newline.rs | 10 + tests/ui/write_with_newline.stderr | 16 +- tests/ui/writeln_empty_string.rs | 10 + tests/ui/writeln_empty_string.stderr | 8 +- tests/ui/wrong_self_convention.rs | 10 + tests/ui/wrong_self_convention.stderr | 48 +-- tests/ui/zero_div_zero.rs | 10 + tests/ui/zero_div_zero.stderr | 74 ++--- tests/ui/zero_ptr.rs | 10 + tests/ui/zero_ptr.stderr | 20 +- tests/versioncheck.rs | 10 + 599 files changed, 9468 insertions(+), 5508 deletions(-) mode change 100755 => 100644 tests/ui/author/call.rs (limited to 'src') diff --git a/build.rs b/build.rs index 146a8dae745..336f0295bdf 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { // Forward the profile to the main compilation println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 2f91c987cb1..2087a4b0740 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::default_hash_types)] diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index f45c52e2271..28f831a9b1c 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + extern crate clap; extern crate clippy_dev; extern crate regex; diff --git a/clippy_dummy/build.rs b/clippy_dummy/build.rs index 97902feff86..b4ea0772ee5 100644 --- a/clippy_dummy/build.rs +++ b/clippy_dummy/build.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + extern crate term; fn main() { diff --git a/clippy_dummy/src/main.rs b/clippy_dummy/src/main.rs index a118834f1fd..878993d5c28 100644 --- a/clippy_dummy/src/main.rs +++ b/clippy_dummy/src/main.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { panic!("This shouldn't even compile") } diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 4d921daea8a..01cb03730b8 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::span_lint; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index bdf8d237c70..4d7e921567d 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::span_lint; use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index a05a4d55010..3fbac7bc153 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq}; use crate::utils::{higher, sugg}; use crate::rustc::hir; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index e192c3f2093..f463ce5fa35 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! checks for attributes use crate::reexport::*; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 7151e8db9aa..6ba6a182902 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 9d6005cd612..ecc9957b88f 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index c1b4b4575ab..129b8fe9e58 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use matches::matches; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 1201b4a0c64..f12859d90c3 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 7ec556b5d78..a61e823f959 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b0fb058116f..85fdca1d421 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for if expressions that contain only an if expression. //! //! For example, the lint would catch: diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index bb9829ad3c9..4c49aee2850 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::syntax::ast::*; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 4e09e039100..584060aeca3 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(clippy::float_cmp)] use crate::rustc::lint::LateContext; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 26669d8c4c2..ac73dc1f5d5 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::ty::Ty; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 17f32c7bb45..f4d29433cb8 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::{is_copy, match_path, paths, span_note_and_lint}; use crate::rustc::hir::{Item, ItemKind}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index db85a3f3fda..7971d20d83f 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! calculate cyclomatic complexity and warn about overly complex functions use crate::rustc::cfg::CFG; diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 5f2b1a29dc7..66d94e00d0d 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 983f347c56f..0067629bbd0 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + macro_rules! declare_deprecated_lint { (pub $name: ident, $_reason: expr) => { declare_lint!(pub $name, Allow, "deprecated lint") diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 21365f60586..792699fc0c5 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 19f2916cc5e..9c25e79aa71 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use itertools::Itertools; use pulldown_cmark; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index c692bffaff6..e151918c1fb 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Lint on unnecessary double comparisons. Some examples: use crate::rustc::hir::*; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 3b2ef4e8bb2..ffaf93bd7a1 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::syntax::ast::*; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 1dbca5ed9ba..cac5d0da71d 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 709cbd27754..a679a97c2e7 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index da6e860e236..26ffef9ebe4 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on if expressions with an else if, but without a final else branch use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 48c96a0ffad..7ac33fd452e 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint when there is an enum with no variants use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 965d425b43d..75c43745207 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index b49322dcaf9..8fba45de8ce 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index d594406decf..ebd28ee2796 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on `use`ing all variants of an enum use crate::rustc::hir::*; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index c68439d161b..8d708f01720 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on enum variants that are prefixed or suffixed by the same characters use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, Lint}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 7b9f2568da9..a454ea83695 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 7e313daffa4..7bfc2ef31d0 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::consts::{constant_simple, Constant}; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 8af232420b1..0491cde4fed 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::hir::intravisit as visit; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 556f76af3a7..59c7f8a36db 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::ty; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 068d6fb135f..31fae2d1967 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::*; use crate::rustc::ty; diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index 0ae228d1dea..9f8224cd2f0 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 888dca97928..b5a5d7e497d 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 146e2366552..07674ef2763 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 7e2e355c251..41046a98a34 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 92950706d88..7f5715ef691 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast; diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index d73c0710ba1..d087452d16d 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use matches::matches; use crate::rustc::hir::intravisit; use crate::rustc::hir; diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index 5b1bd0ada7b..e9761616696 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 836e4fafba4..3f05f21e840 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::consts::{constant_simple, Constant}; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs index c9fbf1b0775..4ee8d9f0ca7 100644 --- a/clippy_lints/src/if_let_redundant_pattern_matching.rs +++ b/clippy_lints/src/if_let_redundant_pattern_matching.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 954f8543a87..e005eb40144 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 1010b53e09a..984d725898d 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on indexing and slicing operations use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs index dabc167f37d..7bbbe72f91d 100644 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ b/clippy_lints/src/infallible_destructuring_match.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use super::utils::{get_arg_name, match_var, remove_blocks, snippet, span_lint_and_sugg}; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index a15ec8c14bd..9c727dccd33 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 167259b7353..3fa442a3562 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on inherent implementations use crate::rustc::hir::*; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 881bebc2f60..bbd16eaeaf8 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! checks for `#[inline]` on trait methods without bodies use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 69a19e2fb01..4349b15f100 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on blocks unnecessarily using >= with a + 1 or - 1 use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index 55de8998378..fe599192053 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index a12c9c400ba..57124e5d019 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint when items are used after statements use matches::matches; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index e8982d92b56..79ff0c84bce 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint when there is a large size difference between variants on an enum use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index b126b8dbb93..defb5892e51 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::def_id::DefId; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 53d13407be3..4cee4f34a63 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3779b09ecf3..e4ad9fe9ca1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern:cargo-clippy #![feature(box_syntax)] diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index dbd433bc909..d1cf0da876b 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::reexport::*; use matches::matches; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 188ca157423..a123415cca9 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Lints concerned with the grouping of digits with underscores in integral or //! floating-point literal expressions. diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2c05d9a198f..b807e4fb9e1 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use itertools::Itertools; use crate::reexport::*; use crate::rustc::hir::*; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index e16a8af7641..c2bfcf18280 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 40b81e6fdb8..e620a1815ce 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c1a65e756a9..e46615f4da2 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index 7a07ecbf02c..dd2a1ca50e7 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index fd22e3afe80..ff57571a948 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e0d858bd270..30c82e3969f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::hir::def::Def; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass}; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 0a3486df8bd..86889c4c7c4 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::hir::def::Def; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 293d301ebb4..222247307c8 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::consts::{constant_simple, Constant}; use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0fa05de2841..a83fa75de69 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::reexport::*; use matches::matches; use crate::rustc::hir::*; diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index d3e1ca93784..a2fd487078e 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 685f701ef8b..20da0e7a698 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // This file incorporates work covered by the following copyright and // permission notice: // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index dea3a81e50d..2f3819a2da4 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // 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. diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index 9c10a929d6f..dbf8cbe16c2 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! lint on multiple versions of a crate being used use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index b3607d623b3..737d8bfd92c 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir; use crate::rustc::hir::intravisit; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 1bf06b9e20a..bdf8bf80c88 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::ty::{self, Ty}; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index f6caddab485..8ddaf692b7e 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for uses of mutex where an atomic value could be used //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 74b6647551a..f102b49d785 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for needless boolean results of if-else expressions //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 8a676be99ea..639358a7ce7 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for needless address of operations (`&`) //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 057a097f4b7..f40fbef6d2f 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for useless borrowed references. //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 0f7ea34f18a..6a39595f62e 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for continue statements in loops that are redundant. //! //! For example, the lint would catch diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 73d59d7a33c..39f519ac586 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use matches::matches; use crate::rustc::hir::*; use crate::rustc::hir::intravisit::FnKind; diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 7c452bed0a3..3388c92e0ec 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::ty; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 08ad4dd43c9..7cd14b9a2d6 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index f39cfc8d122..d3b72372c2f 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index e0b54620faf..9f2d29a1b63 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::def_id::DefId; use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 5ff0979670d..289b5591edc 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::def::Def; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 3b97e9d4a17..61b57db51d5 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for uses of const which the type is not Freeze (Cell-free). //! //! This lint is **deny** by default. diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 77642b4727c..ad4f52a528f 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::source_map::Span; diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index cd97e485342..9a23b05b8d9 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 9133192549f..4f647d053e3 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::{Expr, ExprKind}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index bdd87ad3a25..d0805896fb7 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 404f43312e5..003c9bdf084 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 7eb0c089726..d38e02d6326 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index e77a49266ba..1c5e8fcb964 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast::*; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 86cb89f2de1..187d89cdd79 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Checks for usage of `&Vec[_]` and `&String`. use std::borrow::Cow; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 261e5cccbdd..38a9bbf6d4c 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::{declare_tool_lint, hir, lint, lint_array}; use crate::utils; use std::fmt; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index ced0fe3ef50..0ec57e0be80 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index c60ed3842d4..bc3125253a2 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 38cb4578d9e..526232f7853 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast::*; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 1faacc79df0..79d30612cbd 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::syntax::ast::{Expr, ExprKind, UnOp}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 41ff8a4bc0c..7a818c41fff 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use regex_syntax; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index 05cca2ac338..ca17a032526 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 9ab6b50ada6..f4360802483 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index f2cfdf82d5b..5f8789016b5 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 4a989353600..16567535c90 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::reexport::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 54fced12425..f4798842205 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 78a2c2adeb3..af7ff8d938f 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 5de2f0e54a9..77a33e9eebb 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use matches::matches; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 7cde4eb48f3..292bf9fb6a4 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 69422056df5..0d49f5de265 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index baa9a8c3903..61a2a9ded44 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use std::cmp; use matches::matches; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 2e660088380..24b895b23a6 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(clippy::default_hash_types)] use crate::reexport::*; diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 83f9713b59e..a140b567f01 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::*; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index e6472eb50bf..cd9d649ed0a 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast::*; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 82430a794b1..1bb819a74e3 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir; diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index a67164becfb..0b2237ac22b 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index f8fe1b3bdfa..f7a2d0805fa 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 3b2659a6176..d770ea120eb 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::{in_macro, span_lint_and_sugg}; use if_chain::if_chain; use crate::rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 8e8d40e28a9..6650dd67b4f 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. diff --git a/clippy_lints/src/utils/camel_case.rs b/clippy_lints/src/utils/camel_case.rs index e8a8d510fe5..2b60e2c32fa 100644 --- a/clippy_lints/src/utils/camel_case.rs +++ b/clippy_lints/src/utils/camel_case.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + /// Return the index of the character after the first camel-case component of /// `s`. pub fn camel_case_until(s: &str) -> usize { diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index bd90fe1bc0a..986802107c0 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Utility functions about comparison operators. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index d79a7743e0f..faf4e2702f0 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Read configurations files. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs index b63be9b86c8..42da95a12ed 100644 --- a/clippy_lints/src/utils/constants.rs +++ b/clippy_lints/src/utils/constants.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! This module contains some useful constants. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index cfedad49f31..584a6df1cc6 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! This module contains functions for retrieve the original AST from lowered //! `hir`. diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 2257fbf7743..bc55c22979b 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::consts::{constant_simple, constant_context}; use crate::rustc::lint::LateContext; use crate::rustc::hir::*; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 413c71ab27b..841aaaabdfa 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(clippy::print_stdout, clippy::use_debug)] //! checks for attributes diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 058f7ee2fab..3a0d056bbb5 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::{ match_qpath, match_type, paths, span_help_and_lint, span_lint, span_lint_and_sugg, walk_ptrs_ty, }; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6c963cf205b..7282e5064c3 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::reexport::*; use matches::matches; use if_chain::if_chain; diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index f2f1a4db375..12ef2f51d8c 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! This module contains paths to types and functions Clippy needs to know //! about. diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index a28e1c7fe9d..43ab0f064ac 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use std::borrow::Cow; use crate::rustc::hir::*; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 076907e4945..fecfc0c0789 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 826ca78e64b..d26ffc715e8 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::lint::LateContext; use crate::rustc::hir::def::Def; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 4c6060192cf..21a33bd143f 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index a367a04b2ba..05ddbfe6f84 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::utils::{snippet, span_lint, span_lint_and_sugg}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 5ceff6d4aa0..779a6a59e54 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use crate::consts::{constant_simple, Constant}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_workspace_tests/src/main.rs b/clippy_workspace_tests/src/main.rs index f79c691f085..7af28f80b9b 100644 --- a/clippy_workspace_tests/src/main.rs +++ b/clippy_workspace_tests/src/main.rs @@ -1,2 +1,12 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { } diff --git a/clippy_workspace_tests/subcrate/src/lib.rs b/clippy_workspace_tests/subcrate/src/lib.rs index e69de29bb2d..fd694f68ca6 100644 --- a/clippy_workspace_tests/subcrate/src/lib.rs +++ b/clippy_workspace_tests/subcrate/src/lib.rs @@ -0,0 +1,10 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index 01cdc70c72a..d326dd7e679 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(proc_macro_quote, proc_macro_hygiene)] extern crate proc_macro; diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 09d80072d66..0951a0dee28 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use std::env; #[macro_export] diff --git a/src/driver.rs b/src/driver.rs index 6c442e42d95..d2ed3cb1c26 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] diff --git a/src/lib.rs b/src/lib.rs index bfa44d08703..58158f92e65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] diff --git a/src/main.rs b/src/main.rs index cf26549774c..11c259b4d6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] diff --git a/tests/auxiliary/test_macro.rs b/tests/auxiliary/test_macro.rs index 624ca892add..497fedff15e 100644 --- a/tests/auxiliary/test_macro.rs +++ b/tests/auxiliary/test_macro.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + pub trait A {} macro_rules! __implicit_hasher_test_macro { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index da5c5bd3227..c9d4f658935 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(test)] extern crate compiletest_rs as compiletest; diff --git a/tests/dogfood.rs b/tests/dogfood.rs index ff7452c7c10..0815b146677 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[test] fn dogfood() { if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) { diff --git a/tests/matches.rs b/tests/matches.rs index 3b4910315f5..99b05e50c9f 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(rustc_private)] extern crate clippy_lints; diff --git a/tests/needless_continue_helpers.rs b/tests/needless_continue_helpers.rs index 2f6f5c0a81c..662ae110845 100644 --- a/tests/needless_continue_helpers.rs +++ b/tests/needless_continue_helpers.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // Tests for the various helper functions used by the needless_continue diff --git a/tests/run-pass/associated-constant-ice.rs b/tests/run-pass/associated-constant-ice.rs index 2c5c90683cc..bc9a0b3b6d5 100644 --- a/tests/run-pass/associated-constant-ice.rs +++ b/tests/run-pass/associated-constant-ice.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + pub trait Trait { const CONSTANT: u8; } diff --git a/tests/run-pass/cc_seme.rs b/tests/run-pass/cc_seme.rs index 1539d3c61bc..215b4096b56 100644 --- a/tests/run-pass/cc_seme.rs +++ b/tests/run-pass/cc_seme.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[allow(dead_code)] enum Baz { One, diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs index 6014558a184..c1e1d9645d1 100644 --- a/tests/run-pass/enum-glob-import-crate.rs +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::all)] diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs index fcda3814e4a..db5a6629a2b 100644 --- a/tests/run-pass/ice-1588.rs +++ b/tests/run-pass/ice-1588.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::all)] diff --git a/tests/run-pass/ice-1782.rs b/tests/run-pass/ice-1782.rs index fcd3e7cf530..2101b4d3037 100644 --- a/tests/run-pass/ice-1782.rs +++ b/tests/run-pass/ice-1782.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs index 43d6bd8bfbc..0b4a0f4dfbf 100644 --- a/tests/run-pass/ice-1969.rs +++ b/tests/run-pass/ice-1969.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::all)] diff --git a/tests/run-pass/ice-2499.rs b/tests/run-pass/ice-2499.rs index c6793a78529..9716e5500c7 100644 --- a/tests/run-pass/ice-2499.rs +++ b/tests/run-pass/ice-2499.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] diff --git a/tests/run-pass/ice-2594.rs b/tests/run-pass/ice-2594.rs index 7cd30b6d946..8bd77e3d6f0 100644 --- a/tests/run-pass/ice-2594.rs +++ b/tests/run-pass/ice-2594.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/tests/run-pass/ice-2727.rs b/tests/run-pass/ice-2727.rs index 79c6f1c55db..420be4c7112 100644 --- a/tests/run-pass/ice-2727.rs +++ b/tests/run-pass/ice-2727.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + pub fn f(new: fn()) { new(); } diff --git a/tests/run-pass/ice-2760.rs b/tests/run-pass/ice-2760.rs index 2e9c6d527c4..ad517b84c2c 100644 --- a/tests/run-pass/ice-2760.rs +++ b/tests/run-pass/ice-2760.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused_variables, clippy::blacklisted_name, diff --git a/tests/run-pass/ice-2774.rs b/tests/run-pass/ice-2774.rs index 6b14a2b5e03..6ed09a4a008 100644 --- a/tests/run-pass/ice-2774.rs +++ b/tests/run-pass/ice-2774.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::collections::HashSet; diff --git a/tests/run-pass/ice-2865.rs b/tests/run-pass/ice-2865.rs index 430de25a29d..1713915745a 100644 --- a/tests/run-pass/ice-2865.rs +++ b/tests/run-pass/ice-2865.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[allow(dead_code)] struct Ice { size: String diff --git a/tests/run-pass/ice-3151.rs b/tests/run-pass/ice-3151.rs index 5ee83dac7b3..8e1b7b9a178 100644 --- a/tests/run-pass/ice-3151.rs +++ b/tests/run-pass/ice-3151.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[derive(Clone)] pub struct HashMap<V, S> { hash_builder: S, diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs index 3992af2c280..3252381e1fd 100644 --- a/tests/run-pass/ice-700.rs +++ b/tests/run-pass/ice-700.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::all)] diff --git a/tests/run-pass/ice_exacte_size.rs b/tests/run-pass/ice_exacte_size.rs index 3d25aa50499..8a905a401e5 100644 --- a/tests/run-pass/ice_exacte_size.rs +++ b/tests/run-pass/ice_exacte_size.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::all)] diff --git a/tests/run-pass/if_same_then_else.rs b/tests/run-pass/if_same_then_else.rs index b7536e25028..4f0f581063a 100644 --- a/tests/run-pass/if_same_then_else.rs +++ b/tests/run-pass/if_same_then_else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::if_same_then_else)] diff --git a/tests/run-pass/issue-2862.rs b/tests/run-pass/issue-2862.rs index b35df667f27..298ce088cea 100644 --- a/tests/run-pass/issue-2862.rs +++ b/tests/run-pass/issue-2862.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + pub trait FooMap { fn map<B, F: Fn() -> B>(&self, f: F) -> B; } diff --git a/tests/run-pass/issue-825.rs b/tests/run-pass/issue-825.rs index 79df259eadb..576d53757cf 100644 --- a/tests/run-pass/issue-825.rs +++ b/tests/run-pass/issue-825.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(warnings)] // this should compile in a reasonable amount of time diff --git a/tests/run-pass/issues_loop_mut_cond.rs b/tests/run-pass/issues_loop_mut_cond.rs index 6ecd40b99b1..c3deae9bafd 100644 --- a/tests/run-pass/issues_loop_mut_cond.rs +++ b/tests/run-pass/issues_loop_mut_cond.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(dead_code)] /// Issue: https://github.com/rust-lang-nursery/rust-clippy/issues/2596 diff --git a/tests/run-pass/match_same_arms_const.rs b/tests/run-pass/match_same_arms_const.rs index 59b939f3e01..1e36baf059b 100644 --- a/tests/run-pass/match_same_arms_const.rs +++ b/tests/run-pass/match_same_arms_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::match_same_arms)] diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs index bfb9cfc7170..afc3c9eda15 100644 --- a/tests/run-pass/mut_mut_macro.rs +++ b/tests/run-pass/mut_mut_macro.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)] diff --git a/tests/run-pass/needless_borrow_fp.rs b/tests/run-pass/needless_borrow_fp.rs index 204968e48d0..6a70849d9ca 100644 --- a/tests/run-pass/needless_borrow_fp.rs +++ b/tests/run-pass/needless_borrow_fp.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[deny(clippy::all)] diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs index f727b2547e3..b27bb284e21 100644 --- a/tests/run-pass/needless_lifetimes_impl_trait.rs +++ b/tests/run-pass/needless_lifetimes_impl_trait.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::needless_lifetimes)] diff --git a/tests/run-pass/procedural_macro.rs b/tests/run-pass/procedural_macro.rs index 2b7ff123ea6..a9c9dd06b42 100644 --- a/tests/run-pass/procedural_macro.rs +++ b/tests/run-pass/procedural_macro.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[macro_use] extern crate clippy_mini_macro_test; diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs index aa4e16d3949..a589922218d 100644 --- a/tests/run-pass/regressions.rs +++ b/tests/run-pass/regressions.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::blacklisted_name)] diff --git a/tests/run-pass/returns.rs b/tests/run-pass/returns.rs index 882d3aa7f32..cc7678d603b 100644 --- a/tests/run-pass/returns.rs +++ b/tests/run-pass/returns.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[deny(warnings)] fn cfg_return() -> i32 { #[cfg(unix)] return 1; diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs index 379a98fc3ec..54c282451b8 100644 --- a/tests/run-pass/single-match-else.rs +++ b/tests/run-pass/single-match-else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::single_match_else)] diff --git a/tests/run-pass/used_underscore_binding_macro.rs b/tests/run-pass/used_underscore_binding_macro.rs index 73f48a96e77..b700ab90a68 100644 --- a/tests/run-pass/used_underscore_binding_macro.rs +++ b/tests/run-pass/used_underscore_binding_macro.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::useless_attribute)] //issue #2910 diff --git a/tests/run-pass/whitelist/conf_whitelisted.rs b/tests/run-pass/whitelist/conf_whitelisted.rs index f328e4d9d04..168f09a095a 100644 --- a/tests/run-pass/whitelist/conf_whitelisted.rs +++ b/tests/run-pass/whitelist/conf_whitelisted.rs @@ -1 +1,11 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() {} diff --git a/tests/ui-toml/bad_toml/conf_bad_toml.rs b/tests/ui-toml/bad_toml/conf_bad_toml.rs index 325688ac7da..10c0f0004e4 100644 --- a/tests/ui-toml/bad_toml/conf_bad_toml.rs +++ b/tests/ui-toml/bad_toml/conf_bad_toml.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern: error reading Clippy's configuration file diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.rs b/tests/ui-toml/bad_toml_type/conf_bad_type.rs index f97f5802b13..021a839d9ef 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.rs +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs index fe533f521d0..4f0cd1659f7 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr index 4229b711b0d..dd414657c28 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr +++ b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr @@ -1,45 +1,45 @@ error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 - | -9 | fn test(toto: ()) {} - | ^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` + --> $DIR/conf_french_blacklisted_name.rs:19:9 + | +19 | fn test(toto: ()) {} + | ^^^^ + | + = note: `-D clippy::blacklisted-name` implied by `-D warnings` error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:12:9 + --> $DIR/conf_french_blacklisted_name.rs:22:9 | -12 | let toto = 42; +22 | let toto = 42; | ^^^^ error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:13:9 + --> $DIR/conf_french_blacklisted_name.rs:23:9 | -13 | let tata = 42; +23 | let tata = 42; | ^^^^ error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:14:9 + --> $DIR/conf_french_blacklisted_name.rs:24:9 | -14 | let titi = 42; +24 | let titi = 42; | ^^^^ error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:20:10 + --> $DIR/conf_french_blacklisted_name.rs:30:10 | -20 | (toto, Some(tata), titi @ Some(_)) => (), +30 | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:20:21 + --> $DIR/conf_french_blacklisted_name.rs:30:21 | -20 | (toto, Some(tata), titi @ Some(_)) => (), +30 | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:20:28 + --> $DIR/conf_french_blacklisted_name.rs:30:28 | -20 | (toto, Some(tata), titi @ Some(_)) => (), +30 | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index 074ca064ab5..081dbf9b060 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::many_single_char_names)] diff --git a/tests/ui-toml/toml_trivially_copy/test.stderr b/tests/ui-toml/toml_trivially_copy/test.stderr index cf2f15a68e6..ad3ca831fd7 100644 --- a/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/tests/ui-toml/toml_trivially_copy/test.stderr @@ -1,15 +1,15 @@ error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/test.rs:13:11 + --> $DIR/test.rs:23:11 | -13 | fn bad(x: &u16, y: &Foo) { +23 | fn bad(x: &u16, y: &Foo) { | ^^^^ help: consider passing by value instead: `u16` | = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/test.rs:13:20 + --> $DIR/test.rs:23:20 | -13 | fn bad(x: &u16, y: &Foo) { +23 | fn bad(x: &u16, y: &Foo) { | ^^^^ help: consider passing by value instead: `Foo` error: aborting due to 2 previous errors diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index bfa804558bb..60e8e4fc29a 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // error-pattern: error reading Clippy's configuration file: unknown key `foobar` diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index d08c8008ec9..a88e57a5c43 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr index 2e5ebec7573..6c32b309aa5 100644 --- a/tests/ui/absurd-extreme-comparisons.stderr +++ b/tests/ui/absurd-extreme-comparisons.stderr @@ -1,144 +1,144 @@ error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:10:5 + --> $DIR/absurd-extreme-comparisons.rs:20:5 | -10 | u <= 0; +20 | u <= 0; | ^^^^^^ | = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings` = help: because 0 is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == 0 instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:11:5 + --> $DIR/absurd-extreme-comparisons.rs:21:5 | -11 | u <= Z; +21 | u <= Z; | ^^^^^^ | = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == Z instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:12:5 + --> $DIR/absurd-extreme-comparisons.rs:22:5 | -12 | u < Z; +22 | u < Z; | ^^^^^ | = help: because Z is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:13:5 + --> $DIR/absurd-extreme-comparisons.rs:23:5 | -13 | Z >= u; +23 | Z >= u; | ^^^^^^ | = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using Z == u instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:14:5 + --> $DIR/absurd-extreme-comparisons.rs:24:5 | -14 | Z > u; +24 | Z > u; | ^^^^^ | = help: because Z is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:15:5 + --> $DIR/absurd-extreme-comparisons.rs:25:5 | -15 | u > std::u32::MAX; +25 | u > std::u32::MAX; | ^^^^^^^^^^^^^^^^^ | = help: because std::u32::MAX is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:16:5 + --> $DIR/absurd-extreme-comparisons.rs:26:5 | -16 | u >= std::u32::MAX; +26 | u >= std::u32::MAX; | ^^^^^^^^^^^^^^^^^^ | = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using u == std::u32::MAX instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:17:5 + --> $DIR/absurd-extreme-comparisons.rs:27:5 | -17 | std::u32::MAX < u; +27 | std::u32::MAX < u; | ^^^^^^^^^^^^^^^^^ | = help: because std::u32::MAX is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:18:5 + --> $DIR/absurd-extreme-comparisons.rs:28:5 | -18 | std::u32::MAX <= u; +28 | std::u32::MAX <= u; | ^^^^^^^^^^^^^^^^^^ | = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using std::u32::MAX == u instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:19:5 + --> $DIR/absurd-extreme-comparisons.rs:29:5 | -19 | 1-1 > u; +29 | 1-1 > u; | ^^^^^^^ | = help: because 1-1 is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:20:5 + --> $DIR/absurd-extreme-comparisons.rs:30:5 | -20 | u >= !0; +30 | u >= !0; | ^^^^^^^ | = 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 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:21:5 + --> $DIR/absurd-extreme-comparisons.rs:31:5 | -21 | u <= 12 - 2*6; +31 | u <= 12 - 2*6; | ^^^^^^^^^^^^^ | = 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 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:23:5 + --> $DIR/absurd-extreme-comparisons.rs:33:5 | -23 | i < -127 - 1; +33 | i < -127 - 1; | ^^^^^^^^^^^^ | = help: because -127 - 1 is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:24:5 + --> $DIR/absurd-extreme-comparisons.rs:34:5 | -24 | std::i8::MAX >= i; +34 | std::i8::MAX >= i; | ^^^^^^^^^^^^^^^^^ | = help: because std::i8::MAX is the maximum value for this type, this comparison is always true error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:25:5 + --> $DIR/absurd-extreme-comparisons.rs:35:5 | -25 | 3-7 < std::i32::MIN; +35 | 3-7 < std::i32::MIN; | ^^^^^^^^^^^^^^^^^^^ | = help: because std::i32::MIN is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:27:5 + --> $DIR/absurd-extreme-comparisons.rs:37:5 | -27 | b >= true; +37 | b >= true; | ^^^^^^^^^ | = help: because true is the maximum value for this type, the case where the two sides are not equal never occurs, consider using b == true instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:28:5 + --> $DIR/absurd-extreme-comparisons.rs:38:5 | -28 | false > b; +38 | false > b; | ^^^^^^^^^ | = help: because false is the minimum value for this type, this comparison is always false error: <-comparison of unit values detected. This will always be false - --> $DIR/absurd-extreme-comparisons.rs:31:5 + --> $DIR/absurd-extreme-comparisons.rs:41:5 | -31 | () < {}; +41 | () < {}; | ^^^^^^^ | = note: #[deny(clippy::unit_cmp)] on by default diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index 46ca2fbfb57..ea023b8a7a2 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr index 3ff016b9c40..a765ffb64de 100644 --- a/tests/ui/approx_const.stderr +++ b/tests/ui/approx_const.stderr @@ -1,117 +1,117 @@ error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly - --> $DIR/approx_const.rs:7:16 - | -7 | let my_e = 2.7182; - | ^^^^^^ - | - = note: `-D clippy::approx-constant` implied by `-D warnings` + --> $DIR/approx_const.rs:17:16 + | +17 | let my_e = 2.7182; + | ^^^^^^ + | + = note: `-D clippy::approx-constant` implied by `-D warnings` error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly - --> $DIR/approx_const.rs:8:20 - | -8 | let almost_e = 2.718; - | ^^^^^ + --> $DIR/approx_const.rs:18:20 + | +18 | let almost_e = 2.718; + | ^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found. Consider using it directly - --> $DIR/approx_const.rs:11:24 + --> $DIR/approx_const.rs:21:24 | -11 | let my_1_frac_pi = 0.3183; +21 | let my_1_frac_pi = 0.3183; | ^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:14:28 + --> $DIR/approx_const.rs:24:28 | -14 | let my_frac_1_sqrt_2 = 0.70710678; +24 | let my_frac_1_sqrt_2 = 0.70710678; | ^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:15:32 + --> $DIR/approx_const.rs:25:32 | -15 | let almost_frac_1_sqrt_2 = 0.70711; +25 | let almost_frac_1_sqrt_2 = 0.70711; | ^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found. Consider using it directly - --> $DIR/approx_const.rs:18:24 + --> $DIR/approx_const.rs:28:24 | -18 | let my_frac_2_pi = 0.63661977; +28 | let my_frac_2_pi = 0.63661977; | ^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found. Consider using it directly - --> $DIR/approx_const.rs:21:27 + --> $DIR/approx_const.rs:31:27 | -21 | let my_frac_2_sq_pi = 1.128379; +31 | let my_frac_2_sq_pi = 1.128379; | ^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found. Consider using it directly - --> $DIR/approx_const.rs:24:24 + --> $DIR/approx_const.rs:34:24 | -24 | let my_frac_pi_2 = 1.57079632679; +34 | let my_frac_pi_2 = 1.57079632679; | ^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found. Consider using it directly - --> $DIR/approx_const.rs:27:24 + --> $DIR/approx_const.rs:37:24 | -27 | let my_frac_pi_3 = 1.04719755119; +37 | let my_frac_pi_3 = 1.04719755119; | ^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found. Consider using it directly - --> $DIR/approx_const.rs:30:24 + --> $DIR/approx_const.rs:40:24 | -30 | let my_frac_pi_4 = 0.785398163397; +40 | let my_frac_pi_4 = 0.785398163397; | ^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found. Consider using it directly - --> $DIR/approx_const.rs:33:24 + --> $DIR/approx_const.rs:43:24 | -33 | let my_frac_pi_6 = 0.523598775598; +43 | let my_frac_pi_6 = 0.523598775598; | ^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found. Consider using it directly - --> $DIR/approx_const.rs:36:24 + --> $DIR/approx_const.rs:46:24 | -36 | let my_frac_pi_8 = 0.3926990816987; +46 | let my_frac_pi_8 = 0.3926990816987; | ^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LN_10` found. Consider using it directly - --> $DIR/approx_const.rs:39:20 + --> $DIR/approx_const.rs:49:20 | -39 | let my_ln_10 = 2.302585092994046; +49 | let my_ln_10 = 2.302585092994046; | ^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LN_2` found. Consider using it directly - --> $DIR/approx_const.rs:42:19 + --> $DIR/approx_const.rs:52:19 | -42 | let my_ln_2 = 0.6931471805599453; +52 | let my_ln_2 = 0.6931471805599453; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LOG10_E` found. Consider using it directly - --> $DIR/approx_const.rs:45:22 + --> $DIR/approx_const.rs:55:22 | -45 | let my_log10_e = 0.4342944819032518; +55 | let my_log10_e = 0.4342944819032518; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LOG2_E` found. Consider using it directly - --> $DIR/approx_const.rs:48:21 + --> $DIR/approx_const.rs:58:21 | -48 | let my_log2_e = 1.4426950408889634; +58 | let my_log2_e = 1.4426950408889634; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly - --> $DIR/approx_const.rs:51:17 + --> $DIR/approx_const.rs:61:17 | -51 | let my_pi = 3.1415; +61 | let my_pi = 3.1415; | ^^^^^^ error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly - --> $DIR/approx_const.rs:52:21 + --> $DIR/approx_const.rs:62:21 | -52 | let almost_pi = 3.14; +62 | let almost_pi = 3.14; | ^^^^ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:55:18 + --> $DIR/approx_const.rs:65:18 | -55 | let my_sq2 = 1.4142; +65 | let my_sq2 = 1.4142; | ^^^^^^ error: aborting due to 19 previous errors diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index e7aa9a18b8a..a5bf8c9280e 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr index ee7a594fa15..5e6021403e9 100644 --- a/tests/ui/arithmetic.stderr +++ b/tests/ui/arithmetic.stderr @@ -1,72 +1,72 @@ error: integer arithmetic detected - --> $DIR/arithmetic.rs:8:5 - | -8 | 1 + i; - | ^^^^^ - | - = note: `-D clippy::integer-arithmetic` implied by `-D warnings` + --> $DIR/arithmetic.rs:18:5 + | +18 | 1 + i; + | ^^^^^ + | + = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/arithmetic.rs:9:5 - | -9 | i * 2; - | ^^^^^ + --> $DIR/arithmetic.rs:19:5 + | +19 | i * 2; + | ^^^^^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:10:5 + --> $DIR/arithmetic.rs:20:5 | -10 | / 1 % -11 | | i / 2; // no error, this is part of the expression in the preceding line +20 | / 1 % +21 | | i / 2; // no error, this is part of the expression in the preceding line | |_________^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:12:5 + --> $DIR/arithmetic.rs:22:5 | -12 | i - 2 + 2 - i; +22 | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:13:5 + --> $DIR/arithmetic.rs:23:5 | -13 | -i; +23 | -i; | ^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:23:5 + --> $DIR/arithmetic.rs:33:5 | -23 | f * 2.0; +33 | f * 2.0; | ^^^^^^^ | = note: `-D clippy::float-arithmetic` implied by `-D warnings` error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:25:5 + --> $DIR/arithmetic.rs:35:5 | -25 | 1.0 + f; +35 | 1.0 + f; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:26:5 + --> $DIR/arithmetic.rs:36:5 | -26 | f * 2.0; +36 | f * 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:27:5 + --> $DIR/arithmetic.rs:37:5 | -27 | f / 2.0; +37 | f / 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:28:5 + --> $DIR/arithmetic.rs:38:5 | -28 | f - 2.0 * 4.2; +38 | f - 2.0 * 4.2; | ^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:29:5 + --> $DIR/arithmetic.rs:39:5 | -29 | -f; +39 | -f; | ^^ error: aborting due to 11 previous errors diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 765dbb67990..5d791ba8f54 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[allow(dead_code, unused_assignments)] diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index fe7ccff7805..20ed51334ab 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,57 +1,57 @@ error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:7:5 - | -7 | a = a + 1; - | ^^^^^^^^^ help: replace it with: `a += 1` - | - = note: `-D clippy::assign-op-pattern` implied by `-D warnings` + --> $DIR/assign_ops.rs:17:5 + | +17 | a = a + 1; + | ^^^^^^^^^ help: replace it with: `a += 1` + | + = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:8:5 - | -8 | a = 1 + a; - | ^^^^^^^^^ help: replace it with: `a += 1` + --> $DIR/assign_ops.rs:18:5 + | +18 | a = 1 + a; + | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:9:5 - | -9 | a = a - 1; - | ^^^^^^^^^ help: replace it with: `a -= 1` + --> $DIR/assign_ops.rs:19:5 + | +19 | a = a - 1; + | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:10:5 + --> $DIR/assign_ops.rs:20:5 | -10 | a = a * 99; +20 | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:11:5 + --> $DIR/assign_ops.rs:21:5 | -11 | a = 42 * a; +21 | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:12:5 + --> $DIR/assign_ops.rs:22:5 | -12 | a = a / 2; +22 | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:13:5 + --> $DIR/assign_ops.rs:23:5 | -13 | a = a % 5; +23 | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:14:5 + --> $DIR/assign_ops.rs:24:5 | -14 | a = a & 1; +24 | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:20:5 + --> $DIR/assign_ops.rs:30:5 | -20 | s = s + "bla"; +30 | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: aborting due to 9 previous errors diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index c3f5083bb1f..9eef898c9a7 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 93528e50577..8e44fc13bb7 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -1,129 +1,129 @@ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:8:5 - | -8 | a += a + 1; - | ^^^^^^^^^^ - | - = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings` + --> $DIR/assign_ops2.rs:18:5 + | +18 | a += a + 1; + | ^^^^^^^^^^ + | + = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings` help: Did you mean a = a + 1 or a = a + a + 1? Consider replacing it with - | -8 | a += 1; - | ^^^^^^ + | +18 | a += 1; + | ^^^^^^ help: or - | -8 | a = a + a + 1; - | ^^^^^^^^^^^^^ + | +18 | a = a + a + 1; + | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:9:5 - | -9 | a += 1 + a; - | ^^^^^^^^^^ + --> $DIR/assign_ops2.rs:19:5 + | +19 | a += 1 + a; + | ^^^^^^^^^^ help: Did you mean a = a + 1 or a = a + 1 + a? Consider replacing it with - | -9 | a += 1; - | ^^^^^^ + | +19 | a += 1; + | ^^^^^^ help: or - | -9 | a = a + 1 + a; - | ^^^^^^^^^^^^^ + | +19 | a = a + 1 + a; + | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:10:5 + --> $DIR/assign_ops2.rs:20:5 | -10 | a -= a - 1; +20 | a -= a - 1; | ^^^^^^^^^^ help: Did you mean a = a - 1 or a = a - (a - 1)? Consider replacing it with | -10 | a -= 1; +20 | a -= 1; | ^^^^^^ help: or | -10 | a = a - (a - 1); +20 | a = a - (a - 1); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:11:5 + --> $DIR/assign_ops2.rs:21:5 | -11 | a *= a * 99; +21 | a *= a * 99; | ^^^^^^^^^^^ help: Did you mean a = a * 99 or a = a * a * 99? Consider replacing it with | -11 | a *= 99; +21 | a *= 99; | ^^^^^^^ help: or | -11 | a = a * a * 99; +21 | a = a * a * 99; | ^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:12:5 + --> $DIR/assign_ops2.rs:22:5 | -12 | a *= 42 * a; +22 | a *= 42 * a; | ^^^^^^^^^^^ help: Did you mean a = a * 42 or a = a * 42 * a? Consider replacing it with | -12 | a *= 42; +22 | a *= 42; | ^^^^^^^ help: or | -12 | a = a * 42 * a; +22 | a = a * 42 * a; | ^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:13:5 + --> $DIR/assign_ops2.rs:23:5 | -13 | a /= a / 2; +23 | a /= a / 2; | ^^^^^^^^^^ help: Did you mean a = a / 2 or a = a / (a / 2)? Consider replacing it with | -13 | a /= 2; +23 | a /= 2; | ^^^^^^ help: or | -13 | a = a / (a / 2); +23 | a = a / (a / 2); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:14:5 + --> $DIR/assign_ops2.rs:24:5 | -14 | a %= a % 5; +24 | a %= a % 5; | ^^^^^^^^^^ help: Did you mean a = a % 5 or a = a % (a % 5)? Consider replacing it with | -14 | a %= 5; +24 | a %= 5; | ^^^^^^ help: or | -14 | a = a % (a % 5); +24 | a = a % (a % 5); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:15:5 + --> $DIR/assign_ops2.rs:25:5 | -15 | a &= a & 1; +25 | a &= a & 1; | ^^^^^^^^^^ help: Did you mean a = a & 1 or a = a & a & 1? Consider replacing it with | -15 | a &= 1; +25 | a &= 1; | ^^^^^^ help: or | -15 | a = a & a & 1; +25 | a = a & a & 1; | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:16:5 + --> $DIR/assign_ops2.rs:26:5 | -16 | a *= a * a; +26 | a *= a * a; | ^^^^^^^^^^ help: Did you mean a = a * a or a = a * a * a? Consider replacing it with | -16 | a *= a; +26 | a *= a; | ^^^^^^ help: or | -16 | a = a * a * a; +26 | a = a * a * a; | ^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index b1f0ca640aa..9af9c0e619a 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index 6b6ecd675b3..a361d0968f5 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -1,23 +1,23 @@ error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> $DIR/attrs.rs:6:1 - | -6 | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::inline-always` implied by `-D warnings` + --> $DIR/attrs.rs:16:1 + | +16 | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::inline-always` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:27:14 + --> $DIR/attrs.rs:37:14 | -27 | #[deprecated(since = "forever")] +37 | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::deprecated-semver` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:30:14 + --> $DIR/attrs.rs:40:14 | -30 | #[deprecated(since = "1")] +40 | #[deprecated(since = "1")] | ^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/author.rs b/tests/ui/author.rs index e8a04bb7b13..f151d50f2f2 100644 --- a/tests/ui/author.rs +++ b/tests/ui/author.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { diff --git a/tests/ui/author/call.rs b/tests/ui/author/call.rs old mode 100755 new mode 100644 index c3e9846e21c..3dcf8da5c72 --- a/tests/ui/author/call.rs +++ b/tests/ui/author/call.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { diff --git a/tests/ui/author/for_loop.rs b/tests/ui/author/for_loop.rs index b3dec876535..a27322b3205 100644 --- a/tests/ui/author/for_loop.rs +++ b/tests/ui/author/for_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(stmt_expr_attributes)] fn main() { diff --git a/tests/ui/author/matches.rs b/tests/ui/author/matches.rs index e6bf229103f..956404f3490 100644 --- a/tests/ui/author/matches.rs +++ b/tests/ui/author/matches.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_attributes)] fn main() { diff --git a/tests/ui/author/matches.stderr b/tests/ui/author/matches.stderr index 46618fe4065..d78a173316b 100644 --- a/tests/ui/author/matches.stderr +++ b/tests/ui/author/matches.stderr @@ -1,15 +1,15 @@ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/matches.rs:9:13 - | -9 | x - | ^ - | - = note: `-D clippy::let-and-return` implied by `-D warnings` + --> $DIR/matches.rs:19:13 + | +19 | x + | ^ + | + = note: `-D clippy::let-and-return` implied by `-D warnings` note: this expression can be directly returned - --> $DIR/matches.rs:8:21 - | -8 | let x = 3; - | ^ + --> $DIR/matches.rs:18:21 + | +18 | let x = 3; + | ^ error: aborting due to previous error diff --git a/tests/ui/bit_masks.rs b/tests/ui/bit_masks.rs index 4111f344b66..4110f6ced85 100644 --- a/tests/ui/bit_masks.rs +++ b/tests/ui/bit_masks.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index dcf3f241b4b..f0f450fc169 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -1,109 +1,109 @@ error: &-masking with zero - --> $DIR/bit_masks.rs:12:5 + --> $DIR/bit_masks.rs:22:5 | -12 | x & 0 == 0; +22 | x & 0 == 0; | ^^^^^^^^^^ | = note: `-D clippy::bad-bit-mask` implied by `-D warnings` error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/bit_masks.rs:12:5 + --> $DIR/bit_masks.rs:22:5 | -12 | x & 0 == 0; +22 | x & 0 == 0; | ^^^^^ | = note: #[deny(clippy::erasing_op)] on by default error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> $DIR/bit_masks.rs:15:5 + --> $DIR/bit_masks.rs:25:5 | -15 | x & 2 == 1; +25 | x & 2 == 1; | ^^^^^^^^^^ error: incompatible bit mask: `_ | 3` can never be equal to `2` - --> $DIR/bit_masks.rs:19:5 + --> $DIR/bit_masks.rs:29:5 | -19 | x | 3 == 2; +29 | x | 3 == 2; | ^^^^^^^^^^ error: incompatible bit mask: `_ & 1` will never be higher than `1` - --> $DIR/bit_masks.rs:21:5 + --> $DIR/bit_masks.rs:31:5 | -21 | x & 1 > 1; +31 | x & 1 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> $DIR/bit_masks.rs:25:5 + --> $DIR/bit_masks.rs:35:5 | -25 | x | 2 > 1; +35 | x | 2 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ & 7` can never be equal to `8` - --> $DIR/bit_masks.rs:32:5 + --> $DIR/bit_masks.rs:42:5 | -32 | x & THREE_BITS == 8; +42 | x & THREE_BITS == 8; | ^^^^^^^^^^^^^^^^^^^ error: incompatible bit mask: `_ | 7` will never be lower than `7` - --> $DIR/bit_masks.rs:33:5 + --> $DIR/bit_masks.rs:43:5 | -33 | x | EVEN_MORE_REDIRECTION < 7; +43 | x | EVEN_MORE_REDIRECTION < 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: &-masking with zero - --> $DIR/bit_masks.rs:35:5 + --> $DIR/bit_masks.rs:45:5 | -35 | 0 & x == 0; +45 | 0 & x == 0; | ^^^^^^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/bit_masks.rs:35:5 + --> $DIR/bit_masks.rs:45:5 | -35 | 0 & x == 0; +45 | 0 & x == 0; | ^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> $DIR/bit_masks.rs:39:5 + --> $DIR/bit_masks.rs:49:5 | -39 | 1 < 2 | x; +49 | 1 < 2 | x; | ^^^^^^^^^ error: incompatible bit mask: `_ | 3` can never be equal to `2` - --> $DIR/bit_masks.rs:40:5 + --> $DIR/bit_masks.rs:50:5 | -40 | 2 == 3 | x; +50 | 2 == 3 | x; | ^^^^^^^^^^ error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> $DIR/bit_masks.rs:41:5 + --> $DIR/bit_masks.rs:51:5 | -41 | 1 == x & 2; +51 | 1 == x & 2; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> $DIR/bit_masks.rs:52:5 + --> $DIR/bit_masks.rs:62:5 | -52 | x | 1 > 3; +62 | x | 1 > 3; | ^^^^^^^^^ | = note: `-D clippy::ineffective-bit-mask` implied by `-D warnings` error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly - --> $DIR/bit_masks.rs:53:5 + --> $DIR/bit_masks.rs:63:5 | -53 | x | 1 < 4; +63 | x | 1 < 4; | ^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> $DIR/bit_masks.rs:54:5 + --> $DIR/bit_masks.rs:64:5 | -54 | x | 1 <= 3; +64 | x | 1 <= 3; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared directly - --> $DIR/bit_masks.rs:55:5 + --> $DIR/bit_masks.rs:65:5 | -55 | x | 1 >= 8; +65 | x | 1 >= 8; | ^^^^^^^^^^ error: aborting due to 17 previous errors diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index 4e2e5388c98..be58a8fb601 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr index 472401d5ed6..1e253eba140 100644 --- a/tests/ui/blacklisted_name.stderr +++ b/tests/ui/blacklisted_name.stderr @@ -1,87 +1,87 @@ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:7:9 - | -7 | fn test(foo: ()) {} - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` + --> $DIR/blacklisted_name.rs:17:9 + | +17 | fn test(foo: ()) {} + | ^^^ + | + = note: `-D clippy::blacklisted-name` implied by `-D warnings` error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:10:9 + --> $DIR/blacklisted_name.rs:20:9 | -10 | let foo = 42; +20 | let foo = 42; | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:11:9 + --> $DIR/blacklisted_name.rs:21:9 | -11 | let bar = 42; +21 | let bar = 42; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:12:9 + --> $DIR/blacklisted_name.rs:22:9 | -12 | let baz = 42; +22 | let baz = 42; | ^^^ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:18:10 + --> $DIR/blacklisted_name.rs:28:10 | -18 | (foo, Some(bar), baz @ Some(_)) => (), +28 | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:18:20 + --> $DIR/blacklisted_name.rs:28:20 | -18 | (foo, Some(bar), baz @ Some(_)) => (), +28 | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:18:26 + --> $DIR/blacklisted_name.rs:28:26 | -18 | (foo, Some(bar), baz @ Some(_)) => (), +28 | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:23:19 + --> $DIR/blacklisted_name.rs:33:19 | -23 | fn issue_1647(mut foo: u8) { +33 | fn issue_1647(mut foo: u8) { | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:24:13 + --> $DIR/blacklisted_name.rs:34:13 | -24 | let mut bar = 0; +34 | let mut bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:25:21 + --> $DIR/blacklisted_name.rs:35:21 | -25 | if let Some(mut baz) = Some(42) {} +35 | if let Some(mut baz) = Some(42) {} | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:29:13 + --> $DIR/blacklisted_name.rs:39:13 | -29 | let ref bar = 0; +39 | let ref bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:30:21 + --> $DIR/blacklisted_name.rs:40:21 | -30 | if let Some(ref baz) = Some(42) {} +40 | if let Some(ref baz) = Some(42) {} | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:34:17 + --> $DIR/blacklisted_name.rs:44:17 | -34 | let ref mut bar = 0; +44 | let ref mut bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:35:25 + --> $DIR/blacklisted_name.rs:45:25 | -35 | if let Some(ref mut baz) = Some(42) {} +45 | if let Some(ref mut baz) = Some(42) {} | ^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index dd0e5503437..67bd778acaa 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/block_in_if_condition.stderr b/tests/ui/block_in_if_condition.stderr index 41f1e9c1681..b0036d1ee23 100644 --- a/tests/ui/block_in_if_condition.stderr +++ b/tests/ui/block_in_if_condition.stderr @@ -1,11 +1,11 @@ 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' - --> $DIR/block_in_if_condition.rs:30:8 + --> $DIR/block_in_if_condition.rs:40:8 | -30 | if { +40 | if { | ________^ -31 | | let x = 3; -32 | | x == 3 -33 | | } { +41 | | let x = 3; +42 | | x == 3 +43 | | } { | |_____^ | = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings` @@ -19,9 +19,9 @@ error: in an 'if' condition, avoid complex blocks or closures with blocks; inste } ... error: omit braces around single expression condition - --> $DIR/block_in_if_condition.rs:41:8 + --> $DIR/block_in_if_condition.rs:51:8 | -41 | if { true } { +51 | if { true } { | ^^^^^^^^ | = note: `-D clippy::block-in-if-condition-expr` implied by `-D warnings` @@ -31,21 +31,21 @@ error: omit braces around single expression condition } ... 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' - --> $DIR/block_in_if_condition.rs:58:49 + --> $DIR/block_in_if_condition.rs:68:49 | -58 | if v == 3 && sky == "blue" && predicate(|x| { let target = 3; x == target }, v) { +68 | 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' - --> $DIR/block_in_if_condition.rs:61:22 + --> $DIR/block_in_if_condition.rs:71:22 | -61 | if predicate(|x| { let target = 3; x == target }, v) { +71 | if predicate(|x| { let target = 3; x == target }, v) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/block_in_if_condition.rs:67:8 + --> $DIR/block_in_if_condition.rs:77:8 | -67 | if true && x == 3 { +77 | if true && x == 3 { | ^^^^^^^^^^^^^^ help: try: `x == 3` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 144f9f4c631..1d9756bc39b 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index 2fcde94367a..f1bb50fae9e 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -1,27 +1,27 @@ error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:7:8 - | -7 | if x == true { "yes" } else { "no" }; - | ^^^^^^^^^ help: try simplifying it as shown: `x` - | - = note: `-D clippy::bool-comparison` implied by `-D warnings` + --> $DIR/bool_comparison.rs:17:8 + | +17 | if x == true { "yes" } else { "no" }; + | ^^^^^^^^^ help: try simplifying it as shown: `x` + | + = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:8:8 - | -8 | if x == false { "yes" } else { "no" }; - | ^^^^^^^^^^ help: try simplifying it as shown: `!x` + --> $DIR/bool_comparison.rs:18:8 + | +18 | if x == false { "yes" } else { "no" }; + | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:9:8 - | -9 | if true == x { "yes" } else { "no" }; - | ^^^^^^^^^ help: try simplifying it as shown: `x` + --> $DIR/bool_comparison.rs:19:8 + | +19 | if true == x { "yes" } else { "no" }; + | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:10:8 + --> $DIR/bool_comparison.rs:20:8 | -10 | if false == x { "yes" } else { "no" }; +20 | if false == x { "yes" } else { "no" }; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: aborting due to 4 previous errors diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index eaa686c9a90..556344c77a2 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::nonminimal_bool, clippy::logic_bug)] diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index 45e371025ef..01f821f511f 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -1,202 +1,202 @@ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:12:13 + --> $DIR/booleans.rs:22:13 | -12 | let _ = a && b || a; +22 | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | = note: `-D clippy::logic-bug` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:12:18 + --> $DIR/booleans.rs:22:18 | -12 | let _ = a && b || a; +22 | let _ = a && b || a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:14:13 + --> $DIR/booleans.rs:24:13 | -14 | let _ = !true; +24 | let _ = !true; | ^^^^^ help: try: `false` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/booleans.rs:15:13 + --> $DIR/booleans.rs:25:13 | -15 | let _ = !false; +25 | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/booleans.rs:16:13 + --> $DIR/booleans.rs:26:13 | -16 | let _ = !!a; +26 | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:17:13 + --> $DIR/booleans.rs:27:13 | -17 | let _ = false && a; +27 | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:17:22 + --> $DIR/booleans.rs:27:22 | -17 | let _ = false && a; +27 | let _ = false && a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:18:13 + --> $DIR/booleans.rs:28:13 | -18 | let _ = false || a; +28 | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/booleans.rs:23:13 + --> $DIR/booleans.rs:33:13 | -23 | let _ = !(!a && b); +33 | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `!b || a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:33:13 + --> $DIR/booleans.rs:43:13 | -33 | let _ = a == b && a != b; +43 | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:33:13 + --> $DIR/booleans.rs:43:13 | -33 | let _ = a == b && a != b; +43 | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:34:13 + --> $DIR/booleans.rs:44:13 | -34 | let _ = a == b && c == 5 && a == b; +44 | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try | -34 | let _ = a == b && c == 5; +44 | let _ = a == b && c == 5; | ^^^^^^^^^^^^^^^^ -34 | let _ = !(c != 5 || a != b); +44 | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:35:13 + --> $DIR/booleans.rs:45:13 | -35 | let _ = a == b && c == 5 && b == a; +45 | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try | -35 | let _ = a == b && c == 5; +45 | let _ = a == b && c == 5; | ^^^^^^^^^^^^^^^^ -35 | let _ = !(c != 5 || a != b); +45 | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:36:13 + --> $DIR/booleans.rs:46:13 | -36 | let _ = a < b && a >= b; +46 | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:36:13 + --> $DIR/booleans.rs:46:13 | -36 | let _ = a < b && a >= b; +46 | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:37:13 + --> $DIR/booleans.rs:47:13 | -37 | let _ = a > b && a <= b; +47 | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:37:13 + --> $DIR/booleans.rs:47:13 | -37 | let _ = a > b && a <= b; +47 | let _ = a > b && a <= b; | ^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:39:13 + --> $DIR/booleans.rs:49:13 | -39 | let _ = a != b || !(a != b || c == d); +49 | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try | -39 | let _ = c != d || a != b; +49 | let _ = c != d || a != b; | ^^^^^^^^^^^^^^^^ -39 | let _ = !(a == b && c == d); +49 | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:47:13 + --> $DIR/booleans.rs:57:13 | -47 | let _ = !a.is_some(); +57 | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:49:13 + --> $DIR/booleans.rs:59:13 | -49 | let _ = !a.is_none(); +59 | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:51:13 + --> $DIR/booleans.rs:61:13 | -51 | let _ = !b.is_err(); +61 | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:53:13 + --> $DIR/booleans.rs:63:13 | -53 | let _ = !b.is_ok(); +63 | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:55:13 + --> $DIR/booleans.rs:65:13 | -55 | let _ = !(a.is_some() && !c); +65 | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:56:13 + --> $DIR/booleans.rs:66:13 | -56 | let _ = !(!c ^ c) || !a.is_some(); +66 | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!(!c ^ c) || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:57:13 + --> $DIR/booleans.rs:67:13 | -57 | let _ = (!c ^ c) || !a.is_some(); +67 | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!c ^ c) || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:58:13 + --> $DIR/booleans.rs:68:13 | -58 | let _ = !c ^ c || !a.is_some(); +68 | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `!c ^ c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:110:8 + --> $DIR/booleans.rs:120:8 | -110 | if !res.is_ok() { } +120 | if !res.is_ok() { } | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:111:8 + --> $DIR/booleans.rs:121:8 | -111 | if !res.is_err() { } +121 | if !res.is_err() { } | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:114:8 + --> $DIR/booleans.rs:124:8 | -114 | if !res.is_some() { } +124 | if !res.is_some() { } | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:115:8 + --> $DIR/booleans.rs:125:8 | -115 | if !res.is_none() { } +125 | if !res.is_none() { } | ^^^^^^^^^^^^^^ help: try: `res.is_some()` error: aborting due to 25 previous errors diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 216dbebda67..7c668c33c83 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 1098c7785e2..7cc8eb8da40 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,31 +1,31 @@ error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:9:19 - | -9 | pub fn test1(foo: &mut Box<bool>) { - | ^^^^^^^^^^^^^^ help: try: `&mut bool` - | + --> $DIR/borrow_box.rs:19:19 + | +19 | pub fn test1(foo: &mut Box<bool>) { + | ^^^^^^^^^^^^^^ help: try: `&mut bool` + | note: lint level defined here - --> $DIR/borrow_box.rs:4:9 - | -4 | #![deny(clippy::borrowed_box)] - | ^^^^^^^^^^^^^^^^^^^^ + --> $DIR/borrow_box.rs:14:9 + | +14 | #![deny(clippy::borrowed_box)] + | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:14:14 + --> $DIR/borrow_box.rs:24:14 | -14 | let foo: &Box<bool>; +24 | let foo: &Box<bool>; | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:18:10 + --> $DIR/borrow_box.rs:28:10 | -18 | foo: &'a Box<bool> +28 | foo: &'a Box<bool> | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:22:17 + --> $DIR/borrow_box.rs:32:17 | -22 | fn test4(a: &Box<bool>); +32 | fn test4(a: &Box<bool>); | ^^^^^^^^^^ help: try: `&bool` error: aborting due to 4 previous errors diff --git a/tests/ui/box_vec.rs b/tests/ui/box_vec.rs index bc5e8361d8b..78174d2cd8f 100644 --- a/tests/ui/box_vec.rs +++ b/tests/ui/box_vec.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index b90bb5e2a4e..34be890b534 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -1,7 +1,7 @@ error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>` - --> $DIR/box_vec.rs:17:18 + --> $DIR/box_vec.rs:27:18 | -17 | pub fn test(foo: Box<Vec<bool>>) { +27 | pub fn test(foo: Box<Vec<bool>>) { | ^^^^^^^^^^^^^^ | = note: `-D clippy::box-vec` implied by `-D warnings` diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin-type-shadow.rs index 56892fc9483..a6d0f82a7d6 100644 --- a/tests/ui/builtin-type-shadow.rs +++ b/tests/ui/builtin-type-shadow.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::builtin_type_shadow)] diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr index 78924ebf9cf..11253715716 100644 --- a/tests/ui/builtin-type-shadow.stderr +++ b/tests/ui/builtin-type-shadow.stderr @@ -1,21 +1,21 @@ error: This generic shadows the built-in type `u32` - --> $DIR/builtin-type-shadow.rs:5:8 - | -5 | fn foo<u32>(a: u32) -> u32 { - | ^^^ - | - = note: `-D clippy::builtin-type-shadow` implied by `-D warnings` + --> $DIR/builtin-type-shadow.rs:15:8 + | +15 | fn foo<u32>(a: u32) -> u32 { + | ^^^ + | + = note: `-D clippy::builtin-type-shadow` implied by `-D warnings` error[E0308]: mismatched types - --> $DIR/builtin-type-shadow.rs:6:5 - | -5 | fn foo<u32>(a: u32) -> u32 { - | --- expected `u32` because of return type -6 | 42 - | ^^ expected type parameter, found integral variable - | - = note: expected type `u32` - found type `{integer}` + --> $DIR/builtin-type-shadow.rs:16:5 + | +15 | fn foo<u32>(a: u32) -> u32 { + | --- expected `u32` because of return type +16 | 42 + | ^^ expected type parameter, found integral variable + | + = note: expected type `u32` + found type `{integer}` error: aborting due to 2 previous errors diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 7211284e4a0..71a6e01219e 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/bytecount.stderr b/tests/ui/bytecount.stderr index 0564d6a0b60..c5c0ec7eda4 100644 --- a/tests/ui/bytecount.stderr +++ b/tests/ui/bytecount.stderr @@ -1,25 +1,25 @@ error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:8:13 - | -8 | let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)` - | + --> $DIR/bytecount.rs:18:13 + | +18 | let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)` + | note: lint level defined here - --> $DIR/bytecount.rs:4:8 - | -4 | #[deny(clippy::naive_bytecount)] - | ^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/bytecount.rs:14:8 + | +14 | #[deny(clippy::naive_bytecount)] + | ^^^^^^^^^^^^^^^^^^^^^^^ error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:10:13 + --> $DIR/bytecount.rs:20:13 | -10 | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count +20 | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count((&x[..]), 0)` error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:22:13 + --> $DIR/bytecount.rs:32:13 | -22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count +32 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)` error: aborting due to 3 previous errors diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 0668b16ff32..2fb865b12b8 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 2578c49893f..1f9ab5712f5 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,181 +1,181 @@ error: casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:8:5 - | -8 | 1i32 as f32; - | ^^^^^^^^^^^ - | - = note: `-D clippy::cast-precision-loss` implied by `-D warnings` + --> $DIR/cast.rs:18:5 + | +18 | 1i32 as f32; + | ^^^^^^^^^^^ + | + = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting i64 to f32 causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:9:5 - | -9 | 1i64 as f32; - | ^^^^^^^^^^^ + --> $DIR/cast.rs:19:5 + | +19 | 1i64 as f32; + | ^^^^^^^^^^^ error: casting i64 to f64 causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast.rs:10:5 + --> $DIR/cast.rs:20:5 | -10 | 1i64 as f64; +20 | 1i64 as f64; | ^^^^^^^^^^^ error: casting u32 to f32 causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:11:5 + --> $DIR/cast.rs:21:5 | -11 | 1u32 as f32; +21 | 1u32 as f32; | ^^^^^^^^^^^ error: casting u64 to f32 causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:12:5 + --> $DIR/cast.rs:22:5 | -12 | 1u64 as f32; +22 | 1u64 as f32; | ^^^^^^^^^^^ error: casting u64 to f64 causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast.rs:13:5 + --> $DIR/cast.rs:23:5 | -13 | 1u64 as f64; +23 | 1u64 as f64; | ^^^^^^^^^^^ error: casting f32 to i32 may truncate the value - --> $DIR/cast.rs:15:5 + --> $DIR/cast.rs:25:5 | -15 | 1f32 as i32; +25 | 1f32 as i32; | ^^^^^^^^^^^ | = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting f32 to u32 may truncate the value - --> $DIR/cast.rs:16:5 + --> $DIR/cast.rs:26:5 | -16 | 1f32 as u32; +26 | 1f32 as u32; | ^^^^^^^^^^^ error: casting f32 to u32 may lose the sign of the value - --> $DIR/cast.rs:16:5 + --> $DIR/cast.rs:26:5 | -16 | 1f32 as u32; +26 | 1f32 as u32; | ^^^^^^^^^^^ | = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting f64 to f32 may truncate the value - --> $DIR/cast.rs:17:5 + --> $DIR/cast.rs:27:5 | -17 | 1f64 as f32; +27 | 1f64 as f32; | ^^^^^^^^^^^ error: casting i32 to i8 may truncate the value - --> $DIR/cast.rs:18:5 + --> $DIR/cast.rs:28:5 | -18 | 1i32 as i8; +28 | 1i32 as i8; | ^^^^^^^^^^ error: casting i32 to u8 may lose the sign of the value - --> $DIR/cast.rs:19:5 + --> $DIR/cast.rs:29:5 | -19 | 1i32 as u8; +29 | 1i32 as u8; | ^^^^^^^^^^ error: casting i32 to u8 may truncate the value - --> $DIR/cast.rs:19:5 + --> $DIR/cast.rs:29:5 | -19 | 1i32 as u8; +29 | 1i32 as u8; | ^^^^^^^^^^ error: casting f64 to isize may truncate the value - --> $DIR/cast.rs:20:5 + --> $DIR/cast.rs:30:5 | -20 | 1f64 as isize; +30 | 1f64 as isize; | ^^^^^^^^^^^^^ error: casting f64 to usize may truncate the value - --> $DIR/cast.rs:21:5 + --> $DIR/cast.rs:31:5 | -21 | 1f64 as usize; +31 | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting f64 to usize may lose the sign of the value - --> $DIR/cast.rs:21:5 + --> $DIR/cast.rs:31:5 | -21 | 1f64 as usize; +31 | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting u8 to i8 may wrap around the value - --> $DIR/cast.rs:23:5 + --> $DIR/cast.rs:33:5 | -23 | 1u8 as i8; +33 | 1u8 as i8; | ^^^^^^^^^ | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting u16 to i16 may wrap around the value - --> $DIR/cast.rs:24:5 + --> $DIR/cast.rs:34:5 | -24 | 1u16 as i16; +34 | 1u16 as i16; | ^^^^^^^^^^^ error: casting u32 to i32 may wrap around the value - --> $DIR/cast.rs:25:5 + --> $DIR/cast.rs:35:5 | -25 | 1u32 as i32; +35 | 1u32 as i32; | ^^^^^^^^^^^ error: casting u64 to i64 may wrap around the value - --> $DIR/cast.rs:26:5 + --> $DIR/cast.rs:36:5 | -26 | 1u64 as i64; +36 | 1u64 as i64; | ^^^^^^^^^^^ error: casting usize to isize may wrap around the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:37:5 | -27 | 1usize as isize; +37 | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting f32 to f64 may become silently lossy if types change - --> $DIR/cast.rs:29:5 + --> $DIR/cast.rs:39:5 | -29 | 1.0f32 as f64; +39 | 1.0f32 as f64; | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting u8 to u16 may become silently lossy if types change - --> $DIR/cast.rs:31:5 + --> $DIR/cast.rs:41:5 | -31 | (1u8 + 1u8) as u16; +41 | (1u8 + 1u8) as u16; | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` error: casting i32 to u32 may lose the sign of the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:43:5 | -33 | 1i32 as u32; +43 | 1i32 as u32; | ^^^^^^^^^^^ error: casting isize to usize may lose the sign of the value - --> $DIR/cast.rs:34:5 + --> $DIR/cast.rs:44:5 | -34 | 1isize as usize; +44 | 1isize as usize; | ^^^^^^^^^^^^^^^ error: casting to the same type is unnecessary (`i32` -> `i32`) - --> $DIR/cast.rs:37:5 + --> $DIR/cast.rs:47:5 | -37 | 1i32 as i32; +47 | 1i32 as i32; | ^^^^^^^^^^^ | = note: `-D clippy::unnecessary-cast` implied by `-D warnings` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> $DIR/cast.rs:38:5 + --> $DIR/cast.rs:48:5 | -38 | 1f32 as f32; +48 | 1f32 as f32; | ^^^^^^^^^^^ error: casting to the same type is unnecessary (`bool` -> `bool`) - --> $DIR/cast.rs:39:5 + --> $DIR/cast.rs:49:5 | -39 | false as bool; +49 | false as bool; | ^^^^^^^^^^^^^ error: aborting due to 28 previous errors diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index 1f7606de649..b6e01d21288 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] //! Test casts for alignment issues diff --git a/tests/ui/cast_alignment.stderr b/tests/ui/cast_alignment.stderr index d03d727a89c..a4dd6038cab 100644 --- a/tests/ui/cast_alignment.stderr +++ b/tests/ui/cast_alignment.stderr @@ -1,15 +1,15 @@ error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) - --> $DIR/cast_alignment.rs:15:5 + --> $DIR/cast_alignment.rs:25:5 | -15 | (&1u8 as *const u8) as *const u16; +25 | (&1u8 as *const u8) as *const u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings` error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) - --> $DIR/cast_alignment.rs:16:5 + --> $DIR/cast_alignment.rs:26:5 | -16 | (&mut 1u8 as *mut u8) as *mut u16; +26 | (&mut 1u8 as *mut u8) as *mut u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index 437c4b67120..aa78a62f88b 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.stderr b/tests/ui/cast_lossless_float.stderr index 9025633a141..95b9bfb0262 100644 --- a/tests/ui/cast_lossless_float.stderr +++ b/tests/ui/cast_lossless_float.stderr @@ -1,63 +1,63 @@ error: casting i8 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:7:5 - | -7 | 1i8 as f32; - | ^^^^^^^^^^ help: try: `f32::from(1i8)` - | - = note: `-D clippy::cast-lossless` implied by `-D warnings` + --> $DIR/cast_lossless_float.rs:17:5 + | +17 | 1i8 as f32; + | ^^^^^^^^^^ help: try: `f32::from(1i8)` + | + = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting i8 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:8:5 - | -8 | 1i8 as f64; - | ^^^^^^^^^^ help: try: `f64::from(1i8)` + --> $DIR/cast_lossless_float.rs:18:5 + | +18 | 1i8 as f64; + | ^^^^^^^^^^ help: try: `f64::from(1i8)` error: casting u8 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:9:5 - | -9 | 1u8 as f32; - | ^^^^^^^^^^ help: try: `f32::from(1u8)` + --> $DIR/cast_lossless_float.rs:19:5 + | +19 | 1u8 as f32; + | ^^^^^^^^^^ help: try: `f32::from(1u8)` error: casting u8 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:10:5 + --> $DIR/cast_lossless_float.rs:20:5 | -10 | 1u8 as f64; +20 | 1u8 as f64; | ^^^^^^^^^^ help: try: `f64::from(1u8)` error: casting i16 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:11:5 + --> $DIR/cast_lossless_float.rs:21:5 | -11 | 1i16 as f32; +21 | 1i16 as f32; | ^^^^^^^^^^^ help: try: `f32::from(1i16)` error: casting i16 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:12:5 + --> $DIR/cast_lossless_float.rs:22:5 | -12 | 1i16 as f64; +22 | 1i16 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1i16)` error: casting u16 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:13:5 + --> $DIR/cast_lossless_float.rs:23:5 | -13 | 1u16 as f32; +23 | 1u16 as f32; | ^^^^^^^^^^^ help: try: `f32::from(1u16)` error: casting u16 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:14:5 + --> $DIR/cast_lossless_float.rs:24:5 | -14 | 1u16 as f64; +24 | 1u16 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1u16)` error: casting i32 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:15:5 + --> $DIR/cast_lossless_float.rs:25:5 | -15 | 1i32 as f64; +25 | 1i32 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1i32)` error: casting u32 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:16:5 + --> $DIR/cast_lossless_float.rs:26:5 | -16 | 1u32 as f64; +26 | 1u32 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1u32)` error: aborting due to 10 previous errors diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index e06e653c6f5..ef430d57e1e 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::cast_lossless)] #[allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/cast_lossless_integer.stderr b/tests/ui/cast_lossless_integer.stderr index 9640e1e18fa..5f9c70879b4 100644 --- a/tests/ui/cast_lossless_integer.stderr +++ b/tests/ui/cast_lossless_integer.stderr @@ -1,111 +1,111 @@ error: casting i8 to i16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:6:5 - | -6 | 1i8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1i8)` - | - = note: `-D clippy::cast-lossless` implied by `-D warnings` + --> $DIR/cast_lossless_integer.rs:16:5 + | +16 | 1i8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1i8)` + | + = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting i8 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:7:5 - | -7 | 1i8 as i32; - | ^^^^^^^^^^ help: try: `i32::from(1i8)` + --> $DIR/cast_lossless_integer.rs:17:5 + | +17 | 1i8 as i32; + | ^^^^^^^^^^ help: try: `i32::from(1i8)` error: casting i8 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:8:5 - | -8 | 1i8 as i64; - | ^^^^^^^^^^ help: try: `i64::from(1i8)` + --> $DIR/cast_lossless_integer.rs:18:5 + | +18 | 1i8 as i64; + | ^^^^^^^^^^ help: try: `i64::from(1i8)` error: casting u8 to i16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:9:5 - | -9 | 1u8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1u8)` + --> $DIR/cast_lossless_integer.rs:19:5 + | +19 | 1u8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1u8)` error: casting u8 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:10:5 + --> $DIR/cast_lossless_integer.rs:20:5 | -10 | 1u8 as i32; +20 | 1u8 as i32; | ^^^^^^^^^^ help: try: `i32::from(1u8)` error: casting u8 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:11:5 + --> $DIR/cast_lossless_integer.rs:21:5 | -11 | 1u8 as i64; +21 | 1u8 as i64; | ^^^^^^^^^^ help: try: `i64::from(1u8)` error: casting u8 to u16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:12:5 + --> $DIR/cast_lossless_integer.rs:22:5 | -12 | 1u8 as u16; +22 | 1u8 as u16; | ^^^^^^^^^^ help: try: `u16::from(1u8)` error: casting u8 to u32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:13:5 + --> $DIR/cast_lossless_integer.rs:23:5 | -13 | 1u8 as u32; +23 | 1u8 as u32; | ^^^^^^^^^^ help: try: `u32::from(1u8)` error: casting u8 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:14:5 + --> $DIR/cast_lossless_integer.rs:24:5 | -14 | 1u8 as u64; +24 | 1u8 as u64; | ^^^^^^^^^^ help: try: `u64::from(1u8)` error: casting i16 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:15:5 + --> $DIR/cast_lossless_integer.rs:25:5 | -15 | 1i16 as i32; +25 | 1i16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1i16)` error: casting i16 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:16:5 + --> $DIR/cast_lossless_integer.rs:26:5 | -16 | 1i16 as i64; +26 | 1i16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i16)` error: casting u16 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:17:5 + --> $DIR/cast_lossless_integer.rs:27:5 | -17 | 1u16 as i32; +27 | 1u16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1u16)` error: casting u16 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:18:5 + --> $DIR/cast_lossless_integer.rs:28:5 | -18 | 1u16 as i64; +28 | 1u16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u16)` error: casting u16 to u32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:19:5 + --> $DIR/cast_lossless_integer.rs:29:5 | -19 | 1u16 as u32; +29 | 1u16 as u32; | ^^^^^^^^^^^ help: try: `u32::from(1u16)` error: casting u16 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:20:5 + --> $DIR/cast_lossless_integer.rs:30:5 | -20 | 1u16 as u64; +30 | 1u16 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u16)` error: casting i32 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:21:5 + --> $DIR/cast_lossless_integer.rs:31:5 | -21 | 1i32 as i64; +31 | 1i32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i32)` error: casting u32 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:22:5 + --> $DIR/cast_lossless_integer.rs:32:5 | -22 | 1u32 as i64; +32 | 1u32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u32)` error: casting u32 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:23:5 + --> $DIR/cast_lossless_integer.rs:33:5 | -23 | 1u32 as u64; +33 | 1u32 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u32)` error: aborting due to 18 previous errors diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index 4c72f57165c..e8b0f4a5b82 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap, clippy::cast_lossless)] diff --git a/tests/ui/cast_size.stderr b/tests/ui/cast_size.stderr index 1797e2e367f..c5f569db167 100644 --- a/tests/ui/cast_size.stderr +++ b/tests/ui/cast_size.stderr @@ -1,123 +1,123 @@ error: casting isize to i8 may truncate the value - --> $DIR/cast_size.rs:7:5 - | -7 | 1isize as i8; - | ^^^^^^^^^^^^ - | - = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` + --> $DIR/cast_size.rs:17:5 + | +17 | 1isize as i8; + | ^^^^^^^^^^^^ + | + = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting isize to f64 causes a loss of precision on targets with 64-bit wide pointers (isize is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast_size.rs:8:5 - | -8 | 1isize as f64; - | ^^^^^^^^^^^^^ - | - = note: `-D clippy::cast-precision-loss` implied by `-D warnings` + --> $DIR/cast_size.rs:18:5 + | +18 | 1isize as f64; + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting usize to f64 causes a loss of precision on targets with 64-bit wide pointers (usize is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast_size.rs:9:5 - | -9 | 1usize as f64; - | ^^^^^^^^^^^^^ + --> $DIR/cast_size.rs:19:5 + | +19 | 1usize as f64; + | ^^^^^^^^^^^^^ error: casting isize to f32 causes a loss of precision (isize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast_size.rs:10:5 + --> $DIR/cast_size.rs:20:5 | -10 | 1isize as f32; +20 | 1isize as f32; | ^^^^^^^^^^^^^ error: casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast_size.rs:11:5 + --> $DIR/cast_size.rs:21:5 | -11 | 1usize as f32; +21 | 1usize as f32; | ^^^^^^^^^^^^^ error: casting isize to i32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:12:5 + --> $DIR/cast_size.rs:22:5 | -12 | 1isize as i32; +22 | 1isize as i32; | ^^^^^^^^^^^^^ error: casting isize to u32 may lose the sign of the value - --> $DIR/cast_size.rs:13:5 + --> $DIR/cast_size.rs:23:5 | -13 | 1isize as u32; +23 | 1isize as u32; | ^^^^^^^^^^^^^ | = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting isize to u32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:13:5 + --> $DIR/cast_size.rs:23:5 | -13 | 1isize as u32; +23 | 1isize as u32; | ^^^^^^^^^^^^^ error: casting usize to u32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:14:5 + --> $DIR/cast_size.rs:24:5 | -14 | 1usize as u32; +24 | 1usize as u32; | ^^^^^^^^^^^^^ error: casting usize to i32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:15:5 + --> $DIR/cast_size.rs:25:5 | -15 | 1usize as i32; +25 | 1usize as i32; | ^^^^^^^^^^^^^ error: casting usize to i32 may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:15:5 + --> $DIR/cast_size.rs:25:5 | -15 | 1usize as i32; +25 | 1usize as i32; | ^^^^^^^^^^^^^ | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting i64 to isize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:17:5 + --> $DIR/cast_size.rs:27:5 | -17 | 1i64 as isize; +27 | 1i64 as isize; | ^^^^^^^^^^^^^ error: casting i64 to usize may lose the sign of the value - --> $DIR/cast_size.rs:18:5 + --> $DIR/cast_size.rs:28:5 | -18 | 1i64 as usize; +28 | 1i64 as usize; | ^^^^^^^^^^^^^ error: casting i64 to usize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:18:5 + --> $DIR/cast_size.rs:28:5 | -18 | 1i64 as usize; +28 | 1i64 as usize; | ^^^^^^^^^^^^^ error: casting u64 to isize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:19:5 + --> $DIR/cast_size.rs:29:5 | -19 | 1u64 as isize; +29 | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting u64 to isize may wrap around the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:19:5 + --> $DIR/cast_size.rs:29:5 | -19 | 1u64 as isize; +29 | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting u64 to usize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:20:5 + --> $DIR/cast_size.rs:30:5 | -20 | 1u64 as usize; +30 | 1u64 as usize; | ^^^^^^^^^^^^^ error: casting u32 to isize may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:21:5 + --> $DIR/cast_size.rs:31:5 | -21 | 1u32 as isize; +31 | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting i32 to usize may lose the sign of the value - --> $DIR/cast_size.rs:24:5 + --> $DIR/cast_size.rs:34:5 | -24 | 1i32 as usize; +34 | 1i32 as usize; | ^^^^^^^^^^^^^ error: aborting due to 19 previous errors diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index f9937ede351..8fda473e351 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index f6ea10d5731..38a469bfebb 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -1,12 +1,12 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so casting to u8 truncates them - --> $DIR/char_lit_as_u8.rs:7:13 - | -7 | let c = 'a' as u8; - | ^^^^^^^^^ - | - = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` - = help: Consider using a byte literal instead: - b'a' + --> $DIR/char_lit_as_u8.rs:17:13 + | +17 | let c = 'a' as u8; + | ^^^^^^^^^ + | + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = help: Consider using a byte literal instead: + b'a' error: aborting due to previous error diff --git a/tests/ui/checked_unwrap.rs b/tests/ui/checked_unwrap.rs index b3979245d36..ed9651b1872 100644 --- a/tests/ui/checked_unwrap.rs +++ b/tests/ui/checked_unwrap.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] diff --git a/tests/ui/checked_unwrap.stderr b/tests/ui/checked_unwrap.stderr index 4508ce442fa..f7f49360348 100644 --- a/tests/ui/checked_unwrap.stderr +++ b/tests/ui/checked_unwrap.stderr @@ -1,312 +1,312 @@ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:9:9 - | -8 | if x.is_some() { - | ----------- the check is happening here -9 | x.unwrap(); // unnecessary - | ^^^^^^^^^^ - | + --> $DIR/checked_unwrap.rs:19:9 + | +18 | if x.is_some() { + | ----------- the check is happening here +19 | x.unwrap(); // unnecessary + | ^^^^^^^^^^ + | note: lint level defined here - --> $DIR/checked_unwrap.rs:3:35 - | -3 | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/checked_unwrap.rs:13:35 + | +13 | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:11:9 + --> $DIR/checked_unwrap.rs:21:9 | -8 | if x.is_some() { +18 | if x.is_some() { | ----------- because of this check ... -11 | x.unwrap(); // will panic +21 | x.unwrap(); // will panic | ^^^^^^^^^^ | note: lint level defined here - --> $DIR/checked_unwrap.rs:3:9 + --> $DIR/checked_unwrap.rs:13:9 | -3 | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] +13 | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:14:9 + --> $DIR/checked_unwrap.rs:24:9 | -13 | if x.is_none() { +23 | if x.is_none() { | ----------- because of this check -14 | x.unwrap(); // will panic +24 | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:16:9 + --> $DIR/checked_unwrap.rs:26:9 | -13 | if x.is_none() { +23 | if x.is_none() { | ----------- the check is happening here ... -16 | x.unwrap(); // unnecessary +26 | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:20:9 + --> $DIR/checked_unwrap.rs:30:9 | -19 | if x.is_ok() { +29 | if x.is_ok() { | --------- the check is happening here -20 | x.unwrap(); // unnecessary +30 | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:21:9 + --> $DIR/checked_unwrap.rs:31:9 | -19 | if x.is_ok() { +29 | if x.is_ok() { | --------- because of this check -20 | x.unwrap(); // unnecessary -21 | x.unwrap_err(); // will panic +30 | x.unwrap(); // unnecessary +31 | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:23:9 + --> $DIR/checked_unwrap.rs:33:9 | -19 | if x.is_ok() { +29 | if x.is_ok() { | --------- because of this check ... -23 | x.unwrap(); // will panic +33 | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:24:9 + --> $DIR/checked_unwrap.rs:34:9 | -19 | if x.is_ok() { +29 | if x.is_ok() { | --------- the check is happening here ... -24 | x.unwrap_err(); // unnecessary +34 | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:27:9 + --> $DIR/checked_unwrap.rs:37:9 | -26 | if x.is_err() { +36 | if x.is_err() { | ---------- because of this check -27 | x.unwrap(); // will panic +37 | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:28:9 + --> $DIR/checked_unwrap.rs:38:9 | -26 | if x.is_err() { +36 | if x.is_err() { | ---------- the check is happening here -27 | x.unwrap(); // will panic -28 | x.unwrap_err(); // unnecessary +37 | x.unwrap(); // will panic +38 | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:30:9 + --> $DIR/checked_unwrap.rs:40:9 | -26 | if x.is_err() { +36 | if x.is_err() { | ---------- the check is happening here ... -30 | x.unwrap(); // unnecessary +40 | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:31:9 + --> $DIR/checked_unwrap.rs:41:9 | -26 | if x.is_err() { +36 | if x.is_err() { | ---------- because of this check ... -31 | x.unwrap_err(); // will panic +41 | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:48:9 + --> $DIR/checked_unwrap.rs:58:9 | -47 | if x.is_ok() && y.is_err() { +57 | if x.is_ok() && y.is_err() { | --------- the check is happening here -48 | x.unwrap(); // unnecessary +58 | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:49:9 + --> $DIR/checked_unwrap.rs:59:9 | -47 | if x.is_ok() && y.is_err() { +57 | if x.is_ok() && y.is_err() { | --------- because of this check -48 | x.unwrap(); // unnecessary -49 | x.unwrap_err(); // will panic +58 | x.unwrap(); // unnecessary +59 | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:50:9 + --> $DIR/checked_unwrap.rs:60:9 | -47 | if x.is_ok() && y.is_err() { +57 | if x.is_ok() && y.is_err() { | ---------- because of this check ... -50 | y.unwrap(); // will panic +60 | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:51:9 + --> $DIR/checked_unwrap.rs:61:9 | -47 | if x.is_ok() && y.is_err() { +57 | if x.is_ok() && y.is_err() { | ---------- the check is happening here ... -51 | y.unwrap_err(); // unnecessary +61 | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:65:9 + --> $DIR/checked_unwrap.rs:75:9 | -60 | if x.is_ok() || y.is_ok() { +70 | if x.is_ok() || y.is_ok() { | --------- because of this check ... -65 | x.unwrap(); // will panic +75 | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:66:9 + --> $DIR/checked_unwrap.rs:76:9 | -60 | if x.is_ok() || y.is_ok() { +70 | if x.is_ok() || y.is_ok() { | --------- the check is happening here ... -66 | x.unwrap_err(); // unnecessary +76 | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:67:9 + --> $DIR/checked_unwrap.rs:77:9 | -60 | if x.is_ok() || y.is_ok() { +70 | if x.is_ok() || y.is_ok() { | --------- because of this check ... -67 | y.unwrap(); // will panic +77 | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:68:9 + --> $DIR/checked_unwrap.rs:78:9 | -60 | if x.is_ok() || y.is_ok() { +70 | if x.is_ok() || y.is_ok() { | --------- the check is happening here ... -68 | y.unwrap_err(); // unnecessary +78 | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:72:9 + --> $DIR/checked_unwrap.rs:82:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here -72 | x.unwrap(); // unnecessary +82 | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:73:9 + --> $DIR/checked_unwrap.rs:83:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check -72 | x.unwrap(); // unnecessary -73 | x.unwrap_err(); // will panic +82 | x.unwrap(); // unnecessary +83 | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:74:9 + --> $DIR/checked_unwrap.rs:84:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check ... -74 | y.unwrap(); // will panic +84 | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:75:9 + --> $DIR/checked_unwrap.rs:85:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here ... -75 | y.unwrap_err(); // unnecessary +85 | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:76:9 + --> $DIR/checked_unwrap.rs:86:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here ... -76 | z.unwrap(); // unnecessary +86 | z.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:77:9 + --> $DIR/checked_unwrap.rs:87:9 | -71 | if x.is_ok() && !(y.is_ok() || z.is_err()) { +81 | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check ... -77 | z.unwrap_err(); // will panic +87 | z.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:85:9 + --> $DIR/checked_unwrap.rs:95:9 | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check ... -85 | x.unwrap(); // will panic +95 | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:86:9 + --> $DIR/checked_unwrap.rs:96:9 | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here ... -86 | x.unwrap_err(); // unnecessary +96 | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:87:9 + --> $DIR/checked_unwrap.rs:97:9 | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here ... -87 | y.unwrap(); // unnecessary +97 | y.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:88:9 + --> $DIR/checked_unwrap.rs:98:9 | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check ... -88 | y.unwrap_err(); // will panic +98 | y.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:89:9 + --> $DIR/checked_unwrap.rs:99:9 | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check ... -89 | z.unwrap(); // will panic +99 | z.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:90:9 - | -79 | if x.is_ok() || !(y.is_ok() && z.is_err()) { - | ---------- the check is happening here + --> $DIR/checked_unwrap.rs:100:9 + | +89 | if x.is_ok() || !(y.is_ok() && z.is_err()) { + | ---------- the check is happening here ... -90 | z.unwrap_err(); // unnecessary - | ^^^^^^^^^^^^^^ +100 | z.unwrap_err(); // unnecessary + | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:98:13 - | -97 | if x.is_some() { - | ----------- the check is happening here -98 | x.unwrap(); // unnecessary - | ^^^^^^^^^^ + --> $DIR/checked_unwrap.rs:108:13 + | +107 | if x.is_some() { + | ----------- the check is happening here +108 | x.unwrap(); // unnecessary + | ^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:100:13 + --> $DIR/checked_unwrap.rs:110:13 | -97 | if x.is_some() { +107 | if x.is_some() { | ----------- because of this check ... -100 | x.unwrap(); // will panic +110 | x.unwrap(); // will panic | ^^^^^^^^^^ error: aborting due to 34 previous errors diff --git a/tests/ui/clone_on_copy_impl.rs b/tests/ui/clone_on_copy_impl.rs index e21441640f3..a1353abd92b 100644 --- a/tests/ui/clone_on_copy_impl.rs +++ b/tests/ui/clone_on_copy_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use std::marker::PhantomData; use std::fmt; diff --git a/tests/ui/clone_on_copy_mut.rs b/tests/ui/clone_on_copy_mut.rs index 77dffc67670..ad37d45d36f 100644 --- a/tests/ui/clone_on_copy_mut.rs +++ b/tests/ui/clone_on_copy_mut.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] pub fn dec_read_dec(i: &mut i32) -> i32 { diff --git a/tests/ui/cmp_nan.rs b/tests/ui/cmp_nan.rs index fdebb7da18a..a2506f444f0 100644 --- a/tests/ui/cmp_nan.rs +++ b/tests/ui/cmp_nan.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/cmp_nan.stderr b/tests/ui/cmp_nan.stderr index 7f636e6b534..b880b821f08 100644 --- a/tests/ui/cmp_nan.stderr +++ b/tests/ui/cmp_nan.stderr @@ -1,75 +1,75 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:8:5 - | -8 | x == std::f32::NAN; - | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::cmp-nan` implied by `-D warnings` + --> $DIR/cmp_nan.rs:18:5 + | +18 | x == std::f32::NAN; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::cmp-nan` implied by `-D warnings` error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:9:5 - | -9 | x != std::f32::NAN; - | ^^^^^^^^^^^^^^^^^^ + --> $DIR/cmp_nan.rs:19:5 + | +19 | x != std::f32::NAN; + | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:10:5 + --> $DIR/cmp_nan.rs:20:5 | -10 | x < std::f32::NAN; +20 | x < std::f32::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:11:5 + --> $DIR/cmp_nan.rs:21:5 | -11 | x > std::f32::NAN; +21 | x > std::f32::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:12:5 + --> $DIR/cmp_nan.rs:22:5 | -12 | x <= std::f32::NAN; +22 | x <= std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:13:5 + --> $DIR/cmp_nan.rs:23:5 | -13 | x >= std::f32::NAN; +23 | x >= std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:16:5 + --> $DIR/cmp_nan.rs:26:5 | -16 | y == std::f64::NAN; +26 | y == std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:17:5 + --> $DIR/cmp_nan.rs:27:5 | -17 | y != std::f64::NAN; +27 | y != std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:18:5 + --> $DIR/cmp_nan.rs:28:5 | -18 | y < std::f64::NAN; +28 | y < std::f64::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:19:5 + --> $DIR/cmp_nan.rs:29:5 | -19 | y > std::f64::NAN; +29 | y > std::f64::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:20:5 + --> $DIR/cmp_nan.rs:30:5 | -20 | y <= std::f64::NAN; +30 | y <= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:21:5 + --> $DIR/cmp_nan.rs:31:5 | -21 | y >= std::f64::NAN; +31 | y >= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index e10b3e104ec..d8214876a1b 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::cmp_null)] diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 55050d2a320..1f1fdf32852 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -1,15 +1,15 @@ error: Comparing with null is better expressed by the .is_null() method - --> $DIR/cmp_null.rs:11:8 + --> $DIR/cmp_null.rs:21:8 | -11 | if p == ptr::null() { +21 | if p == ptr::null() { | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::cmp-null` implied by `-D warnings` error: Comparing with null is better expressed by the .is_null() method - --> $DIR/cmp_null.rs:16:8 + --> $DIR/cmp_null.rs:26:8 | -16 | if m == ptr::null_mut() { +26 | if m == ptr::null_mut() { | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 713975c4404..e937afc1a81 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/cmp_owned.stderr b/tests/ui/cmp_owned.stderr index 2691c12eab1..020ffe805cd 100644 --- a/tests/ui/cmp_owned.stderr +++ b/tests/ui/cmp_owned.stderr @@ -1,39 +1,39 @@ error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:8:14 - | -8 | x != "foo".to_string(); - | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` - | - = note: `-D clippy::cmp-owned` implied by `-D warnings` + --> $DIR/cmp_owned.rs:18:14 + | +18 | x != "foo".to_string(); + | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` + | + = note: `-D clippy::cmp-owned` implied by `-D warnings` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:10:9 + --> $DIR/cmp_owned.rs:20:9 | -10 | "foo".to_string() != x; +20 | "foo".to_string() != x; | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:17:10 + --> $DIR/cmp_owned.rs:27:10 | -17 | x != "foo".to_owned(); +27 | x != "foo".to_owned(); | ^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:19:10 + --> $DIR/cmp_owned.rs:29:10 | -19 | x != String::from("foo"); +29 | x != String::from("foo"); | ^^^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:23:5 + --> $DIR/cmp_owned.rs:33:5 | -23 | Foo.to_owned() == Foo; +33 | Foo.to_owned() == Foo; | ^^^^^^^^^^^^^^ help: try: `Foo` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:30:9 + --> $DIR/cmp_owned.rs:40:9 | -30 | self.to_owned() == *other +40 | self.to_owned() == *other | ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating error: aborting due to 6 previous errors diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index d40be631933..fa80b27f590 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index a447fab7b6e..87c279cd725 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -1,243 +1,243 @@ error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:8:5 + --> $DIR/collapsible_if.rs:18:5 | -8 | / if x == "hello" { -9 | | if y == "world" { -10 | | println!("Hello world!"); -11 | | } -12 | | } +18 | / if x == "hello" { +19 | | if y == "world" { +20 | | println!("Hello world!"); +21 | | } +22 | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` help: try | -8 | if x == "hello" && y == "world" { -9 | println!("Hello world!"); -10 | } +18 | if x == "hello" && y == "world" { +19 | println!("Hello world!"); +20 | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:14:5 + --> $DIR/collapsible_if.rs:24:5 | -14 | / if x == "hello" || x == "world" { -15 | | if y == "world" || y == "hello" { -16 | | println!("Hello world!"); -17 | | } -18 | | } +24 | / if x == "hello" || x == "world" { +25 | | if y == "world" || y == "hello" { +26 | | println!("Hello world!"); +27 | | } +28 | | } | |_____^ help: try | -14 | if (x == "hello" || x == "world") && (y == "world" || y == "hello") { -15 | println!("Hello world!"); -16 | } +24 | if (x == "hello" || x == "world") && (y == "world" || y == "hello") { +25 | println!("Hello world!"); +26 | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:20:5 + --> $DIR/collapsible_if.rs:30:5 | -20 | / if x == "hello" && x == "world" { -21 | | if y == "world" || y == "hello" { -22 | | println!("Hello world!"); -23 | | } -24 | | } +30 | / if x == "hello" && x == "world" { +31 | | if y == "world" || y == "hello" { +32 | | println!("Hello world!"); +33 | | } +34 | | } | |_____^ help: try | -20 | if x == "hello" && x == "world" && (y == "world" || y == "hello") { -21 | println!("Hello world!"); -22 | } +30 | if x == "hello" && x == "world" && (y == "world" || y == "hello") { +31 | println!("Hello world!"); +32 | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:26:5 + --> $DIR/collapsible_if.rs:36:5 | -26 | / if x == "hello" || x == "world" { -27 | | if y == "world" && y == "hello" { -28 | | println!("Hello world!"); -29 | | } -30 | | } +36 | / if x == "hello" || x == "world" { +37 | | if y == "world" && y == "hello" { +38 | | println!("Hello world!"); +39 | | } +40 | | } | |_____^ help: try | -26 | if (x == "hello" || x == "world") && y == "world" && y == "hello" { -27 | println!("Hello world!"); -28 | } +36 | if (x == "hello" || x == "world") && y == "world" && y == "hello" { +37 | println!("Hello world!"); +38 | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:32:5 + --> $DIR/collapsible_if.rs:42:5 | -32 | / if x == "hello" && x == "world" { -33 | | if y == "world" && y == "hello" { -34 | | println!("Hello world!"); -35 | | } -36 | | } +42 | / if x == "hello" && x == "world" { +43 | | if y == "world" && y == "hello" { +44 | | println!("Hello world!"); +45 | | } +46 | | } | |_____^ help: try | -32 | if x == "hello" && x == "world" && y == "world" && y == "hello" { -33 | println!("Hello world!"); -34 | } +42 | if x == "hello" && x == "world" && y == "world" && y == "hello" { +43 | println!("Hello world!"); +44 | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:38:5 + --> $DIR/collapsible_if.rs:48:5 | -38 | / if 42 == 1337 { -39 | | if 'a' != 'A' { -40 | | println!("world!") -41 | | } -42 | | } +48 | / if 42 == 1337 { +49 | | if 'a' != 'A' { +50 | | println!("world!") +51 | | } +52 | | } | |_____^ help: try | -38 | if 42 == 1337 && 'a' != 'A' { -39 | println!("world!") -40 | } +48 | if 42 == 1337 && 'a' != 'A' { +49 | println!("world!") +50 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:47:12 + --> $DIR/collapsible_if.rs:57:12 | -47 | } else { +57 | } else { | ____________^ -48 | | if y == "world" { -49 | | println!("world!") -50 | | } -51 | | } +58 | | if y == "world" { +59 | | println!("world!") +60 | | } +61 | | } | |_____^ help: try | -47 | } else if y == "world" { -48 | println!("world!") -49 | } +57 | } else if y == "world" { +58 | println!("world!") +59 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:55:12 + --> $DIR/collapsible_if.rs:65:12 | -55 | } else { +65 | } else { | ____________^ -56 | | if let Some(42) = Some(42) { -57 | | println!("world!") -58 | | } -59 | | } +66 | | if let Some(42) = Some(42) { +67 | | println!("world!") +68 | | } +69 | | } | |_____^ help: try | -55 | } else if let Some(42) = Some(42) { -56 | println!("world!") -57 | } +65 | } else if let Some(42) = Some(42) { +66 | println!("world!") +67 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:63:12 + --> $DIR/collapsible_if.rs:73:12 | -63 | } else { +73 | } else { | ____________^ -64 | | if y == "world" { -65 | | println!("world") -66 | | } +74 | | if y == "world" { +75 | | println!("world") +76 | | } ... | -69 | | } -70 | | } +79 | | } +80 | | } | |_____^ help: try | -63 | } else if y == "world" { -64 | println!("world") -65 | } -66 | else { -67 | println!("!") -68 | } +73 | } else if y == "world" { +74 | println!("world") +75 | } +76 | else { +77 | println!("!") +78 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:74:12 + --> $DIR/collapsible_if.rs:84:12 | -74 | } else { +84 | } else { | ____________^ -75 | | if let Some(42) = Some(42) { -76 | | println!("world") -77 | | } +85 | | if let Some(42) = Some(42) { +86 | | println!("world") +87 | | } ... | -80 | | } -81 | | } +90 | | } +91 | | } | |_____^ help: try | -74 | } else if let Some(42) = Some(42) { -75 | println!("world") -76 | } -77 | else { -78 | println!("!") -79 | } +84 | } else if let Some(42) = Some(42) { +85 | println!("world") +86 | } +87 | else { +88 | println!("!") +89 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:85:12 - | -85 | } else { - | ____________^ -86 | | if let Some(42) = Some(42) { -87 | | println!("world") -88 | | } -... | -91 | | } -92 | | } - | |_____^ + --> $DIR/collapsible_if.rs:95:12 + | +95 | } else { + | ____________^ +96 | | if let Some(42) = Some(42) { +97 | | println!("world") +98 | | } +... | +101 | | } +102 | | } + | |_____^ help: try - | -85 | } else if let Some(42) = Some(42) { -86 | println!("world") -87 | } -88 | else { -89 | println!("!") -90 | } - | + | +95 | } else if let Some(42) = Some(42) { +96 | println!("world") +97 | } +98 | else { +99 | println!("!") +100 | } + | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:96:12 + --> $DIR/collapsible_if.rs:106:12 | -96 | } else { +106 | } else { | ____________^ -97 | | if x == "hello" { -98 | | println!("world") -99 | | } +107 | | if x == "hello" { +108 | | println!("world") +109 | | } ... | -102 | | } -103 | | } +112 | | } +113 | | } | |_____^ help: try | -96 | } else if x == "hello" { -97 | println!("world") -98 | } -99 | else { -100 | println!("!") -101 | } +106 | } else if x == "hello" { +107 | println!("world") +108 | } +109 | else { +110 | println!("!") +111 | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:107:12 + --> $DIR/collapsible_if.rs:117:12 | -107 | } else { +117 | } else { | ____________^ -108 | | if let Some(42) = Some(42) { -109 | | println!("world") -110 | | } +118 | | if let Some(42) = Some(42) { +119 | | println!("world") +120 | | } ... | -113 | | } -114 | | } +123 | | } +124 | | } | |_____^ help: try | -107 | } else if let Some(42) = Some(42) { -108 | println!("world") -109 | } -110 | else { -111 | println!("!") -112 | } +117 | } else if let Some(42) = Some(42) { +118 | println!("world") +119 | } +120 | else { +121 | println!("!") +122 | } | error: aborting due to 13 previous errors diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index eac2c07c12e..5779c9da47f 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all)] diff --git a/tests/ui/complex_types.stderr b/tests/ui/complex_types.stderr index 1c9106c0c21..f373f09951b 100644 --- a/tests/ui/complex_types.stderr +++ b/tests/ui/complex_types.stderr @@ -1,93 +1,93 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:9:12 - | -9 | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::type-complexity` implied by `-D warnings` + --> $DIR/complex_types.rs:19:12 + | +19 | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::type-complexity` implied by `-D warnings` error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:10:12 + --> $DIR/complex_types.rs:20:12 | -10 | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); +20 | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:13:8 + --> $DIR/complex_types.rs:23:8 | -13 | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, +23 | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:16:11 + --> $DIR/complex_types.rs:26:11 | -16 | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); +26 | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:19:11 + --> $DIR/complex_types.rs:29:11 | -19 | Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>), +29 | Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:20:17 + --> $DIR/complex_types.rs:30:17 | -20 | Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, +30 | Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:24:14 + --> $DIR/complex_types.rs:34:14 | -24 | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); +34 | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:25:30 + --> $DIR/complex_types.rs:35:30 | -25 | fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } +35 | fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:29:14 + --> $DIR/complex_types.rs:39:14 | -29 | const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; +39 | const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:30:14 + --> $DIR/complex_types.rs:40:14 | -30 | type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; +40 | type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:31:25 + --> $DIR/complex_types.rs:41:25 | -31 | fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); +41 | fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:32:29 + --> $DIR/complex_types.rs:42:29 | -32 | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } +42 | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:35:15 + --> $DIR/complex_types.rs:45:15 | -35 | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] } +45 | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:37:14 + --> $DIR/complex_types.rs:47:14 | -37 | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } +47 | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:40:13 + --> $DIR/complex_types.rs:50:13 | -40 | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; +50 | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 15 previous errors diff --git a/tests/ui/const_static_lifetime.rs b/tests/ui/const_static_lifetime.rs index 745821a1503..2b6a5dc249a 100644 --- a/tests/ui/const_static_lifetime.rs +++ b/tests/ui/const_static_lifetime.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[derive(Debug)] struct Foo {} diff --git a/tests/ui/const_static_lifetime.stderr b/tests/ui/const_static_lifetime.stderr index db6c4d9444f..908a681584d 100644 --- a/tests/ui/const_static_lifetime.stderr +++ b/tests/ui/const_static_lifetime.stderr @@ -1,81 +1,81 @@ error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:4:17 - | -4 | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. - | -^^^^^^^---- help: consider removing `'static`: `&str` - | - = note: `-D clippy::const-static-lifetime` implied by `-D warnings` + --> $DIR/const_static_lifetime.rs:14:17 + | +14 | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. + | -^^^^^^^---- help: consider removing `'static`: `&str` + | + = note: `-D clippy::const-static-lifetime` implied by `-D warnings` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:8:21 - | -8 | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static - | -^^^^^^^---- help: consider removing `'static`: `&str` + --> $DIR/const_static_lifetime.rs:18:21 + | +18 | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static + | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:10:32 + --> $DIR/const_static_lifetime.rs:20:32 | -10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +20 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:10:47 + --> $DIR/const_static_lifetime.rs:20:47 | -10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +20 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:12:18 + --> $DIR/const_static_lifetime.rs:22:18 | -12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +22 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:12:30 + --> $DIR/const_static_lifetime.rs:22:30 | -12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +22 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:14:17 + --> $DIR/const_static_lifetime.rs:24:17 | -14 | const VAR_SIX: &'static u8 = &5; +24 | const VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:16:29 + --> $DIR/const_static_lifetime.rs:26:29 | -16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; +26 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:16:39 + --> $DIR/const_static_lifetime.rs:26:39 | -16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; +26 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:18:20 + --> $DIR/const_static_lifetime.rs:28:20 | -18 | const VAR_HEIGHT: &'static Foo = &Foo {}; +28 | const VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:20:19 + --> $DIR/const_static_lifetime.rs:30:19 | -20 | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. +30 | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:22:19 + --> $DIR/const_static_lifetime.rs:32:19 | -22 | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. +32 | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:24:19 + --> $DIR/const_static_lifetime.rs:34:19 | -24 | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +34 | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: aborting due to 13 previous errors diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index 064c7fc1c59..2b29e76c4e0 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::blacklisted_name, clippy::collapsible_if, clippy::cyclomatic_complexity, clippy::eq_op, clippy::needless_continue, diff --git a/tests/ui/copies.stderr b/tests/ui/copies.stderr index febd34603c9..e5f808218fe 100644 --- a/tests/ui/copies.stderr +++ b/tests/ui/copies.stderr @@ -1,384 +1,384 @@ error: this `if` has identical blocks - --> $DIR/copies.rs:31:10 + --> $DIR/copies.rs:41:10 | -31 | else { //~ ERROR same body as `if` block +41 | else { //~ ERROR same body as `if` block | __________^ -32 | | Foo { bar: 42 }; -33 | | 0..10; -34 | | ..; +42 | | Foo { bar: 42 }; +43 | | 0..10; +44 | | ..; ... | -38 | | foo(); -39 | | } +48 | | foo(); +49 | | } | |_____^ | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/copies.rs:22:13 + --> $DIR/copies.rs:32:13 | -22 | if true { +32 | if true { | _____________^ -23 | | Foo { bar: 42 }; -24 | | 0..10; -25 | | ..; +33 | | Foo { bar: 42 }; +34 | | 0..10; +35 | | ..; ... | -29 | | foo(); -30 | | } +39 | | foo(); +40 | | } | |_____^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:80:14 + --> $DIR/copies.rs:90:14 | -80 | _ => { //~ ERROR match arms have same body +90 | _ => { //~ ERROR match arms have same body | ______________^ -81 | | foo(); -82 | | let mut a = 42 + [23].len() as i32; -83 | | if true { +91 | | foo(); +92 | | let mut a = 42 + [23].len() as i32; +93 | | if true { ... | -87 | | a -88 | | } +97 | | a +98 | | } | |_________^ | = note: `-D clippy::match-same-arms` implied by `-D warnings` note: same as this - --> $DIR/copies.rs:71:15 + --> $DIR/copies.rs:81:15 | -71 | 42 => { +81 | 42 => { | _______________^ -72 | | foo(); -73 | | let mut a = 42 + [23].len() as i32; -74 | | if true { +82 | | foo(); +83 | | let mut a = 42 + [23].len() as i32; +84 | | if true { ... | -78 | | a -79 | | } +88 | | a +89 | | } | |_________^ note: `42` has the same arm body as the `_` wildcard, consider removing it` - --> $DIR/copies.rs:71:15 + --> $DIR/copies.rs:81:15 | -71 | 42 => { +81 | 42 => { | _______________^ -72 | | foo(); -73 | | let mut a = 42 + [23].len() as i32; -74 | | if true { +82 | | foo(); +83 | | let mut a = 42 + [23].len() as i32; +84 | | if true { ... | -78 | | a -79 | | } +88 | | a +89 | | } | |_________^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:94:14 - | -94 | _ => 0, //~ ERROR match arms have same body - | ^ - | + --> $DIR/copies.rs:104:14 + | +104 | _ => 0, //~ ERROR match arms have same body + | ^ + | note: same as this - --> $DIR/copies.rs:92:19 - | -92 | Abc::A => 0, - | ^ + --> $DIR/copies.rs:102:19 + | +102 | Abc::A => 0, + | ^ note: `Abc::A` has the same arm body as the `_` wildcard, consider removing it` - --> $DIR/copies.rs:92:19 - | -92 | Abc::A => 0, - | ^ + --> $DIR/copies.rs:102:19 + | +102 | Abc::A => 0, + | ^ error: this `if` has identical blocks - --> $DIR/copies.rs:104:10 + --> $DIR/copies.rs:114:10 | -104 | else { //~ ERROR same body as `if` block +114 | else { //~ ERROR same body as `if` block | __________^ -105 | | 42 -106 | | }; +115 | | 42 +116 | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:101:21 + --> $DIR/copies.rs:111:21 | -101 | let _ = if true { +111 | let _ = if true { | _____________________^ -102 | | 42 -103 | | } +112 | | 42 +113 | | } | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:118:10 + --> $DIR/copies.rs:128:10 | -118 | else { //~ ERROR same body as `if` block +128 | else { //~ ERROR same body as `if` block | __________^ -119 | | for _ in &[42] { -120 | | let foo: &Option<_> = &Some::<u8>(42); -121 | | if true { +129 | | for _ in &[42] { +130 | | let foo: &Option<_> = &Some::<u8>(42); +131 | | if true { ... | -126 | | } -127 | | } +136 | | } +137 | | } | |_____^ | note: same as this - --> $DIR/copies.rs:108:13 + --> $DIR/copies.rs:118:13 | -108 | if true { +118 | if true { | _____________^ -109 | | for _ in &[42] { -110 | | let foo: &Option<_> = &Some::<u8>(42); -111 | | if true { +119 | | for _ in &[42] { +120 | | let foo: &Option<_> = &Some::<u8>(42); +121 | | if true { ... | -116 | | } -117 | | } +126 | | } +127 | | } | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:140:10 + --> $DIR/copies.rs:150:10 | -140 | else { //~ ERROR same body as `if` block +150 | else { //~ ERROR same body as `if` block | __________^ -141 | | let bar = if true { -142 | | 42 -143 | | } +151 | | let bar = if true { +152 | | 42 +153 | | } ... | -149 | | bar + 1; -150 | | } +159 | | bar + 1; +160 | | } | |_____^ | note: same as this - --> $DIR/copies.rs:129:13 + --> $DIR/copies.rs:139:13 | -129 | if true { +139 | if true { | _____________^ -130 | | let bar = if true { -131 | | 42 -132 | | } +140 | | let bar = if true { +141 | | 42 +142 | | } ... | -138 | | bar + 1; -139 | | } +148 | | bar + 1; +149 | | } | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:175:10 + --> $DIR/copies.rs:185:10 | -175 | else { //~ ERROR same body as `if` block +185 | else { //~ ERROR same body as `if` block | __________^ -176 | | if let Some(a) = Some(42) {} -177 | | } +186 | | if let Some(a) = Some(42) {} +187 | | } | |_____^ | note: same as this - --> $DIR/copies.rs:172:13 + --> $DIR/copies.rs:182:13 | -172 | if true { +182 | if true { | _____________^ -173 | | if let Some(a) = Some(42) {} -174 | | } +183 | | if let Some(a) = Some(42) {} +184 | | } | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:182:10 + --> $DIR/copies.rs:192:10 | -182 | else { //~ ERROR same body as `if` block +192 | else { //~ ERROR same body as `if` block | __________^ -183 | | if let (1, .., 3) = (1, 2, 3) {} -184 | | } +193 | | if let (1, .., 3) = (1, 2, 3) {} +194 | | } | |_____^ | note: same as this - --> $DIR/copies.rs:179:13 + --> $DIR/copies.rs:189:13 | -179 | if true { +189 | if true { | _____________^ -180 | | if let (1, .., 3) = (1, 2, 3) {} -181 | | } +190 | | if let (1, .., 3) = (1, 2, 3) {} +191 | | } | |_____^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:237:15 + --> $DIR/copies.rs:247:15 | -237 | 51 => foo(), //~ ERROR match arms have same body +247 | 51 => foo(), //~ ERROR match arms have same body | ^^^^^ | note: same as this - --> $DIR/copies.rs:236:15 + --> $DIR/copies.rs:246:15 | -236 | 42 => foo(), +246 | 42 => foo(), | ^^^^^ note: consider refactoring into `42 | 51` - --> $DIR/copies.rs:236:15 + --> $DIR/copies.rs:246:15 | -236 | 42 => foo(), +246 | 42 => foo(), | ^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:243:17 + --> $DIR/copies.rs:253:17 | -243 | None => 24, //~ ERROR match arms have same body +253 | None => 24, //~ ERROR match arms have same body | ^^ | note: same as this - --> $DIR/copies.rs:242:20 + --> $DIR/copies.rs:252:20 | -242 | Some(_) => 24, +252 | Some(_) => 24, | ^^ note: consider refactoring into `Some(_) | None` - --> $DIR/copies.rs:242:20 + --> $DIR/copies.rs:252:20 | -242 | Some(_) => 24, +252 | Some(_) => 24, | ^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:265:28 + --> $DIR/copies.rs:275:28 | -265 | (None, Some(a)) => bar(a), //~ ERROR match arms have same body +275 | (None, Some(a)) => bar(a), //~ ERROR match arms have same body | ^^^^^^ | note: same as this - --> $DIR/copies.rs:264:28 + --> $DIR/copies.rs:274:28 | -264 | (Some(a), None) => bar(a), +274 | (Some(a), None) => bar(a), | ^^^^^^ note: consider refactoring into `(Some(a), None) | (None, Some(a))` - --> $DIR/copies.rs:264:28 + --> $DIR/copies.rs:274:28 | -264 | (Some(a), None) => bar(a), +274 | (Some(a), None) => bar(a), | ^^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:271:26 + --> $DIR/copies.rs:281:26 | -271 | (.., Some(a)) => bar(a), //~ ERROR match arms have same body +281 | (.., Some(a)) => bar(a), //~ ERROR match arms have same body | ^^^^^^ | note: same as this - --> $DIR/copies.rs:270:26 + --> $DIR/copies.rs:280:26 | -270 | (Some(a), ..) => bar(a), +280 | (Some(a), ..) => bar(a), | ^^^^^^ note: consider refactoring into `(Some(a), ..) | (.., Some(a))` - --> $DIR/copies.rs:270:26 + --> $DIR/copies.rs:280:26 | -270 | (Some(a), ..) => bar(a), +280 | (Some(a), ..) => bar(a), | ^^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:277:20 + --> $DIR/copies.rs:287:20 | -277 | (.., 3) => 42, //~ ERROR match arms have same body +287 | (.., 3) => 42, //~ ERROR match arms have same body | ^^ | note: same as this - --> $DIR/copies.rs:276:23 + --> $DIR/copies.rs:286:23 | -276 | (1, .., 3) => 42, +286 | (1, .., 3) => 42, | ^^ note: consider refactoring into `(1, .., 3) | (.., 3)` - --> $DIR/copies.rs:276:23 + --> $DIR/copies.rs:286:23 | -276 | (1, .., 3) => 42, +286 | (1, .., 3) => 42, | ^^ error: this `if` has identical blocks - --> $DIR/copies.rs:283:12 + --> $DIR/copies.rs:293:12 | -283 | } else { //~ ERROR same body as `if` block +293 | } else { //~ ERROR same body as `if` block | ____________^ -284 | | 0.0 -285 | | }; +294 | | 0.0 +295 | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:281:21 + --> $DIR/copies.rs:291:21 | -281 | let _ = if true { +291 | let _ = if true { | _____________________^ -282 | | 0.0 -283 | | } else { //~ ERROR same body as `if` block +292 | | 0.0 +293 | | } else { //~ ERROR same body as `if` block | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:289:12 + --> $DIR/copies.rs:299:12 | -289 | } else { //~ ERROR same body as `if` block +299 | } else { //~ ERROR same body as `if` block | ____________^ -290 | | -0.0 -291 | | }; +300 | | -0.0 +301 | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:287:21 + --> $DIR/copies.rs:297:21 | -287 | let _ = if true { +297 | let _ = if true { | _____________________^ -288 | | -0.0 -289 | | } else { //~ ERROR same body as `if` block +298 | | -0.0 +299 | | } else { //~ ERROR same body as `if` block | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:309:12 + --> $DIR/copies.rs:319:12 | -309 | } else { //~ ERROR same body as `if` block +319 | } else { //~ ERROR same body as `if` block | ____________^ -310 | | std::f32::NAN -311 | | }; +320 | | std::f32::NAN +321 | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:307:21 + --> $DIR/copies.rs:317:21 | -307 | let _ = if true { +317 | let _ = if true { | _____________________^ -308 | | std::f32::NAN -309 | | } else { //~ ERROR same body as `if` block +318 | | std::f32::NAN +319 | | } else { //~ ERROR same body as `if` block | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:327:10 + --> $DIR/copies.rs:337:10 | -327 | else { //~ ERROR same body as `if` block +337 | else { //~ ERROR same body as `if` block | __________^ -328 | | try!(Ok("foo")); -329 | | } +338 | | try!(Ok("foo")); +339 | | } | |_____^ | note: same as this - --> $DIR/copies.rs:324:13 + --> $DIR/copies.rs:334:13 | -324 | if true { +334 | if true { | _____________^ -325 | | try!(Ok("foo")); -326 | | } +335 | | try!(Ok("foo")); +336 | | } | |_____^ error: this `if` has the same condition as a previous if - --> $DIR/copies.rs:353:13 + --> $DIR/copies.rs:363:13 | -353 | else if b { //~ ERROR ifs same condition +363 | else if b { //~ ERROR ifs same condition | ^ | = note: `-D clippy::ifs-same-cond` implied by `-D warnings` note: same as this - --> $DIR/copies.rs:351:8 + --> $DIR/copies.rs:361:8 | -351 | if b { +361 | if b { | ^ error: this `if` has the same condition as a previous if - --> $DIR/copies.rs:358:13 + --> $DIR/copies.rs:368:13 | -358 | else if a == 1 { //~ ERROR ifs same condition +368 | else if a == 1 { //~ ERROR ifs same condition | ^^^^^^ | note: same as this - --> $DIR/copies.rs:356:8 + --> $DIR/copies.rs:366:8 | -356 | if a == 1 { +366 | if a == 1 { | ^^^^^^ error: this `if` has the same condition as a previous if - --> $DIR/copies.rs:365:13 + --> $DIR/copies.rs:375:13 | -365 | else if 2*a == 1 { //~ ERROR ifs same condition +375 | else if 2*a == 1 { //~ ERROR ifs same condition | ^^^^^^^^ | note: same as this - --> $DIR/copies.rs:361:8 + --> $DIR/copies.rs:371:8 | -361 | if 2*a == 1 { +371 | if 2*a == 1 { | ^^^^^^^^ error: aborting due to 20 previous errors diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs index 5ccb9910c1e..6984b612f23 100644 --- a/tests/ui/copy_iterator.rs +++ b/tests/ui/copy_iterator.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::copy_iterator)] diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr index 9a06a52d4bb..4620958f47b 100644 --- a/tests/ui/copy_iterator.stderr +++ b/tests/ui/copy_iterator.stderr @@ -1,13 +1,13 @@ error: you are implementing `Iterator` on a `Copy` type - --> $DIR/copy_iterator.rs:8:1 + --> $DIR/copy_iterator.rs:18:1 | -8 | / impl Iterator for Countdown { -9 | | type Item = u8; -10 | | -11 | | fn next(&mut self) -> Option<u8> { +18 | / impl Iterator for Countdown { +19 | | type Item = u8; +20 | | +21 | | fn next(&mut self) -> Option<u8> { ... | -16 | | } -17 | | } +26 | | } +27 | | } | |_^ | = note: `-D clippy::copy-iterator` implied by `-D warnings` diff --git a/tests/ui/cstring.rs b/tests/ui/cstring.rs index e68874d5409..fd5d00059a7 100644 --- a/tests/ui/cstring.rs +++ b/tests/ui/cstring.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] fn main() {} diff --git a/tests/ui/cstring.stderr b/tests/ui/cstring.stderr index 2b2b51de6ae..74d6e864de4 100644 --- a/tests/ui/cstring.stderr +++ b/tests/ui/cstring.stderr @@ -1,16 +1,16 @@ error: you are getting the inner pointer of a temporary `CString` - --> $DIR/cstring.rs:9:5 - | -9 | CString::new("foo").unwrap().as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[deny(clippy::temporary_cstring_as_ptr)] on by default - = note: that pointer will be invalid outside this expression + --> $DIR/cstring.rs:19:5 + | +19 | CString::new("foo").unwrap().as_ptr(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: #[deny(clippy::temporary_cstring_as_ptr)] on by default + = note: that pointer will be invalid outside this expression help: assign the `CString` to a variable to extend its lifetime - --> $DIR/cstring.rs:9:5 - | -9 | CString::new("foo").unwrap().as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/cstring.rs:19:5 + | +19 | CString::new("foo").unwrap().as_ptr(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index 84e2a1b6583..3c8ab8694a6 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::all)] diff --git a/tests/ui/cyclomatic_complexity.stderr b/tests/ui/cyclomatic_complexity.stderr index ff93f21e3ae..ddc2f5b159f 100644 --- a/tests/ui/cyclomatic_complexity.stderr +++ b/tests/ui/cyclomatic_complexity.stderr @@ -1,129 +1,115 @@ error: the function has a cyclomatic complexity of 28 - --> $DIR/cyclomatic_complexity.rs:7:1 + --> $DIR/cyclomatic_complexity.rs:17:1 | -7 | / fn main() { -8 | | if true { -9 | | println!("a"); -10 | | } +17 | / fn main() { +18 | | if true { +19 | | println!("a"); +20 | | } ... | -88 | | } -89 | | } +98 | | } +99 | | } | |_^ | = note: `-D clippy::cyclomatic-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 7 - --> $DIR/cyclomatic_complexity.rs:92:1 + --> $DIR/cyclomatic_complexity.rs:102:1 | -92 | / fn kaboom() { -93 | | let n = 0; -94 | | 'a: for i in 0..20 { -95 | | 'b: for j in i..20 { +102 | / fn kaboom() { +103 | | let n = 0; +104 | | 'a: for i in 0..20 { +105 | | 'b: for j in i..20 { ... | -110 | | } -111 | | } +120 | | } +121 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:138:1 + --> $DIR/cyclomatic_complexity.rs:148:1 | -138 | / fn lots_of_short_circuits() -> bool { -139 | | true && false && true && false && true && false && true -140 | | } +148 | / fn lots_of_short_circuits() -> bool { +149 | | true && false && true && false && true && false && true +150 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:143:1 + --> $DIR/cyclomatic_complexity.rs:153:1 | -143 | / fn lots_of_short_circuits2() -> bool { -144 | | true || false || true || false || true || false || true -145 | | } +153 | / fn lots_of_short_circuits2() -> bool { +154 | | true || false || true || false || true || false || true +155 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:148:1 + --> $DIR/cyclomatic_complexity.rs:158:1 | -148 | / fn baa() { -149 | | let x = || match 99 { -150 | | 0 => 0, -151 | | 1 => 1, +158 | / fn baa() { +159 | | let x = || match 99 { +160 | | 0 => 0, +161 | | 1 => 1, ... | -162 | | } -163 | | } +172 | | } +173 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:149:13 + --> $DIR/cyclomatic_complexity.rs:159:13 | -149 | let x = || match 99 { +159 | let x = || match 99 { | _____________^ -150 | | 0 => 0, -151 | | 1 => 1, -152 | | 2 => 2, +160 | | 0 => 0, +161 | | 1 => 1, +162 | | 2 => 2, ... | -156 | | _ => 42, -157 | | }; +166 | | _ => 42, +167 | | }; | |_____^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:166:1 - | -166 | / fn bar() { -167 | | match 99 { -168 | | 0 => println!("hi"), -169 | | _ => println!("bye"), -170 | | } -171 | | } + --> $DIR/cyclomatic_complexity.rs:176:1 + | +176 | / fn bar() { +177 | | match 99 { +178 | | 0 => println!("hi"), +179 | | _ => println!("bye"), +180 | | } +181 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:185:1 - | -185 | / fn barr() { -186 | | match 99 { -187 | | 0 => println!("hi"), -188 | | 1 => println!("bla"), -... | -191 | | } -192 | | } - | |_^ - | - = help: you could split it up into multiple smaller functions - -error: the function has a cyclomatic complexity of 3 --> $DIR/cyclomatic_complexity.rs:195:1 | -195 | / fn barr2() { +195 | / fn barr() { 196 | | match 99 { 197 | | 0 => println!("hi"), 198 | | 1 => println!("bla"), ... | -207 | | } -208 | | } +201 | | } +202 | | } | |_^ | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:211:1 +error: the function has a cyclomatic complexity of 3 + --> $DIR/cyclomatic_complexity.rs:205:1 | -211 | / fn barrr() { -212 | | match 99 { -213 | | 0 => println!("hi"), -214 | | 1 => panic!("bla"), +205 | / fn barr2() { +206 | | match 99 { +207 | | 0 => println!("hi"), +208 | | 1 => println!("bla"), ... | 217 | | } 218 | | } @@ -131,27 +117,27 @@ error: the function has a cyclomatic complexity of 2 | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 3 +error: the function has a cyclomatic complexity of 2 --> $DIR/cyclomatic_complexity.rs:221:1 | -221 | / fn barrr2() { +221 | / fn barrr() { 222 | | match 99 { 223 | | 0 => println!("hi"), 224 | | 1 => panic!("bla"), ... | -233 | | } -234 | | } +227 | | } +228 | | } | |_^ | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:237:1 +error: the function has a cyclomatic complexity of 3 + --> $DIR/cyclomatic_complexity.rs:231:1 | -237 | / fn barrrr() { -238 | | match 99 { -239 | | 0 => println!("hi"), -240 | | 1 => println!("bla"), +231 | / fn barrr2() { +232 | | match 99 { +233 | | 0 => println!("hi"), +234 | | 1 => panic!("bla"), ... | 243 | | } 244 | | } @@ -159,55 +145,56 @@ error: the function has a cyclomatic complexity of 2 | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 3 +error: the function has a cyclomatic complexity of 2 --> $DIR/cyclomatic_complexity.rs:247:1 | -247 | / fn barrrr2() { +247 | / fn barrrr() { 248 | | match 99 { 249 | | 0 => println!("hi"), 250 | | 1 => println!("bla"), ... | -259 | | } -260 | | } +253 | | } +254 | | } | |_^ | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:263:1 +error: the function has a cyclomatic complexity of 3 + --> $DIR/cyclomatic_complexity.rs:257:1 | -263 | / fn cake() { -264 | | if 4 == 5 { -265 | | println!("yea"); -266 | | } else { +257 | / fn barrrr2() { +258 | | match 99 { +259 | | 0 => println!("hi"), +260 | | 1 => println!("bla"), ... | -269 | | println!("whee"); +269 | | } 270 | | } | |_^ | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 4 - --> $DIR/cyclomatic_complexity.rs:274:1 +error: the function has a cyclomatic complexity of 2 + --> $DIR/cyclomatic_complexity.rs:273:1 | -274 | / pub fn read_file(input_path: &str) -> String { -275 | | use std::fs::File; -276 | | use std::io::{Read, Write}; -277 | | use std::path::Path; +273 | / fn cake() { +274 | | if 4 == 5 { +275 | | println!("yea"); +276 | | } else { ... | -299 | | } -300 | | } +279 | | println!("whee"); +280 | | } | |_^ | = help: you could split it up into multiple smaller functions -error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:305:1 +error: the function has a cyclomatic complexity of 4 + --> $DIR/cyclomatic_complexity.rs:284:1 | -305 | / fn void(void: Void) { -306 | | if true { -307 | | match void { -308 | | } +284 | / pub fn read_file(input_path: &str) -> String { +285 | | use std::fs::File; +286 | | use std::io::{Read, Write}; +287 | | use std::path::Path; +... | 309 | | } 310 | | } | |_^ @@ -215,56 +202,69 @@ error: the function has a cyclomatic complexity of 1 = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:319:1 - | -319 | / fn try() -> Result<i32, &'static str> { -320 | | match 5 { -321 | | 5 => Ok(5), -322 | | _ => return Err("bla"), -323 | | } -324 | | } + --> $DIR/cyclomatic_complexity.rs:315:1 + | +315 | / fn void(void: Void) { +316 | | if true { +317 | | match void { +318 | | } +319 | | } +320 | | } + | |_^ + | + = help: you could split it up into multiple smaller functions + +error: the function has a cyclomatic complexity of 1 + --> $DIR/cyclomatic_complexity.rs:329:1 + | +329 | / fn try() -> Result<i32, &'static str> { +330 | | match 5 { +331 | | 5 => Ok(5), +332 | | _ => return Err("bla"), +333 | | } +334 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:327:1 + --> $DIR/cyclomatic_complexity.rs:337:1 | -327 | / fn try_again() -> Result<i32, &'static str> { -328 | | let _ = try!(Ok(42)); -329 | | let _ = try!(Ok(43)); -330 | | let _ = try!(Ok(44)); +337 | / fn try_again() -> Result<i32, &'static str> { +338 | | let _ = try!(Ok(42)); +339 | | let _ = try!(Ok(43)); +340 | | let _ = try!(Ok(44)); ... | -339 | | } -340 | | } +349 | | } +350 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:343:1 + --> $DIR/cyclomatic_complexity.rs:353:1 | -343 | / fn early() -> Result<i32, &'static str> { -344 | | return Ok(5); -345 | | return Ok(5); -346 | | return Ok(5); +353 | / fn early() -> Result<i32, &'static str> { +354 | | return Ok(5); +355 | | return Ok(5); +356 | | return Ok(5); ... | -352 | | return Ok(5); -353 | | } +362 | | return Ok(5); +363 | | } | |_^ | = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 8 - --> $DIR/cyclomatic_complexity.rs:356:1 + --> $DIR/cyclomatic_complexity.rs:366:1 | -356 | / fn early_ret() -> i32 { -357 | | let a = if true { 42 } else { return 0; }; -358 | | let a = if a < 99 { 42 } else { return 0; }; -359 | | let a = if a < 99 { 42 } else { return 0; }; +366 | / fn early_ret() -> i32 { +367 | | let a = if true { 42 } else { return 0; }; +368 | | let a = if a < 99 { 42 } else { return 0; }; +369 | | let a = if a < 99 { 42 } else { return 0; }; ... | -372 | | } -373 | | } +382 | | } +383 | | } | |_^ | = help: you could split it up into multiple smaller functions diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index fd8be25e670..1699601aa50 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::cyclomatic_complexity)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.stderr b/tests/ui/cyclomatic_complexity_attr_used.stderr index f8342f0d9e5..f066e29ce75 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.stderr +++ b/tests/ui/cyclomatic_complexity_attr_used.stderr @@ -1,13 +1,13 @@ error: the function has a cyclomatic complexity of 3 - --> $DIR/cyclomatic_complexity_attr_used.rs:11:1 + --> $DIR/cyclomatic_complexity_attr_used.rs:21:1 | -11 | / fn kaboom() { -12 | | if 42 == 43 { -13 | | panic!(); -14 | | } else if "cake" == "lie" { -15 | | println!("what?"); -16 | | } -17 | | } +21 | / fn kaboom() { +22 | | if 42 == 43 { +23 | | panic!(); +24 | | } else if "cake" == "lie" { +25 | | println!("what?"); +26 | | } +27 | | } | |_^ | = note: `-D clippy::cyclomatic-complexity` implied by `-D warnings` diff --git a/tests/ui/decimal_literal_representation.rs b/tests/ui/decimal_literal_representation.rs index 472ea618571..f85ccd84722 100644 --- a/tests/ui/decimal_literal_representation.rs +++ b/tests/ui/decimal_literal_representation.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/decimal_literal_representation.stderr b/tests/ui/decimal_literal_representation.stderr index 343936bb7a2..d944c49066a 100644 --- a/tests/ui/decimal_literal_representation.stderr +++ b/tests/ui/decimal_literal_representation.stderr @@ -1,33 +1,33 @@ error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:18:9 + --> $DIR/decimal_literal_representation.rs:28:9 | -18 | 32_773, // 0x8005 +28 | 32_773, // 0x8005 | ^^^^^^ help: consider: `0x8005` | = note: `-D clippy::decimal-literal-representation` implied by `-D warnings` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:19:9 + --> $DIR/decimal_literal_representation.rs:29:9 | -19 | 65_280, // 0xFF00 +29 | 65_280, // 0xFF00 | ^^^^^^ help: consider: `0xFF00` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:20:9 + --> $DIR/decimal_literal_representation.rs:30:9 | -20 | 2_131_750_927, // 0x7F0F_F00F +30 | 2_131_750_927, // 0x7F0F_F00F | ^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:21:9 + --> $DIR/decimal_literal_representation.rs:31:9 | -21 | 2_147_483_647, // 0x7FFF_FFFF +31 | 2_147_483_647, // 0x7FFF_FFFF | ^^^^^^^^^^^^^ help: consider: `0x7FFF_FFFF` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:22:9 + --> $DIR/decimal_literal_representation.rs:32:9 | -22 | 4_042_322_160, // 0xF0F0_F0F0 +32 | 4_042_322_160, // 0xF0F0_F0F0 | ^^^^^^^^^^^^^ help: consider: `0xF0F0_F0F0` error: aborting due to 5 previous errors diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 248b4ec0066..d268746d765 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::default_trait_access)] diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index e3c263e7732..d6ae00214c0 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,51 +1,51 @@ error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:10:22 + --> $DIR/default_trait_access.rs:20:22 | -10 | let s1: String = Default::default(); +20 | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | = note: `-D clippy::default-trait-access` implied by `-D warnings` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:14:22 + --> $DIR/default_trait_access.rs:24:22 | -14 | let s3: String = D2::default(); +24 | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:16:22 + --> $DIR/default_trait_access.rs:26:22 | -16 | let s4: String = std::default::Default::default(); +26 | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:20:22 + --> $DIR/default_trait_access.rs:30:22 | -20 | let s6: String = default::Default::default(); +30 | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling GenericDerivedDefault<std::string::String>::default() is more clear than this expression - --> $DIR/default_trait_access.rs:30:46 + --> $DIR/default_trait_access.rs:40:46 | -30 | let s11: GenericDerivedDefault<String> = Default::default(); +40 | let s11: GenericDerivedDefault<String> = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()` error: Calling TupleDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:36:36 + --> $DIR/default_trait_access.rs:46:36 | -36 | let s14: TupleDerivedDefault = Default::default(); +46 | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: Calling ArrayDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:38:36 + --> $DIR/default_trait_access.rs:48:36 | -38 | let s15: ArrayDerivedDefault = Default::default(); +48 | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: Calling TupleStructDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:42:42 + --> $DIR/default_trait_access.rs:52:42 | -42 | let s17: TupleStructDerivedDefault = Default::default(); +52 | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` error: aborting due to 8 previous errors diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index f456c417223..a7e95ad5dde 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 6bbc0aebf9c..d44528ab28f 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,33 +1,33 @@ error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:4:8 - | -4 | #[warn(str_to_string)] - | ^^^^^^^^^^^^^ - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` + --> $DIR/deprecated.rs:14:8 + | +14 | #[warn(str_to_string)] + | ^^^^^^^^^^^^^ + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:6:8 - | -6 | #[warn(string_to_string)] - | ^^^^^^^^^^^^^^^^ + --> $DIR/deprecated.rs:16:8 + | +16 | #[warn(string_to_string)] + | ^^^^^^^^^^^^^^^^ error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:8:8 - | -8 | #[warn(unstable_as_slice)] - | ^^^^^^^^^^^^^^^^^ + --> $DIR/deprecated.rs:18:8 + | +18 | #[warn(unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^ error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:10:8 + --> $DIR/deprecated.rs:20:8 | -10 | #[warn(unstable_as_mut_slice)] +20 | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated.rs:12:8 + --> $DIR/deprecated.rs:22:8 | -12 | #[warn(misaligned_transmute)] +22 | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index ae54c0290bc..c5ce42586fa 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(untagged_unions)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index fa706f22b90..824b5b44cba 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -1,83 +1,67 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive.rs:17:10 + --> $DIR/derive.rs:27:10 | -17 | #[derive(Hash)] +27 | #[derive(Hash)] | ^^^^ | = note: #[deny(clippy::derive_hash_xor_eq)] on by default note: `PartialEq` implemented here - --> $DIR/derive.rs:20:1 + --> $DIR/derive.rs:30:1 | -20 | / impl PartialEq for Bar { -21 | | fn eq(&self, _: &Bar) -> bool { true } -22 | | } +30 | / impl PartialEq for Bar { +31 | | fn eq(&self, _: &Bar) -> bool { true } +32 | | } | |_^ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive.rs:24:10 + --> $DIR/derive.rs:34:10 | -24 | #[derive(Hash)] +34 | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> $DIR/derive.rs:27:1 + --> $DIR/derive.rs:37:1 | -27 | / impl PartialEq<Baz> for Baz { -28 | | fn eq(&self, _: &Baz) -> bool { true } -29 | | } +37 | / impl PartialEq<Baz> for Baz { +38 | | fn eq(&self, _: &Baz) -> bool { true } +39 | | } | |_^ error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive.rs:34:1 + --> $DIR/derive.rs:44:1 | -34 | / impl Hash for Bah { -35 | | fn hash<H: Hasher>(&self, _: &mut H) {} -36 | | } +44 | / impl Hash for Bah { +45 | | fn hash<H: Hasher>(&self, _: &mut H) {} +46 | | } | |_^ | note: `PartialEq` implemented here - --> $DIR/derive.rs:31:10 + --> $DIR/derive.rs:41:10 | -31 | #[derive(PartialEq)] +41 | #[derive(PartialEq)] | ^^^^^^^^^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:41:1 + --> $DIR/derive.rs:51:1 | -41 | / impl Clone for Qux { -42 | | fn clone(&self) -> Self { Qux } -43 | | } +51 | / impl Clone for Qux { +52 | | fn clone(&self) -> Self { Qux } +53 | | } | |_^ | = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:41:1 + --> $DIR/derive.rs:51:1 | -41 | / impl Clone for Qux { -42 | | fn clone(&self) -> Self { Qux } -43 | | } - | |_^ - -error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:65:1 - | -65 | / impl<'a> Clone for Lt<'a> { -66 | | fn clone(&self) -> Self { unimplemented!() } -67 | | } - | |_^ - | -note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:65:1 - | -65 | / impl<'a> Clone for Lt<'a> { -66 | | fn clone(&self) -> Self { unimplemented!() } -67 | | } +51 | / impl Clone for Qux { +52 | | fn clone(&self) -> Self { Qux } +53 | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type --> $DIR/derive.rs:75:1 | -75 | / impl Clone for BigArray { +75 | / impl<'a> Clone for Lt<'a> { 76 | | fn clone(&self) -> Self { unimplemented!() } 77 | | } | |_^ @@ -85,7 +69,7 @@ error: you are implementing `Clone` explicitly on a `Copy` type note: consider deriving `Clone` or removing `Copy` --> $DIR/derive.rs:75:1 | -75 | / impl Clone for BigArray { +75 | / impl<'a> Clone for Lt<'a> { 76 | | fn clone(&self) -> Self { unimplemented!() } 77 | | } | |_^ @@ -93,7 +77,7 @@ note: consider deriving `Clone` or removing `Copy` error: you are implementing `Clone` explicitly on a `Copy` type --> $DIR/derive.rs:85:1 | -85 | / impl Clone for FnPtr { +85 | / impl Clone for BigArray { 86 | | fn clone(&self) -> Self { unimplemented!() } 87 | | } | |_^ @@ -101,10 +85,26 @@ error: you are implementing `Clone` explicitly on a `Copy` type note: consider deriving `Clone` or removing `Copy` --> $DIR/derive.rs:85:1 | -85 | / impl Clone for FnPtr { +85 | / impl Clone for BigArray { 86 | | fn clone(&self) -> Self { unimplemented!() } 87 | | } | |_^ +error: you are implementing `Clone` explicitly on a `Copy` type + --> $DIR/derive.rs:95:1 + | +95 | / impl Clone for FnPtr { +96 | | fn clone(&self) -> Self { unimplemented!() } +97 | | } + | |_^ + | +note: consider deriving `Clone` or removing `Copy` + --> $DIR/derive.rs:95:1 + | +95 | / impl Clone for FnPtr { +96 | | fn clone(&self) -> Self { unimplemented!() } +97 | | } + | |_^ + error: aborting due to 7 previous errors diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index a8284dca326..9cf6f22fb27 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(never_type)] diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 8e86a7734dc..fea2bd1aa41 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -1,39 +1,39 @@ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:20:10 + --> $DIR/diverging_sub_expression.rs:30:10 | -20 | b || diverge(); +30 | b || diverge(); | ^^^^^^^^^ | = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:21:10 + --> $DIR/diverging_sub_expression.rs:31:10 | -21 | b || A.foo(); +31 | b || A.foo(); | ^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:30:26 + --> $DIR/diverging_sub_expression.rs:40:26 | -30 | 6 => true || return, +40 | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:31:26 + --> $DIR/diverging_sub_expression.rs:41:26 | -31 | 7 => true || continue, +41 | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:34:26 + --> $DIR/diverging_sub_expression.rs:44:26 | -34 | 3 => true || diverge(), +44 | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:39:26 + --> $DIR/diverging_sub_expression.rs:49:26 | -39 | _ => true || break, +49 | _ => true || break, | ^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index 395ff217497..dbbac901b03 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(alloc)] diff --git a/tests/ui/dlist.stderr b/tests/ui/dlist.stderr index 5322075208c..b3dc6095cd8 100644 --- a/tests/ui/dlist.stderr +++ b/tests/ui/dlist.stderr @@ -1,48 +1,48 @@ error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:14:16 + --> $DIR/dlist.rs:24:16 | -14 | type Baz = LinkedList<u8>; +24 | type Baz = LinkedList<u8>; | ^^^^^^^^^^^^^^ | = note: `-D clippy::linkedlist` implied by `-D warnings` = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:15:12 + --> $DIR/dlist.rs:25:12 | -15 | fn foo(LinkedList<u8>); +25 | fn foo(LinkedList<u8>); | ^^^^^^^^^^^^^^ | = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:16:24 + --> $DIR/dlist.rs:26:24 | -16 | const BAR : Option<LinkedList<u8>>; +26 | const BAR : Option<LinkedList<u8>>; | ^^^^^^^^^^^^^^ | = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:27:15 + --> $DIR/dlist.rs:37:15 | -27 | fn foo(_: LinkedList<u8>) {} +37 | fn foo(_: LinkedList<u8>) {} | ^^^^^^^^^^^^^^ | = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:30:39 + --> $DIR/dlist.rs:40:39 | -30 | pub fn test(my_favourite_linked_list: LinkedList<u8>) { +40 | pub fn test(my_favourite_linked_list: LinkedList<u8>) { | ^^^^^^^^^^^^^^ | = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:34:29 + --> $DIR/dlist.rs:44:29 | -34 | pub fn test_ret() -> Option<LinkedList<u8>> { +44 | pub fn test_ret() -> Option<LinkedList<u8>> { | ^^^^^^^^^^^^^^ | = help: a VecDeque might work diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index d48007a9347..85e688e0f07 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] //! This file tests for the DOC_MARKDOWN lint diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index c781f36db7a..69fa4e32cd3 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -1,183 +1,183 @@ error: you should put `DOC_MARKDOWN` between ticks in the documentation - --> $DIR/doc.rs:3:29 - | -3 | //! This file tests for the DOC_MARKDOWN lint - | ^^^^^^^^^^^^ - | - = note: `-D clippy::doc-markdown` implied by `-D warnings` + --> $DIR/doc.rs:13:29 + | +13 | //! This file tests for the DOC_MARKDOWN lint + | ^^^^^^^^^^^^ + | + = note: `-D clippy::doc-markdown` implied by `-D warnings` error: you should put `foo_bar` between ticks in the documentation - --> $DIR/doc.rs:10:9 + --> $DIR/doc.rs:20:9 | -10 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) +20 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^ error: you should put `foo::bar` between ticks in the documentation - --> $DIR/doc.rs:10:51 + --> $DIR/doc.rs:20:51 | -10 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) +20 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^^ error: you should put `Foo::some_fun` between ticks in the documentation - --> $DIR/doc.rs:11:84 + --> $DIR/doc.rs:21:84 | -11 | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun +21 | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ error: you should put `a::global:path` between ticks in the documentation - --> $DIR/doc.rs:13:15 + --> $DIR/doc.rs:23:15 | -13 | /// Here be ::a::global:path. +23 | /// Here be ::a::global:path. | ^^^^^^^^^^^^^^ error: you should put `NotInCodeBlock` between ticks in the documentation - --> $DIR/doc.rs:14:22 + --> $DIR/doc.rs:24:22 | -14 | /// That's not code ~NotInCodeBlock~. +24 | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:15:5 + --> $DIR/doc.rs:25:5 | -15 | /// be_sure_we_got_to_the_end_of_it +25 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:29:5 + --> $DIR/doc.rs:39:5 | -29 | /// be_sure_we_got_to_the_end_of_it +39 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:36:5 + --> $DIR/doc.rs:46:5 | -36 | /// be_sure_we_got_to_the_end_of_it +46 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:50:5 + --> $DIR/doc.rs:60:5 | -50 | /// be_sure_we_got_to_the_end_of_it +60 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:54:22 + --> $DIR/doc.rs:64:22 | -54 | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. +64 | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:57:21 + --> $DIR/doc.rs:67:21 | -57 | /// It can also be [inline_link2]. +67 | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:67:5 + --> $DIR/doc.rs:77:5 | -67 | /// be_sure_we_got_to_the_end_of_it +77 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:75:8 + --> $DIR/doc.rs:85:8 | -75 | /// ## CamelCaseThing +85 | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:78:7 + --> $DIR/doc.rs:88:7 | -78 | /// # CamelCaseThing +88 | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:80:22 + --> $DIR/doc.rs:90:22 | -80 | /// Not a title #897 CamelCaseThing +90 | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:81:5 + --> $DIR/doc.rs:91:5 | -81 | /// be_sure_we_got_to_the_end_of_it +91 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:88:5 + --> $DIR/doc.rs:98:5 | -88 | /// be_sure_we_got_to_the_end_of_it +98 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:101:5 + --> $DIR/doc.rs:111:5 | -101 | /// be_sure_we_got_to_the_end_of_it +111 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:112:42 + --> $DIR/doc.rs:122:42 | -112 | /** E.g. serialization of an empty list: FooBar +122 | /** E.g. serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:117:5 + --> $DIR/doc.rs:127:5 | -117 | And BarQuz too. +127 | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:118:1 + --> $DIR/doc.rs:128:1 | -118 | be_sure_we_got_to_the_end_of_it +128 | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:123:42 + --> $DIR/doc.rs:133:42 | -123 | /** E.g. serialization of an empty list: FooBar +133 | /** E.g. serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:128:5 + --> $DIR/doc.rs:138:5 | -128 | And BarQuz too. +138 | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:129:1 + --> $DIR/doc.rs:139:1 | -129 | be_sure_we_got_to_the_end_of_it +139 | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:140:5 + --> $DIR/doc.rs:150:5 | -140 | /// be_sure_we_got_to_the_end_of_it +150 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:167:13 + --> $DIR/doc.rs:177:13 | -167 | /// Not ok: http://www.unicode.org +177 | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:168:13 + --> $DIR/doc.rs:178:13 | -168 | /// Not ok: https://www.unicode.org +178 | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:169:13 + --> $DIR/doc.rs:179:13 | -169 | /// Not ok: http://www.unicode.org/ +179 | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:170:13 + --> $DIR/doc.rs:180:13 | -170 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels +180 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 30 previous errors diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index 2c8f116281b..555f35884f9 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { let x = 1; let y = 2; diff --git a/tests/ui/double_comparison.stderr b/tests/ui/double_comparison.stderr index e6a0e976414..646b6f13fab 100644 --- a/tests/ui/double_comparison.stderr +++ b/tests/ui/double_comparison.stderr @@ -1,51 +1,51 @@ error: This binary expression can be simplified - --> $DIR/double_comparison.rs:4:8 - | -4 | if x == y || x < y { - | ^^^^^^^^^^^^^^^ help: try: `x <= y` - | - = note: `-D clippy::double-comparisons` implied by `-D warnings` + --> $DIR/double_comparison.rs:14:8 + | +14 | if x == y || x < y { + | ^^^^^^^^^^^^^^^ help: try: `x <= y` + | + = note: `-D clippy::double-comparisons` implied by `-D warnings` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:7:8 - | -7 | if x < y || x == y { - | ^^^^^^^^^^^^^^^ help: try: `x <= y` + --> $DIR/double_comparison.rs:17:8 + | +17 | if x < y || x == y { + | ^^^^^^^^^^^^^^^ help: try: `x <= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:10:8 + --> $DIR/double_comparison.rs:20:8 | -10 | if x == y || x > y { +20 | if x == y || x > y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:13:8 + --> $DIR/double_comparison.rs:23:8 | -13 | if x > y || x == y { +23 | if x > y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:16:8 + --> $DIR/double_comparison.rs:26:8 | -16 | if x < y || x > y { +26 | if x < y || x > y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:19:8 + --> $DIR/double_comparison.rs:29:8 | -19 | if x > y || x < y { +29 | if x > y || x < y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:22:8 + --> $DIR/double_comparison.rs:32:8 | -22 | if x <= y && x >= y { +32 | if x <= y && x >= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:25:8 + --> $DIR/double_comparison.rs:35:8 | -25 | if x >= y && x <= y { +35 | if x >= y && x <= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` error: aborting due to 8 previous errors diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index 0ec13900f99..31e7a508fcd 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/double_neg.stderr b/tests/ui/double_neg.stderr index 02202dbd63c..cf0292f7af1 100644 --- a/tests/ui/double_neg.stderr +++ b/tests/ui/double_neg.stderr @@ -1,10 +1,10 @@ error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op - --> $DIR/double_neg.rs:9:5 - | -9 | --x; - | ^^^ - | - = note: `-D clippy::double-neg` implied by `-D warnings` + --> $DIR/double_neg.rs:19:5 + | +19 | --x; + | ^^^ + | + = note: `-D clippy::double-neg` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index c217972fa6a..18ff140c3ca 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr index 3e38db730e0..727b2c4ef42 100644 --- a/tests/ui/double_parens.stderr +++ b/tests/ui/double_parens.stderr @@ -1,39 +1,39 @@ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:16:5 + --> $DIR/double_parens.rs:26:5 | -16 | ((0)) +26 | ((0)) | ^^^^^ | = note: `-D clippy::double-parens` implied by `-D warnings` error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:20:14 + --> $DIR/double_parens.rs:30:14 | -20 | dummy_fn((0)); +30 | dummy_fn((0)); | ^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:24:20 + --> $DIR/double_parens.rs:34:20 | -24 | x.dummy_method((0)); +34 | x.dummy_method((0)); | ^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:28:5 + --> $DIR/double_parens.rs:38:5 | -28 | ((1, 2)) +38 | ((1, 2)) | ^^^^^^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:32:5 + --> $DIR/double_parens.rs:42:5 | -32 | (()) +42 | (()) | ^^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:54:16 + --> $DIR/double_parens.rs:64:16 | -54 | assert_eq!(((1, 2)), (1, 2), "Error"); +64 | assert_eq!(((1, 2)), (1, 2), "Error"); | ^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index aa70490f8ab..8b2b96a14d3 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 043067fe8af..ef337ae6691 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -1,75 +1,75 @@ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:33:5 + --> $DIR/drop_forget_copy.rs:43:5 | -33 | drop(s1); +43 | drop(s1); | ^^^^^^^^ | = note: `-D clippy::drop-copy` implied by `-D warnings` note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:33:10 + --> $DIR/drop_forget_copy.rs:43:10 | -33 | drop(s1); +43 | drop(s1); | ^^ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:34:5 + --> $DIR/drop_forget_copy.rs:44:5 | -34 | drop(s2); +44 | drop(s2); | ^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:34:10 + --> $DIR/drop_forget_copy.rs:44:10 | -34 | drop(s2); +44 | drop(s2); | ^^ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:36:5 + --> $DIR/drop_forget_copy.rs:46:5 | -36 | drop(s4); +46 | drop(s4); | ^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:36:10 + --> $DIR/drop_forget_copy.rs:46:10 | -36 | drop(s4); +46 | drop(s4); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:39:5 + --> $DIR/drop_forget_copy.rs:49:5 | -39 | forget(s1); +49 | forget(s1); | ^^^^^^^^^^ | = note: `-D clippy::forget-copy` implied by `-D warnings` note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:39:12 + --> $DIR/drop_forget_copy.rs:49:12 | -39 | forget(s1); +49 | forget(s1); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:40:5 + --> $DIR/drop_forget_copy.rs:50:5 | -40 | forget(s2); +50 | forget(s2); | ^^^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:40:12 + --> $DIR/drop_forget_copy.rs:50:12 | -40 | forget(s2); +50 | forget(s2); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:42:5 + --> $DIR/drop_forget_copy.rs:52:5 | -42 | forget(s4); +52 | forget(s4); | ^^^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:42:12 + --> $DIR/drop_forget_copy.rs:52:12 | -42 | forget(s4); +52 | forget(s4); | ^^ error: aborting due to 6 previous errors diff --git a/tests/ui/drop_forget_ref.rs b/tests/ui/drop_forget_ref.rs index bb4781db71b..0f36b823e0f 100644 --- a/tests/ui/drop_forget_ref.rs +++ b/tests/ui/drop_forget_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/drop_forget_ref.stderr b/tests/ui/drop_forget_ref.stderr index 227918f5917..15661ef1d2b 100644 --- a/tests/ui/drop_forget_ref.stderr +++ b/tests/ui/drop_forget_ref.stderr @@ -1,219 +1,219 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:12:5 + --> $DIR/drop_forget_ref.rs:22:5 | -12 | drop(&SomeStruct); +22 | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:12:10 + --> $DIR/drop_forget_ref.rs:22:10 | -12 | drop(&SomeStruct); +22 | drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:13:5 + --> $DIR/drop_forget_ref.rs:23:5 | -13 | forget(&SomeStruct); +23 | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:13:12 + --> $DIR/drop_forget_ref.rs:23:12 | -13 | forget(&SomeStruct); +23 | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:16:5 + --> $DIR/drop_forget_ref.rs:26:5 | -16 | drop(&owned1); +26 | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:16:10 + --> $DIR/drop_forget_ref.rs:26:10 | -16 | drop(&owned1); +26 | drop(&owned1); | ^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:17:5 + --> $DIR/drop_forget_ref.rs:27:5 | -17 | drop(&&owned1); +27 | drop(&&owned1); | ^^^^^^^^^^^^^^ | note: argument has type &&SomeStruct - --> $DIR/drop_forget_ref.rs:17:10 + --> $DIR/drop_forget_ref.rs:27:10 | -17 | drop(&&owned1); +27 | drop(&&owned1); | ^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:18:5 + --> $DIR/drop_forget_ref.rs:28:5 | -18 | drop(&mut owned1); +28 | drop(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:18:10 + --> $DIR/drop_forget_ref.rs:28:10 | -18 | drop(&mut owned1); +28 | drop(&mut owned1); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:21:5 + --> $DIR/drop_forget_ref.rs:31:5 | -21 | forget(&owned2); +31 | forget(&owned2); | ^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:21:12 + --> $DIR/drop_forget_ref.rs:31:12 | -21 | forget(&owned2); +31 | forget(&owned2); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:22:5 + --> $DIR/drop_forget_ref.rs:32:5 | -22 | forget(&&owned2); +32 | forget(&&owned2); | ^^^^^^^^^^^^^^^^ | note: argument has type &&SomeStruct - --> $DIR/drop_forget_ref.rs:22:12 + --> $DIR/drop_forget_ref.rs:32:12 | -22 | forget(&&owned2); +32 | forget(&&owned2); | ^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:23:5 + --> $DIR/drop_forget_ref.rs:33:5 | -23 | forget(&mut owned2); +33 | forget(&mut owned2); | ^^^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:23:12 + --> $DIR/drop_forget_ref.rs:33:12 | -23 | forget(&mut owned2); +33 | forget(&mut owned2); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:27:5 + --> $DIR/drop_forget_ref.rs:37:5 | -27 | drop(reference1); +37 | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:27:10 + --> $DIR/drop_forget_ref.rs:37:10 | -27 | drop(reference1); +37 | drop(reference1); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:28:5 + --> $DIR/drop_forget_ref.rs:38:5 | -28 | forget(&*reference1); +38 | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:28:12 + --> $DIR/drop_forget_ref.rs:38:12 | -28 | forget(&*reference1); +38 | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:31:5 + --> $DIR/drop_forget_ref.rs:41:5 | -31 | drop(reference2); +41 | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:31:10 + --> $DIR/drop_forget_ref.rs:41:10 | -31 | drop(reference2); +41 | drop(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:33:5 + --> $DIR/drop_forget_ref.rs:43:5 | -33 | forget(reference3); +43 | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:33:12 + --> $DIR/drop_forget_ref.rs:43:12 | -33 | forget(reference3); +43 | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:36:5 + --> $DIR/drop_forget_ref.rs:46:5 | -36 | drop(reference4); +46 | drop(reference4); | ^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:36:10 + --> $DIR/drop_forget_ref.rs:46:10 | -36 | drop(reference4); +46 | drop(reference4); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:37:5 + --> $DIR/drop_forget_ref.rs:47:5 | -37 | forget(reference4); +47 | forget(reference4); | ^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:37:12 + --> $DIR/drop_forget_ref.rs:47:12 | -37 | forget(reference4); +47 | forget(reference4); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:42:5 + --> $DIR/drop_forget_ref.rs:52:5 | -42 | drop(&val); +52 | drop(&val); | ^^^^^^^^^^ | note: argument has type &T - --> $DIR/drop_forget_ref.rs:42:10 + --> $DIR/drop_forget_ref.rs:52:10 | -42 | drop(&val); +52 | drop(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:48:5 + --> $DIR/drop_forget_ref.rs:58:5 | -48 | forget(&val); +58 | forget(&val); | ^^^^^^^^^^^^ | note: argument has type &T - --> $DIR/drop_forget_ref.rs:48:12 + --> $DIR/drop_forget_ref.rs:58:12 | -48 | forget(&val); +58 | forget(&val); | ^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:56:5 + --> $DIR/drop_forget_ref.rs:66:5 | -56 | std::mem::drop(&SomeStruct); +66 | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:56:20 + --> $DIR/drop_forget_ref.rs:66:20 | -56 | std::mem::drop(&SomeStruct); +66 | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:59:5 + --> $DIR/drop_forget_ref.rs:69:5 | -59 | std::mem::forget(&SomeStruct); +69 | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:59:22 + --> $DIR/drop_forget_ref.rs:69:22 | -59 | std::mem::forget(&SomeStruct); +69 | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ error: aborting due to 18 previous errors diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index e54920c1b56..25b2a0ba8b6 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index 70714534653..87b5c5e19d9 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -1,10 +1,10 @@ error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult - --> $DIR/duplicate_underscore_argument.rs:7:23 - | -7 | fn join_the_dark_side(darth: i32, _darth: i32) {} - | ^^^^^ - | - = note: `-D clippy::duplicate-underscore-argument` implied by `-D warnings` + --> $DIR/duplicate_underscore_argument.rs:17:23 + | +17 | fn join_the_dark_side(darth: i32, _darth: i32) {} + | ^^^^^ + | + = note: `-D clippy::duplicate-underscore-argument` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/duration_subsec.rs b/tests/ui/duration_subsec.rs index d732a0228d5..75352ad182b 100644 --- a/tests/ui/duration_subsec.rs +++ b/tests/ui/duration_subsec.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::duration_subsec)] diff --git a/tests/ui/duration_subsec.stderr b/tests/ui/duration_subsec.stderr index c23b041a80a..854af9dcb51 100644 --- a/tests/ui/duration_subsec.stderr +++ b/tests/ui/duration_subsec.stderr @@ -1,33 +1,33 @@ error: Calling `subsec_millis()` is more concise than this calculation - --> $DIR/duration_subsec.rs:10:24 + --> $DIR/duration_subsec.rs:20:24 | -10 | let bad_millis_1 = dur.subsec_micros() / 1_000; +20 | let bad_millis_1 = dur.subsec_micros() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` | = note: `-D clippy::duration-subsec` implied by `-D warnings` error: Calling `subsec_millis()` is more concise than this calculation - --> $DIR/duration_subsec.rs:11:24 + --> $DIR/duration_subsec.rs:21:24 | -11 | let bad_millis_2 = dur.subsec_nanos() / 1_000_000; +21 | let bad_millis_2 = dur.subsec_nanos() / 1_000_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:16:22 + --> $DIR/duration_subsec.rs:26:22 | -16 | let bad_micros = dur.subsec_nanos() / 1_000; +26 | let bad_micros = dur.subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:21:13 + --> $DIR/duration_subsec.rs:31:13 | -21 | let _ = (&dur).subsec_nanos() / 1_000; +31 | let _ = (&dur).subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:25:13 + --> $DIR/duration_subsec.rs:35:13 | -25 | let _ = dur.subsec_nanos() / NANOS_IN_MICRO; +35 | let _ = dur.subsec_nanos() / NANOS_IN_MICRO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` error: aborting due to 5 previous errors diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index 3776aecf54f..56987d0d64d 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all)] diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index a352546ce9f..9eddd4ab30d 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -1,21 +1,21 @@ error: if expression with an `else if`, but without a final `else` - --> $DIR/else_if_without_else.rs:41:12 + --> $DIR/else_if_without_else.rs:51:12 | -41 | } else if bla2() { //~ ERROR else if without else +51 | } else if bla2() { //~ ERROR else if without else | ____________^ -42 | | println!("else if"); -43 | | } +52 | | println!("else if"); +53 | | } | |_____^ help: add an `else` block here | = note: `-D clippy::else-if-without-else` implied by `-D warnings` error: if expression with an `else if`, but without a final `else` - --> $DIR/else_if_without_else.rs:49:12 + --> $DIR/else_if_without_else.rs:59:12 | -49 | } else if bla3() { //~ ERROR else if without else +59 | } else if bla3() { //~ ERROR else if without else | ____________^ -50 | | println!("else if 2"); -51 | | } +60 | | println!("else if 2"); +61 | | } | |_____^ help: add an `else` block here error: aborting due to 2 previous errors diff --git a/tests/ui/empty_enum.rs b/tests/ui/empty_enum.rs index 3398b71eead..cd63acb9ed6 100644 --- a/tests/ui/empty_enum.rs +++ b/tests/ui/empty_enum.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index f198793fed4..9d6691c974d 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -1,15 +1,15 @@ error: enum with no variants - --> $DIR/empty_enum.rs:7:1 - | -7 | enum Empty {} - | ^^^^^^^^^^^^^ - | - = note: `-D clippy::empty-enum` implied by `-D warnings` + --> $DIR/empty_enum.rs:17:1 + | +17 | enum Empty {} + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::empty-enum` implied by `-D warnings` help: consider using the uninhabited type `!` or a wrapper around it - --> $DIR/empty_enum.rs:7:1 - | -7 | enum Empty {} - | ^^^^^^^^^^^^^ + --> $DIR/empty_enum.rs:17:1 + | +17 | enum Empty {} + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index c46a0496a73..8aa2e8a1f46 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::empty_line_after_outer_attr)] diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index 7bcec54a600..e742c0b6615 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,53 +1,53 @@ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:5:1 - | -5 | / #[crate_type = "lib"] -6 | | -7 | | /// some comment -8 | | fn with_one_newline_and_comment() { assert!(true) } - | |_ - | - = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` + --> $DIR/empty_line_after_outer_attribute.rs:15:1 + | +15 | / #[crate_type = "lib"] +16 | | +17 | | /// some comment +18 | | fn with_one_newline_and_comment() { assert!(true) } + | |_ + | + = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:17:1 + --> $DIR/empty_line_after_outer_attribute.rs:27:1 | -17 | / #[crate_type = "lib"] -18 | | -19 | | fn with_one_newline() { assert!(true) } +27 | / #[crate_type = "lib"] +28 | | +29 | | fn with_one_newline() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:22:1 + --> $DIR/empty_line_after_outer_attribute.rs:32:1 | -22 | / #[crate_type = "lib"] -23 | | -24 | | -25 | | fn with_two_newlines() { assert!(true) } +32 | / #[crate_type = "lib"] +33 | | +34 | | +35 | | fn with_two_newlines() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:29:1 + --> $DIR/empty_line_after_outer_attribute.rs:39:1 | -29 | / #[crate_type = "lib"] -30 | | -31 | | enum Baz { +39 | / #[crate_type = "lib"] +40 | | +41 | | enum Baz { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:37:1 + --> $DIR/empty_line_after_outer_attribute.rs:47:1 | -37 | / #[crate_type = "lib"] -38 | | -39 | | struct Foo { +47 | / #[crate_type = "lib"] +48 | | +49 | | struct Foo { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:45:1 + --> $DIR/empty_line_after_outer_attribute.rs:55:1 | -45 | / #[crate_type = "lib"] -46 | | -47 | | mod foo { +55 | / #[crate_type = "lib"] +56 | | +57 | | mod foo { | |_ error: aborting due to 6 previous errors diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 955b0a6e917..0bab6bf332e 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused, clippy::needless_pass_by_value)] diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index cffe8b23235..60e5ae893b6 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -1,45 +1,45 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:13:5 + --> $DIR/entry.rs:23:5 | -13 | if !m.contains_key(&k) { m.insert(k, v); } +23 | if !m.contains_key(&k) { m.insert(k, v); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k).or_insert(v)` | = note: `-D clippy::map-entry` implied by `-D warnings` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:17:5 + --> $DIR/entry.rs:27:5 | -17 | if !m.contains_key(&k) { foo(); m.insert(k, v); } +27 | if !m.contains_key(&k) { foo(); m.insert(k, v); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:21:5 + --> $DIR/entry.rs:31:5 | -21 | if !m.contains_key(&k) { m.insert(k, v) } else { None }; +31 | if !m.contains_key(&k) { m.insert(k, v) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:25:5 + --> $DIR/entry.rs:35:5 | -25 | if m.contains_key(&k) { None } else { m.insert(k, v) }; +35 | if m.contains_key(&k) { None } else { m.insert(k, v) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:29:5 + --> $DIR/entry.rs:39:5 | -29 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; +39 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:33:5 + --> $DIR/entry.rs:43:5 | -33 | if m.contains_key(&k) { None } else { foo(); m.insert(k, v) }; +43 | if m.contains_key(&k) { None } else { foo(); m.insert(k, v) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `BTreeMap` - --> $DIR/entry.rs:37:5 + --> $DIR/entry.rs:47:5 | -37 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; +47 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` error: aborting due to 7 previous errors diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index 47082f8f3e6..e24e2fd8eb3 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all, clippy::pedantic)] diff --git a/tests/ui/enum_glob_use.stderr b/tests/ui/enum_glob_use.stderr index bb1d19e41b2..2dac4a2b106 100644 --- a/tests/ui/enum_glob_use.stderr +++ b/tests/ui/enum_glob_use.stderr @@ -1,15 +1,15 @@ error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:6:1 - | -6 | use std::cmp::Ordering::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::enum-glob-use` implied by `-D warnings` + --> $DIR/enum_glob_use.rs:16:1 + | +16 | use std::cmp::Ordering::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::enum-glob-use` implied by `-D warnings` error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:12:1 + --> $DIR/enum_glob_use.rs:22:1 | -12 | use self::Enum::*; +22 | use self::Enum::*; | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index 4ddb7207a30..8a51e2f58f1 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(non_ascii_idents)] diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index bd083e7e069..7b63fab3a99 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -1,101 +1,101 @@ error: Variant name ends with the enum's name - --> $DIR/enum_variants.rs:16:5 + --> $DIR/enum_variants.rs:26:5 | -16 | cFoo, +26 | cFoo, | ^^^^ | = note: `-D clippy::enum-variant-names` implied by `-D warnings` error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:27:5 + --> $DIR/enum_variants.rs:37:5 | -27 | FoodGood, +37 | FoodGood, | ^^^^^^^^ error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:28:5 + --> $DIR/enum_variants.rs:38:5 | -28 | FoodMiddle, +38 | FoodMiddle, | ^^^^^^^^^^ error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:29:5 + --> $DIR/enum_variants.rs:39:5 | -29 | FoodBad, +39 | FoodBad, | ^^^^^^^ error: All variants have the same prefix: `Food` - --> $DIR/enum_variants.rs:26:1 + --> $DIR/enum_variants.rs:36:1 | -26 | / enum Food { -27 | | FoodGood, -28 | | FoodMiddle, -29 | | FoodBad, -30 | | } +36 | / enum Food { +37 | | FoodGood, +38 | | FoodMiddle, +39 | | FoodBad, +40 | | } | |_^ | = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `CallType` - --> $DIR/enum_variants.rs:36:1 + --> $DIR/enum_variants.rs:46:1 | -36 | / enum BadCallType { -37 | | CallTypeCall, -38 | | CallTypeCreate, -39 | | CallTypeDestroy, -40 | | } +46 | / enum BadCallType { +47 | | CallTypeCall, +48 | | CallTypeCreate, +49 | | CallTypeDestroy, +50 | | } | |_^ | = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `Constant` - --> $DIR/enum_variants.rs:47:1 + --> $DIR/enum_variants.rs:57:1 | -47 | / enum Consts { -48 | | ConstantInt, -49 | | ConstantCake, -50 | | ConstantLie, -51 | | } +57 | / enum Consts { +58 | | ConstantInt, +59 | | ConstantCake, +60 | | ConstantLie, +61 | | } | |_^ | = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `With` - --> $DIR/enum_variants.rs:80:1 + --> $DIR/enum_variants.rs:90:1 | -80 | / enum Seallll { -81 | | WithOutCake, -82 | | WithOutTea, -83 | | WithOut, -84 | | } +90 | / enum Seallll { +91 | | WithOutCake, +92 | | WithOutTea, +93 | | WithOut, +94 | | } | |_^ | = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `Prefix` - --> $DIR/enum_variants.rs:86:1 - | -86 | / enum NonCaps { -87 | | Prefix的, -88 | | PrefixTea, -89 | | PrefixCake, -90 | | } - | |_^ - | - = help: remove the prefixes and use full paths to the variants instead of glob imports + --> $DIR/enum_variants.rs:96:1 + | +96 | / enum NonCaps { +97 | | Prefix的, +98 | | PrefixTea, +99 | | PrefixCake, +100 | | } + | |_^ + | + = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `With` - --> $DIR/enum_variants.rs:92:1 - | -92 | / pub enum PubSeall { -93 | | WithOutCake, -94 | | WithOutTea, -95 | | WithOut, -96 | | } - | |_^ - | - = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings` - = help: remove the prefixes and use full paths to the variants instead of glob imports + --> $DIR/enum_variants.rs:102:1 + | +102 | / pub enum PubSeall { +103 | | WithOutCake, +104 | | WithOutTea, +105 | | WithOut, +106 | | } + | |_^ + | + = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings` + = help: remove the prefixes and use full paths to the variants instead of glob imports error: aborting due to 10 previous errors diff --git a/tests/ui/enums_clike.rs b/tests/ui/enums_clike.rs index 8212f12b3db..17983255030 100644 --- a/tests/ui/enums_clike.rs +++ b/tests/ui/enums_clike.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] // ignore-x86 diff --git a/tests/ui/enums_clike.stderr b/tests/ui/enums_clike.stderr index cccf4ed030c..27b184ea3cc 100644 --- a/tests/ui/enums_clike.stderr +++ b/tests/ui/enums_clike.stderr @@ -1,51 +1,51 @@ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:12:5 + --> $DIR/enums_clike.rs:22:5 | -12 | X = 0x1_0000_0000, +22 | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings` error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:19:5 + --> $DIR/enums_clike.rs:29:5 | -19 | X = 0x1_0000_0000, +29 | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:22:5 + --> $DIR/enums_clike.rs:32:5 | -22 | A = 0xFFFF_FFFF, +32 | A = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:29:5 + --> $DIR/enums_clike.rs:39:5 | -29 | Z = 0xFFFF_FFFF, +39 | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:30:5 + --> $DIR/enums_clike.rs:40:5 | -30 | A = 0x1_0000_0000, +40 | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:32:5 + --> $DIR/enums_clike.rs:42:5 | -32 | C = (std::i32::MIN as isize) - 1, +42 | C = (std::i32::MIN as isize) - 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:38:5 + --> $DIR/enums_clike.rs:48:5 | -38 | Z = 0xFFFF_FFFF, +48 | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:39:5 + --> $DIR/enums_clike.rs:49:5 | -39 | A = 0x1_0000_0000, +49 | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index a88866436dd..c96cd8b9af2 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index ad0c8d8ecd7..21487884d35 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -1,203 +1,203 @@ error: this boolean expression can be simplified - --> $DIR/eq_op.rs:37:5 + --> $DIR/eq_op.rs:47:5 | -37 | true && true; +47 | true && true; | ^^^^^^^^^^^^ help: try: `true` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:39:5 + --> $DIR/eq_op.rs:49:5 | -39 | true || true; +49 | true || true; | ^^^^^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:45:5 + --> $DIR/eq_op.rs:55:5 | -45 | a == b && b == a; +55 | a == b && b == a; | ^^^^^^^^^^^^^^^^ help: try: `a == b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:46:5 + --> $DIR/eq_op.rs:56:5 | -46 | a != b && b != a; +56 | a != b && b != a; | ^^^^^^^^^^^^^^^^ help: try: `a != b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:47:5 + --> $DIR/eq_op.rs:57:5 | -47 | a < b && b > a; +57 | a < b && b > a; | ^^^^^^^^^^^^^^ help: try: `a < b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:48:5 + --> $DIR/eq_op.rs:58:5 | -48 | a <= b && b >= a; +58 | a <= b && b >= a; | ^^^^^^^^^^^^^^^^ help: try: `a <= b` error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:10:5 + --> $DIR/eq_op.rs:20:5 | -10 | 1 == 1; +20 | 1 == 1; | ^^^^^^ | = note: `-D clippy::eq-op` implied by `-D warnings` error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:11:5 + --> $DIR/eq_op.rs:21:5 | -11 | "no" == "no"; +21 | "no" == "no"; | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:13:5 + --> $DIR/eq_op.rs:23:5 | -13 | false != false; +23 | false != false; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> $DIR/eq_op.rs:14:5 + --> $DIR/eq_op.rs:24:5 | -14 | 1.5 < 1.5; +24 | 1.5 < 1.5; | ^^^^^^^^^ error: equal expressions as operands to `>=` - --> $DIR/eq_op.rs:15:5 + --> $DIR/eq_op.rs:25:5 | -15 | 1u64 >= 1u64; +25 | 1u64 >= 1u64; | ^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:18:5 + --> $DIR/eq_op.rs:28:5 | -18 | (1 as u64) & (1 as u64); +28 | (1 as u64) & (1 as u64); | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `^` - --> $DIR/eq_op.rs:19:5 + --> $DIR/eq_op.rs:29:5 | -19 | 1 ^ ((((((1)))))); +29 | 1 ^ ((((((1)))))); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> $DIR/eq_op.rs:22:5 + --> $DIR/eq_op.rs:32:5 | -22 | (-(2) < -(2)); +32 | (-(2) < -(2)); | ^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:23:5 + --> $DIR/eq_op.rs:33:5 | -23 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); +33 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:23:6 + --> $DIR/eq_op.rs:33:6 | -23 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); +33 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:23:27 + --> $DIR/eq_op.rs:33:27 | -23 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); +33 | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:24:5 + --> $DIR/eq_op.rs:34:5 | -24 | (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; +34 | (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:27:5 + --> $DIR/eq_op.rs:37:5 | -27 | ([1] != [1]); +37 | ([1] != [1]); | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:28:5 + --> $DIR/eq_op.rs:38:5 | -28 | ((1, 2) != (1, 2)); +38 | ((1, 2) != (1, 2)); | ^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:32:5 + --> $DIR/eq_op.rs:42:5 | -32 | 1 + 1 == 2; +42 | 1 + 1 == 2; | ^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:33:5 + --> $DIR/eq_op.rs:43:5 | -33 | 1 - 1 == 0; +43 | 1 - 1 == 0; | ^^^^^^^^^^ error: equal expressions as operands to `-` - --> $DIR/eq_op.rs:33:5 + --> $DIR/eq_op.rs:43:5 | -33 | 1 - 1 == 0; +43 | 1 - 1 == 0; | ^^^^^ error: equal expressions as operands to `-` - --> $DIR/eq_op.rs:35:5 + --> $DIR/eq_op.rs:45:5 | -35 | 1 - 1; +45 | 1 - 1; | ^^^^^ error: equal expressions as operands to `/` - --> $DIR/eq_op.rs:36:5 + --> $DIR/eq_op.rs:46:5 | -36 | 1 / 1; +46 | 1 / 1; | ^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:37:5 + --> $DIR/eq_op.rs:47:5 | -37 | true && true; +47 | true && true; | ^^^^^^^^^^^^ error: equal expressions as operands to `||` - --> $DIR/eq_op.rs:39:5 + --> $DIR/eq_op.rs:49:5 | -39 | true || true; +49 | true || true; | ^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:45:5 + --> $DIR/eq_op.rs:55:5 | -45 | a == b && b == a; +55 | a == b && b == a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:46:5 + --> $DIR/eq_op.rs:56:5 | -46 | a != b && b != a; +56 | a != b && b != a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:47:5 + --> $DIR/eq_op.rs:57:5 | -47 | a < b && b > a; +57 | a < b && b > a; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:48:5 + --> $DIR/eq_op.rs:58:5 | -48 | a <= b && b >= a; +58 | a <= b && b >= a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:51:5 + --> $DIR/eq_op.rs:61:5 | -51 | a == a; +61 | a == a; | ^^^^^^ error: taken reference of right operand - --> $DIR/eq_op.rs:89:13 + --> $DIR/eq_op.rs:99:13 | -89 | let z = x & &y; +99 | let z = x & &y; | ^^^^-- | | | help: use the right value directly: `y` @@ -205,10 +205,10 @@ error: taken reference of right operand = note: `-D clippy::op-ref` implied by `-D warnings` error: equal expressions as operands to `/` - --> $DIR/eq_op.rs:97:20 - | -97 | const D: u32 = A / A; - | ^^^^^ + --> $DIR/eq_op.rs:107:20 + | +107 | const D: u32 = A / A; + | ^^^^^ error: aborting due to 34 previous errors diff --git a/tests/ui/erasing_op.rs b/tests/ui/erasing_op.rs index 02745ac5d91..1c572b55554 100644 --- a/tests/ui/erasing_op.rs +++ b/tests/ui/erasing_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/erasing_op.stderr b/tests/ui/erasing_op.stderr index 18486ab4781..2cc3db7c268 100644 --- a/tests/ui/erasing_op.stderr +++ b/tests/ui/erasing_op.stderr @@ -1,21 +1,21 @@ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:9:5 - | -9 | x * 0; - | ^^^^^ - | - = note: `-D clippy::erasing-op` implied by `-D warnings` + --> $DIR/erasing_op.rs:19:5 + | +19 | x * 0; + | ^^^^^ + | + = note: `-D clippy::erasing-op` implied by `-D warnings` error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:10:5 + --> $DIR/erasing_op.rs:20:5 | -10 | 0 & x; +20 | 0 & x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:11:5 + --> $DIR/erasing_op.rs:21:5 | -11 | 0 / x; +21 | 0 / x; | ^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index 7a888f01914..1f2f46b03cd 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(box_syntax)] #![allow(warnings, clippy)] diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 4dd46f20e76..a580ce0831a 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unknown_lints, unused, clippy::no_effect, clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 89543d6af0c..dcdf0699ff7 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,35 +1,35 @@ error: redundant closure found - --> $DIR/eta.rs:7:27 - | -7 | let a = Some(1u8).map(|a| foo(a)); - | ^^^^^^^^^^ help: remove closure as shown: `foo` - | - = note: `-D clippy::redundant-closure` implied by `-D warnings` + --> $DIR/eta.rs:17:27 + | +17 | let a = Some(1u8).map(|a| foo(a)); + | ^^^^^^^^^^ help: remove closure as shown: `foo` + | + = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:8:10 - | -8 | meta(|a| foo(a)); - | ^^^^^^^^^^ help: remove closure as shown: `foo` + --> $DIR/eta.rs:18:10 + | +18 | meta(|a| foo(a)); + | ^^^^^^^^^^ help: remove closure as shown: `foo` error: redundant closure found - --> $DIR/eta.rs:9:27 - | -9 | let c = Some(1u8).map(|a| {1+2; foo}(a)); - | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `{1+2; foo}` + --> $DIR/eta.rs:19:27 + | +19 | let c = Some(1u8).map(|a| {1+2; foo}(a)); + | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `{1+2; foo}` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/eta.rs:11:21 + --> $DIR/eta.rs:21:21 | -11 | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted +21 | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` | = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:18:27 + --> $DIR/eta.rs:28:27 | -18 | let e = Some(1u8).map(|a| generic(a)); +28 | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` error: aborting due to 5 previous errors diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index b240dde06f8..4e525b9b2b0 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/eval_order_dependence.stderr b/tests/ui/eval_order_dependence.stderr index 3caba829be4..d5be92e993f 100644 --- a/tests/ui/eval_order_dependence.stderr +++ b/tests/ui/eval_order_dependence.stderr @@ -1,50 +1,50 @@ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:8:28 - | -8 | let a = { x = 1; 1 } + x; - | ^ - | - = note: `-D clippy::eval-order-dependence` implied by `-D warnings` + --> $DIR/eval_order_dependence.rs:18:28 + | +18 | let a = { x = 1; 1 } + x; + | ^ + | + = note: `-D clippy::eval-order-dependence` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:8:15 - | -8 | let a = { x = 1; 1 } + x; - | ^^^^^ + --> $DIR/eval_order_dependence.rs:18:15 + | +18 | let a = { x = 1; 1 } + x; + | ^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:11:5 + --> $DIR/eval_order_dependence.rs:21:5 | -11 | x += { x = 20; 2 }; +21 | x += { x = 20; 2 }; | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:11:12 + --> $DIR/eval_order_dependence.rs:21:12 | -11 | x += { x = 20; 2 }; +21 | x += { x = 20; 2 }; | ^^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:17:24 + --> $DIR/eval_order_dependence.rs:27:24 | -17 | let foo = Foo { a: x, .. { x = 6; base } }; +27 | let foo = Foo { a: x, .. { x = 6; base } }; | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:17:32 + --> $DIR/eval_order_dependence.rs:27:32 | -17 | let foo = Foo { a: x, .. { x = 6; base } }; +27 | let foo = Foo { a: x, .. { x = 6; base } }; | ^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:21:9 + --> $DIR/eval_order_dependence.rs:31:9 | -21 | x += { x = 20; 2 }; +31 | x += { x = 20; 2 }; | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:21:16 + --> $DIR/eval_order_dependence.rs:31:16 | -21 | x += { x = 20; 2 }; +31 | x += { x = 20; 2 }; | ^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 1b3412166d4..ab0412a16b5 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::excessive_precision)] #![allow(clippy::print_literal)] diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index bb0546cdcc6..783e41f2b50 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -1,111 +1,111 @@ error: float has excessive precision - --> $DIR/excessive_precision.rs:15:26 + --> $DIR/excessive_precision.rs:25:26 | -15 | const BAD32_1: f32 = 0.123_456_789_f32; +25 | const BAD32_1: f32 = 0.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` | = note: `-D clippy::excessive-precision` implied by `-D warnings` error: float has excessive precision - --> $DIR/excessive_precision.rs:16:26 + --> $DIR/excessive_precision.rs:26:26 | -16 | const BAD32_2: f32 = 0.123_456_789; +26 | const BAD32_2: f32 = 0.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:17:26 + --> $DIR/excessive_precision.rs:27:26 | -17 | const BAD32_3: f32 = 0.100_000_000_000_1; +27 | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:18:29 + --> $DIR/excessive_precision.rs:28:29 | -18 | const BAD32_EDGE: f32 = 1.000_000_9; +28 | const BAD32_EDGE: f32 = 1.000_000_9; | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` error: float has excessive precision - --> $DIR/excessive_precision.rs:20:26 + --> $DIR/excessive_precision.rs:30:26 | -20 | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; +30 | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:21:26 + --> $DIR/excessive_precision.rs:31:26 | -21 | const BAD64_2: f64 = 0.123_456_789_012_345_67; +31 | const BAD64_2: f64 = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:22:26 + --> $DIR/excessive_precision.rs:32:26 | -22 | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; +32 | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:25:22 + --> $DIR/excessive_precision.rs:35:22 | -25 | println!("{:?}", 8.888_888_888_888_888_888_888); +35 | println!("{:?}", 8.888_888_888_888_888_888_888); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` error: float has excessive precision - --> $DIR/excessive_precision.rs:36:22 + --> $DIR/excessive_precision.rs:46:22 | -36 | let bad32: f32 = 1.123_456_789; +46 | let bad32: f32 = 1.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:37:26 + --> $DIR/excessive_precision.rs:47:26 | -37 | let bad32_suf: f32 = 1.123_456_789_f32; +47 | let bad32_suf: f32 = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:38:21 + --> $DIR/excessive_precision.rs:48:21 | -38 | let bad32_inf = 1.123_456_789_f32; +48 | let bad32_inf = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:40:22 + --> $DIR/excessive_precision.rs:50:22 | -40 | let bad64: f64 = 0.123_456_789_012_345_67; +50 | let bad64: f64 = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:41:26 + --> $DIR/excessive_precision.rs:51:26 | -41 | let bad64_suf: f64 = 0.123_456_789_012_345_67f64; +51 | let bad64_suf: f64 = 0.123_456_789_012_345_67f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:42:21 + --> $DIR/excessive_precision.rs:52:21 | -42 | let bad64_inf = 0.123_456_789_012_345_67; +52 | let bad64_inf = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:48:36 + --> $DIR/excessive_precision.rs:58:36 | -48 | let bad_vec32: Vec<f32> = vec![0.123_456_789]; +58 | let bad_vec32: Vec<f32> = vec![0.123_456_789]; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:49:36 + --> $DIR/excessive_precision.rs:59:36 | -49 | let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789]; +59 | let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78` error: float has excessive precision - --> $DIR/excessive_precision.rs:53:24 + --> $DIR/excessive_precision.rs:63:24 | -53 | let bad_e32: f32 = 1.123_456_788_888e-10; +63 | let bad_e32: f32 = 1.123_456_788_888e-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10` error: float has excessive precision - --> $DIR/excessive_precision.rs:56:27 + --> $DIR/excessive_precision.rs:66:27 | -56 | let bad_bige32: f32 = 1.123_456_788_888E-10; +66 | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` error: aborting due to 18 previous errors diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index 9d6d13c84c5..2a748d25724 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::explicit_write)] diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr index fb14120b16d..fadc12c7594 100644 --- a/tests/ui/explicit_write.stderr +++ b/tests/ui/explicit_write.stderr @@ -1,39 +1,39 @@ error: use of `write!(stdout(), ...).unwrap()`. Consider using `print!` instead - --> $DIR/explicit_write.rs:18:9 + --> $DIR/explicit_write.rs:28:9 | -18 | write!(std::io::stdout(), "test").unwrap(); +28 | write!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::explicit-write` implied by `-D warnings` error: use of `write!(stderr(), ...).unwrap()`. Consider using `eprint!` instead - --> $DIR/explicit_write.rs:19:9 + --> $DIR/explicit_write.rs:29:9 | -19 | write!(std::io::stderr(), "test").unwrap(); +29 | write!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `writeln!(stdout(), ...).unwrap()`. Consider using `println!` instead - --> $DIR/explicit_write.rs:20:9 + --> $DIR/explicit_write.rs:30:9 | -20 | writeln!(std::io::stdout(), "test").unwrap(); +30 | writeln!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `writeln!(stderr(), ...).unwrap()`. Consider using `eprintln!` instead - --> $DIR/explicit_write.rs:21:9 + --> $DIR/explicit_write.rs:31:9 | -21 | writeln!(std::io::stderr(), "test").unwrap(); +31 | writeln!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `stdout().write_fmt(...).unwrap()`. Consider using `print!` instead - --> $DIR/explicit_write.rs:22:9 + --> $DIR/explicit_write.rs:32:9 | -22 | std::io::stdout().write_fmt(format_args!("test")).unwrap(); +32 | std::io::stdout().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `stderr().write_fmt(...).unwrap()`. Consider using `eprint!` instead - --> $DIR/explicit_write.rs:23:9 + --> $DIR/explicit_write.rs:33:9 | -23 | std::io::stderr().write_fmt(format_args!("test")).unwrap(); +33 | std::io::stderr().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 5e33cca59fa..1e1e24ee954 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::fallible_impl_from)] diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index 4dbc7879d31..97ece931464 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -1,91 +1,91 @@ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:7:1 + --> $DIR/fallible_impl_from.rs:17:1 | -7 | / impl From<String> for Foo { -8 | | fn from(s: String) -> Self { -9 | | Foo(s.parse().unwrap()) -10 | | } -11 | | } +17 | / impl From<String> for Foo { +18 | | fn from(s: String) -> Self { +19 | | Foo(s.parse().unwrap()) +20 | | } +21 | | } | |_^ | note: lint level defined here - --> $DIR/fallible_impl_from.rs:3:9 + --> $DIR/fallible_impl_from.rs:13:9 | -3 | #![deny(clippy::fallible_impl_from)] +13 | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:9:13 + --> $DIR/fallible_impl_from.rs:19:13 | -9 | Foo(s.parse().unwrap()) +19 | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:30:1 + --> $DIR/fallible_impl_from.rs:40:1 | -30 | / impl From<usize> for Invalid { -31 | | fn from(i: usize) -> Invalid { -32 | | if i != 42 { -33 | | panic!(); +40 | / impl From<usize> for Invalid { +41 | | fn from(i: usize) -> Invalid { +42 | | if i != 42 { +43 | | panic!(); ... | -36 | | } -37 | | } +46 | | } +47 | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:33:13 + --> $DIR/fallible_impl_from.rs:43:13 | -33 | panic!(); +43 | panic!(); | ^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:39:1 + --> $DIR/fallible_impl_from.rs:49:1 | -39 | / impl From<Option<String>> for Invalid { -40 | | fn from(s: Option<String>) -> Invalid { -41 | | let s = s.unwrap(); -42 | | if !s.is_empty() { +49 | / impl From<Option<String>> for Invalid { +50 | | fn from(s: Option<String>) -> Invalid { +51 | | let s = s.unwrap(); +52 | | if !s.is_empty() { ... | -48 | | } -49 | | } +58 | | } +59 | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:41:17 + --> $DIR/fallible_impl_from.rs:51:17 | -41 | let s = s.unwrap(); +51 | let s = s.unwrap(); | ^^^^^^^^^^ -42 | if !s.is_empty() { -43 | panic!(42); +52 | if !s.is_empty() { +53 | panic!(42); | ^^^^^^^^^^^ -44 | } else if s.parse::<u32>().unwrap() != 42 { +54 | } else if s.parse::<u32>().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -45 | panic!("{:?}", s); +55 | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:57:1 + --> $DIR/fallible_impl_from.rs:67:1 | -57 | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid { -58 | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid { -59 | | if s.parse::<u32>().ok().unwrap() != 42 { -60 | | panic!("{:?}", s); +67 | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid { +68 | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid { +69 | | if s.parse::<u32>().ok().unwrap() != 42 { +70 | | panic!("{:?}", s); ... | -63 | | } -64 | | } +73 | | } +74 | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:59:12 + --> $DIR/fallible_impl_from.rs:69:12 | -59 | if s.parse::<u32>().ok().unwrap() != 42 { +69 | if s.parse::<u32>().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -60 | panic!("{:?}", s); +70 | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index d7a50a58838..1bfc03356fb 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 1fde70601aa..6adbec44cf9 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,39 +1,39 @@ error: called `filter(p).map(q)` on an `Iterator`. This is more succinctly expressed by calling `.filter_map(..)` instead. - --> $DIR/filter_methods.rs:8:21 + --> $DIR/filter_methods.rs:18:21 | -8 | let _: Vec<_> = vec![5; 6].into_iter() +18 | let _: Vec<_> = vec![5; 6].into_iter() | _____________________^ -9 | | .filter(|&x| x == 0) -10 | | .map(|x| x * 2) +19 | | .filter(|&x| x == 0) +20 | | .map(|x| x * 2) | |_____________________________________________^ | = note: `-D clippy::filter-map` implied by `-D warnings` error: called `filter(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator. - --> $DIR/filter_methods.rs:13:21 + --> $DIR/filter_methods.rs:23:21 | -13 | let _: Vec<_> = vec![5_i8; 6].into_iter() +23 | let _: Vec<_> = vec![5_i8; 6].into_iter() | _____________________^ -14 | | .filter(|&x| x == 0) -15 | | .flat_map(|x| x.checked_mul(2)) +24 | | .filter(|&x| x == 0) +25 | | .flat_map(|x| x.checked_mul(2)) | |_______________________________________________________________^ error: called `filter_map(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator. - --> $DIR/filter_methods.rs:18:21 + --> $DIR/filter_methods.rs:28:21 | -18 | let _: Vec<_> = vec![5_i8; 6].into_iter() +28 | let _: Vec<_> = vec![5_i8; 6].into_iter() | _____________________^ -19 | | .filter_map(|x| x.checked_mul(2)) -20 | | .flat_map(|x| x.checked_mul(2)) +29 | | .filter_map(|x| x.checked_mul(2)) +30 | | .flat_map(|x| x.checked_mul(2)) | |_______________________________________________________________^ error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly expressed by only calling `.filter_map(..)` instead. - --> $DIR/filter_methods.rs:23:21 + --> $DIR/filter_methods.rs:33:21 | -23 | let _: Vec<_> = vec![5_i8; 6].into_iter() +33 | let _: Vec<_> = vec![5_i8; 6].into_iter() | _____________________^ -24 | | .filter_map(|x| x.checked_mul(2)) -25 | | .map(|x| x.checked_mul(2)) +34 | | .filter_map(|x| x.checked_mul(2)) +35 | | .map(|x| x.checked_mul(2)) | |__________________________________________________________^ error: aborting due to 4 previous errors diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index d5b02fb706f..cb8b7a98e39 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index 598ebf33668..52ec0e3ed78 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -1,38 +1,38 @@ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:49:5 + --> $DIR/float_cmp.rs:59:5 | -49 | ONE as f64 != 2.0; +59 | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() < error` | = note: `-D clippy::float-cmp` implied by `-D warnings` note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:49:5 + --> $DIR/float_cmp.rs:59:5 | -49 | ONE as f64 != 2.0; +59 | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:54:5 + --> $DIR/float_cmp.rs:64:5 | -54 | x == 1.0; +64 | x == 1.0; | ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:54:5 + --> $DIR/float_cmp.rs:64:5 | -54 | x == 1.0; +64 | x == 1.0; | ^^^^^^^^ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:57:5 + --> $DIR/float_cmp.rs:67:5 | -57 | twice(x) != twice(ONE as f64); +67 | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:57:5 + --> $DIR/float_cmp.rs:67:5 | -57 | twice(x) != twice(ONE as f64); +67 | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index 279400604a2..27d829ed105 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index 14083979511..d9b1d268505 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -1,86 +1,86 @@ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:17:5 + --> $DIR/float_cmp_const.rs:27:5 | -17 | 1f32 == ONE; +27 | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error` | = note: `-D clippy::float-cmp-const` implied by `-D warnings` note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:17:5 + --> $DIR/float_cmp_const.rs:27:5 | -17 | 1f32 == ONE; +27 | 1f32 == ONE; | ^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:18:5 + --> $DIR/float_cmp_const.rs:28:5 | -18 | TWO == ONE; +28 | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:18:5 + --> $DIR/float_cmp_const.rs:28:5 | -18 | TWO == ONE; +28 | TWO == ONE; | ^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:19:5 + --> $DIR/float_cmp_const.rs:29:5 | -19 | TWO != ONE; +29 | TWO != ONE; | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:19:5 + --> $DIR/float_cmp_const.rs:29:5 | -19 | TWO != ONE; +29 | TWO != ONE; | ^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:20:5 + --> $DIR/float_cmp_const.rs:30:5 | -20 | ONE + ONE == TWO; +30 | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:20:5 + --> $DIR/float_cmp_const.rs:30:5 | -20 | ONE + ONE == TWO; +30 | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:21:5 + --> $DIR/float_cmp_const.rs:31:5 | -21 | 1 as f32 == ONE; +31 | 1 as f32 == ONE; | ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(1 as f32 - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:21:5 + --> $DIR/float_cmp_const.rs:31:5 | -21 | 1 as f32 == ONE; +31 | 1 as f32 == ONE; | ^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:24:5 + --> $DIR/float_cmp_const.rs:34:5 | -24 | v == ONE; +34 | v == ONE; | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:24:5 + --> $DIR/float_cmp_const.rs:34:5 | -24 | v == ONE; +34 | v == ONE; | ^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:25:5 + --> $DIR/float_cmp_const.rs:35:5 | -25 | v != ONE; +35 | v != ONE; | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:25:5 + --> $DIR/float_cmp_const.rs:35:5 | -25 | v != ONE; +35 | v != ONE; | ^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs index fc8aa19dcf0..0066b9a3587 100644 --- a/tests/ui/fn_to_numeric_cast.rs +++ b/tests/ui/fn_to_numeric_cast.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // only-64bit #![feature(tool_lints)] diff --git a/tests/ui/fn_to_numeric_cast.stderr b/tests/ui/fn_to_numeric_cast.stderr index 29320f0d8ed..2e186145eae 100644 --- a/tests/ui/fn_to_numeric_cast.stderr +++ b/tests/ui/fn_to_numeric_cast.stderr @@ -1,143 +1,143 @@ error: casting function pointer `foo` to `i8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:9:13 - | -9 | let _ = foo as i8; - | ^^^^^^^^^ help: try: `foo as usize` - | - = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings` + --> $DIR/fn_to_numeric_cast.rs:19:13 + | +19 | let _ = foo as i8; + | ^^^^^^^^^ help: try: `foo as usize` + | + = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings` error: casting function pointer `foo` to `i16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:10:13 + --> $DIR/fn_to_numeric_cast.rs:20:13 | -10 | let _ = foo as i16; +20 | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:11:13 + --> $DIR/fn_to_numeric_cast.rs:21:13 | -11 | let _ = foo as i32; +21 | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i64` - --> $DIR/fn_to_numeric_cast.rs:12:13 + --> $DIR/fn_to_numeric_cast.rs:22:13 | -12 | let _ = foo as i64; +22 | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` | = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i128` - --> $DIR/fn_to_numeric_cast.rs:13:13 + --> $DIR/fn_to_numeric_cast.rs:23:13 | -13 | let _ = foo as i128; +23 | let _ = foo as i128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `isize` - --> $DIR/fn_to_numeric_cast.rs:14:13 + --> $DIR/fn_to_numeric_cast.rs:24:13 | -14 | let _ = foo as isize; +24 | let _ = foo as isize; | ^^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:16:13 + --> $DIR/fn_to_numeric_cast.rs:26:13 | -16 | let _ = foo as u8; +26 | let _ = foo as u8; | ^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:17:13 + --> $DIR/fn_to_numeric_cast.rs:27:13 | -17 | let _ = foo as u16; +27 | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:18:13 + --> $DIR/fn_to_numeric_cast.rs:28:13 | -18 | let _ = foo as u32; +28 | let _ = foo as u32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u64` - --> $DIR/fn_to_numeric_cast.rs:19:13 + --> $DIR/fn_to_numeric_cast.rs:29:13 | -19 | let _ = foo as u64; +29 | let _ = foo as u64; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u128` - --> $DIR/fn_to_numeric_cast.rs:20:13 + --> $DIR/fn_to_numeric_cast.rs:30:13 | -20 | let _ = foo as u128; +30 | let _ = foo as u128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `abc` to `i8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:29:13 + --> $DIR/fn_to_numeric_cast.rs:39:13 | -29 | let _ = abc as i8; +39 | let _ = abc as i8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:30:13 + --> $DIR/fn_to_numeric_cast.rs:40:13 | -30 | let _ = abc as i16; +40 | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:31:13 + --> $DIR/fn_to_numeric_cast.rs:41:13 | -31 | let _ = abc as i32; +41 | let _ = abc as i32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i64` - --> $DIR/fn_to_numeric_cast.rs:32:13 + --> $DIR/fn_to_numeric_cast.rs:42:13 | -32 | let _ = abc as i64; +42 | let _ = abc as i64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i128` - --> $DIR/fn_to_numeric_cast.rs:33:13 + --> $DIR/fn_to_numeric_cast.rs:43:13 | -33 | let _ = abc as i128; +43 | let _ = abc as i128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `isize` - --> $DIR/fn_to_numeric_cast.rs:34:13 + --> $DIR/fn_to_numeric_cast.rs:44:13 | -34 | let _ = abc as isize; +44 | let _ = abc as isize; | ^^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:36:13 + --> $DIR/fn_to_numeric_cast.rs:46:13 | -36 | let _ = abc as u8; +46 | let _ = abc as u8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:37:13 + --> $DIR/fn_to_numeric_cast.rs:47:13 | -37 | let _ = abc as u16; +47 | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:38:13 + --> $DIR/fn_to_numeric_cast.rs:48:13 | -38 | let _ = abc as u32; +48 | let _ = abc as u32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u64` - --> $DIR/fn_to_numeric_cast.rs:39:13 + --> $DIR/fn_to_numeric_cast.rs:49:13 | -39 | let _ = abc as u64; +49 | let _ = abc as u64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u128` - --> $DIR/fn_to_numeric_cast.rs:40:13 + --> $DIR/fn_to_numeric_cast.rs:50:13 | -40 | let _ = abc as u128; +50 | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `f` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:47:5 + --> $DIR/fn_to_numeric_cast.rs:57:5 | -47 | f as i32 +57 | f as i32 | ^^^^^^^^ help: try: `f as usize` error: aborting due to 23 previous errors diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index 55060b0769d..cff7075543b 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index d829147541e..472fa148609 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -1,502 +1,502 @@ error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop.rs:17:14 + --> $DIR/for_loop.rs:27:14 | -17 | for x in option { +27 | for x in option { | ^^^^^^ | = note: `-D clippy::for-loop-over-option` implied by `-D warnings` = help: consider replacing `for x in option` with `if let Some(x) = option` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop.rs:22:14 + --> $DIR/for_loop.rs:32:14 | -22 | for x in result { +32 | for x in result { | ^^^^^^ | = note: `-D clippy::for-loop-over-result` implied by `-D warnings` = help: consider replacing `for x in result` with `if let Ok(x) = result` error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop.rs:26:14 + --> $DIR/for_loop.rs:36:14 | -26 | for x in option.ok_or("x not found") { +36 | for x in option.ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop.rs:32:14 + --> $DIR/for_loop.rs:42:14 | -32 | for x in v.iter().next() { +42 | for x in v.iter().next() { | ^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-next-loop` implied by `-D warnings` error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop.rs:37:14 + --> $DIR/for_loop.rs:47:14 | -37 | for x in v.iter().next().and(Some(0)) { +47 | for x in v.iter().next().and(Some(0)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop.rs:41:14 + --> $DIR/for_loop.rs:51:14 | -41 | for x in v.iter().next().ok_or("x not found") { +51 | for x in v.iter().next().ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")` error: this loop never actually loops - --> $DIR/for_loop.rs:53:5 + --> $DIR/for_loop.rs:63:5 | -53 | / while let Some(x) = option { -54 | | println!("{}", x); -55 | | break; -56 | | } +63 | / while let Some(x) = option { +64 | | println!("{}", x); +65 | | break; +66 | | } | |_____^ | = note: `-D clippy::never-loop` implied by `-D warnings` error: this loop never actually loops - --> $DIR/for_loop.rs:59:5 + --> $DIR/for_loop.rs:69:5 | -59 | / while let Ok(x) = result { -60 | | println!("{}", x); -61 | | break; -62 | | } +69 | / while let Ok(x) = result { +70 | | println!("{}", x); +71 | | break; +72 | | } | |_____^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:86:14 + --> $DIR/for_loop.rs:96:14 | -86 | for i in 0..vec.len() { +96 | for i in 0..vec.len() { | ^^^^^^^^^^^^ | = note: `-D clippy::needless-range-loop` implied by `-D warnings` help: consider using an iterator | -86 | for <item> in &vec { +96 | for <item> in &vec { | ^^^^^^ ^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:95:14 - | -95 | for i in 0..vec.len() { - | ^^^^^^^^^^^^ + --> $DIR/for_loop.rs:105:14 + | +105 | for i in 0..vec.len() { + | ^^^^^^^^^^^^ help: consider using an iterator - | -95 | for <item> in &vec { - | ^^^^^^ ^^^^ + | +105 | for <item> in &vec { + | ^^^^^^ ^^^^ error: the loop variable `j` is only used to index `STATIC`. - --> $DIR/for_loop.rs:100:14 + --> $DIR/for_loop.rs:110:14 | -100 | for j in 0..4 { +110 | for j in 0..4 { | ^^^^ help: consider using an iterator | -100 | for <item> in STATIC.iter().take(4) { +110 | for <item> in STATIC.iter().take(4) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `j` is only used to index `CONST`. - --> $DIR/for_loop.rs:104:14 + --> $DIR/for_loop.rs:114:14 | -104 | for j in 0..4 { +114 | for j in 0..4 { | ^^^^ help: consider using an iterator | -104 | for <item> in CONST.iter().take(4) { +114 | for <item> in CONST.iter().take(4) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:108:14 + --> $DIR/for_loop.rs:118:14 | -108 | for i in 0..vec.len() { +118 | for i in 0..vec.len() { | ^^^^^^^^^^^^ help: consider using an iterator | -108 | for (i, <item>) in vec.iter().enumerate() { +118 | for (i, <item>) in vec.iter().enumerate() { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec2`. - --> $DIR/for_loop.rs:116:14 + --> $DIR/for_loop.rs:126:14 | -116 | for i in 0..vec.len() { +126 | for i in 0..vec.len() { | ^^^^^^^^^^^^ help: consider using an iterator | -116 | for <item> in vec2.iter().take(vec.len()) { +126 | for <item> in vec2.iter().take(vec.len()) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:120:14 + --> $DIR/for_loop.rs:130:14 | -120 | for i in 5..vec.len() { +130 | for i in 5..vec.len() { | ^^^^^^^^^^^^ help: consider using an iterator | -120 | for <item> in vec.iter().skip(5) { +130 | for <item> in vec.iter().skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:124:14 + --> $DIR/for_loop.rs:134:14 | -124 | for i in 0..MAX_LEN { +134 | for i in 0..MAX_LEN { | ^^^^^^^^^^ help: consider using an iterator | -124 | for <item> in vec.iter().take(MAX_LEN) { +134 | for <item> in vec.iter().take(MAX_LEN) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:128:14 + --> $DIR/for_loop.rs:138:14 | -128 | for i in 0..=MAX_LEN { +138 | for i in 0..=MAX_LEN { | ^^^^^^^^^^^ help: consider using an iterator | -128 | for <item> in vec.iter().take(MAX_LEN + 1) { +138 | for <item> in vec.iter().take(MAX_LEN + 1) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:132:14 + --> $DIR/for_loop.rs:142:14 | -132 | for i in 5..10 { +142 | for i in 5..10 { | ^^^^^ help: consider using an iterator | -132 | for <item> in vec.iter().take(10).skip(5) { +142 | for <item> in vec.iter().take(10).skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:136:14 + --> $DIR/for_loop.rs:146:14 | -136 | for i in 5..=10 { +146 | for i in 5..=10 { | ^^^^^^ help: consider using an iterator | -136 | for <item> in vec.iter().take(10 + 1).skip(5) { +146 | for <item> in vec.iter().take(10 + 1).skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:140:14 + --> $DIR/for_loop.rs:150:14 | -140 | for i in 5..vec.len() { +150 | for i in 5..vec.len() { | ^^^^^^^^^^^^ help: consider using an iterator | -140 | for (i, <item>) in vec.iter().enumerate().skip(5) { +150 | for (i, <item>) in vec.iter().enumerate().skip(5) { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:144:14 + --> $DIR/for_loop.rs:154:14 | -144 | for i in 5..10 { +154 | for i in 5..10 { | ^^^^^ help: consider using an iterator | -144 | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) { +154 | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:148:14 + --> $DIR/for_loop.rs:158:14 | -148 | for i in 10..0 { +158 | for i in 10..0 { | ^^^^^ | = note: `-D clippy::reverse-range-loop` implied by `-D warnings` help: consider using the following if you are attempting to iterate over this range in reverse | -148 | for i in (0..10).rev() { +158 | for i in (0..10).rev() { | ^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:152:14 + --> $DIR/for_loop.rs:162:14 | -152 | for i in 10..=0 { +162 | for i in 10..=0 { | ^^^^^^ help: consider using the following if you are attempting to iterate over this range in reverse | -152 | for i in (0...10).rev() { +162 | for i in (0...10).rev() { | ^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:156:14 + --> $DIR/for_loop.rs:166:14 | -156 | for i in MAX_LEN..0 { +166 | for i in MAX_LEN..0 { | ^^^^^^^^^^ help: consider using the following if you are attempting to iterate over this range in reverse | -156 | for i in (0..MAX_LEN).rev() { +166 | for i in (0..MAX_LEN).rev() { | ^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:160:14 + --> $DIR/for_loop.rs:170:14 | -160 | for i in 5..5 { +170 | for i in 5..5 { | ^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:185:14 + --> $DIR/for_loop.rs:195:14 | -185 | for i in 10..5 + 4 { +195 | for i in 10..5 + 4 { | ^^^^^^^^^ help: consider using the following if you are attempting to iterate over this range in reverse | -185 | for i in (5 + 4..10).rev() { +195 | for i in (5 + 4..10).rev() { | ^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:189:14 + --> $DIR/for_loop.rs:199:14 | -189 | for i in (5 + 2)..(3 - 1) { +199 | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ help: consider using the following if you are attempting to iterate over this range in reverse | -189 | for i in ((3 - 1)..(5 + 2)).rev() { +199 | for i in ((3 - 1)..(5 + 2)).rev() { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:193:14 + --> $DIR/for_loop.rs:203:14 | -193 | for i in (5 + 2)..(8 - 1) { +203 | for i in (5 + 2)..(8 - 1) { | ^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:215:15 + --> $DIR/for_loop.rs:225:15 | -215 | for _v in vec.iter() {} +225 | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` | = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:217:15 + --> $DIR/for_loop.rs:227:15 | -217 | for _v in vec.iter_mut() {} +227 | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods` - --> $DIR/for_loop.rs:220:15 + --> $DIR/for_loop.rs:230:15 | -220 | for _v in out_vec.into_iter() {} +230 | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` | = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:223:15 + --> $DIR/for_loop.rs:233:15 | -223 | for _v in array.into_iter() {} +233 | for _v in array.into_iter() {} | ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&array` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:228:15 + --> $DIR/for_loop.rs:238:15 | -228 | for _v in [1, 2, 3].iter() {} +238 | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:232:15 + --> $DIR/for_loop.rs:242:15 | -232 | for _v in [0; 32].iter() {} +242 | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:237:15 + --> $DIR/for_loop.rs:247:15 | -237 | for _v in ll.iter() {} +247 | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:240:15 + --> $DIR/for_loop.rs:250:15 | -240 | for _v in vd.iter() {} +250 | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:243:15 + --> $DIR/for_loop.rs:253:15 | -243 | for _v in bh.iter() {} +253 | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:246:15 + --> $DIR/for_loop.rs:256:15 | -246 | for _v in hm.iter() {} +256 | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:249:15 + --> $DIR/for_loop.rs:259:15 | -249 | for _v in bt.iter() {} +259 | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:252:15 + --> $DIR/for_loop.rs:262:15 | -252 | for _v in hs.iter() {} +262 | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:255:15 + --> $DIR/for_loop.rs:265:15 | -255 | for _v in bs.iter() {} +265 | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop.rs:257:15 + --> $DIR/for_loop.rs:267:15 | -257 | for _v in vec.iter().next() {} +267 | for _v in vec.iter().next() {} | ^^^^^^^^^^^^^^^^^ error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/for_loop.rs:264:5 + --> $DIR/for_loop.rs:274:5 | -264 | vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); +274 | vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unused-collect` implied by `-D warnings` error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators - --> $DIR/for_loop.rs:269:15 + --> $DIR/for_loop.rs:279:15 | -269 | for _v in &vec { +279 | for _v in &vec { | ^^^^ | = note: `-D clippy::explicit-counter-loop` implied by `-D warnings` error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators - --> $DIR/for_loop.rs:275:15 + --> $DIR/for_loop.rs:285:15 | -275 | for _v in &vec { +285 | for _v in &vec { | ^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_loop.rs:385:19 + --> $DIR/for_loop.rs:395:19 | -385 | for (_, v) in &m { +395 | for (_, v) in &m { | ^^ | = note: `-D clippy::for-kv-map` implied by `-D warnings` help: use the corresponding method | -385 | for v in m.values() { +395 | for v in m.values() { | ^ ^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_loop.rs:390:19 + --> $DIR/for_loop.rs:400:19 | -390 | for (_, v) in &*m { +400 | for (_, v) in &*m { | ^^^ help: use the corresponding method | -390 | for v in (*m).values() { +400 | for v in (*m).values() { | ^ ^^^^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_loop.rs:398:19 + --> $DIR/for_loop.rs:408:19 | -398 | for (_, v) in &mut m { +408 | for (_, v) in &mut m { | ^^^^^^ help: use the corresponding method | -398 | for v in m.values_mut() { +408 | for v in m.values_mut() { | ^ ^^^^^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_loop.rs:403:19 + --> $DIR/for_loop.rs:413:19 | -403 | for (_, v) in &mut *m { +413 | for (_, v) in &mut *m { | ^^^^^^^ help: use the corresponding method | -403 | for v in (*m).values_mut() { +413 | for v in (*m).values_mut() { | ^ ^^^^^^^^^^^^^^^^^ error: you seem to want to iterate on a map's keys - --> $DIR/for_loop.rs:409:24 + --> $DIR/for_loop.rs:419:24 | -409 | for (k, _value) in rm { +419 | for (k, _value) in rm { | ^^ help: use the corresponding method | -409 | for k in rm.keys() { +419 | for k in rm.keys() { | ^ ^^^^^^^^^ error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:462:14 + --> $DIR/for_loop.rs:472:14 | -462 | for i in 0..src.len() { +472 | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` | = note: `-D clippy::manual-memcpy` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:467:14 + --> $DIR/for_loop.rs:477:14 | -467 | for i in 0..src.len() { +477 | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:472:14 + --> $DIR/for_loop.rs:482:14 | -472 | for i in 0..src.len() { +482 | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:477:14 + --> $DIR/for_loop.rs:487:14 | -477 | for i in 11..src.len() { +487 | for i in 11..src.len() { | ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:482:14 + --> $DIR/for_loop.rs:492:14 | -482 | for i in 0..dst.len() { +492 | for i in 0..dst.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:495:14 + --> $DIR/for_loop.rs:505:14 | -495 | for i in 10..256 { +505 | for i in 10..256 { | ^^^^^^^ help: try replacing the loop by | -495 | for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)]) -496 | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) { +505 | for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)]) +506 | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) { | error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:507:14 + --> $DIR/for_loop.rs:517:14 | -507 | for i in 10..LOOP_OFFSET { +517 | for i in 10..LOOP_OFFSET { | ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:520:14 + --> $DIR/for_loop.rs:530:14 | -520 | for i in 0..src_vec.len() { +530 | for i in 0..src_vec.len() { | ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:547:14 + --> $DIR/for_loop.rs:557:14 | -547 | for i in 0..src.len() { +557 | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators - --> $DIR/for_loop.rs:608:19 + --> $DIR/for_loop.rs:618:19 | -608 | for ch in text.chars() { +618 | for ch in text.chars() { | ^^^^^^^^^^^^ error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators - --> $DIR/for_loop.rs:619:19 + --> $DIR/for_loop.rs:629:19 | -619 | for ch in text.chars() { +629 | for ch in text.chars() { | ^^^^^^^^^^^^ error: aborting due to 61 previous errors diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 858c9fc8de5..5679a55755c 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::print_literal)] #![warn(clippy::useless_format)] diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 520c1b79433..c4ecd1dcc00 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,71 +1,71 @@ error: useless use of `format!` - --> $DIR/format.rs:12:5 + --> $DIR/format.rs:22:5 | -12 | format!("foo"); +22 | format!("foo"); | ^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` | = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:14:5 + --> $DIR/format.rs:24:5 | -14 | format!("{}", "foo"); +24 | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:18:5 + --> $DIR/format.rs:28:5 | -18 | format!("{:+}", "foo"); // warn when the format makes no difference +28 | format!("{:+}", "foo"); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:19:5 + --> $DIR/format.rs:29:5 | -19 | format!("{:<}", "foo"); // warn when the format makes no difference +29 | format!("{:<}", "foo"); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:24:5 + --> $DIR/format.rs:34:5 | -24 | format!("{}", arg); +34 | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:28:5 + --> $DIR/format.rs:38:5 | -28 | format!("{:+}", arg); // warn when the format makes no difference +38 | format!("{:+}", arg); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:29:5 + --> $DIR/format.rs:39:5 | -29 | format!("{:<}", arg); // warn when the format makes no difference +39 | format!("{:<}", arg); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:56:5 + --> $DIR/format.rs:66:5 | -56 | format!("{}", 42.to_string()); +66 | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `42.to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:58:5 + --> $DIR/format.rs:68:5 | -58 | format!("{}", x.display().to_string()); +68 | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `x.display().to_string()` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index 74d42f08f5a..15aff5a3bba 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index d9fee73660c..e1620b22125 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -1,87 +1,87 @@ error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:15:6 + --> $DIR/formatting.rs:25:6 | -15 | } if foo() { +25 | } if foo() { | ^ | = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:22:10 + --> $DIR/formatting.rs:32:10 | -22 | } if foo() { +32 | } if foo() { | ^ | = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:30:10 + --> $DIR/formatting.rs:40:10 | -30 | } if foo() { +40 | } if foo() { | ^ | = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:39:6 + --> $DIR/formatting.rs:49:6 | -39 | } else +49 | } else | ______^ -40 | | if foo() { // the span of the above error should continue here +50 | | if foo() { // the span of the above error should continue here | |____^ | = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:44:6 + --> $DIR/formatting.rs:54:6 | -44 | } +54 | } | ______^ -45 | | else -46 | | if foo() { // the span of the above error should continue here +55 | | else +56 | | if foo() { // the span of the above error should continue here | |____^ | = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` - --> $DIR/formatting.rs:71:6 + --> $DIR/formatting.rs:81:6 | -71 | a =- 35; +81 | a =- 35; | ^^^^ | = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings` = note: to remove this lint, use either `-=` or `= -` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> $DIR/formatting.rs:72:6 + --> $DIR/formatting.rs:82:6 | -72 | a =* &191; +82 | a =* &191; | ^^^^ | = note: to remove this lint, use either `*=` or `= *` error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> $DIR/formatting.rs:75:6 + --> $DIR/formatting.rs:85:6 | -75 | b =! false; +85 | b =! false; | ^^^^ | = note: to remove this lint, use either `!=` or `= !` error: possibly missing a comma here - --> $DIR/formatting.rs:84:19 + --> $DIR/formatting.rs:94:19 | -84 | -1, -2, -3 // <= no comma here +94 | -1, -2, -3 // <= no comma here | ^ | = note: `-D clippy::possible-missing-comma` implied by `-D warnings` = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> $DIR/formatting.rs:88:19 + --> $DIR/formatting.rs:98:19 | -88 | -1, -2, -3 // <= no comma here +98 | -1, -2, -3 // <= no comma here | ^ | = note: to remove this lint, add a comma or write the expr in a single line diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index ab5ce5b06d8..136adef823b 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index c2f7b76aab4..9c45eb033ea 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -1,78 +1,78 @@ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:11:1 + --> $DIR/functions.rs:21:1 | -11 | / fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) { -12 | | } +21 | / fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) { +22 | | } | |_^ | = note: `-D clippy::too-many-arguments` implied by `-D warnings` error: this function has too many arguments (8/7) - --> $DIR/functions.rs:19:5 + --> $DIR/functions.rs:29:5 | -19 | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); +29 | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:28:5 + --> $DIR/functions.rs:38:5 | -28 | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} +38 | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:37:34 + --> $DIR/functions.rs:47:34 | -37 | println!("{}", unsafe { *p }); +47 | println!("{}", unsafe { *p }); | ^ | = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:38:35 + --> $DIR/functions.rs:48:35 | -38 | println!("{:?}", unsafe { p.as_ref() }); +48 | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:39:33 + --> $DIR/functions.rs:49:33 | -39 | unsafe { std::ptr::read(p) }; +49 | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:50:30 + --> $DIR/functions.rs:60:30 | -50 | println!("{}", unsafe { *p }); +60 | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:51:31 + --> $DIR/functions.rs:61:31 | -51 | println!("{:?}", unsafe { p.as_ref() }); +61 | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:52:29 + --> $DIR/functions.rs:62:29 | -52 | unsafe { std::ptr::read(p) }; +62 | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:61:34 + --> $DIR/functions.rs:71:34 | -61 | println!("{}", unsafe { *p }); +71 | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:62:35 + --> $DIR/functions.rs:72:35 | -62 | println!("{:?}", unsafe { p.as_ref() }); +72 | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:63:33 + --> $DIR/functions.rs:73:33 | -63 | unsafe { std::ptr::read(p) }; +73 | unsafe { std::ptr::read(p) }; | ^ error: aborting due to 12 previous errors diff --git a/tests/ui/fxhash.rs b/tests/ui/fxhash.rs index 1376b9442b6..e91cfcb9e70 100644 --- a/tests/ui/fxhash.rs +++ b/tests/ui/fxhash.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::default_hash_types)] diff --git a/tests/ui/fxhash.stderr b/tests/ui/fxhash.stderr index 869a315c9eb..f5f8ae7e801 100644 --- a/tests/ui/fxhash.stderr +++ b/tests/ui/fxhash.stderr @@ -1,39 +1,39 @@ error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:8:24 - | -8 | use std::collections::{HashMap, HashSet}; - | ^^^^^^^ help: use: `FxHashMap` - | - = note: `-D clippy::default-hash-types` implied by `-D warnings` + --> $DIR/fxhash.rs:18:24 + | +18 | use std::collections::{HashMap, HashSet}; + | ^^^^^^^ help: use: `FxHashMap` + | + = note: `-D clippy::default-hash-types` implied by `-D warnings` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:8:33 - | -8 | use std::collections::{HashMap, HashSet}; - | ^^^^^^^ help: use: `FxHashSet` + --> $DIR/fxhash.rs:18:33 + | +18 | use std::collections::{HashMap, HashSet}; + | ^^^^^^^ help: use: `FxHashSet` error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:12:15 + --> $DIR/fxhash.rs:22:15 | -12 | let _map: HashMap<String, String> = HashMap::default(); +22 | let _map: HashMap<String, String> = HashMap::default(); | ^^^^^^^ help: use: `FxHashMap` error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:12:41 + --> $DIR/fxhash.rs:22:41 | -12 | let _map: HashMap<String, String> = HashMap::default(); +22 | let _map: HashMap<String, String> = HashMap::default(); | ^^^^^^^ help: use: `FxHashMap` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:13:15 + --> $DIR/fxhash.rs:23:15 | -13 | let _set: HashSet<String> = HashSet::default(); +23 | let _set: HashSet<String> = HashSet::default(); | ^^^^^^^ help: use: `FxHashSet` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:13:33 + --> $DIR/fxhash.rs:23:33 | -13 | let _set: HashSet<String> = HashSet::default(); +23 | let _set: HashSet<String> = HashSet::default(); | ^^^^^^^ help: use: `FxHashSet` error: aborting due to 6 previous errors diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index 141233e0d8a..7b672c0748c 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(unused_mut)] use std::collections::BTreeMap; diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 669903da190..90b46e960f4 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -1,75 +1,75 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:27:17 + --> $DIR/get_unwrap.rs:37:17 | -27 | let _ = boxed_slice.get(1).unwrap(); +37 | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` | = note: `-D clippy::get-unwrap` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:28:17 + --> $DIR/get_unwrap.rs:38:17 | -28 | let _ = some_slice.get(0).unwrap(); +38 | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:29:17 + --> $DIR/get_unwrap.rs:39:17 | -29 | let _ = some_vec.get(0).unwrap(); +39 | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:30:17 + --> $DIR/get_unwrap.rs:40:17 | -30 | let _ = some_vecdeque.get(0).unwrap(); +40 | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:31:17 + --> $DIR/get_unwrap.rs:41:17 | -31 | let _ = some_hashmap.get(&1).unwrap(); +41 | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:32:17 + --> $DIR/get_unwrap.rs:42:17 | -32 | let _ = some_btreemap.get(&1).unwrap(); +42 | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:37:10 + --> $DIR/get_unwrap.rs:47:10 | -37 | *boxed_slice.get_mut(0).unwrap() = 1; +47 | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut boxed_slice[0]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:38:10 + --> $DIR/get_unwrap.rs:48:10 | -38 | *some_slice.get_mut(0).unwrap() = 1; +48 | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_slice[0]` error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:39:10 + --> $DIR/get_unwrap.rs:49:10 | -39 | *some_vec.get_mut(0).unwrap() = 1; +49 | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vec[0]` error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:40:10 + --> $DIR/get_unwrap.rs:50:10 | -40 | *some_vecdeque.get_mut(0).unwrap() = 1; +50 | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vecdeque[0]` error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:48:17 + --> $DIR/get_unwrap.rs:58:17 | -48 | let _ = some_vec.get(0..1).unwrap().to_vec(); +58 | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:49:17 + --> $DIR/get_unwrap.rs:59:17 | -49 | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); +59 | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: aborting due to 12 previous errors diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs index b9ad8d06ad5..a4f5babecfc 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/identity_conversion.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::identity_conversion)] diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/identity_conversion.stderr index ffcd3649ad6..2ac74191931 100644 --- a/tests/ui/identity_conversion.stderr +++ b/tests/ui/identity_conversion.stderr @@ -1,61 +1,61 @@ error: identical conversion - --> $DIR/identity_conversion.rs:6:13 - | -6 | let _ = T::from(val); - | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` - | + --> $DIR/identity_conversion.rs:16:13 + | +16 | let _ = T::from(val); + | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` + | note: lint level defined here - --> $DIR/identity_conversion.rs:3:9 - | -3 | #![deny(clippy::identity_conversion)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/identity_conversion.rs:13:9 + | +13 | #![deny(clippy::identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: identical conversion - --> $DIR/identity_conversion.rs:7:5 - | -7 | val.into() - | ^^^^^^^^^^ help: consider removing `.into()`: `val` + --> $DIR/identity_conversion.rs:17:5 + | +17 | val.into() + | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: identical conversion - --> $DIR/identity_conversion.rs:19:22 + --> $DIR/identity_conversion.rs:29:22 | -19 | let _: i32 = 0i32.into(); +29 | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: identical conversion - --> $DIR/identity_conversion.rs:40:21 + --> $DIR/identity_conversion.rs:50:21 | -40 | let _: String = "foo".to_string().into(); +50 | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:41:21 + --> $DIR/identity_conversion.rs:51:21 | -41 | let _: String = From::from("foo".to_string()); +51 | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:42:13 + --> $DIR/identity_conversion.rs:52:13 | -42 | let _ = String::from("foo".to_string()); +52 | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:43:13 + --> $DIR/identity_conversion.rs:53:13 | -43 | let _ = String::from(format!("A: {:04}", 123)); +53 | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: identical conversion - --> $DIR/identity_conversion.rs:44:13 + --> $DIR/identity_conversion.rs:54:13 | -44 | let _ = "".lines().into_iter(); +54 | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: identical conversion - --> $DIR/identity_conversion.rs:45:13 + --> $DIR/identity_conversion.rs:55:13 | -45 | let _ = vec![1, 2, 3].into_iter().into_iter(); +55 | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: aborting due to 9 previous errors diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index ae8c66faa41..35afb85109f 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index e494250c019..332350fd1d8 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -1,51 +1,51 @@ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:13:5 + --> $DIR/identity_op.rs:23:5 | -13 | x + 0; +23 | x + 0; | ^^^^^ | = note: `-D clippy::identity-op` implied by `-D warnings` error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:14:5 + --> $DIR/identity_op.rs:24:5 | -14 | x + (1 - 1); +24 | x + (1 - 1); | ^^^^^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:16:5 + --> $DIR/identity_op.rs:26:5 | -16 | 0 + x; +26 | 0 + x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:19:5 + --> $DIR/identity_op.rs:29:5 | -19 | x | (0); +29 | x | (0); | ^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:22:5 + --> $DIR/identity_op.rs:32:5 | -22 | x * 1; +32 | x * 1; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:23:5 + --> $DIR/identity_op.rs:33:5 | -23 | 1 * x; +33 | 1 * x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:29:5 + --> $DIR/identity_op.rs:39:5 | -29 | -1 & x; +39 | -1 & x; | ^^^^^^ error: the operation is ineffective. Consider reducing it to `u` - --> $DIR/identity_op.rs:32:5 + --> $DIR/identity_op.rs:42:5 | -32 | u & 255; +42 | u & 255; | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/tests/ui/if_let_redundant_pattern_matching.rs b/tests/ui/if_let_redundant_pattern_matching.rs index 90265853f00..84f4b711f53 100644 --- a/tests/ui/if_let_redundant_pattern_matching.rs +++ b/tests/ui/if_let_redundant_pattern_matching.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/if_let_redundant_pattern_matching.stderr b/tests/ui/if_let_redundant_pattern_matching.stderr index 9046625855c..00eb7885540 100644 --- a/tests/ui/if_let_redundant_pattern_matching.stderr +++ b/tests/ui/if_let_redundant_pattern_matching.stderr @@ -1,27 +1,27 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/if_let_redundant_pattern_matching.rs:9:12 - | -9 | if let Ok(_) = Ok::<i32, i32>(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` - | - = note: `-D clippy::if-let-redundant-pattern-matching` implied by `-D warnings` + --> $DIR/if_let_redundant_pattern_matching.rs:19:12 + | +19 | if let Ok(_) = Ok::<i32, i32>(42) {} + | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` + | + = note: `-D clippy::if-let-redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/if_let_redundant_pattern_matching.rs:11:12 + --> $DIR/if_let_redundant_pattern_matching.rs:21:12 | -11 | if let Err(_) = Err::<i32, i32>(42) { +21 | if let Err(_) = Err::<i32, i32>(42) { | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/if_let_redundant_pattern_matching.rs:14:12 + --> $DIR/if_let_redundant_pattern_matching.rs:24:12 | -14 | if let None = None::<()> { +24 | if let None = None::<()> { | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/if_let_redundant_pattern_matching.rs:17:12 + --> $DIR/if_let_redundant_pattern_matching.rs:27:12 | -17 | if let Some(_) = Some(42) { +27 | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: aborting due to 4 previous errors diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index bb16e16700b..b0744d8c600 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all)] diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 9682f6dc18f..a054ac6223d 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -1,24 +1,24 @@ error: Unnecessary boolean `not` operation - --> $DIR/if_not_else.rs:9:5 + --> $DIR/if_not_else.rs:19:5 | -9 | / if !bla() { -10 | | println!("Bugs"); -11 | | } else { -12 | | println!("Bunny"); -13 | | } +19 | / if !bla() { +20 | | println!("Bugs"); +21 | | } else { +22 | | println!("Bunny"); +23 | | } | |_____^ | = note: `-D clippy::if-not-else` implied by `-D warnings` = help: remove the `!` and swap the blocks of the if/else error: Unnecessary `!=` operation - --> $DIR/if_not_else.rs:14:5 + --> $DIR/if_not_else.rs:24:5 | -14 | / if 4 != 5 { -15 | | println!("Bugs"); -16 | | } else { -17 | | println!("Bunny"); -18 | | } +24 | / if 4 != 5 { +25 | | println!("Bugs"); +26 | | } else { +27 | | println!("Bunny"); +28 | | } | |_____^ | = help: change to `==` and swap the blocks of the if/else diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index 7da0e04e59e..6c2152220cf 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(dead_code)] diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 13d4a76558d..c24a96e8aa7 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -1,34 +1,34 @@ error: Multiple implementations of this structure - --> $DIR/impl.rs:12:1 + --> $DIR/impl.rs:22:1 | -12 | / impl MyStruct { -13 | | fn second() {} -14 | | } +22 | / impl MyStruct { +23 | | fn second() {} +24 | | } | |_^ | = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` note: First implementation here - --> $DIR/impl.rs:8:1 + --> $DIR/impl.rs:18:1 | -8 | / impl MyStruct { -9 | | fn first() {} -10 | | } +18 | / impl MyStruct { +19 | | fn first() {} +20 | | } | |_^ error: Multiple implementations of this structure - --> $DIR/impl.rs:26:5 + --> $DIR/impl.rs:36:5 | -26 | / impl super::MyStruct { -27 | | fn third() {} -28 | | } +36 | / impl super::MyStruct { +37 | | fn third() {} +38 | | } | |_____^ | note: First implementation here - --> $DIR/impl.rs:8:1 + --> $DIR/impl.rs:18:1 | -8 | / impl MyStruct { -9 | | fn first() {} -10 | | } +18 | / impl MyStruct { +19 | | fn first() {} +20 | | } | |_^ error: aborting due to 2 previous errors diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index 49df39ca71b..a6be909c0cc 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![allow(unused)] use std::collections::{HashMap, HashSet}; diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 5bb6f11b2a7..c561e0a3dfb 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,136 +1,136 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:11:35 + --> $DIR/implicit_hasher.rs:21:35 | -11 | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { +21 | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { | ^^^^^^^^^^^^^ | = note: `-D clippy::implicit-hasher` implied by `-D warnings` help: consider adding a type parameter | -11 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> { +21 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ help: ...and use generic constructor | -17 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) +27 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:20:36 + --> $DIR/implicit_hasher.rs:30:36 | -20 | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { +30 | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { | ^^^^^^^^^^^^^ help: consider adding a type parameter | -20 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) { +30 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ help: ...and use generic constructor | -22 | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),)) +32 | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),)) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:19 + --> $DIR/implicit_hasher.rs:35:19 | -25 | impl Foo<i16> for HashMap<String, String> { +35 | impl Foo<i16> for HashMap<String, String> { | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding a type parameter | -25 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> { +35 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: ...and use generic constructor | -27 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) +37 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:43:32 + --> $DIR/implicit_hasher.rs:53:32 | -43 | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { +53 | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { | ^^^^^^^^^^ help: consider adding a type parameter | -43 | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> { +53 | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ help: ...and use generic constructor | -45 | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) +55 | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:48:19 + --> $DIR/implicit_hasher.rs:58:19 | -48 | impl Foo<i16> for HashSet<String> { +58 | impl Foo<i16> for HashSet<String> { | ^^^^^^^^^^^^^^^ help: consider adding a type parameter | -48 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> { +58 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ help: ...and use generic constructor | -50 | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) +60 | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:65:23 + --> $DIR/implicit_hasher.rs:75:23 | -65 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { +75 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^^^^^^ help: consider adding a type parameter | -65 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) { +75 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:65:53 + --> $DIR/implicit_hasher.rs:75:53 | -65 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { +75 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^ help: consider adding a type parameter | -65 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) { +75 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:70:43 + --> $DIR/implicit_hasher.rs:80:43 | -70 | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { +80 | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { | ^^^^^^^^^^^^^ ... -83 | gen!(impl); +93 | gen!(impl); | ----------- in this macro invocation help: consider adding a type parameter | -70 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> { +80 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ help: ...and use generic constructor | -72 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) +82 | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:78:33 + --> $DIR/implicit_hasher.rs:88:33 | -78 | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { +88 | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^^^^^^ ... -84 | gen!(fn bar); +94 | gen!(fn bar); | ------------- in this macro invocation help: consider adding a type parameter | -78 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) { +88 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:78:63 + --> $DIR/implicit_hasher.rs:88:63 | -78 | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { +88 | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) { | ^^^^^^^^^^^^ ... -84 | gen!(fn bar); +94 | gen!(fn bar); | ------------- in this macro invocation help: consider adding a type parameter | -78 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) { +88 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ error: aborting due to 10 previous errors diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index 056d8761109..dc73952ca25 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::inconsistent_digit_grouping)] diff --git a/tests/ui/inconsistent_digit_grouping.stderr b/tests/ui/inconsistent_digit_grouping.stderr index 51eeca2b864..a417394629e 100644 --- a/tests/ui/inconsistent_digit_grouping.stderr +++ b/tests/ui/inconsistent_digit_grouping.stderr @@ -1,34 +1,34 @@ error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:7:16 - | -7 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); - | ^^^^^^^^ help: consider: `123_456` - | - = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + --> $DIR/inconsistent_digit_grouping.rs:17:16 + | +17 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + | ^^^^^^^^ help: consider: `123_456` + | + = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:7:26 - | -7 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); - | ^^^^^^^^^^ help: consider: `12_345_678` + --> $DIR/inconsistent_digit_grouping.rs:17:26 + | +17 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + | ^^^^^^^^^^ help: consider: `12_345_678` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:7:38 - | -7 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); - | ^^^^^^^^ help: consider: `1_234_567` + --> $DIR/inconsistent_digit_grouping.rs:17:38 + | +17 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + | ^^^^^^^^ help: consider: `1_234_567` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:7:48 - | -7 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); - | ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32` + --> $DIR/inconsistent_digit_grouping.rs:17:48 + | +17 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + | ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:7:64 - | -7 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); - | ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32` + --> $DIR/inconsistent_digit_grouping.rs:17:64 + | +17 | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + | ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32` error: aborting due to 5 previous errors diff --git a/tests/ui/indexing_slicing.rs b/tests/ui/indexing_slicing.rs index b9f1c4a4a5d..8d3f3cee99a 100644 --- a/tests/ui/indexing_slicing.rs +++ b/tests/ui/indexing_slicing.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(plugin)] diff --git a/tests/ui/indexing_slicing.stderr b/tests/ui/indexing_slicing.stderr index 3f09a6516e0..7d847c7a673 100644 --- a/tests/ui/indexing_slicing.stderr +++ b/tests/ui/indexing_slicing.stderr @@ -1,268 +1,268 @@ error: indexing may panic. - --> $DIR/indexing_slicing.rs:13:5 + --> $DIR/indexing_slicing.rs:23:5 | -13 | x[index]; +23 | x[index]; | ^^^^^^^^ | = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:14:6 + --> $DIR/indexing_slicing.rs:24:6 | -14 | &x[index..]; +24 | &x[index..]; | ^^^^^^^^^^ | = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:15:6 + --> $DIR/indexing_slicing.rs:25:6 | -15 | &x[..index]; +25 | &x[..index]; | ^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:16:6 + --> $DIR/indexing_slicing.rs:26:6 | -16 | &x[index_from..index_to]; +26 | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:17:6 + --> $DIR/indexing_slicing.rs:27:6 | -17 | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. +27 | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:17:6 + --> $DIR/indexing_slicing.rs:27:6 | -17 | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. +27 | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^ | = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:20:6 + --> $DIR/indexing_slicing.rs:30:6 | -20 | &x[..=4]; +30 | &x[..=4]; | ^^^^^^^ | = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` error: range is out of bounds - --> $DIR/indexing_slicing.rs:21:6 + --> $DIR/indexing_slicing.rs:31:6 | -21 | &x[1..5]; +31 | &x[1..5]; | ^^^^^^^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:22:6 + --> $DIR/indexing_slicing.rs:32:6 | -22 | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. +32 | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. | ^^^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:22:6 + --> $DIR/indexing_slicing.rs:32:6 | -22 | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. +32 | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. | ^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:23:6 + --> $DIR/indexing_slicing.rs:33:6 | -23 | &x[5..]; +33 | &x[5..]; | ^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:24:6 + --> $DIR/indexing_slicing.rs:34:6 | -24 | &x[..5]; +34 | &x[..5]; | ^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:25:6 + --> $DIR/indexing_slicing.rs:35:6 | -25 | &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>(); +35 | &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>(); | ^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:26:6 + --> $DIR/indexing_slicing.rs:36:6 | -26 | &x[0..=4]; +36 | &x[0..=4]; | ^^^^^^^^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:27:6 + --> $DIR/indexing_slicing.rs:37:6 | -27 | &x[0..][..3]; +37 | &x[0..][..3]; | ^^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:28:6 + --> $DIR/indexing_slicing.rs:38:6 | -28 | &x[1..][..5]; +38 | &x[1..][..5]; | ^^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:41:5 + --> $DIR/indexing_slicing.rs:51:5 | -41 | y[0]; +51 | y[0]; | ^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:42:6 + --> $DIR/indexing_slicing.rs:52:6 | -42 | &y[1..2]; +52 | &y[1..2]; | ^^^^^^^ | = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:43:6 + --> $DIR/indexing_slicing.rs:53:6 | -43 | &y[0..=4]; +53 | &y[0..=4]; | ^^^^^^^^ | = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:44:6 + --> $DIR/indexing_slicing.rs:54:6 | -44 | &y[..=4]; +54 | &y[..=4]; | ^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:50:6 + --> $DIR/indexing_slicing.rs:60:6 | -50 | &empty[1..5]; +60 | &empty[1..5]; | ^^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:51:6 + --> $DIR/indexing_slicing.rs:61:6 | -51 | &empty[0..=4]; +61 | &empty[0..=4]; | ^^^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:52:6 + --> $DIR/indexing_slicing.rs:62:6 | -52 | &empty[..=4]; +62 | &empty[..=4]; | ^^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:53:6 + --> $DIR/indexing_slicing.rs:63:6 | -53 | &empty[1..]; +63 | &empty[1..]; | ^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:54:6 + --> $DIR/indexing_slicing.rs:64:6 | -54 | &empty[..4]; +64 | &empty[..4]; | ^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:55:6 + --> $DIR/indexing_slicing.rs:65:6 | -55 | &empty[0..=0]; +65 | &empty[0..=0]; | ^^^^^^^^^^^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:56:6 + --> $DIR/indexing_slicing.rs:66:6 | -56 | &empty[..=0]; +66 | &empty[..=0]; | ^^^^^^^^^^^ error: indexing may panic. - --> $DIR/indexing_slicing.rs:64:5 + --> $DIR/indexing_slicing.rs:74:5 | -64 | v[0]; +74 | v[0]; | ^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:65:5 + --> $DIR/indexing_slicing.rs:75:5 | -65 | v[10]; +75 | v[10]; | ^^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:66:5 + --> $DIR/indexing_slicing.rs:76:5 | -66 | v[1 << 3]; +76 | v[1 << 3]; | ^^^^^^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:67:6 + --> $DIR/indexing_slicing.rs:77:6 | -67 | &v[10..100]; +77 | &v[10..100]; | ^^^^^^^^^^ | = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:68:6 + --> $DIR/indexing_slicing.rs:78:6 | -68 | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. +78 | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^^^^^^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:68:6 + --> $DIR/indexing_slicing.rs:78:6 | -68 | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. +78 | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^^^^^^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:69:6 + --> $DIR/indexing_slicing.rs:79:6 | -69 | &v[10..]; +79 | &v[10..]; | ^^^^^^^ | = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:70:6 + --> $DIR/indexing_slicing.rs:80:6 | -70 | &v[..100]; +80 | &v[..100]; | ^^^^^^^^ | = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:82:5 + --> $DIR/indexing_slicing.rs:92:5 | -82 | v[N]; +92 | v[N]; | ^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:83:5 + --> $DIR/indexing_slicing.rs:93:5 | -83 | v[M]; +93 | v[M]; | ^^^^ | = help: Consider using `.get(n)` or `.get_mut(n)` instead diff --git a/tests/ui/infallible_destructuring_match.rs b/tests/ui/infallible_destructuring_match.rs index b3e2835d72f..bd4e4b49a4a 100644 --- a/tests/ui/infallible_destructuring_match.rs +++ b/tests/ui/infallible_destructuring_match.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(exhaustive_patterns, never_type)] diff --git a/tests/ui/infallible_destructuring_match.stderr b/tests/ui/infallible_destructuring_match.stderr index 6e26741fc87..bce83b91242 100644 --- a/tests/ui/infallible_destructuring_match.stderr +++ b/tests/ui/infallible_destructuring_match.stderr @@ -1,27 +1,27 @@ error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:18:5 + --> $DIR/infallible_destructuring_match.rs:28:5 | -18 | / let data = match wrapper { -19 | | SingleVariantEnum::Variant(i) => i, -20 | | }; +28 | / let data = match wrapper { +29 | | SingleVariantEnum::Variant(i) => i, +30 | | }; | |______^ help: try this: `let SingleVariantEnum::Variant(data) = wrapper;` | = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings` error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:39:5 + --> $DIR/infallible_destructuring_match.rs:49:5 | -39 | / let data = match wrapper { -40 | | TupleStruct(i) => i, -41 | | }; +49 | / let data = match wrapper { +50 | | TupleStruct(i) => i, +51 | | }; | |______^ help: try this: `let TupleStruct(data) = wrapper;` error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:60:5 + --> $DIR/infallible_destructuring_match.rs:70:5 | -60 | / let data = match wrapper { -61 | | Ok(i) => i, -62 | | }; +70 | / let data = match wrapper { +71 | | Ok(i) => i, +72 | | }; | |______^ help: try this: `let Ok(data) = wrapper;` error: aborting due to 3 previous errors diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index 44fa934aa26..cf30a2e35ed 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::iter::repeat; diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index c3d67bdfde3..5b783c2b8b9 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,99 +1,99 @@ error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/infinite_iter.rs:10:5 + --> $DIR/infinite_iter.rs:20:5 | -10 | repeat(0_u8).collect::<Vec<_>>(); // infinite iter +20 | repeat(0_u8).collect::<Vec<_>>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unused-collect` implied by `-D warnings` error: infinite iteration detected - --> $DIR/infinite_iter.rs:10:5 + --> $DIR/infinite_iter.rs:20:5 | -10 | repeat(0_u8).collect::<Vec<_>>(); // infinite iter +20 | repeat(0_u8).collect::<Vec<_>>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/infinite_iter.rs:8:8 + --> $DIR/infinite_iter.rs:18:8 | -8 | #[deny(clippy::infinite_iter)] +18 | #[deny(clippy::infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:11:5 + --> $DIR/infinite_iter.rs:21:5 | -11 | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter +21 | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:12:5 + --> $DIR/infinite_iter.rs:22:5 | -12 | (0..8_u64).chain(0..).max(); // infinite iter +22 | (0..8_u64).chain(0..).max(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:14:5 + --> $DIR/infinite_iter.rs:24:5 | -14 | (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter +24 | (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:16:5 + --> $DIR/infinite_iter.rs:26:5 | -16 | (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter +26 | (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:17:5 + --> $DIR/infinite_iter.rs:27:5 | -17 | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter +27 | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:24:5 + --> $DIR/infinite_iter.rs:34:5 | -24 | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter +34 | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/infinite_iter.rs:22:8 + --> $DIR/infinite_iter.rs:32:8 | -22 | #[deny(clippy::maybe_infinite_iter)] +32 | #[deny(clippy::maybe_infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:25:5 + --> $DIR/infinite_iter.rs:35:5 | -25 | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter +35 | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:26:5 + --> $DIR/infinite_iter.rs:36:5 | -26 | (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter +36 | (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:27:5 + --> $DIR/infinite_iter.rs:37:5 | -27 | (0..).find(|x| *x == 24); // maybe infinite iter +37 | (0..).find(|x| *x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:28:5 + --> $DIR/infinite_iter.rs:38:5 | -28 | (0..).position(|x| x == 24); // maybe infinite iter +38 | (0..).position(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:29:5 + --> $DIR/infinite_iter.rs:39:5 | -29 | (0..).any(|x| x == 24); // maybe infinite iter +39 | (0..).any(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:30:5 + --> $DIR/infinite_iter.rs:40:5 | -30 | (0..).all(|x| x == 24); // maybe infinite iter +40 | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 9449a295e3a..e837e563f18 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index edbe4937425..fdbdd13fd8f 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,57 +1,57 @@ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:16:11 + --> $DIR/infinite_loop.rs:26:11 | -16 | while y < 10 { +26 | while y < 10 { | ^^^^^^ | = note: #[deny(clippy::while_immutable_condition)] on by default error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:21:11 + --> $DIR/infinite_loop.rs:31:11 | -21 | while y < 10 && x < 3 { +31 | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:28:11 + --> $DIR/infinite_loop.rs:38:11 | -28 | while !cond { +38 | while !cond { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:72:11 + --> $DIR/infinite_loop.rs:82:11 | -72 | while i < 3 { +82 | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:77:11 + --> $DIR/infinite_loop.rs:87:11 | -77 | while i < 3 && j > 0 { +87 | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:81:11 + --> $DIR/infinite_loop.rs:91:11 | -81 | while i < 3 { +91 | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:96:11 - | -96 | while i < 3 { - | ^^^^^ + --> $DIR/infinite_loop.rs:106:11 + | +106 | while i < 3 { + | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:101:11 + --> $DIR/infinite_loop.rs:111:11 | -101 | while i < 3 { +111 | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:164:15 + --> $DIR/infinite_loop.rs:174:15 | -164 | while self.count < n { +174 | while self.count < n { | ^^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs index 830da6d1124..93dff0d350f 100644 --- a/tests/ui/inline_fn_without_body.rs +++ b/tests/ui/inline_fn_without_body.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/inline_fn_without_body.stderr b/tests/ui/inline_fn_without_body.stderr index a9a52b19053..112fad812e5 100644 --- a/tests/ui/inline_fn_without_body.stderr +++ b/tests/ui/inline_fn_without_body.stderr @@ -1,25 +1,25 @@ error: use of `#[inline]` on trait method `default_inline` which has no body - --> $DIR/inline_fn_without_body.rs:8:5 - | -8 | #[inline] - | _____-^^^^^^^^ -9 | | fn default_inline(); - | |____- help: remove - | - = note: `-D clippy::inline-fn-without-body` implied by `-D warnings` + --> $DIR/inline_fn_without_body.rs:18:5 + | +18 | #[inline] + | _____-^^^^^^^^ +19 | | fn default_inline(); + | |____- help: remove + | + = note: `-D clippy::inline-fn-without-body` implied by `-D warnings` error: use of `#[inline]` on trait method `always_inline` which has no body - --> $DIR/inline_fn_without_body.rs:11:5 + --> $DIR/inline_fn_without_body.rs:21:5 | -11 | #[inline(always)]fn always_inline(); +21 | #[inline(always)]fn always_inline(); | ^^^^^^^^^^^^^^^^^ help: remove error: use of `#[inline]` on trait method `never_inline` which has no body - --> $DIR/inline_fn_without_body.rs:13:5 + --> $DIR/inline_fn_without_body.rs:23:5 | -13 | #[inline(never)] +23 | #[inline(never)] | _____-^^^^^^^^^^^^^^^ -14 | | fn never_inline(); +24 | | fn never_inline(); | |____- help: remove error: aborting due to 3 previous errors diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index 1eb0e49290f..df16a393824 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 12d7000dcfa..5612b203290 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,43 +1,43 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:10:5 + --> $DIR/int_plus_one.rs:20:5 | -10 | x >= y + 1; +20 | x >= y + 1; | ^^^^^^^^^^ | = note: `-D clippy::int-plus-one` implied by `-D warnings` help: change `>= y + 1` to `> y` as shown | -10 | x > y; +20 | x > y; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:11:5 + --> $DIR/int_plus_one.rs:21:5 | -11 | y + 1 <= x; +21 | y + 1 <= x; | ^^^^^^^^^^ help: change `>= y + 1` to `> y` as shown | -11 | y < x; +21 | y < x; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:13:5 + --> $DIR/int_plus_one.rs:23:5 | -13 | x - 1 >= y; +23 | x - 1 >= y; | ^^^^^^^^^^ help: change `>= y + 1` to `> y` as shown | -13 | x > y; +23 | x > y; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:14:5 + --> $DIR/int_plus_one.rs:24:5 | -14 | y <= x - 1; +24 | y <= x - 1; | ^^^^^^^^^^ help: change `>= y + 1` to `> y` as shown | -14 | y < x; +24 | y < x; | ^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/invalid_ref.rs b/tests/ui/invalid_ref.rs index ce2596c0c1a..9fb6c7fd4b7 100644 --- a/tests/ui/invalid_ref.rs +++ b/tests/ui/invalid_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index 1ca825dd94c..52868e908ca 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,48 +1,48 @@ error: reference to zeroed memory - --> $DIR/invalid_ref.rs:27:24 + --> $DIR/invalid_ref.rs:37:24 | -27 | let ref_zero: &T = std::mem::zeroed(); // warning +37 | let ref_zero: &T = std::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^ | = note: #[deny(clippy::invalid_ref)] on by default = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:31:24 + --> $DIR/invalid_ref.rs:41:24 | -31 | let ref_zero: &T = core::mem::zeroed(); // warning +41 | let ref_zero: &T = core::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:35:24 + --> $DIR/invalid_ref.rs:45:24 | -35 | let ref_zero: &T = std::intrinsics::init(); // warning +45 | let ref_zero: &T = std::intrinsics::init(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:39:26 + --> $DIR/invalid_ref.rs:49:26 | -39 | let ref_uninit: &T = std::mem::uninitialized(); // warning +49 | let ref_uninit: &T = std::mem::uninitialized(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:43:26 + --> $DIR/invalid_ref.rs:53:26 | -43 | let ref_uninit: &T = core::mem::uninitialized(); // warning +53 | let ref_uninit: &T = core::mem::uninitialized(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:47:26 + --> $DIR/invalid_ref.rs:57:26 | -47 | let ref_uninit: &T = std::intrinsics::uninit(); // warning +57 | let ref_uninit: &T = std::intrinsics::uninit(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html diff --git a/tests/ui/invalid_upcast_comparisons.rs b/tests/ui/invalid_upcast_comparisons.rs index 0a700518f8f..5c17970d337 100644 --- a/tests/ui/invalid_upcast_comparisons.rs +++ b/tests/ui/invalid_upcast_comparisons.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/invalid_upcast_comparisons.stderr b/tests/ui/invalid_upcast_comparisons.stderr index ce6d1dfa1ae..e41132dfc8b 100644 --- a/tests/ui/invalid_upcast_comparisons.stderr +++ b/tests/ui/invalid_upcast_comparisons.stderr @@ -1,165 +1,165 @@ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:16:5 + --> $DIR/invalid_upcast_comparisons.rs:26:5 | -16 | (u8 as u32) > 300; +26 | (u8 as u32) > 300; | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings` error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:17:5 + --> $DIR/invalid_upcast_comparisons.rs:27:5 | -17 | (u8 as i32) > 300; +27 | (u8 as i32) > 300; | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:18:5 + --> $DIR/invalid_upcast_comparisons.rs:28:5 | -18 | (u8 as u32) == 300; +28 | (u8 as u32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:19:5 + --> $DIR/invalid_upcast_comparisons.rs:29:5 | -19 | (u8 as i32) == 300; +29 | (u8 as i32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:20:5 + --> $DIR/invalid_upcast_comparisons.rs:30:5 | -20 | 300 < (u8 as u32); +30 | 300 < (u8 as u32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:21:5 + --> $DIR/invalid_upcast_comparisons.rs:31:5 | -21 | 300 < (u8 as i32); +31 | 300 < (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:22:5 + --> $DIR/invalid_upcast_comparisons.rs:32:5 | -22 | 300 == (u8 as u32); +32 | 300 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:23:5 + --> $DIR/invalid_upcast_comparisons.rs:33:5 | -23 | 300 == (u8 as i32); +33 | 300 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:25:5 + --> $DIR/invalid_upcast_comparisons.rs:35:5 | -25 | (u8 as u32) <= 300; +35 | (u8 as u32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:26:5 + --> $DIR/invalid_upcast_comparisons.rs:36:5 | -26 | (u8 as i32) <= 300; +36 | (u8 as i32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:27:5 + --> $DIR/invalid_upcast_comparisons.rs:37:5 | -27 | (u8 as u32) != 300; +37 | (u8 as u32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:28:5 + --> $DIR/invalid_upcast_comparisons.rs:38:5 | -28 | (u8 as i32) != 300; +38 | (u8 as i32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:29:5 + --> $DIR/invalid_upcast_comparisons.rs:39:5 | -29 | 300 >= (u8 as u32); +39 | 300 >= (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:30:5 + --> $DIR/invalid_upcast_comparisons.rs:40:5 | -30 | 300 >= (u8 as i32); +40 | 300 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:31:5 + --> $DIR/invalid_upcast_comparisons.rs:41:5 | -31 | 300 != (u8 as u32); +41 | 300 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:32:5 + --> $DIR/invalid_upcast_comparisons.rs:42:5 | -32 | 300 != (u8 as i32); +42 | 300 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:35:5 + --> $DIR/invalid_upcast_comparisons.rs:45:5 | -35 | (u8 as i32) < 0; +45 | (u8 as i32) < 0; | ^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:36:5 + --> $DIR/invalid_upcast_comparisons.rs:46:5 | -36 | -5 != (u8 as i32); +46 | -5 != (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:38:5 + --> $DIR/invalid_upcast_comparisons.rs:48:5 | -38 | (u8 as i32) >= 0; +48 | (u8 as i32) >= 0; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:39:5 + --> $DIR/invalid_upcast_comparisons.rs:49:5 | -39 | -5 == (u8 as i32); +49 | -5 == (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:42:5 + --> $DIR/invalid_upcast_comparisons.rs:52:5 | -42 | 1337 == (u8 as i32); +52 | 1337 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:43:5 + --> $DIR/invalid_upcast_comparisons.rs:53:5 | -43 | 1337 == (u8 as u32); +53 | 1337 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:45:5 + --> $DIR/invalid_upcast_comparisons.rs:55:5 | -45 | 1337 != (u8 as i32); +55 | 1337 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:46:5 + --> $DIR/invalid_upcast_comparisons.rs:56:5 | -46 | 1337 != (u8 as u32); +56 | 1337 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:61:5 + --> $DIR/invalid_upcast_comparisons.rs:71:5 | -61 | (u8 as i32) > -1; +71 | (u8 as i32) > -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:62:5 + --> $DIR/invalid_upcast_comparisons.rs:72:5 | -62 | (u8 as i32) < -1; +72 | (u8 as i32) < -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:78:5 + --> $DIR/invalid_upcast_comparisons.rs:88:5 | -78 | -5 >= (u8 as i32); +88 | -5 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: aborting due to 27 previous errors diff --git a/tests/ui/issue-3145.rs b/tests/ui/issue-3145.rs index f497d5550af..74a11925a76 100644 --- a/tests/ui/issue-3145.rs +++ b/tests/ui/issue-3145.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { println!("{}" a); //~ERROR expected token: `,` } diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr index e289df043a3..2086f11463f 100644 --- a/tests/ui/issue-3145.stderr +++ b/tests/ui/issue-3145.stderr @@ -1,8 +1,8 @@ error: expected token: `,` - --> $DIR/issue-3145.rs:2:19 - | -2 | println!("{}" a); //~ERROR expected token: `,` - | ^ + --> $DIR/issue-3145.rs:12:19 + | +12 | println!("{}" a); //~ERROR expected token: `,` + | ^ error: aborting due to previous error diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index 398e0d1d1f0..d251d51f3fc 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::while_let_on_iterator)] diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr index fe2d9d45b77..291e64bec6f 100644 --- a/tests/ui/issue_2356.stderr +++ b/tests/ui/issue_2356.stderr @@ -1,13 +1,13 @@ error: this loop could be written as a `for` loop - --> $DIR/issue_2356.rs:17:29 + --> $DIR/issue_2356.rs:27:29 | -17 | while let Some(e) = it.next() { +27 | while let Some(e) = it.next() { | ^^^^^^^^^ help: try: `for e in it { .. }` | note: lint level defined here - --> $DIR/issue_2356.rs:3:9 + --> $DIR/issue_2356.rs:13:9 | -3 | #![deny(clippy::while_let_on_iterator)] +13 | #![deny(clippy::while_let_on_iterator)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index 9626a59ed02..d765adae38c 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::items_after_statements)] diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index 6d20899b5ec..15c0cc3af4c 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -1,15 +1,15 @@ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:12:5 + --> $DIR/item_after_statement.rs:22:5 | -12 | fn foo() { println!("foo"); } +22 | fn foo() { println!("foo"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::items-after-statements` implied by `-D warnings` error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:17:5 + --> $DIR/item_after_statement.rs:27:5 | -17 | fn foo() { println!("foo"); } +27 | fn foo() { println!("foo"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index af569ea7566..7cc1f9c881d 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::large_digit_groups)] diff --git a/tests/ui/large_digit_groups.stderr b/tests/ui/large_digit_groups.stderr index b322ded9cfb..c38abb8887c 100644 --- a/tests/ui/large_digit_groups.stderr +++ b/tests/ui/large_digit_groups.stderr @@ -1,40 +1,40 @@ error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:16 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64` - | - = note: `-D clippy::large-digit-groups` implied by `-D warnings` + --> $DIR/large_digit_groups.rs:17:16 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64` + | + = note: `-D clippy::large-digit-groups` implied by `-D warnings` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:31 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` + --> $DIR/large_digit_groups.rs:17:31 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:54 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^ help: consider: `123_456_f32` + --> $DIR/large_digit_groups.rs:17:54 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^ help: consider: `123_456_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:67 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32` + --> $DIR/large_digit_groups.rs:17:67 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:83 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f32` + --> $DIR/large_digit_groups.rs:17:83 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:7:102 - | -7 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); - | ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f32` + --> $DIR/large_digit_groups.rs:17:102 + | +17 | let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32); + | ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f32` error: aborting due to 6 previous errors diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index cd1772ad1d1..729cc8940ef 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index af42f905458..4bb25dd855a 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -1,69 +1,69 @@ error: large size difference between variants - --> $DIR/large_enum_variant.rs:10:5 + --> $DIR/large_enum_variant.rs:20:5 | -10 | B([i32; 8000]), +20 | B([i32; 8000]), | ^^^^^^^^^^^^^^ | = note: `-D clippy::large-enum-variant` implied by `-D warnings` help: consider boxing the large fields to reduce the total size of the enum | -10 | B(Box<[i32; 8000]>), +20 | B(Box<[i32; 8000]>), | ^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:21:5 + --> $DIR/large_enum_variant.rs:31:5 | -21 | C(T, [i32; 8000]), +31 | C(T, [i32; 8000]), | ^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:21:5 + --> $DIR/large_enum_variant.rs:31:5 | -21 | C(T, [i32; 8000]), +31 | C(T, [i32; 8000]), | ^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:34:5 + --> $DIR/large_enum_variant.rs:44:5 | -34 | ContainingLargeEnum(LargeEnum), +44 | ContainingLargeEnum(LargeEnum), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | -34 | ContainingLargeEnum(Box<LargeEnum>), +44 | ContainingLargeEnum(Box<LargeEnum>), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:37:5 + --> $DIR/large_enum_variant.rs:47:5 | -37 | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), +47 | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:37:5 + --> $DIR/large_enum_variant.rs:47:5 | -37 | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), +47 | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:44:5 + --> $DIR/large_enum_variant.rs:54:5 | -44 | StructLikeLarge { x: [i32; 8000], y: i32 }, +54 | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:44:5 + --> $DIR/large_enum_variant.rs:54:5 | -44 | StructLikeLarge { x: [i32; 8000], y: i32 }, +54 | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:49:5 + --> $DIR/large_enum_variant.rs:59:5 | -49 | StructLikeLarge2 { x: [i32; 8000] }, +59 | StructLikeLarge2 { x: [i32; 8000] }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | -49 | StructLikeLarge2 { x: Box<[i32; 8000]> }, +59 | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index b188db5186e..a8f1e283643 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::len_without_is_empty, clippy::len_zero)] diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index 49e365e6c21..ffba33a65f8 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -1,139 +1,139 @@ error: item `PubOne` has a public `len` method but no corresponding `is_empty` method - --> $DIR/len_zero.rs:8:1 + --> $DIR/len_zero.rs:18:1 | -8 | / impl PubOne { -9 | | pub fn len(self: &Self) -> isize { -10 | | 1 -11 | | } -12 | | } +18 | / impl PubOne { +19 | | pub fn len(self: &Self) -> isize { +20 | | 1 +21 | | } +22 | | } | |_^ | = note: `-D clippy::len-without-is-empty` implied by `-D warnings` error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_zero.rs:57:1 + --> $DIR/len_zero.rs:67:1 | -57 | / pub trait PubTraitsToo { -58 | | fn len(self: &Self) -> isize; -59 | | } +67 | / pub trait PubTraitsToo { +68 | | fn len(self: &Self) -> isize; +69 | | } | |_^ error: item `HasIsEmpty` has a public `len` method but a private `is_empty` method - --> $DIR/len_zero.rs:91:1 - | -91 | / impl HasIsEmpty { -92 | | pub fn len(self: &Self) -> isize { -93 | | 1 -94 | | } -... | -98 | | } -99 | | } - | |_^ + --> $DIR/len_zero.rs:101:1 + | +101 | / impl HasIsEmpty { +102 | | pub fn len(self: &Self) -> isize { +103 | | 1 +104 | | } +... | +108 | | } +109 | | } + | |_^ error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty` method - --> $DIR/len_zero.rs:120:1 + --> $DIR/len_zero.rs:130:1 | -120 | / impl HasWrongIsEmpty { -121 | | pub fn len(self: &Self) -> isize { -122 | | 1 -123 | | } +130 | / impl HasWrongIsEmpty { +131 | | pub fn len(self: &Self) -> isize { +132 | | 1 +133 | | } ... | -127 | | } -128 | | } +137 | | } +138 | | } | |_^ error: length comparison to zero - --> $DIR/len_zero.rs:141:8 + --> $DIR/len_zero.rs:151:8 | -141 | if x.len() == 0 { +151 | if x.len() == 0 { | ^^^^^^^^^^^^ help: using `is_empty` is more concise: `x.is_empty()` | = note: `-D clippy::len-zero` implied by `-D warnings` error: length comparison to zero - --> $DIR/len_zero.rs:145:8 + --> $DIR/len_zero.rs:155:8 | -145 | if "".len() == 0 {} +155 | if "".len() == 0 {} | ^^^^^^^^^^^^^ help: using `is_empty` is more concise: `"".is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:160:8 + --> $DIR/len_zero.rs:170:8 | -160 | if has_is_empty.len() == 0 { +170 | if has_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:163:8 + --> $DIR/len_zero.rs:173:8 | -163 | if has_is_empty.len() != 0 { +173 | if has_is_empty.len() != 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:166:8 + --> $DIR/len_zero.rs:176:8 | -166 | if has_is_empty.len() > 0 { +176 | if has_is_empty.len() > 0 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:169:8 + --> $DIR/len_zero.rs:179:8 | -169 | if has_is_empty.len() < 1 { +179 | if has_is_empty.len() < 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:172:8 + --> $DIR/len_zero.rs:182:8 | -172 | if has_is_empty.len() >= 1 { +182 | if has_is_empty.len() >= 1 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:183:8 + --> $DIR/len_zero.rs:193:8 | -183 | if 0 == has_is_empty.len() { +193 | if 0 == has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:186:8 + --> $DIR/len_zero.rs:196:8 | -186 | if 0 != has_is_empty.len() { +196 | if 0 != has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:189:8 + --> $DIR/len_zero.rs:199:8 | -189 | if 0 < has_is_empty.len() { +199 | if 0 < has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:192:8 + --> $DIR/len_zero.rs:202:8 | -192 | if 1 <= has_is_empty.len() { +202 | if 1 <= has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:195:8 + --> $DIR/len_zero.rs:205:8 | -195 | if 1 > has_is_empty.len() { +205 | if 1 > has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:209:8 + --> $DIR/len_zero.rs:219:8 | -209 | if with_is_empty.len() == 0 { +219 | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `with_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:222:8 + --> $DIR/len_zero.rs:232:8 | -222 | if b.len() != 0 {} +232 | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `is_empty` is more concise: `!b.is_empty()` error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_zero.rs:228:1 + --> $DIR/len_zero.rs:238:1 | -228 | / pub trait DependsOnFoo: Foo { -229 | | fn len(&mut self) -> usize; -230 | | } +238 | / pub trait DependsOnFoo: Foo { +239 | | fn len(&mut self) -> usize; +240 | | } | |_^ error: aborting due to 19 previous errors diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 102b72f3e25..5fca759a4b3 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index 7b4c78003ab..6e2ec6d4aaa 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -1,47 +1,47 @@ error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:57:5 + --> $DIR/let_if_seq.rs:67:5 | -57 | / let mut foo = 0; -58 | | if f() { -59 | | foo = 42; -60 | | } +67 | / let mut foo = 0; +68 | | if f() { +69 | | foo = 42; +70 | | } | |_____^ help: it is more idiomatic to write: `let <mut> foo = if f() { 42 } else { 0 };` | = note: `-D clippy::useless-let-if-seq` implied by `-D warnings` = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:62:5 + --> $DIR/let_if_seq.rs:72:5 | -62 | / let mut bar = 0; -63 | | if f() { -64 | | f(); -65 | | bar = 42; +72 | / let mut bar = 0; +73 | | if f() { +74 | | f(); +75 | | bar = 42; ... | -68 | | f(); -69 | | } +78 | | f(); +79 | | } | |_____^ help: it is more idiomatic to write: `let <mut> bar = if f() { ..; 42 } else { ..; 0 };` | = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:71:5 + --> $DIR/let_if_seq.rs:81:5 | -71 | / let quz; -72 | | if f() { -73 | | quz = 42; -74 | | } else { -75 | | quz = 0; -76 | | } +81 | / let quz; +82 | | if f() { +83 | | quz = 42; +84 | | } else { +85 | | quz = 0; +86 | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:100:5 + --> $DIR/let_if_seq.rs:110:5 | -100 | / let mut baz = 0; -101 | | if f() { -102 | | baz = 42; -103 | | } +110 | / let mut baz = 0; +111 | | if f() { +112 | | baz = 42; +113 | | } | |_____^ help: it is more idiomatic to write: `let <mut> baz = if f() { 42 } else { 0 };` | = note: you might not need `mut` at all diff --git a/tests/ui/let_return.rs b/tests/ui/let_return.rs index 9b584d6e293..380f775689d 100644 --- a/tests/ui/let_return.rs +++ b/tests/ui/let_return.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused)] diff --git a/tests/ui/let_return.stderr b/tests/ui/let_return.stderr index dad628bc912..cdd4b6bd537 100644 --- a/tests/ui/let_return.stderr +++ b/tests/ui/let_return.stderr @@ -1,26 +1,26 @@ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/let_return.rs:10:5 + --> $DIR/let_return.rs:20:5 | -10 | x +20 | x | ^ | = note: `-D clippy::let-and-return` implied by `-D warnings` note: this expression can be directly returned - --> $DIR/let_return.rs:9:13 + --> $DIR/let_return.rs:19:13 | -9 | let x = 5; +19 | let x = 5; | ^ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/let_return.rs:16:9 + --> $DIR/let_return.rs:26:9 | -16 | x +26 | x | ^ | note: this expression can be directly returned - --> $DIR/let_return.rs:15:17 + --> $DIR/let_return.rs:25:17 | -15 | let x = 5; +25 | let x = 5; | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 187ff9d1358..578fcb2ddde 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index f6f5d3f7dcc..e8c7bb37e73 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -1,15 +1,15 @@ error: this let-binding has unit value. Consider omitting `let _x =` - --> $DIR/let_unit.rs:14:5 + --> $DIR/let_unit.rs:24:5 | -14 | let _x = println!("x"); +24 | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::let-unit-value` implied by `-D warnings` error: this let-binding has unit value. Consider omitting `let _a =` - --> $DIR/let_unit.rs:18:9 + --> $DIR/let_unit.rs:28:9 | -18 | let _a = (); +28 | let _a = (); | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index aa5640f4e22..cae18498779 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/lifetimes.stderr b/tests/ui/lifetimes.stderr index 42fb01b7580..9e4fac1e4f2 100644 --- a/tests/ui/lifetimes.stderr +++ b/tests/ui/lifetimes.stderr @@ -1,89 +1,89 @@ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:7:1 - | -7 | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::needless-lifetimes` implied by `-D warnings` + --> $DIR/lifetimes.rs:17:1 + | +17 | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:9:1 - | -9 | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/lifetimes.rs:19:1 + | +19 | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:17:1 + --> $DIR/lifetimes.rs:27:1 | -17 | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x } +27 | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:29:1 + --> $DIR/lifetimes.rs:39:1 | -29 | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } +39 | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:32:1 + --> $DIR/lifetimes.rs:42:1 | -32 | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) } +42 | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:38:1 + --> $DIR/lifetimes.rs:48:1 | -38 | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { } +48 | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:52:1 + --> $DIR/lifetimes.rs:62:1 | -52 | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> -53 | | where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I> -54 | | { unreachable!() } +62 | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +63 | | where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I> +64 | | { unreachable!() } | |__________________^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:77:5 + --> $DIR/lifetimes.rs:87:5 | -77 | fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x } +87 | fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:81:5 + --> $DIR/lifetimes.rs:91:5 | -81 | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { } +91 | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:97:1 - | -97 | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/lifetimes.rs:107:1 + | +107 | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:117:1 + --> $DIR/lifetimes.rs:127:1 | -117 | fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() } +127 | fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:121:1 + --> $DIR/lifetimes.rs:131:1 | -121 | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() } +131 | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:132:1 + --> $DIR/lifetimes.rs:142:1 | -132 | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() } +142 | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided - --> $DIR/lifetimes.rs:136:1 + --> $DIR/lifetimes.rs:146:1 | -136 | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() } +146 | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index 7a9efaeec84..3c1dcf09af2 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::mixed_case_hex_literals)] diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index bd2d1f81831..4e26b9dd321 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -1,181 +1,181 @@ error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:14:17 + --> $DIR/literals.rs:24:17 | -14 | let fail1 = 0xabCD; +24 | let fail1 = 0xabCD; | ^^^^^^ | = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:15:17 + --> $DIR/literals.rs:25:17 | -15 | let fail2 = 0xabCD_u32; +25 | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:16:17 + --> $DIR/literals.rs:26:17 | -16 | let fail2 = 0xabCD_isize; +26 | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:17:27 + --> $DIR/literals.rs:27:27 | -17 | let fail_multi_zero = 000_123usize; +27 | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ | = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` error: this is a decimal constant - --> $DIR/literals.rs:17:27 + --> $DIR/literals.rs:27:27 | -17 | let fail_multi_zero = 000_123usize; +27 | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ | = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings` help: if you mean to use a decimal constant, remove the `0` to remove confusion | -17 | let fail_multi_zero = 123usize; +27 | let fail_multi_zero = 123usize; | ^^^^^^^^ help: if you mean to use an octal constant, use `0o` | -17 | let fail_multi_zero = 0o123usize; +27 | let fail_multi_zero = 0o123usize; | ^^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:22:17 + --> $DIR/literals.rs:32:17 | -22 | let fail3 = 1234i32; +32 | let fail3 = 1234i32; | ^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:23:17 + --> $DIR/literals.rs:33:17 | -23 | let fail4 = 1234u32; +33 | let fail4 = 1234u32; | ^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:24:17 + --> $DIR/literals.rs:34:17 | -24 | let fail5 = 1234isize; +34 | let fail5 = 1234isize; | ^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:25:17 + --> $DIR/literals.rs:35:17 | -25 | let fail6 = 1234usize; +35 | let fail6 = 1234usize; | ^^^^^^^^^ error: float type suffix should be separated by an underscore - --> $DIR/literals.rs:26:17 + --> $DIR/literals.rs:36:17 | -26 | let fail7 = 1.5f32; +36 | let fail7 = 1.5f32; | ^^^^^^ error: this is a decimal constant - --> $DIR/literals.rs:30:17 + --> $DIR/literals.rs:40:17 | -30 | let fail8 = 0123; +40 | let fail8 = 0123; | ^^^^ help: if you mean to use a decimal constant, remove the `0` to remove confusion | -30 | let fail8 = 123; +40 | let fail8 = 123; | ^^^ help: if you mean to use an octal constant, use `0o` | -30 | let fail8 = 0o123; +40 | let fail8 = 0o123; | ^^^^^ error: long literal lacking separators - --> $DIR/literals.rs:41:17 + --> $DIR/literals.rs:51:17 | -41 | let fail9 = 0xabcdef; +51 | let fail9 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` | = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/literals.rs:42:18 + --> $DIR/literals.rs:52:18 | -42 | let fail10 = 0xBAFEBAFE; +52 | let fail10 = 0xBAFEBAFE; | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> $DIR/literals.rs:43:18 + --> $DIR/literals.rs:53:18 | -43 | let fail11 = 0xabcdeff; +53 | let fail11 = 0xabcdeff; | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> $DIR/literals.rs:44:18 + --> $DIR/literals.rs:54:18 | -44 | let fail12 = 0xabcabcabcabcabcabc; +54 | let fail12 = 0xabcabcabcabcabcabc; | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` error: digit groups should be smaller - --> $DIR/literals.rs:45:18 + --> $DIR/literals.rs:55:18 | -45 | let fail13 = 0x1_23456_78901_usize; +55 | let fail13 = 0x1_23456_78901_usize; | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` | = note: `-D clippy::large-digit-groups` implied by `-D warnings` error: mistyped literal suffix - --> $DIR/literals.rs:47:18 + --> $DIR/literals.rs:57:18 | -47 | let fail14 = 2_32; +57 | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` | = note: #[deny(clippy::mistyped_literal_suffixes)] on by default error: mistyped literal suffix - --> $DIR/literals.rs:48:18 + --> $DIR/literals.rs:58:18 | -48 | let fail15 = 4_64; +58 | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/literals.rs:49:18 + --> $DIR/literals.rs:59:18 | -49 | let fail16 = 7_8; +59 | let fail16 = 7_8; | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/literals.rs:50:18 + --> $DIR/literals.rs:60:18 | -50 | let fail17 = 23_16; +60 | let fail17 = 23_16; | ^^^^^ help: did you mean to write: `23_i16` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:52:18 + --> $DIR/literals.rs:62:18 | -52 | let fail19 = 12_3456_21; +62 | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` | = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: mistyped literal suffix - --> $DIR/literals.rs:53:18 + --> $DIR/literals.rs:63:18 | -53 | let fail20 = 2__8; +63 | let fail20 = 2__8; | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/literals.rs:54:18 + --> $DIR/literals.rs:64:18 | -54 | let fail21 = 4___16; +64 | let fail21 = 4___16; | ^^^^^^ help: did you mean to write: `4_i16` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:55:18 + --> $DIR/literals.rs:65:18 | -55 | let fail22 = 3__4___23; +65 | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:56:18 + --> $DIR/literals.rs:66:18 | -56 | let fail23 = 3__16___23; +66 | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: aborting due to 25 previous errors diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 11a5316a367..8a410737f83 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index e80983cdbf7..50856f6a937 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,22 +1,22 @@ error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:6:22 - | -6 | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![5_i8; 6].iter().cloned()` - | - = note: `-D clippy::map-clone` implied by `-D warnings` + --> $DIR/map_clone.rs:16:22 + | +16 | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![5_i8; 6].iter().cloned()` + | + = note: `-D clippy::map-clone` implied by `-D warnings` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:7:26 - | -7 | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` + --> $DIR/map_clone.rs:17:26 + | +17 | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:8:23 - | -8 | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![42, 43].iter().cloned()` + --> $DIR/map_clone.rs:18:23 + | +18 | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![42, 43].iter().cloned()` error: aborting due to 3 previous errors diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index c5cf24d9bb0..b3f86d81e3f 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index d4ce44490d1..d41e6297758 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,10 +1,10 @@ error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` - --> $DIR/map_flatten.rs:6:21 - | -6 | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using flat_map instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` - | - = note: `-D clippy::map-flatten` implied by `-D warnings` + --> $DIR/map_flatten.rs:16:21 + | +16 | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using flat_map instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` + | + = note: `-D clippy::map-flatten` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index 07efe2c6808..7548b83764d 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn match_bool() { let test: bool = true; diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index 7ef6f714f3a..9bef0d823e2 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -1,73 +1,73 @@ error: this boolean expression can be simplified - --> $DIR/match_bool.rs:25:11 + --> $DIR/match_bool.rs:35:11 | -25 | match test && test { +35 | match test && test { | ^^^^^^^^^^^^ help: try: `test` | = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:4:5 - | -4 | / match test { -5 | | true => 0, -6 | | false => 42, -7 | | }; - | |_____^ help: consider using an if/else expression: `if test { 0 } else { 42 }` - | - = note: `-D clippy::match-bool` implied by `-D warnings` + --> $DIR/match_bool.rs:14:5 + | +14 | / match test { +15 | | true => 0, +16 | | false => 42, +17 | | }; + | |_____^ help: consider using an if/else expression: `if test { 0 } else { 42 }` + | + = note: `-D clippy::match-bool` implied by `-D warnings` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:10:5 + --> $DIR/match_bool.rs:20:5 | -10 | / match option == 1 { -11 | | true => 1, -12 | | false => 0, -13 | | }; +20 | / match option == 1 { +21 | | true => 1, +22 | | false => 0, +23 | | }; | |_____^ help: consider using an if/else expression: `if option == 1 { 1 } else { 0 }` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:15:5 + --> $DIR/match_bool.rs:25:5 | -15 | / match test { -16 | | true => (), -17 | | false => { println!("Noooo!"); } -18 | | }; +25 | / match test { +26 | | true => (), +27 | | false => { println!("Noooo!"); } +28 | | }; | |_____^ help: consider using an if/else expression: `if !test { println!("Noooo!"); }` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:20:5 + --> $DIR/match_bool.rs:30:5 | -20 | / match test { -21 | | false => { println!("Noooo!"); } -22 | | _ => (), -23 | | }; +30 | / match test { +31 | | false => { println!("Noooo!"); } +32 | | _ => (), +33 | | }; | |_____^ help: consider using an if/else expression: `if !test { println!("Noooo!"); }` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:25:5 + --> $DIR/match_bool.rs:35:5 | -25 | / match test && test { -26 | | false => { println!("Noooo!"); } -27 | | _ => (), -28 | | }; +35 | / match test && test { +36 | | false => { println!("Noooo!"); } +37 | | _ => (), +38 | | }; | |_____^ help: consider using an if/else expression: `if !(test && test) { println!("Noooo!"); }` error: equal expressions as operands to `&&` - --> $DIR/match_bool.rs:25:11 + --> $DIR/match_bool.rs:35:11 | -25 | match test && test { +35 | match test && test { | ^^^^^^^^^^^^ | = note: #[deny(clippy::eq_op)] on by default error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:30:5 + --> $DIR/match_bool.rs:40:5 | -30 | / match test { -31 | | false => { println!("Noooo!"); } -32 | | true => { println!("Yes!"); } -33 | | }; +40 | / match test { +41 | | false => { println!("Noooo!"); } +42 | | true => { println!("Yes!"); } +43 | | }; | |_____^ help: consider using an if/else expression: `if test { println!("Yes!"); } else { println!("Noooo!"); }` error: aborting due to 8 previous errors diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index 92befb25a7e..e6e4154e437 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(exclusive_range_pattern)] diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index 6f1a067382a..bed903faf1a 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -1,362 +1,362 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/matches.rs:21:5 + --> $DIR/matches.rs:31:5 | -21 | / match ExprNode::Butterflies { -22 | | ExprNode::ExprAddrOf => Some(&NODE), -23 | | _ => { let x = 5; None }, -24 | | } +31 | / match ExprNode::Butterflies { +32 | | ExprNode::ExprAddrOf => Some(&NODE), +33 | | _ => { let x = 5; None }, +34 | | } | |_____^ help: try this: `if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { let x = 5; None }` | = note: `-D clippy::single-match-else` implied by `-D warnings` error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:30:9 + --> $DIR/matches.rs:40:9 | -30 | / match v { -31 | | &Some(v) => println!("{:?}", v), -32 | | &None => println!("none"), -33 | | } +40 | / match v { +41 | | &Some(v) => println!("{:?}", v), +42 | | &None => println!("none"), +43 | | } | |_________^ | = note: `-D clippy::match-ref-pats` implied by `-D warnings` help: instead of prefixing all patterns with `&`, you can dereference the expression | -30 | match *v { -31 | Some(v) => println!("{:?}", v), -32 | None => println!("none"), +40 | match *v { +41 | Some(v) => println!("{:?}", v), +42 | None => println!("none"), | error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/matches.rs:40:5 + --> $DIR/matches.rs:50:5 | -40 | / match tup { -41 | | &(v, 1) => println!("{}", v), -42 | | _ => println!("none"), -43 | | } +50 | / match tup { +51 | | &(v, 1) => println!("{}", v), +52 | | _ => println!("none"), +53 | | } | |_____^ help: try this: `if let &(v, 1) = tup { $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ; } else { $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ; }` error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:40:5 + --> $DIR/matches.rs:50:5 | -40 | / match tup { -41 | | &(v, 1) => println!("{}", v), -42 | | _ => println!("none"), -43 | | } +50 | / match tup { +51 | | &(v, 1) => println!("{}", v), +52 | | _ => println!("none"), +53 | | } | |_____^ help: instead of prefixing all patterns with `&`, you can dereference the expression | -40 | match *tup { -41 | (v, 1) => println!("{}", v), +50 | match *tup { +51 | (v, 1) => println!("{}", v), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/matches.rs:46:5 + --> $DIR/matches.rs:56:5 | -46 | / match &w { -47 | | &Some(v) => println!("{:?}", v), -48 | | &None => println!("none"), -49 | | } +56 | / match &w { +57 | | &Some(v) => println!("{:?}", v), +58 | | &None => println!("none"), +59 | | } | |_____^ help: try | -46 | match w { -47 | Some(v) => println!("{:?}", v), -48 | None => println!("none"), +56 | match w { +57 | Some(v) => println!("{:?}", v), +58 | None => println!("none"), | error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:57:5 + --> $DIR/matches.rs:67:5 | -57 | / if let &None = a { -58 | | println!("none"); -59 | | } +67 | / if let &None = a { +68 | | println!("none"); +69 | | } | |_____^ help: instead of prefixing all patterns with `&`, you can dereference the expression | -57 | if let None = *a { +67 | if let None = *a { | ^^^^ ^^ error: you don't need to add `&` to both the expression and the patterns - --> $DIR/matches.rs:62:5 + --> $DIR/matches.rs:72:5 | -62 | / if let &None = &b { -63 | | println!("none"); -64 | | } +72 | / if let &None = &b { +73 | | println!("none"); +74 | | } | |_____^ help: try | -62 | if let None = b { +72 | if let None = b { | ^^^^ ^ error: some ranges overlap - --> $DIR/matches.rs:71:9 + --> $DIR/matches.rs:81:9 | -71 | 0 ... 10 => println!("0 ... 10"), +81 | 0 ... 10 => println!("0 ... 10"), | ^^^^^^^^ | = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` note: overlaps with this - --> $DIR/matches.rs:72:9 + --> $DIR/matches.rs:82:9 | -72 | 0 ... 11 => println!("0 ... 11"), +82 | 0 ... 11 => println!("0 ... 11"), | ^^^^^^^^ error: some ranges overlap - --> $DIR/matches.rs:77:9 + --> $DIR/matches.rs:87:9 | -77 | 0 ... 5 => println!("0 ... 5"), +87 | 0 ... 5 => println!("0 ... 5"), | ^^^^^^^ | note: overlaps with this - --> $DIR/matches.rs:79:9 + --> $DIR/matches.rs:89:9 | -79 | FOO ... 11 => println!("0 ... 11"), +89 | FOO ... 11 => println!("0 ... 11"), | ^^^^^^^^^^ error: some ranges overlap - --> $DIR/matches.rs:85:9 + --> $DIR/matches.rs:95:9 | -85 | 0 ... 5 => println!("0 ... 5"), +95 | 0 ... 5 => println!("0 ... 5"), | ^^^^^^^ | note: overlaps with this - --> $DIR/matches.rs:84:9 + --> $DIR/matches.rs:94:9 | -84 | 2 => println!("2"), +94 | 2 => println!("2"), | ^ error: some ranges overlap - --> $DIR/matches.rs:91:9 - | -91 | 0 ... 2 => println!("0 ... 2"), - | ^^^^^^^ - | + --> $DIR/matches.rs:101:9 + | +101 | 0 ... 2 => println!("0 ... 2"), + | ^^^^^^^ + | note: overlaps with this - --> $DIR/matches.rs:90:9 - | -90 | 2 => println!("2"), - | ^ + --> $DIR/matches.rs:100:9 + | +100 | 2 => println!("2"), + | ^ error: some ranges overlap - --> $DIR/matches.rs:114:9 + --> $DIR/matches.rs:124:9 | -114 | 0 .. 11 => println!("0 .. 11"), +124 | 0 .. 11 => println!("0 .. 11"), | ^^^^^^^ | note: overlaps with this - --> $DIR/matches.rs:115:9 + --> $DIR/matches.rs:125:9 | -115 | 0 ... 11 => println!("0 ... 11"), +125 | 0 ... 11 => println!("0 ... 11"), | ^^^^^^^^ error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:132:9 + --> $DIR/matches.rs:142:9 | -132 | Err(_) => panic!("err") +142 | Err(_) => panic!("err") | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:131:18 + --> $DIR/matches.rs:141:18 | -131 | Ok(_) => println!("ok"), +141 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | = note: `-D clippy::match-same-arms` implied by `-D warnings` note: same as this - --> $DIR/matches.rs:130:18 + --> $DIR/matches.rs:140:18 | -130 | Ok(3) => println!("ok"), +140 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:130:18 + --> $DIR/matches.rs:140:18 | -130 | Ok(3) => println!("ok"), +140 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:138:9 + --> $DIR/matches.rs:148:9 | -138 | Err(_) => {panic!()} +148 | Err(_) => {panic!()} | ^^^^^^ | = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:137:18 + --> $DIR/matches.rs:147:18 | -137 | Ok(_) => println!("ok"), +147 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:136:18 + --> $DIR/matches.rs:146:18 | -136 | Ok(3) => println!("ok"), +146 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:136:18 + --> $DIR/matches.rs:146:18 | -136 | Ok(3) => println!("ok"), +146 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:144:9 + --> $DIR/matches.rs:154:9 | -144 | Err(_) => {panic!();} +154 | Err(_) => {panic!();} | ^^^^^^ | = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:143:18 + --> $DIR/matches.rs:153:18 | -143 | Ok(_) => println!("ok"), +153 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:142:18 + --> $DIR/matches.rs:152:18 | -142 | Ok(3) => println!("ok"), +152 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:142:18 + --> $DIR/matches.rs:152:18 | -142 | Ok(3) => println!("ok"), +152 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:150:18 + --> $DIR/matches.rs:160:18 | -150 | Ok(_) => println!("ok"), +160 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:149:18 + --> $DIR/matches.rs:159:18 | -149 | Ok(3) => println!("ok"), +159 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:149:18 + --> $DIR/matches.rs:159:18 | -149 | Ok(3) => println!("ok"), +159 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:157:18 + --> $DIR/matches.rs:167:18 | -157 | Ok(_) => println!("ok"), +167 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:156:18 + --> $DIR/matches.rs:166:18 | -156 | Ok(3) => println!("ok"), +166 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:156:18 + --> $DIR/matches.rs:166:18 | -156 | Ok(3) => println!("ok"), +166 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:163:18 + --> $DIR/matches.rs:173:18 | -163 | Ok(_) => println!("ok"), +173 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:162:18 + --> $DIR/matches.rs:172:18 | -162 | Ok(3) => println!("ok"), +172 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:162:18 + --> $DIR/matches.rs:172:18 | -162 | Ok(3) => println!("ok"), +172 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:169:18 + --> $DIR/matches.rs:179:18 | -169 | Ok(_) => println!("ok"), +179 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:168:18 + --> $DIR/matches.rs:178:18 | -168 | Ok(3) => println!("ok"), +178 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:168:18 + --> $DIR/matches.rs:178:18 | -168 | Ok(3) => println!("ok"), +178 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:190:29 + --> $DIR/matches.rs:200:29 | -190 | (Ok(_), Some(x)) => println!("ok {}", x), +200 | (Ok(_), Some(x)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:189:29 + --> $DIR/matches.rs:199:29 | -189 | (Ok(x), Some(_)) => println!("ok {}", x), +199 | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ note: consider refactoring into `(Ok(x), Some(_)) | (Ok(_), Some(x))` - --> $DIR/matches.rs:189:29 + --> $DIR/matches.rs:199:29 | -189 | (Ok(x), Some(_)) => println!("ok {}", x), +199 | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:205:18 + --> $DIR/matches.rs:215:18 | -205 | Ok(_) => println!("ok"), +215 | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:204:18 + --> $DIR/matches.rs:214:18 | -204 | Ok(3) => println!("ok"), +214 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:204:18 + --> $DIR/matches.rs:214:18 | -204 | Ok(3) => println!("ok"), +214 | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: use as_ref() instead - --> $DIR/matches.rs:212:33 + --> $DIR/matches.rs:222:33 | -212 | let borrowed: Option<&()> = match owned { +222 | let borrowed: Option<&()> = match owned { | _________________________________^ -213 | | None => None, -214 | | Some(ref v) => Some(v), -215 | | }; +223 | | None => None, +224 | | Some(ref v) => Some(v), +225 | | }; | |_____^ help: try this: `owned.as_ref()` | = note: `-D clippy::match-as-ref` implied by `-D warnings` error: use as_mut() instead - --> $DIR/matches.rs:218:39 + --> $DIR/matches.rs:228:39 | -218 | let borrow_mut: Option<&mut ()> = match mut_owned { +228 | let borrow_mut: Option<&mut ()> = match mut_owned { | _______________________________________^ -219 | | None => None, -220 | | Some(ref mut v) => Some(v), -221 | | }; +229 | | None => None, +230 | | Some(ref mut v) => Some(v), +231 | | }; | |_____^ help: try this: `mut_owned.as_mut()` error: aborting due to 26 previous errors diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index 96d333a7170..0e7cfbffa4c 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/mem_forget.stderr b/tests/ui/mem_forget.stderr index 1f43d9f360a..06ac6a3679d 100644 --- a/tests/ui/mem_forget.stderr +++ b/tests/ui/mem_forget.stderr @@ -1,21 +1,21 @@ error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:18:5 + --> $DIR/mem_forget.rs:28:5 | -18 | memstuff::forget(six); +28 | memstuff::forget(six); | ^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mem-forget` implied by `-D warnings` error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:21:5 + --> $DIR/mem_forget.rs:31:5 | -21 | std::mem::forget(seven); +31 | std::mem::forget(seven); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:24:5 + --> $DIR/mem_forget.rs:34:5 | -24 | forgetSomething(eight); +34 | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index 62df42ef2d2..69e3ae96bad 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)] diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr index 8385fa3cb3c..64a1690156c 100644 --- a/tests/ui/mem_replace.stderr +++ b/tests/ui/mem_replace.stderr @@ -1,15 +1,15 @@ error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:8:13 - | -8 | let _ = mem::replace(&mut an_option, None); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` - | - = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` + --> $DIR/mem_replace.rs:18:13 + | +18 | let _ = mem::replace(&mut an_option, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` + | + = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:10:13 + --> $DIR/mem_replace.rs:20:13 | -10 | let _ = mem::replace(an_option, None); +20 | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: aborting due to 2 previous errors diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 7faa45b987d..5bf52c740fe 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 3189f375647..4b8c0403702 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,454 +1,454 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:21:5 + --> $DIR/methods.rs:31:5 | -21 | pub fn add(self, other: T) -> T { self } +31 | pub fn add(self, other: T) -> T { self } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/methods.rs:32:17 + --> $DIR/methods.rs:42:17 | -32 | fn into_u16(&self) -> u16 { 0 } +42 | fn into_u16(&self) -> u16 { 0 } | ^^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/methods.rs:34:21 + --> $DIR/methods.rs:44:21 | -34 | fn to_something(self) -> u32 { 0 } +44 | fn to_something(self) -> u32 { 0 } | ^^^^ error: methods called `new` usually take no self; consider choosing a less ambiguous name - --> $DIR/methods.rs:36:12 + --> $DIR/methods.rs:46:12 | -36 | fn new(self) {} +46 | fn new(self) {} | ^^^^ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:36:5 + --> $DIR/methods.rs:46:5 | -36 | fn new(self) {} +46 | fn new(self) {} | ^^^^^^^^^^^^^^^ | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:104:13 + --> $DIR/methods.rs:114:13 | -104 | let _ = opt.map(|x| x + 1) +114 | let _ = opt.map(|x| x + 1) | _____________^ -105 | | -106 | | .unwrap_or(0); // should lint even though this call is on a separate line +115 | | +116 | | .unwrap_or(0); // should lint even though this call is on a separate line | |____________________________^ | = note: `-D clippy::option-map-unwrap-or` implied by `-D warnings` = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:108:13 + --> $DIR/methods.rs:118:13 | -108 | let _ = opt.map(|x| { +118 | let _ = opt.map(|x| { | _____________^ -109 | | x + 1 -110 | | } -111 | | ).unwrap_or(0); +119 | | x + 1 +120 | | } +121 | | ).unwrap_or(0); | |____________________________^ error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:112:13 + --> $DIR/methods.rs:122:13 | -112 | let _ = opt.map(|x| x + 1) +122 | let _ = opt.map(|x| x + 1) | _____________^ -113 | | .unwrap_or({ -114 | | 0 -115 | | }); +123 | | .unwrap_or({ +124 | | 0 +125 | | }); | |__________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:117:13 + --> $DIR/methods.rs:127:13 | -117 | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); +127 | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:119:13 + --> $DIR/methods.rs:129:13 | -119 | let _ = opt.map(|x| { +129 | let _ = opt.map(|x| { | _____________^ -120 | | Some(x + 1) -121 | | } -122 | | ).unwrap_or(None); +130 | | Some(x + 1) +131 | | } +132 | | ).unwrap_or(None); | |_____________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:123:13 + --> $DIR/methods.rs:133:13 | -123 | let _ = opt +133 | let _ = opt | _____________^ -124 | | .map(|x| Some(x + 1)) -125 | | .unwrap_or(None); +134 | | .map(|x| Some(x + 1)) +135 | | .unwrap_or(None); | |________________________^ | = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:131:13 + --> $DIR/methods.rs:141:13 | -131 | let _ = opt.map(|x| x + 1) +141 | let _ = opt.map(|x| x + 1) | _____________^ -132 | | -133 | | .unwrap_or_else(|| 0); // should lint even though this call is on a separate line +142 | | +143 | | .unwrap_or_else(|| 0); // should lint even though this call is on a separate line | |____________________________________^ | = note: `-D clippy::option-map-unwrap-or-else` implied by `-D warnings` = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:135:13 + --> $DIR/methods.rs:145:13 | -135 | let _ = opt.map(|x| { +145 | let _ = opt.map(|x| { | _____________^ -136 | | x + 1 -137 | | } -138 | | ).unwrap_or_else(|| 0); +146 | | x + 1 +147 | | } +148 | | ).unwrap_or_else(|| 0); | |____________________________________^ error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:139:13 + --> $DIR/methods.rs:149:13 | -139 | let _ = opt.map(|x| x + 1) +149 | let _ = opt.map(|x| x + 1) | _____________^ -140 | | .unwrap_or_else(|| -141 | | 0 -142 | | ); +150 | | .unwrap_or_else(|| +151 | | 0 +152 | | ); | |_________________^ error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:148:13 + --> $DIR/methods.rs:158:13 | -148 | let _ = opt.map_or(None, |x| Some(x + 1)); +158 | let _ = opt.map_or(None, |x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using and_then instead: `opt.and_then(|x| Some(x + 1))` | = note: `-D clippy::option-map-or-none` implied by `-D warnings` error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:150:13 + --> $DIR/methods.rs:160:13 | -150 | let _ = opt.map_or(None, |x| { +160 | let _ = opt.map_or(None, |x| { | _____________^ -151 | | Some(x + 1) -152 | | } -153 | | ); +161 | | Some(x + 1) +162 | | } +163 | | ); | |_________________^ help: try using and_then instead | -150 | let _ = opt.and_then(|x| { -151 | Some(x + 1) -152 | }); +160 | let _ = opt.and_then(|x| { +161 | Some(x + 1) +162 | }); | error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/methods.rs:163:13 + --> $DIR/methods.rs:173:13 | -163 | let _ = res.map(|x| x + 1) +173 | let _ = res.map(|x| x + 1) | _____________^ -164 | | -165 | | .unwrap_or_else(|e| 0); // should lint even though this call is on a separate line +174 | | +175 | | .unwrap_or_else(|e| 0); // should lint even though this call is on a separate line | |_____________________________________^ | = note: `-D clippy::result-map-unwrap-or-else` implied by `-D warnings` = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/methods.rs:167:13 + --> $DIR/methods.rs:177:13 | -167 | let _ = res.map(|x| { +177 | let _ = res.map(|x| { | _____________^ -168 | | x + 1 -169 | | } -170 | | ).unwrap_or_else(|e| 0); +178 | | x + 1 +179 | | } +180 | | ).unwrap_or_else(|e| 0); | |_____________________________________^ error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/methods.rs:171:13 + --> $DIR/methods.rs:181:13 | -171 | let _ = res.map(|x| x + 1) +181 | let _ = res.map(|x| x + 1) | _____________^ -172 | | .unwrap_or_else(|e| -173 | | 0 -174 | | ); +182 | | .unwrap_or_else(|e| +183 | | 0 +184 | | ); | |_________________^ error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:234:13 + --> $DIR/methods.rs:244:13 | -234 | let _ = v.iter().filter(|&x| *x < 0).next(); +244 | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::filter-next` implied by `-D warnings` = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:237:13 + --> $DIR/methods.rs:247:13 | -237 | let _ = v.iter().filter(|&x| { +247 | let _ = v.iter().filter(|&x| { | _____________^ -238 | | *x < 0 -239 | | } -240 | | ).next(); +248 | | *x < 0 +249 | | } +250 | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:252:13 + --> $DIR/methods.rs:262:13 | -252 | let _ = v.iter().find(|&x| *x < 0).is_some(); +262 | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::search-is-some` implied by `-D warnings` = note: replace `find(|&x| *x < 0).is_some()` with `any(|&x| *x < 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:255:13 + --> $DIR/methods.rs:265:13 | -255 | let _ = v.iter().find(|&x| { +265 | let _ = v.iter().find(|&x| { | _____________^ -256 | | *x < 0 -257 | | } -258 | | ).is_some(); +266 | | *x < 0 +267 | | } +268 | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:261:13 + --> $DIR/methods.rs:271:13 | -261 | let _ = v.iter().position(|&x| x < 0).is_some(); +271 | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: replace `position(|&x| x < 0).is_some()` with `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:264:13 + --> $DIR/methods.rs:274:13 | -264 | let _ = v.iter().position(|&x| { +274 | let _ = v.iter().position(|&x| { | _____________^ -265 | | x < 0 -266 | | } -267 | | ).is_some(); +275 | | x < 0 +276 | | } +277 | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:270:13 + --> $DIR/methods.rs:280:13 | -270 | let _ = v.iter().rposition(|&x| x < 0).is_some(); +280 | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: replace `rposition(|&x| x < 0).is_some()` with `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:273:13 + --> $DIR/methods.rs:283:13 | -273 | let _ = v.iter().rposition(|&x| { +283 | let _ = v.iter().rposition(|&x| { | _____________^ -274 | | x < 0 -275 | | } -276 | | ).is_some(); +284 | | x < 0 +285 | | } +286 | | ).is_some(); | |______________________________^ error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:308:22 + --> $DIR/methods.rs:318:22 | -308 | with_constructor.unwrap_or(make()); +318 | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` | = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/methods.rs:311:5 + --> $DIR/methods.rs:321:5 | -311 | with_new.unwrap_or(Vec::new()); +321 | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:314:21 + --> $DIR/methods.rs:324:21 | -314 | with_const_args.unwrap_or(Vec::with_capacity(12)); +324 | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:317:14 + --> $DIR/methods.rs:327:14 | -317 | with_err.unwrap_or(make()); +327 | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:320:19 + --> $DIR/methods.rs:330:19 | -320 | with_err_args.unwrap_or(Vec::with_capacity(12)); +330 | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/methods.rs:323:5 + --> $DIR/methods.rs:333:5 | -323 | with_default_trait.unwrap_or(Default::default()); +333 | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/methods.rs:326:5 + --> $DIR/methods.rs:336:5 | -326 | with_default_type.unwrap_or(u64::default()); +336 | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:329:14 + --> $DIR/methods.rs:339:14 | -329 | with_vec.unwrap_or(vec![]); +339 | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| < [ _ ] > :: into_vec ( box [ $ ( $ x ) , * ] ))` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:334:21 + --> $DIR/methods.rs:344:21 | -334 | without_default.unwrap_or(Foo::new()); +344 | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/methods.rs:337:19 + --> $DIR/methods.rs:347:19 | -337 | map.entry(42).or_insert(String::new()); +347 | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/methods.rs:340:21 + --> $DIR/methods.rs:350:21 | -340 | btree.entry(42).or_insert(String::new()); +350 | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:343:21 + --> $DIR/methods.rs:353:21 | -343 | let _ = stringy.unwrap_or("".to_owned()); +353 | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: `error_code` is shadowed by `123_i32` - --> $DIR/methods.rs:377:9 + --> $DIR/methods.rs:387:9 | -377 | let error_code = 123_i32; +387 | let error_code = 123_i32; | ^^^^^^^^^^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: initialization happens here - --> $DIR/methods.rs:377:22 + --> $DIR/methods.rs:387:22 | -377 | let error_code = 123_i32; +387 | let error_code = 123_i32; | ^^^^^^^ note: previous binding is here - --> $DIR/methods.rs:364:9 + --> $DIR/methods.rs:374:9 | -364 | let error_code = 123_i32; +374 | let error_code = 123_i32; | ^^^^^^^^^^ error: use of `expect` followed by a function call - --> $DIR/methods.rs:366:26 + --> $DIR/methods.rs:376:26 | -366 | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); +376 | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` | = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/methods.rs:369:26 + --> $DIR/methods.rs:379:26 | -369 | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); +379 | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!(format!("Error {}: fake error", error_code).as_str()))` error: use of `expect` followed by a function call - --> $DIR/methods.rs:379:25 + --> $DIR/methods.rs:389:25 | -379 | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); +389 | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/methods.rs:382:25 + --> $DIR/methods.rs:392:25 | -382 | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); +392 | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!(format!("Error {}: fake error", error_code).as_str()))` error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:406:23 + --> $DIR/methods.rs:416:23 | -406 | let bad_vec = some_vec.iter().nth(3); +416 | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:407:26 + --> $DIR/methods.rs:417:26 | -407 | let bad_slice = &some_vec[..].iter().nth(3); +417 | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:408:31 + --> $DIR/methods.rs:418:31 | -408 | let bad_boxed_slice = boxed_slice.iter().nth(3); +418 | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:409:29 + --> $DIR/methods.rs:419:29 | -409 | let bad_vec_deque = some_vec_deque.iter().nth(3); +419 | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:414:23 + --> $DIR/methods.rs:424:23 | -414 | let bad_vec = some_vec.iter_mut().nth(3); +424 | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:417:26 + --> $DIR/methods.rs:427:26 | -417 | let bad_slice = &some_vec[..].iter_mut().nth(3); +427 | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:420:29 + --> $DIR/methods.rs:430:29 | -420 | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); +430 | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/methods.rs:432:13 + --> $DIR/methods.rs:442:13 | -432 | let _ = some_vec.iter().skip(42).next(); +442 | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/methods.rs:433:13 + --> $DIR/methods.rs:443:13 | -433 | let _ = some_vec.iter().cycle().skip(42).next(); +443 | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/methods.rs:434:13 + --> $DIR/methods.rs:444:13 | -434 | let _ = (1..10).skip(10).next(); +444 | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^^^^^^^^ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/methods.rs:435:14 + --> $DIR/methods.rs:445:14 | -435 | let _ = &some_vec[..].iter().skip(3).next(); +445 | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message - --> $DIR/methods.rs:444:13 + --> $DIR/methods.rs:454:13 | -444 | let _ = opt.unwrap(); +454 | let _ = opt.unwrap(); | ^^^^^^^^^^^^ | = note: `-D clippy::option-unwrap-used` implied by `-D warnings` diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 9866933f9fe..32e3863ad40 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index e89542a2ddc..3ed67ad258e 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,45 +1,45 @@ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:15:5 + --> $DIR/min_max.rs:25:5 | -15 | min(1, max(3, x)); +25 | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::min-max` implied by `-D warnings` error: this min/max combination leads to constant result - --> $DIR/min_max.rs:16:5 + --> $DIR/min_max.rs:26:5 | -16 | min(max(3, x), 1); +26 | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:17:5 + --> $DIR/min_max.rs:27:5 | -17 | max(min(x, 1), 3); +27 | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:18:5 + --> $DIR/min_max.rs:28:5 | -18 | max(3, min(x, 1)); +28 | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:20:5 + --> $DIR/min_max.rs:30:5 | -20 | my_max(3, my_min(x, 1)); +30 | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:32:5 + --> $DIR/min_max.rs:42:5 | -32 | min("Apple", max("Zoo", s)); +42 | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:33:5 + --> $DIR/min_max.rs:43:5 | -33 | max(min(s, "Apple"), "Zoo"); +43 | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index 6968adb312b..43dad8398f1 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] /* This file incorporates work covered by the following copyright and diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing-doc.stderr index ebc4c5aca43..67f50152c73 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing-doc.stderr @@ -1,267 +1,267 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:28:1 + --> $DIR/missing-doc.rs:38:1 | -28 | type Typedef = String; +38 | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:29:1 + --> $DIR/missing-doc.rs:39:1 | -29 | pub type PubTypedef = String; +39 | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc.rs:31:1 + --> $DIR/missing-doc.rs:41:1 | -31 | / struct Foo { -32 | | a: isize, -33 | | b: isize, -34 | | } +41 | / struct Foo { +42 | | a: isize, +43 | | b: isize, +44 | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:32:5 + --> $DIR/missing-doc.rs:42:5 | -32 | a: isize, +42 | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:33:5 + --> $DIR/missing-doc.rs:43:5 | -33 | b: isize, +43 | b: isize, | ^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc.rs:36:1 + --> $DIR/missing-doc.rs:46:1 | -36 | / pub struct PubFoo { -37 | | pub a: isize, -38 | | b: isize, -39 | | } +46 | / pub struct PubFoo { +47 | | pub a: isize, +48 | | b: isize, +49 | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:37:5 + --> $DIR/missing-doc.rs:47:5 | -37 | pub a: isize, +47 | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:38:5 + --> $DIR/missing-doc.rs:48:5 | -38 | b: isize, +48 | b: isize, | ^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:47:1 + --> $DIR/missing-doc.rs:57:1 | -47 | mod module_no_dox {} +57 | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:48:1 + --> $DIR/missing-doc.rs:58:1 | -48 | pub mod pub_module_no_dox {} +58 | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:52:1 + --> $DIR/missing-doc.rs:62:1 | -52 | pub fn foo2() {} +62 | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:53:1 + --> $DIR/missing-doc.rs:63:1 | -53 | fn foo3() {} +63 | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for a trait - --> $DIR/missing-doc.rs:70:1 + --> $DIR/missing-doc.rs:80:1 | -70 | / pub trait C { -71 | | fn foo(&self); -72 | | fn foo_with_impl(&self) {} -73 | | } +80 | / pub trait C { +81 | | fn foo(&self); +82 | | fn foo_with_impl(&self) {} +83 | | } | |_^ error: missing documentation for a trait method - --> $DIR/missing-doc.rs:71:5 + --> $DIR/missing-doc.rs:81:5 | -71 | fn foo(&self); +81 | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for a trait method - --> $DIR/missing-doc.rs:72:5 + --> $DIR/missing-doc.rs:82:5 | -72 | fn foo_with_impl(&self) {} +82 | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing-doc.rs:92:5 | -82 | type AssociatedType; +92 | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc.rs:83:5 + --> $DIR/missing-doc.rs:93:5 | -83 | type AssociatedTypeDef = Self; +93 | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:94:5 - | -94 | pub fn foo() {} - | ^^^^^^^^^^^^^^^ + --> $DIR/missing-doc.rs:104:5 + | +104 | pub fn foo() {} + | ^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:95:5 - | -95 | fn bar() {} - | ^^^^^^^^^^^ + --> $DIR/missing-doc.rs:105:5 + | +105 | fn bar() {} + | ^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:99:5 - | -99 | pub fn foo() {} - | ^^^^^^^^^^^^^^^ + --> $DIR/missing-doc.rs:109:5 + | +109 | pub fn foo() {} + | ^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:102:5 + --> $DIR/missing-doc.rs:112:5 | -102 | fn foo2() {} +112 | fn foo2() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:128:1 + --> $DIR/missing-doc.rs:138:1 | -128 | / enum Baz { -129 | | BazA { -130 | | a: isize, -131 | | b: isize -132 | | }, -133 | | BarB -134 | | } +138 | / enum Baz { +139 | | BazA { +140 | | a: isize, +141 | | b: isize +142 | | }, +143 | | BarB +144 | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:129:5 + --> $DIR/missing-doc.rs:139:5 | -129 | / BazA { -130 | | a: isize, -131 | | b: isize -132 | | }, +139 | / BazA { +140 | | a: isize, +141 | | b: isize +142 | | }, | |_____^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:130:9 + --> $DIR/missing-doc.rs:140:9 | -130 | a: isize, +140 | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:131:9 + --> $DIR/missing-doc.rs:141:9 | -131 | b: isize +141 | b: isize | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:133:5 + --> $DIR/missing-doc.rs:143:5 | -133 | BarB +143 | BarB | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:136:1 + --> $DIR/missing-doc.rs:146:1 | -136 | / pub enum PubBaz { -137 | | PubBazA { -138 | | a: isize, -139 | | }, -140 | | } +146 | / pub enum PubBaz { +147 | | PubBazA { +148 | | a: isize, +149 | | }, +150 | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:137:5 + --> $DIR/missing-doc.rs:147:5 | -137 | / PubBazA { -138 | | a: isize, -139 | | }, +147 | / PubBazA { +148 | | a: isize, +149 | | }, | |_____^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:138:9 + --> $DIR/missing-doc.rs:148:9 | -138 | a: isize, +148 | a: isize, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:162:1 + --> $DIR/missing-doc.rs:172:1 | -162 | const FOO: u32 = 0; +172 | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:169:1 + --> $DIR/missing-doc.rs:179:1 | -169 | pub const FOO4: u32 = 0; +179 | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:172:1 + --> $DIR/missing-doc.rs:182:1 | -172 | static BAR: u32 = 0; +182 | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:179:1 + --> $DIR/missing-doc.rs:189:1 | -179 | pub static BAR4: u32 = 0; +189 | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:182:1 + --> $DIR/missing-doc.rs:192:1 | -182 | / mod internal_impl { -183 | | /// dox -184 | | pub fn documented() {} -185 | | pub fn undocumented1() {} +192 | / mod internal_impl { +193 | | /// dox +194 | | pub fn documented() {} +195 | | pub fn undocumented1() {} ... | -194 | | } -195 | | } +204 | | } +205 | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:185:5 + --> $DIR/missing-doc.rs:195:5 | -185 | pub fn undocumented1() {} +195 | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:186:5 + --> $DIR/missing-doc.rs:196:5 | -186 | pub fn undocumented2() {} +196 | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:187:5 + --> $DIR/missing-doc.rs:197:5 | -187 | fn undocumented3() {} +197 | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:192:9 + --> $DIR/missing-doc.rs:202:9 | -192 | pub fn also_undocumented1() {} +202 | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:193:9 + --> $DIR/missing-doc.rs:203:9 | -193 | fn also_undocumented2() {} +203 | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 39 previous errors diff --git a/tests/ui/missing_inline.rs b/tests/ui/missing_inline.rs index 7fbb01c6d2b..593774da1b4 100644 --- a/tests/ui/missing_inline.rs +++ b/tests/ui/missing_inline.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] /* This file incorporates work covered by the following copyright and diff --git a/tests/ui/missing_inline.stderr b/tests/ui/missing_inline.stderr index 3609c9101b7..fc617ef54c9 100644 --- a/tests/ui/missing_inline.stderr +++ b/tests/ui/missing_inline.stderr @@ -1,39 +1,39 @@ error: missing `#[inline]` for a function - --> $DIR/missing_inline.rs:33:1 + --> $DIR/missing_inline.rs:43:1 | -33 | pub fn pub_foo() {} // missing #[inline] +43 | pub fn pub_foo() {} // missing #[inline] | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` error: missing `#[inline]` for a default trait method - --> $DIR/missing_inline.rs:48:5 + --> $DIR/missing_inline.rs:58:5 | -48 | fn PubBar_b() {} // missing #[inline] +58 | fn PubBar_b() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:61:5 + --> $DIR/missing_inline.rs:71:5 | -61 | fn PubBar_a() {} // missing #[inline] +71 | fn PubBar_a() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:62:5 + --> $DIR/missing_inline.rs:72:5 | -62 | fn PubBar_b() {} // missing #[inline] +72 | fn PubBar_b() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:63:5 + --> $DIR/missing_inline.rs:73:5 | -63 | fn PubBar_c() {} // missing #[inline] +73 | fn PubBar_c() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:73:5 + --> $DIR/missing_inline.rs:83:5 | -73 | pub fn PubFooImpl() {} // missing #[inline] +83 | pub fn PubFooImpl() {} // missing #[inline] | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index b6917020ea2..1dfc06f38af 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::module_inception)] diff --git a/tests/ui/module_inception.stderr b/tests/ui/module_inception.stderr index 43f9666f78d..c1e6d0a6e62 100644 --- a/tests/ui/module_inception.stderr +++ b/tests/ui/module_inception.stderr @@ -1,19 +1,19 @@ error: module has the same name as its containing module - --> $DIR/module_inception.rs:7:9 - | -7 | / mod bar { -8 | | mod foo {} -9 | | } - | |_________^ - | - = note: `-D clippy::module-inception` implied by `-D warnings` + --> $DIR/module_inception.rs:17:9 + | +17 | / mod bar { +18 | | mod foo {} +19 | | } + | |_________^ + | + = note: `-D clippy::module-inception` implied by `-D warnings` error: module has the same name as its containing module - --> $DIR/module_inception.rs:12:5 + --> $DIR/module_inception.rs:22:5 | -12 | / mod foo { -13 | | mod bar {} -14 | | } +22 | / mod foo { +23 | | mod bar {} +24 | | } | |_____^ error: aborting due to 2 previous errors diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index 7dcec04baf9..6e0cbc581dc 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::modulo_one)] diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 5d42c3e0a29..57e2c59ee14 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,10 +1,10 @@ error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:7:5 - | -7 | 10 % 1; - | ^^^^^^ - | - = note: `-D clippy::modulo-one` implied by `-D warnings` + --> $DIR/modulo_one.rs:17:5 + | +17 | 10 % 1; + | ^^^^^^ + | + = note: `-D clippy::modulo-one` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index b75fa92f098..37256efb839 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index 0f5baa2d27e..48b5abf5a6e 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -1,62 +1,62 @@ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:9:39 - | -9 | fn this_wont_hurt_a_bit(&self) -> &mut Foo { - | ^^^^^^^^ - | - = note: `-D clippy::mut-from-ref` implied by `-D warnings` + --> $DIR/mut_from_ref.rs:19:39 + | +19 | fn this_wont_hurt_a_bit(&self) -> &mut Foo { + | ^^^^^^^^ + | + = note: `-D clippy::mut-from-ref` implied by `-D warnings` note: immutable borrow here - --> $DIR/mut_from_ref.rs:9:29 - | -9 | fn this_wont_hurt_a_bit(&self) -> &mut Foo { - | ^^^^^ + --> $DIR/mut_from_ref.rs:19:29 + | +19 | fn this_wont_hurt_a_bit(&self) -> &mut Foo { + | ^^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:15:25 + --> $DIR/mut_from_ref.rs:25:25 | -15 | fn ouch(x: &Foo) -> &mut Foo; +25 | fn ouch(x: &Foo) -> &mut Foo; | ^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:15:16 + --> $DIR/mut_from_ref.rs:25:16 | -15 | fn ouch(x: &Foo) -> &mut Foo; +25 | fn ouch(x: &Foo) -> &mut Foo; | ^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:24:21 + --> $DIR/mut_from_ref.rs:34:21 | -24 | fn fail(x: &u32) -> &mut u16 { +34 | fn fail(x: &u32) -> &mut u16 { | ^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:24:12 + --> $DIR/mut_from_ref.rs:34:12 | -24 | fn fail(x: &u32) -> &mut u16 { +34 | fn fail(x: &u32) -> &mut u16 { | ^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:28:50 + --> $DIR/mut_from_ref.rs:38:50 | -28 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { +38 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:28:25 + --> $DIR/mut_from_ref.rs:38:25 | -28 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { +38 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:32:67 + --> $DIR/mut_from_ref.rs:42:67 | -32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { +42 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:32:27 + --> $DIR/mut_from_ref.rs:42:27 | -32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { +42 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 4656d27648f..81c945beafc 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 88bd2f729af..c05c0215795 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,60 +1,60 @@ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:10:12 + --> $DIR/mut_mut.rs:20:12 | -10 | fn fun(x : &mut &mut u32) -> bool { +20 | fn fun(x : &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ | = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:24:17 + --> $DIR/mut_mut.rs:34:17 | -24 | let mut x = &mut &mut 1u32; +34 | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:19:20 + --> $DIR/mut_mut.rs:29:20 | -19 | ($p:expr) => { &mut $p } +29 | ($p:expr) => { &mut $p } | ^^^^^^^ ... -39 | let mut z = mut_ptr!(&mut 3u32); +49 | let mut z = mut_ptr!(&mut 3u32); | ------------------- in this macro invocation error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:26:21 + --> $DIR/mut_mut.rs:36:21 | -26 | let mut y = &mut x; +36 | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:30:33 + --> $DIR/mut_mut.rs:40:33 | -30 | let y : &mut &mut u32 = &mut &mut 2; +40 | let y : &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:30:17 + --> $DIR/mut_mut.rs:40:17 | -30 | let y : &mut &mut u32 = &mut &mut 2; +40 | let y : &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:38 + --> $DIR/mut_mut.rs:45:38 | -35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; +45 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:17 + --> $DIR/mut_mut.rs:45:17 | -35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; +45 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:22 + --> $DIR/mut_mut.rs:45:22 | -35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; +45 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/mut_range_bound.rs b/tests/ui/mut_range_bound.rs index 0e397c7ae8c..edc86b5d6ac 100644 --- a/tests/ui/mut_range_bound.rs +++ b/tests/ui/mut_range_bound.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index fece9610697..a476ad5d14e 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -1,33 +1,33 @@ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:18:21 + --> $DIR/mut_range_bound.rs:28:21 | -18 | for i in 0..m { m = 5; } // warning +28 | for i in 0..m { m = 5; } // warning | ^^^^^ | = note: `-D clippy::mut-range-bound` implied by `-D warnings` error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:23:22 + --> $DIR/mut_range_bound.rs:33:22 | -23 | for i in m..10 { m *= 2; } // warning +33 | for i in m..10 { m *= 2; } // warning | ^^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:29:21 + --> $DIR/mut_range_bound.rs:39:21 | -29 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) +39 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) | ^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:29:28 + --> $DIR/mut_range_bound.rs:39:28 | -29 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) +39 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) | ^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:40:22 + --> $DIR/mut_range_bound.rs:50:22 | -40 | let n = &mut m; // warning +50 | let n = &mut m; // warning | ^ error: aborting due to 5 previous errors diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index 38b0e25e07c..f42d48f0db4 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index ee62e264767..07b07580d4b 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,21 +1,21 @@ error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:22:34 + --> $DIR/mut_reference.rs:32:34 | -22 | takes_an_immutable_reference(&mut 42); +32 | takes_an_immutable_reference(&mut 42); | ^^^^^^^ | = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` error: The function/method `as_ptr` doesn't need a mutable reference - --> $DIR/mut_reference.rs:24:12 + --> $DIR/mut_reference.rs:34:12 | -24 | as_ptr(&mut 42); +34 | as_ptr(&mut 42); | ^^^^^^^ error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:28:44 + --> $DIR/mut_reference.rs:38:44 | -28 | my_struct.takes_an_immutable_reference(&mut 42); +38 | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 3eefbb97ab8..e0ce93bf698 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 2df58889a47..a317e8a6c94 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -1,47 +1,47 @@ error: Consider using an AtomicBool instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:9:5 - | -9 | Mutex::new(true); - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::mutex-atomic` implied by `-D warnings` + --> $DIR/mutex_atomic.rs:19:5 + | +19 | Mutex::new(true); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::mutex-atomic` implied by `-D warnings` error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:10:5 + --> $DIR/mutex_atomic.rs:20:5 | -10 | Mutex::new(5usize); +20 | Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:11:5 + --> $DIR/mutex_atomic.rs:21:5 | -11 | Mutex::new(9isize); +21 | Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:13:5 + --> $DIR/mutex_atomic.rs:23:5 | -13 | Mutex::new(&x as *const u32); +23 | Mutex::new(&x as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:14:5 + --> $DIR/mutex_atomic.rs:24:5 | -14 | Mutex::new(&mut x as *mut u32); +24 | Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:15:5 + --> $DIR/mutex_atomic.rs:25:5 | -15 | Mutex::new(0u32); +25 | Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::mutex-integer` implied by `-D warnings` error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:16:5 + --> $DIR/mutex_atomic.rs:26:5 | -16 | Mutex::new(0i32); +26 | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/needless_bool.rs b/tests/ui/needless_bool.rs index 4e6f65ed0dd..0e8e250c95d 100644 --- a/tests/ui/needless_bool.rs +++ b/tests/ui/needless_bool.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::needless_bool)] diff --git a/tests/ui/needless_bool.stderr b/tests/ui/needless_bool.stderr index dd132bc671e..13af6fc3564 100644 --- a/tests/ui/needless_bool.stderr +++ b/tests/ui/needless_bool.stderr @@ -1,69 +1,69 @@ error: this if-then-else expression will always return true - --> $DIR/needless_bool.rs:9:5 - | -9 | if x { true } else { true }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::needless-bool` implied by `-D warnings` + --> $DIR/needless_bool.rs:19:5 + | +19 | if x { true } else { true }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression will always return false - --> $DIR/needless_bool.rs:10:5 + --> $DIR/needless_bool.rs:20:5 | -10 | if x { false } else { false }; +20 | if x { false } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:11:5 + --> $DIR/needless_bool.rs:21:5 | -11 | if x { true } else { false }; +21 | if x { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:12:5 + --> $DIR/needless_bool.rs:22:5 | -12 | if x { false } else { true }; +22 | if x { false } else { true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:13:5 + --> $DIR/needless_bool.rs:23:5 | -13 | if x && y { false } else { true }; +23 | if x && y { false } else { true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression will always return true - --> $DIR/needless_bool.rs:25:5 + --> $DIR/needless_bool.rs:35:5 | -25 | if x { return true } else { return true }; +35 | if x { return true } else { return true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this if-then-else expression will always return false - --> $DIR/needless_bool.rs:30:5 + --> $DIR/needless_bool.rs:40:5 | -30 | if x { return false } else { return false }; +40 | if x { return false } else { return false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:35:5 + --> $DIR/needless_bool.rs:45:5 | -35 | if x { return true } else { return false }; +45 | if x { return true } else { return false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:40:5 + --> $DIR/needless_bool.rs:50:5 | -40 | if x && y { return true } else { return false }; +50 | if x && y { return true } else { return false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:45:5 + --> $DIR/needless_bool.rs:55:5 | -45 | if x { return false } else { return true }; +55 | if x { return false } else { return true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:50:5 + --> $DIR/needless_bool.rs:60:5 | -50 | if x && y { return false } else { return true }; +60 | if x && y { return false } else { return true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !(x && y)` error: aborting due to 11 previous errors diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 61384c43fa9..1cf7b40661d 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::borrow::Cow; diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index c720dff5d29..93ba61784d3 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,41 +1,41 @@ error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:15:15 + --> $DIR/needless_borrow.rs:25:15 | -15 | let c = x(&&a); +25 | let c = x(&&a); | ^^^ help: change this to: `&a` | = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:22:17 + --> $DIR/needless_borrow.rs:32:17 | -22 | if let Some(ref cake) = Some(&5) {} +32 | if let Some(ref cake) = Some(&5) {} | ^^^^^^^^ help: change this to: `cake` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:29:15 + --> $DIR/needless_borrow.rs:39:15 | -29 | 46 => &&a, +39 | 46 => &&a, | ^^^ help: change this to: `&a` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrow.rs:51:34 + --> $DIR/needless_borrow.rs:61:34 | -51 | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +61 | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); | ^^^^^^ help: try removing the `&ref` part and just keep: `a` | = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrow.rs:52:30 + --> $DIR/needless_borrow.rs:62:30 | -52 | let _ = v.iter().filter(|&ref a| a.is_empty()); +62 | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^^ help: try removing the `&ref` part and just keep: `a` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:52:31 + --> $DIR/needless_borrow.rs:62:31 | -52 | let _ = v.iter().filter(|&ref a| a.is_empty()); +62 | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^ help: change this to: `a` error: aborting due to 6 previous errors diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 000ecd32da4..650b57b586c 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 3113b887b05..ef80473a9dc 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -1,27 +1,27 @@ error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:8:34 - | -8 | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - | ^^^^^^ help: try removing the `&ref` part and just keep: `a` - | - = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` + --> $DIR/needless_borrowed_ref.rs:18:34 + | +18 | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); + | ^^^^^^ help: try removing the `&ref` part and just keep: `a` + | + = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:13:17 + --> $DIR/needless_borrowed_ref.rs:23:17 | -13 | if let Some(&ref v) = thingy { +23 | if let Some(&ref v) = thingy { | ^^^^^^ help: try removing the `&ref` part and just keep: `v` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:42:27 + --> $DIR/needless_borrowed_ref.rs:52:27 | -42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' +52 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:42:38 + --> $DIR/needless_borrowed_ref.rs:52:38 | -42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' +52 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` error: aborting due to 4 previous errors diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index b001f20d527..45622b33384 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::collections::{HashMap, HashSet, BTreeSet}; diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 0124db3b975..ee41a9d8dea 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -1,27 +1,27 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:9:28 - | -9 | let len = sample.iter().collect::<Vec<_>>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` - | - = note: `-D clippy::needless-collect` implied by `-D warnings` + --> $DIR/needless_collect.rs:19:28 + | +19 | let len = sample.iter().collect::<Vec<_>>().len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | + = note: `-D clippy::needless-collect` implied by `-D warnings` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:10:21 + --> $DIR/needless_collect.rs:20:21 | -10 | if sample.iter().collect::<Vec<_>>().is_empty() { +20 | if sample.iter().collect::<Vec<_>>().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:13:27 + --> $DIR/needless_collect.rs:23:27 | -13 | sample.iter().cloned().collect::<Vec<_>>().contains(&1); +23 | sample.iter().cloned().collect::<Vec<_>>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|&x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:14:34 + --> $DIR/needless_collect.rs:24:34 | -14 | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); +24 | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` error: aborting due to 4 previous errors diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 4fe523e48de..4a15987ba96 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 7cfaf89d6e0..10e7062f2a6 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -1,11 +1,11 @@ error: This else block is redundant. - --> $DIR/needless_continue.rs:26:16 + --> $DIR/needless_continue.rs:36:16 | -26 | } else { +36 | } else { | ________________^ -27 | | continue; -28 | | } +37 | | continue; +38 | | } | |_________^ | = note: `-D clippy::needless-continue` implied by `-D warnings` @@ -37,14 +37,14 @@ error: This else block is redundant. error: There is no need for an explicit `else` block for this `if` expression - --> $DIR/needless_continue.rs:41:9 + --> $DIR/needless_continue.rs:51:9 | -41 | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { -42 | | continue; -43 | | } else { -44 | | println!("Blabber"); -45 | | println!("Jabber"); -46 | | } +51 | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { +52 | | continue; +53 | | } else { +54 | | println!("Blabber"); +55 | | println!("Jabber"); +56 | | } | |_________^ | = help: Consider dropping the else clause, and moving out the code in the else block, like so: diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 31ad96942d6..3e029de4755 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::needless_pass_by_value)] diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 0d4a35363fb..3685f0e9614 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -1,199 +1,199 @@ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:11:23 + --> $DIR/needless_pass_by_value.rs:21:23 | -11 | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> { +21 | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> { | ^^^^^^ help: consider changing the type to: `&[T]` | = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:25:11 + --> $DIR/needless_pass_by_value.rs:35:11 | -25 | fn bar(x: String, y: Wrapper) { +35 | fn bar(x: String, y: Wrapper) { | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:25:22 + --> $DIR/needless_pass_by_value.rs:35:22 | -25 | fn bar(x: String, y: Wrapper) { +35 | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:31:71 + --> $DIR/needless_pass_by_value.rs:41:71 | -31 | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) { +41 | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:43:18 + --> $DIR/needless_pass_by_value.rs:53:18 | -43 | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) { +53 | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead | -43 | fn test_match(x: &Option<Option<String>>, y: Option<Option<String>>) { -44 | match *x { +53 | fn test_match(x: &Option<Option<String>>, y: Option<Option<String>>) { +54 | match *x { | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:56:24 + --> $DIR/needless_pass_by_value.rs:66:24 | -56 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { +66 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:56:36 + --> $DIR/needless_pass_by_value.rs:66:36 | -56 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { +66 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead | -56 | fn test_destructure(x: Wrapper, y: &Wrapper, z: Wrapper) { -57 | let Wrapper(s) = z; // moved -58 | let Wrapper(ref t) = *y; // not moved -59 | let Wrapper(_) = *y; // still not moved +66 | fn test_destructure(x: Wrapper, y: &Wrapper, z: Wrapper) { +67 | let Wrapper(s) = z; // moved +68 | let Wrapper(ref t) = *y; // not moved +69 | let Wrapper(_) = *y; // still not moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:72:49 + --> $DIR/needless_pass_by_value.rs:82:49 | -72 | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {} +82 | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:74:18 + --> $DIR/needless_pass_by_value.rs:84:18 | -74 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { +84 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:74:29 + --> $DIR/needless_pass_by_value.rs:84:29 | -74 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { +84 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^ help: consider changing the type to | -74 | fn issue_2114(s: String, t: &str, u: Vec<i32>, v: Vec<i32>) { +84 | fn issue_2114(s: String, t: &str, u: Vec<i32>, v: Vec<i32>) { | ^^^^ help: change `t.clone()` to | -76 | let _ = t.to_string(); +86 | let _ = t.to_string(); | ^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:74:40 + --> $DIR/needless_pass_by_value.rs:84:40 | -74 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { +84 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:74:53 + --> $DIR/needless_pass_by_value.rs:84:53 | -74 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { +84 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^^^ help: consider changing the type to | -74 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: &[i32]) { +84 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: &[i32]) { | ^^^^^^ help: change `v.clone()` to | -78 | let _ = v.to_owned(); +88 | let _ = v.to_owned(); | ^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:86:12 + --> $DIR/needless_pass_by_value.rs:96:12 | -86 | s: String, +96 | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:87:12 + --> $DIR/needless_pass_by_value.rs:97:12 | -87 | t: String, +97 | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:99:13 - | -99 | _u: U, - | ^ help: consider taking a reference instead: `&U` + --> $DIR/needless_pass_by_value.rs:109:13 + | +109 | _u: U, + | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:100:13 + --> $DIR/needless_pass_by_value.rs:110:13 | -100 | _s: Self, +110 | _s: Self, | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:122:24 + --> $DIR/needless_pass_by_value.rs:132:24 | -122 | fn bar_copy(x: u32, y: CopyWrapper) { +132 | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:120:1 + --> $DIR/needless_pass_by_value.rs:130:1 | -120 | struct CopyWrapper(u32); +130 | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:128:29 + --> $DIR/needless_pass_by_value.rs:138:29 | -128 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { +138 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:120:1 + --> $DIR/needless_pass_by_value.rs:130:1 | -120 | struct CopyWrapper(u32); +130 | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:128:45 + --> $DIR/needless_pass_by_value.rs:138:45 | -128 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { +138 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:120:1 + --> $DIR/needless_pass_by_value.rs:130:1 | -120 | struct CopyWrapper(u32); +130 | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead | -128 | fn test_destructure_copy(x: CopyWrapper, y: &CopyWrapper, z: CopyWrapper) { -129 | let CopyWrapper(s) = z; // moved -130 | let CopyWrapper(ref t) = *y; // not moved -131 | let CopyWrapper(_) = *y; // still not moved +138 | fn test_destructure_copy(x: CopyWrapper, y: &CopyWrapper, z: CopyWrapper) { +139 | let CopyWrapper(s) = z; // moved +140 | let CopyWrapper(ref t) = *y; // not moved +141 | let CopyWrapper(_) = *y; // still not moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:128:61 + --> $DIR/needless_pass_by_value.rs:138:61 | -128 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { +138 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:120:1 + --> $DIR/needless_pass_by_value.rs:130:1 | -120 | struct CopyWrapper(u32); +130 | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead | -128 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: &CopyWrapper) { -129 | let CopyWrapper(s) = *z; // moved +138 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: &CopyWrapper) { +139 | let CopyWrapper(s) = *z; // moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:140:40 + --> $DIR/needless_pass_by_value.rs:150:40 | -140 | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} +150 | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:145:20 + --> $DIR/needless_pass_by_value.rs:155:20 | -145 | fn more_fun(_item: impl Club<'static, i32>) {} +155 | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` error: aborting due to 22 previous errors diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index 6b1305fa2d8..b1ca6d75c99 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![crate_type = "proc-macro"] diff --git a/tests/ui/needless_range_loop.rs b/tests/ui/needless_range_loop.rs index 30613f98f2b..44515502835 100644 --- a/tests/ui/needless_range_loop.rs +++ b/tests/ui/needless_range_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn calc_idx(i: usize) -> usize { (i + i + 20) % 4 } diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index 1954a8240b2..64b1f3c08f7 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -1,33 +1,33 @@ error: the loop variable `i` is only used to index `ns`. - --> $DIR/needless_range_loop.rs:8:14 - | -8 | for i in 3..10 { - | ^^^^^ - | - = note: `-D clippy::needless-range-loop` implied by `-D warnings` + --> $DIR/needless_range_loop.rs:18:14 + | +18 | for i in 3..10 { + | ^^^^^ + | + = note: `-D clippy::needless-range-loop` implied by `-D warnings` help: consider using an iterator - | -8 | for <item> in ns.iter().take(10).skip(3) { - | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +18 | for <item> in ns.iter().take(10).skip(3) { + | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `ms`. - --> $DIR/needless_range_loop.rs:29:14 + --> $DIR/needless_range_loop.rs:39:14 | -29 | for i in 0..ms.len() { +39 | for i in 0..ms.len() { | ^^^^^^^^^^^ help: consider using an iterator | -29 | for <item> in &mut ms { +39 | for <item> in &mut ms { | ^^^^^^ ^^^^^^^ error: the loop variable `i` is only used to index `ms`. - --> $DIR/needless_range_loop.rs:35:14 + --> $DIR/needless_range_loop.rs:45:14 | -35 | for i in 0..ms.len() { +45 | for i in 0..ms.len() { | ^^^^^^^^^^^ help: consider using an iterator | -35 | for <item> in &mut ms { +45 | for <item> in &mut ms { | ^^^^^^ ^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index a834563eca3..bfe86573a4d 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 094fe3642a2..742ef8d379e 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,51 +1,51 @@ error: unneeded return statement - --> $DIR/needless_return.rs:11:5 + --> $DIR/needless_return.rs:21:5 | -11 | return true; +21 | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` | = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded return statement - --> $DIR/needless_return.rs:15:5 + --> $DIR/needless_return.rs:25:5 | -15 | return true +25 | return true | ^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:20:9 + --> $DIR/needless_return.rs:30:9 | -20 | return true; +30 | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:22:9 + --> $DIR/needless_return.rs:32:9 | -22 | return false; +32 | return false; | ^^^^^^^^^^^^^ help: remove `return` as shown: `false` error: unneeded return statement - --> $DIR/needless_return.rs:28:17 + --> $DIR/needless_return.rs:38:17 | -28 | true => return false, +38 | true => return false, | ^^^^^^^^^^^^ help: remove `return` as shown: `false` error: unneeded return statement - --> $DIR/needless_return.rs:30:13 + --> $DIR/needless_return.rs:40:13 | -30 | return true; +40 | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:37:9 + --> $DIR/needless_return.rs:47:9 | -37 | return true; +47 | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:39:16 + --> $DIR/needless_return.rs:49:16 | -39 | let _ = || return true; +49 | let _ = || return true; | ^^^^^^^^^^^ help: remove `return` as shown: `true` error: aborting due to 8 previous errors diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index 675c60e2477..70fe7236c24 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr index acc51198497..512cec84770 100644 --- a/tests/ui/needless_update.stderr +++ b/tests/ui/needless_update.stderr @@ -1,7 +1,7 @@ error: struct update has no effect, all the fields in the struct have already been specified - --> $DIR/needless_update.rs:16:23 + --> $DIR/needless_update.rs:26:23 | -16 | S { a: 1, b: 1, ..base }; +26 | S { a: 1, b: 1, ..base }; | ^^^^ | = note: `-D clippy::needless-update` implied by `-D warnings` diff --git a/tests/ui/neg_cmp_op_on_partial_ord.rs b/tests/ui/neg_cmp_op_on_partial_ord.rs index 3a472bf6995..c8edba32219 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] //! This test case utilizes `f64` an easy example for `PartialOrd` only types diff --git a/tests/ui/neg_cmp_op_on_partial_ord.stderr b/tests/ui/neg_cmp_op_on_partial_ord.stderr index 5fd4ab9ba48..1bd292818b3 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.stderr +++ b/tests/ui/neg_cmp_op_on_partial_ord.stderr @@ -1,27 +1,27 @@ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:19:21 + --> $DIR/neg_cmp_op_on_partial_ord.rs:29:21 | -19 | let _not_less = !(a_value < another_value); +29 | let _not_less = !(a_value < another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings` error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:22:30 + --> $DIR/neg_cmp_op_on_partial_ord.rs:32:30 | -22 | let _not_less_or_equal = !(a_value <= another_value); +32 | let _not_less_or_equal = !(a_value <= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:25:24 + --> $DIR/neg_cmp_op_on_partial_ord.rs:35:24 | -25 | let _not_greater = !(a_value > another_value); +35 | let _not_greater = !(a_value > another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:28:33 + --> $DIR/neg_cmp_op_on_partial_ord.rs:38:33 | -28 | let _not_greater_or_equal = !(a_value >= another_value); +38 | let _not_greater_or_equal = !(a_value >= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index b1a1879a3fc..2589f3b8551 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/neg_multiply.stderr b/tests/ui/neg_multiply.stderr index ba59fdb8940..ed96dd519ff 100644 --- a/tests/ui/neg_multiply.stderr +++ b/tests/ui/neg_multiply.stderr @@ -1,15 +1,15 @@ error: Negation by multiplying with -1 - --> $DIR/neg_multiply.rs:30:5 + --> $DIR/neg_multiply.rs:40:5 | -30 | x * -1; +40 | x * -1; | ^^^^^^ | = note: `-D clippy::neg-multiply` implied by `-D warnings` error: Negation by multiplying with -1 - --> $DIR/neg_multiply.rs:32:5 + --> $DIR/neg_multiply.rs:42:5 | -32 | -1 * x; +42 | -1 * x; | ^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index bb6d76b06cd..901a98559e7 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::single_match, unused_assignments, unused_variables, clippy::while_immutable_condition)] diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index 3d1235964d1..e4daa6e4350 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -1,93 +1,93 @@ error: this loop never actually loops - --> $DIR/never_loop.rs:7:5 + --> $DIR/never_loop.rs:17:5 | -7 | / loop { // clippy::never_loop -8 | | x += 1; -9 | | if x == 1 { -10 | | return -11 | | } -12 | | break; -13 | | } +17 | / loop { // clippy::never_loop +18 | | x += 1; +19 | | if x == 1 { +20 | | return +21 | | } +22 | | break; +23 | | } | |_____^ | = note: #[deny(clippy::never_loop)] on by default error: this loop never actually loops - --> $DIR/never_loop.rs:28:5 + --> $DIR/never_loop.rs:38:5 | -28 | / loop { // never loops -29 | | x += 1; -30 | | break -31 | | } +38 | / loop { // never loops +39 | | x += 1; +40 | | break +41 | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:47:2 + --> $DIR/never_loop.rs:57:2 | -47 | loop { // never loops +57 | loop { // never loops | _____^ -48 | | while i == 0 { // never loops -49 | | break -50 | | } -51 | | return -52 | | } +58 | | while i == 0 { // never loops +59 | | break +60 | | } +61 | | return +62 | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:48:9 + --> $DIR/never_loop.rs:58:9 | -48 | / while i == 0 { // never loops -49 | | break -50 | | } +58 | / while i == 0 { // never loops +59 | | break +60 | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:59:3 + --> $DIR/never_loop.rs:69:3 | -59 | loop { // never loops +69 | loop { // never loops | _________^ -60 | | if x == 5 { break } -61 | | continue 'outer -62 | | } +70 | | if x == 5 { break } +71 | | continue 'outer +72 | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:92:5 - | -92 | / while let Some(y) = x { // never loops -93 | | return -94 | | } - | |_____^ + --> $DIR/never_loop.rs:102:5 + | +102 | / while let Some(y) = x { // never loops +103 | | return +104 | | } + | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:98:5 + --> $DIR/never_loop.rs:108:5 | -98 | / for x in 0..10 { // never loops -99 | | match x { -100 | | 1 => break, -101 | | _ => return, -102 | | } -103 | | } +108 | / for x in 0..10 { // never loops +109 | | match x { +110 | | 1 => break, +111 | | _ => return, +112 | | } +113 | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:144:5 + --> $DIR/never_loop.rs:154:5 | -144 | / 'outer: while a { // never loops -145 | | while a { -146 | | if a { -147 | | a = false; +154 | / 'outer: while a { // never loops +155 | | while a { +156 | | if a { +157 | | a = false; ... | -151 | | break 'outer; -152 | | } +161 | | break 'outer; +162 | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:158:9 + --> $DIR/never_loop.rs:168:9 | -158 | / while false { -159 | | break 'label; -160 | | } +168 | / while false { +169 | | break 'label; +170 | | } | |_________^ error: aborting due to 9 previous errors diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index bf63e9336e5..46d2bc45f68 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(const_fn)] diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 11ece5e8708..5343428636c 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,39 +1,39 @@ error: you should consider deriving a `Default` implementation for `Foo` - --> $DIR/new_without_default.rs:12:5 + --> $DIR/new_without_default.rs:22:5 | -12 | pub fn new() -> Foo { Foo } +22 | pub fn new() -> Foo { Foo } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::new-without-default-derive` implied by `-D warnings` help: try this | -9 | #[derive(Default)] +19 | #[derive(Default)] | error: you should consider deriving a `Default` implementation for `Bar` - --> $DIR/new_without_default.rs:18:5 + --> $DIR/new_without_default.rs:28:5 | -18 | pub fn new() -> Self { Bar } +28 | pub fn new() -> Self { Bar } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this | -15 | #[derive(Default)] +25 | #[derive(Default)] | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> $DIR/new_without_default.rs:66:5 + --> $DIR/new_without_default.rs:76:5 | -66 | pub fn new() -> LtKo<'c> { unimplemented!() } +76 | pub fn new() -> LtKo<'c> { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::new-without-default` implied by `-D warnings` help: try this | -65 | impl Default for LtKo<'c> { -66 | fn default() -> Self { -67 | Self::new() -68 | } -69 | } +75 | impl Default for LtKo<'c> { +76 | fn default() -> Self { +77 | Self::new() +78 | } +79 | } | error: aborting due to 3 previous errors diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 2913ecdbf59..a56327eeefa 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(box_syntax)] diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 2429d934ca1..eca47d7546e 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,275 +1,275 @@ error: statement with no effect - --> $DIR/no_effect.rs:61:5 + --> $DIR/no_effect.rs:71:5 | -61 | 0; +71 | 0; | ^^ | = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:62:5 + --> $DIR/no_effect.rs:72:5 | -62 | s2; +72 | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:63:5 + --> $DIR/no_effect.rs:73:5 | -63 | Unit; +73 | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:64:5 + --> $DIR/no_effect.rs:74:5 | -64 | Tuple(0); +74 | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:65:5 + --> $DIR/no_effect.rs:75:5 | -65 | Struct { field: 0 }; +75 | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:66:5 + --> $DIR/no_effect.rs:76:5 | -66 | Struct { ..s }; +76 | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:67:5 + --> $DIR/no_effect.rs:77:5 | -67 | Union { a: 0 }; +77 | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:68:5 + --> $DIR/no_effect.rs:78:5 | -68 | Enum::Tuple(0); +78 | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:69:5 + --> $DIR/no_effect.rs:79:5 | -69 | Enum::Struct { field: 0 }; +79 | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:70:5 + --> $DIR/no_effect.rs:80:5 | -70 | 5 + 6; +80 | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:71:5 + --> $DIR/no_effect.rs:81:5 | -71 | *&42; +81 | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:72:5 + --> $DIR/no_effect.rs:82:5 | -72 | &6; +82 | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:73:5 + --> $DIR/no_effect.rs:83:5 | -73 | (5, 6, 7); +83 | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:74:5 + --> $DIR/no_effect.rs:84:5 | -74 | box 42; +84 | box 42; | ^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:75:5 + --> $DIR/no_effect.rs:85:5 | -75 | ..; +85 | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:76:5 + --> $DIR/no_effect.rs:86:5 | -76 | 5..; +86 | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:77:5 + --> $DIR/no_effect.rs:87:5 | -77 | ..5; +87 | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:78:5 + --> $DIR/no_effect.rs:88:5 | -78 | 5..6; +88 | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:80:5 + --> $DIR/no_effect.rs:90:5 | -80 | [42, 55]; +90 | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:81:5 + --> $DIR/no_effect.rs:91:5 | -81 | [42, 55][1]; +91 | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:82:5 + --> $DIR/no_effect.rs:92:5 | -82 | (42, 55).1; +92 | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:83:5 + --> $DIR/no_effect.rs:93:5 | -83 | [42; 55]; +93 | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:84:5 + --> $DIR/no_effect.rs:94:5 | -84 | [42; 55][13]; +94 | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:86:5 + --> $DIR/no_effect.rs:96:5 | -86 | || x += 5; +96 | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:88:5 + --> $DIR/no_effect.rs:98:5 | -88 | FooString { s: s }; +98 | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: statement can be reduced - --> $DIR/no_effect.rs:99:5 - | -99 | Tuple(get_number()); - | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` - | - = note: `-D clippy::unnecessary-operation` implied by `-D warnings` + --> $DIR/no_effect.rs:109:5 + | +109 | Tuple(get_number()); + | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` + | + = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: statement can be reduced - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:110:5 | -100 | Struct { field: get_number() }; +110 | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:111:5 | -101 | Struct { ..get_struct() }; +111 | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();` error: statement can be reduced - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:112:5 | -102 | Enum::Tuple(get_number()); +112 | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:113:5 | -103 | Enum::Struct { field: get_number() }; +113 | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:114:5 | -104 | 5 + get_number(); +114 | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:115:5 | -105 | *&get_number(); +115 | *&get_number(); | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:116:5 | -106 | &get_number(); +116 | &get_number(); | ^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:117:5 | -107 | (5, 6, get_number()); +117 | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:118:5 | -108 | box get_number(); +118 | box get_number(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:119:5 | -109 | get_number()..; +119 | get_number()..; | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:120:5 | -110 | ..get_number(); +120 | ..get_number(); | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:121:5 | -111 | 5..get_number(); +121 | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:122:5 | -112 | [42, get_number()]; +122 | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:123:5 | -113 | [42, 55][get_number() as usize]; +123 | [42, 55][get_number() as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_number() as usize;` error: statement can be reduced - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:124:5 | -114 | (42, get_number()).1; +124 | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:115:5 + --> $DIR/no_effect.rs:125:5 | -115 | [get_number(); 55]; +125 | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:126:5 | -116 | [42; 55][get_number() as usize]; +126 | [42; 55][get_number() as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_number() as usize;` error: statement can be reduced - --> $DIR/no_effect.rs:117:5 + --> $DIR/no_effect.rs:127:5 | -117 | {get_number()}; +127 | {get_number()}; | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/no_effect.rs:118:5 + --> $DIR/no_effect.rs:128:5 | -118 | FooString { s: String::from("blah"), }; +128 | FooString { s: String::from("blah"), }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `String::from("blah");` error: aborting due to 45 previous errors diff --git a/tests/ui/non_copy_const.rs b/tests/ui/non_copy_const.rs index 4e086333b0c..6c57a37e2ab 100644 --- a/tests/ui/non_copy_const.rs +++ b/tests/ui/non_copy_const.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(const_string_new, const_vec_new)] diff --git a/tests/ui/non_copy_const.stderr b/tests/ui/non_copy_const.stderr index 7f164595b59..744b5474844 100644 --- a/tests/ui/non_copy_const.stderr +++ b/tests/ui/non_copy_const.stderr @@ -1,7 +1,7 @@ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:12:1 + --> $DIR/non_copy_const.rs:22:1 | -12 | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +22 | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: make this a static item: `static` @@ -9,264 +9,264 @@ error: a const item should never be interior mutable = note: #[deny(clippy::declare_interior_mutable_const)] on by default error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:13:1 + --> $DIR/non_copy_const.rs:23:1 | -13 | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable +23 | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: make this a static item: `static` error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:14:1 + --> $DIR/non_copy_const.rs:24:1 | -14 | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7); +24 | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: make this a static item: `static` error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:18:42 + --> $DIR/non_copy_const.rs:28:42 | -18 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; +28 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; | ^^^^^^^^^^^^^^^^^^^^^^ -19 | } -20 | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable +29 | } +30 | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable | ------------------------------------------ in this macro invocation error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:41:5 + --> $DIR/non_copy_const.rs:51:5 | -41 | const ATOMIC: AtomicUsize; //~ ERROR interior mutable +51 | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:45:5 + --> $DIR/non_copy_const.rs:55:5 | -45 | const INPUT: T; +55 | const INPUT: T; | ^^^^^^^^^^^^^^^ | help: consider requiring `T` to be `Copy` - --> $DIR/non_copy_const.rs:45:18 + --> $DIR/non_copy_const.rs:55:18 | -45 | const INPUT: T; +55 | const INPUT: T; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:48:5 + --> $DIR/non_copy_const.rs:58:5 | -48 | const ASSOC: Self::NonCopyType; +58 | const ASSOC: Self::NonCopyType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy` - --> $DIR/non_copy_const.rs:48:18 + --> $DIR/non_copy_const.rs:58:18 | -48 | const ASSOC: Self::NonCopyType; +58 | const ASSOC: Self::NonCopyType; | ^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:52:5 + --> $DIR/non_copy_const.rs:62:5 | -52 | const AN_INPUT: T = Self::INPUT; +62 | const AN_INPUT: T = Self::INPUT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `T` to be `Copy` - --> $DIR/non_copy_const.rs:52:21 + --> $DIR/non_copy_const.rs:62:21 | -52 | const AN_INPUT: T = Self::INPUT; +62 | const AN_INPUT: T = Self::INPUT; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:18:42 + --> $DIR/non_copy_const.rs:28:42 | -18 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; +28 | ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; | ^^^^^^^^^^^^^^^^^^^^^^ ... -55 | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable +65 | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable | ----------------------------------------------- in this macro invocation error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:61:5 + --> $DIR/non_copy_const.rs:71:5 | -61 | const SELF_2: Self; +71 | const SELF_2: Self; | ^^^^^^^^^^^^^^^^^^^ | help: consider requiring `Self` to be `Copy` - --> $DIR/non_copy_const.rs:61:19 + --> $DIR/non_copy_const.rs:71:19 | -61 | const SELF_2: Self; +71 | const SELF_2: Self; | ^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:82:5 + --> $DIR/non_copy_const.rs:92:5 | -82 | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable +92 | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:85:5 + --> $DIR/non_copy_const.rs:95:5 | -85 | const U_SELF: U = U::SELF_2; +95 | const U_SELF: U = U::SELF_2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `U` to be `Copy` - --> $DIR/non_copy_const.rs:85:19 + --> $DIR/non_copy_const.rs:95:19 | -85 | const U_SELF: U = U::SELF_2; +95 | const U_SELF: U = U::SELF_2; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:88:5 + --> $DIR/non_copy_const.rs:98:5 | -88 | const T_ASSOC: T::NonCopyType = T::ASSOC; +98 | const T_ASSOC: T::NonCopyType = T::ASSOC; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy` - --> $DIR/non_copy_const.rs:88:20 + --> $DIR/non_copy_const.rs:98:20 | -88 | const T_ASSOC: T::NonCopyType = T::ASSOC; +98 | const T_ASSOC: T::NonCopyType = T::ASSOC; | ^^^^^^^^^^^^^^ error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:95:5 - | -95 | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability - | ^^^^^^ - | - = note: #[deny(clippy::borrow_interior_mutable_const)] on by default - = help: assign this const to a local or static variable, and use the variable here + --> $DIR/non_copy_const.rs:105:5 + | +105 | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^ + | + = note: #[deny(clippy::borrow_interior_mutable_const)] on by default + = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:96:16 - | -96 | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability - | ^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here + --> $DIR/non_copy_const.rs:106:16 + | +106 | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability + | ^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:98:5 - | -98 | ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability - | ^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here + --> $DIR/non_copy_const.rs:108:5 + | +108 | ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:99:16 - | -99 | assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability - | ^^^^^^^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here + --> $DIR/non_copy_const.rs:109:16 + | +109 | assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:102:22 + --> $DIR/non_copy_const.rs:112:22 | -102 | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability +112 | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:103:25 + --> $DIR/non_copy_const.rs:113:25 | -103 | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability +113 | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:104:27 + --> $DIR/non_copy_const.rs:114:27 | -104 | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability +114 | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:105:26 + --> $DIR/non_copy_const.rs:115:26 | -105 | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability +115 | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:116:14 + --> $DIR/non_copy_const.rs:126:14 | -116 | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability +126 | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:117:14 + --> $DIR/non_copy_const.rs:127:14 | -117 | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability +127 | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:118:19 + --> $DIR/non_copy_const.rs:128:19 | -118 | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability +128 | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:119:14 + --> $DIR/non_copy_const.rs:129:14 | -119 | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability +129 | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:120:13 + --> $DIR/non_copy_const.rs:130:13 | -120 | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability +130 | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:126:13 + --> $DIR/non_copy_const.rs:136:13 | -126 | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability +136 | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:131:5 + --> $DIR/non_copy_const.rs:141:5 | -131 | CELL.set(2); //~ ERROR interior mutability +141 | CELL.set(2); //~ ERROR interior mutability | ^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:132:16 + --> $DIR/non_copy_const.rs:142:16 | -132 | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability +142 | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:145:5 + --> $DIR/non_copy_const.rs:155:5 | -145 | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability +155 | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:146:16 + --> $DIR/non_copy_const.rs:156:16 | -146 | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability +156 | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index e8b0021e301..47e4da61b51 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all,clippy::similar_names)] diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 53cb36edacb..1369cd8a4ad 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,170 +1,170 @@ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:18:9 + --> $DIR/non_expressive_names.rs:28:9 | -18 | let bpple: i32; +28 | let bpple: i32; | ^^^^^ | = note: `-D clippy::similar-names` implied by `-D warnings` note: existing binding defined here - --> $DIR/non_expressive_names.rs:16:9 + --> $DIR/non_expressive_names.rs:26:9 | -16 | let apple: i32; +26 | let apple: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `b_pple` - --> $DIR/non_expressive_names.rs:18:9 + --> $DIR/non_expressive_names.rs:28:9 | -18 | let bpple: i32; +28 | let bpple: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:20:9 + --> $DIR/non_expressive_names.rs:30:9 | -20 | let cpple: i32; +30 | let cpple: i32; | ^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:16:9 + --> $DIR/non_expressive_names.rs:26:9 | -16 | let apple: i32; +26 | let apple: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `c_pple` - --> $DIR/non_expressive_names.rs:20:9 + --> $DIR/non_expressive_names.rs:30:9 | -20 | let cpple: i32; +30 | let cpple: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:45:9 + --> $DIR/non_expressive_names.rs:55:9 | -45 | let bluby: i32; +55 | let bluby: i32; | ^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:44:9 + --> $DIR/non_expressive_names.rs:54:9 | -44 | let blubx: i32; +54 | let blubx: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `blub_y` - --> $DIR/non_expressive_names.rs:45:9 + --> $DIR/non_expressive_names.rs:55:9 | -45 | let bluby: i32; +55 | let bluby: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:50:9 + --> $DIR/non_expressive_names.rs:60:9 | -50 | let coke: i32; +60 | let coke: i32; | ^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:48:9 + --> $DIR/non_expressive_names.rs:58:9 | -48 | let cake: i32; +58 | let cake: i32; | ^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:68:9 + --> $DIR/non_expressive_names.rs:78:9 | -68 | let xyzeabc: i32; +78 | let xyzeabc: i32; | ^^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:66:9 + --> $DIR/non_expressive_names.rs:76:9 | -66 | let xyz1abc: i32; +76 | let xyz1abc: i32; | ^^^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:72:9 + --> $DIR/non_expressive_names.rs:82:9 | -72 | let parsee: i32; +82 | let parsee: i32; | ^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:70:9 + --> $DIR/non_expressive_names.rs:80:9 | -70 | let parser: i32; +80 | let parser: i32; | ^^^^^^ help: separate the discriminating character by an underscore like: `parse_e` - --> $DIR/non_expressive_names.rs:72:9 + --> $DIR/non_expressive_names.rs:82:9 | -72 | let parsee: i32; +82 | let parsee: i32; | ^^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:86:16 + --> $DIR/non_expressive_names.rs:96:16 | -86 | bpple: sprang } = unimplemented!(); +96 | bpple: sprang } = unimplemented!(); | ^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:85:22 + --> $DIR/non_expressive_names.rs:95:22 | -85 | let Foo { apple: spring, +95 | let Foo { apple: spring, | ^^^^^^ error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:120:17 + --> $DIR/non_expressive_names.rs:130:17 | -120 | let e: i32; +130 | let e: i32; | ^ | = note: `-D clippy::many-single-char-names` implied by `-D warnings` error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:123:17 + --> $DIR/non_expressive_names.rs:133:17 | -123 | let e: i32; +133 | let e: i32; | ^ error: 6th binding whose name is just one char - --> $DIR/non_expressive_names.rs:124:17 + --> $DIR/non_expressive_names.rs:134:17 | -124 | let f: i32; +134 | let f: i32; | ^ error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:129:13 + --> $DIR/non_expressive_names.rs:139:13 | -129 | e => panic!(), +139 | e => panic!(), | ^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:139:9 + --> $DIR/non_expressive_names.rs:149:9 | -139 | let _1 = 1; //~ERROR Consider a more descriptive name +149 | let _1 = 1; //~ERROR Consider a more descriptive name | ^^ | = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings` error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:140:9 + --> $DIR/non_expressive_names.rs:150:9 | -140 | let ____1 = 1; //~ERROR Consider a more descriptive name +150 | let ____1 = 1; //~ERROR Consider a more descriptive name | ^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:141:9 + --> $DIR/non_expressive_names.rs:151:9 | -141 | let __1___2 = 12; //~ERROR Consider a more descriptive name +151 | let __1___2 = 12; //~ERROR Consider a more descriptive name | ^^^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:161:13 + --> $DIR/non_expressive_names.rs:171:13 | -161 | let _1 = 1; +171 | let _1 = 1; | ^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:162:13 + --> $DIR/non_expressive_names.rs:172:13 | -162 | let ____1 = 1; +172 | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:163:13 + --> $DIR/non_expressive_names.rs:173:13 | -163 | let __1___2 = 12; +173 | let __1___2 = 12; | ^^^^^^^ error: aborting due to 17 previous errors diff --git a/tests/ui/ok_expect.rs b/tests/ui/ok_expect.rs index 4341e8ea70b..5d333a72cc0 100644 --- a/tests/ui/ok_expect.rs +++ b/tests/ui/ok_expect.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + use std::io; struct MyError(()); // doesn't implement Debug diff --git a/tests/ui/ok_expect.stderr b/tests/ui/ok_expect.stderr index 7c158b5207b..f4c8440a774 100644 --- a/tests/ui/ok_expect.stderr +++ b/tests/ui/ok_expect.stderr @@ -1,33 +1,33 @@ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:14:5 + --> $DIR/ok_expect.rs:24:5 | -14 | res.ok().expect("disaster!"); +24 | res.ok().expect("disaster!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::ok-expect` implied by `-D warnings` error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:20:5 + --> $DIR/ok_expect.rs:30:5 | -20 | res3.ok().expect("whoof"); +30 | res3.ok().expect("whoof"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:22:5 + --> $DIR/ok_expect.rs:32:5 | -22 | res4.ok().expect("argh"); +32 | res4.ok().expect("argh"); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:24:5 + --> $DIR/ok_expect.rs:34:5 | -24 | res5.ok().expect("oops"); +34 | res5.ok().expect("oops"); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:26:5 + --> $DIR/ok_expect.rs:36:5 | -26 | res6.ok().expect("meh"); +36 | res6.ok().expect("meh"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index 46d85bb9cd0..71b301cbc42 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr index eac49032ed8..27b3ef28ff3 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/ok_if_let.stderr @@ -1,11 +1,11 @@ error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:7:5 + --> $DIR/ok_if_let.rs:17:5 | -7 | / if let Some(y) = x.parse().ok() { -8 | | y -9 | | } else { -10 | | 0 -11 | | } +17 | / if let Some(y) = x.parse().ok() { +18 | | y +19 | | } else { +20 | | 0 +21 | | } | |_____^ | = note: `-D clippy::if-let-some-result` implied by `-D warnings` diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index a85a2c8bb51..96a208ef807 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/op_ref.stderr b/tests/ui/op_ref.stderr index 398e3a6e9e6..e2b7b7820f3 100644 --- a/tests/ui/op_ref.stderr +++ b/tests/ui/op_ref.stderr @@ -1,19 +1,19 @@ error: needlessly taken reference of both operands - --> $DIR/op_ref.rs:13:15 + --> $DIR/op_ref.rs:23:15 | -13 | let foo = &5 - &6; +23 | let foo = &5 - &6; | ^^^^^^^ | = note: `-D clippy::op-ref` implied by `-D warnings` help: use the values directly | -13 | let foo = 5 - 6; +23 | let foo = 5 - 6; | ^ ^ error: taken reference of right operand - --> $DIR/op_ref.rs:21:8 + --> $DIR/op_ref.rs:31:8 | -21 | if b < &a { +31 | if b < &a { | ^^^^-- | | | help: use the right value directly: `a` diff --git a/tests/ui/open_options.rs b/tests/ui/open_options.rs index 38b3dd7e49d..a01f2b1ce39 100644 --- a/tests/ui/open_options.rs +++ b/tests/ui/open_options.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::fs::OpenOptions; diff --git a/tests/ui/open_options.stderr b/tests/ui/open_options.stderr index 64ad667a4c7..2835eebfbb3 100644 --- a/tests/ui/open_options.stderr +++ b/tests/ui/open_options.stderr @@ -1,45 +1,45 @@ error: file opened with "truncate" and "read" - --> $DIR/open_options.rs:8:5 - | -8 | OpenOptions::new().read(true).truncate(true).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::nonsensical-open-options` implied by `-D warnings` + --> $DIR/open_options.rs:18:5 + | +18 | OpenOptions::new().read(true).truncate(true).open("foo.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::nonsensical-open-options` implied by `-D warnings` error: file opened with "append" and "truncate" - --> $DIR/open_options.rs:9:5 - | -9 | OpenOptions::new().append(true).truncate(true).open("foo.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/open_options.rs:19:5 + | +19 | OpenOptions::new().append(true).truncate(true).open("foo.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "read" is called more than once - --> $DIR/open_options.rs:11:5 + --> $DIR/open_options.rs:21:5 | -11 | OpenOptions::new().read(true).read(false).open("foo.txt"); +21 | OpenOptions::new().read(true).read(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "create" is called more than once - --> $DIR/open_options.rs:12:5 + --> $DIR/open_options.rs:22:5 | -12 | OpenOptions::new().create(true).create(false).open("foo.txt"); +22 | OpenOptions::new().create(true).create(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "write" is called more than once - --> $DIR/open_options.rs:13:5 + --> $DIR/open_options.rs:23:5 | -13 | OpenOptions::new().write(true).write(false).open("foo.txt"); +23 | OpenOptions::new().write(true).write(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "append" is called more than once - --> $DIR/open_options.rs:14:5 + --> $DIR/open_options.rs:24:5 | -14 | OpenOptions::new().append(true).append(false).open("foo.txt"); +24 | OpenOptions::new().append(true).append(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "truncate" is called more than once - --> $DIR/open_options.rs:15:5 + --> $DIR/open_options.rs:25:5 | -15 | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); +25 | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/option_map_unit_fn.rs b/tests/ui/option_map_unit_fn.rs index e86cc99c522..a69c41ce967 100644 --- a/tests/ui/option_map_unit_fn.rs +++ b/tests/ui/option_map_unit_fn.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::option_map_unit_fn)] diff --git a/tests/ui/option_map_unit_fn.stderr b/tests/ui/option_map_unit_fn.stderr index 77fe24d2696..7a2dfd338a3 100644 --- a/tests/ui/option_map_unit_fn.stderr +++ b/tests/ui/option_map_unit_fn.stderr @@ -1,7 +1,7 @@ error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:34:5 + --> $DIR/option_map_unit_fn.rs:44:5 | -34 | x.field.map(do_nothing); +44 | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(x_field) = x.field { do_nothing(...) }` @@ -9,202 +9,202 @@ error: called `map(f)` on an Option value where `f` is a unit function = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:36:5 + --> $DIR/option_map_unit_fn.rs:46:5 | -36 | x.field.map(do_nothing); +46 | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(x_field) = x.field { do_nothing(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:38:5 + --> $DIR/option_map_unit_fn.rs:48:5 | -38 | x.field.map(diverge); +48 | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(x_field) = x.field { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:44:5 + --> $DIR/option_map_unit_fn.rs:54:5 | -44 | x.field.map(|value| x.do_option_nothing(value + captured)); +54 | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:46:5 + --> $DIR/option_map_unit_fn.rs:56:5 | -46 | x.field.map(|value| { x.do_option_plus_one(value + captured); }); +56 | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:49:5 + --> $DIR/option_map_unit_fn.rs:59:5 | -49 | x.field.map(|value| do_nothing(value + captured)); +59 | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:51:5 + --> $DIR/option_map_unit_fn.rs:61:5 | -51 | x.field.map(|value| { do_nothing(value + captured) }); +61 | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:53:5 + --> $DIR/option_map_unit_fn.rs:63:5 | -53 | x.field.map(|value| { do_nothing(value + captured); }); +63 | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:55:5 + --> $DIR/option_map_unit_fn.rs:65:5 | -55 | x.field.map(|value| { { do_nothing(value + captured); } }); +65 | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:58:5 + --> $DIR/option_map_unit_fn.rs:68:5 | -58 | x.field.map(|value| diverge(value + captured)); +68 | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:60:5 + --> $DIR/option_map_unit_fn.rs:70:5 | -60 | x.field.map(|value| { diverge(value + captured) }); +70 | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:62:5 + --> $DIR/option_map_unit_fn.rs:72:5 | -62 | x.field.map(|value| { diverge(value + captured); }); +72 | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:64:5 + --> $DIR/option_map_unit_fn.rs:74:5 | -64 | x.field.map(|value| { { diverge(value + captured); } }); +74 | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:69:5 + --> $DIR/option_map_unit_fn.rs:79:5 | -69 | x.field.map(|value| { let y = plus_one(value + captured); }); +79 | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:71:5 + --> $DIR/option_map_unit_fn.rs:81:5 | -71 | x.field.map(|value| { plus_one(value + captured); }); +81 | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:73:5 + --> $DIR/option_map_unit_fn.rs:83:5 | -73 | x.field.map(|value| { { plus_one(value + captured); } }); +83 | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:76:5 + --> $DIR/option_map_unit_fn.rs:86:5 | -76 | x.field.map(|ref value| { do_nothing(value + captured) }); +86 | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:79:5 + --> $DIR/option_map_unit_fn.rs:89:5 | -79 | x.field.map(|value| { do_nothing(value); do_nothing(value) }); +89 | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:81:5 + --> $DIR/option_map_unit_fn.rs:91:5 | -81 | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); +91 | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:85:5 + --> $DIR/option_map_unit_fn.rs:95:5 | -85 | x.field.map(|value| { +95 | x.field.map(|value| { | _____^ | |_____| | || -86 | || do_nothing(value); -87 | || do_nothing(value) -88 | || }); +96 | || do_nothing(value); +97 | || do_nothing(value) +98 | || }); | ||______^- help: try this: `if let Some(value) = x.field { ... }` | |_______| | error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:89:5 + --> $DIR/option_map_unit_fn.rs:99:5 | -89 | x.field.map(|value| { do_nothing(value); do_nothing(value); }); +99 | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:92:5 - | -92 | Some(42).map(diverge); - | ^^^^^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Some(_) = Some(42) { diverge(...) }` + --> $DIR/option_map_unit_fn.rs:102:5 + | +102 | Some(42).map(diverge); + | ^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Some(_) = Some(42) { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:93:5 - | -93 | "12".parse::<i32>().ok().map(diverge); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }` + --> $DIR/option_map_unit_fn.rs:103:5 + | +103 | "12".parse::<i32>().ok().map(diverge); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:94:5 - | -94 | Some(plus_one(1)).map(do_nothing); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }` + --> $DIR/option_map_unit_fn.rs:104:5 + | +104 | Some(plus_one(1)).map(do_nothing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:98:5 - | -98 | y.map(do_nothing); - | ^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Some(_y) = y { do_nothing(...) }` + --> $DIR/option_map_unit_fn.rs:108:5 + | +108 | y.map(do_nothing); + | ^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Some(_y) = y { do_nothing(...) }` error: aborting due to 25 previous errors diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 249745c6a45..3cb4fdc27eb 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn input(_: Option<Option<u8>>) { } diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 4341857cce0..8a867fd4fe2 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,57 +1,57 @@ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:1:13 - | -1 | fn input(_: Option<Option<u8>>) { - | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::option-option` implied by `-D warnings` + --> $DIR/option_option.rs:11:13 + | +11 | fn input(_: Option<Option<u8>>) { + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::option-option` implied by `-D warnings` error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:4:16 - | -4 | fn output() -> Option<Option<u8>> { - | ^^^^^^^^^^^^^^^^^^ + --> $DIR/option_option.rs:14:16 + | +14 | fn output() -> Option<Option<u8>> { + | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:8:27 - | -8 | fn output_nested() -> Vec<Option<Option<u8>>> { - | ^^^^^^^^^^^^^^^^^^ + --> $DIR/option_option.rs:18:27 + | +18 | fn output_nested() -> Vec<Option<Option<u8>>> { + | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:13:30 + --> $DIR/option_option.rs:23:30 | -13 | fn output_nested_nested() -> Option<Option<Option<u8>>> { +23 | fn output_nested_nested() -> Option<Option<Option<u8>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:18:8 + --> $DIR/option_option.rs:28:8 | -18 | x: Option<Option<u8>>, +28 | x: Option<Option<u8>>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:22:23 + --> $DIR/option_option.rs:32:23 | -22 | fn struct_fn() -> Option<Option<u8>> { +32 | fn struct_fn() -> Option<Option<u8>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:28:22 + --> $DIR/option_option.rs:38:22 | -28 | fn trait_fn() -> Option<Option<u8>>; +38 | fn trait_fn() -> Option<Option<u8>>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:32:11 + --> $DIR/option_option.rs:42:11 | -32 | Tuple(Option<Option<u8>>), +42 | Tuple(Option<Option<u8>>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:33:15 + --> $DIR/option_option.rs:43:15 | -33 | Struct{x: Option<Option<u8>>}, +43 | Struct{x: Option<Option<u8>>}, | ^^^^^^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index 5c3cc5b08a9..8aba051c65e 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 9659e352af1..0bd20210f01 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -1,51 +1,51 @@ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:11:5 + --> $DIR/overflow_check_conditional.rs:21:5 | -11 | if a + b < a { +21 | if a + b < a { | ^^^^^^^^^ | = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:14:5 + --> $DIR/overflow_check_conditional.rs:24:5 | -14 | if a > a + b { +24 | if a > a + b { | ^^^^^^^^^ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:17:5 + --> $DIR/overflow_check_conditional.rs:27:5 | -17 | if a + b < b { +27 | if a + b < b { | ^^^^^^^^^ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:20:5 + --> $DIR/overflow_check_conditional.rs:30:5 | -20 | if b > a + b { +30 | if b > a + b { | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:23:5 + --> $DIR/overflow_check_conditional.rs:33:5 | -23 | if a - b > b { +33 | if a - b > b { | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:26:5 + --> $DIR/overflow_check_conditional.rs:36:5 | -26 | if b < a - b { +36 | if b < a - b { | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:29:5 + --> $DIR/overflow_check_conditional.rs:39:5 | -29 | if a - b > a { +39 | if a - b > a { | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:32:5 + --> $DIR/overflow_check_conditional.rs:42:5 | -32 | if a < a - b { +42 | if a < a - b { | ^^^^^^^^^ error: aborting due to 8 previous errors diff --git a/tests/ui/panic_unimplemented.rs b/tests/ui/panic_unimplemented.rs index 693dc921be3..f292455dc7d 100644 --- a/tests/ui/panic_unimplemented.rs +++ b/tests/ui/panic_unimplemented.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/panic_unimplemented.stderr b/tests/ui/panic_unimplemented.stderr index c5ce42f4c54..75032c1170e 100644 --- a/tests/ui/panic_unimplemented.stderr +++ b/tests/ui/panic_unimplemented.stderr @@ -1,33 +1,33 @@ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:8:16 - | -8 | panic!("{}"); - | ^^^^ - | - = note: `-D clippy::panic-params` implied by `-D warnings` + --> $DIR/panic_unimplemented.rs:18:16 + | +18 | panic!("{}"); + | ^^^^ + | + = note: `-D clippy::panic-params` implied by `-D warnings` error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:10:16 + --> $DIR/panic_unimplemented.rs:20:16 | -10 | panic!("{:?}"); +20 | panic!("{:?}"); | ^^^^^^ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:12:23 + --> $DIR/panic_unimplemented.rs:22:23 | -12 | assert!(true, "here be missing values: {}"); +22 | assert!(true, "here be missing values: {}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:15:12 + --> $DIR/panic_unimplemented.rs:25:12 | -15 | panic!("{{{this}}}"); +25 | panic!("{{{this}}}"); | ^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> $DIR/panic_unimplemented.rs:58:5 + --> $DIR/panic_unimplemented.rs:68:5 | -58 | unimplemented!(); +68 | unimplemented!(); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` diff --git a/tests/ui/partialeq_ne_impl.rs b/tests/ui/partialeq_ne_impl.rs index 36dd4df8a6e..45aa0decd58 100644 --- a/tests/ui/partialeq_ne_impl.rs +++ b/tests/ui/partialeq_ne_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/tests/ui/partialeq_ne_impl.stderr b/tests/ui/partialeq_ne_impl.stderr index 773bed8fd8e..0ed2d0789cb 100644 --- a/tests/ui/partialeq_ne_impl.stderr +++ b/tests/ui/partialeq_ne_impl.stderr @@ -1,7 +1,7 @@ error: re-implementing `PartialEq::ne` is unnecessary - --> $DIR/partialeq_ne_impl.rs:10:5 + --> $DIR/partialeq_ne_impl.rs:20:5 | -10 | fn ne(&self, _: &Foo) -> bool { false } +20 | fn ne(&self, _: &Foo) -> bool { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::partialeq-ne-impl` implied by `-D warnings` diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 70f86afbacb..2b42aae63ea 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused)] diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index ce8aab7e627..d236da24022 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,7 +1,7 @@ error: the `y @ _` pattern can be written as just `y` - --> $DIR/patterns.rs:10:9 + --> $DIR/patterns.rs:20:9 | -10 | y @ _ => (), +20 | y @ _ => (), | ^^^^^ | = note: `-D clippy::redundant-pattern` implied by `-D warnings` diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 95476dd4f51..ccc08ddc5d7 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 5ec1732ee56..3d5553ed0c3 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -1,57 +1,57 @@ error: operator precedence can trip the unwary - --> $DIR/precedence.rs:18:5 + --> $DIR/precedence.rs:28:5 | -18 | 1 << 2 + 3; +28 | 1 << 2 + 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)` | = note: `-D clippy::precedence` implied by `-D warnings` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:19:5 + --> $DIR/precedence.rs:29:5 | -19 | 1 + 2 << 3; +29 | 1 + 2 << 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:20:5 + --> $DIR/precedence.rs:30:5 | -20 | 4 >> 1 + 1; +30 | 4 >> 1 + 1; | ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:21:5 + --> $DIR/precedence.rs:31:5 | -21 | 1 + 3 >> 2; +31 | 1 + 3 >> 2; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:22:5 + --> $DIR/precedence.rs:32:5 | -22 | 1 ^ 1 - 1; +32 | 1 ^ 1 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:23:5 + --> $DIR/precedence.rs:33:5 | -23 | 3 | 2 - 1; +33 | 3 | 2 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:24:5 + --> $DIR/precedence.rs:34:5 | -24 | 3 & 5 - 2; +34 | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` error: unary minus has lower precedence than method call - --> $DIR/precedence.rs:25:5 + --> $DIR/precedence.rs:35:5 | -25 | -1i32.abs(); +35 | -1i32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())` error: unary minus has lower precedence than method call - --> $DIR/precedence.rs:26:5 + --> $DIR/precedence.rs:36:5 | -26 | -1f32.abs(); +36 | -1f32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` error: aborting due to 9 previous errors diff --git a/tests/ui/print.rs b/tests/ui/print.rs index cee3e700036..3bb72fcb1f4 100644 --- a/tests/ui/print.rs +++ b/tests/ui/print.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::print_literal, clippy::write_literal)] diff --git a/tests/ui/print.stderr b/tests/ui/print.stderr index 92a2f2f9627..605e527c208 100644 --- a/tests/ui/print.stderr +++ b/tests/ui/print.stderr @@ -1,59 +1,59 @@ error: use of `Debug`-based formatting - --> $DIR/print.rs:13:19 + --> $DIR/print.rs:23:19 | -13 | write!(f, "{:?}", 43.1415) +23 | write!(f, "{:?}", 43.1415) | ^^^^^^ | = note: `-D clippy::use-debug` implied by `-D warnings` error: use of `Debug`-based formatting - --> $DIR/print.rs:20:19 + --> $DIR/print.rs:30:19 | -20 | write!(f, "{:?}", 42.718) +30 | write!(f, "{:?}", 42.718) | ^^^^^^ error: use of `println!` - --> $DIR/print.rs:25:5 + --> $DIR/print.rs:35:5 | -25 | println!("Hello"); +35 | println!("Hello"); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::print-stdout` implied by `-D warnings` error: use of `print!` - --> $DIR/print.rs:26:5 + --> $DIR/print.rs:36:5 | -26 | print!("Hello"); +36 | print!("Hello"); | ^^^^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:28:5 + --> $DIR/print.rs:38:5 | -28 | print!("Hello {}", "World"); +38 | print!("Hello {}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:30:5 + --> $DIR/print.rs:40:5 | -30 | print!("Hello {:?}", "World"); +40 | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:30:12 + --> $DIR/print.rs:40:12 | -30 | print!("Hello {:?}", "World"); +40 | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:32:5 + --> $DIR/print.rs:42:5 | -32 | print!("Hello {:#?}", "#orld"); +42 | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:32:12 + --> $DIR/print.rs:42:12 | -32 | print!("Hello {:#?}", "#orld"); +42 | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 46b91d40f8c..fd68751820d 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::print_literal)] diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index bd13f5d1730..9fe7fe34e6e 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,87 +1,87 @@ error: literal with an empty format string - --> $DIR/print_literal.rs:24:71 + --> $DIR/print_literal.rs:34:71 | -24 | println!("{} of {:b} people know binary, the other half doesn't", 1, 2); +34 | println!("{} of {:b} people know binary, the other half doesn't", 1, 2); | ^ | = note: `-D clippy::print-literal` implied by `-D warnings` error: literal with an empty format string - --> $DIR/print_literal.rs:25:24 + --> $DIR/print_literal.rs:35:24 | -25 | print!("Hello {}", "world"); +35 | print!("Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:26:36 + --> $DIR/print_literal.rs:36:36 | -26 | println!("Hello {} {}", world, "world"); +36 | println!("Hello {} {}", world, "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:27:26 + --> $DIR/print_literal.rs:37:26 | -27 | println!("Hello {}", "world"); +37 | println!("Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:28:30 + --> $DIR/print_literal.rs:38:30 | -28 | println!("10 / 4 is {}", 2.5); +38 | println!("10 / 4 is {}", 2.5); | ^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:29:28 + --> $DIR/print_literal.rs:39:28 | -29 | println!("2 + 1 = {}", 3); +39 | println!("2 + 1 = {}", 3); | ^ error: literal with an empty format string - --> $DIR/print_literal.rs:34:25 + --> $DIR/print_literal.rs:44:25 | -34 | println!("{0} {1}", "hello", "world"); +44 | println!("{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:34:34 + --> $DIR/print_literal.rs:44:34 | -34 | println!("{0} {1}", "hello", "world"); +44 | println!("{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:35:25 + --> $DIR/print_literal.rs:45:25 | -35 | println!("{1} {0}", "hello", "world"); +45 | println!("{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:35:34 + --> $DIR/print_literal.rs:45:34 | -35 | println!("{1} {0}", "hello", "world"); +45 | println!("{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:38:33 + --> $DIR/print_literal.rs:48:33 | -38 | println!("{foo} {bar}", foo="hello", bar="world"); +48 | println!("{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:38:46 + --> $DIR/print_literal.rs:48:46 | -38 | println!("{foo} {bar}", foo="hello", bar="world"); +48 | println!("{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:39:33 + --> $DIR/print_literal.rs:49:33 | -39 | println!("{bar} {foo}", foo="hello", bar="world"); +49 | println!("{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:39:46 + --> $DIR/print_literal.rs:49:46 | -39 | println!("{bar} {foo}", foo="hello", bar="world"); +49 | println!("{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index c2c79c726e8..4fc24080d46 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::print_literal)] diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 12c4ecb2f3e..4cd7a6685d4 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -1,27 +1,27 @@ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:7:5 - | -7 | print!("Hello/n"); - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::print-with-newline` implied by `-D warnings` + --> $DIR/print_with_newline.rs:17:5 + | +17 | print!("Hello/n"); + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::print-with-newline` implied by `-D warnings` error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:8:5 - | -8 | print!("Hello {}/n", "world"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/print_with_newline.rs:18:5 + | +18 | print!("Hello {}/n", "world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:9:5 - | -9 | print!("Hello {} {}/n", "world", "#2"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/print_with_newline.rs:19:5 + | +19 | print!("Hello {} {}/n", "world", "#2"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:10:5 + --> $DIR/print_with_newline.rs:20:5 | -10 | print!("{}/n", 1265); +20 | print!("{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 9df348050ad..afc37b1bec7 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { println!(); println!(""); diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 96d15838400..e06b403cfec 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -1,16 +1,16 @@ error: using `println!("")` - --> $DIR/println_empty_string.rs:3:5 - | -3 | println!(""); - | ^^^^^^^^^^^^ help: replace it with: `println!()` - | - = note: `-D clippy::println-empty-string` implied by `-D warnings` + --> $DIR/println_empty_string.rs:13:5 + | +13 | println!(""); + | ^^^^^^^^^^^^ help: replace it with: `println!()` + | + = note: `-D clippy::println-empty-string` implied by `-D warnings` error: using `println!("")` - --> $DIR/println_empty_string.rs:6:14 - | -6 | _ => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` + --> $DIR/println_empty_string.rs:16:14 + | +16 | _ => println!(""), + | ^^^^^^^^^^^^ help: replace it with: `println!()` error: aborting due to 2 previous errors diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 7cd3c9f9c72..4d5f353bb6a 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused, clippy::many_single_char_names)] diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 6c16443f524..e7aecf7c20b 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,85 +1,85 @@ error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:8:14 - | -8 | fn do_vec(x: &Vec<i64>) { - | ^^^^^^^^^ help: change this to: `&[i64]` - | - = note: `-D clippy::ptr-arg` implied by `-D warnings` + --> $DIR/ptr_arg.rs:18:14 + | +18 | fn do_vec(x: &Vec<i64>) { + | ^^^^^^^^^ help: change this to: `&[i64]` + | + = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:16:14 + --> $DIR/ptr_arg.rs:26:14 | -16 | fn do_str(x: &String) { +26 | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:29:18 + --> $DIR/ptr_arg.rs:39:18 | -29 | fn do_vec(x: &Vec<i64>); +39 | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:42:14 + --> $DIR/ptr_arg.rs:52:14 | -42 | fn cloned(x: &Vec<u8>) -> Vec<u8> { +52 | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ help: change this to | -42 | fn cloned(x: &[u8]) -> Vec<u8> { +52 | fn cloned(x: &[u8]) -> Vec<u8> { | ^^^^^ help: change `x.clone()` to | -43 | let e = x.to_owned(); +53 | let e = x.to_owned(); | ^^^^^^^^^^^^ help: change `x.clone()` to | -48 | x.to_owned() +58 | x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:51:18 + --> $DIR/ptr_arg.rs:61:18 | -51 | fn str_cloned(x: &String) -> String { +61 | fn str_cloned(x: &String) -> String { | ^^^^^^^ help: change this to | -51 | fn str_cloned(x: &str) -> String { +61 | fn str_cloned(x: &str) -> String { | ^^^^ help: change `x.clone()` to | -52 | let a = x.to_string(); +62 | let a = x.to_string(); | ^^^^^^^^^^^^^ help: change `x.clone()` to | -53 | let b = x.to_string(); +63 | let b = x.to_string(); | ^^^^^^^^^^^^^ help: change `x.clone()` to | -58 | x.to_string() +68 | x.to_string() | error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:61:44 + --> $DIR/ptr_arg.rs:71:44 | -61 | fn false_positive_capacity(x: &Vec<u8>, y: &String) { +71 | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ help: change this to | -61 | fn false_positive_capacity(x: &Vec<u8>, y: &str) { +71 | fn false_positive_capacity(x: &Vec<u8>, y: &str) { | ^^^^ help: change `y.clone()` to | -63 | let b = y.to_string(); +73 | let b = y.to_string(); | ^^^^^^^^^^^^^ help: change `y.as_str()` to | -64 | let c = y; +74 | let c = y; | ^ error: using a reference to `Cow` is not recommended. - --> $DIR/ptr_arg.rs:73:25 + --> $DIR/ptr_arg.rs:83:25 | -73 | fn test_cow_with_ref(c: &Cow<[i32]>) { +83 | fn test_cow_with_ref(c: &Cow<[i32]>) { | ^^^^^^^^^^^ help: change this to: `&[i32]` error: aborting due to 7 previous errors diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 4549f960ca0..a6f86a230f3 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { let vec = vec![b'a', b'b', b'c']; let ptr = vec.as_ptr(); diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr index 214a39cdc11..b3df0abbaa8 100644 --- a/tests/ui/ptr_offset_with_cast.stderr +++ b/tests/ui/ptr_offset_with_cast.stderr @@ -1,15 +1,15 @@ error: use of `offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:10:9 + --> $DIR/ptr_offset_with_cast.rs:20:9 | -10 | ptr.offset(offset_usize as isize); +20 | ptr.offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` | = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:14:9 + --> $DIR/ptr_offset_with_cast.rs:24:9 | -14 | ptr.wrapping_offset(offset_usize as isize); +24 | ptr.wrapping_offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` error: aborting due to 2 previous errors diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 369b868a50d..a39ea00cb8b 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn some_func(a: Option<u32>) -> Option<u32> { if a.is_none() { return None diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 68c0e5e381a..7ca76e38192 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,21 +1,21 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:2:2 - | -2 | if a.is_none() { - | _____^ -3 | | return None -4 | | } - | |_____^ help: replace_it_with: `a?;` - | - = note: `-D clippy::question-mark` implied by `-D warnings` + --> $DIR/question_mark.rs:12:2 + | +12 | if a.is_none() { + | _____^ +13 | | return None +14 | | } + | |_____^ help: replace_it_with: `a?;` + | + = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:37:3 + --> $DIR/question_mark.rs:47:3 | -37 | if (self.opt).is_none() { +47 | if (self.opt).is_none() { | _________^ -38 | | return None; -39 | | } +48 | | return None; +49 | | } | |_________^ help: replace_it_with: `(self.opt)?;` error: aborting due to 2 previous errors diff --git a/tests/ui/range.rs b/tests/ui/range.rs index df3ce12689b..270b71d263f 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] struct NotARange; diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index 651ff266c1a..2dc81b4f042 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -1,41 +1,41 @@ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:10:13 + --> $DIR/range.rs:20:13 | -10 | let _ = (0..1).step_by(0); +20 | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:14:13 + --> $DIR/range.rs:24:13 | -14 | let _ = (1..).step_by(0); +24 | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:15:13 + --> $DIR/range.rs:25:13 | -15 | let _ = (1..=2).step_by(0); +25 | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:18:13 + --> $DIR/range.rs:28:13 | -18 | let _ = x.step_by(0); +28 | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: It is more idiomatic to use v1.iter().enumerate() - --> $DIR/range.rs:26:14 + --> $DIR/range.rs:36:14 | -26 | let _x = v1.iter().zip(0..v1.len()); +36 | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::range-zip-with-len` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:30:13 + --> $DIR/range.rs:40:13 | -30 | let _ = v1.iter().step_by(2/3); +40 | let _ = v1.iter().step_by(2/3); | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index 1ee3637f266..15743828d8b 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] fn f() -> usize { diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index 3fe4e7ca073..0cac21734dc 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -1,53 +1,53 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:12:14 + --> $DIR/range_plus_minus_one.rs:22:14 | -12 | for _ in 0..3+1 { } +22 | for _ in 0..3+1 { } | ^^^^^^ help: use: `0..=3` | = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:15:14 + --> $DIR/range_plus_minus_one.rs:25:14 | -15 | for _ in 0..1+5 { } +25 | for _ in 0..1+5 { } | ^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:18:14 + --> $DIR/range_plus_minus_one.rs:28:14 | -18 | for _ in 1..1+1 { } +28 | for _ in 1..1+1 { } | ^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:24:14 + --> $DIR/range_plus_minus_one.rs:34:14 | -24 | for _ in 0..(1+f()) { } +34 | for _ in 0..(1+f()) { } | ^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:28:13 + --> $DIR/range_plus_minus_one.rs:38:13 | -28 | let _ = ..=11-1; +38 | let _ = ..=11-1; | ^^^^^^^ help: use: `..11` | = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:29:13 + --> $DIR/range_plus_minus_one.rs:39:13 | -29 | let _ = ..=(11-1); +39 | let _ = ..=(11-1); | ^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:30:13 + --> $DIR/range_plus_minus_one.rs:40:13 | -30 | let _ = (1..11+1); +40 | let _ = (1..11+1); | ^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:13 + --> $DIR/range_plus_minus_one.rs:41:13 | -31 | let _ = (f()+1)..(f()+1); +41 | let _ = (f()+1)..(f()+1); | ^^^^^^^^^^^^^^^^ help: use: `((f()+1)..=f())` error: aborting due to 8 previous errors diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index b09ed9a3574..bf0cc550b0d 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call.stderr index e4d490743ad..1563de3d74f 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call.stderr @@ -1,33 +1,33 @@ error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:15:2 + --> $DIR/redundant_closure_call.rs:25:2 | -15 | i = closure(); +25 | i = closure(); | ^^^^^^^^^^^^^ | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:18:2 + --> $DIR/redundant_closure_call.rs:28:2 | -18 | i = closure(3); +28 | i = closure(3); | ^^^^^^^^^^^^^^ error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:7:10 - | -7 | let a = (|| 42)(); - | ^^^^^^^^^ help: Try doing something like: : `42` + --> $DIR/redundant_closure_call.rs:17:10 + | +17 | let a = (|| 42)(); + | ^^^^^^^^^ help: Try doing something like: : `42` error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:10:14 + --> $DIR/redundant_closure_call.rs:20:14 | -10 | let mut k = (|m| m+1)(i); +20 | let mut k = (|m| m+1)(i); | ^^^^^^^^^^^^ error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:12:6 + --> $DIR/redundant_closure_call.rs:22:6 | -12 | k = (|a,b| a*b)(1,5); +22 | k = (|a,b| a*b)(1,5); | ^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index b379aa661cb..ac0d5d10535 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::redundant_field_names)] diff --git a/tests/ui/redundant_field_names.stderr b/tests/ui/redundant_field_names.stderr index 457fe7d3c6c..d81ddf343f1 100644 --- a/tests/ui/redundant_field_names.stderr +++ b/tests/ui/redundant_field_names.stderr @@ -1,45 +1,45 @@ error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:36:9 + --> $DIR/redundant_field_names.rs:46:9 | -36 | gender: gender, +46 | gender: gender, | ^^^^^^^^^^^^^^ help: replace it with: `gender` | = note: `-D clippy::redundant-field-names` implied by `-D warnings` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:37:9 + --> $DIR/redundant_field_names.rs:47:9 | -37 | age: age, +47 | age: age, | ^^^^^^^^ help: replace it with: `age` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:58:25 + --> $DIR/redundant_field_names.rs:68:25 | -58 | let _ = RangeFrom { start: start }; +68 | let _ = RangeFrom { start: start }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:59:23 + --> $DIR/redundant_field_names.rs:69:23 | -59 | let _ = RangeTo { end: end }; +69 | let _ = RangeTo { end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:60:21 + --> $DIR/redundant_field_names.rs:70:21 | -60 | let _ = Range { start: start, end: end }; +70 | let _ = Range { start: start, end: end }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:60:35 + --> $DIR/redundant_field_names.rs:70:35 | -60 | let _ = Range { start: start, end: end }; +70 | let _ = Range { start: start, end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:62:32 + --> $DIR/redundant_field_names.rs:72:32 | -62 | let _ = RangeToInclusive { end: end }; +72 | let _ = RangeToInclusive { end: end }; | ^^^^^^^^ help: replace it with: `end` error: aborting due to 7 previous errors diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs index 97a0030a99a..9298aee2cac 100644 --- a/tests/ui/reference.rs +++ b/tests/ui/reference.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/reference.stderr b/tests/ui/reference.stderr index 13e0da98795..4187d55cb47 100644 --- a/tests/ui/reference.stderr +++ b/tests/ui/reference.stderr @@ -1,69 +1,69 @@ error: immediately dereferencing a reference - --> $DIR/reference.rs:19:13 + --> $DIR/reference.rs:29:13 | -19 | let b = *&a; +29 | let b = *&a; | ^^^ help: try this: `a` | = note: `-D clippy::deref-addrof` implied by `-D warnings` error: immediately dereferencing a reference - --> $DIR/reference.rs:21:13 + --> $DIR/reference.rs:31:13 | -21 | let b = *&get_number(); +31 | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try this: `get_number()` error: immediately dereferencing a reference - --> $DIR/reference.rs:26:13 + --> $DIR/reference.rs:36:13 | -26 | let b = *&bytes[1..2][0]; +36 | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` error: immediately dereferencing a reference - --> $DIR/reference.rs:30:13 + --> $DIR/reference.rs:40:13 | -30 | let b = *&(a); +40 | let b = *&(a); | ^^^^^ help: try this: `(a)` error: immediately dereferencing a reference - --> $DIR/reference.rs:32:13 + --> $DIR/reference.rs:42:13 | -32 | let b = *(&a); +42 | let b = *(&a); | ^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/reference.rs:34:13 + --> $DIR/reference.rs:44:13 | -34 | let b = *((&a)); +44 | let b = *((&a)); | ^^^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/reference.rs:36:13 + --> $DIR/reference.rs:46:13 | -36 | let b = *&&a; +46 | let b = *&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/reference.rs:38:14 + --> $DIR/reference.rs:48:14 | -38 | let b = **&aref; +48 | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/reference.rs:42:14 + --> $DIR/reference.rs:52:14 | -42 | let b = **&&a; +52 | let b = **&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/reference.rs:46:17 + --> $DIR/reference.rs:56:17 | -46 | let y = *&mut x; +56 | let y = *&mut x; | ^^^^^^^ help: try this: `x` error: immediately dereferencing a reference - --> $DIR/reference.rs:53:18 + --> $DIR/reference.rs:63:18 | -53 | let y = **&mut &mut x; +63 | let y = **&mut &mut x; | ^^^^^^^^^^^^ help: try this: `&mut x` error: aborting due to 11 previous errors diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index e3837e104f4..6e77c589023 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index fd8fecb1139..1da859dea5c 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -1,168 +1,168 @@ error: trivial regex - --> $DIR/regex.rs:16:45 + --> $DIR/regex.rs:26:45 | -16 | let pipe_in_wrong_position = Regex::new("|"); +26 | let pipe_in_wrong_position = Regex::new("|"); | ^^^ | = note: `-D clippy::trivial-regex` implied by `-D warnings` = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:17:60 + --> $DIR/regex.rs:27:60 | -17 | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); +27 | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); | ^^^ | = help: the regex is unlikely to be useful as it is error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:18:42 + --> $DIR/regex.rs:28:42 | -18 | let wrong_char_ranice = Regex::new("[z-a]"); +28 | let wrong_char_ranice = Regex::new("[z-a]"); | ^^^ | = note: `-D clippy::invalid-regex` implied by `-D warnings` error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:19:37 + --> $DIR/regex.rs:29:37 | -19 | let some_unicode = Regex::new("[é-è]"); +29 | let some_unicode = Regex::new("[é-è]"); | ^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:21:33 + --> $DIR/regex.rs:31:33 | -21 | let some_regex = Regex::new(OPENING_PAREN); +31 | let some_regex = Regex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: trivial regex - --> $DIR/regex.rs:23:53 + --> $DIR/regex.rs:33:53 | -23 | let binary_pipe_in_wrong_position = BRegex::new("|"); +33 | let binary_pipe_in_wrong_position = BRegex::new("|"); | ^^^ | = help: the regex is unlikely to be useful as it is error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:24:41 + --> $DIR/regex.rs:34:41 | -24 | let some_binary_regex = BRegex::new(OPENING_PAREN); +34 | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:25:56 + --> $DIR/regex.rs:35:56 | -25 | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); +35 | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:41:9 + --> $DIR/regex.rs:51:9 | -41 | OPENING_PAREN, +51 | OPENING_PAREN, | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:45:9 + --> $DIR/regex.rs:55:9 | -45 | OPENING_PAREN, +55 | OPENING_PAREN, | ^^^^^^^^^^^^^ error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:49:45 + --> $DIR/regex.rs:59:45 | -49 | let raw_string_error = Regex::new(r"[...//...]"); +59 | let raw_string_error = Regex::new(r"[...//...]"); | ^^ error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:50:46 + --> $DIR/regex.rs:60:46 | -50 | let raw_string_error = Regex::new(r#"[...//...]"#); +60 | let raw_string_error = Regex::new(r#"[...//...]"#); | ^^ error: trivial regex - --> $DIR/regex.rs:54:33 + --> $DIR/regex.rs:64:33 | -54 | let trivial_eq = Regex::new("^foobar$"); +64 | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ | = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:56:48 + --> $DIR/regex.rs:66:48 | -56 | let trivial_eq_builder = RegexBuilder::new("^foobar$"); +66 | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ | = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:58:42 + --> $DIR/regex.rs:68:42 | -58 | let trivial_starts_with = Regex::new("^foobar"); +68 | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ | = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:60:40 + --> $DIR/regex.rs:70:40 | -60 | let trivial_ends_with = Regex::new("foobar$"); +70 | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ | = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:62:39 + --> $DIR/regex.rs:72:39 | -62 | let trivial_contains = Regex::new("foobar"); +72 | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ | = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:64:39 + --> $DIR/regex.rs:74:39 | -64 | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); +74 | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ | = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:66:40 + --> $DIR/regex.rs:76:40 | -66 | let trivial_backslash = Regex::new("a/.b"); +76 | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ | = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:69:36 + --> $DIR/regex.rs:79:36 | -69 | let trivial_empty = Regex::new(""); +79 | let trivial_empty = Regex::new(""); | ^^ | = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:71:36 + --> $DIR/regex.rs:81:36 | -71 | let trivial_empty = Regex::new("^"); +81 | let trivial_empty = Regex::new("^"); | ^^^ | = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:73:36 + --> $DIR/regex.rs:83:36 | -73 | let trivial_empty = Regex::new("^$"); +83 | let trivial_empty = Regex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:75:44 + --> $DIR/regex.rs:85:44 | -75 | let binary_trivial_empty = BRegex::new("^$"); +85 | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` diff --git a/tests/ui/replace_consts.rs b/tests/ui/replace_consts.rs index 8420b368d3d..2f961e86f9a 100644 --- a/tests/ui/replace_consts.rs +++ b/tests/ui/replace_consts.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(integer_atomics)] diff --git a/tests/ui/replace_consts.stderr b/tests/ui/replace_consts.stderr index fb9c9414c85..02100b4194d 100644 --- a/tests/ui/replace_consts.stderr +++ b/tests/ui/replace_consts.stderr @@ -1,217 +1,217 @@ error: using `ATOMIC_BOOL_INIT` - --> $DIR/replace_consts.rs:14:17 + --> $DIR/replace_consts.rs:24:17 | -14 | { let foo = ATOMIC_BOOL_INIT; }; +24 | { let foo = ATOMIC_BOOL_INIT; }; | ^^^^^^^^^^^^^^^^ help: try this: `AtomicBool::new(false)` | note: lint level defined here - --> $DIR/replace_consts.rs:5:9 + --> $DIR/replace_consts.rs:15:9 | -5 | #![deny(clippy::replace_consts)] +15 | #![deny(clippy::replace_consts)] | ^^^^^^^^^^^^^^^^^^^^^^ error: using `ATOMIC_ISIZE_INIT` - --> $DIR/replace_consts.rs:15:17 + --> $DIR/replace_consts.rs:25:17 | -15 | { let foo = ATOMIC_ISIZE_INIT; }; +25 | { let foo = ATOMIC_ISIZE_INIT; }; | ^^^^^^^^^^^^^^^^^ help: try this: `AtomicIsize::new(0)` error: using `ATOMIC_I8_INIT` - --> $DIR/replace_consts.rs:16:17 + --> $DIR/replace_consts.rs:26:17 | -16 | { let foo = ATOMIC_I8_INIT; }; +26 | { let foo = ATOMIC_I8_INIT; }; | ^^^^^^^^^^^^^^ help: try this: `AtomicI8::new(0)` error: using `ATOMIC_I16_INIT` - --> $DIR/replace_consts.rs:17:17 + --> $DIR/replace_consts.rs:27:17 | -17 | { let foo = ATOMIC_I16_INIT; }; +27 | { let foo = ATOMIC_I16_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI16::new(0)` error: using `ATOMIC_I32_INIT` - --> $DIR/replace_consts.rs:18:17 + --> $DIR/replace_consts.rs:28:17 | -18 | { let foo = ATOMIC_I32_INIT; }; +28 | { let foo = ATOMIC_I32_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI32::new(0)` error: using `ATOMIC_I64_INIT` - --> $DIR/replace_consts.rs:19:17 + --> $DIR/replace_consts.rs:29:17 | -19 | { let foo = ATOMIC_I64_INIT; }; +29 | { let foo = ATOMIC_I64_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI64::new(0)` error: using `ATOMIC_USIZE_INIT` - --> $DIR/replace_consts.rs:20:17 + --> $DIR/replace_consts.rs:30:17 | -20 | { let foo = ATOMIC_USIZE_INIT; }; +30 | { let foo = ATOMIC_USIZE_INIT; }; | ^^^^^^^^^^^^^^^^^ help: try this: `AtomicUsize::new(0)` error: using `ATOMIC_U8_INIT` - --> $DIR/replace_consts.rs:21:17 + --> $DIR/replace_consts.rs:31:17 | -21 | { let foo = ATOMIC_U8_INIT; }; +31 | { let foo = ATOMIC_U8_INIT; }; | ^^^^^^^^^^^^^^ help: try this: `AtomicU8::new(0)` error: using `ATOMIC_U16_INIT` - --> $DIR/replace_consts.rs:22:17 + --> $DIR/replace_consts.rs:32:17 | -22 | { let foo = ATOMIC_U16_INIT; }; +32 | { let foo = ATOMIC_U16_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU16::new(0)` error: using `ATOMIC_U32_INIT` - --> $DIR/replace_consts.rs:23:17 + --> $DIR/replace_consts.rs:33:17 | -23 | { let foo = ATOMIC_U32_INIT; }; +33 | { let foo = ATOMIC_U32_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU32::new(0)` error: using `ATOMIC_U64_INIT` - --> $DIR/replace_consts.rs:24:17 + --> $DIR/replace_consts.rs:34:17 | -24 | { let foo = ATOMIC_U64_INIT; }; +34 | { let foo = ATOMIC_U64_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU64::new(0)` error: using `MIN` - --> $DIR/replace_consts.rs:26:17 + --> $DIR/replace_consts.rs:36:17 | -26 | { let foo = std::isize::MIN; }; +36 | { let foo = std::isize::MIN; }; | ^^^^^^^^^^^^^^^ help: try this: `isize::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:27:17 + --> $DIR/replace_consts.rs:37:17 | -27 | { let foo = std::i8::MIN; }; +37 | { let foo = std::i8::MIN; }; | ^^^^^^^^^^^^ help: try this: `i8::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:28:17 + --> $DIR/replace_consts.rs:38:17 | -28 | { let foo = std::i16::MIN; }; +38 | { let foo = std::i16::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i16::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:29:17 + --> $DIR/replace_consts.rs:39:17 | -29 | { let foo = std::i32::MIN; }; +39 | { let foo = std::i32::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i32::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:30:17 + --> $DIR/replace_consts.rs:40:17 | -30 | { let foo = std::i64::MIN; }; +40 | { let foo = std::i64::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i64::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:31:17 + --> $DIR/replace_consts.rs:41:17 | -31 | { let foo = std::i128::MIN; }; +41 | { let foo = std::i128::MIN; }; | ^^^^^^^^^^^^^^ help: try this: `i128::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:32:17 + --> $DIR/replace_consts.rs:42:17 | -32 | { let foo = std::usize::MIN; }; +42 | { let foo = std::usize::MIN; }; | ^^^^^^^^^^^^^^^ help: try this: `usize::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:33:17 + --> $DIR/replace_consts.rs:43:17 | -33 | { let foo = std::u8::MIN; }; +43 | { let foo = std::u8::MIN; }; | ^^^^^^^^^^^^ help: try this: `u8::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:34:17 + --> $DIR/replace_consts.rs:44:17 | -34 | { let foo = std::u16::MIN; }; +44 | { let foo = std::u16::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u16::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:35:17 + --> $DIR/replace_consts.rs:45:17 | -35 | { let foo = std::u32::MIN; }; +45 | { let foo = std::u32::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u32::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:36:17 + --> $DIR/replace_consts.rs:46:17 | -36 | { let foo = std::u64::MIN; }; +46 | { let foo = std::u64::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u64::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:37:17 + --> $DIR/replace_consts.rs:47:17 | -37 | { let foo = std::u128::MIN; }; +47 | { let foo = std::u128::MIN; }; | ^^^^^^^^^^^^^^ help: try this: `u128::min_value()` error: using `MAX` - --> $DIR/replace_consts.rs:39:17 + --> $DIR/replace_consts.rs:49:17 | -39 | { let foo = std::isize::MAX; }; +49 | { let foo = std::isize::MAX; }; | ^^^^^^^^^^^^^^^ help: try this: `isize::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:40:17 + --> $DIR/replace_consts.rs:50:17 | -40 | { let foo = std::i8::MAX; }; +50 | { let foo = std::i8::MAX; }; | ^^^^^^^^^^^^ help: try this: `i8::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:41:17 + --> $DIR/replace_consts.rs:51:17 | -41 | { let foo = std::i16::MAX; }; +51 | { let foo = std::i16::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i16::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:42:17 + --> $DIR/replace_consts.rs:52:17 | -42 | { let foo = std::i32::MAX; }; +52 | { let foo = std::i32::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i32::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:43:17 + --> $DIR/replace_consts.rs:53:17 | -43 | { let foo = std::i64::MAX; }; +53 | { let foo = std::i64::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i64::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:44:17 + --> $DIR/replace_consts.rs:54:17 | -44 | { let foo = std::i128::MAX; }; +54 | { let foo = std::i128::MAX; }; | ^^^^^^^^^^^^^^ help: try this: `i128::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:45:17 + --> $DIR/replace_consts.rs:55:17 | -45 | { let foo = std::usize::MAX; }; +55 | { let foo = std::usize::MAX; }; | ^^^^^^^^^^^^^^^ help: try this: `usize::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:46:17 + --> $DIR/replace_consts.rs:56:17 | -46 | { let foo = std::u8::MAX; }; +56 | { let foo = std::u8::MAX; }; | ^^^^^^^^^^^^ help: try this: `u8::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:47:17 + --> $DIR/replace_consts.rs:57:17 | -47 | { let foo = std::u16::MAX; }; +57 | { let foo = std::u16::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u16::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:48:17 + --> $DIR/replace_consts.rs:58:17 | -48 | { let foo = std::u32::MAX; }; +58 | { let foo = std::u32::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u32::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:49:17 + --> $DIR/replace_consts.rs:59:17 | -49 | { let foo = std::u64::MAX; }; +59 | { let foo = std::u64::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u64::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:50:17 + --> $DIR/replace_consts.rs:60:17 | -50 | { let foo = std::u128::MAX; }; +60 | { let foo = std::u128::MAX; }; | ^^^^^^^^^^^^^^ help: try this: `u128::max_value()` error: aborting due to 35 previous errors diff --git a/tests/ui/result_map_unit_fn.rs b/tests/ui/result_map_unit_fn.rs index 8cac6a9c827..4edbfdd5bf4 100644 --- a/tests/ui/result_map_unit_fn.rs +++ b/tests/ui/result_map_unit_fn.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(never_type)] diff --git a/tests/ui/result_map_unit_fn.stderr b/tests/ui/result_map_unit_fn.stderr index 5fba1a0d7ad..04f105c78e2 100644 --- a/tests/ui/result_map_unit_fn.stderr +++ b/tests/ui/result_map_unit_fn.stderr @@ -1,7 +1,7 @@ error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:35:5 + --> $DIR/result_map_unit_fn.rs:45:5 | -35 | x.field.map(do_nothing); +45 | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(x_field) = x.field { do_nothing(...) }` @@ -9,183 +9,183 @@ error: called `map(f)` on an Result value where `f` is a unit function = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:37:5 + --> $DIR/result_map_unit_fn.rs:47:5 | -37 | x.field.map(do_nothing); +47 | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(x_field) = x.field { do_nothing(...) }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:39:5 + --> $DIR/result_map_unit_fn.rs:49:5 | -39 | x.field.map(diverge); +49 | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(x_field) = x.field { diverge(...) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:45:5 + --> $DIR/result_map_unit_fn.rs:55:5 | -45 | x.field.map(|value| x.do_result_nothing(value + captured)); +55 | x.field.map(|value| x.do_result_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:47:5 + --> $DIR/result_map_unit_fn.rs:57:5 | -47 | x.field.map(|value| { x.do_result_plus_one(value + captured); }); +57 | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:50:5 + --> $DIR/result_map_unit_fn.rs:60:5 | -50 | x.field.map(|value| do_nothing(value + captured)); +60 | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:52:5 + --> $DIR/result_map_unit_fn.rs:62:5 | -52 | x.field.map(|value| { do_nothing(value + captured) }); +62 | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:54:5 + --> $DIR/result_map_unit_fn.rs:64:5 | -54 | x.field.map(|value| { do_nothing(value + captured); }); +64 | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:56:5 + --> $DIR/result_map_unit_fn.rs:66:5 | -56 | x.field.map(|value| { { do_nothing(value + captured); } }); +66 | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:59:5 + --> $DIR/result_map_unit_fn.rs:69:5 | -59 | x.field.map(|value| diverge(value + captured)); +69 | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:61:5 + --> $DIR/result_map_unit_fn.rs:71:5 | -61 | x.field.map(|value| { diverge(value + captured) }); +71 | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:63:5 + --> $DIR/result_map_unit_fn.rs:73:5 | -63 | x.field.map(|value| { diverge(value + captured); }); +73 | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:65:5 + --> $DIR/result_map_unit_fn.rs:75:5 | -65 | x.field.map(|value| { { diverge(value + captured); } }); +75 | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:70:5 + --> $DIR/result_map_unit_fn.rs:80:5 | -70 | x.field.map(|value| { let y = plus_one(value + captured); }); +80 | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:72:5 + --> $DIR/result_map_unit_fn.rs:82:5 | -72 | x.field.map(|value| { plus_one(value + captured); }); +82 | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:74:5 + --> $DIR/result_map_unit_fn.rs:84:5 | -74 | x.field.map(|value| { { plus_one(value + captured); } }); +84 | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:77:5 + --> $DIR/result_map_unit_fn.rs:87:5 | -77 | x.field.map(|ref value| { do_nothing(value + captured) }); +87 | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:80:5 + --> $DIR/result_map_unit_fn.rs:90:5 | -80 | x.field.map(|value| { do_nothing(value); do_nothing(value) }); +90 | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:82:5 + --> $DIR/result_map_unit_fn.rs:92:5 | -82 | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); +92 | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:86:5 + --> $DIR/result_map_unit_fn.rs:96:5 | -86 | x.field.map(|value| { +96 | x.field.map(|value| { | _____^ | |_____| | || -87 | || do_nothing(value); -88 | || do_nothing(value) -89 | || }); +97 | || do_nothing(value); +98 | || do_nothing(value) +99 | || }); | ||______^- help: try this: `if let Ok(value) = x.field { ... }` | |_______| | error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:90:5 - | -90 | x.field.map(|value| { do_nothing(value); do_nothing(value); }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Ok(value) = x.field { ... }` + --> $DIR/result_map_unit_fn.rs:100:5 + | +100 | x.field.map(|value| { do_nothing(value); do_nothing(value); }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:94:5 - | -94 | "12".parse::<i32>().map(diverge); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: try this: `if let Ok(_) = "12".parse::<i32>() { diverge(...) }` + --> $DIR/result_map_unit_fn.rs:104:5 + | +104 | "12".parse::<i32>().map(diverge); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try this: `if let Ok(_) = "12".parse::<i32>() { diverge(...) }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:100:5 + --> $DIR/result_map_unit_fn.rs:110:5 | -100 | y.map(do_nothing); +110 | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- | | | help: try this: `if let Ok(_y) = y { do_nothing(...) }` diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index 65c2c344da7..caa954bea44 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::serde_api_misuse)] diff --git a/tests/ui/serde.stderr b/tests/ui/serde.stderr index cce839a0d94..e223430e680 100644 --- a/tests/ui/serde.stderr +++ b/tests/ui/serde.stderr @@ -1,11 +1,11 @@ error: you should not implement `visit_string` without also implementing `visit_str` - --> $DIR/serde.rs:39:5 + --> $DIR/serde.rs:49:5 | -39 | / fn visit_string<E>(self, _v: String) -> Result<Self::Value, E> -40 | | where E: serde::de::Error, -41 | | { -42 | | unimplemented!() -43 | | } +49 | / fn visit_string<E>(self, _v: String) -> Result<Self::Value, E> +50 | | where E: serde::de::Error, +51 | | { +52 | | unimplemented!() +53 | | } | |_____^ | = note: `-D clippy::serde-api-misuse` implied by `-D warnings` diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index c73acf5c5dd..a607161a949 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 311177e25b4..adca299d382 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,137 +1,137 @@ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:13:5 + --> $DIR/shadow.rs:23:5 | -13 | let x = &mut x; +23 | let x = &mut x; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:12:13 + --> $DIR/shadow.rs:22:13 | -12 | let mut x = 1; +22 | let mut x = 1; | ^ error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:14:5 + --> $DIR/shadow.rs:24:5 | -14 | let x = { x }; +24 | let x = { x }; | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:13:9 + --> $DIR/shadow.rs:23:9 | -13 | let x = &mut x; +23 | let x = &mut x; | ^ error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:15:5 + --> $DIR/shadow.rs:25:5 | -15 | let x = (&*x); +25 | let x = (&*x); | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:24:9 | -14 | let x = { x }; +24 | let x = { x }; | ^ error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:16:9 + --> $DIR/shadow.rs:26:9 | -16 | let x = { *x + 1 }; +26 | let x = { *x + 1 }; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:16:13 + --> $DIR/shadow.rs:26:13 | -16 | let x = { *x + 1 }; +26 | let x = { *x + 1 }; | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:25:9 | -15 | let x = (&*x); +25 | let x = (&*x); | ^ error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:27:9 | -17 | let x = id(x); +27 | let x = id(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:17:13 + --> $DIR/shadow.rs:27:13 | -17 | let x = id(x); +27 | let x = id(x); | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:16:9 + --> $DIR/shadow.rs:26:9 | -16 | let x = { *x + 1 }; +26 | let x = { *x + 1 }; | ^ error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:28:9 | -18 | let x = (1, x); +28 | let x = (1, x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:18:13 + --> $DIR/shadow.rs:28:13 | -18 | let x = (1, x); +28 | let x = (1, x); | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:27:9 | -17 | let x = id(x); +27 | let x = id(x); | ^ error: `x` is shadowed by `first(x)` which reuses the original value - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:29:9 | -19 | let x = first(x); +29 | let x = first(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:19:13 + --> $DIR/shadow.rs:29:13 | -19 | let x = first(x); +29 | let x = first(x); | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:28:9 | -18 | let x = (1, x); +28 | let x = (1, x); | ^ error: `x` is shadowed by `y` - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:31:9 | -21 | let x = y; +31 | let x = y; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:21:13 + --> $DIR/shadow.rs:31:13 | -21 | let x = y; +31 | let x = y; | ^ note: previous binding is here - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:29:9 | -19 | let x = first(x); +29 | let x = first(x); | ^ error: `x` shadows a previous declaration - --> $DIR/shadow.rs:23:5 + --> $DIR/shadow.rs:33:5 | -23 | let x; +33 | let x; | ^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:31:9 | -21 | let x = y; +31 | let x = y; | ^ error: aborting due to 9 previous errors diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index e9cb8e4ad8c..01511314c7d 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/short_circuit_statement.stderr b/tests/ui/short_circuit_statement.stderr index bef497c33a0..331bdac3128 100644 --- a/tests/ui/short_circuit_statement.stderr +++ b/tests/ui/short_circuit_statement.stderr @@ -1,22 +1,22 @@ error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:7:5 - | -7 | f() && g(); - | ^^^^^^^^^^^ help: replace it with: `if f() { g(); }` - | - = note: `-D clippy::short-circuit-statement` implied by `-D warnings` + --> $DIR/short_circuit_statement.rs:17:5 + | +17 | f() && g(); + | ^^^^^^^^^^^ help: replace it with: `if f() { g(); }` + | + = note: `-D clippy::short-circuit-statement` implied by `-D warnings` error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:8:5 - | -8 | f() || g(); - | ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }` + --> $DIR/short_circuit_statement.rs:18:5 + | +18 | f() || g(); + | ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:9:5 - | -9 | 1 == 2 || g(); - | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` + --> $DIR/short_circuit_statement.rs:19:5 + | +19 | 1 == 2 || g(); + | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` error: aborting due to 3 previous errors diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index c4e88e9ee2b..12aaa69f34b 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] use std::collections::HashSet; diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 78355612717..ff657df1bf8 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -1,123 +1,123 @@ error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:7:13 - | -7 | x.split("x"); - | ^^^ help: try using a char instead: `'x'` - | - = note: `-D clippy::single-char-pattern` implied by `-D warnings` + --> $DIR/single_char_pattern.rs:17:13 + | +17 | x.split("x"); + | ^^^ help: try using a char instead: `'x'` + | + = note: `-D clippy::single-char-pattern` implied by `-D warnings` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:24:16 + --> $DIR/single_char_pattern.rs:34:16 | -24 | x.contains("x"); +34 | x.contains("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:25:19 + --> $DIR/single_char_pattern.rs:35:19 | -25 | x.starts_with("x"); +35 | x.starts_with("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:26:17 + --> $DIR/single_char_pattern.rs:36:17 | -26 | x.ends_with("x"); +36 | x.ends_with("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:27:12 + --> $DIR/single_char_pattern.rs:37:12 | -27 | x.find("x"); +37 | x.find("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:28:13 + --> $DIR/single_char_pattern.rs:38:13 | -28 | x.rfind("x"); +38 | x.rfind("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:29:14 + --> $DIR/single_char_pattern.rs:39:14 | -29 | x.rsplit("x"); +39 | x.rsplit("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:30:24 + --> $DIR/single_char_pattern.rs:40:24 | -30 | x.split_terminator("x"); +40 | x.split_terminator("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:31:25 + --> $DIR/single_char_pattern.rs:41:25 | -31 | x.rsplit_terminator("x"); +41 | x.rsplit_terminator("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:32:17 + --> $DIR/single_char_pattern.rs:42:17 | -32 | x.splitn(0, "x"); +42 | x.splitn(0, "x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:33:18 + --> $DIR/single_char_pattern.rs:43:18 | -33 | x.rsplitn(0, "x"); +43 | x.rsplitn(0, "x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:34:15 + --> $DIR/single_char_pattern.rs:44:15 | -34 | x.matches("x"); +44 | x.matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:35:16 + --> $DIR/single_char_pattern.rs:45:16 | -35 | x.rmatches("x"); +45 | x.rmatches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:36:21 + --> $DIR/single_char_pattern.rs:46:21 | -36 | x.match_indices("x"); +46 | x.match_indices("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:22 + --> $DIR/single_char_pattern.rs:47:22 | -37 | x.rmatch_indices("x"); +47 | x.rmatch_indices("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:38:25 + --> $DIR/single_char_pattern.rs:48:25 | -38 | x.trim_left_matches("x"); +48 | x.trim_left_matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:26 + --> $DIR/single_char_pattern.rs:49:26 | -39 | x.trim_right_matches("x"); +49 | x.trim_right_matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:41:13 + --> $DIR/single_char_pattern.rs:51:13 | -41 | x.split("/n"); +51 | x.split("/n"); | ^^^^ help: try using a char instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:46:31 + --> $DIR/single_char_pattern.rs:56:31 | -46 | x.replace(";", ",").split(","); // issue #2978 +56 | x.replace(";", ",").split(","); // issue #2978 | ^^^ help: try using a char instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:47:19 + --> $DIR/single_char_pattern.rs:57:19 | -47 | x.starts_with("/x03"); // issue #2996 +57 | x.starts_with("/x03"); // issue #2996 | ^^^^^^ help: try using a char instead: `'/x03'` error: aborting due to 20 previous errors diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index c0c82adafb5..07c1a95025a 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::single_match)] diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 20d8fed25fd..74448391ca5 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,48 +1,48 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:11:5 + --> $DIR/single_match.rs:21:5 | -11 | / match x { -12 | | Some(y) => { println!("{:?}", y); } -13 | | _ => () -14 | | }; +21 | / match x { +22 | | Some(y) => { println!("{:?}", y); } +23 | | _ => () +24 | | }; | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y); }` | = note: `-D clippy::single-match` implied by `-D warnings` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:17:5 + --> $DIR/single_match.rs:27:5 | -17 | / match z { -18 | | (2...3, 7...9) => dummy(), -19 | | _ => {} -20 | | }; +27 | / match z { +28 | | (2...3, 7...9) => dummy(), +29 | | _ => {} +30 | | }; | |_____^ help: try this: `if let (2...3, 7...9) = z { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:43:5 + --> $DIR/single_match.rs:53:5 | -43 | / match x { -44 | | Some(y) => dummy(), -45 | | None => () -46 | | }; +53 | / match x { +54 | | Some(y) => dummy(), +55 | | None => () +56 | | }; | |_____^ help: try this: `if let Some(y) = x { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:48:5 + --> $DIR/single_match.rs:58:5 | -48 | / match y { -49 | | Ok(y) => dummy(), -50 | | Err(..) => () -51 | | }; +58 | / match y { +59 | | Ok(y) => dummy(), +60 | | Err(..) => () +61 | | }; | |_____^ help: try this: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:55:5 + --> $DIR/single_match.rs:65:5 | -55 | / match c { -56 | | Cow::Borrowed(..) => dummy(), -57 | | Cow::Owned(..) => (), -58 | | }; +65 | / match c { +66 | | Cow::Borrowed(..) => dummy(), +67 | | Cow::Owned(..) => (), +68 | | }; | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` error: aborting due to 5 previous errors diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index adea56cf9a2..180924d2c9c 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(dead_code)] diff --git a/tests/ui/starts_ends_with.stderr b/tests/ui/starts_ends_with.stderr index b3fb444b562..9921819e093 100644 --- a/tests/ui/starts_ends_with.stderr +++ b/tests/ui/starts_ends_with.stderr @@ -1,77 +1,77 @@ error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:9:5 - | -9 | "".chars().next() == Some(' '); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')` - | - = note: `-D clippy::chars-next-cmp` implied by `-D warnings` + --> $DIR/starts_ends_with.rs:19:5 + | +19 | "".chars().next() == Some(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')` + | + = note: `-D clippy::chars-next-cmp` implied by `-D warnings` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:10:5 + --> $DIR/starts_ends_with.rs:20:5 | -10 | Some(' ') != "".chars().next(); +20 | Some(' ') != "".chars().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:15:8 + --> $DIR/starts_ends_with.rs:25:8 | -15 | if s.chars().next().unwrap() == 'f' { // s.starts_with('f') +25 | if s.chars().next().unwrap() == 'f' { // s.starts_with('f') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:18:8 + --> $DIR/starts_ends_with.rs:28:8 | -18 | if s.chars().next_back().unwrap() == 'o' { // s.ends_with('o') +28 | if s.chars().next_back().unwrap() == 'o' { // s.ends_with('o') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` | = note: `-D clippy::chars-last-cmp` implied by `-D warnings` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:21:8 + --> $DIR/starts_ends_with.rs:31:8 | -21 | if s.chars().last().unwrap() == 'o' { // s.ends_with('o') +31 | if s.chars().last().unwrap() == 'o' { // s.ends_with('o') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:24:8 + --> $DIR/starts_ends_with.rs:34:8 | -24 | if s.chars().next().unwrap() != 'f' { // !s.starts_with('f') +34 | if s.chars().next().unwrap() != 'f' { // !s.starts_with('f') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:27:8 + --> $DIR/starts_ends_with.rs:37:8 | -27 | if s.chars().next_back().unwrap() != 'o' { // !s.ends_with('o') +37 | if s.chars().next_back().unwrap() != 'o' { // !s.ends_with('o') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:30:8 + --> $DIR/starts_ends_with.rs:40:8 | -30 | if s.chars().last().unwrap() != 'o' { // !s.ends_with('o') +40 | if s.chars().last().unwrap() != 'o' { // !s.ends_with('o') | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:37:5 + --> $DIR/starts_ends_with.rs:47:5 | -37 | "".chars().last() == Some(' '); +47 | "".chars().last() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:38:5 + --> $DIR/starts_ends_with.rs:48:5 | -38 | Some(' ') != "".chars().last(); +48 | Some(' ') != "".chars().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:39:5 + --> $DIR/starts_ends_with.rs:49:5 | -39 | "".chars().next_back() == Some(' '); +49 | "".chars().next_back() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:40:5 + --> $DIR/starts_ends_with.rs:50:5 | -40 | Some(' ') != "".chars().next_back(); +50 | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: aborting due to 12 previous errors diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index d99adb19f89..a0cf9c46906 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #[derive(Copy, Clone)] struct HasChars; diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index 32e3482699c..2a82972a3cd 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -1,21 +1,21 @@ error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:16:5 + --> $DIR/string_extend.rs:26:5 | -16 | s.extend(abc.chars()); +26 | s.extend(abc.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` | = note: `-D clippy::string-extend-chars` implied by `-D warnings` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:19:5 + --> $DIR/string_extend.rs:29:5 | -19 | s.extend("abc".chars()); +29 | s.extend("abc".chars()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:22:5 + --> $DIR/string_extend.rs:32:5 | -22 | s.extend(def.chars()); +32 | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` error: aborting due to 3 previous errors diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 86819e3fd5c..31e6c9a059f 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index 258920e2652..bcdf91568d2 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -1,75 +1,75 @@ error: manual implementation of an assign operation - --> $DIR/strings.rs:10:9 + --> $DIR/strings.rs:20:9 | -10 | x = x + "."; +20 | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` | = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:10:13 + --> $DIR/strings.rs:20:13 | -10 | x = x + "."; +20 | x = x + "."; | ^^^^^^^ | = note: `-D clippy::string-add` implied by `-D warnings` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:14:13 + --> $DIR/strings.rs:24:13 | -14 | let z = y + "..."; +24 | let z = y + "..."; | ^^^^^^^^^ error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:24:9 + --> $DIR/strings.rs:34:9 | -24 | x = x + "."; +34 | x = x + "."; | ^^^^^^^^^^^ | = note: `-D clippy::string-add-assign` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/strings.rs:24:9 + --> $DIR/strings.rs:34:9 | -24 | x = x + "."; +34 | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:38:9 + --> $DIR/strings.rs:48:9 | -38 | x = x + "."; +48 | x = x + "."; | ^^^^^^^^^^^ error: manual implementation of an assign operation - --> $DIR/strings.rs:38:9 + --> $DIR/strings.rs:48:9 | -38 | x = x + "."; +48 | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:42:13 + --> $DIR/strings.rs:52:13 | -42 | let z = y + "..."; +52 | let z = y + "..."; | ^^^^^^^^^ error: calling `as_bytes()` on a string literal - --> $DIR/strings.rs:50:14 + --> $DIR/strings.rs:60:14 | -50 | let bs = "hello there".as_bytes(); +60 | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` | = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` error: calling `as_bytes()` on a string literal - --> $DIR/strings.rs:55:18 + --> $DIR/strings.rs:65:18 | -55 | let strify = stringify!(foobar).as_bytes(); +65 | let strify = stringify!(foobar).as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `bstringify!(foobar)` error: manual implementation of an assign operation - --> $DIR/strings.rs:65:7 + --> $DIR/strings.rs:75:7 | -65 | ; x = x + 1; +75 | ; x = x + 1; | ^^^^^^^^^ help: replace it with: `x += 1` error: aborting due to 11 previous errors diff --git a/tests/ui/stutter.rs b/tests/ui/stutter.rs index de67bb1aff5..148e8071ce0 100644 --- a/tests/ui/stutter.rs +++ b/tests/ui/stutter.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::stutter)] diff --git a/tests/ui/stutter.stderr b/tests/ui/stutter.stderr index 3cc0be39567..2ff992fccf6 100644 --- a/tests/ui/stutter.stderr +++ b/tests/ui/stutter.stderr @@ -1,33 +1,33 @@ error: item name starts with its containing module's name - --> $DIR/stutter.rs:8:5 - | -8 | pub fn foo_bar() {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::stutter` implied by `-D warnings` + --> $DIR/stutter.rs:18:5 + | +18 | pub fn foo_bar() {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::stutter` implied by `-D warnings` error: item name ends with its containing module's name - --> $DIR/stutter.rs:9:5 - | -9 | pub fn bar_foo() {} - | ^^^^^^^^^^^^^^^^^^^ + --> $DIR/stutter.rs:19:5 + | +19 | pub fn bar_foo() {} + | ^^^^^^^^^^^^^^^^^^^ error: item name starts with its containing module's name - --> $DIR/stutter.rs:10:5 + --> $DIR/stutter.rs:20:5 | -10 | pub struct FooCake {} +20 | pub struct FooCake {} | ^^^^^^^^^^^^^^^^^^^^^ error: item name ends with its containing module's name - --> $DIR/stutter.rs:11:5 + --> $DIR/stutter.rs:21:5 | -11 | pub enum CakeFoo {} +21 | pub enum CakeFoo {} | ^^^^^^^^^^^^^^^^^^^ error: item name starts with its containing module's name - --> $DIR/stutter.rs:12:5 + --> $DIR/stutter.rs:22:5 | -12 | pub struct Foo7Bar; +22 | pub struct Foo7Bar; | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs index 04e235c690b..a183576b40e 100644 --- a/tests/ui/suspicious_arithmetic_impl.rs +++ b/tests/ui/suspicious_arithmetic_impl.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr index 0f396c3a560..64070cce3a8 100644 --- a/tests/ui/suspicious_arithmetic_impl.stderr +++ b/tests/ui/suspicious_arithmetic_impl.stderr @@ -1,15 +1,15 @@ error: Suspicious use of binary operator in `Add` impl - --> $DIR/suspicious_arithmetic_impl.rs:14:20 + --> $DIR/suspicious_arithmetic_impl.rs:24:20 | -14 | Foo(self.0 - other.0) +24 | Foo(self.0 - other.0) | ^ | = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` error: Suspicious use of binary operator in `AddAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:20:23 + --> $DIR/suspicious_arithmetic_impl.rs:30:23 | -20 | *self = *self - other; +30 | *self = *self - other; | ^ | = note: #[deny(clippy::suspicious_op_assign_impl)] on by default diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 377319e8faa..bef2031f8a8 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 67d4fd8a14b..7a4fbdad791 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,66 +1,66 @@ error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:11:5 + --> $DIR/swap.rs:21:5 | -11 | / let temp = foo[0]; -12 | | foo[0] = foo[1]; -13 | | foo[1] = temp; +21 | / let temp = foo[0]; +22 | | foo[0] = foo[1]; +23 | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` | = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:20:5 + --> $DIR/swap.rs:30:5 | -20 | / let temp = foo[0]; -21 | | foo[0] = foo[1]; -22 | | foo[1] = temp; +30 | / let temp = foo[0]; +31 | | foo[0] = foo[1]; +32 | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:29:5 + --> $DIR/swap.rs:39:5 | -29 | / let temp = foo[0]; -30 | | foo[0] = foo[1]; -31 | | foo[1] = temp; +39 | / let temp = foo[0]; +40 | | foo[0] = foo[1]; +41 | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:47:7 + --> $DIR/swap.rs:57:7 | -47 | ; let t = a; +57 | ; let t = a; | _______^ -48 | | a = b; -49 | | b = t; +58 | | a = b; +59 | | b = t; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:56:7 + --> $DIR/swap.rs:66:7 | -56 | ; let t = c.0; +66 | ; let t = c.0; | _______^ -57 | | c.0 = a; -58 | | a = t; +67 | | c.0 = a; +68 | | a = t; | |_________^ help: try: `std::mem::swap(&mut c.0, &mut a)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:44:5 + --> $DIR/swap.rs:54:5 | -44 | / a = b; -45 | | b = a; +54 | / a = b; +55 | | b = a; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | = note: `-D clippy::almost-swapped` implied by `-D warnings` = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:53:5 + --> $DIR/swap.rs:63:5 | -53 | / c.0 = a; -54 | | a = c.0; +63 | / c.0 = a; +64 | | a = c.0; | |___________^ help: try: `std::mem::swap(&mut c.0, &mut a)` | = note: or maybe you should use `std::mem::replace`? diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index 1d0cffcfc0a..cf92f9fd6c2 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 38379d8bd20..17b1ca1251a 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -1,15 +1,15 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:29:5 + --> $DIR/temporary_assignment.rs:39:5 | -29 | Struct { field: 0 }.field = 1; +39 | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:30:5 + --> $DIR/temporary_assignment.rs:40:5 | -30 | (0, 0).0 = 1; +40 | (0, 0).0 = 1; | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 86eb7fa5565..9f92d706ad6 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index f3fe563f294..edde5510e2a 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -1,33 +1,33 @@ error: `ref` directly on a function argument is ignored. Consider using a reference type instead. - --> $DIR/toplevel_ref_arg.rs:7:15 - | -7 | fn the_answer(ref mut x: u8) { - | ^^^^^^^^^ - | - = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` + --> $DIR/toplevel_ref_arg.rs:17:15 + | +17 | fn the_answer(ref mut x: u8) { + | ^^^^^^^^^ + | + = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:18:7 + --> $DIR/toplevel_ref_arg.rs:28:7 | -18 | let ref x = 1; +28 | let ref x = 1; | ----^^^^^----- help: try: `let x = &1;` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:20:7 + --> $DIR/toplevel_ref_arg.rs:30:7 | -20 | let ref y: (&_, u8) = (&1, 2); +30 | let ref y: (&_, u8) = (&1, 2); | ----^^^^^--------------------- help: try: `let y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:22:7 + --> $DIR/toplevel_ref_arg.rs:32:7 | -22 | let ref z = 1 + 2; +32 | let ref z = 1 + 2; | ----^^^^^--------- help: try: `let z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:24:7 + --> $DIR/toplevel_ref_arg.rs:34:7 | -24 | let ref mut z = 1 + 2; +34 | let ref mut z = 1 + 2; | ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);` error: aborting due to 5 previous errors diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 58c04d292bc..7ed076225e2 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(stmt_expr_attributes)] #![allow(unused_parens)] diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr index 477f42c28f4..4dbb82b3460 100644 --- a/tests/ui/trailing_zeros.stderr +++ b/tests/ui/trailing_zeros.stderr @@ -1,16 +1,16 @@ error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:7:31 - | -7 | let _ = #[clippy::author] (x & 0b1111 == 0); // suggest trailing_zeros - | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4` - | - = note: `-D clippy::verbose-bit-mask` implied by `-D warnings` + --> $DIR/trailing_zeros.rs:17:31 + | +17 | let _ = #[clippy::author] (x & 0b1111 == 0); // suggest trailing_zeros + | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4` + | + = note: `-D clippy::verbose-bit-mask` implied by `-D warnings` error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:8:13 - | -8 | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros - | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` + --> $DIR/trailing_zeros.rs:18:13 + | +18 | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros + | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` error: aborting due to 2 previous errors diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 34d50da11ca..4108750acf6 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 4340c16b97c..bde43da499f 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -1,245 +1,245 @@ error: transmute from a type (`&'a T`) to itself - --> $DIR/transmute.rs:22:20 + --> $DIR/transmute.rs:32:20 | -22 | let _: &'a T = core::intrinsics::transmute(t); +32 | let _: &'a T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::useless-transmute` implied by `-D warnings` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:26:23 + --> $DIR/transmute.rs:36:23 | -26 | let _: *const T = core::intrinsics::transmute(t); +36 | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:28:21 + --> $DIR/transmute.rs:38:21 | -28 | let _: *mut T = core::intrinsics::transmute(t); +38 | let _: *mut T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:30:23 + --> $DIR/transmute.rs:40:23 | -30 | let _: *const U = core::intrinsics::transmute(t); +40 | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> $DIR/transmute.rs:35:17 + --> $DIR/transmute.rs:45:17 | -35 | let _: &T = std::mem::transmute(p); +45 | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` | = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:38:21 + --> $DIR/transmute.rs:48:21 | -38 | let _: &mut T = std::mem::transmute(m); +48 | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> $DIR/transmute.rs:41:17 + --> $DIR/transmute.rs:51:17 | -41 | let _: &T = std::mem::transmute(m); +51 | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:44:21 + --> $DIR/transmute.rs:54:21 | -44 | let _: &mut T = std::mem::transmute(p as *mut T); +54 | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> $DIR/transmute.rs:47:17 + --> $DIR/transmute.rs:57:17 | -47 | let _: &T = std::mem::transmute(o); +57 | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:50:21 + --> $DIR/transmute.rs:60:21 | -50 | let _: &mut T = std::mem::transmute(om); +60 | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> $DIR/transmute.rs:53:17 + --> $DIR/transmute.rs:63:17 | -53 | let _: &T = std::mem::transmute(om); +63 | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`) - --> $DIR/transmute.rs:64:32 + --> $DIR/transmute.rs:74:32 | -64 | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; +74 | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)` error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`) - --> $DIR/transmute.rs:66:33 + --> $DIR/transmute.rs:76:33 | -66 | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; +76 | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> $DIR/transmute.rs:70:14 + --> $DIR/transmute.rs:80:14 | -70 | unsafe { std::mem::transmute::<_, Bar>(raw) }; +80 | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:76:27 + --> $DIR/transmute.rs:86:27 | -76 | let _: Vec<i32> = core::intrinsics::transmute(my_vec()); +86 | let _: Vec<i32> = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:78:27 + --> $DIR/transmute.rs:88:27 | -78 | let _: Vec<i32> = core::mem::transmute(my_vec()); +88 | let _: Vec<i32> = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:80:27 + --> $DIR/transmute.rs:90:27 | -80 | let _: Vec<i32> = std::intrinsics::transmute(my_vec()); +90 | let _: Vec<i32> = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:82:27 + --> $DIR/transmute.rs:92:27 | -82 | let _: Vec<i32> = std::mem::transmute(my_vec()); +92 | let _: Vec<i32> = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:84:27 + --> $DIR/transmute.rs:94:27 | -84 | let _: Vec<i32> = my_transmute(my_vec()); +94 | let _: Vec<i32> = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> $DIR/transmute.rs:92:31 - | -92 | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` + --> $DIR/transmute.rs:102:31 + | +102 | let _: *const usize = std::mem::transmute(5_isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> $DIR/transmute.rs:96:31 - | -96 | let _: *const usize = std::mem::transmute(1+1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1+1usize) as *const usize` + --> $DIR/transmute.rs:106:31 + | +106 | let _: *const usize = std::mem::transmute(1+1usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1+1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:111:24 + --> $DIR/transmute.rs:121:24 | -111 | let _: Usize = core::intrinsics::transmute(int_const_ptr); +121 | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::crosspointer-transmute` implied by `-D warnings` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:113:24 + --> $DIR/transmute.rs:123:24 | -113 | let _: Usize = core::intrinsics::transmute(int_mut_ptr); +123 | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> $DIR/transmute.rs:115:31 + --> $DIR/transmute.rs:125:31 | -115 | let _: *const Usize = core::intrinsics::transmute(my_int()); +125 | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> $DIR/transmute.rs:117:29 + --> $DIR/transmute.rs:127:29 | -117 | let _: *mut Usize = core::intrinsics::transmute(my_int()); +127 | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:123:28 + --> $DIR/transmute.rs:133:28 | -123 | let _: char = unsafe { std::mem::transmute(0_u32) }; +133 | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` | = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:124:28 + --> $DIR/transmute.rs:134:28 | -124 | let _: char = unsafe { std::mem::transmute(0_i32) }; +134 | let _: char = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:129:28 + --> $DIR/transmute.rs:139:28 | -129 | let _: bool = unsafe { std::mem::transmute(0_u8) }; +139 | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` | = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:134:27 + --> $DIR/transmute.rs:144:27 | -134 | let _: f32 = unsafe { std::mem::transmute(0_u32) }; +144 | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` | = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:135:27 + --> $DIR/transmute.rs:145:27 | -135 | let _: f32 = unsafe { std::mem::transmute(0_i32) }; +145 | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:139:28 + --> $DIR/transmute.rs:149:28 | -139 | let _: &str = unsafe { std::mem::transmute(b) }; +149 | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` | = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:140:32 + --> $DIR/transmute.rs:150:32 | -140 | let _: &mut str = unsafe { std::mem::transmute(mb) }; +150 | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:172:29 + --> $DIR/transmute.rs:182:29 | -172 | let _: *const f32 = std::mem::transmute(ptr); +182 | let _: *const f32 = std::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32` | = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:173:27 + --> $DIR/transmute.rs:183:27 | -173 | let _: *mut f32 = std::mem::transmute(mut_ptr); +183 | let _: *mut f32 = std::mem::transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32` error: transmute from a reference to a reference - --> $DIR/transmute.rs:175:23 + --> $DIR/transmute.rs:185:23 | -175 | let _: &f32 = std::mem::transmute(&1u32); +185 | let _: &f32 = std::mem::transmute(&1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:176:23 + --> $DIR/transmute.rs:186:23 | -176 | let _: &f64 = std::mem::transmute(&1f32); +186 | let _: &f64 = std::mem::transmute(&1f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:179:27 + --> $DIR/transmute.rs:189:27 | -179 | let _: &mut f32 = std::mem::transmute(&mut 1u32); +189 | let _: &mut f32 = std::mem::transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:180:37 + --> $DIR/transmute.rs:190:37 | -180 | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); +190 | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` error: aborting due to 38 previous errors diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index 08866c63ec6..59d3d82ccae 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + //ignore-x86_64 diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 539b403cff9..630b594eb1b 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] //ignore-x86 diff --git a/tests/ui/transmute_64bit.stderr b/tests/ui/transmute_64bit.stderr index e86908655a8..dcc6d264caf 100644 --- a/tests/ui/transmute_64bit.stderr +++ b/tests/ui/transmute_64bit.stderr @@ -1,15 +1,15 @@ error: transmute from a `f64` to a pointer - --> $DIR/transmute_64bit.rs:11:31 + --> $DIR/transmute_64bit.rs:21:31 | -11 | let _: *const usize = std::mem::transmute(6.0f64); +21 | let _: *const usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::wrong-transmute` implied by `-D warnings` error: transmute from a `f64` to a pointer - --> $DIR/transmute_64bit.rs:13:29 + --> $DIR/transmute_64bit.rs:23:29 | -13 | let _: *mut usize = std::mem::transmute(6.0f64); +23 | let _: *mut usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index e3dbe510a47..716e0dc6420 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::many_single_char_names, clippy::blacklisted_name, clippy::redundant_field_names)] diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 2db627dd9b1..2026d4c00d8 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,81 +1,81 @@ error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:42:11 + --> $DIR/trivially_copy_pass_by_ref.rs:52:11 | -42 | fn bad(x: &u32, y: &Foo, z: &Baz) { +52 | fn bad(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `u32` | = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:42:20 + --> $DIR/trivially_copy_pass_by_ref.rs:52:20 | -42 | fn bad(x: &u32, y: &Foo, z: &Baz) { +52 | fn bad(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:42:29 + --> $DIR/trivially_copy_pass_by_ref.rs:52:29 | -42 | fn bad(x: &u32, y: &Foo, z: &Baz) { +52 | fn bad(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:52:12 + --> $DIR/trivially_copy_pass_by_ref.rs:62:12 | -52 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { +62 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { | ^^^^^ help: consider passing by value instead: `self` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:52:22 + --> $DIR/trivially_copy_pass_by_ref.rs:62:22 | -52 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { +62 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:52:31 + --> $DIR/trivially_copy_pass_by_ref.rs:62:31 | -52 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { +62 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:52:40 + --> $DIR/trivially_copy_pass_by_ref.rs:62:40 | -52 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { +62 | fn bad(&self, x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:55:16 + --> $DIR/trivially_copy_pass_by_ref.rs:65:16 | -55 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +65 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:55:25 + --> $DIR/trivially_copy_pass_by_ref.rs:65:25 | -55 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +65 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:55:34 + --> $DIR/trivially_copy_pass_by_ref.rs:65:34 | -55 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +65 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:69:16 + --> $DIR/trivially_copy_pass_by_ref.rs:79:16 | -69 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +79 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:69:25 + --> $DIR/trivially_copy_pass_by_ref.rs:79:25 | -69 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +79 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:69:34 + --> $DIR/trivially_copy_pass_by_ref.rs:79:34 | -69 | fn bad2(x: &u32, y: &Foo, z: &Baz) { +79 | fn bad2(x: &u32, y: &Foo, z: &Baz) { | ^^^^ help: consider passing by value instead: `Baz` error: aborting due to 13 previous errors diff --git a/tests/ui/ty_fn_sig.rs b/tests/ui/ty_fn_sig.rs index 9e2753dcb18..82b5deda3ba 100644 --- a/tests/ui/ty_fn_sig.rs +++ b/tests/ui/ty_fn_sig.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // Regression test pub fn retry<F: Fn()>(f: F) { diff --git a/tests/ui/types.rs b/tests/ui/types.rs index 10d1c490ee6..03676f69ab4 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + // should not warn on lossy casting in constant types // because not supported yet const C : i32 = 42; diff --git a/tests/ui/types.stderr b/tests/ui/types.stderr index e2f75162867..0940cd53b5c 100644 --- a/tests/ui/types.stderr +++ b/tests/ui/types.stderr @@ -1,10 +1,10 @@ error: casting i32 to i64 may become silently lossy if types change - --> $DIR/types.rs:9:23 - | -9 | let c_i64 : i64 = c as i64; - | ^^^^^^^^ help: try: `i64::from(c)` - | - = note: `-D clippy::cast-lossless` implied by `-D warnings` + --> $DIR/types.rs:19:23 + | +19 | let c_i64 : i64 = c as i64; + | ^^^^^^^^ help: try: `i64::from(c)` + | + = note: `-D clippy::cast-lossless` implied by `-D warnings` error: aborting due to previous error diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index b997d6d3f14..486135ddfa5 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index b0e567fc212..8de848caec3 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,17 +1,17 @@ error: zero-width space detected - --> $DIR/unicode.rs:6:12 - | -6 | print!("Here >​< is a ZWS, and ​another"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::zero-width-space` implied by `-D warnings` - = help: Consider replacing the string with: - ""Here >/u{200B}< is a ZWS, and /u{200B}another"" + --> $DIR/unicode.rs:16:12 + | +16 | print!("Here >​< is a ZWS, and ​another"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::zero-width-space` implied by `-D warnings` + = help: Consider replacing the string with: + ""Here >/u{200B}< is a ZWS, and /u{200B}another"" error: non-nfc unicode sequence detected - --> $DIR/unicode.rs:12:12 + --> $DIR/unicode.rs:22:12 | -12 | print!("̀àh?"); +22 | print!("̀àh?"); | ^^^^^ | = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` @@ -19,9 +19,9 @@ error: non-nfc unicode sequence detected ""̀àh?"" error: literal non-ASCII character detected - --> $DIR/unicode.rs:18:12 + --> $DIR/unicode.rs:28:12 | -18 | print!("Üben!"); +28 | print!("Üben!"); | ^^^^^^^ | = note: `-D clippy::non-ascii-literal` implied by `-D warnings` diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 2f743f227b8..ed70ee843b1 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::unit_arg)] diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index e1845c0c0ea..6e5cf8354bc 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,67 +1,67 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:9 + --> $DIR/unit_arg.rs:35:9 | -25 | foo({}); +35 | foo({}); | ^^ | = note: `-D clippy::unit-arg` implied by `-D warnings` help: if you intended to pass a unit value, use a unit literal instead | -25 | foo(()); +35 | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:26:9 + --> $DIR/unit_arg.rs:36:9 | -26 | foo({ 1; }); +36 | foo({ 1; }); | ^^^^^^ help: if you intended to pass a unit value, use a unit literal instead | -26 | foo(()); +36 | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:9 + --> $DIR/unit_arg.rs:37:9 | -27 | foo(foo(1)); +37 | foo(foo(1)); | ^^^^^^ help: if you intended to pass a unit value, use a unit literal instead | -27 | foo(()); +37 | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:9 + --> $DIR/unit_arg.rs:38:9 | -28 | foo({ +38 | foo({ | _________^ -29 | | foo(1); -30 | | foo(2); -31 | | }); +39 | | foo(1); +40 | | foo(2); +41 | | }); | |_____^ help: if you intended to pass a unit value, use a unit literal instead | -28 | foo(()); +38 | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:10 + --> $DIR/unit_arg.rs:42:10 | -32 | foo3({}, 2, 2); +42 | foo3({}, 2, 2); | ^^ help: if you intended to pass a unit value, use a unit literal instead | -32 | foo3((), 2, 2); +42 | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:34:11 + --> $DIR/unit_arg.rs:44:11 | -34 | b.bar({ 1; }); +44 | b.bar({ 1; }); | ^^^^^^ help: if you intended to pass a unit value, use a unit literal instead | -34 | b.bar(()); +44 | b.bar(()); | ^^ error: aborting due to 6 previous errors diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index bd79d0f8189..e8726bf7364 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index a85eb32841f..bd9ac25a64f 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -1,15 +1,15 @@ error: ==-comparison of unit values detected. This will always be true - --> $DIR/unit_cmp.rs:16:8 + --> $DIR/unit_cmp.rs:26:8 | -16 | if { true; } == { false; } { +26 | if { true; } == { false; } { | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unit-cmp` implied by `-D warnings` error: >-comparison of unit values detected. This will always be false - --> $DIR/unit_cmp.rs:19:8 + --> $DIR/unit_cmp.rs:29:8 | -19 | if { true; } > { false; } { +29 | if { true; } > { false; } { | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 7a2fc4ac1f6..82010db7a99 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::clone_on_ref_ptr)] diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index b2985f84b04..051fc1fcdf9 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -1,81 +1,81 @@ error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:18:5 + --> $DIR/unnecessary_clone.rs:28:5 | -18 | 42.clone(); +28 | 42.clone(); | ^^^^^^^^^^ help: try removing the `clone` call: `42` | = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:22:5 + --> $DIR/unnecessary_clone.rs:32:5 | -22 | (&42).clone(); +32 | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:32:5 + --> $DIR/unnecessary_clone.rs:42:5 | -32 | rc.clone(); +42 | rc.clone(); | ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)` | = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:35:5 + --> $DIR/unnecessary_clone.rs:45:5 | -35 | arc.clone(); +45 | arc.clone(); | ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:38:5 + --> $DIR/unnecessary_clone.rs:48:5 | -38 | rcweak.clone(); +48 | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:41:5 + --> $DIR/unnecessary_clone.rs:51:5 | -41 | arc_weak.clone(); +51 | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:45:29 + --> $DIR/unnecessary_clone.rs:55:29 | -45 | let _: Arc<SomeTrait> = x.clone(); +55 | let _: Arc<SomeTrait> = x.clone(); | ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:49:5 + --> $DIR/unnecessary_clone.rs:59:5 | -49 | t.clone(); +59 | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:51:5 + --> $DIR/unnecessary_clone.rs:61:5 | -51 | Some(t).clone(); +61 | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:57:22 + --> $DIR/unnecessary_clone.rs:67:22 | -57 | let z: &Vec<_> = y.clone(); +67 | let z: &Vec<_> = y.clone(); | ^^^^^^^^^ | = note: #[deny(clippy::clone_double_ref)] on by default help: try dereferencing it | -57 | let z: &Vec<_> = &(*y).clone(); +67 | let z: &Vec<_> = &(*y).clone(); | ^^^^^^^^^^^^^ help: or try being explicit about what type to clone | -57 | let z: &Vec<_> = &std::vec::Vec<i32>::clone(y); +67 | let z: &Vec<_> = &std::vec::Vec<i32>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/unnecessary_clone.rs:64:27 + --> $DIR/unnecessary_clone.rs:74:27 | -64 | let v2 : Vec<isize> = v.iter().cloned().collect(); +74 | let v2 : Vec<isize> = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs index dd6cdc5d39d..8b74ca3a425 100644 --- a/tests/ui/unnecessary_filter_map.rs +++ b/tests/ui/unnecessary_filter_map.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + fn main() { let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); let _ = (0..4).filter_map(|x| { if x > 1 { return Some(x); }; None }); diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr index 045802047d2..8fef6068167 100644 --- a/tests/ui/unnecessary_filter_map.stderr +++ b/tests/ui/unnecessary_filter_map.stderr @@ -1,32 +1,32 @@ error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:2:13 - | -2 | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` + --> $DIR/unnecessary_filter_map.rs:12:13 + | +12 | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:3:13 - | -3 | let _ = (0..4).filter_map(|x| { if x > 1 { return Some(x); }; None }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/unnecessary_filter_map.rs:13:13 + | +13 | let _ = (0..4).filter_map(|x| { if x > 1 { return Some(x); }; None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:4:13 - | -4 | let _ = (0..4).filter_map(|x| match x { - | _____________^ -5 | | 0 | 1 => None, -6 | | _ => Some(x), -7 | | }); - | |______^ + --> $DIR/unnecessary_filter_map.rs:14:13 + | +14 | let _ = (0..4).filter_map(|x| match x { + | _____________^ +15 | | 0 | 1 => None, +16 | | _ => Some(x), +17 | | }); + | |______^ error: this `.filter_map` can be written more simply using `.map` - --> $DIR/unnecessary_filter_map.rs:9:13 - | -9 | let _ = (0..4).filter_map(|x| Some(x + 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/unnecessary_filter_map.rs:19:13 + | +19 | let _ = (0..4).filter_map(|x| Some(x + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 62198e21ef7..e8d84ecea8c 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { // Can be replaced by .any diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index e72f671b67e..b2865479c43 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -1,33 +1,33 @@ error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:4:19 - | -4 | let _ = (0..3).fold(false, |acc, x| acc || x > 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` - | - = note: `-D clippy::unnecessary-fold` implied by `-D warnings` + --> $DIR/unnecessary_fold.rs:14:19 + | +14 | let _ = (0..3).fold(false, |acc, x| acc || x > 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` + | + = note: `-D clippy::unnecessary-fold` implied by `-D warnings` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:6:19 - | -6 | let _ = (0..3).fold(true, |acc, x| acc && x > 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)` + --> $DIR/unnecessary_fold.rs:16:19 + | +16 | let _ = (0..3).fold(true, |acc, x| acc && x > 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:8:19 - | -8 | let _ = (0..3).fold(0, |acc, x| acc + x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.sum()` + --> $DIR/unnecessary_fold.rs:18:19 + | +18 | let _ = (0..3).fold(0, |acc, x| acc + x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.sum()` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:10:19 + --> $DIR/unnecessary_fold.rs:20:19 | -10 | let _ = (0..3).fold(1, |acc, x| acc * x); +20 | let _ = (0..3).fold(1, |acc, x| acc * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.product()` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:15:34 + --> $DIR/unnecessary_fold.rs:25:34 | -15 | let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); +25 | let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` error: aborting due to 5 previous errors diff --git a/tests/ui/unnecessary_ref.rs b/tests/ui/unnecessary_ref.rs index afc920832ce..6fb2abaf19c 100644 --- a/tests/ui/unnecessary_ref.rs +++ b/tests/ui/unnecessary_ref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![feature(tool_attributes)] diff --git a/tests/ui/unnecessary_ref.stderr b/tests/ui/unnecessary_ref.stderr index d27ba26f349..a3d8f5e337c 100644 --- a/tests/ui/unnecessary_ref.stderr +++ b/tests/ui/unnecessary_ref.stderr @@ -1,13 +1,13 @@ error: Creating a reference that is immediately dereferenced. - --> $DIR/unnecessary_ref.rs:13:17 + --> $DIR/unnecessary_ref.rs:23:17 | -13 | let inner = (&outer).inner; +23 | let inner = (&outer).inner; | ^^^^^^^^ help: try this: `outer.inner` | note: lint level defined here - --> $DIR/unnecessary_ref.rs:10:8 + --> $DIR/unnecessary_ref.rs:20:8 | -10 | #[deny(clippy::ref_in_deref)] +20 | #[deny(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index 88b91235df6..963d555ca56 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index 40aa4f524fe..85982d75494 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -1,16 +1,16 @@ error: You matched a field with a wildcard pattern. Consider using `..` instead - --> $DIR/unneeded_field_pattern.rs:17:15 + --> $DIR/unneeded_field_pattern.rs:27:15 | -17 | Foo { a: _, b: 0, .. } => {} +27 | Foo { a: _, b: 0, .. } => {} | ^^^^ | = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings` = help: Try with `Foo { b: 0, .. }` error: All the struct fields are matched to a wildcard pattern, consider using `..`. - --> $DIR/unneeded_field_pattern.rs:19:9 + --> $DIR/unneeded_field_pattern.rs:29:9 | -19 | Foo { a: _, b: _, c: _ } => {} +29 | Foo { a: _, b: _, c: _ } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Try with `Foo { .. }` instead diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index df3539e38e8..67e04706f04 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #[warn(clippy::unreadable_literal)] diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 516b6ccc595..b5ab6937d95 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,34 +1,34 @@ error: long literal lacking separators - --> $DIR/unreadable_literal.rs:7:16 - | -7 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); - | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` - | - = note: `-D clippy::unreadable-literal` implied by `-D warnings` + --> $DIR/unreadable_literal.rs:17:16 + | +17 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); + | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` + | + = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:7:30 - | -7 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); - | ^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` + --> $DIR/unreadable_literal.rs:17:30 + | +17 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); + | ^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:7:51 - | -7 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); - | ^^^^^^^^^^ help: consider: `123_456_f32` + --> $DIR/unreadable_literal.rs:17:51 + | +17 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); + | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:7:63 - | -7 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); - | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` + --> $DIR/unreadable_literal.rs:17:63 + | +17 | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); + | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:9:19 - | -9 | let bad_sci = 1.123456e1; - | ^^^^^^^^^^ help: consider: `1.123_456e1` + --> $DIR/unreadable_literal.rs:19:19 + | +19 | let bad_sci = 1.123456e1; + | ^^^^^^^^^^ help: consider: `1.123_456e1` error: aborting due to 5 previous errors diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index 41b98975d53..39aa4afdf8d 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused_imports)] diff --git a/tests/ui/unsafe_removed_from_name.stderr b/tests/ui/unsafe_removed_from_name.stderr index 2b014ca5863..f4bb93735d7 100644 --- a/tests/ui/unsafe_removed_from_name.stderr +++ b/tests/ui/unsafe_removed_from_name.stderr @@ -1,21 +1,21 @@ error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCell` - --> $DIR/unsafe_removed_from_name.rs:7:1 - | -7 | use std::cell::{UnsafeCell as TotallySafeCell}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` + --> $DIR/unsafe_removed_from_name.rs:17:1 + | +17 | use std::cell::{UnsafeCell as TotallySafeCell}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCellAgain` - --> $DIR/unsafe_removed_from_name.rs:9:1 - | -9 | use std::cell::UnsafeCell as TotallySafeCellAgain; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $DIR/unsafe_removed_from_name.rs:19:1 + | +19 | use std::cell::UnsafeCell as TotallySafeCellAgain; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed "unsafe" from the name of `Unsafe` in use as `LieAboutModSafety` - --> $DIR/unsafe_removed_from_name.rs:23:1 + --> $DIR/unsafe_removed_from_name.rs:33:1 | -23 | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; +33 | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 53bcbce9dbf..0ab89c994f4 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 48a5751579c..329dfacd43b 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -1,42 +1,42 @@ error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:11:5 + --> $DIR/unused_io_amount.rs:21:5 | -11 | try!(s.write(b"test")); +21 | try!(s.write(b"test")); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unused-io-amount` implied by `-D warnings` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:13:5 + --> $DIR/unused_io_amount.rs:23:5 | -13 | try!(s.read(&mut buf)); +23 | try!(s.read(&mut buf)); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:18:5 + --> $DIR/unused_io_amount.rs:28:5 | -18 | s.write(b"test")?; +28 | s.write(b"test")?; | ^^^^^^^^^^^^^^^^^ error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:20:5 + --> $DIR/unused_io_amount.rs:30:5 | -20 | s.read(&mut buf)?; +30 | s.read(&mut buf)?; | ^^^^^^^^^^^^^^^^^ error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:25:5 + --> $DIR/unused_io_amount.rs:35:5 | -25 | s.write(b"test").unwrap(); +35 | s.write(b"test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:27:5 + --> $DIR/unused_io_amount.rs:37:5 | -27 | s.read(&mut buf).unwrap(); +37 | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs index b76fcad1699..ecfdab490f6 100644 --- a/tests/ui/unused_labels.rs +++ b/tests/ui/unused_labels.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/unused_labels.stderr b/tests/ui/unused_labels.stderr index d35ca41a1a1..5a31ada902e 100644 --- a/tests/ui/unused_labels.stderr +++ b/tests/ui/unused_labels.stderr @@ -1,25 +1,25 @@ error: unused label `'label` - --> $DIR/unused_labels.rs:8:5 + --> $DIR/unused_labels.rs:18:5 | -8 | / 'label: for i in 1..2 { -9 | | if i > 4 { continue } -10 | | } +18 | / 'label: for i in 1..2 { +19 | | if i > 4 { continue } +20 | | } | |_____^ | = note: `-D clippy::unused-label` implied by `-D warnings` error: unused label `'a` - --> $DIR/unused_labels.rs:21:5 + --> $DIR/unused_labels.rs:31:5 | -21 | 'a: loop { break } +31 | 'a: loop { break } | ^^^^^^^^^^^^^^^^^^ error: unused label `'same_label_in_two_fns` - --> $DIR/unused_labels.rs:32:5 + --> $DIR/unused_labels.rs:42:5 | -32 | / 'same_label_in_two_fns: loop { -33 | | let _ = 1; -34 | | } +42 | / 'same_label_in_two_fns: loop { +43 | | let _ = 1; +44 | | } | |_____^ error: aborting due to 3 previous errors diff --git a/tests/ui/unused_lt.rs b/tests/ui/unused_lt.rs index e5c5e893504..3aea986d28d 100644 --- a/tests/ui/unused_lt.rs +++ b/tests/ui/unused_lt.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused, dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/unused_lt.stderr b/tests/ui/unused_lt.stderr index 4cad611c2a1..f5b788c16a7 100644 --- a/tests/ui/unused_lt.stderr +++ b/tests/ui/unused_lt.stderr @@ -1,21 +1,21 @@ error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:16:14 + --> $DIR/unused_lt.rs:26:14 | -16 | fn unused_lt<'a>(x: u8) { +26 | fn unused_lt<'a>(x: u8) { | ^^ | = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:20:25 + --> $DIR/unused_lt.rs:30:25 | -20 | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { +30 | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:50:10 + --> $DIR/unused_lt.rs:60:10 | -50 | fn x<'a>(&self) {} +60 | fn x<'a>(&self) {} | ^^ error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index 682c42dc935..b31ccfea200 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all)] diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index 42c72090ca5..ffdeeb5307f 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -1,15 +1,15 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:5:47 - | -5 | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` - | - = note: `-D clippy::or-fun-call` implied by `-D warnings` + --> $DIR/unwrap_or.rs:15:47 + | +15 | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` + | + = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:10:10 + --> $DIR/unwrap_or.rs:20:10 | -10 | .unwrap_or("Fail".to_string()) +20 | .unwrap_or("Fail".to_string()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` error: aborting due to 2 previous errors diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 8d18d848ae0..784e0c04016 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::use_self)] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index cf673e166d8..627fc3a97cb 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,123 +1,123 @@ error: unnecessary structure name repetition - --> $DIR/use_self.rs:13:21 + --> $DIR/use_self.rs:23:21 | -13 | fn new() -> Foo { +23 | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` | = note: `-D clippy::use-self` implied by `-D warnings` error: unnecessary structure name repetition - --> $DIR/use_self.rs:14:13 + --> $DIR/use_self.rs:24:13 | -14 | Foo {} +24 | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:16:22 + --> $DIR/use_self.rs:26:22 | -16 | fn test() -> Foo { +26 | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:17:13 + --> $DIR/use_self.rs:27:13 | -17 | Foo::new() +27 | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:22:25 + --> $DIR/use_self.rs:32:25 | -22 | fn default() -> Foo { +32 | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:23:13 + --> $DIR/use_self.rs:33:13 | -23 | Foo::new() +33 | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:86:22 + --> $DIR/use_self.rs:96:22 | -86 | fn refs(p1: &Bad) -> &Bad { +96 | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:86:31 + --> $DIR/use_self.rs:96:31 | -86 | fn refs(p1: &Bad) -> &Bad { +96 | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:90:37 - | -90 | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:100:37 + | +100 | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:90:53 - | -90 | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:100:53 + | +100 | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:94:30 - | -94 | fn mut_refs(p1: &mut Bad) -> &mut Bad { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:104:30 + | +104 | fn mut_refs(p1: &mut Bad) -> &mut Bad { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:94:43 - | -94 | fn mut_refs(p1: &mut Bad) -> &mut Bad { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:104:43 + | +104 | fn mut_refs(p1: &mut Bad) -> &mut Bad { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:28 - | -98 | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:108:28 + | +108 | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:46 - | -98 | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) { - | ^^^ help: use the applicable keyword: `Self` + --> $DIR/use_self.rs:108:46 + | +108 | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:101:20 + --> $DIR/use_self.rs:111:20 | -101 | fn vals(_: Bad) -> Bad { +111 | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:101:28 + --> $DIR/use_self.rs:111:28 | -101 | fn vals(_: Bad) -> Bad { +111 | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:102:13 + --> $DIR/use_self.rs:112:13 | -102 | Bad::default() +112 | Bad::default() | ^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:107:23 + --> $DIR/use_self.rs:117:23 | -107 | type Output = Bad; +117 | type Output = Bad; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:109:27 + --> $DIR/use_self.rs:119:27 | -109 | fn mul(self, rhs: Bad) -> Bad { +119 | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:109:35 + --> $DIR/use_self.rs:119:35 | -109 | fn mul(self, rhs: Bad) -> Bad { +119 | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: aborting due to 20 previous errors diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index c1e1c9af5db..13ae1d67f15 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::all)] diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index a1bb57a50a5..8092119470e 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,33 +1,33 @@ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:17:5 + --> $DIR/used_underscore_binding.rs:27:5 | -17 | _foo + 1 +27 | _foo + 1 | ^^^^ | = note: `-D clippy::used-underscore-binding` implied by `-D warnings` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:22:20 + --> $DIR/used_underscore_binding.rs:32:20 | -22 | println!("{}", _foo); +32 | println!("{}", _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:23:16 + --> $DIR/used_underscore_binding.rs:33:16 | -23 | assert_eq!(_foo, _foo); +33 | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:23:22 + --> $DIR/used_underscore_binding.rs:33:22 | -23 | assert_eq!(_foo, _foo); +33 | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:36:5 + --> $DIR/used_underscore_binding.rs:46:5 | -36 | s._underscore_field += 1; +46 | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index 52994566e09..598618365c8 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![deny(clippy::useless_asref)] diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 6247fb27a79..8e45facf587 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -1,73 +1,73 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:33:18 + --> $DIR/useless_asref.rs:43:18 | -33 | foo_rstr(rstr.as_ref()); +43 | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` | note: lint level defined here - --> $DIR/useless_asref.rs:3:9 + --> $DIR/useless_asref.rs:13:9 | -3 | #![deny(clippy::useless_asref)] +13 | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:35:20 + --> $DIR/useless_asref.rs:45:20 | -35 | foo_rslice(rslice.as_ref()); +45 | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:39:21 + --> $DIR/useless_asref.rs:49:21 | -39 | foo_mrslice(mrslice.as_mut()); +49 | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:41:20 + --> $DIR/useless_asref.rs:51:20 | -41 | foo_rslice(mrslice.as_ref()); +51 | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:48:20 + --> $DIR/useless_asref.rs:58:20 | -48 | foo_rslice(rrrrrslice.as_ref()); +58 | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:50:18 + --> $DIR/useless_asref.rs:60:18 | -50 | foo_rstr(rrrrrstr.as_ref()); +60 | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:55:21 + --> $DIR/useless_asref.rs:65:21 | -55 | foo_mrslice(mrrrrrslice.as_mut()); +65 | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:57:20 + --> $DIR/useless_asref.rs:67:20 | -57 | foo_rslice(mrrrrrslice.as_ref()); +67 | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:60:16 + --> $DIR/useless_asref.rs:70:16 | -60 | foo_rrrrmr((&&&&MoreRef).as_ref()); +70 | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:106:13 + --> $DIR/useless_asref.rs:116:13 | -106 | foo_mrt(mrt.as_mut()); +116 | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:108:12 + --> $DIR/useless_asref.rs:118:12 | -108 | foo_rt(mrt.as_ref()); +118 | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` error: aborting due to 11 previous errors diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 80d4ebcedba..710f35da72b 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index d498fe64ebf..4a27d1148b4 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -1,16 +1,16 @@ error: useless lint attribute - --> $DIR/useless_attribute.rs:5:1 - | -5 | #[allow(dead_code)] - | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]` - | - = note: `-D clippy::useless-attribute` implied by `-D warnings` + --> $DIR/useless_attribute.rs:15:1 + | +15 | #[allow(dead_code)] + | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]` + | + = note: `-D clippy::useless-attribute` implied by `-D warnings` error: useless lint attribute - --> $DIR/useless_attribute.rs:6:1 - | -6 | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code))` + --> $DIR/useless_attribute.rs:16:1 + | +16 | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code))` error: aborting due to 2 previous errors diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 78a49f2580a..45e51663795 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index b9541e58c77..e4649eab5ec 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -1,39 +1,39 @@ error: useless use of `vec!` - --> $DIR/vec.rs:24:14 + --> $DIR/vec.rs:34:14 | -24 | on_slice(&vec![]); +34 | on_slice(&vec![]); | ^^^^^^^ help: you can use a slice directly: `&[]` | = note: `-D clippy::useless-vec` implied by `-D warnings` error: useless use of `vec!` - --> $DIR/vec.rs:27:14 + --> $DIR/vec.rs:37:14 | -27 | on_slice(&vec![1, 2]); +37 | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:30:14 + --> $DIR/vec.rs:40:14 | -30 | on_slice(&vec ![1, 2]); +40 | on_slice(&vec ![1, 2]); | ^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:33:14 + --> $DIR/vec.rs:43:14 | -33 | on_slice(&vec!(1, 2)); +43 | on_slice(&vec!(1, 2)); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:36:14 + --> $DIR/vec.rs:46:14 | -36 | on_slice(&vec![1; 2]); +46 | on_slice(&vec![1; 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` error: useless use of `vec!` - --> $DIR/vec.rs:49:14 + --> $DIR/vec.rs:59:14 | -49 | for a in vec![1, 2, 3] { +59 | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` error: aborting due to 6 previous errors diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index 0b8691d57b4..ff7a43fd693 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/while_loop.stderr b/tests/ui/while_loop.stderr index cc309e37946..b166e8bacb5 100644 --- a/tests/ui/while_loop.stderr +++ b/tests/ui/while_loop.stderr @@ -1,114 +1,114 @@ error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:9:5 + --> $DIR/while_loop.rs:19:5 | -9 | / loop { -10 | | if let Some(_x) = y { -11 | | let _v = 1; -12 | | } else { -13 | | break -14 | | } -15 | | } +19 | / loop { +20 | | if let Some(_x) = y { +21 | | let _v = 1; +22 | | } else { +23 | | break +24 | | } +25 | | } | |_____^ help: try: `while let Some(_x) = y { .. }` | = note: `-D clippy::while-let-loop` implied by `-D warnings` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:22:5 + --> $DIR/while_loop.rs:32:5 | -22 | / loop { -23 | | match y { -24 | | Some(_x) => true, -25 | | None => break -26 | | }; -27 | | } +32 | / loop { +33 | | match y { +34 | | Some(_x) => true, +35 | | None => break +36 | | }; +37 | | } | |_____^ help: try: `while let Some(_x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:28:5 + --> $DIR/while_loop.rs:38:5 | -28 | / loop { -29 | | let x = match y { -30 | | Some(x) => x, -31 | | None => break +38 | / loop { +39 | | let x = match y { +40 | | Some(x) => x, +41 | | None => break ... | -34 | | let _str = "foo"; -35 | | } +44 | | let _str = "foo"; +45 | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:36:5 + --> $DIR/while_loop.rs:46:5 | -36 | / loop { -37 | | let x = match y { -38 | | Some(x) => x, -39 | | None => break, +46 | / loop { +47 | | let x = match y { +48 | | Some(x) => x, +49 | | None => break, ... | -42 | | { let _b = "foobar"; } -43 | | } +52 | | { let _b = "foobar"; } +53 | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:58:5 + --> $DIR/while_loop.rs:68:5 | -58 | / loop { -59 | | let (e, l) = match "".split_whitespace().next() { -60 | | Some(word) => (word.is_empty(), word.len()), -61 | | None => break +68 | / loop { +69 | | let (e, l) = match "".split_whitespace().next() { +70 | | Some(word) => (word.is_empty(), word.len()), +71 | | None => break ... | -64 | | let _ = (e, l); -65 | | } +74 | | let _ = (e, l); +75 | | } | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:68:33 + --> $DIR/while_loop.rs:78:33 | -68 | while let Option::Some(x) = iter.next() { +78 | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^ help: try: `for x in iter { .. }` | = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:73:25 + --> $DIR/while_loop.rs:83:25 | -73 | while let Some(x) = iter.next() { +83 | while let Some(x) = iter.next() { | ^^^^^^^^^^^ help: try: `for x in iter { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:78:25 + --> $DIR/while_loop.rs:88:25 | -78 | while let Some(_) = iter.next() {} +88 | while let Some(_) = iter.next() {} | ^^^^^^^^^^^ help: try: `for _ in iter { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:118:5 + --> $DIR/while_loop.rs:128:5 | -118 | / loop { -119 | | let _ = match iter.next() { -120 | | Some(ele) => ele, -121 | | None => break -122 | | }; -123 | | loop {} -124 | | } +128 | / loop { +129 | | let _ = match iter.next() { +130 | | Some(ele) => ele, +131 | | None => break +132 | | }; +133 | | loop {} +134 | | } | |_____^ help: try: `while let Some(ele) = iter.next() { .. }` error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body. - --> $DIR/while_loop.rs:123:9 + --> $DIR/while_loop.rs:133:9 | -123 | loop {} +133 | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:183:29 + --> $DIR/while_loop.rs:193:29 | -183 | while let Some(v) = y.next() { // use a for loop here +193 | while let Some(v) = y.next() { // use a for loop here | ^^^^^^^^ help: try: `for v in y { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:210:26 + --> $DIR/while_loop.rs:220:26 | -210 | while let Some(..) = values.iter().next() { +220 | while let Some(..) = values.iter().next() { | ^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in values.iter() { .. }` error: aborting due to 12 previous errors diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 5ef4c15f409..9a27ca11dae 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused_must_use)] diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 644f6f15b42..2aa66c32049 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -1,87 +1,87 @@ error: literal with an empty format string - --> $DIR/write_literal.rs:29:79 + --> $DIR/write_literal.rs:39:79 | -29 | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2); +39 | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2); | ^ | = note: `-D clippy::write-literal` implied by `-D warnings` error: literal with an empty format string - --> $DIR/write_literal.rs:30:32 + --> $DIR/write_literal.rs:40:32 | -30 | write!(&mut v, "Hello {}", "world"); +40 | write!(&mut v, "Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:31:44 + --> $DIR/write_literal.rs:41:44 | -31 | writeln!(&mut v, "Hello {} {}", world, "world"); +41 | writeln!(&mut v, "Hello {} {}", world, "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:32:34 + --> $DIR/write_literal.rs:42:34 | -32 | writeln!(&mut v, "Hello {}", "world"); +42 | writeln!(&mut v, "Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:33:38 + --> $DIR/write_literal.rs:43:38 | -33 | writeln!(&mut v, "10 / 4 is {}", 2.5); +43 | writeln!(&mut v, "10 / 4 is {}", 2.5); | ^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:34:36 + --> $DIR/write_literal.rs:44:36 | -34 | writeln!(&mut v, "2 + 1 = {}", 3); +44 | writeln!(&mut v, "2 + 1 = {}", 3); | ^ error: literal with an empty format string - --> $DIR/write_literal.rs:39:33 + --> $DIR/write_literal.rs:49:33 | -39 | writeln!(&mut v, "{0} {1}", "hello", "world"); +49 | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:39:42 + --> $DIR/write_literal.rs:49:42 | -39 | writeln!(&mut v, "{0} {1}", "hello", "world"); +49 | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:40:33 + --> $DIR/write_literal.rs:50:33 | -40 | writeln!(&mut v, "{1} {0}", "hello", "world"); +50 | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:40:42 + --> $DIR/write_literal.rs:50:42 | -40 | writeln!(&mut v, "{1} {0}", "hello", "world"); +50 | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:43:41 + --> $DIR/write_literal.rs:53:41 | -43 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); +53 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:43:54 + --> $DIR/write_literal.rs:53:54 | -43 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); +53 | writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:44:41 + --> $DIR/write_literal.rs:54:41 | -44 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); +54 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:44:54 + --> $DIR/write_literal.rs:54:54 | -44 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); +54 | writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world"); | ^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index 58e6002fa6a..f3e26ed904f 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(clippy::write_literal)] diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index c8617b4939a..dd7f223c517 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -1,27 +1,27 @@ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:12:5 + --> $DIR/write_with_newline.rs:22:5 | -12 | write!(&mut v, "Hello/n"); +22 | write!(&mut v, "Hello/n"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::write-with-newline` implied by `-D warnings` error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:13:5 + --> $DIR/write_with_newline.rs:23:5 | -13 | write!(&mut v, "Hello {}/n", "world"); +23 | write!(&mut v, "Hello {}/n", "world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:14:5 + --> $DIR/write_with_newline.rs:24:5 | -14 | write!(&mut v, "Hello {} {}/n", "world", "#2"); +24 | write!(&mut v, "Hello {} {}/n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:15:5 + --> $DIR/write_with_newline.rs:25:5 | -15 | write!(&mut v, "{}/n", 1265); +25 | write!(&mut v, "{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/writeln_empty_string.rs b/tests/ui/writeln_empty_string.rs index 81dfdcdc0d0..888e870667c 100644 --- a/tests/ui/writeln_empty_string.rs +++ b/tests/ui/writeln_empty_string.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] #![allow(unused_must_use)] diff --git a/tests/ui/writeln_empty_string.stderr b/tests/ui/writeln_empty_string.stderr index ef1e9b3d36e..3e6ec33623a 100644 --- a/tests/ui/writeln_empty_string.stderr +++ b/tests/ui/writeln_empty_string.stderr @@ -1,15 +1,15 @@ error: using `writeln!(&mut v, "")` - --> $DIR/writeln_empty_string.rs:11:5 + --> $DIR/writeln_empty_string.rs:21:5 | -11 | writeln!(&mut v, ""); +21 | writeln!(&mut v, ""); | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)` | = note: `-D clippy::writeln-empty-string` implied by `-D warnings` error: using `writeln!(&mut suggestion, "")` - --> $DIR/writeln_empty_string.rs:14:5 + --> $DIR/writeln_empty_string.rs:24:5 | -14 | writeln!(&mut suggestion, ""); +24 | writeln!(&mut suggestion, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)` error: aborting due to 2 previous errors diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 2fb33d08619..d843af1a396 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 4a6e5e0ab22..ee0f4f8a143 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,75 +1,75 @@ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:21:17 + --> $DIR/wrong_self_convention.rs:31:17 | -21 | fn from_i32(self) {} +31 | fn from_i32(self) {} | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:27:21 + --> $DIR/wrong_self_convention.rs:37:21 | -27 | pub fn from_i64(self) {} +37 | pub fn from_i64(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:40:15 + --> $DIR/wrong_self_convention.rs:50:15 | -40 | fn as_i32(self) {} +50 | fn as_i32(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:42:17 + --> $DIR/wrong_self_convention.rs:52:17 | -42 | fn into_i32(&self) {} +52 | fn into_i32(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:44:15 + --> $DIR/wrong_self_convention.rs:54:15 | -44 | fn is_i32(self) {} +54 | fn is_i32(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:46:15 + --> $DIR/wrong_self_convention.rs:56:15 | -46 | fn to_i32(self) {} +56 | fn to_i32(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:48:17 + --> $DIR/wrong_self_convention.rs:58:17 | -48 | fn from_i32(self) {} +58 | fn from_i32(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:50:19 + --> $DIR/wrong_self_convention.rs:60:19 | -50 | pub fn as_i64(self) {} +60 | pub fn as_i64(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:51:21 + --> $DIR/wrong_self_convention.rs:61:21 | -51 | pub fn into_i64(&self) {} +61 | pub fn into_i64(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:52:19 + --> $DIR/wrong_self_convention.rs:62:19 | -52 | pub fn is_i64(self) {} +62 | pub fn is_i64(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:53:19 + --> $DIR/wrong_self_convention.rs:63:19 | -53 | pub fn to_i64(self) {} +63 | pub fn to_i64(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:54:21 + --> $DIR/wrong_self_convention.rs:64:21 | -54 | pub fn from_i64(self) {} +64 | pub fn from_i64(self) {} | ^^^^ error: aborting due to 12 previous errors diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index 7927e8b8ac7..c2cbd32968f 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + #![feature(tool_lints)] diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index a5e86883d25..0c24a08a634 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -1,58 +1,58 @@ error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:7:15 - | -7 | let nan = 0.0 / 0.0; - | ^^^^^^^^^ - | - = note: #[deny(clippy::eq_op)] on by default + --> $DIR/zero_div_zero.rs:17:15 + | +17 | let nan = 0.0 / 0.0; + | ^^^^^^^^^ + | + = note: #[deny(clippy::eq_op)] on by default error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:7:15 - | -7 | let nan = 0.0 / 0.0; - | ^^^^^^^^^ - | - = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + --> $DIR/zero_div_zero.rs:17:15 + | +17 | let nan = 0.0 / 0.0; + | ^^^^^^^^^ + | + = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` + = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:8:19 - | -8 | let f64_nan = 0.0 / 0.0f64; - | ^^^^^^^^^^^^ + --> $DIR/zero_div_zero.rs:18:19 + | +18 | let f64_nan = 0.0 / 0.0f64; + | ^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:8:19 - | -8 | let f64_nan = 0.0 / 0.0f64; - | ^^^^^^^^^^^^ - | - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + --> $DIR/zero_div_zero.rs:18:19 + | +18 | let f64_nan = 0.0 / 0.0f64; + | ^^^^^^^^^^^^ + | + = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:9:25 - | -9 | let other_f64_nan = 0.0f64 / 0.0; - | ^^^^^^^^^^^^ + --> $DIR/zero_div_zero.rs:19:25 + | +19 | let other_f64_nan = 0.0f64 / 0.0; + | ^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:9:25 - | -9 | let other_f64_nan = 0.0f64 / 0.0; - | ^^^^^^^^^^^^ - | - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + --> $DIR/zero_div_zero.rs:19:25 + | +19 | let other_f64_nan = 0.0f64 / 0.0; + | ^^^^^^^^^^^^ + | + = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:10:28 + --> $DIR/zero_div_zero.rs:20:28 | -10 | let one_more_f64_nan = 0.0f64/0.0f64; +20 | let one_more_f64_nan = 0.0f64/0.0f64; | ^^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:10:28 + --> $DIR/zero_div_zero.rs:20:28 | -10 | let one_more_f64_nan = 0.0f64/0.0f64; +20 | let one_more_f64_nan = 0.0f64/0.0f64; | ^^^^^^^^^^^^^ | = help: Consider using `std::f64::NAN` if you would like a constant representing NaN diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index 4a6010f4bd0..fbe4f950da5 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + diff --git a/tests/ui/zero_ptr.stderr b/tests/ui/zero_ptr.stderr index b5e279eaa3a..7a0c8e70b22 100644 --- a/tests/ui/zero_ptr.stderr +++ b/tests/ui/zero_ptr.stderr @@ -1,16 +1,16 @@ error: `0 as *const _` detected. Consider using `ptr::null()` - --> $DIR/zero_ptr.rs:6:13 - | -6 | let x = 0 as *const usize; - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::zero-ptr` implied by `-D warnings` + --> $DIR/zero_ptr.rs:16:13 + | +16 | let x = 0 as *const usize; + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::zero-ptr` implied by `-D warnings` error: `0 as *mut _` detected. Consider using `ptr::null_mut()` - --> $DIR/zero_ptr.rs:7:13 - | -7 | let y = 0 as *mut f64; - | ^^^^^^^^^^^^^ + --> $DIR/zero_ptr.rs:17:13 + | +17 | let y = 0 as *mut f64; + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 25b0ceefae7..5b189a797b7 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -1,3 +1,13 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + extern crate cargo_metadata; extern crate semver; use semver::VersionReq; -- cgit 1.4.1-3-g733a5 From eef2e8948b4f0de21669231933739ef0d0f0017a Mon Sep 17 00:00:00 2001 From: Devon Hollowood <devonhollowood@gmail.com> Date: Mon, 8 Oct 2018 21:40:21 -0700 Subject: Fix cast_possible_truncation warnings --- clippy_lints/src/consts.rs | 27 ++++++++++++++++++++------- clippy_lints/src/lib.rs | 1 + clippy_lints/src/regex.rs | 19 +++++++++++++++++-- clippy_lints/src/utils/sugg.rs | 3 ++- src/driver.rs | 4 +++- 5 files changed, 43 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 2422e8e8a10..b84430e6819 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -18,6 +18,7 @@ use crate::rustc::ty::{self, Ty, TyCtxt, Instance}; use crate::rustc::ty::subst::{Subst, Substs}; use std::cmp::Ordering::{self, Equal}; use std::cmp::PartialOrd; +use std::convert::TryInto; use std::hash::{Hash, Hasher}; use std::mem; use std::rc::Rc; @@ -341,8 +342,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BinOpKind::Mul => l.checked_mul(r).map(zext), BinOpKind::Div if r != 0 => l.checked_div(r).map(zext), BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext), - BinOpKind::Shr => l.checked_shr(r as u128 as u32).map(zext), - BinOpKind::Shl => l.checked_shl(r as u128 as u32).map(zext), + BinOpKind::Shr => l.checked_shr( + (r as u128).try_into().expect("shift too large") + ).map(zext), + BinOpKind::Shl => l.checked_shl( + (r as u128).try_into().expect("shift too large") + ).map(zext), BinOpKind::BitXor => Some(zext(l ^ r)), BinOpKind::BitOr => Some(zext(l | r)), BinOpKind::BitAnd => Some(zext(l & r)), @@ -362,8 +367,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { BinOpKind::Mul => l.checked_mul(r).map(Constant::Int), BinOpKind::Div => l.checked_div(r).map(Constant::Int), BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), - BinOpKind::Shr => l.checked_shr(r as u32).map(Constant::Int), - BinOpKind::Shl => l.checked_shl(r as u32).map(Constant::Int), + BinOpKind::Shr => l.checked_shr( + r.try_into().expect("shift too large") + ).map(Constant::Int), + BinOpKind::Shl => l.checked_shl( + r.try_into().expect("shift too large") + ).map(Constant::Int), BinOpKind::BitXor => Some(Constant::Int(l ^ r)), BinOpKind::BitOr => Some(Constant::Int(l | r)), BinOpKind::BitAnd => Some(Constant::Int(l & r)), @@ -426,8 +435,12 @@ pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<' ConstValue::Scalar(Scalar::Bits{ bits: b, ..}) => match result.ty.sty { ty::Bool => Some(Constant::Bool(b == 1)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(b)), - ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(b as u32))), - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(b as u64))), + ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( + b.try_into().expect("invalid f32 bit representation") + ))), + ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( + b.try_into().expect("invalid f64 bit representation") + ))), // FIXME: implement other conversion _ => None, }, @@ -439,7 +452,7 @@ pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<' .alloc_map .lock() .unwrap_memory(ptr.alloc_id); - let offset = ptr.offset.bytes() as usize; + let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset"); let n = n as usize; String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned()).ok().map(Constant::Str) }, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e4ad9fe9ca1..af69a6284f3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -21,6 +21,7 @@ #![feature(tool_lints)] #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![feature(crate_visibility_modifier)] +#![feature(try_from)] // FIXME: switch to something more ergonomic here, once available. // (currently there is no way to opt into sysroot crates w/o `extern crate`) diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 7a818c41fff..deb32e49a0d 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -18,6 +18,7 @@ use crate::syntax::ast::{LitKind, NodeId, StrStyle}; use crate::syntax::source_map::{BytePos, Span}; use crate::utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint}; use crate::consts::{constant, Constant}; +use std::convert::TryInto; /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct @@ -143,8 +144,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span { let offset = u32::from(offset); - let end = base.lo() + BytePos(c.end.offset as u32 + offset); - let start = base.lo() + BytePos(c.start.offset as u32 + offset); + let end = base.lo() + BytePos( + c.end + .offset + .try_into() + .ok() + .and_then(|o: u32| o.checked_add(offset)) + .expect("offset too large"), + ); + let start = base.lo() + BytePos( + c.start + .offset + .try_into() + .ok() + .and_then(|o: u32| o.checked_add(offset)) + .expect("offset too large"), + ); assert!(start <= end); Span::new(start, end, base.ctxt()) } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index fecfc0c0789..eb67838f1d1 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -16,6 +16,7 @@ use crate::rustc::hir; use crate::rustc::lint::{EarlyContext, LateContext, LintContext}; use crate::rustc_errors; use std::borrow::Cow; +use std::convert::TryInto; use std::fmt::Display; use std; use crate::syntax::source_map::{CharPos, Span}; @@ -551,7 +552,7 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n'); if let Some(non_whitespace_offset) = non_whitespace_offset { - remove_span = remove_span.with_hi(remove_span.hi() + BytePos(non_whitespace_offset as u32)) + remove_span = remove_span.with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))) } } diff --git a/src/driver.rs b/src/driver.rs index d2ed3cb1c26..0619b3ae0d9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -12,6 +12,7 @@ #![feature(box_syntax)] #![feature(rustc_private)] #![feature(tool_lints)] +#![feature(try_from)] #![allow(unknown_lints, clippy::missing_docs_in_private_items)] // FIXME: switch to something more ergonomic here, once available. @@ -22,6 +23,7 @@ extern crate rustc_driver; extern crate rustc_plugin; use self::rustc_driver::{driver::CompileController, Compilation}; +use std::convert::TryInto; use std::path::Path; use std::process::{exit, Command}; @@ -153,5 +155,5 @@ pub fn main() { let args = args; rustc_driver::run_compiler(&args, Box::new(controller), None, None) - }) as i32) + }).try_into().expect("exit code too large")) } -- cgit 1.4.1-3-g733a5 From b8654eaa6c4c4abaed9b8e448445b992c87bb41e Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Thu, 11 Oct 2018 12:16:22 +0200 Subject: Stabilize tool lints --- README.md | 9 ++++----- clippy_dev/src/lib.rs | 2 +- clippy_lints/src/lib.rs | 2 +- src/driver.rs | 2 +- src/lib.rs | 2 +- src/main.rs | 2 +- tests/run-pass/enum-glob-import-crate.rs | 2 +- tests/run-pass/ice-1588.rs | 2 +- tests/run-pass/ice-1969.rs | 2 +- tests/run-pass/ice-2499.rs | 2 +- tests/run-pass/ice-2760.rs | 2 +- tests/run-pass/ice-2774.rs | 2 +- tests/run-pass/ice-700.rs | 2 +- tests/run-pass/ice_exacte_size.rs | 2 +- tests/run-pass/if_same_then_else.rs | 2 +- tests/run-pass/match_same_arms_const.rs | 2 +- tests/run-pass/mut_mut_macro.rs | 2 +- tests/run-pass/needless_borrow_fp.rs | 2 +- tests/run-pass/needless_lifetimes_impl_trait.rs | 2 +- tests/run-pass/regressions.rs | 2 +- tests/run-pass/single-match-else.rs | 2 +- tests/run-pass/used_underscore_binding_macro.rs | 2 +- tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs | 2 +- tests/ui-toml/toml_trivially_copy/test.rs | 2 +- tests/ui/absurd-extreme-comparisons.rs | 2 +- tests/ui/approx_const.rs | 2 +- tests/ui/arithmetic.rs | 2 +- tests/ui/assign_ops.rs | 2 +- tests/ui/assign_ops2.rs | 2 +- tests/ui/attrs.rs | 2 +- tests/ui/bit_masks.rs | 2 +- tests/ui/blacklisted_name.rs | 2 +- tests/ui/block_in_if_condition.rs | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/booleans.rs | 2 +- tests/ui/borrow_box.rs | 2 +- tests/ui/box_vec.rs | 2 +- tests/ui/builtin-type-shadow.rs | 2 +- tests/ui/bytecount.rs | 2 +- tests/ui/cast.rs | 2 +- tests/ui/cast_alignment.rs | 2 +- tests/ui/cast_lossless_float.rs | 2 +- tests/ui/cast_lossless_integer.rs | 2 +- tests/ui/cast_size.rs | 2 +- tests/ui/char_lit_as_u8.rs | 2 +- tests/ui/checked_unwrap.rs | 2 +- tests/ui/clone_on_copy_mut.rs | 2 +- tests/ui/cmp_nan.rs | 2 +- tests/ui/cmp_null.rs | 2 +- tests/ui/cmp_owned.rs | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/complex_types.rs | 2 +- tests/ui/copies.rs | 2 +- tests/ui/copy_iterator.rs | 2 +- tests/ui/cstring.rs | 2 +- tests/ui/cyclomatic_complexity.rs | 2 +- tests/ui/cyclomatic_complexity_attr_used.rs | 2 +- tests/ui/decimal_literal_representation.rs | 2 +- tests/ui/default_trait_access.rs | 2 +- tests/ui/derive.rs | 2 +- tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/dlist.rs | 2 +- tests/ui/doc.rs | 2 +- tests/ui/double_neg.rs | 2 +- tests/ui/double_parens.rs | 2 +- tests/ui/drop_forget_copy.rs | 2 +- tests/ui/drop_forget_ref.rs | 2 +- tests/ui/duplicate_underscore_argument.rs | 2 +- tests/ui/duration_subsec.rs | 2 +- tests/ui/else_if_without_else.rs | 2 +- tests/ui/empty_enum.rs | 2 +- tests/ui/empty_line_after_outer_attribute.rs | 2 +- tests/ui/entry.rs | 2 +- tests/ui/enum_glob_use.rs | 2 +- tests/ui/enum_variants.rs | 2 +- tests/ui/enums_clike.rs | 2 +- tests/ui/eq_op.rs | 2 +- tests/ui/erasing_op.rs | 2 +- tests/ui/eta.rs | 2 +- tests/ui/eval_order_dependence.rs | 2 +- tests/ui/excessive_precision.rs | 2 +- tests/ui/explicit_write.rs | 2 +- tests/ui/fallible_impl_from.rs | 2 +- tests/ui/filter_methods.rs | 2 +- tests/ui/float_cmp.rs | 2 +- tests/ui/float_cmp_const.rs | 2 +- tests/ui/fn_to_numeric_cast.rs | 2 +- tests/ui/for_loop.rs | 2 +- tests/ui/format.rs | 2 +- tests/ui/formatting.rs | 2 +- tests/ui/functions.rs | 2 +- tests/ui/fxhash.rs | 2 +- tests/ui/identity_conversion.rs | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/if_let_redundant_pattern_matching.rs | 2 +- tests/ui/if_not_else.rs | 2 +- tests/ui/impl.rs | 2 +- tests/ui/inconsistent_digit_grouping.rs | 2 +- tests/ui/indexing_slicing.rs | 2 +- tests/ui/infallible_destructuring_match.rs | 2 +- tests/ui/infinite_iter.rs | 2 +- tests/ui/infinite_loop.rs | 2 +- tests/ui/inline_fn_without_body.rs | 2 +- tests/ui/int_plus_one.rs | 4 ++-- tests/ui/invalid_upcast_comparisons.rs | 2 +- tests/ui/issue_2356.rs | 2 +- tests/ui/item_after_statement.rs | 2 +- tests/ui/large_digit_groups.rs | 2 +- tests/ui/large_enum_variant.rs | 2 +- tests/ui/len_zero.rs | 2 +- tests/ui/let_if_seq.rs | 2 +- tests/ui/let_return.rs | 2 +- tests/ui/let_unit.rs | 2 +- tests/ui/lifetimes.rs | 2 +- tests/ui/literals.rs | 2 +- tests/ui/map_clone.rs | 2 +- tests/ui/map_flatten.rs | 2 +- tests/ui/matches.rs | 2 +- tests/ui/mem_forget.rs | 2 +- tests/ui/mem_replace.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/min_max.rs | 2 +- tests/ui/missing-doc.rs | 2 +- tests/ui/missing_inline.rs | 2 +- tests/ui/module_inception.rs | 2 +- tests/ui/modulo_one.rs | 2 +- tests/ui/mut_from_ref.rs | 2 +- tests/ui/mut_mut.rs | 2 +- tests/ui/mut_reference.rs | 2 +- tests/ui/mutex_atomic.rs | 2 +- tests/ui/needless_bool.rs | 2 +- tests/ui/needless_borrow.rs | 2 +- tests/ui/needless_borrowed_ref.rs | 2 +- tests/ui/needless_collect.rs | 2 +- tests/ui/needless_continue.rs | 2 +- tests/ui/needless_pass_by_value.rs | 2 +- tests/ui/needless_pass_by_value_proc_macro.rs | 2 +- tests/ui/needless_return.rs | 2 +- tests/ui/needless_update.rs | 2 +- tests/ui/neg_cmp_op_on_partial_ord.rs | 4 ++-- tests/ui/neg_multiply.rs | 2 +- tests/ui/never_loop.rs | 2 +- tests/ui/new_without_default.rs | 2 +- tests/ui/no_effect.rs | 2 +- tests/ui/non_copy_const.rs | 2 +- tests/ui/non_expressive_names.rs | 2 +- tests/ui/ok_if_let.rs | 2 +- tests/ui/op_ref.rs | 4 ++-- tests/ui/open_options.rs | 2 +- tests/ui/option_map_unit_fn.rs | 2 +- tests/ui/overflow_check_conditional.rs | 2 +- tests/ui/panic_unimplemented.rs | 2 +- tests/ui/patterns.rs | 2 +- tests/ui/precedence.rs | 2 +- tests/ui/print.rs | 2 +- tests/ui/print_literal.rs | 2 +- tests/ui/print_with_newline.rs | 2 +- tests/ui/ptr_arg.rs | 2 +- tests/ui/range.rs | 2 +- tests/ui/range_plus_minus_one.rs | 2 +- tests/ui/redundant_closure_call.rs | 2 +- tests/ui/redundant_field_names.rs | 2 +- tests/ui/reference.rs | 2 +- tests/ui/regex.rs | 2 +- tests/ui/replace_consts.rs | 2 +- tests/ui/result_map_unit_fn.rs | 2 +- tests/ui/serde.rs | 2 +- tests/ui/shadow.rs | 2 +- tests/ui/short_circuit_statement.rs | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_match.rs | 2 +- tests/ui/starts_ends_with.rs | 2 +- tests/ui/strings.rs | 2 +- tests/ui/stutter.rs | 2 +- tests/ui/suspicious_arithmetic_impl.rs | 2 +- tests/ui/swap.rs | 2 +- tests/ui/temporary_assignment.rs | 2 +- tests/ui/toplevel_ref_arg.rs | 2 +- tests/ui/transmute.rs | 2 +- tests/ui/transmute_64bit.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 2 +- tests/ui/unicode.rs | 2 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unit_cmp.rs | 2 +- tests/ui/unnecessary_clone.rs | 2 +- tests/ui/unnecessary_ref.rs | 2 +- tests/ui/unneeded_field_pattern.rs | 2 +- tests/ui/unreadable_literal.rs | 2 +- tests/ui/unsafe_removed_from_name.rs | 2 +- tests/ui/unused_io_amount.rs | 2 +- tests/ui/unused_labels.rs | 2 +- tests/ui/unused_lt.rs | 2 +- tests/ui/unwrap_or.rs | 2 +- tests/ui/use_self.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- tests/ui/useless_asref.rs | 2 +- tests/ui/useless_attribute.rs | 2 +- tests/ui/useless_attribute.stderr | 2 +- tests/ui/vec.rs | 2 +- tests/ui/while_loop.rs | 2 +- tests/ui/write_literal.rs | 2 +- tests/ui/write_with_newline.rs | 2 +- tests/ui/writeln_empty_string.rs | 2 +- tests/ui/wrong_self_convention.rs | 2 +- tests/ui/zero_div_zero.rs | 2 +- 205 files changed, 211 insertions(+), 212 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 9dd41f6513c..14a5e56cdea 100644 --- a/README.md +++ b/README.md @@ -130,16 +130,15 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints: Note: `deny` produces errors instead of warnings. -Note: To use the new `clippy::lint_name` syntax, `#![feature(tool_lints)]` has to be activated -currently. If you want to compile your code with the stable toolchain you can use a `cfg_attr` to +Note: To use the new `clippy::lint_name` syntax, a recent compiler has to be used +currently. If you want to compile your code with the stable toolchain you can use a `cfg_attr` to activate the `tool_lints` feature: ```rust -#![cfg_attr(feature = "cargo-clippy", feature(tool_lints))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::lint_name))] ``` -For this to work you have to use Clippy on the nightly toolchain: `cargo +nightly clippy`. If you -want to use Clippy with the stable toolchain, you can stick to the old unscoped method to +For this to work you have to use Clippy on the nightly toolchain: `cargo +nightly clippy`. If you +want to use Clippy with the stable toolchain, you can stick to the old unscoped method to enable/disable Clippy lints until `tool_lints` are stable: ```rust #![cfg_attr(feature = "cargo-clippy", allow(clippy_lint))] diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 0e29db9bef0..eee9089e7c4 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::default_hash_types)] use itertools::Itertools; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index af69a6284f3..451374c9a47 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -18,7 +18,7 @@ #![allow(unknown_lints, clippy::shadow_reuse, clippy::missing_docs_in_private_items)] #![recursion_limit = "256"] #![feature(macro_at_most_once_rep)] -#![feature(tool_lints)] + #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![feature(crate_visibility_modifier)] #![feature(try_from)] diff --git a/src/driver.rs b/src/driver.rs index 0619b3ae0d9..6af0f0be190 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -11,7 +11,7 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(tool_lints)] + #![feature(try_from)] #![allow(unknown_lints, clippy::missing_docs_in_private_items)] diff --git a/src/lib.rs b/src/lib.rs index 58158f92e65..62c9da03278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] -#![feature(tool_lints)] + #![allow(unknown_lints)] #![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] diff --git a/src/main.rs b/src/main.rs index 11c259b4d6b..efdcc42dea3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(tool_lints)] + #![allow(unknown_lints, clippy::missing_docs_in_private_items)] use rustc_tools_util::*; diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs index c1e1d9645d1..df8b32cde2b 100644 --- a/tests/run-pass/enum-glob-import-crate.rs +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::all)] #![allow(unused_imports)] diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs index db5a6629a2b..a54c77cce73 100644 --- a/tests/run-pass/ice-1588.rs +++ b/tests/run-pass/ice-1588.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::all)] diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs index 0b4a0f4dfbf..848d9743dcd 100644 --- a/tests/run-pass/ice-1969.rs +++ b/tests/run-pass/ice-1969.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::all)] diff --git a/tests/run-pass/ice-2499.rs b/tests/run-pass/ice-2499.rs index 9716e5500c7..1a973d737ba 100644 --- a/tests/run-pass/ice-2499.rs +++ b/tests/run-pass/ice-2499.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] diff --git a/tests/run-pass/ice-2760.rs b/tests/run-pass/ice-2760.rs index ad517b84c2c..7a83094ea76 100644 --- a/tests/run-pass/ice-2760.rs +++ b/tests/run-pass/ice-2760.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_variables, clippy::blacklisted_name, clippy::needless_pass_by_value, dead_code)] diff --git a/tests/run-pass/ice-2774.rs b/tests/run-pass/ice-2774.rs index 6ed09a4a008..67a77340d91 100644 --- a/tests/run-pass/ice-2774.rs +++ b/tests/run-pass/ice-2774.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::collections::HashSet; diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs index 3252381e1fd..cb6ba21e72b 100644 --- a/tests/run-pass/ice-700.rs +++ b/tests/run-pass/ice-700.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::all)] diff --git a/tests/run-pass/ice_exacte_size.rs b/tests/run-pass/ice_exacte_size.rs index 8a905a401e5..74eda792e75 100644 --- a/tests/run-pass/ice_exacte_size.rs +++ b/tests/run-pass/ice_exacte_size.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::all)] diff --git a/tests/run-pass/if_same_then_else.rs b/tests/run-pass/if_same_then_else.rs index 4f0f581063a..cc95262fe3c 100644 --- a/tests/run-pass/if_same_then_else.rs +++ b/tests/run-pass/if_same_then_else.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::if_same_then_else)] diff --git a/tests/run-pass/match_same_arms_const.rs b/tests/run-pass/match_same_arms_const.rs index 1e36baf059b..bd180e9cad9 100644 --- a/tests/run-pass/match_same_arms_const.rs +++ b/tests/run-pass/match_same_arms_const.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::match_same_arms)] diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs index afc3c9eda15..8859009479c 100644 --- a/tests/run-pass/mut_mut_macro.rs +++ b/tests/run-pass/mut_mut_macro.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)] #![allow(dead_code)] diff --git a/tests/run-pass/needless_borrow_fp.rs b/tests/run-pass/needless_borrow_fp.rs index 6a70849d9ca..ad4b04864e4 100644 --- a/tests/run-pass/needless_borrow_fp.rs +++ b/tests/run-pass/needless_borrow_fp.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[deny(clippy::all)] diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs index b27bb284e21..0514d7ab008 100644 --- a/tests/run-pass/needless_lifetimes_impl_trait.rs +++ b/tests/run-pass/needless_lifetimes_impl_trait.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::needless_lifetimes)] #![allow(dead_code)] diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs index a589922218d..9be3bab185c 100644 --- a/tests/run-pass/regressions.rs +++ b/tests/run-pass/regressions.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::blacklisted_name)] diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs index 54c282451b8..cf032c65703 100644 --- a/tests/run-pass/single-match-else.rs +++ b/tests/run-pass/single-match-else.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::single_match_else)] diff --git a/tests/run-pass/used_underscore_binding_macro.rs b/tests/run-pass/used_underscore_binding_macro.rs index b700ab90a68..68bd6922062 100644 --- a/tests/run-pass/used_underscore_binding_macro.rs +++ b/tests/run-pass/used_underscore_binding_macro.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::useless_attribute)] //issue #2910 diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs index 4f0cd1659f7..ad81b82b2c5 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index 081dbf9b060..eb09d6dfc5c 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::many_single_char_names)] #[derive(Copy, Clone)] diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index a88e57a5c43..b219cb0397b 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::absurd_extreme_comparisons)] diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index ea023b8a7a2..b2f50cc2ce3 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::approx_constant)] diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index a5bf8c9280e..ff550c9593c 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 5d791ba8f54..419e63b2c62 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index 60a9d2fb73e..4f9fbc80aaa 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[allow(unused_assignments)] diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 9af9c0e619a..1d0c23905bd 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::inline_always, clippy::deprecated_semver)] diff --git a/tests/ui/bit_masks.rs b/tests/ui/bit_masks.rs index 4110f6ced85..db5a6885c9e 100644 --- a/tests/ui/bit_masks.rs +++ b/tests/ui/bit_masks.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + const THREE_BITS : i64 = 7; diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index be58a8fb601..285438810d9 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code, clippy::similar_names, clippy::single_match, clippy::toplevel_ref_arg, unused_mut, unused_variables)] diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index 67bd778acaa..bb87315bcc4 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::block_in_if_condition_expr)] diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 1d9756bc39b..c213414a63d 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::bool_comparison)] diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index 556344c77a2..962f03dc9cd 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::nonminimal_bool, clippy::logic_bug)] diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 7c668c33c83..dbcd42a692c 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::borrowed_box)] diff --git a/tests/ui/box_vec.rs b/tests/ui/box_vec.rs index 78174d2cd8f..bf505c85abc 100644 --- a/tests/ui/box_vec.rs +++ b/tests/ui/box_vec.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin-type-shadow.rs index a6d0f82a7d6..e43a2789ce1 100644 --- a/tests/ui/builtin-type-shadow.rs +++ b/tests/ui/builtin-type-shadow.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::builtin_type_shadow)] diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 71a6e01219e..170666d1f18 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[deny(clippy::naive_bytecount)] diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 2fb865b12b8..9976a4aa96a 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap, clippy::cast_lossless)] diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index b6e01d21288..a1a2e1c9a8f 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + //! Test casts for alignment issues diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index aa78a62f88b..468774dd88b 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cast_lossless)] #[allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index ef430d57e1e..4f7432de620 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cast_lossless)] #[allow(clippy::no_effect, clippy::unnecessary_operation)] fn main() { diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index e8b0f4a5b82..fddf9669a8f 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cast_precision_loss, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap, clippy::cast_lossless)] #[allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index 8fda473e351..d684fcf5746 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::char_lit_as_u8)] diff --git a/tests/ui/checked_unwrap.rs b/tests/ui/checked_unwrap.rs index ed9651b1872..383fd82240b 100644 --- a/tests/ui/checked_unwrap.rs +++ b/tests/ui/checked_unwrap.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow(clippy::if_same_then_else)] diff --git a/tests/ui/clone_on_copy_mut.rs b/tests/ui/clone_on_copy_mut.rs index ad37d45d36f..81d70eb9458 100644 --- a/tests/ui/clone_on_copy_mut.rs +++ b/tests/ui/clone_on_copy_mut.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + pub fn dec_read_dec(i: &mut i32) -> i32 { *i -= 1; diff --git a/tests/ui/cmp_nan.rs b/tests/ui/cmp_nan.rs index a2506f444f0..4b62d0e53f1 100644 --- a/tests/ui/cmp_nan.rs +++ b/tests/ui/cmp_nan.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cmp_nan)] diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index d8214876a1b..03f0367a640 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::cmp_null)] #![allow(unused_mut)] diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 031809f5df5..978e919ff43 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::cmp_owned)] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index fa80b27f590..a6df9109df9 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::collapsible_if)] diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index 5779c9da47f..e735bf8e487 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] #![allow(unused, clippy::needless_pass_by_value)] diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index 2b29e76c4e0..8d0bc802daf 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::blacklisted_name, clippy::collapsible_if, clippy::cyclomatic_complexity, clippy::eq_op, clippy::needless_continue, clippy::needless_return, clippy::never_loop, clippy::no_effect, clippy::zero_divided_by_zero)] diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs index 6984b612f23..b5684f183eb 100644 --- a/tests/ui/copy_iterator.rs +++ b/tests/ui/copy_iterator.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::copy_iterator)] diff --git a/tests/ui/cstring.rs b/tests/ui/cstring.rs index fd5d00059a7..6121166debe 100644 --- a/tests/ui/cstring.rs +++ b/tests/ui/cstring.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + fn main() {} diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index 3c8ab8694a6..35451a99acc 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::all)] #![warn(clippy::cyclomatic_complexity)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index 1699601aa50..63d4e65a977 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::cyclomatic_complexity)] #![warn(unused)] diff --git a/tests/ui/decimal_literal_representation.rs b/tests/ui/decimal_literal_representation.rs index f85ccd84722..c52fcd826ca 100644 --- a/tests/ui/decimal_literal_representation.rs +++ b/tests/ui/decimal_literal_representation.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::decimal_literal_representation)] diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index d268746d765..331ad03f9a2 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::default_trait_access)] diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index c5ce42586fa..521a2e323fc 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(untagged_unions)] diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 9cf6f22fb27..a47c96759ac 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(never_type)] diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index dbbac901b03..cf16777b77a 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(alloc)] #![feature(associated_type_defaults)] diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 85e688e0f07..37f89de471f 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + //! This file tests for the DOC_MARKDOWN lint diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index 31e7a508fcd..3785c09060b 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::double_neg)] diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 18ff140c3ca..be1676a7487 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::double_parens)] diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index 8b2b96a14d3..44e9ae0e044 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::drop_copy, clippy::forget_copy)] diff --git a/tests/ui/drop_forget_ref.rs b/tests/ui/drop_forget_ref.rs index 0f36b823e0f..0aee38d3cbf 100644 --- a/tests/ui/drop_forget_ref.rs +++ b/tests/ui/drop_forget_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::drop_ref, clippy::forget_ref)] diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index 25b2a0ba8b6..27329965f0c 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::duplicate_underscore_argument)] diff --git a/tests/ui/duration_subsec.rs b/tests/ui/duration_subsec.rs index 75352ad182b..c8db599a840 100644 --- a/tests/ui/duration_subsec.rs +++ b/tests/ui/duration_subsec.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::duration_subsec)] diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index 56987d0d64d..caaa024ff6b 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] #![warn(clippy::else_if_without_else)] diff --git a/tests/ui/empty_enum.rs b/tests/ui/empty_enum.rs index cd63acb9ed6..b60f5491a93 100644 --- a/tests/ui/empty_enum.rs +++ b/tests/ui/empty_enum.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 8aa2e8a1f46..43105b6e342 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::empty_line_after_outer_attr)] // This should produce a warning diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 0bab6bf332e..0ee6d799222 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused, clippy::needless_pass_by_value)] diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index e24e2fd8eb3..9b7d4518c66 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic)] #![allow(unused_imports, dead_code, clippy::missing_docs_in_private_items)] diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index 8a51e2f58f1..34c69854b75 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(non_ascii_idents)] diff --git a/tests/ui/enums_clike.rs b/tests/ui/enums_clike.rs index 17983255030..5513a9506aa 100644 --- a/tests/ui/enums_clike.rs +++ b/tests/ui/enums_clike.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + // ignore-x86 diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index c96cd8b9af2..36c54b0f42e 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::eq_op)] diff --git a/tests/ui/erasing_op.rs b/tests/ui/erasing_op.rs index 1c572b55554..696c58f98ae 100644 --- a/tests/ui/erasing_op.rs +++ b/tests/ui/erasing_op.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[allow(clippy::no_effect)] diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index a580ce0831a..e516dd6910a 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unknown_lints, unused, clippy::no_effect, clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::redundant_closure, clippy::needless_borrow)] diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index 4e525b9b2b0..ee8f834fe56 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::eval_order_dependence)] diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index abfdb0b3da1..5945298da9f 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::excessive_precision)] #![allow(clippy::print_literal)] diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index 2a748d25724..8c1e35daa48 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::explicit_write)] diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 1e1e24ee954..f50d5999de6 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::fallible_impl_from)] diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index 1bfc03356fb..33441d728ca 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic)] diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index cb8b7a98e39..5619539fb5a 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::float_cmp)] diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index 27d829ed105..7cca1df65ae 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::float_cmp_const)] diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs index 9bd0ad7687f..50796e13ef6 100644 --- a/tests/ui/fn_to_numeric_cast.rs +++ b/tests/ui/fn_to_numeric_cast.rs @@ -9,7 +9,7 @@ // only-64bit -#![feature(tool_lints)] + #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index cff7075543b..bdb6b56e0bb 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::collections::*; diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 5679a55755c..e314d3022da 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::print_literal)] #![warn(clippy::useless_format)] diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index 15aff5a3bba..0dca8c8585b 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 136adef823b..f5ba0f791ee 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/fxhash.rs b/tests/ui/fxhash.rs index e91cfcb9e70..fe4b80807c0 100644 --- a/tests/ui/fxhash.rs +++ b/tests/ui/fxhash.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::default_hash_types)] #![feature(rustc_private)] diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs index a4f5babecfc..9384c9eb206 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/identity_conversion.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::identity_conversion)] diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 35afb85109f..07a4ef8f3eb 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + const ONE : i64 = 1; diff --git a/tests/ui/if_let_redundant_pattern_matching.rs b/tests/ui/if_let_redundant_pattern_matching.rs index 84f4b711f53..1c0e7e79c68 100644 --- a/tests/ui/if_let_redundant_pattern_matching.rs +++ b/tests/ui/if_let_redundant_pattern_matching.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index b0744d8c600..23895c0ab52 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] #![warn(clippy::if_not_else)] diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index 6c2152220cf..38c0a484091 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] #![warn(clippy::multiple_inherent_impl)] diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index dc73952ca25..941fbe5154a 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::inconsistent_digit_grouping)] #[allow(unused_variables)] diff --git a/tests/ui/indexing_slicing.rs b/tests/ui/indexing_slicing.rs index 8d3f3cee99a..6a32eb87491 100644 --- a/tests/ui/indexing_slicing.rs +++ b/tests/ui/indexing_slicing.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(plugin)] #![warn(clippy::indexing_slicing)] diff --git a/tests/ui/infallible_destructuring_match.rs b/tests/ui/infallible_destructuring_match.rs index bd4e4b49a4a..62036cbc107 100644 --- a/tests/ui/infallible_destructuring_match.rs +++ b/tests/ui/infallible_destructuring_match.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(exhaustive_patterns, never_type)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index cf30a2e35ed..68c10acb2be 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::iter::repeat; #[allow(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index e837e563f18..869b34e8ade 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs index 93dff0d350f..8434d33f65e 100644 --- a/tests/ui/inline_fn_without_body.rs +++ b/tests/ui/inline_fn_without_body.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::inline_fn_without_body)] diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index df16a393824..8a0405321d0 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[allow(clippy::no_effect, clippy::unnecessary_operation)] @@ -16,7 +16,7 @@ fn main() { let x = 1i32; let y = 0i32; - + x >= y + 1; y + 1 <= x; diff --git a/tests/ui/invalid_upcast_comparisons.rs b/tests/ui/invalid_upcast_comparisons.rs index 5c17970d337..3e62f11006d 100644 --- a/tests/ui/invalid_upcast_comparisons.rs +++ b/tests/ui/invalid_upcast_comparisons.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::invalid_upcast_comparisons)] diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index d251d51f3fc..070808f7b69 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::while_let_on_iterator)] diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index d765adae38c..a4cc42f0d72 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::items_after_statements)] diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index 7cc1f9c881d..aad5c205041 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::large_digit_groups)] #[allow(unused_variables)] diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 729cc8940ef..419cb0ab428 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index a8f1e283643..bc82e0bca04 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::len_without_is_empty, clippy::len_zero)] #![allow(dead_code, unused)] diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 5fca759a4b3..080fa3b24b8 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_variables, unused_assignments, clippy::similar_names, clippy::blacklisted_name)] diff --git a/tests/ui/let_return.rs b/tests/ui/let_return.rs index 380f775689d..317aaf42b5c 100644 --- a/tests/ui/let_return.rs +++ b/tests/ui/let_return.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused)] diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 578fcb2ddde..d77bc8712bf 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::let_unit_value)] diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index c7ed303b43b..77f25afe023 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::needless_lifetimes, clippy::extra_unused_lifetimes)] diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index 3c1dcf09af2..4db7ce95712 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::mixed_case_hex_literals)] #![warn(clippy::unseparated_literal_suffix)] diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 90611023f75..162d8a484b4 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index b3f86d81e3f..1b5c20069d1 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index e6e4154e437..c43fead08f8 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(exclusive_range_pattern)] diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index 0e7cfbffa4c..266c5c267f8 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index 69e3ae96bad..2b6e6f2ce67 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)] use std::mem; diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index e247a3d6450..883dbf589d7 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)] diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 32e3863ad40..b4ca46231e0 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index 43dad8398f1..6e7dfbfa37a 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + /* This file incorporates work covered by the following copyright and * permission notice: diff --git a/tests/ui/missing_inline.rs b/tests/ui/missing_inline.rs index 593774da1b4..0b86c4e5cfe 100644 --- a/tests/ui/missing_inline.rs +++ b/tests/ui/missing_inline.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + /* This file incorporates work covered by the following copyright and * permission notice: diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index 1dfc06f38af..333a8efec32 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::module_inception)] diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index 6e0cbc581dc..f1576447708 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::modulo_one)] #![allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 37256efb839..0a68d449d92 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::mut_from_ref)] diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 81c945beafc..bed872902af 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index f42d48f0db4..d63b854fd09 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_variables, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index e0ce93bf698..87b4ac9d8e3 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/needless_bool.rs b/tests/ui/needless_bool.rs index 0e8e250c95d..a9a2e3709f1 100644 --- a/tests/ui/needless_bool.rs +++ b/tests/ui/needless_bool.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::needless_bool)] diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 1cf7b40661d..f8a170f38d4 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::borrow::Cow; diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 650b57b586c..ca3e60bd7e7 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::needless_borrowed_reference)] diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 45622b33384..91ebd354146 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::collections::{HashMap, HashSet, BTreeSet}; diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 4a15987ba96..3d91132ea62 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + macro_rules! zero { diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index 3e029de4755..5825d9e9074 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::needless_pass_by_value)] #![allow(dead_code, clippy::single_match, clippy::if_let_redundant_pattern_matching, clippy::many_single_char_names, clippy::option_option)] diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index b1ca6d75c99..f8f279ccb66 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![crate_type = "proc-macro"] #![warn(clippy::needless_pass_by_value)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index bfe86573a4d..9380f7c48a5 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::needless_return)] diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index 70fe7236c24..974f3603fc6 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::needless_update)] diff --git a/tests/ui/neg_cmp_op_on_partial_ord.rs b/tests/ui/neg_cmp_op_on_partial_ord.rs index c8edba32219..6d26d2ec6d1 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + //! This test case utilizes `f64` an easy example for `PartialOrd` only types //! but the lint itself actually validates any expression where the left @@ -27,7 +27,7 @@ fn main() { // Not Less but potentially Greater, Equal or Uncomparable. let _not_less = !(a_value < another_value); - + // Not Less or Equal but potentially Greater or Uncomparable. let _not_less_or_equal = !(a_value <= another_value); diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 2589f3b8551..446af7bbe94 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::neg_multiply)] diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 901a98559e7..b952b1197dd 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::single_match, unused_assignments, unused_variables, clippy::while_immutable_condition)] diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 7fa369354b3..783308d264a 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(const_fn)] diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index a56327eeefa..32e1ccb7bee 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(box_syntax)] diff --git a/tests/ui/non_copy_const.rs b/tests/ui/non_copy_const.rs index 6c57a37e2ab..5cbb610fea3 100644 --- a/tests/ui/non_copy_const.rs +++ b/tests/ui/non_copy_const.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(const_string_new, const_vec_new)] #![allow(clippy::ref_in_deref, dead_code)] diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index 47e4da61b51..67fded14485 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all,clippy::similar_names)] #![allow(unused, clippy::println_empty_string)] diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index 71b301cbc42..b318a90d883 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::if_let_some_result)] diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index 96a208ef807..bacf9f1057b 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_variables, clippy::blacklisted_name)] @@ -19,7 +19,7 @@ fn main() { let tracked_fds: HashSet<i32> = HashSet::new(); let new_fds = HashSet::new(); let unwanted = &tracked_fds - &new_fds; - + let foo = &5 - &6; let bar = String::new(); diff --git a/tests/ui/open_options.rs b/tests/ui/open_options.rs index a01f2b1ce39..6b891d72e8b 100644 --- a/tests/ui/open_options.rs +++ b/tests/ui/open_options.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::fs::OpenOptions; diff --git a/tests/ui/option_map_unit_fn.rs b/tests/ui/option_map_unit_fn.rs index a69c41ce967..b023181fcf7 100644 --- a/tests/ui/option_map_unit_fn.rs +++ b/tests/ui/option_map_unit_fn.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::option_map_unit_fn)] #![allow(unused)] diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index 8aba051c65e..82fdfe14ab6 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::many_single_char_names)] diff --git a/tests/ui/panic_unimplemented.rs b/tests/ui/panic_unimplemented.rs index f292455dc7d..ede2e8f063b 100644 --- a/tests/ui/panic_unimplemented.rs +++ b/tests/ui/panic_unimplemented.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::panic_params, clippy::unimplemented)] diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 2b42aae63ea..41e9ec8ca81 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused)] #![warn(clippy::all)] diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index ccc08ddc5d7..4b404022ed4 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::precedence)] diff --git a/tests/ui/print.rs b/tests/ui/print.rs index 3bb72fcb1f4..5fa2cfcc315 100644 --- a/tests/ui/print.rs +++ b/tests/ui/print.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::print_literal, clippy::write_literal)] #![warn(clippy::print_stdout, clippy::use_debug)] diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index fd68751820d..0df26f6d25f 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::print_literal)] diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index 4fc24080d46..2dd08a5b88d 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::print_literal)] #![warn(clippy::print_with_newline)] diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 4d5f353bb6a..df0bde14960 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused, clippy::many_single_char_names)] #![warn(clippy::ptr_arg)] diff --git a/tests/ui/range.rs b/tests/ui/range.rs index 270b71d263f..8b7f0673e24 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + struct NotARange; impl NotARange { diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index 15743828d8b..602743d6914 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + fn f() -> usize { 42 diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index bf0cc550b0d..4912e5fc1b4 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::redundant_closure_call)] diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index ac0d5d10535..41e90bba368 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::redundant_field_names)] #![allow(unused_variables)] diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs index 9298aee2cac..bd0fdd5d5ea 100644 --- a/tests/ui/reference.rs +++ b/tests/ui/reference.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + fn get_number() -> usize { diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 6e77c589023..2623438c4c4 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused)] diff --git a/tests/ui/replace_consts.rs b/tests/ui/replace_consts.rs index 2f961e86f9a..7a2584f174d 100644 --- a/tests/ui/replace_consts.rs +++ b/tests/ui/replace_consts.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(integer_atomics)] #![allow(clippy::blacklisted_name)] diff --git a/tests/ui/result_map_unit_fn.rs b/tests/ui/result_map_unit_fn.rs index 4edbfdd5bf4..f24e52b10fd 100644 --- a/tests/ui/result_map_unit_fn.rs +++ b/tests/ui/result_map_unit_fn.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index caa954bea44..47be8423d7b 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::serde_api_misuse)] #![allow(dead_code)] diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index a607161a949..aa29bd1d79c 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all, clippy::pedantic, clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index 01511314c7d..67999a74e5e 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::short_circuit_statement)] diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 12aaa69f34b..5e1231f1227 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + use std::collections::HashSet; diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 07c1a95025a..5c7cae249b4 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::single_match)] diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index 180924d2c9c..5c09e8f1f28 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 31e6c9a059f..7bc4e6515f6 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::string_add)] diff --git a/tests/ui/stutter.rs b/tests/ui/stutter.rs index 148e8071ce0..17d528d1050 100644 --- a/tests/ui/stutter.rs +++ b/tests/ui/stutter.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::stutter)] #![allow(dead_code)] diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs index a183576b40e..5e7608565ed 100644 --- a/tests/ui/suspicious_arithmetic_impl.rs +++ b/tests/ui/suspicious_arithmetic_impl.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::suspicious_arithmetic_impl)] diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index bef2031f8a8..90c2aec9875 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index cf92f9fd6c2..9c4365bef40 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::temporary_assignment)] diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 9f92d706ad6..09ee79f6d8b 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 4108750acf6..285c07a9724 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 630b594eb1b..8620628fdce 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + //ignore-x86 //no-ignore-x86_64 diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 716e0dc6420..cebe15b2cc8 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::many_single_char_names, clippy::blacklisted_name, clippy::redundant_field_names)] diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 486135ddfa5..8de17fea220 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::zero_width_space)] diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index ed70ee843b1..058c6563c5a 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::unit_arg)] #![allow(clippy::no_effect)] diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index e8726bf7364..10eb0c70c54 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::unit_cmp)] diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 82010db7a99..df02570d692 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::clone_on_ref_ptr)] #![allow(unused)] diff --git a/tests/ui/unnecessary_ref.rs b/tests/ui/unnecessary_ref.rs index 6fb2abaf19c..adc628fe8b6 100644 --- a/tests/ui/unnecessary_ref.rs +++ b/tests/ui/unnecessary_ref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![feature(tool_attributes)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index 963d555ca56..128a3fee429 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::unneeded_field_pattern)] diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 67e04706f04..9142b3d2911 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[warn(clippy::unreadable_literal)] #[allow(unused_variables)] diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index 39aa4afdf8d..9c1800467d3 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_imports)] #![allow(dead_code)] diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 0ab89c994f4..a47a6ccfdf6 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code)] diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs index ecfdab490f6..d7d843dfc25 100644 --- a/tests/ui/unused_labels.rs +++ b/tests/ui/unused_labels.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(dead_code, clippy::items_after_statements, clippy::never_loop)] diff --git a/tests/ui/unused_lt.rs b/tests/ui/unused_lt.rs index 3aea986d28d..de13864421e 100644 --- a/tests/ui/unused_lt.rs +++ b/tests/ui/unused_lt.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused, dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::extra_unused_lifetimes)] diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index b31ccfea200..80965635a08 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] fn main() { diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 784e0c04016..6ebe8f16a90 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::use_self)] #![allow(dead_code)] diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 13ae1d67f15..b6b055e58bc 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::all)] diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index 598618365c8..a5e9caf3a67 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![deny(clippy::useless_asref)] #![allow(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 710f35da72b..9fb84866ef6 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index 4a27d1148b4..6b82b105b05 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -10,7 +10,7 @@ error: useless lint attribute --> $DIR/useless_attribute.rs:16:1 | 16 | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)` error: aborting due to 2 previous errors diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 45e51663795..e74aded5728 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::useless_vec)] diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index ff7a43fd693..3cc7c52df5d 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::while_let_loop, clippy::empty_loop, clippy::while_let_on_iterator)] diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 9a27ca11dae..7917479ed67 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_must_use)] #![warn(clippy::write_literal)] diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index f3e26ed904f..e9fcff0b3dd 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(clippy::write_literal)] #![warn(clippy::write_with_newline)] diff --git a/tests/ui/writeln_empty_string.rs b/tests/ui/writeln_empty_string.rs index 888e870667c..e272a5af88b 100644 --- a/tests/ui/writeln_empty_string.rs +++ b/tests/ui/writeln_empty_string.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index d843af1a396..d1c7424c8d7 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #![warn(clippy::wrong_self_convention)] diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index c2cbd32968f..4e2272c8e09 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -8,7 +8,7 @@ // except according to those terms. -#![feature(tool_lints)] + #[allow(unused_variables)] -- cgit 1.4.1-3-g733a5 From 9d3373137b74a403281b293b19ab9346773af073 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Thu, 11 Oct 2018 12:18:27 +0200 Subject: Remove now-useless `allow(unknown_lints)` --- clippy_lints/src/lib.rs | 2 +- src/driver.rs | 2 +- src/lib.rs | 1 - src/main.rs | 2 +- tests/ui/eta.rs | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 451374c9a47..c343cf364f6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -15,7 +15,7 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(range_contains)] -#![allow(unknown_lints, clippy::shadow_reuse, clippy::missing_docs_in_private_items)] +#![allow(clippy::shadow_reuse, clippy::missing_docs_in_private_items)] #![recursion_limit = "256"] #![feature(macro_at_most_once_rep)] diff --git a/src/driver.rs b/src/driver.rs index 6af0f0be190..9abe6bd91de 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -13,7 +13,7 @@ #![feature(rustc_private)] #![feature(try_from)] -#![allow(unknown_lints, clippy::missing_docs_in_private_items)] +#![allow(clippy::missing_docs_in_private_items)] // FIXME: switch to something more ergonomic here, once available. // (currently there is no way to opt into sysroot crates w/o `extern crate`) diff --git a/src/lib.rs b/src/lib.rs index 62c9da03278..97f1f81091d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,6 @@ #![feature(plugin_registrar)] #![feature(rustc_private)] -#![allow(unknown_lints)] #![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] diff --git a/src/main.rs b/src/main.rs index efdcc42dea3..4a1dc487cea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ #![feature(box_syntax)] #![feature(rustc_private)] -#![allow(unknown_lints, clippy::missing_docs_in_private_items)] +#![allow(clippy::missing_docs_in_private_items)] use rustc_tools_util::*; diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index e516dd6910a..dd41433d2db 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -10,7 +10,7 @@ -#![allow(unknown_lints, unused, clippy::no_effect, clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, clippy::trivially_copy_pass_by_ref)] +#![allow(unused, clippy::no_effect, clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::redundant_closure, clippy::needless_borrow)] fn main() { -- cgit 1.4.1-3-g733a5 From 3a11cd428902feafdc70c279d2dbc950f580db3f Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Sat, 17 Nov 2018 13:47:27 +0100 Subject: remove unused allow() attributes, NFC --- clippy_lints/src/consts.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 1 - clippy_lints/src/enum_variants.rs | 2 -- clippy_lints/src/eta_reduction.rs | 1 - clippy_lints/src/lib.rs | 4 ++-- clippy_lints/src/minmax.rs | 1 - clippy_lints/src/panic_unimplemented.rs | 1 - clippy_lints/src/redundant_pattern_matching.rs | 1 - clippy_lints/src/types.rs | 4 ---- clippy_lints/src/utils/author.rs | 2 -- clippy_lints/src/utils/inspector.rs | 2 -- src/driver.rs | 1 - src/main.rs | 2 -- 13 files changed, 3 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 5d509ef76f3..67c0de93496 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -293,7 +293,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { instance, promoted: None, }; - + let result = self.tcx.const_eval(self.param_env.and(gid)).ok()?; let ret = miri_to_const(self.tcx, result); if ret.is_some() { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index cac5d0da71d..9bead9c1d86 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -116,7 +116,6 @@ const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that imp const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements Copy. \ Forgetting a copy leaves the original intact."; -#[allow(missing_copy_implementations)] pub struct Pass; impl LintPass for Pass { diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 16d1e40484d..121a33f9475 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -156,8 +156,6 @@ fn partial_rmatch(post: &str, name: &str) -> usize { .count() } -// FIXME: #600 -#[allow(clippy::while_let_on_iterator)] fn check_variant( cx: &EarlyContext<'_>, threshold: u64, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 59c7f8a36db..95191b471a8 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -15,7 +15,6 @@ use crate::rustc::hir::*; use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then}; use crate::rustc_errors::Applicability; -#[allow(missing_copy_implementations)] pub struct EtaPass; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6ebe9df6a1e..3debe567cda 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -15,7 +15,7 @@ #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] #![feature(range_contains)] -#![allow(clippy::shadow_reuse, clippy::missing_docs_in_private_items)] +#![allow(clippy::missing_docs_in_private_items)] #![recursion_limit = "256"] #![feature(macro_at_most_once_rep)] @@ -1005,7 +1005,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { // only exists to let the dogfood integration test works. // Don't run clippy as an executable directly -#[allow(dead_code, clippy::print_stdout)] +#[allow(dead_code)] fn main() { panic!("Please use the cargo-clippy executable"); } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 222247307c8..4a3fcfc853e 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -35,7 +35,6 @@ declare_clippy_lint! { "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant" } -#[allow(missing_copy_implementations)] pub struct MinMaxPass; impl LintPass for MinMaxPass { diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 003c9bdf084..68b989721af 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -52,7 +52,6 @@ declare_clippy_lint! { "`unimplemented!` should not be present in production code" } -#[allow(missing_copy_implementations)] pub struct Pass; impl LintPass for Pass { diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs index 7c888b36503..130b1144329 100644 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ b/clippy_lints/src/redundant_pattern_matching.rs @@ -63,7 +63,6 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - #[allow(clippy::similar_names)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprKind::Match(ref op, ref arms, ref match_source) = expr.node { match match_source { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 035ca2b0496..c9068be838f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -34,7 +34,6 @@ use crate::utils::paths; use crate::consts::{constant, Constant}; /// Handles all the linting of funky types -#[allow(missing_copy_implementations)] pub struct TypePass; /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code. @@ -371,7 +370,6 @@ fn is_any_trait(t: &hir::Ty) -> bool { false } -#[allow(missing_copy_implementations)] pub struct LetPass; /// **What it does:** Checks for binding a unit value. @@ -447,7 +445,6 @@ declare_clippy_lint! { "comparing unit values" } -#[allow(missing_copy_implementations)] pub struct UnitCmp; impl LintPass for UnitCmp { @@ -1142,7 +1139,6 @@ declare_clippy_lint! { "usage of very complex types that might be better factored into `type` definitions" } -#[allow(missing_copy_implementations)] pub struct TypeComplexityPass { threshold: u64, } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 6650dd67b4f..d88a70e4e49 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -11,8 +11,6 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -#![allow(clippy::print_stdout, clippy::use_debug)] - use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 54ca0736c52..e750c1c9bce 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -8,8 +8,6 @@ // except according to those terms. -#![allow(clippy::print_stdout, clippy::use_debug)] - //! checks for attributes use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/src/driver.rs b/src/driver.rs index 9abe6bd91de..f99c37b8519 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -27,7 +27,6 @@ use std::convert::TryInto; use std::path::Path; use std::process::{exit, Command}; -#[allow(clippy::print_stdout)] fn show_version() { println!(env!("CARGO_PKG_VERSION")); } diff --git a/src/main.rs b/src/main.rs index 4a1dc487cea..be28fe12899 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,12 +41,10 @@ it to allow or deny lints from the code, eg.: #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] "#; -#[allow(clippy::print_stdout)] fn show_help() { println!("{}", CARGO_CLIPPY_HELP); } -#[allow(clippy::print_stdout)] fn show_version() { let version_info = rustc_tools_util::get_version_info!(); println!("{}", version_info); -- cgit 1.4.1-3-g733a5 From d71c871568c4febd047ab46be6370a36aefcb882 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Tue, 27 Nov 2018 21:12:13 +0100 Subject: Run rustfmt on src --- src/driver.rs | 238 +++++++++++++++++++++++++++++----------------------------- src/lib.rs | 2 - src/main.rs | 5 +- 3 files changed, 121 insertions(+), 124 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index f99c37b8519..fd9c8693c95 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -7,11 +7,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] - #![feature(try_from)] #![allow(clippy::missing_docs_in_private_items)] @@ -33,126 +31,128 @@ fn show_version() { pub fn main() { rustc_driver::init_rustc_env_logger(); - exit(rustc_driver::run(move || { - use std::env; - - if std::env::args().any(|a| a == "--version" || a == "-V") { - show_version(); - exit(0); - } - - let sys_root = option_env!("SYSROOT") - .map(String::from) - .or_else(|| std::env::var("SYSROOT").ok()) - .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programmatically, so we ignore this/ - let mut orig_args: Vec<String> = env::args().collect(); - if orig_args.len() <= 1 { - std::process::exit(1); - } - if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { - // we still want to be able to invoke it normally though - orig_args.remove(1); - } - // this conditional check for the --sysroot flag is there so users can call - // `clippy_driver` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() - } else { - orig_args - .clone() - .into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - - // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); - - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend( - extra_args - .split("__CLIPPY_HACKERY__") - .filter_map(|s| if s.is_empty() { + exit( + rustc_driver::run(move || { + use std::env; + + if std::env::args().any(|a| a == "--version" || a == "-V") { + show_version(); + exit(0); + } + + let sys_root = option_env!("SYSROOT") + .map(String::from) + .or_else(|| std::env::var("SYSROOT").ok()) + .or_else(|| { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) + }) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); + + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programmatically, so we ignore this/ + let mut orig_args: Vec<String> = env::args().collect(); + if orig_args.len() <= 1 { + std::process::exit(1); + } + if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args + .clone() + .into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") + || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); + + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + if let Ok(extra_args) = env::var("CLIPPY_ARGS") { + args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { + if s.is_empty() { None } else { Some(s.to_string()) - }) - ); - } - } - - let mut controller = CompileController::basic(); - if clippy_enabled { - controller.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 crate must be parsed", - ) - .span, - ); - registry.args_hidden = Some(Vec::new()); - - let conf = clippy_lints::read_conf(®istry); - clippy_lints::register_plugins(&mut registry, &conf); - - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); + } + })); } - clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - }); - } - controller.compilation_done.stop = Compilation::Stop; + } - let args = args; - rustc_driver::run_compiler(&args, Box::new(controller), None, None) - }).try_into().expect("exit code too large")) + let mut controller = CompileController::basic(); + if clippy_enabled { + controller.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 crate must be parsed", + ) + .span, + ); + registry.args_hidden = Some(Vec::new()); + + let conf = clippy_lints::read_conf(®istry); + clippy_lints::register_plugins(&mut registry, &conf); + + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, (to, deprecated_name)) in lint_groups { + ls.register_group(Some(sess), true, name, deprecated_name, to); + } + clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + }); + } + controller.compilation_done.stop = Compilation::Stop; + + let args = args; + rustc_driver::run_compiler(&args, Box::new(controller), None, None) + }) + .try_into() + .expect("exit code too large"), + ) } diff --git a/src/lib.rs b/src/lib.rs index 97f1f81091d..4069472612d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] - #![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] diff --git a/src/main.rs b/src/main.rs index be28fe12899..6c5cfe69166 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] - #![allow(clippy::missing_docs_in_private_items)] use rustc_tools_util::*; @@ -106,7 +104,8 @@ where .into_os_string() }, ) - }).map(|p| ("CARGO_TARGET_DIR", p)); + }) + .map(|p| ("CARGO_TARGET_DIR", p)); let exit_status = std::process::Command::new("cargo") .args(&args) -- cgit 1.4.1-3-g733a5 From 69813d6faf2c9caaf2e8131e6218bd056366da53 Mon Sep 17 00:00:00 2001 From: O01eg <o01eg@yandex.ru> Date: Thu, 4 Oct 2018 10:58:09 +0300 Subject: Don't try to determine sysroot. rustc_driver will use default value. --- src/driver.rs | 44 ++++++-------------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index fd9c8693c95..6b327d08207 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -23,7 +23,7 @@ use self::rustc_driver::{driver::CompileController, Compilation}; use std::convert::TryInto; use std::path::Path; -use std::process::{exit, Command}; +use std::process::exit; fn show_version() { println!(env!("CARGO_PKG_VERSION")); @@ -40,54 +40,22 @@ pub fn main() { exit(0); } - let sys_root = option_env!("SYSROOT") - .map(String::from) - .or_else(|| std::env::var("SYSROOT").ok()) - .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let mut orig_args: Vec<String> = env::args().collect(); - if orig_args.len() <= 1 { + let mut args: Vec<String> = env::args().collect(); + if args.len() <= 1 { std::process::exit(1); } - if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { + if Path::new(&args[1]).file_stem() == Some("rustc".as_ref()) { // we still want to be able to invoke it normally though - orig_args.remove(1); + args.remove(1); } - // this conditional check for the --sysroot flag is there so users can call - // `clippy_driver` directly - // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() - } else { - orig_args - .clone() - .into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); + || args.iter().any(|s| s == "--emit=dep-info,metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); -- cgit 1.4.1-3-g733a5 From a9509eb5984c1bb14fbba687cba7117a4aee8b02 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Fri, 14 Dec 2018 10:15:56 +0100 Subject: Revert "Merge pull request #3257 from o01eg/remove-sysroot" This reverts commit 041c49c1ed11b016d6ab9379643bb1da2adf5bfe, reversing changes made to 1df5766cbb559aab0ad5c2296d8b768182b5186c. --- src/driver.rs | 44 ++++++++++++++++++++++++++++++++++++++------ tests/compile-test.rs | 29 +---------------------------- tests/dogfood.rs | 27 --------------------------- 3 files changed, 39 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 6b327d08207..fd9c8693c95 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -23,7 +23,7 @@ use self::rustc_driver::{driver::CompileController, Compilation}; use std::convert::TryInto; use std::path::Path; -use std::process::exit; +use std::process::{exit, Command}; fn show_version() { println!(env!("CARGO_PKG_VERSION")); @@ -40,22 +40,54 @@ pub fn main() { exit(0); } + let sys_root = option_env!("SYSROOT") + .map(String::from) + .or_else(|| std::env::var("SYSROOT").ok()) + .or_else(|| { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) + }) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let mut args: Vec<String> = env::args().collect(); - if args.len() <= 1 { + let mut orig_args: Vec<String> = env::args().collect(); + if orig_args.len() <= 1 { std::process::exit(1); } - if Path::new(&args[1]).file_stem() == Some("rustc".as_ref()) { + if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { // we still want to be able to invoke it normally though - args.remove(1); + orig_args.remove(1); } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args + .clone() + .into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") - || args.iter().any(|s| s == "--emit=dep-info,metadata"); + || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 62fa17d388a..5cb37b6b6fd 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -17,7 +17,6 @@ use std::ffi::OsStr; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use std::process::Command; fn clippy_driver_path() -> PathBuf { if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { @@ -43,28 +42,6 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn rustc_sysroot_path() -> PathBuf { - option_env!("SYSROOT") - .map(String::from) - .or_else(|| std::env::var("SYSROOT").ok()) - .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - .into() -} - fn config(mode: &str, dir: PathBuf) -> compiletest::Config { let mut config = compiletest::Config::default(); @@ -78,11 +55,7 @@ fn config(mode: &str, dir: PathBuf) -> compiletest::Config { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - config.target_rustcflags = Some(format!( - "-L {0} -L {0}/deps -Dwarnings --sysroot {1}", - host_libs().display(), - rustc_sysroot_path().display() - )); + config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display())); config.mode = cfg_mode; config.build_base = if rustc_test_suite().is_some() { diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 69f4f9901b7..c1f02b9fcef 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -7,31 +7,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::path::PathBuf; -use std::process::Command; - -fn rustc_sysroot_path() -> PathBuf { - option_env!("SYSROOT") - .map(String::from) - .or_else(|| std::env::var("SYSROOT").ok()) - .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust") - .into() -} - #[test] fn dogfood() { if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) { @@ -46,7 +21,6 @@ fn dogfood() { let output = std::process::Command::new(clippy_cmd) .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") - .env("RUSTFLAGS", format!("--sysroot {}", rustc_sysroot_path().display())) .arg("clippy") .arg("--all-targets") .arg("--all-features") @@ -85,7 +59,6 @@ fn dogfood_tests() { let output = std::process::Command::new(&clippy_cmd) .current_dir(root_dir.join(d)) .env("CLIPPY_DOGFOOD", "1") - .env("RUSTFLAGS", format!("--sysroot {}", rustc_sysroot_path().display())) .arg("clippy") .arg("--") .args(&["-D", "clippy::all"]) -- cgit 1.4.1-3-g733a5 From 0516c2e04a620493fe92b82c4cdecf32dae2f96a Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Mon, 17 Dec 2018 13:58:41 +0100 Subject: Move renaming to the right place --- clippy_lints/src/lib.rs | 4 +++- src/driver.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8f528ea83e3..5c1469536f5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1028,8 +1028,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { unwrap::PANICKING_UNWRAP, unwrap::UNNECESSARY_UNWRAP, ]); +} - store.register_renamed("stutter", "module_name_repeat"); +pub fn register_renamed(ls: &mut rustc::lint::LintStore) { + ls.register_renamed("clippy::stutter", "clippy::module_name_repeat"); } // only exists to let the dogfood integration test works. diff --git a/src/driver.rs b/src/driver.rs index 6b327d08207..0df2d898860 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -110,6 +110,7 @@ pub fn main() { ls.register_group(Some(sess), true, name, deprecated_name, to); } clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); + clippy_lints::register_renamed(&mut ls); sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); sess.plugin_attributes.borrow_mut().extend(attributes); -- cgit 1.4.1-3-g733a5 From b5f6eb6e75b983b33f4f37a11300f5679443e9c1 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Wed, 19 Dec 2018 11:41:27 -0800 Subject: Link to `rustc_driver` crate in plugin This is in anticipation for rust-lang/rust#56987 where the `rustc_driver` crate being linked in will be required to link correctly against the compiler. In the meantime it should be harmless otherwise! --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4069472612d..ef6f4cd7b3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ // FIXME: switch to something more ergonomic here, once available. // (currently there is no way to opt into sysroot crates w/o `extern crate`) #[allow(unused_extern_crates)] +extern crate rustc_driver; +#[allow(unused_extern_crates)] extern crate rustc_plugin; use self::rustc_plugin::Registry; -- cgit 1.4.1-3-g733a5 From 5f0617b92fef67dc24c48f19bc9ade4314ca9015 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Tue, 25 Dec 2018 17:11:57 +0100 Subject: update CARGO_CLIPPY_HELP string to suggest tool lints. --- src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 6c5cfe69166..369528f1954 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,10 +33,9 @@ with: -D --deny OPT Set lint denied -F --forbid OPT Set lint forbidden -The feature `cargo-clippy` is automatically defined for convenience. You can use -it to allow or deny lints from the code, eg.: +You can use tool lints to allow or deny lints from your code, eg.: - #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] + #[allow(clippy::needless_lifetimes)] "#; fn show_help() { -- cgit 1.4.1-3-g733a5 From 38d4ac7ceaf8ace26864e847c8280dc66410587c Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Mon, 7 Jan 2019 22:33:18 +0100 Subject: Remove all copyright license headers Discussion previously happened in https://github.com/rust-lang/rust/pull/43498 --- .github/deploy.sh | 11 --- COPYRIGHT | 2 +- README.md | 2 +- build.rs | 9 --- ci/base-tests.sh | 11 --- ci/integration-tests.sh | 10 --- clippy_dev/src/lib.rs | 9 --- clippy_dev/src/main.rs | 9 --- clippy_dummy/build.rs | 12 +-- clippy_dummy/src/main.rs | 10 --- clippy_lints/src/approx_const.rs | 9 --- clippy_lints/src/arithmetic.rs | 9 --- clippy_lints/src/assign_ops.rs | 9 --- clippy_lints/src/attrs.rs | 9 --- clippy_lints/src/bit_mask.rs | 9 --- clippy_lints/src/blacklisted_name.rs | 9 --- clippy_lints/src/block_in_if_condition.rs | 9 --- clippy_lints/src/booleans.rs | 9 --- clippy_lints/src/bytecount.rs | 9 --- clippy_lints/src/cargo_common_metadata.rs | 9 --- clippy_lints/src/collapsible_if.rs | 9 --- clippy_lints/src/const_static_lifetime.rs | 9 --- clippy_lints/src/consts.rs | 10 --- clippy_lints/src/copies.rs | 9 --- clippy_lints/src/copy_iterator.rs | 9 --- clippy_lints/src/cyclomatic_complexity.rs | 9 --- clippy_lints/src/default_trait_access.rs | 9 --- clippy_lints/src/deprecated_lints.rs | 10 --- clippy_lints/src/derive.rs | 9 --- clippy_lints/src/doc.rs | 9 --- clippy_lints/src/double_comparison.rs | 9 --- clippy_lints/src/double_parens.rs | 9 --- clippy_lints/src/drop_forget_ref.rs | 9 --- clippy_lints/src/duration_subsec.rs | 9 --- clippy_lints/src/else_if_without_else.rs | 9 --- clippy_lints/src/empty_enum.rs | 9 --- clippy_lints/src/entry.rs | 9 --- clippy_lints/src/enum_clike.rs | 9 --- clippy_lints/src/enum_glob_use.rs | 9 --- clippy_lints/src/enum_variants.rs | 9 --- clippy_lints/src/eq_op.rs | 9 --- clippy_lints/src/erasing_op.rs | 9 --- clippy_lints/src/escape.rs | 9 --- clippy_lints/src/eta_reduction.rs | 9 --- clippy_lints/src/eval_order_dependence.rs | 9 --- clippy_lints/src/excessive_precision.rs | 9 --- clippy_lints/src/explicit_write.rs | 9 --- clippy_lints/src/fallible_impl_from.rs | 9 --- clippy_lints/src/format.rs | 9 --- clippy_lints/src/formatting.rs | 9 --- clippy_lints/src/functions.rs | 9 --- clippy_lints/src/identity_conversion.rs | 9 --- clippy_lints/src/identity_op.rs | 9 --- clippy_lints/src/if_not_else.rs | 9 --- clippy_lints/src/implicit_return.rs | 9 --- clippy_lints/src/indexing_slicing.rs | 9 --- clippy_lints/src/infallible_destructuring_match.rs | 9 --- clippy_lints/src/infinite_iter.rs | 9 --- clippy_lints/src/inherent_impl.rs | 9 --- clippy_lints/src/inline_fn_without_body.rs | 9 --- clippy_lints/src/int_plus_one.rs | 9 --- clippy_lints/src/invalid_ref.rs | 9 --- clippy_lints/src/items_after_statements.rs | 9 --- clippy_lints/src/large_enum_variant.rs | 9 --- clippy_lints/src/len_zero.rs | 9 --- clippy_lints/src/let_if_seq.rs | 9 --- clippy_lints/src/lib.rs | 9 --- clippy_lints/src/lifetimes.rs | 9 --- clippy_lints/src/literal_representation.rs | 9 --- clippy_lints/src/loops.rs | 9 --- clippy_lints/src/map_clone.rs | 9 --- clippy_lints/src/map_unit_fn.rs | 9 --- clippy_lints/src/matches.rs | 9 --- clippy_lints/src/mem_discriminant.rs | 9 --- clippy_lints/src/mem_forget.rs | 9 --- clippy_lints/src/mem_replace.rs | 9 --- clippy_lints/src/methods/mod.rs | 9 --- clippy_lints/src/methods/unnecessary_filter_map.rs | 9 --- clippy_lints/src/minmax.rs | 9 --- clippy_lints/src/misc.rs | 9 --- clippy_lints/src/misc_early.rs | 9 --- clippy_lints/src/missing_doc.rs | 22 ------ clippy_lints/src/missing_inline.rs | 20 ----- clippy_lints/src/multiple_crate_versions.rs | 9 --- clippy_lints/src/mut_mut.rs | 9 --- clippy_lints/src/mut_reference.rs | 9 --- clippy_lints/src/mutex_atomic.rs | 9 --- clippy_lints/src/needless_bool.rs | 9 --- clippy_lints/src/needless_borrow.rs | 9 --- clippy_lints/src/needless_borrowed_ref.rs | 9 --- clippy_lints/src/needless_continue.rs | 9 --- clippy_lints/src/needless_pass_by_value.rs | 9 --- clippy_lints/src/needless_update.rs | 9 --- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 9 --- clippy_lints/src/neg_multiply.rs | 9 --- clippy_lints/src/new_without_default.rs | 9 --- clippy_lints/src/no_effect.rs | 9 --- clippy_lints/src/non_copy_const.rs | 9 --- clippy_lints/src/non_expressive_names.rs | 9 --- clippy_lints/src/ok_if_let.rs | 9 --- clippy_lints/src/open_options.rs | 9 --- clippy_lints/src/overflow_check_conditional.rs | 9 --- clippy_lints/src/panic_unimplemented.rs | 9 --- clippy_lints/src/partialeq_ne_impl.rs | 9 --- clippy_lints/src/precedence.rs | 9 --- clippy_lints/src/ptr.rs | 9 --- clippy_lints/src/ptr_offset_with_cast.rs | 9 --- clippy_lints/src/question_mark.rs | 9 --- clippy_lints/src/ranges.rs | 9 --- clippy_lints/src/redundant_clone.rs | 9 --- clippy_lints/src/redundant_field_names.rs | 9 --- clippy_lints/src/redundant_pattern_matching.rs | 9 --- clippy_lints/src/reference.rs | 9 --- clippy_lints/src/regex.rs | 9 --- clippy_lints/src/replace_consts.rs | 9 --- clippy_lints/src/returns.rs | 9 --- clippy_lints/src/serde_api.rs | 9 --- clippy_lints/src/shadow.rs | 9 --- clippy_lints/src/slow_vector_initialization.rs | 9 --- clippy_lints/src/strings.rs | 9 --- clippy_lints/src/suspicious_trait_impl.rs | 9 --- clippy_lints/src/swap.rs | 9 --- clippy_lints/src/temporary_assignment.rs | 9 --- clippy_lints/src/transmute.rs | 9 --- clippy_lints/src/trivially_copy_pass_by_ref.rs | 9 --- clippy_lints/src/types.rs | 10 --- clippy_lints/src/unicode.rs | 9 --- clippy_lints/src/unsafe_removed_from_name.rs | 9 --- clippy_lints/src/unused_io_amount.rs | 9 --- clippy_lints/src/unused_label.rs | 9 --- clippy_lints/src/unwrap.rs | 9 --- clippy_lints/src/use_self.rs | 9 --- clippy_lints/src/utils/author.rs | 9 --- clippy_lints/src/utils/camel_case.rs | 9 --- clippy_lints/src/utils/comparisons.rs | 9 --- clippy_lints/src/utils/conf.rs | 9 --- clippy_lints/src/utils/constants.rs | 9 --- clippy_lints/src/utils/higher.rs | 9 --- clippy_lints/src/utils/hir_utils.rs | 9 --- clippy_lints/src/utils/inspector.rs | 9 --- clippy_lints/src/utils/internal_lints.rs | 9 --- clippy_lints/src/utils/mod.rs | 9 --- clippy_lints/src/utils/paths.rs | 9 --- clippy_lints/src/utils/ptr.rs | 9 --- clippy_lints/src/utils/sugg.rs | 9 --- clippy_lints/src/utils/usage.rs | 9 --- clippy_lints/src/vec.rs | 9 --- clippy_lints/src/wildcard_dependencies.rs | 9 --- clippy_lints/src/write.rs | 9 --- clippy_lints/src/zero_div_zero.rs | 9 --- clippy_workspace_tests/src/main.rs | 10 --- clippy_workspace_tests/subcrate/src/lib.rs | 10 --- mini-macro/src/lib.rs | 10 --- pre_publish.sh | 11 --- rustc_tools_util/README.md | 2 +- rustc_tools_util/src/lib.rs | 9 --- src/driver.rs | 9 --- src/lib.rs | 9 --- src/main.rs | 9 --- tests/auxiliary/test_macro.rs | 9 --- tests/compile-test.rs | 9 --- tests/dogfood.rs | 9 --- tests/matches.rs | 9 --- tests/needless_continue_helpers.rs | 9 --- tests/run-pass/associated-constant-ice.rs | 9 --- tests/run-pass/cc_seme.rs | 9 --- tests/run-pass/enum-glob-import-crate.rs | 9 --- tests/run-pass/ice-1588.rs | 9 --- tests/run-pass/ice-1782.rs | 9 --- tests/run-pass/ice-1969.rs | 9 --- tests/run-pass/ice-2499.rs | 9 --- tests/run-pass/ice-2594.rs | 9 --- tests/run-pass/ice-2727.rs | 9 --- tests/run-pass/ice-2760.rs | 9 --- tests/run-pass/ice-2774.rs | 9 --- tests/run-pass/ice-2865.rs | 9 --- tests/run-pass/ice-3151.rs | 9 --- tests/run-pass/ice-3462.rs | 9 --- tests/run-pass/ice-700.rs | 9 --- tests/run-pass/ice_exacte_size.rs | 9 --- tests/run-pass/if_same_then_else.rs | 9 --- tests/run-pass/issue-2862.rs | 9 --- tests/run-pass/issue-825.rs | 9 --- tests/run-pass/issues_loop_mut_cond.rs | 9 --- tests/run-pass/match_same_arms_const.rs | 9 --- tests/run-pass/mut_mut_macro.rs | 9 --- tests/run-pass/needless_borrow_fp.rs | 9 --- tests/run-pass/needless_lifetimes_impl_trait.rs | 9 --- tests/run-pass/procedural_macro.rs | 9 --- tests/run-pass/regressions.rs | 9 --- tests/run-pass/returns.rs | 9 --- tests/run-pass/single-match-else.rs | 9 --- tests/run-pass/used_underscore_binding_macro.rs | 9 --- tests/run-pass/whitelist/conf_whitelisted.rs | 9 --- tests/ui-toml/bad_toml/conf_bad_toml.rs | 9 --- tests/ui-toml/bad_toml_type/conf_bad_type.rs | 9 --- .../toml_blacklist/conf_french_blacklisted_name.rs | 9 --- .../conf_french_blacklisted_name.stderr | 14 ++-- tests/ui-toml/toml_trivially_copy/test.rs | 9 --- tests/ui-toml/toml_trivially_copy/test.stderr | 4 +- tests/ui-toml/toml_unknown_key/conf_unknown_key.rs | 9 --- tests/ui-toml/update-all-references.sh | 10 --- tests/ui-toml/update-references.sh | 10 --- tests/ui/absurd-extreme-comparisons.rs | 9 --- tests/ui/absurd-extreme-comparisons.stderr | 36 ++++----- tests/ui/approx_const.rs | 9 --- tests/ui/approx_const.stderr | 38 ++++----- tests/ui/arithmetic.rs | 9 --- tests/ui/arithmetic.stderr | 22 +++--- tests/ui/assign_ops.rs | 9 --- tests/ui/assign_ops.stderr | 18 ++--- tests/ui/assign_ops2.rs | 9 --- tests/ui/assign_ops2.stderr | 20 ++--- tests/ui/attrs.rs | 9 --- tests/ui/attrs.stderr | 6 +- tests/ui/author.rs | 9 --- tests/ui/author/call.rs | 9 --- tests/ui/author/for_loop.rs | 9 --- tests/ui/author/matches.rs | 9 --- tests/ui/author/matches.stderr | 4 +- tests/ui/bit_masks.rs | 9 --- tests/ui/bit_masks.stderr | 34 ++++---- tests/ui/blacklisted_name.rs | 9 --- tests/ui/blacklisted_name.stderr | 28 +++---- tests/ui/block_in_if_condition.rs | 9 --- tests/ui/block_in_if_condition.stderr | 10 +-- tests/ui/bool_comparison.rs | 9 --- tests/ui/bool_comparison.stderr | 28 +++---- tests/ui/booleans.rs | 9 --- tests/ui/booleans.stderr | 60 +++++++------- tests/ui/borrow_box.rs | 9 --- tests/ui/borrow_box.stderr | 10 +-- tests/ui/box_vec.rs | 9 --- tests/ui/box_vec.stderr | 2 +- tests/ui/builtin-type-shadow.rs | 9 --- tests/ui/builtin-type-shadow.stderr | 4 +- tests/ui/bytecount.rs | 9 --- tests/ui/bytecount.stderr | 8 +- tests/ui/cast.rs | 9 --- tests/ui/cast.stderr | 56 ++++++------- tests/ui/cast_alignment.rs | 9 --- tests/ui/cast_alignment.stderr | 4 +- tests/ui/cast_lossless_float.fixed | 9 --- tests/ui/cast_lossless_float.rs | 9 --- tests/ui/cast_lossless_float.stderr | 20 ++--- tests/ui/cast_lossless_integer.fixed | 9 --- tests/ui/cast_lossless_integer.rs | 9 --- tests/ui/cast_lossless_integer.stderr | 36 ++++----- tests/ui/cast_size.rs | 9 --- tests/ui/cast_size.stderr | 38 ++++----- tests/ui/cfg_attr_rustfmt.rs | 9 --- tests/ui/cfg_attr_rustfmt.stderr | 6 +- tests/ui/char_lit_as_u8.rs | 9 --- tests/ui/char_lit_as_u8.stderr | 2 +- tests/ui/checked_unwrap.rs | 9 --- tests/ui/checked_unwrap.stderr | 72 ++++++++--------- tests/ui/clone_on_copy_impl.rs | 9 --- tests/ui/clone_on_copy_mut.rs | 9 --- tests/ui/cmp_nan.rs | 9 --- tests/ui/cmp_nan.stderr | 24 +++--- tests/ui/cmp_null.rs | 9 --- tests/ui/cmp_null.stderr | 4 +- tests/ui/cmp_owned.rs | 9 --- tests/ui/cmp_owned.stderr | 18 ++--- tests/ui/collapsible_if.rs | 9 --- tests/ui/collapsible_if.stderr | 28 +++---- tests/ui/complex_types.rs | 9 --- tests/ui/complex_types.stderr | 30 +++---- tests/ui/const_static_lifetime.rs | 9 --- tests/ui/const_static_lifetime.stderr | 26 +++--- tests/ui/copies.rs | 9 --- tests/ui/copies.stderr | 82 +++++++++---------- tests/ui/copy_iterator.rs | 9 --- tests/ui/copy_iterator.stderr | 2 +- tests/ui/cstring.rs | 9 --- tests/ui/cstring.stderr | 4 +- tests/ui/cyclomatic_complexity.rs | 9 --- tests/ui/cyclomatic_complexity.stderr | 40 +++++----- tests/ui/cyclomatic_complexity_attr_used.rs | 9 --- tests/ui/cyclomatic_complexity_attr_used.stderr | 2 +- tests/ui/decimal_literal_representation.rs | 9 --- tests/ui/decimal_literal_representation.stderr | 10 +-- tests/ui/default_trait_access.rs | 9 --- tests/ui/default_trait_access.stderr | 16 ++-- tests/ui/deprecated.rs | 9 --- tests/ui/deprecated.stderr | 10 +-- tests/ui/derive.rs | 9 --- tests/ui/derive.stderr | 28 +++---- tests/ui/diverging_sub_expression.rs | 9 --- tests/ui/diverging_sub_expression.stderr | 12 +-- tests/ui/dlist.rs | 9 --- tests/ui/dlist.stderr | 12 +-- tests/ui/doc.rs | 9 --- tests/ui/doc.stderr | 62 +++++++-------- tests/ui/double_comparison.fixed | 9 --- tests/ui/double_comparison.rs | 9 --- tests/ui/double_comparison.stderr | 16 ++-- tests/ui/double_neg.rs | 9 --- tests/ui/double_neg.stderr | 2 +- tests/ui/double_parens.rs | 9 --- tests/ui/double_parens.stderr | 12 +-- tests/ui/drop_forget_copy.rs | 9 --- tests/ui/drop_forget_copy.stderr | 24 +++--- tests/ui/drop_forget_ref.rs | 9 --- tests/ui/drop_forget_ref.stderr | 72 ++++++++--------- tests/ui/duplicate_underscore_argument.rs | 9 --- tests/ui/duplicate_underscore_argument.stderr | 2 +- tests/ui/duration_subsec.rs | 9 --- tests/ui/duration_subsec.stderr | 10 +-- tests/ui/else_if_without_else.rs | 9 --- tests/ui/else_if_without_else.stderr | 4 +- tests/ui/empty_enum.rs | 9 --- tests/ui/empty_enum.stderr | 4 +- tests/ui/empty_line_after_outer_attribute.rs | 9 --- tests/ui/empty_line_after_outer_attribute.stderr | 12 +-- tests/ui/entry.rs | 9 --- tests/ui/entry.stderr | 14 ++-- tests/ui/enum_glob_use.rs | 9 --- tests/ui/enum_glob_use.stderr | 4 +- tests/ui/enum_variants.rs | 9 --- tests/ui/enum_variants.stderr | 20 ++--- tests/ui/enums_clike.rs | 9 --- tests/ui/enums_clike.stderr | 16 ++-- tests/ui/eq_op.rs | 9 --- tests/ui/eq_op.stderr | 68 ++++++++-------- tests/ui/erasing_op.rs | 9 --- tests/ui/erasing_op.stderr | 6 +- tests/ui/escape_analysis.rs | 9 --- tests/ui/escape_analysis.stderr | 4 +- tests/ui/eta.rs | 9 --- tests/ui/eta.stderr | 10 +-- tests/ui/eval_order_dependence.rs | 9 --- tests/ui/eval_order_dependence.stderr | 16 ++-- tests/ui/excessive_precision.rs | 9 --- tests/ui/excessive_precision.stderr | 36 ++++----- tests/ui/expect_fun_call.rs | 9 --- tests/ui/expect_fun_call.stderr | 12 +-- tests/ui/explicit_counter_loop.rs | 9 --- tests/ui/explicit_counter_loop.stderr | 8 +- tests/ui/explicit_write.rs | 9 --- tests/ui/explicit_write.stderr | 16 ++-- tests/ui/fallible_impl_from.rs | 9 --- tests/ui/fallible_impl_from.stderr | 18 ++--- tests/ui/filter_methods.rs | 9 --- tests/ui/filter_methods.stderr | 8 +- tests/ui/float_cmp.rs | 9 --- tests/ui/float_cmp.stderr | 12 +-- tests/ui/float_cmp_const.rs | 9 --- tests/ui/float_cmp_const.stderr | 28 +++---- tests/ui/fn_to_numeric_cast.rs | 9 --- tests/ui/fn_to_numeric_cast.stderr | 46 +++++------ tests/ui/for_kv_map.rs | 9 --- tests/ui/for_kv_map.stderr | 10 +-- tests/ui/for_loop.rs | 9 --- tests/ui/for_loop.stderr | 92 +++++++++++----------- tests/ui/for_loop_over_option_result.rs | 9 --- tests/ui/for_loop_over_option_result.stderr | 16 ++-- tests/ui/format.rs | 10 --- tests/ui/format.stderr | 18 ++--- tests/ui/formatting.rs | 9 --- tests/ui/formatting.stderr | 26 +++--- tests/ui/functions.rs | 9 --- tests/ui/functions.stderr | 24 +++--- tests/ui/fxhash.rs | 9 --- tests/ui/fxhash.stderr | 12 +-- tests/ui/get_unwrap.fixed | 9 --- tests/ui/get_unwrap.rs | 9 --- tests/ui/get_unwrap.stderr | 26 +++--- tests/ui/ice-2636.rs | 9 --- tests/ui/ice-2636.stderr | 2 +- tests/ui/identity_conversion.rs | 9 --- tests/ui/identity_conversion.stderr | 22 +++--- tests/ui/identity_op.rs | 9 --- tests/ui/identity_op.stderr | 16 ++-- tests/ui/if_not_else.rs | 9 --- tests/ui/if_not_else.stderr | 4 +- tests/ui/impl.rs | 9 --- tests/ui/impl.stderr | 8 +- tests/ui/implicit_hasher.rs | 9 --- tests/ui/implicit_hasher.stderr | 20 ++--- tests/ui/implicit_return.rs | 9 --- tests/ui/implicit_return.stderr | 20 ++--- tests/ui/inconsistent_digit_grouping.rs | 9 --- tests/ui/inconsistent_digit_grouping.stderr | 10 +-- tests/ui/indexing_slicing.rs | 9 --- tests/ui/indexing_slicing.stderr | 86 ++++++++++---------- tests/ui/infallible_destructuring_match.rs | 9 --- tests/ui/infallible_destructuring_match.stderr | 6 +- tests/ui/infinite_iter.rs | 9 --- tests/ui/infinite_iter.stderr | 34 ++++---- tests/ui/infinite_loop.rs | 9 --- tests/ui/infinite_loop.stderr | 18 ++--- tests/ui/inline_fn_without_body.rs | 9 --- tests/ui/inline_fn_without_body.stderr | 6 +- tests/ui/int_plus_one.rs | 9 --- tests/ui/int_plus_one.stderr | 8 +- tests/ui/invalid_ref.rs | 9 --- tests/ui/invalid_ref.stderr | 12 +-- tests/ui/invalid_upcast_comparisons.rs | 9 --- tests/ui/invalid_upcast_comparisons.stderr | 54 ++++++------- tests/ui/issue-3145.rs | 9 --- tests/ui/issue-3145.stderr | 2 +- tests/ui/issue_2356.rs | 9 --- tests/ui/issue_2356.stderr | 4 +- tests/ui/item_after_statement.rs | 9 --- tests/ui/item_after_statement.stderr | 4 +- tests/ui/iter_skip_next.rs | 9 --- tests/ui/iter_skip_next.stderr | 8 +- tests/ui/large_digit_groups.rs | 9 --- tests/ui/large_digit_groups.stderr | 12 +-- tests/ui/large_enum_variant.rs | 9 --- tests/ui/large_enum_variant.stderr | 18 ++--- tests/ui/len_zero.rs | 9 --- tests/ui/len_zero.stderr | 38 ++++----- tests/ui/let_if_seq.rs | 9 --- tests/ui/let_if_seq.stderr | 8 +- tests/ui/let_return.rs | 9 --- tests/ui/let_return.stderr | 8 +- tests/ui/let_unit.rs | 9 --- tests/ui/let_unit.stderr | 4 +- tests/ui/lifetimes.rs | 9 --- tests/ui/lifetimes.stderr | 30 +++---- tests/ui/literals.rs | 9 --- tests/ui/literals.stderr | 62 +++++++-------- tests/ui/map_clone.rs | 9 --- tests/ui/map_clone.stderr | 6 +- tests/ui/map_flatten.rs | 9 --- tests/ui/map_flatten.stderr | 2 +- tests/ui/map_unit_fn.rs | 9 --- tests/ui/match_bool.rs | 9 --- tests/ui/match_bool.stderr | 16 ++-- tests/ui/match_overlapping_arm.rs | 9 --- tests/ui/match_overlapping_arm.stderr | 20 ++--- tests/ui/matches.rs | 9 --- tests/ui/matches.stderr | 74 ++++++++--------- tests/ui/mem_discriminant.rs | 9 --- tests/ui/mem_discriminant.stderr | 26 +++--- tests/ui/mem_forget.rs | 9 --- tests/ui/mem_forget.stderr | 6 +- tests/ui/mem_replace.rs | 2 +- tests/ui/methods.rs | 9 --- tests/ui/methods.stderr | 86 ++++++++++---------- tests/ui/min_max.rs | 9 --- tests/ui/min_max.stderr | 14 ++-- tests/ui/missing-doc.rs | 22 ------ tests/ui/missing-doc.stderr | 78 +++++++++--------- tests/ui/missing_inline.rs | 21 ----- tests/ui/missing_inline.stderr | 12 +-- tests/ui/module_inception.rs | 9 --- tests/ui/module_inception.stderr | 4 +- tests/ui/module_name_repetitions.rs | 9 --- tests/ui/module_name_repetitions.stderr | 10 +-- tests/ui/modulo_one.rs | 9 --- tests/ui/modulo_one.stderr | 2 +- tests/ui/mut_from_ref.rs | 9 --- tests/ui/mut_from_ref.stderr | 20 ++--- tests/ui/mut_mut.rs | 9 --- tests/ui/mut_mut.stderr | 18 ++--- tests/ui/mut_range_bound.rs | 9 --- tests/ui/mut_range_bound.stderr | 10 +-- tests/ui/mut_reference.rs | 9 --- tests/ui/mut_reference.stderr | 6 +- tests/ui/mutex_atomic.rs | 9 --- tests/ui/mutex_atomic.stderr | 14 ++-- tests/ui/needless_bool.rs | 9 --- tests/ui/needless_bool.stderr | 30 +++---- tests/ui/needless_borrow.rs | 9 --- tests/ui/needless_borrow.stderr | 12 +-- tests/ui/needless_borrowed_ref.rs | 9 --- tests/ui/needless_borrowed_ref.stderr | 8 +- tests/ui/needless_collect.rs | 9 --- tests/ui/needless_collect.stderr | 8 +- tests/ui/needless_continue.rs | 9 --- tests/ui/needless_continue.stderr | 4 +- tests/ui/needless_pass_by_value.rs | 9 --- tests/ui/needless_pass_by_value.stderr | 52 ++++++------ tests/ui/needless_pass_by_value_proc_macro.rs | 9 --- tests/ui/needless_range_loop.rs | 9 --- tests/ui/needless_range_loop.stderr | 16 ++-- tests/ui/needless_return.rs | 9 --- tests/ui/needless_return.stderr | 16 ++-- tests/ui/needless_update.rs | 9 --- tests/ui/needless_update.stderr | 2 +- tests/ui/neg_cmp_op_on_partial_ord.rs | 9 --- tests/ui/neg_cmp_op_on_partial_ord.stderr | 8 +- tests/ui/neg_multiply.rs | 9 --- tests/ui/neg_multiply.stderr | 4 +- tests/ui/never_loop.rs | 9 --- tests/ui/never_loop.stderr | 18 ++--- tests/ui/new_without_default.rs | 9 --- tests/ui/new_without_default.stderr | 6 +- tests/ui/no_effect.rs | 9 --- tests/ui/no_effect.stderr | 50 ++++++------ tests/ui/non_copy_const.rs | 9 --- tests/ui/non_copy_const.stderr | 74 ++++++++--------- tests/ui/non_expressive_names.rs | 9 --- tests/ui/non_expressive_names.stderr | 56 ++++++------- tests/ui/ok_expect.rs | 9 --- tests/ui/ok_expect.stderr | 10 +-- tests/ui/ok_if_let.rs | 9 --- tests/ui/ok_if_let.stderr | 2 +- tests/ui/op_ref.rs | 9 --- tests/ui/op_ref.stderr | 4 +- tests/ui/open_options.rs | 9 --- tests/ui/open_options.stderr | 14 ++-- tests/ui/option_map_unit_fn.rs | 9 --- tests/ui/option_map_unit_fn.stderr | 50 ++++++------ tests/ui/option_option.rs | 9 --- tests/ui/option_option.stderr | 18 ++--- tests/ui/overflow_check_conditional.rs | 9 --- tests/ui/overflow_check_conditional.stderr | 16 ++-- tests/ui/panic_unimplemented.rs | 9 --- tests/ui/panic_unimplemented.stderr | 10 +-- tests/ui/partialeq_ne_impl.rs | 9 --- tests/ui/partialeq_ne_impl.stderr | 2 +- tests/ui/patterns.rs | 9 --- tests/ui/patterns.stderr | 2 +- tests/ui/precedence.rs | 9 --- tests/ui/precedence.stderr | 18 ++--- tests/ui/print.rs | 9 --- tests/ui/print.stderr | 18 ++--- tests/ui/print_literal.rs | 9 --- tests/ui/print_literal.stderr | 28 +++---- tests/ui/print_with_newline.rs | 9 --- tests/ui/print_with_newline.stderr | 8 +- tests/ui/println_empty_string.fixed | 9 --- tests/ui/println_empty_string.rs | 9 --- tests/ui/println_empty_string.stderr | 4 +- tests/ui/ptr_arg.rs | 9 --- tests/ui/ptr_arg.stderr | 14 ++-- tests/ui/ptr_offset_with_cast.fixed | 9 --- tests/ui/ptr_offset_with_cast.rs | 9 --- tests/ui/ptr_offset_with_cast.stderr | 4 +- tests/ui/question_mark.rs | 9 --- tests/ui/question_mark.stderr | 14 ++-- tests/ui/range.rs | 9 --- tests/ui/range.stderr | 12 +-- tests/ui/range_plus_minus_one.rs | 9 --- tests/ui/range_plus_minus_one.stderr | 16 ++-- tests/ui/redundant_clone.rs | 9 --- tests/ui/redundant_clone.stderr | 40 +++++----- tests/ui/redundant_closure_call.rs | 9 --- tests/ui/redundant_closure_call.stderr | 10 +-- tests/ui/redundant_field_names.rs | 9 --- tests/ui/redundant_field_names.stderr | 14 ++-- tests/ui/redundant_pattern_matching.rs | 9 --- tests/ui/redundant_pattern_matching.stderr | 20 ++--- tests/ui/reference.rs | 9 --- tests/ui/reference.stderr | 22 +++--- tests/ui/regex.rs | 9 --- tests/ui/regex.stderr | 46 +++++------ tests/ui/rename.rs | 9 --- tests/ui/rename.stderr | 6 +- tests/ui/replace_consts.rs | 9 --- tests/ui/replace_consts.stderr | 72 ++++++++--------- tests/ui/result_map_unit_fn.rs | 9 --- tests/ui/result_map_unit_fn.stderr | 46 +++++------ tests/ui/result_map_unwrap_or_else.rs | 9 --- tests/ui/result_map_unwrap_or_else.stderr | 6 +- tests/ui/serde.rs | 9 --- tests/ui/serde.stderr | 2 +- tests/ui/shadow.rs | 9 --- tests/ui/shadow.stderr | 46 +++++------ tests/ui/short_circuit_statement.rs | 9 --- tests/ui/short_circuit_statement.stderr | 6 +- tests/ui/single_char_pattern.fixed | 9 --- tests/ui/single_char_pattern.rs | 9 --- tests/ui/single_char_pattern.stderr | 40 +++++----- tests/ui/single_match.rs | 9 --- tests/ui/single_match.stderr | 12 +-- tests/ui/single_match_else.rs | 9 --- tests/ui/single_match_else.stderr | 2 +- tests/ui/slow_vector_initialization.rs | 9 --- tests/ui/slow_vector_initialization.stderr | 14 ++-- tests/ui/starts_ends_with.rs | 9 --- tests/ui/starts_ends_with.stderr | 24 +++--- tests/ui/string_extend.fixed | 9 --- tests/ui/string_extend.rs | 9 --- tests/ui/string_extend.stderr | 6 +- tests/ui/strings.rs | 9 --- tests/ui/strings.stderr | 22 +++--- tests/ui/suspicious_arithmetic_impl.rs | 9 --- tests/ui/suspicious_arithmetic_impl.stderr | 4 +- tests/ui/swap.rs | 9 --- tests/ui/swap.stderr | 14 ++-- tests/ui/temporary_assignment.rs | 9 --- tests/ui/temporary_assignment.stderr | 16 ++-- tests/ui/toplevel_ref_arg.rs | 9 --- tests/ui/toplevel_ref_arg.stderr | 10 +-- tests/ui/trailing_zeros.rs | 9 --- tests/ui/trailing_zeros.stderr | 4 +- tests/ui/transmute.rs | 9 --- tests/ui/transmute.stderr | 76 +++++++++--------- tests/ui/transmute_32bit.rs | 9 --- tests/ui/transmute_64bit.rs | 9 --- tests/ui/transmute_64bit.stderr | 4 +- tests/ui/trivially_copy_pass_by_ref.rs | 9 --- tests/ui/trivially_copy_pass_by_ref.stderr | 30 +++---- tests/ui/ty_fn_sig.rs | 9 --- tests/ui/types.rs | 9 --- tests/ui/types.stderr | 2 +- tests/ui/unicode.rs | 9 --- tests/ui/unicode.stderr | 6 +- tests/ui/unit_arg.rs | 9 --- tests/ui/unit_arg.stderr | 12 +-- tests/ui/unit_cmp.rs | 9 --- tests/ui/unit_cmp.stderr | 4 +- tests/ui/unknown_clippy_lints.rs | 9 --- tests/ui/unknown_clippy_lints.stderr | 4 +- tests/ui/unnecessary_clone.rs | 9 --- tests/ui/unnecessary_clone.stderr | 26 +++--- tests/ui/unnecessary_filter_map.rs | 9 --- tests/ui/unnecessary_filter_map.stderr | 8 +- tests/ui/unnecessary_fold.rs | 9 --- tests/ui/unnecessary_fold.stderr | 10 +-- tests/ui/unnecessary_operation.rs | 9 --- tests/ui/unnecessary_operation.stderr | 40 +++++----- tests/ui/unnecessary_ref.fixed | 9 --- tests/ui/unnecessary_ref.rs | 9 --- tests/ui/unnecessary_ref.stderr | 4 +- tests/ui/unneeded_field_pattern.rs | 9 --- tests/ui/unneeded_field_pattern.stderr | 4 +- tests/ui/unreadable_literal.fixed | 9 --- tests/ui/unreadable_literal.rs | 9 --- tests/ui/unreadable_literal.stderr | 10 +-- tests/ui/unsafe_removed_from_name.rs | 9 --- tests/ui/unsafe_removed_from_name.stderr | 6 +- tests/ui/unused_io_amount.rs | 9 --- tests/ui/unused_io_amount.stderr | 12 +-- tests/ui/unused_labels.rs | 9 --- tests/ui/unused_labels.stderr | 6 +- tests/ui/unused_lt.rs | 9 --- tests/ui/unused_lt.stderr | 6 +- tests/ui/unused_unit.rs | 10 --- tests/ui/unused_unit.stderr | 16 ++-- tests/ui/unwrap_or.rs | 9 --- tests/ui/unwrap_or.stderr | 4 +- tests/ui/update-all-references.sh | 10 --- tests/ui/update-references.sh | 10 --- tests/ui/use_self.rs | 9 --- tests/ui/use_self.stderr | 52 ++++++------ tests/ui/used_underscore_binding.rs | 9 --- tests/ui/used_underscore_binding.stderr | 10 +-- tests/ui/useful_asref.rs | 9 --- tests/ui/useless_asref.rs | 9 --- tests/ui/useless_asref.stderr | 24 +++--- tests/ui/useless_attribute.rs | 9 --- tests/ui/useless_attribute.stderr | 4 +- tests/ui/vec.fixed | 9 --- tests/ui/vec.rs | 9 --- tests/ui/vec.stderr | 12 +-- tests/ui/while_loop.rs | 9 --- tests/ui/while_loop.stderr | 24 +++--- tests/ui/write_literal.rs | 9 --- tests/ui/write_literal.stderr | 28 +++---- tests/ui/write_with_newline.rs | 9 --- tests/ui/write_with_newline.stderr | 10 +-- tests/ui/writeln_empty_string.fixed | 9 --- tests/ui/writeln_empty_string.rs | 9 --- tests/ui/writeln_empty_string.stderr | 4 +- tests/ui/wrong_self_convention.rs | 9 --- tests/ui/wrong_self_convention.stderr | 24 +++--- tests/ui/zero_div_zero.rs | 9 --- tests/ui/zero_div_zero.stderr | 16 ++-- tests/ui/zero_ptr.rs | 9 --- tests/ui/zero_ptr.stderr | 4 +- tests/versioncheck.rs | 9 --- util/cov.sh | 11 --- util/export.py | 11 --- util/lintlib.py | 10 --- util/update_lints.py | 10 --- 671 files changed, 2153 insertions(+), 6243 deletions(-) (limited to 'src') diff --git a/.github/deploy.sh b/.github/deploy.sh index 11d0b2d2a85..a242c35c3ae 100755 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -1,16 +1,5 @@ #!/bin/bash -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - - # Automatically deploy on gh-pages set -ex diff --git a/COPYRIGHT b/COPYRIGHT index cb9970597a2..e507fb8b9b9 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright 2014-2018 The Rust Project Developers +Copyright 2014-2019 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license diff --git a/README.md b/README.md index 8ca10da416d..ca2ff529552 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT ## License -Copyright 2014-2018 The Rust Project Developers +Copyright 2014-2019 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license diff --git a/build.rs b/build.rs index 22a6910f167..146a8dae745 100644 --- a/build.rs +++ b/build.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { // Forward the profile to the main compilation println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); diff --git a/ci/base-tests.sh b/ci/base-tests.sh index b69e86ad3ac..6675c795b3b 100755 --- a/ci/base-tests.sh +++ b/ci/base-tests.sh @@ -1,14 +1,3 @@ -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - - set -ex echo "Running clippy base tests" diff --git a/ci/integration-tests.sh b/ci/integration-tests.sh index bf43d5b6811..1259c5e1d37 100755 --- a/ci/integration-tests.sh +++ b/ci/integration-tests.sh @@ -1,13 +1,3 @@ -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - set -x rm ~/.cargo/bin/cargo-clippy cargo install --force --path . diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 60f1a3df522..073b3a9e97f 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::default_hash_types)] use itertools::Itertools; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 4ed07960010..1d9245d1347 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - extern crate clap; extern crate clippy_dev; extern crate regex; diff --git a/clippy_dummy/build.rs b/clippy_dummy/build.rs index b4ea0772ee5..59d32e5db43 100644 --- a/clippy_dummy/build.rs +++ b/clippy_dummy/build.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - extern crate term; fn main() { @@ -49,4 +39,4 @@ fn foo() -> Result<(), ()> { t.reset().map_err(|_| ())?; Ok(()) -} \ No newline at end of file +} diff --git a/clippy_dummy/src/main.rs b/clippy_dummy/src/main.rs index 878993d5c28..a118834f1fd 100644 --- a/clippy_dummy/src/main.rs +++ b/clippy_dummy/src/main.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - fn main() { panic!("This shouldn't even compile") } diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index afbfdd32304..8410408312f 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index c466b8cd5c9..d133a583f02 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 496b6d65993..ad77ee3a3fa 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq}; use crate::utils::{higher, sugg}; use if_chain::if_chain; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 41946d06293..24cc8a81dc0 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! checks for attributes use crate::reexport::*; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 9af80493af1..b08d9961d25 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; use crate::utils::{span_lint, span_lint_and_then}; diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index ed7437e495b..64b3be8f302 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 92979dc024d..6e850931e6b 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::*; use matches::matches; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2279d24af95..8b1a56e3b6e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq, }; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 0f2062d9e0f..794b43f4db5 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty, diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 9f396b61330..70ea387515a 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on missing cargo common metadata use crate::utils::span_lint; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index ae613d70240..10cbc9e6ccd 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for if expressions that contain only an if expression. //! //! For example, the lint would catch: diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index a7509dae3d5..229a411ce06 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, snippet, span_lint_and_then}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 8102a416d82..5780b9bcfd4 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - #![allow(clippy::float_cmp)] use crate::utils::{clip, sext, unsext}; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 01398380075..3676519adc1 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint}; use crate::utils::{SpanlessEq, SpanlessHash}; use rustc::hir::*; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index f45d8eea5e1..3d0df7424f1 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_copy, match_path, paths, span_note_and_lint}; use rustc::hir::{Item, ItemKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index 695e4329dfd..9170f1e8ecf 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! calculate cyclomatic complexity and warn about overly complex functions use rustc::cfg::CFG; diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 9dc404efd7e..c4b39dc0f0a 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 17bef09164b..7cb04d7a95b 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - macro_rules! declare_deprecated_lint { (pub $name: ident, $_reason: expr) => { declare_lint!(pub $name, Allow, "deprecated lint") diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index b4556ebaff9..a2bf0098ab8 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; use if_chain::if_chain; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index a3504e7e330..e96ef9ac621 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use itertools::Itertools; use pulldown_cmark; diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 34f4a56bef9..fc4af438d44 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Lint on unnecessary double comparisons. Some examples: use rustc::hir::*; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 3b476b81707..38381b069f0 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, span_lint}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index f0f91c9ab69..4a2a38f6ea1 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index aebb378ee9b..3ac98c71644 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index ff8345290b2..f633d81764b 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on if expressions with an else if, but without a final else branch use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index af2a54069fc..71e84bf1b47 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint when there is an enum with no variants use crate::utils::span_lint_and_then; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index c59bfd1ad92..646a2569bbe 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::SpanlessEq; use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; use if_chain::if_chain; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 78cade1f2fb..ab9bc6cd0ca 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index aa1ee038c59..9402c2a5aad 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on `use`ing all variants of an enum use crate::utils::span_lint; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 5466baae886..ffaa8b2811a 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on enum variants that are prefixed or suffixed by the same characters use crate::utils::{camel_case, in_macro}; diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index af9de9fe7e4..93132534a76 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq, }; diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 43f16c74eb1..fea31855543 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant_simple, Constant}; use crate::utils::{in_macro, span_lint}; use rustc::hir::*; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 445aeb3377b..75020b14492 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir::intravisit as visit; use rustc::hir::*; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index dd80afbc4ae..624d215492f 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 50944eb5e7e..8bd8461b119 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_parent_expr, span_lint, span_note_and_lint}; use if_chain::if_chain; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index b3cf9131cce..f17b82ab33d 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint_and_sugg; use if_chain::if_chain; use rustc::hir; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index f56e3225d0a..0bbc85a0416 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_expn_of, match_def_path, opt_def_id, resolve_node, span_lint, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 65790b1b42e..2d11b3bd947 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT}; use crate::utils::{is_expn_of, match_def_path, method_chain_args, opt_def_id, span_lint_and_then, walk_ptrs_ty}; use if_chain::if_chain; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 1db52079d3f..57c21bee722 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::{ in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index ce51f1433f9..6459e7b81c6 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 19adf2d1dc4..a2b7d31b183 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function}; use matches::matches; use rustc::hir; diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index b18d63a94b6..d0e1ee57748 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then, }; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 5f1101461bd..862c289fce1 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant_simple, Constant}; use crate::utils::{clip, in_macro, snippet, span_lint, unsext}; use rustc::hir::*; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index c40fb540da6..19554c7e207 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 674667c4b5b..cd5db359628 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, snippet_opt, span_lint_and_then}; use rustc::hir::{intravisit::FnKind, Body, ExprKind, FnDecl}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index cf971b63052..b4893c759c8 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on indexing and slicing operations use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs index e3d03c0e697..5d0c5a4a79d 100644 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ b/clippy_lints/src/infallible_destructuring_match.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index e2da8461f41..c25c4ec488f 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 5224b5fb867..52aa73d7a10 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on inherent implementations use crate::utils::span_lint_and_then; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index afa8f234023..a092f86658b 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! checks for `#[inline]` on trait methods without bodies use crate::utils::span_lint_and_then; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 3498c1e8114..547052f3429 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on blocks unnecessarily using >= with a + 1 or - 1 use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index c0dcda6349b..03b099b4393 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 2d8f284ea6d..0af8c3dd5cb 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint when items are used after statements use crate::utils::{in_macro, span_lint}; diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 052504cc57c..d5bc2a8fad7 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint when there is a large size difference between variants on an enum use crate::utils::{snippet_opt, span_lint_and_then}; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 233bea77e03..40fef2df27f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc::hir::def_id::DefId; use rustc::hir::*; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 7e9f1b41d27..c3b3272dffd 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{snippet, span_lint_and_then}; use if_chain::if_chain; use rustc::hir; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 35c00fb6328..e9d8732cb35 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern:cargo-clippy #![feature(box_syntax)] diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 32170c9a7c6..f7512446c87 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::reexport::*; use crate::utils::{last_path_segment, span_lint}; use matches::matches; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 72bd6b09fea..d6e6ffa61b3 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Lints concerned with the grouping of digits with underscores in integral or //! floating-point literal expressions. diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index d8d95cf9a23..d6430cf291b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::reexport::*; use if_chain::if_chain; use itertools::Itertools; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 2a7177d1fb9..1546964e426 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::{ in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg, diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index eca35422de2..4b4f1ad5919 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then}; use if_chain::if_chain; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 00292eb9603..b003da44236 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index 0f8ccc7dedb..a75959e58fa 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_def_path, opt_def_id, paths, snippet, span_lint_and_then, walk_ptrs_ty_depth}; use if_chain::if_chain; use rustc::hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index d231d054610..f83a8b5f7fe 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; use rustc::hir::{Expr, ExprKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 0a77b7d2044..d649895e33f 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_def_path, match_qpath, opt_def_id, paths, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir::{Expr, ExprKind, MutMutable, QPath}; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4473802da3b..41011e8f66a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::sugg; use crate::utils::{ diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index c5a22961db9..8d90a4388fc 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::usage::mutated_variables; use crate::utils::{match_qpath, match_trait_method, span_lint}; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 087aa94a7ec..beea667dd43 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant_simple, Constant}; use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; use rustc::hir::*; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e96261bbe28..4e5910f76bb 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant, Constant}; use crate::reexport::*; use crate::utils::sugg::Sugg; diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 6b9b90e17a5..2cda1accc56 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then}; use if_chain::if_chain; use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 90503970823..7b56609e493 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -1,25 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - // Note: More specifically this lint is largely inspired (aka copied) from // *rustc*'s // [`missing_doc`]. diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 8fb677c7cdf..e9d0d2d77f1 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -1,23 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - use crate::utils::span_lint; use rustc::hir; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index c6374afb4de..073d3857c55 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! lint on multiple versions of a crate being used use crate::utils::span_lint; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index e1702cc373b..9aa3cce9d4b 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{higher, span_lint}; use rustc::hir; use rustc::hir::intravisit; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index ddb8bd30137..5293c80ca2b 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index a114e691228..b85f4b8ad30 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for uses of mutex where an atomic value could be used //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 08408c4475c..1dfc3f6501e 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for needless boolean results of if-else expressions //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 80c9fc549d9..f21cbe8b9ad 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for needless address of operations (`&`) //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index e2801a2e1e0..792e38e1875 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for useless borrowed references. //! //! This lint is **warn** by default diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 9044245c5a6..0b5ea255d7f 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for continue statements in loops that are redundant. //! //! For example, the lint would catch diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 9184a486374..b02faa08006 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::ptr::get_spans; use crate::utils::{ get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths, snippet, diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 993aa73f6f7..ab22e2c19b3 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::hir::{Expr, ExprKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 6642f674da8..919c771ccf5 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass}; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 55edca6cece..846794d8b99 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 832311dc027..37e0446faed 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index c2cffadf6c1..53d7575e3e0 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg}; use rustc::hir::def::Def; use rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 57482ff4179..11295c3c092 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for uses of const which the type is not Freeze (Cell-free). //! //! This lint is **deny** by default. diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 2ab7d7e62f3..f39cae46de0 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{span_lint, span_lint_and_then}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index e060220d56b..5f15662c90c 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index f6773dcb158..e21225fbd29 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty}; use rustc::hir::{Expr, ExprKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 8df3ba4197f..d76a9f96eff 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{span_lint, SpanlessEq}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 822361175d6..61646613b11 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index c33367e7a3f..03d2d5d3bab 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_automatically_derived, span_lint_node}; use if_chain::if_chain; use rustc::hir::*; diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 20a797937de..44e82984c54 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index f45bb54d191..87cd9892893 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Checks for usage of `&Vec[_]` and `&String`. use crate::utils::ptr::get_spans; diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 8d6bca8b689..32d330ac171 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils; use rustc::{declare_tool_lint, hir, lint, lint_array}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index c1a76eed928..a4c4e66cf71 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc::hir::def::Def; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index a0870ea72d0..2e01afc2258 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::sugg::Sugg; use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq}; use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then}; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 1983cb6cbc4..f584ef19d5a 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,12 +1,3 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ has_drop, in_macro, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_node, span_lint_node_and_then, walk_ptrs_ty_depth, diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index a53df6a292a..9076d67cb14 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint_and_sugg; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs index bd194dd7bc3..bc61ee8e7e3 100644 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ b/clippy_lints/src/redundant_pattern_matching.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_qpath, paths, snippet, span_lint_and_then}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 54a9c0336f0..8d2543ef618 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 021237d38c0..6a58a6e73c7 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant, Constant}; use crate::utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint}; use if_chain::if_chain; diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index d905d3dbdf4..ea51e4711cd 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{match_def_path, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir; diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 1ef03a77bd7..d81d04b81d3 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint}; use if_chain::if_chain; use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index d381f8c4419..da8675b38da 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_trait_def_id, paths, span_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 329e83e100b..84dd339a985 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::reexport::*; use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; use rustc::hir::intravisit::FnKind; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index fde679b6ed2..77f70fad588 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::sugg::Sugg; use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq}; use if_chain::if_chain; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 5414a1ac0de..ffec764fd5e 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::SpanlessEq; use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc::hir::*; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 04f8e4993f0..c6dd9504857 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_trait_def_id, span_lint}; use if_chain::if_chain; use rustc::hir; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 4c4fda26253..56f503afeae 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::sugg::Sugg; use crate::utils::{ differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq, diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index 381efd57135..c8a01c3668c 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::is_adjusted; use crate::utils::span_lint; use rustc::hir::def::Def; diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index be3475f6703..02205cfbd68 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; use crate::utils::{opt_def_id, sugg}; use if_chain::if_chain; diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index efa6c0486eb..5ab73758301 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::cmp; use crate::utils::{in_macro, is_copy, is_self_ty, snippet, span_lint_and_sugg}; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index f9ed38e52a0..f4b75437ff6 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - #![allow(clippy::default_hash_types)] use crate::consts::{constant, Constant}; diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index a38fe4a5aa9..d9207fd2131 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_allowed, snippet, span_help_and_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 626b1c31013..6beda8ce706 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 43f980c72c4..c33b6b742fa 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint}; use rustc::hir; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index 766431c3687..d53fd265d37 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{in_macro, span_lint}; use rustc::hir; use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index b61b3b975f5..369b33363b5 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use if_chain::if_chain; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5ec809f1b76..b72401e1cca 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint_and_sugg; use if_chain::if_chain; use rustc::hir::def::{CtorKind, Def}; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index e13c64b5c78..51e7d333084 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. diff --git a/clippy_lints/src/utils/camel_case.rs b/clippy_lints/src/utils/camel_case.rs index f58f3e3b98a..b49287b30d1 100644 --- a/clippy_lints/src/utils/camel_case.rs +++ b/clippy_lints/src/utils/camel_case.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - /// Return the index of the character after the first camel-case component of /// `s`. pub fn until(s: &str) -> usize { diff --git a/clippy_lints/src/utils/comparisons.rs b/clippy_lints/src/utils/comparisons.rs index 8b6a97a505c..31e20f37e20 100644 --- a/clippy_lints/src/utils/comparisons.rs +++ b/clippy_lints/src/utils/comparisons.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Utility functions about comparison operators. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index da3a256a83d..55256a25427 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Read configurations files. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/constants.rs b/clippy_lints/src/utils/constants.rs index dde70d8e2cc..522932f054d 100644 --- a/clippy_lints/src/utils/constants.rs +++ b/clippy_lints/src/utils/constants.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! This module contains some useful constants. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 214b3dc10e6..682093b08e4 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! This module contains functions for retrieve the original AST from lowered //! `hir`. diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 377e56ddcac..aed9bb9afc9 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant_context, constant_simple}; use crate::utils::differing_macro_contexts; use rustc::hir::*; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 98ddcf945d9..6ce27c18cec 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! checks for attributes use crate::utils::get_attr; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index be412f36edd..788fc434d51 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{ match_def_path, match_type, paths, span_help_and_lint, span_lint, span_lint_and_sugg, walk_ptrs_ty, }; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 9b5e18413a2..5d94f0f3f05 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::reexport::*; use if_chain::if_chain; use matches::matches; diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 0779d77936f..a74e457a9fd 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! This module contains paths to types and functions Clippy needs to know //! about. diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index 3f589c3b687..3d221fbfb81 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{get_pat_name, match_var, snippet}; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc::hir::*; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index a8bc0f3fca1..d42af5fde3a 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index e4d3fa29996..a3d3518ef98 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use rustc::lint::LateContext; use rustc::hir::def::Def; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 2f259bf8bca..407722bc66e 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::constant; use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index 38bce9da932..e3c35286251 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::span_lint; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 6531e71a9fa..bb62cdeb9ed 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 93606e378d9..962d42e631e 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use crate::consts::{constant_simple, Constant}; use crate::utils::span_help_and_lint; use if_chain::if_chain; diff --git a/clippy_workspace_tests/src/main.rs b/clippy_workspace_tests/src/main.rs index 7af28f80b9b..f79c691f085 100644 --- a/clippy_workspace_tests/src/main.rs +++ b/clippy_workspace_tests/src/main.rs @@ -1,12 +1,2 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - fn main() { } diff --git a/clippy_workspace_tests/subcrate/src/lib.rs b/clippy_workspace_tests/subcrate/src/lib.rs index fd694f68ca6..e69de29bb2d 100644 --- a/clippy_workspace_tests/subcrate/src/lib.rs +++ b/clippy_workspace_tests/subcrate/src/lib.rs @@ -1,10 +0,0 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index b6405975862..0a96be71b35 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - #![feature(proc_macro_quote, proc_macro_hygiene)] extern crate proc_macro; diff --git a/pre_publish.sh b/pre_publish.sh index fc7ae212fcf..3602f671e3d 100755 --- a/pre_publish.sh +++ b/pre_publish.sh @@ -1,16 +1,5 @@ #!/bin/bash -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - - set -e ./util/update_lints.py diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index b101f55e509..a88f47e4dbc 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -49,7 +49,7 @@ This gives the following output in clippy: ## License -Copyright 2014-2018 The Rust Project Developers +Copyright 2014-2019 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 49bfb7d8b59..f13fa12ccca 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::env; #[macro_export] diff --git a/src/driver.rs b/src/driver.rs index 269228988f7..2faa77785bb 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] diff --git a/src/lib.rs b/src/lib.rs index ef6f4cd7b3d..be0c10c8ff2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] diff --git a/src/main.rs b/src/main.rs index 369528f1954..eefababb96d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] diff --git a/tests/auxiliary/test_macro.rs b/tests/auxiliary/test_macro.rs index d5fef588971..624ca892add 100644 --- a/tests/auxiliary/test_macro.rs +++ b/tests/auxiliary/test_macro.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub trait A {} macro_rules! __implicit_hasher_test_macro { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 005c2ce33f9..c67b6f08c9f 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(test)] use compiletest_rs as compiletest; diff --git a/tests/dogfood.rs b/tests/dogfood.rs index c1f02b9fcef..87fe5887bcc 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[test] fn dogfood() { if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) { diff --git a/tests/matches.rs b/tests/matches.rs index 7d099665259..15a0ea503bf 100644 --- a/tests/matches.rs +++ b/tests/matches.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(rustc_private)] extern crate syntax; diff --git a/tests/needless_continue_helpers.rs b/tests/needless_continue_helpers.rs index e0dcd035c58..255653b4737 100644 --- a/tests/needless_continue_helpers.rs +++ b/tests/needless_continue_helpers.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Tests for the various helper functions used by the needless_continue // lint that don't belong in utils. diff --git a/tests/run-pass/associated-constant-ice.rs b/tests/run-pass/associated-constant-ice.rs index df84009c889..2c5c90683cc 100644 --- a/tests/run-pass/associated-constant-ice.rs +++ b/tests/run-pass/associated-constant-ice.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub trait Trait { const CONSTANT: u8; } diff --git a/tests/run-pass/cc_seme.rs b/tests/run-pass/cc_seme.rs index 7e1f13d4460..169403df562 100644 --- a/tests/run-pass/cc_seme.rs +++ b/tests/run-pass/cc_seme.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(dead_code)] enum Baz { One, diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs index 6e64f174e4c..dca32aa3b56 100644 --- a/tests/run-pass/enum-glob-import-crate.rs +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::all)] #![allow(unused_imports)] diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs index 87f2afaa602..6a5bf429f2d 100644 --- a/tests/run-pass/ice-1588.rs +++ b/tests/run-pass/ice-1588.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::all)] fn main() { diff --git a/tests/run-pass/ice-1782.rs b/tests/run-pass/ice-1782.rs index ddb4367c914..81af88962a6 100644 --- a/tests/run-pass/ice-1782.rs +++ b/tests/run-pass/ice-1782.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs index 2a0cdb19fce..eab4f338f97 100644 --- a/tests/run-pass/ice-1969.rs +++ b/tests/run-pass/ice-1969.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::all)] fn main() {} diff --git a/tests/run-pass/ice-2499.rs b/tests/run-pass/ice-2499.rs index 804f416800c..45b3b1869dd 100644 --- a/tests/run-pass/ice-2499.rs +++ b/tests/run-pass/ice-2499.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/tests/run-pass/ice-2594.rs b/tests/run-pass/ice-2594.rs index e91b71b3a1c..3f3986b6fc6 100644 --- a/tests/run-pass/ice-2594.rs +++ b/tests/run-pass/ice-2594.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/tests/run-pass/ice-2727.rs b/tests/run-pass/ice-2727.rs index 9d00f2bacd0..79c6f1c55db 100644 --- a/tests/run-pass/ice-2727.rs +++ b/tests/run-pass/ice-2727.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub fn f(new: fn()) { new(); } diff --git a/tests/run-pass/ice-2760.rs b/tests/run-pass/ice-2760.rs index 533cc3b952a..949e273997c 100644 --- a/tests/run-pass/ice-2760.rs +++ b/tests/run-pass/ice-2760.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( unused_variables, clippy::blacklisted_name, diff --git a/tests/run-pass/ice-2774.rs b/tests/run-pass/ice-2774.rs index ae51f036207..2cc19ae32b8 100644 --- a/tests/run-pass/ice-2774.rs +++ b/tests/run-pass/ice-2774.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::collections::HashSet; // See https://github.com/rust-lang/rust-clippy/issues/2774 diff --git a/tests/run-pass/ice-2865.rs b/tests/run-pass/ice-2865.rs index 970ac5bd3a8..64092afd53d 100644 --- a/tests/run-pass/ice-2865.rs +++ b/tests/run-pass/ice-2865.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(dead_code)] struct Ice { size: String, diff --git a/tests/run-pass/ice-3151.rs b/tests/run-pass/ice-3151.rs index 7a26f4c3925..a03dd05e7d3 100644 --- a/tests/run-pass/ice-3151.rs +++ b/tests/run-pass/ice-3151.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[derive(Clone)] pub struct HashMap<V, S> { hash_builder: S, diff --git a/tests/run-pass/ice-3462.rs b/tests/run-pass/ice-3462.rs index 8aea905cd80..d4f6f355c85 100644 --- a/tests/run-pass/ice-3462.rs +++ b/tests/run-pass/ice-3462.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2019 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(clippy::blacklisted_name)] #![allow(unused)] diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs index b839ac2a214..10546850611 100644 --- a/tests/run-pass/ice-700.rs +++ b/tests/run-pass/ice-700.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::all)] fn core() {} diff --git a/tests/run-pass/ice_exacte_size.rs b/tests/run-pass/ice_exacte_size.rs index b2b331bd342..ac643fafabc 100644 --- a/tests/run-pass/ice_exacte_size.rs +++ b/tests/run-pass/ice_exacte_size.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::all)] #[allow(dead_code)] diff --git a/tests/run-pass/if_same_then_else.rs b/tests/run-pass/if_same_then_else.rs index 0241d2adcf7..e6ab7cc9d8c 100644 --- a/tests/run-pass/if_same_then_else.rs +++ b/tests/run-pass/if_same_then_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::if_same_then_else)] fn main() {} diff --git a/tests/run-pass/issue-2862.rs b/tests/run-pass/issue-2862.rs index a5342492045..b35df667f27 100644 --- a/tests/run-pass/issue-2862.rs +++ b/tests/run-pass/issue-2862.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub trait FooMap { fn map<B, F: Fn() -> B>(&self, f: F) -> B; } diff --git a/tests/run-pass/issue-825.rs b/tests/run-pass/issue-825.rs index 9f1195a4ac0..b1339212e6e 100644 --- a/tests/run-pass/issue-825.rs +++ b/tests/run-pass/issue-825.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(warnings)] // this should compile in a reasonable amount of time diff --git a/tests/run-pass/issues_loop_mut_cond.rs b/tests/run-pass/issues_loop_mut_cond.rs index a81f8f55dc8..bb238c81ebc 100644 --- a/tests/run-pass/issues_loop_mut_cond.rs +++ b/tests/run-pass/issues_loop_mut_cond.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596 diff --git a/tests/run-pass/match_same_arms_const.rs b/tests/run-pass/match_same_arms_const.rs index 661f2ac1dc7..50732475562 100644 --- a/tests/run-pass/match_same_arms_const.rs +++ b/tests/run-pass/match_same_arms_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::match_same_arms)] const PRICE_OF_SWEETS: u32 = 5; diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs index f1a2cad3ae7..af11c29d9b0 100644 --- a/tests/run-pass/mut_mut_macro.rs +++ b/tests/run-pass/mut_mut_macro.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)] #![allow(dead_code)] diff --git a/tests/run-pass/needless_borrow_fp.rs b/tests/run-pass/needless_borrow_fp.rs index 81b77855711..4f61c76828d 100644 --- a/tests/run-pass/needless_borrow_fp.rs +++ b/tests/run-pass/needless_borrow_fp.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[deny(clippy::all)] #[derive(Debug)] pub enum Error { diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs index 9648f530c2a..676564b2445 100644 --- a/tests/run-pass/needless_lifetimes_impl_trait.rs +++ b/tests/run-pass/needless_lifetimes_impl_trait.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::needless_lifetimes)] #![allow(dead_code)] diff --git a/tests/run-pass/procedural_macro.rs b/tests/run-pass/procedural_macro.rs index 9ac47599ea0..c7468493380 100644 --- a/tests/run-pass/procedural_macro.rs +++ b/tests/run-pass/procedural_macro.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[macro_use] extern crate clippy_mini_macro_test; diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs index b109eecf624..84470addd4a 100644 --- a/tests/run-pass/regressions.rs +++ b/tests/run-pass/regressions.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::blacklisted_name)] pub fn foo(bar: *const u8) { diff --git a/tests/run-pass/returns.rs b/tests/run-pass/returns.rs index 045cf001eb2..d6b2a4ef170 100644 --- a/tests/run-pass/returns.rs +++ b/tests/run-pass/returns.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[deny(warnings)] fn cfg_return() -> i32 { #[cfg(unix)] diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs index 80fc88f30df..efcc6363eb0 100644 --- a/tests/run-pass/single-match-else.rs +++ b/tests/run-pass/single-match-else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::single_match_else)] fn main() { diff --git a/tests/run-pass/used_underscore_binding_macro.rs b/tests/run-pass/used_underscore_binding_macro.rs index 8b6c6557b49..3030786aea6 100644 --- a/tests/run-pass/used_underscore_binding_macro.rs +++ b/tests/run-pass/used_underscore_binding_macro.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::useless_attribute)] //issue #2910 #[macro_use] diff --git a/tests/run-pass/whitelist/conf_whitelisted.rs b/tests/run-pass/whitelist/conf_whitelisted.rs index e7f5ddb561f..f328e4d9d04 100644 --- a/tests/run-pass/whitelist/conf_whitelisted.rs +++ b/tests/run-pass/whitelist/conf_whitelisted.rs @@ -1,10 +1 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() {} diff --git a/tests/ui-toml/bad_toml/conf_bad_toml.rs b/tests/ui-toml/bad_toml/conf_bad_toml.rs index 31781277ae8..3b9458fc284 100644 --- a/tests/ui-toml/bad_toml/conf_bad_toml.rs +++ b/tests/ui-toml/bad_toml/conf_bad_toml.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern: error reading Clippy's configuration file fn main() {} diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.rs b/tests/ui-toml/bad_toml_type/conf_bad_type.rs index 2307bfff21c..8a0062423ad 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.rs +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a // `Vec < String >` but is a `integer` diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs index b00a21b3f2f..cb35d0e8589 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] #![allow(clippy::single_match)] #![allow(unused_variables)] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr index 9f35b1751ac..84ba77851f7 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr +++ b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr @@ -1,5 +1,5 @@ error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:15:9 + --> $DIR/conf_french_blacklisted_name.rs:6:9 | LL | fn test(toto: ()) {} | ^^^^ @@ -7,37 +7,37 @@ LL | fn test(toto: ()) {} = note: `-D clippy::blacklisted-name` implied by `-D warnings` error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:18:9 + --> $DIR/conf_french_blacklisted_name.rs:9:9 | LL | let toto = 42; | ^^^^ error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:19:9 + --> $DIR/conf_french_blacklisted_name.rs:10:9 | LL | let tata = 42; | ^^^^ error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:20:9 + --> $DIR/conf_french_blacklisted_name.rs:11:9 | LL | let titi = 42; | ^^^^ error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:26:10 + --> $DIR/conf_french_blacklisted_name.rs:17:10 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:26:21 + --> $DIR/conf_french_blacklisted_name.rs:17:21 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:26:28 + --> $DIR/conf_french_blacklisted_name.rs:17:28 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index 39de0de0dc7..f24fe51d30f 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::many_single_char_names)] #[derive(Copy, Clone)] diff --git a/tests/ui-toml/toml_trivially_copy/test.stderr b/tests/ui-toml/toml_trivially_copy/test.stderr index 49cbc0691bc..746b9ffa4af 100644 --- a/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/tests/ui-toml/toml_trivially_copy/test.stderr @@ -1,5 +1,5 @@ error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/test.rs:20:11 + --> $DIR/test.rs:11:11 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` @@ -7,7 +7,7 @@ LL | fn bad(x: &u16, y: &Foo) {} = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/test.rs:20:20 + --> $DIR/test.rs:11:20 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `Foo` diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index c8e6268e95d..a47569f62a3 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // error-pattern: error reading Clippy's configuration file: unknown key `foobar` fn main() {} diff --git a/tests/ui-toml/update-all-references.sh b/tests/ui-toml/update-all-references.sh index acc38f15fbd..71404b68c45 100755 --- a/tests/ui-toml/update-all-references.sh +++ b/tests/ui-toml/update-all-references.sh @@ -1,15 +1,5 @@ #!/bin/bash # -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - # A script to update the references for all tests. The idea is that # you do a run, which will generate files in the build directory # containing the (normalized) actual output of the compiler. You then diff --git a/tests/ui-toml/update-references.sh b/tests/ui-toml/update-references.sh index aa99d35f7aa..2c4fef43d96 100755 --- a/tests/ui-toml/update-references.sh +++ b/tests/ui-toml/update-references.sh @@ -1,14 +1,4 @@ #!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. # A script to update the references for particular tests. The idea is # that you do a run, which will generate files in the build directory diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index 666c4325706..ae0727fe2ba 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::absurd_extreme_comparisons)] #![allow( unused, diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr index 5c8d537b21c..b18a943c557 100644 --- a/tests/ui/absurd-extreme-comparisons.stderr +++ b/tests/ui/absurd-extreme-comparisons.stderr @@ -1,5 +1,5 @@ error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:23:5 + --> $DIR/absurd-extreme-comparisons.rs:14:5 | LL | u <= 0; | ^^^^^^ @@ -8,7 +8,7 @@ LL | u <= 0; = help: because 0 is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == 0 instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:24:5 + --> $DIR/absurd-extreme-comparisons.rs:15:5 | LL | u <= Z; | ^^^^^^ @@ -16,7 +16,7 @@ LL | u <= Z; = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == Z instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:25:5 + --> $DIR/absurd-extreme-comparisons.rs:16:5 | LL | u < Z; | ^^^^^ @@ -24,7 +24,7 @@ LL | u < Z; = help: because Z is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:26:5 + --> $DIR/absurd-extreme-comparisons.rs:17:5 | LL | Z >= u; | ^^^^^^ @@ -32,7 +32,7 @@ LL | Z >= u; = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using Z == u instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:27:5 + --> $DIR/absurd-extreme-comparisons.rs:18:5 | LL | Z > u; | ^^^^^ @@ -40,7 +40,7 @@ LL | Z > u; = help: because Z is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:28:5 + --> $DIR/absurd-extreme-comparisons.rs:19:5 | LL | u > std::u32::MAX; | ^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | u > std::u32::MAX; = help: because std::u32::MAX is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:29:5 + --> $DIR/absurd-extreme-comparisons.rs:20:5 | LL | u >= std::u32::MAX; | ^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | u >= std::u32::MAX; = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using u == std::u32::MAX instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:30:5 + --> $DIR/absurd-extreme-comparisons.rs:21:5 | LL | std::u32::MAX < u; | ^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | std::u32::MAX < u; = help: because std::u32::MAX is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:31:5 + --> $DIR/absurd-extreme-comparisons.rs:22:5 | LL | std::u32::MAX <= u; | ^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | std::u32::MAX <= u; = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using std::u32::MAX == u instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:32:5 + --> $DIR/absurd-extreme-comparisons.rs:23:5 | LL | 1-1 > u; | ^^^^^^^ @@ -80,7 +80,7 @@ LL | 1-1 > u; = help: because 1-1 is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:33:5 + --> $DIR/absurd-extreme-comparisons.rs:24:5 | LL | u >= !0; | ^^^^^^^ @@ -88,7 +88,7 @@ LL | u >= !0; = 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 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:34:5 + --> $DIR/absurd-extreme-comparisons.rs:25:5 | LL | u <= 12 - 2*6; | ^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | u <= 12 - 2*6; = 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 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:36:5 + --> $DIR/absurd-extreme-comparisons.rs:27:5 | LL | i < -127 - 1; | ^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | i < -127 - 1; = help: because -127 - 1 is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:37:5 + --> $DIR/absurd-extreme-comparisons.rs:28:5 | LL | std::i8::MAX >= i; | ^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | std::i8::MAX >= i; = help: because std::i8::MAX is the maximum value for this type, this comparison is always true error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:38:5 + --> $DIR/absurd-extreme-comparisons.rs:29:5 | LL | 3-7 < std::i32::MIN; | ^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | 3-7 < std::i32::MIN; = help: because std::i32::MIN is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:40:5 + --> $DIR/absurd-extreme-comparisons.rs:31:5 | LL | b >= true; | ^^^^^^^^^ @@ -128,7 +128,7 @@ LL | b >= true; = help: because true is the maximum value for this type, the case where the two sides are not equal never occurs, consider using b == true instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> $DIR/absurd-extreme-comparisons.rs:41:5 + --> $DIR/absurd-extreme-comparisons.rs:32:5 | LL | false > b; | ^^^^^^^^^ @@ -136,7 +136,7 @@ LL | false > b; = help: because false is the minimum value for this type, this comparison is always false error: <-comparison of unit values detected. This will always be false - --> $DIR/absurd-extreme-comparisons.rs:44:5 + --> $DIR/absurd-extreme-comparisons.rs:35:5 | LL | () < {}; | ^^^^^^^ diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index 8eefb6af01d..8c295d1438a 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::approx_constant)] #[allow(unused, clippy::shadow_unrelated, clippy::similar_names, clippy::unreadable_literal)] fn main() { diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr index c29ea3d467a..71c1c360e74 100644 --- a/tests/ui/approx_const.stderr +++ b/tests/ui/approx_const.stderr @@ -1,5 +1,5 @@ error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly - --> $DIR/approx_const.rs:13:16 + --> $DIR/approx_const.rs:4:16 | LL | let my_e = 2.7182; | ^^^^^^ @@ -7,109 +7,109 @@ LL | let my_e = 2.7182; = note: `-D clippy::approx-constant` implied by `-D warnings` error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly - --> $DIR/approx_const.rs:14:20 + --> $DIR/approx_const.rs:5:20 | LL | let almost_e = 2.718; | ^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found. Consider using it directly - --> $DIR/approx_const.rs:17:24 + --> $DIR/approx_const.rs:8:24 | LL | let my_1_frac_pi = 0.3183; | ^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:20:28 + --> $DIR/approx_const.rs:11:28 | LL | let my_frac_1_sqrt_2 = 0.70710678; | ^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:21:32 + --> $DIR/approx_const.rs:12:32 | LL | let almost_frac_1_sqrt_2 = 0.70711; | ^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found. Consider using it directly - --> $DIR/approx_const.rs:24:24 + --> $DIR/approx_const.rs:15:24 | LL | let my_frac_2_pi = 0.63661977; | ^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found. Consider using it directly - --> $DIR/approx_const.rs:27:27 + --> $DIR/approx_const.rs:18:27 | LL | let my_frac_2_sq_pi = 1.128379; | ^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found. Consider using it directly - --> $DIR/approx_const.rs:30:24 + --> $DIR/approx_const.rs:21:24 | LL | let my_frac_pi_2 = 1.57079632679; | ^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found. Consider using it directly - --> $DIR/approx_const.rs:33:24 + --> $DIR/approx_const.rs:24:24 | LL | let my_frac_pi_3 = 1.04719755119; | ^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found. Consider using it directly - --> $DIR/approx_const.rs:36:24 + --> $DIR/approx_const.rs:27:24 | LL | let my_frac_pi_4 = 0.785398163397; | ^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found. Consider using it directly - --> $DIR/approx_const.rs:39:24 + --> $DIR/approx_const.rs:30:24 | LL | let my_frac_pi_6 = 0.523598775598; | ^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found. Consider using it directly - --> $DIR/approx_const.rs:42:24 + --> $DIR/approx_const.rs:33:24 | LL | let my_frac_pi_8 = 0.3926990816987; | ^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LN_10` found. Consider using it directly - --> $DIR/approx_const.rs:45:20 + --> $DIR/approx_const.rs:36:20 | LL | let my_ln_10 = 2.302585092994046; | ^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LN_2` found. Consider using it directly - --> $DIR/approx_const.rs:48:19 + --> $DIR/approx_const.rs:39:19 | LL | let my_ln_2 = 0.6931471805599453; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LOG10_E` found. Consider using it directly - --> $DIR/approx_const.rs:51:22 + --> $DIR/approx_const.rs:42:22 | LL | let my_log10_e = 0.4342944819032518; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::LOG2_E` found. Consider using it directly - --> $DIR/approx_const.rs:54:21 + --> $DIR/approx_const.rs:45:21 | LL | let my_log2_e = 1.4426950408889634; | ^^^^^^^^^^^^^^^^^^ error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly - --> $DIR/approx_const.rs:57:17 + --> $DIR/approx_const.rs:48:17 | LL | let my_pi = 3.1415; | ^^^^^^ error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly - --> $DIR/approx_const.rs:58:21 + --> $DIR/approx_const.rs:49:21 | LL | let almost_pi = 3.14; | ^^^^ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it directly - --> $DIR/approx_const.rs:61:18 + --> $DIR/approx_const.rs:52:18 | LL | let my_sq2 = 1.4142; | ^^^^^^ diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index 00de38039a7..874604889b9 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] #![allow( unused, diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr index cea9676c2b8..c9bb68f857c 100644 --- a/tests/ui/arithmetic.stderr +++ b/tests/ui/arithmetic.stderr @@ -1,5 +1,5 @@ error: integer arithmetic detected - --> $DIR/arithmetic.rs:22:5 + --> $DIR/arithmetic.rs:13:5 | LL | 1 + i; | ^^^^^ @@ -7,32 +7,32 @@ LL | 1 + i; = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/arithmetic.rs:23:5 + --> $DIR/arithmetic.rs:14:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:24:5 + --> $DIR/arithmetic.rs:15:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line | |_________^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:26:5 + --> $DIR/arithmetic.rs:17:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/arithmetic.rs:27:5 + --> $DIR/arithmetic.rs:18:5 | LL | -i; | ^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:37:5 + --> $DIR/arithmetic.rs:28:5 | LL | f * 2.0; | ^^^^^^^ @@ -40,31 +40,31 @@ LL | f * 2.0; = note: `-D clippy::float-arithmetic` implied by `-D warnings` error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:39:5 + --> $DIR/arithmetic.rs:30:5 | LL | 1.0 + f; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:40:5 + --> $DIR/arithmetic.rs:31:5 | LL | f * 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:41:5 + --> $DIR/arithmetic.rs:32:5 | LL | f / 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:42:5 + --> $DIR/arithmetic.rs:33:5 | LL | f - 2.0 * 4.2; | ^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/arithmetic.rs:43:5 + --> $DIR/arithmetic.rs:34:5 | LL | -f; | ^^ diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 75cd7543823..c7b4865f5c2 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(dead_code, unused_assignments)] #[warn(clippy::assign_op_pattern)] fn main() { diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 194033981e1..646f9970122 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:14:5 + --> $DIR/assign_ops.rs:5:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -7,49 +7,49 @@ LL | a = a + 1; = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:15:5 + --> $DIR/assign_ops.rs:6:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:16:5 + --> $DIR/assign_ops.rs:7:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:17:5 + --> $DIR/assign_ops.rs:8:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:18:5 + --> $DIR/assign_ops.rs:9:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:19:5 + --> $DIR/assign_ops.rs:10:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:20:5 + --> $DIR/assign_ops.rs:11:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:21:5 + --> $DIR/assign_ops.rs:12:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> $DIR/assign_ops.rs:27:5 + --> $DIR/assign_ops.rs:18:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index 24d0d77a20d..4703a8c7777 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(unused_assignments)] #[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)] fn main() { diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 99983c0d054..872d6e0d734 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -1,5 +1,5 @@ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:14:5 + --> $DIR/assign_ops2.rs:5:5 | LL | a += a + 1; | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | a = a + a + 1; | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:15:5 + --> $DIR/assign_ops2.rs:6:5 | LL | a += 1 + a; | ^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | a = a + 1 + a; | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:16:5 + --> $DIR/assign_ops2.rs:7:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | a = a - (a - 1); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:17:5 + --> $DIR/assign_ops2.rs:8:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | a = a * a * 99; | ^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:18:5 + --> $DIR/assign_ops2.rs:9:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | a = a * 42 * a; | ^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:19:5 + --> $DIR/assign_ops2.rs:10:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | a = a / (a / 2); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:20:5 + --> $DIR/assign_ops2.rs:11:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | a = a % (a % 5); | ^^^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:21:5 + --> $DIR/assign_ops2.rs:12:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | a = a & a & 1; | ^^^^^^^^^^^^^ error: variable appears on both sides of an assignment operation - --> $DIR/assign_ops2.rs:22:5 + --> $DIR/assign_ops2.rs:13:5 | LL | a *= a * a; | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | a = a * a * a; | ^^^^^^^^^^^^^ error: manual implementation of an assign operation - --> $DIR/assign_ops2.rs:59:5 + --> $DIR/assign_ops2.rs:50:5 | LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 413c30a1945..4dbb5c67f5d 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::inline_always, clippy::deprecated_semver)] #[inline(always)] diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index bc40cb8c86d..39ddf6f226d 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -1,5 +1,5 @@ error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> $DIR/attrs.rs:12:1 + --> $DIR/attrs.rs:3:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[inline(always)] = note: `-D clippy::inline-always` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:32:14 + --> $DIR/attrs.rs:23:14 | LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[deprecated(since = "forever")] = note: `-D clippy::deprecated-semver` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:35:14 + --> $DIR/attrs.rs:26:14 | LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ diff --git a/tests/ui/author.rs b/tests/ui/author.rs index 4b7729e23b1..0a1be356896 100644 --- a/tests/ui/author.rs +++ b/tests/ui/author.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { #[clippy::author] let x: char = 0x45 as char; diff --git a/tests/ui/author/call.rs b/tests/ui/author/call.rs index 40cc0d7a919..e99c3c41dc4 100644 --- a/tests/ui/author/call.rs +++ b/tests/ui/author/call.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { #[clippy::author] let _ = ::std::cmp::min(3, 4); diff --git a/tests/ui/author/for_loop.rs b/tests/ui/author/for_loop.rs index 4acd0b452bb..b3dec876535 100644 --- a/tests/ui/author/for_loop.rs +++ b/tests/ui/author/for_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(stmt_expr_attributes)] fn main() { diff --git a/tests/ui/author/matches.rs b/tests/ui/author/matches.rs index 4c220dded8a..e6bf229103f 100644 --- a/tests/ui/author/matches.rs +++ b/tests/ui/author/matches.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(tool_attributes)] fn main() { diff --git a/tests/ui/author/matches.stderr b/tests/ui/author/matches.stderr index 5fb2a01f1b2..fa7e5cce43c 100644 --- a/tests/ui/author/matches.stderr +++ b/tests/ui/author/matches.stderr @@ -1,12 +1,12 @@ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/matches.rs:18:13 + --> $DIR/matches.rs:9:13 | LL | x | ^ | = note: `-D clippy::let-and-return` implied by `-D warnings` note: this expression can be directly returned - --> $DIR/matches.rs:17:21 + --> $DIR/matches.rs:8:21 | LL | let x = 3; | ^ diff --git a/tests/ui/bit_masks.rs b/tests/ui/bit_masks.rs index bda952db723..cfb493fb52a 100644 --- a/tests/ui/bit_masks.rs +++ b/tests/ui/bit_masks.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - const THREE_BITS: i64 = 7; const EVEN_MORE_REDIRECTION: i64 = THREE_BITS; diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index da883dcbfc4..159db0374d2 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -1,5 +1,5 @@ error: &-masking with zero - --> $DIR/bit_masks.rs:23:5 + --> $DIR/bit_masks.rs:14:5 | LL | x & 0 == 0; | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | x & 0 == 0; = note: `-D clippy::bad-bit-mask` implied by `-D warnings` error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/bit_masks.rs:23:5 + --> $DIR/bit_masks.rs:14:5 | LL | x & 0 == 0; | ^^^^^ @@ -15,73 +15,73 @@ LL | x & 0 == 0; = note: #[deny(clippy::erasing_op)] on by default error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> $DIR/bit_masks.rs:26:5 + --> $DIR/bit_masks.rs:17:5 | LL | x & 2 == 1; | ^^^^^^^^^^ error: incompatible bit mask: `_ | 3` can never be equal to `2` - --> $DIR/bit_masks.rs:30:5 + --> $DIR/bit_masks.rs:21:5 | LL | x | 3 == 2; | ^^^^^^^^^^ error: incompatible bit mask: `_ & 1` will never be higher than `1` - --> $DIR/bit_masks.rs:32:5 + --> $DIR/bit_masks.rs:23:5 | LL | x & 1 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> $DIR/bit_masks.rs:36:5 + --> $DIR/bit_masks.rs:27:5 | LL | x | 2 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ & 7` can never be equal to `8` - --> $DIR/bit_masks.rs:43:5 + --> $DIR/bit_masks.rs:34:5 | LL | x & THREE_BITS == 8; | ^^^^^^^^^^^^^^^^^^^ error: incompatible bit mask: `_ | 7` will never be lower than `7` - --> $DIR/bit_masks.rs:44:5 + --> $DIR/bit_masks.rs:35:5 | LL | x | EVEN_MORE_REDIRECTION < 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: &-masking with zero - --> $DIR/bit_masks.rs:46:5 + --> $DIR/bit_masks.rs:37:5 | LL | 0 & x == 0; | ^^^^^^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/bit_masks.rs:46:5 + --> $DIR/bit_masks.rs:37:5 | LL | 0 & x == 0; | ^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> $DIR/bit_masks.rs:50:5 + --> $DIR/bit_masks.rs:41:5 | LL | 1 < 2 | x; | ^^^^^^^^^ error: incompatible bit mask: `_ | 3` can never be equal to `2` - --> $DIR/bit_masks.rs:51:5 + --> $DIR/bit_masks.rs:42:5 | LL | 2 == 3 | x; | ^^^^^^^^^^ error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> $DIR/bit_masks.rs:52:5 + --> $DIR/bit_masks.rs:43:5 | LL | 1 == x & 2; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> $DIR/bit_masks.rs:63:5 + --> $DIR/bit_masks.rs:54:5 | LL | x | 1 > 3; | ^^^^^^^^^ @@ -89,19 +89,19 @@ LL | x | 1 > 3; = note: `-D clippy::ineffective-bit-mask` implied by `-D warnings` error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly - --> $DIR/bit_masks.rs:64:5 + --> $DIR/bit_masks.rs:55:5 | LL | x | 1 < 4; | ^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> $DIR/bit_masks.rs:65:5 + --> $DIR/bit_masks.rs:56:5 | LL | x | 1 <= 3; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared directly - --> $DIR/bit_masks.rs:66:5 + --> $DIR/bit_masks.rs:57:5 | LL | x | 1 >= 8; | ^^^^^^^^^^ diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index fef73e9d84f..ca9d8d16b78 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( dead_code, clippy::similar_names, diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr index 5b65d4ed13f..44123829fb0 100644 --- a/tests/ui/blacklisted_name.stderr +++ b/tests/ui/blacklisted_name.stderr @@ -1,5 +1,5 @@ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:20:9 + --> $DIR/blacklisted_name.rs:11:9 | LL | fn test(foo: ()) {} | ^^^ @@ -7,79 +7,79 @@ LL | fn test(foo: ()) {} = note: `-D clippy::blacklisted-name` implied by `-D warnings` error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:23:9 + --> $DIR/blacklisted_name.rs:14:9 | LL | let foo = 42; | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:24:9 + --> $DIR/blacklisted_name.rs:15:9 | LL | let bar = 42; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:25:9 + --> $DIR/blacklisted_name.rs:16:9 | LL | let baz = 42; | ^^^ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:31:10 + --> $DIR/blacklisted_name.rs:22:10 | LL | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:31:20 + --> $DIR/blacklisted_name.rs:22:20 | LL | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:31:26 + --> $DIR/blacklisted_name.rs:22:26 | LL | (foo, Some(bar), baz @ Some(_)) => (), | ^^^ error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:36:19 + --> $DIR/blacklisted_name.rs:27:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:37:13 + --> $DIR/blacklisted_name.rs:28:13 | LL | let mut bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:38:21 + --> $DIR/blacklisted_name.rs:29:21 | LL | if let Some(mut baz) = Some(42) {} | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:42:13 + --> $DIR/blacklisted_name.rs:33:13 | LL | let ref bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:43:21 + --> $DIR/blacklisted_name.rs:34:21 | LL | if let Some(ref baz) = Some(42) {} | ^^^ error: use of a blacklisted/placeholder name `bar` - --> $DIR/blacklisted_name.rs:47:17 + --> $DIR/blacklisted_name.rs:38:17 | LL | let ref mut bar = 0; | ^^^ error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:48:25 + --> $DIR/blacklisted_name.rs:39:25 | LL | if let Some(ref mut baz) = Some(42) {} | ^^^ diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index eaaf5e050bf..17ee1cd6873 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![allow(unused, clippy::let_and_return)] diff --git a/tests/ui/block_in_if_condition.stderr b/tests/ui/block_in_if_condition.stderr index 522c7dc779e..34c0454b782 100644 --- a/tests/ui/block_in_if_condition.stderr +++ b/tests/ui/block_in_if_condition.stderr @@ -1,5 +1,5 @@ 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' - --> $DIR/block_in_if_condition.rs:35:8 + --> $DIR/block_in_if_condition.rs:26:8 | LL | if { | ________^ @@ -19,7 +19,7 @@ LL | | } { } ... error: omit braces around single expression condition - --> $DIR/block_in_if_condition.rs:46:8 + --> $DIR/block_in_if_condition.rs:37:8 | LL | if { true } { | ^^^^^^^^ @@ -31,7 +31,7 @@ LL | if { true } { } ... 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' - --> $DIR/block_in_if_condition.rs:66:17 + --> $DIR/block_in_if_condition.rs:57:17 | LL | |x| { | _________________^ @@ -41,7 +41,7 @@ LL | | }, | |_____________^ 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' - --> $DIR/block_in_if_condition.rs:75:13 + --> $DIR/block_in_if_condition.rs:66:13 | LL | |x| { | _____________^ @@ -51,7 +51,7 @@ LL | | }, | |_________^ error: this boolean expression can be simplified - --> $DIR/block_in_if_condition.rs:85:8 + --> $DIR/block_in_if_condition.rs:76:8 | LL | if true && x == 3 { | ^^^^^^^^^^^^^^ help: try: `x == 3` diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 2a28d0af1b2..48c5e9d6d0c 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::bool_comparison)] fn main() { let x = true; diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index 7bd48f2e3dc..2d473d91d66 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -1,5 +1,5 @@ error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:13:8 + --> $DIR/bool_comparison.rs:4:8 | LL | if x == true { | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -7,79 +7,79 @@ LL | if x == true { = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:18:8 + --> $DIR/bool_comparison.rs:9:8 | LL | if x == false { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:23:8 + --> $DIR/bool_comparison.rs:14:8 | LL | if true == x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:28:8 + --> $DIR/bool_comparison.rs:19:8 | LL | if false == x { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:33:8 + --> $DIR/bool_comparison.rs:24:8 | LL | if x != true { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:38:8 + --> $DIR/bool_comparison.rs:29:8 | LL | if x != false { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:43:8 + --> $DIR/bool_comparison.rs:34:8 | LL | if true != x { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:48:8 + --> $DIR/bool_comparison.rs:39:8 | LL | if false != x { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:53:8 + --> $DIR/bool_comparison.rs:44:8 | LL | if x < true { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:58:8 + --> $DIR/bool_comparison.rs:49:8 | LL | if false < x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:63:8 + --> $DIR/bool_comparison.rs:54:8 | LL | if x > false { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:68:8 + --> $DIR/bool_comparison.rs:59:8 | LL | if true > x { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:74:8 + --> $DIR/bool_comparison.rs:65:8 | LL | if x < y { | ^^^^^ help: try simplifying it as shown: `!x & y` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:79:8 + --> $DIR/bool_comparison.rs:70:8 | LL | if x > y { | ^^^^^ help: try simplifying it as shown: `x & !y` diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index 8eb1b52577c..c8e01d4b258 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::nonminimal_bool, clippy::logic_bug)] #[allow(unused, clippy::many_single_char_names)] diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index c9446f5e4bc..eebab8c3e25 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -1,18 +1,18 @@ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:19:13 + --> $DIR/booleans.rs:10:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | = note: `-D clippy::logic-bug` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:19:18 + --> $DIR/booleans.rs:10:18 | LL | let _ = a && b || a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:21:13 + --> $DIR/booleans.rs:12:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -20,55 +20,55 @@ LL | let _ = !true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/booleans.rs:22:13 + --> $DIR/booleans.rs:13:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/booleans.rs:23:13 + --> $DIR/booleans.rs:14:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:24:13 + --> $DIR/booleans.rs:15:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:24:22 + --> $DIR/booleans.rs:15:22 | LL | let _ = false && a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:25:13 + --> $DIR/booleans.rs:16:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/booleans.rs:30:13 + --> $DIR/booleans.rs:21:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `!b || a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:40:13 + --> $DIR/booleans.rs:31:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:40:13 + --> $DIR/booleans.rs:31:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:41:13 + --> $DIR/booleans.rs:32:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:42:13 + --> $DIR/booleans.rs:33:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,31 +92,31 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:43:13 + --> $DIR/booleans.rs:34:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:43:13 + --> $DIR/booleans.rs:34:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:44:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:44:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a > b && a <= b; | ^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:46:13 + --> $DIR/booleans.rs:37:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,73 +128,73 @@ LL | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:54:13 + --> $DIR/booleans.rs:45:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:56:13 + --> $DIR/booleans.rs:47:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:58:13 + --> $DIR/booleans.rs:49:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:60:13 + --> $DIR/booleans.rs:51:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:62:13 + --> $DIR/booleans.rs:53:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:63:13 + --> $DIR/booleans.rs:54:13 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!(!c ^ c) || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:64:13 + --> $DIR/booleans.rs:55:13 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!c ^ c) || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:65:13 + --> $DIR/booleans.rs:56:13 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `!c ^ c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:137:8 + --> $DIR/booleans.rs:128:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:138:8 + --> $DIR/booleans.rs:129:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:141:8 + --> $DIR/booleans.rs:132:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:142:8 + --> $DIR/booleans.rs:133:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index cf204150f8b..3b53aab7e23 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::borrowed_box)] #![allow(clippy::blacklisted_name)] #![allow(unused_variables)] diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 33bd50286a5..0cb455433c4 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,29 +1,29 @@ error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:15:19 + --> $DIR/borrow_box.rs:6:19 | LL | pub fn test1(foo: &mut Box<bool>) { | ^^^^^^^^^^^^^^ help: try: `&mut bool` | note: lint level defined here - --> $DIR/borrow_box.rs:10:9 + --> $DIR/borrow_box.rs:1:9 | LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:20:14 + --> $DIR/borrow_box.rs:11:14 | LL | let foo: &Box<bool>; | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:24:10 + --> $DIR/borrow_box.rs:15:10 | LL | foo: &'a Box<bool>, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box<T>`. Consider using just `&T` - --> $DIR/borrow_box.rs:28:17 + --> $DIR/borrow_box.rs:19:17 | LL | fn test4(a: &Box<bool>); | ^^^^^^^^^^ help: try: `&bool` diff --git a/tests/ui/box_vec.rs b/tests/ui/box_vec.rs index 48523054097..af3ba5b4d35 100644 --- a/tests/ui/box_vec.rs +++ b/tests/ui/box_vec.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::blacklisted_name)] diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index 8b5fc24a371..fca12eddd57 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>` - --> $DIR/box_vec.rs:23:18 + --> $DIR/box_vec.rs:14:18 | LL | pub fn test(foo: Box<Vec<bool>>) { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin-type-shadow.rs index e9df0992c5e..69b8b6a0e68 100644 --- a/tests/ui/builtin-type-shadow.rs +++ b/tests/ui/builtin-type-shadow.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::builtin_type_shadow)] #![allow(non_camel_case_types)] diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr index 940a6dc2bcc..5714f2094da 100644 --- a/tests/ui/builtin-type-shadow.stderr +++ b/tests/ui/builtin-type-shadow.stderr @@ -1,5 +1,5 @@ error: This generic shadows the built-in type `u32` - --> $DIR/builtin-type-shadow.rs:13:8 + --> $DIR/builtin-type-shadow.rs:4:8 | LL | fn foo<u32>(a: u32) -> u32 { | ^^^ @@ -7,7 +7,7 @@ LL | fn foo<u32>(a: u32) -> u32 { = note: `-D clippy::builtin-type-shadow` implied by `-D warnings` error[E0308]: mismatched types - --> $DIR/builtin-type-shadow.rs:14:5 + --> $DIR/builtin-type-shadow.rs:5:5 | LL | fn foo<u32>(a: u32) -> u32 { | --- expected `u32` because of return type diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 6bc9b5ddecd..c724ee21be3 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[deny(clippy::naive_bytecount)] fn main() { let x = vec![0_u8; 16]; diff --git a/tests/ui/bytecount.stderr b/tests/ui/bytecount.stderr index a2890fe5a6d..43bc4b3c61e 100644 --- a/tests/ui/bytecount.stderr +++ b/tests/ui/bytecount.stderr @@ -1,23 +1,23 @@ error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:14:13 + --> $DIR/bytecount.rs:5:13 | LL | let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)` | note: lint level defined here - --> $DIR/bytecount.rs:10:8 + --> $DIR/bytecount.rs:1:8 | LL | #[deny(clippy::naive_bytecount)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:16:13 + --> $DIR/bytecount.rs:7:13 | LL | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count((&x[..]), 0)` error: You appear to be counting bytes the naive way - --> $DIR/bytecount.rs:28:13 + --> $DIR/bytecount.rs:19:13 | LL | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)` diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 51e41b70172..5f4de9894c7 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 78631ffa8c8..92587312a53 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:20:5 + --> $DIR/cast.rs:11:5 | LL | 1i32 as f32; | ^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | 1i32 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting i64 to f32 causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:21:5 + --> $DIR/cast.rs:12:5 | LL | 1i64 as f32; | ^^^^^^^^^^^ error: casting i64 to f64 causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:13:5 | LL | 1i64 as f64; | ^^^^^^^^^^^ error: casting u32 to f32 causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:23:5 + --> $DIR/cast.rs:14:5 | LL | 1u32 as f32; | ^^^^^^^^^^^ error: casting u64 to f32 causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast.rs:24:5 + --> $DIR/cast.rs:15:5 | LL | 1u64 as f32; | ^^^^^^^^^^^ error: casting u64 to f64 causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast.rs:25:5 + --> $DIR/cast.rs:16:5 | LL | 1u64 as f64; | ^^^^^^^^^^^ error: casting f32 to i32 may truncate the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:18:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -45,13 +45,13 @@ LL | 1f32 as i32; = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting f32 to u32 may truncate the value - --> $DIR/cast.rs:28:5 + --> $DIR/cast.rs:19:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ error: casting f32 to u32 may lose the sign of the value - --> $DIR/cast.rs:28:5 + --> $DIR/cast.rs:19:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -59,49 +59,49 @@ LL | 1f32 as u32; = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting f64 to f32 may truncate the value - --> $DIR/cast.rs:29:5 + --> $DIR/cast.rs:20:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ error: casting i32 to i8 may truncate the value - --> $DIR/cast.rs:30:5 + --> $DIR/cast.rs:21:5 | LL | 1i32 as i8; | ^^^^^^^^^^ error: casting i32 to u8 may lose the sign of the value - --> $DIR/cast.rs:31:5 + --> $DIR/cast.rs:22:5 | LL | 1i32 as u8; | ^^^^^^^^^^ error: casting i32 to u8 may truncate the value - --> $DIR/cast.rs:31:5 + --> $DIR/cast.rs:22:5 | LL | 1i32 as u8; | ^^^^^^^^^^ error: casting f64 to isize may truncate the value - --> $DIR/cast.rs:32:5 + --> $DIR/cast.rs:23:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ error: casting f64 to usize may truncate the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:24:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting f64 to usize may lose the sign of the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:24:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting u8 to i8 may wrap around the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:26:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -109,31 +109,31 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting u16 to i16 may wrap around the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:27:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting u32 to i32 may wrap around the value - --> $DIR/cast.rs:37:5 + --> $DIR/cast.rs:28:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting u64 to i64 may wrap around the value - --> $DIR/cast.rs:38:5 + --> $DIR/cast.rs:29:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting usize to isize may wrap around the value - --> $DIR/cast.rs:39:5 + --> $DIR/cast.rs:30:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting f32 to f64 may become silently lossy if types change - --> $DIR/cast.rs:41:5 + --> $DIR/cast.rs:32:5 | LL | 1.0f32 as f64; | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` @@ -141,25 +141,25 @@ LL | 1.0f32 as f64; = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting u8 to u16 may become silently lossy if types change - --> $DIR/cast.rs:43:5 + --> $DIR/cast.rs:34:5 | LL | (1u8 + 1u8) as u16; | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` error: casting i32 to u32 may lose the sign of the value - --> $DIR/cast.rs:45:5 + --> $DIR/cast.rs:36:5 | LL | 1i32 as u32; | ^^^^^^^^^^^ error: casting isize to usize may lose the sign of the value - --> $DIR/cast.rs:46:5 + --> $DIR/cast.rs:37:5 | LL | 1isize as usize; | ^^^^^^^^^^^^^^^ error: casting to the same type is unnecessary (`i32` -> `i32`) - --> $DIR/cast.rs:49:5 + --> $DIR/cast.rs:40:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ @@ -167,13 +167,13 @@ LL | 1i32 as i32; = note: `-D clippy::unnecessary-cast` implied by `-D warnings` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> $DIR/cast.rs:50:5 + --> $DIR/cast.rs:41:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ error: casting to the same type is unnecessary (`bool` -> `bool`) - --> $DIR/cast.rs:51:5 + --> $DIR/cast.rs:42:5 | LL | false as bool; | ^^^^^^^^^^^^^ diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index dba19dfd023..2814fe6c03d 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! Test casts for alignment issues #![feature(rustc_private)] diff --git a/tests/ui/cast_alignment.stderr b/tests/ui/cast_alignment.stderr index 261bce613bf..0077be1b570 100644 --- a/tests/ui/cast_alignment.stderr +++ b/tests/ui/cast_alignment.stderr @@ -1,5 +1,5 @@ error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) - --> $DIR/cast_alignment.rs:21:5 + --> $DIR/cast_alignment.rs:12:5 | LL | (&1u8 as *const u8) as *const u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | (&1u8 as *const u8) as *const u16; = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings` error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) - --> $DIR/cast_alignment.rs:22:5 + --> $DIR/cast_alignment.rs:13:5 | LL | (&mut 1u8 as *mut u8) as *mut u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed index 5f4e54eb565..22df1137922 100644 --- a/tests/ui/cast_lossless_float.fixed +++ b/tests/ui/cast_lossless_float.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index b818010feb2..c86b4d05f28 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.stderr b/tests/ui/cast_lossless_float.stderr index aa48bd4d1c7..c2b01e83bbe 100644 --- a/tests/ui/cast_lossless_float.stderr +++ b/tests/ui/cast_lossless_float.stderr @@ -1,5 +1,5 @@ error: casting i8 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:16:5 + --> $DIR/cast_lossless_float.rs:7:5 | LL | 1i8 as f32; | ^^^^^^^^^^ help: try: `f32::from(1i8)` @@ -7,55 +7,55 @@ LL | 1i8 as f32; = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting i8 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:17:5 + --> $DIR/cast_lossless_float.rs:8:5 | LL | 1i8 as f64; | ^^^^^^^^^^ help: try: `f64::from(1i8)` error: casting u8 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:18:5 + --> $DIR/cast_lossless_float.rs:9:5 | LL | 1u8 as f32; | ^^^^^^^^^^ help: try: `f32::from(1u8)` error: casting u8 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:19:5 + --> $DIR/cast_lossless_float.rs:10:5 | LL | 1u8 as f64; | ^^^^^^^^^^ help: try: `f64::from(1u8)` error: casting i16 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:20:5 + --> $DIR/cast_lossless_float.rs:11:5 | LL | 1i16 as f32; | ^^^^^^^^^^^ help: try: `f32::from(1i16)` error: casting i16 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:21:5 + --> $DIR/cast_lossless_float.rs:12:5 | LL | 1i16 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1i16)` error: casting u16 to f32 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:22:5 + --> $DIR/cast_lossless_float.rs:13:5 | LL | 1u16 as f32; | ^^^^^^^^^^^ help: try: `f32::from(1u16)` error: casting u16 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:23:5 + --> $DIR/cast_lossless_float.rs:14:5 | LL | 1u16 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1u16)` error: casting i32 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:24:5 + --> $DIR/cast_lossless_float.rs:15:5 | LL | 1i32 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1i32)` error: casting u32 to f64 may become silently lossy if types change - --> $DIR/cast_lossless_float.rs:25:5 + --> $DIR/cast_lossless_float.rs:16:5 | LL | 1u32 as f64; | ^^^^^^^^^^^ help: try: `f64::from(1u32)` diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 83f3e024209..e5b33d5e1b0 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index 75c63957001..61170625c8a 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.stderr b/tests/ui/cast_lossless_integer.stderr index f49dc0d9eff..ac385298ecb 100644 --- a/tests/ui/cast_lossless_integer.stderr +++ b/tests/ui/cast_lossless_integer.stderr @@ -1,5 +1,5 @@ error: casting i8 to i16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:16:5 + --> $DIR/cast_lossless_integer.rs:7:5 | LL | 1i8 as i16; | ^^^^^^^^^^ help: try: `i16::from(1i8)` @@ -7,103 +7,103 @@ LL | 1i8 as i16; = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting i8 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:17:5 + --> $DIR/cast_lossless_integer.rs:8:5 | LL | 1i8 as i32; | ^^^^^^^^^^ help: try: `i32::from(1i8)` error: casting i8 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:18:5 + --> $DIR/cast_lossless_integer.rs:9:5 | LL | 1i8 as i64; | ^^^^^^^^^^ help: try: `i64::from(1i8)` error: casting u8 to i16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:19:5 + --> $DIR/cast_lossless_integer.rs:10:5 | LL | 1u8 as i16; | ^^^^^^^^^^ help: try: `i16::from(1u8)` error: casting u8 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:20:5 + --> $DIR/cast_lossless_integer.rs:11:5 | LL | 1u8 as i32; | ^^^^^^^^^^ help: try: `i32::from(1u8)` error: casting u8 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:21:5 + --> $DIR/cast_lossless_integer.rs:12:5 | LL | 1u8 as i64; | ^^^^^^^^^^ help: try: `i64::from(1u8)` error: casting u8 to u16 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:22:5 + --> $DIR/cast_lossless_integer.rs:13:5 | LL | 1u8 as u16; | ^^^^^^^^^^ help: try: `u16::from(1u8)` error: casting u8 to u32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:23:5 + --> $DIR/cast_lossless_integer.rs:14:5 | LL | 1u8 as u32; | ^^^^^^^^^^ help: try: `u32::from(1u8)` error: casting u8 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:24:5 + --> $DIR/cast_lossless_integer.rs:15:5 | LL | 1u8 as u64; | ^^^^^^^^^^ help: try: `u64::from(1u8)` error: casting i16 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:25:5 + --> $DIR/cast_lossless_integer.rs:16:5 | LL | 1i16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1i16)` error: casting i16 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:26:5 + --> $DIR/cast_lossless_integer.rs:17:5 | LL | 1i16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i16)` error: casting u16 to i32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:27:5 + --> $DIR/cast_lossless_integer.rs:18:5 | LL | 1u16 as i32; | ^^^^^^^^^^^ help: try: `i32::from(1u16)` error: casting u16 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:28:5 + --> $DIR/cast_lossless_integer.rs:19:5 | LL | 1u16 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u16)` error: casting u16 to u32 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:29:5 + --> $DIR/cast_lossless_integer.rs:20:5 | LL | 1u16 as u32; | ^^^^^^^^^^^ help: try: `u32::from(1u16)` error: casting u16 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:30:5 + --> $DIR/cast_lossless_integer.rs:21:5 | LL | 1u16 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u16)` error: casting i32 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:31:5 + --> $DIR/cast_lossless_integer.rs:22:5 | LL | 1i32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1i32)` error: casting u32 to i64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:32:5 + --> $DIR/cast_lossless_integer.rs:23:5 | LL | 1u32 as i64; | ^^^^^^^^^^^ help: try: `i64::from(1u32)` error: casting u32 to u64 may become silently lossy if types change - --> $DIR/cast_lossless_integer.rs:33:5 + --> $DIR/cast_lossless_integer.rs:24:5 | LL | 1u32 as u64; | ^^^^^^^^^^^ help: try: `u64::from(1u32)` diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index 8f691104c51..fde178b1874 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast_size.stderr b/tests/ui/cast_size.stderr index eab1014128a..9346deb19ec 100644 --- a/tests/ui/cast_size.stderr +++ b/tests/ui/cast_size.stderr @@ -1,5 +1,5 @@ error: casting isize to i8 may truncate the value - --> $DIR/cast_size.rs:20:5 + --> $DIR/cast_size.rs:11:5 | LL | 1isize as i8; | ^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | 1isize as i8; = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting isize to f64 causes a loss of precision on targets with 64-bit wide pointers (isize is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast_size.rs:21:5 + --> $DIR/cast_size.rs:12:5 | LL | 1isize as f64; | ^^^^^^^^^^^^^ @@ -15,31 +15,31 @@ LL | 1isize as f64; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting usize to f64 causes a loss of precision on targets with 64-bit wide pointers (usize is 64 bits wide, but f64's mantissa is only 52 bits wide) - --> $DIR/cast_size.rs:22:5 + --> $DIR/cast_size.rs:13:5 | LL | 1usize as f64; | ^^^^^^^^^^^^^ error: casting isize to f32 causes a loss of precision (isize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast_size.rs:23:5 + --> $DIR/cast_size.rs:14:5 | LL | 1isize as f32; | ^^^^^^^^^^^^^ error: casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide) - --> $DIR/cast_size.rs:24:5 + --> $DIR/cast_size.rs:15:5 | LL | 1usize as f32; | ^^^^^^^^^^^^^ error: casting isize to i32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:25:5 + --> $DIR/cast_size.rs:16:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ error: casting isize to u32 may lose the sign of the value - --> $DIR/cast_size.rs:26:5 + --> $DIR/cast_size.rs:17:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -47,25 +47,25 @@ LL | 1isize as u32; = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting isize to u32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:26:5 + --> $DIR/cast_size.rs:17:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ error: casting usize to u32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:27:5 + --> $DIR/cast_size.rs:18:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ error: casting usize to i32 may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:28:5 + --> $DIR/cast_size.rs:19:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting usize to i32 may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:28:5 + --> $DIR/cast_size.rs:19:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -73,49 +73,49 @@ LL | 1usize as i32; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting i64 to isize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:30:5 + --> $DIR/cast_size.rs:21:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ error: casting i64 to usize may lose the sign of the value - --> $DIR/cast_size.rs:31:5 + --> $DIR/cast_size.rs:22:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ error: casting i64 to usize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:31:5 + --> $DIR/cast_size.rs:22:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ error: casting u64 to isize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:32:5 + --> $DIR/cast_size.rs:23:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting u64 to isize may wrap around the value on targets with 64-bit wide pointers - --> $DIR/cast_size.rs:32:5 + --> $DIR/cast_size.rs:23:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting u64 to usize may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:33:5 + --> $DIR/cast_size.rs:24:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ error: casting u32 to isize may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast_size.rs:34:5 + --> $DIR/cast_size.rs:25:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting i32 to usize may lose the sign of the value - --> $DIR/cast_size.rs:37:5 + --> $DIR/cast_size.rs:28:5 | LL | 1i32 as usize; | ^^^^^^^^^^^^^ diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index 614cd3e30ec..7f4a86ae185 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(stmt_expr_attributes)] #![warn(clippy::deprecated_cfg_attr)] diff --git a/tests/ui/cfg_attr_rustfmt.stderr b/tests/ui/cfg_attr_rustfmt.stderr index 233aafc3c79..e60f5f25535 100644 --- a/tests/ui/cfg_attr_rustfmt.stderr +++ b/tests/ui/cfg_attr_rustfmt.stderr @@ -1,5 +1,5 @@ error: `cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes - --> $DIR/cfg_attr_rustfmt.rs:25:5 + --> $DIR/cfg_attr_rustfmt.rs:16:5 | LL | #[cfg_attr(rustfmt, rustfmt::skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]` @@ -7,13 +7,13 @@ LL | #[cfg_attr(rustfmt, rustfmt::skip)] = note: `-D clippy::deprecated-cfg-attr` implied by `-D warnings` error: `cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes - --> $DIR/cfg_attr_rustfmt.rs:29:1 + --> $DIR/cfg_attr_rustfmt.rs:20:1 | LL | #[cfg_attr(rustfmt, rustfmt_skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]` error: `cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes - --> $DIR/cfg_attr_rustfmt.rs:35:5 + --> $DIR/cfg_attr_rustfmt.rs:26:5 | LL | #![cfg_attr(rustfmt, rustfmt_skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#![rustfmt::skip]` diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index 663962afeae..211cbfe98f3 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::char_lit_as_u8)] #![allow(unused_variables)] fn main() { diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index a577c55d261..52f29a3f553 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -1,5 +1,5 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so casting to u8 truncates them - --> $DIR/char_lit_as_u8.rs:13:13 + --> $DIR/char_lit_as_u8.rs:4:13 | LL | let c = 'a' as u8; | ^^^^^^^^^ diff --git a/tests/ui/checked_unwrap.rs b/tests/ui/checked_unwrap.rs index 4d250a80e90..21f9e33201f 100644 --- a/tests/ui/checked_unwrap.rs +++ b/tests/ui/checked_unwrap.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] #![allow(clippy::if_same_then_else)] diff --git a/tests/ui/checked_unwrap.stderr b/tests/ui/checked_unwrap.stderr index 7e6a487ad1e..514814b0ee0 100644 --- a/tests/ui/checked_unwrap.stderr +++ b/tests/ui/checked_unwrap.stderr @@ -1,5 +1,5 @@ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:16:9 + --> $DIR/checked_unwrap.rs:7:9 | LL | if x.is_some() { | ----------- the check is happening here @@ -7,13 +7,13 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ | note: lint level defined here - --> $DIR/checked_unwrap.rs:10:35 + --> $DIR/checked_unwrap.rs:1:35 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:18:9 + --> $DIR/checked_unwrap.rs:9:9 | LL | if x.is_some() { | ----------- because of this check @@ -22,13 +22,13 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ | note: lint level defined here - --> $DIR/checked_unwrap.rs:10:9 + --> $DIR/checked_unwrap.rs:1:9 | LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:21:9 + --> $DIR/checked_unwrap.rs:12:9 | LL | if x.is_none() { | ----------- because of this check @@ -36,7 +36,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:23:9 + --> $DIR/checked_unwrap.rs:14:9 | LL | if x.is_none() { | ----------- the check is happening here @@ -45,7 +45,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:27:9 + --> $DIR/checked_unwrap.rs:18:9 | LL | if x.is_ok() { | --------- the check is happening here @@ -53,7 +53,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:28:9 + --> $DIR/checked_unwrap.rs:19:9 | LL | if x.is_ok() { | --------- because of this check @@ -62,7 +62,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:30:9 + --> $DIR/checked_unwrap.rs:21:9 | LL | if x.is_ok() { | --------- because of this check @@ -71,7 +71,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:31:9 + --> $DIR/checked_unwrap.rs:22:9 | LL | if x.is_ok() { | --------- the check is happening here @@ -80,7 +80,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:34:9 + --> $DIR/checked_unwrap.rs:25:9 | LL | if x.is_err() { | ---------- because of this check @@ -88,7 +88,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:35:9 + --> $DIR/checked_unwrap.rs:26:9 | LL | if x.is_err() { | ---------- the check is happening here @@ -97,7 +97,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:37:9 + --> $DIR/checked_unwrap.rs:28:9 | LL | if x.is_err() { | ---------- the check is happening here @@ -106,7 +106,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:38:9 + --> $DIR/checked_unwrap.rs:29:9 | LL | if x.is_err() { | ---------- because of this check @@ -115,7 +115,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:55:9 + --> $DIR/checked_unwrap.rs:46:9 | LL | if x.is_ok() && y.is_err() { | --------- the check is happening here @@ -123,7 +123,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:56:9 + --> $DIR/checked_unwrap.rs:47:9 | LL | if x.is_ok() && y.is_err() { | --------- because of this check @@ -132,7 +132,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:57:9 + --> $DIR/checked_unwrap.rs:48:9 | LL | if x.is_ok() && y.is_err() { | ---------- because of this check @@ -141,7 +141,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:58:9 + --> $DIR/checked_unwrap.rs:49:9 | LL | if x.is_ok() && y.is_err() { | ---------- the check is happening here @@ -150,7 +150,7 @@ LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:72:9 + --> $DIR/checked_unwrap.rs:63:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -159,7 +159,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:73:9 + --> $DIR/checked_unwrap.rs:64:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -168,7 +168,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:74:9 + --> $DIR/checked_unwrap.rs:65:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -177,7 +177,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:75:9 + --> $DIR/checked_unwrap.rs:66:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -186,7 +186,7 @@ LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:79:9 + --> $DIR/checked_unwrap.rs:70:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -194,7 +194,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:80:9 + --> $DIR/checked_unwrap.rs:71:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -203,7 +203,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:81:9 + --> $DIR/checked_unwrap.rs:72:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -212,7 +212,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:82:9 + --> $DIR/checked_unwrap.rs:73:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -221,7 +221,7 @@ LL | y.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:83:9 + --> $DIR/checked_unwrap.rs:74:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here @@ -230,7 +230,7 @@ LL | z.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:84:9 + --> $DIR/checked_unwrap.rs:75:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check @@ -239,7 +239,7 @@ LL | z.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:92:9 + --> $DIR/checked_unwrap.rs:83:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -248,7 +248,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:93:9 + --> $DIR/checked_unwrap.rs:84:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -257,7 +257,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:94:9 + --> $DIR/checked_unwrap.rs:85:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -266,7 +266,7 @@ LL | y.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap_err()` will always panic. - --> $DIR/checked_unwrap.rs:95:9 + --> $DIR/checked_unwrap.rs:86:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -275,7 +275,7 @@ LL | y.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:96:9 + --> $DIR/checked_unwrap.rs:87:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check @@ -284,7 +284,7 @@ LL | z.unwrap(); // will panic | ^^^^^^^^^^ error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:97:9 + --> $DIR/checked_unwrap.rs:88:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- the check is happening here @@ -293,7 +293,7 @@ LL | z.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`. - --> $DIR/checked_unwrap.rs:105:13 + --> $DIR/checked_unwrap.rs:96:13 | LL | if x.is_some() { | ----------- the check is happening here @@ -301,7 +301,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: This call to `unwrap()` will always panic. - --> $DIR/checked_unwrap.rs:107:13 + --> $DIR/checked_unwrap.rs:98:13 | LL | if x.is_some() { | ----------- because of this check diff --git a/tests/ui/clone_on_copy_impl.rs b/tests/ui/clone_on_copy_impl.rs index 058cbf7a16c..8f9f2a0db8c 100644 --- a/tests/ui/clone_on_copy_impl.rs +++ b/tests/ui/clone_on_copy_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::fmt; use std::marker::PhantomData; diff --git a/tests/ui/clone_on_copy_mut.rs b/tests/ui/clone_on_copy_mut.rs index 82f411d5c9d..3cbbcb7c083 100644 --- a/tests/ui/clone_on_copy_mut.rs +++ b/tests/ui/clone_on_copy_mut.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub fn dec_read_dec(i: &mut i32) -> i32 { *i -= 1; let ret = *i; diff --git a/tests/ui/cmp_nan.rs b/tests/ui/cmp_nan.rs index d6bdb5894d5..33e039308ec 100644 --- a/tests/ui/cmp_nan.rs +++ b/tests/ui/cmp_nan.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::cmp_nan)] #[allow(clippy::float_cmp, clippy::no_effect, clippy::unnecessary_operation)] fn main() { diff --git a/tests/ui/cmp_nan.stderr b/tests/ui/cmp_nan.stderr index 2a7772308b8..421f3451823 100644 --- a/tests/ui/cmp_nan.stderr +++ b/tests/ui/cmp_nan.stderr @@ -1,5 +1,5 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:14:5 + --> $DIR/cmp_nan.rs:5:5 | LL | x == std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ @@ -7,67 +7,67 @@ LL | x == std::f32::NAN; = note: `-D clippy::cmp-nan` implied by `-D warnings` error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:15:5 + --> $DIR/cmp_nan.rs:6:5 | LL | x != std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:16:5 + --> $DIR/cmp_nan.rs:7:5 | LL | x < std::f32::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:17:5 + --> $DIR/cmp_nan.rs:8:5 | LL | x > std::f32::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:18:5 + --> $DIR/cmp_nan.rs:9:5 | LL | x <= std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:19:5 + --> $DIR/cmp_nan.rs:10:5 | LL | x >= std::f32::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:22:5 + --> $DIR/cmp_nan.rs:13:5 | LL | y == std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:23:5 + --> $DIR/cmp_nan.rs:14:5 | LL | y != std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:24:5 + --> $DIR/cmp_nan.rs:15:5 | LL | y < std::f64::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:25:5 + --> $DIR/cmp_nan.rs:16:5 | LL | y > std::f64::NAN; | ^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:26:5 + --> $DIR/cmp_nan.rs:17:5 | LL | y <= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead - --> $DIR/cmp_nan.rs:27:5 + --> $DIR/cmp_nan.rs:18:5 | LL | y >= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 37615c9e113..2d2d04178c3 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::cmp_null)] #![allow(unused_mut)] diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 68789b5b635..063e716676c 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -1,5 +1,5 @@ error: Comparing with null is better expressed by the .is_null() method - --> $DIR/cmp_null.rs:18:8 + --> $DIR/cmp_null.rs:9:8 | LL | if p == ptr::null() { | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | if p == ptr::null() { = note: `-D clippy::cmp-null` implied by `-D warnings` error: Comparing with null is better expressed by the .is_null() method - --> $DIR/cmp_null.rs:23:8 + --> $DIR/cmp_null.rs:14:8 | LL | if m == ptr::null_mut() { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 53de5136105..a5f92b30bc2 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation)] fn main() { diff --git a/tests/ui/cmp_owned.stderr b/tests/ui/cmp_owned.stderr index 9177c6bd73e..9be749f8d04 100644 --- a/tests/ui/cmp_owned.stderr +++ b/tests/ui/cmp_owned.stderr @@ -1,5 +1,5 @@ error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:14:14 + --> $DIR/cmp_owned.rs:5:14 | LL | x != "foo".to_string(); | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` @@ -7,49 +7,49 @@ LL | x != "foo".to_string(); = note: `-D clippy::cmp-owned` implied by `-D warnings` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:16:9 + --> $DIR/cmp_owned.rs:7:9 | LL | "foo".to_string() != x; | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:23:10 + --> $DIR/cmp_owned.rs:14:10 | LL | x != "foo".to_owned(); | ^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:25:10 + --> $DIR/cmp_owned.rs:16:10 | LL | x != String::from("foo"); | ^^^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:29:5 + --> $DIR/cmp_owned.rs:20:5 | LL | Foo.to_owned() == Foo; | ^^^^^^^^^^^^^^ help: try: `Foo` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:31:30 + --> $DIR/cmp_owned.rs:22:30 | LL | "abc".chars().filter(|c| c.to_owned() != 'X'); | ^^^^^^^^^^^^ help: try: `*c` error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:38:5 + --> $DIR/cmp_owned.rs:29:5 | LL | y.to_owned() == *x; | ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:43:5 + --> $DIR/cmp_owned.rs:34:5 | LL | y.to_owned() == **x; | ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating error: this creates an owned instance just for comparison - --> $DIR/cmp_owned.rs:50:9 + --> $DIR/cmp_owned.rs:41:9 | LL | self.to_owned() == *other | ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index 6828743abf3..e8918ddecb5 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[rustfmt::skip] #[warn(clippy::collapsible_if)] fn main() { diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 2c60234eb5d..1b9195563e5 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -1,5 +1,5 @@ error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:15:5 + --> $DIR/collapsible_if.rs:6:5 | LL | / if x == "hello" { LL | | if y == "world" { @@ -17,7 +17,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:21:5 + --> $DIR/collapsible_if.rs:12:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -33,7 +33,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:27:5 + --> $DIR/collapsible_if.rs:18:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -49,7 +49,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:33:5 + --> $DIR/collapsible_if.rs:24:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -65,7 +65,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:39:5 + --> $DIR/collapsible_if.rs:30:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -81,7 +81,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:45:5 + --> $DIR/collapsible_if.rs:36:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -97,7 +97,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:54:12 + --> $DIR/collapsible_if.rs:45:12 | LL | } else { | ____________^ @@ -114,7 +114,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:62:12 + --> $DIR/collapsible_if.rs:53:12 | LL | } else { | ____________^ @@ -131,7 +131,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:70:12 + --> $DIR/collapsible_if.rs:61:12 | LL | } else { | ____________^ @@ -153,7 +153,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:81:12 + --> $DIR/collapsible_if.rs:72:12 | LL | } else { | ____________^ @@ -175,7 +175,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:92:12 + --> $DIR/collapsible_if.rs:83:12 | LL | } else { | ____________^ @@ -197,7 +197,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:103:12 + --> $DIR/collapsible_if.rs:94:12 | LL | } else { | ____________^ @@ -219,7 +219,7 @@ LL | } | error: this `else { if .. }` block can be collapsed - --> $DIR/collapsible_if.rs:114:12 + --> $DIR/collapsible_if.rs:105:12 | LL | } else { | ____________^ @@ -241,7 +241,7 @@ LL | } | error: this if statement can be collapsed - --> $DIR/collapsible_if.rs:173:5 + --> $DIR/collapsible_if.rs:164:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index 9d75de62d74..cfece3768ef 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(unused, clippy::needless_pass_by_value)] #![feature(associated_type_defaults)] diff --git a/tests/ui/complex_types.stderr b/tests/ui/complex_types.stderr index 8f46d38921d..8f5dbd27956 100644 --- a/tests/ui/complex_types.stderr +++ b/tests/ui/complex_types.stderr @@ -1,5 +1,5 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:16:12 + --> $DIR/complex_types.rs:7:12 | LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,85 +7,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); = note: `-D clippy::type-complexity` implied by `-D warnings` error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:17:12 + --> $DIR/complex_types.rs:8:12 | LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:20:8 + --> $DIR/complex_types.rs:11:8 | LL | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:23:11 + --> $DIR/complex_types.rs:14:11 | LL | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:26:11 + --> $DIR/complex_types.rs:17:11 | LL | Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:27:17 + --> $DIR/complex_types.rs:18:17 | LL | Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:31:14 + --> $DIR/complex_types.rs:22:14 | LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:32:30 + --> $DIR/complex_types.rs:23:30 | LL | fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:36:14 + --> $DIR/complex_types.rs:27:14 | LL | const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:37:14 + --> $DIR/complex_types.rs:28:14 | LL | type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:38:25 + --> $DIR/complex_types.rs:29:25 | LL | fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:39:29 + --> $DIR/complex_types.rs:30:29 | LL | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:42:15 + --> $DIR/complex_types.rs:33:15 | LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:46:14 + --> $DIR/complex_types.rs:37:14 | LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> $DIR/complex_types.rs:49:13 + --> $DIR/complex_types.rs:40:13 | LL | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const_static_lifetime.rs b/tests/ui/const_static_lifetime.rs index 3e1aa94f969..745821a1503 100644 --- a/tests/ui/const_static_lifetime.rs +++ b/tests/ui/const_static_lifetime.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[derive(Debug)] struct Foo {} diff --git a/tests/ui/const_static_lifetime.stderr b/tests/ui/const_static_lifetime.stderr index b3fabb3522f..c329e860558 100644 --- a/tests/ui/const_static_lifetime.stderr +++ b/tests/ui/const_static_lifetime.stderr @@ -1,5 +1,5 @@ error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:13:17 + --> $DIR/const_static_lifetime.rs:4:17 | LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` @@ -7,73 +7,73 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin = note: `-D clippy::const-static-lifetime` implied by `-D warnings` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:17:21 + --> $DIR/const_static_lifetime.rs:8:21 | LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:19:32 + --> $DIR/const_static_lifetime.rs:10:32 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:19:47 + --> $DIR/const_static_lifetime.rs:10:47 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:21:18 + --> $DIR/const_static_lifetime.rs:12:18 | LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:21:30 + --> $DIR/const_static_lifetime.rs:12:30 | LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:23:17 + --> $DIR/const_static_lifetime.rs:14:17 | LL | const VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:25:29 + --> $DIR/const_static_lifetime.rs:16:29 | LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:25:39 + --> $DIR/const_static_lifetime.rs:16:39 | LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^---- help: consider removing `'static`: `&str` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:27:20 + --> $DIR/const_static_lifetime.rs:18:20 | LL | const VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:29:19 + --> $DIR/const_static_lifetime.rs:20:19 | LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:31:19 + --> $DIR/const_static_lifetime.rs:22:19 | LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: Constants have by default a `'static` lifetime - --> $DIR/const_static_lifetime.rs:33:19 + --> $DIR/const_static_lifetime.rs:24:19 | LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index 5db82006dea..a78209bcce8 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( clippy::blacklisted_name, clippy::collapsible_if, diff --git a/tests/ui/copies.stderr b/tests/ui/copies.stderr index 3fbc279b537..a0a5c3890ed 100644 --- a/tests/ui/copies.stderr +++ b/tests/ui/copies.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/copies.rs:50:12 + --> $DIR/copies.rs:41:12 | LL | } else { | ____________^ @@ -13,7 +13,7 @@ LL | | } | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/copies.rs:42:13 + --> $DIR/copies.rs:33:13 | LL | if true { | _____________^ @@ -26,7 +26,7 @@ LL | | } else { | |_____^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:96:14 + --> $DIR/copies.rs:87:14 | LL | _ => { | ______________^ @@ -40,7 +40,7 @@ LL | | }, | = note: `-D clippy::match-same-arms` implied by `-D warnings` note: same as this - --> $DIR/copies.rs:87:15 + --> $DIR/copies.rs:78:15 | LL | 42 => { | _______________^ @@ -52,7 +52,7 @@ LL | | a LL | | }, | |_________^ note: `42` has the same arm body as the `_` wildcard, consider removing it` - --> $DIR/copies.rs:87:15 + --> $DIR/copies.rs:78:15 | LL | 42 => { | _______________^ @@ -65,24 +65,24 @@ LL | | }, | |_________^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:111:14 + --> $DIR/copies.rs:102:14 | LL | _ => 0, //~ ERROR match arms have same body | ^ | note: same as this - --> $DIR/copies.rs:109:19 + --> $DIR/copies.rs:100:19 | LL | Abc::A => 0, | ^ note: `Abc::A` has the same arm body as the `_` wildcard, consider removing it` - --> $DIR/copies.rs:109:19 + --> $DIR/copies.rs:100:19 | LL | Abc::A => 0, | ^ error: this `if` has identical blocks - --> $DIR/copies.rs:120:12 + --> $DIR/copies.rs:111:12 | LL | } else { | ____________^ @@ -92,7 +92,7 @@ LL | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:118:21 + --> $DIR/copies.rs:109:21 | LL | let _ = if true { | _____________________^ @@ -101,7 +101,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:134:12 + --> $DIR/copies.rs:125:12 | LL | } else { | ____________^ @@ -114,7 +114,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/copies.rs:125:13 + --> $DIR/copies.rs:116:13 | LL | if true { | _____________^ @@ -127,7 +127,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:153:12 + --> $DIR/copies.rs:144:12 | LL | } else { | ____________^ @@ -140,7 +140,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/copies.rs:146:13 + --> $DIR/copies.rs:137:13 | LL | if true { | _____________^ @@ -153,7 +153,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:183:12 + --> $DIR/copies.rs:174:12 | LL | } else { | ____________^ @@ -163,7 +163,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/copies.rs:181:13 + --> $DIR/copies.rs:172:13 | LL | if true { | _____________^ @@ -172,7 +172,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:190:12 + --> $DIR/copies.rs:181:12 | LL | } else { | ____________^ @@ -182,7 +182,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/copies.rs:188:13 + --> $DIR/copies.rs:179:13 | LL | if true { | _____________^ @@ -191,92 +191,92 @@ LL | | } else { | |_____^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:239:15 + --> $DIR/copies.rs:230:15 | LL | 51 => foo(), //~ ERROR match arms have same body | ^^^^^ | note: same as this - --> $DIR/copies.rs:238:15 + --> $DIR/copies.rs:229:15 | LL | 42 => foo(), | ^^^^^ note: consider refactoring into `42 | 51` - --> $DIR/copies.rs:238:15 + --> $DIR/copies.rs:229:15 | LL | 42 => foo(), | ^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:245:17 + --> $DIR/copies.rs:236:17 | LL | None => 24, //~ ERROR match arms have same body | ^^ | note: same as this - --> $DIR/copies.rs:244:20 + --> $DIR/copies.rs:235:20 | LL | Some(_) => 24, | ^^ note: consider refactoring into `Some(_) | None` - --> $DIR/copies.rs:244:20 + --> $DIR/copies.rs:235:20 | LL | Some(_) => 24, | ^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:267:28 + --> $DIR/copies.rs:258:28 | LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body | ^^^^^^ | note: same as this - --> $DIR/copies.rs:266:28 + --> $DIR/copies.rs:257:28 | LL | (Some(a), None) => bar(a), | ^^^^^^ note: consider refactoring into `(Some(a), None) | (None, Some(a))` - --> $DIR/copies.rs:266:28 + --> $DIR/copies.rs:257:28 | LL | (Some(a), None) => bar(a), | ^^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:273:26 + --> $DIR/copies.rs:264:26 | LL | (.., Some(a)) => bar(a), //~ ERROR match arms have same body | ^^^^^^ | note: same as this - --> $DIR/copies.rs:272:26 + --> $DIR/copies.rs:263:26 | LL | (Some(a), ..) => bar(a), | ^^^^^^ note: consider refactoring into `(Some(a), ..) | (.., Some(a))` - --> $DIR/copies.rs:272:26 + --> $DIR/copies.rs:263:26 | LL | (Some(a), ..) => bar(a), | ^^^^^^ error: this `match` has identical arm bodies - --> $DIR/copies.rs:279:20 + --> $DIR/copies.rs:270:20 | LL | (.., 3) => 42, //~ ERROR match arms have same body | ^^ | note: same as this - --> $DIR/copies.rs:278:23 + --> $DIR/copies.rs:269:23 | LL | (1, .., 3) => 42, | ^^ note: consider refactoring into `(1, .., 3) | (.., 3)` - --> $DIR/copies.rs:278:23 + --> $DIR/copies.rs:269:23 | LL | (1, .., 3) => 42, | ^^ error: this `if` has identical blocks - --> $DIR/copies.rs:285:12 + --> $DIR/copies.rs:276:12 | LL | } else { | ____________^ @@ -286,7 +286,7 @@ LL | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:283:21 + --> $DIR/copies.rs:274:21 | LL | let _ = if true { | _____________________^ @@ -295,7 +295,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:292:12 + --> $DIR/copies.rs:283:12 | LL | } else { | ____________^ @@ -305,7 +305,7 @@ LL | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:290:21 + --> $DIR/copies.rs:281:21 | LL | let _ = if true { | _____________________^ @@ -314,7 +314,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:305:12 + --> $DIR/copies.rs:296:12 | LL | } else { | ____________^ @@ -324,7 +324,7 @@ LL | | }; | |_____^ | note: same as this - --> $DIR/copies.rs:303:21 + --> $DIR/copies.rs:294:21 | LL | let _ = if true { | _____________________^ @@ -333,7 +333,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/copies.rs:323:12 + --> $DIR/copies.rs:314:12 | LL | } else { | ____________^ @@ -343,7 +343,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/copies.rs:321:13 + --> $DIR/copies.rs:312:13 | LL | if true { | _____________^ diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs index 22d3e138898..e3d5928be23 100644 --- a/tests/ui/copy_iterator.rs +++ b/tests/ui/copy_iterator.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::copy_iterator)] #[derive(Copy, Clone)] diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr index 34606df8595..f8ce6af7961 100644 --- a/tests/ui/copy_iterator.stderr +++ b/tests/ui/copy_iterator.stderr @@ -1,5 +1,5 @@ error: you are implementing `Iterator` on a `Copy` type - --> $DIR/copy_iterator.rs:15:1 + --> $DIR/copy_iterator.rs:6:1 | LL | / impl Iterator for Countdown { LL | | type Item = u8; diff --git a/tests/ui/cstring.rs b/tests/ui/cstring.rs index 5fe915a8368..6cc36518e27 100644 --- a/tests/ui/cstring.rs +++ b/tests/ui/cstring.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() {} #[allow(clippy::result_unwrap_used)] diff --git a/tests/ui/cstring.stderr b/tests/ui/cstring.stderr index d2968eb9d18..a2fc07d4af0 100644 --- a/tests/ui/cstring.stderr +++ b/tests/ui/cstring.stderr @@ -1,5 +1,5 @@ error: you are getting the inner pointer of a temporary `CString` - --> $DIR/cstring.rs:16:5 + --> $DIR/cstring.rs:7:5 | LL | CString::new("foo").unwrap().as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | CString::new("foo").unwrap().as_ptr(); = note: #[deny(clippy::temporary_cstring_as_ptr)] on by default = note: that pointer will be invalid outside this expression help: assign the `CString` to a variable to extend its lifetime - --> $DIR/cstring.rs:16:5 + --> $DIR/cstring.rs:7:5 | LL | CString::new("foo").unwrap().as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index fff67762924..d552ef50ff0 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::all)] #![warn(clippy::cyclomatic_complexity)] #![allow(unused)] diff --git a/tests/ui/cyclomatic_complexity.stderr b/tests/ui/cyclomatic_complexity.stderr index f8e3a54debd..944bba6e488 100644 --- a/tests/ui/cyclomatic_complexity.stderr +++ b/tests/ui/cyclomatic_complexity.stderr @@ -1,5 +1,5 @@ error: the function has a cyclomatic complexity of 28 - --> $DIR/cyclomatic_complexity.rs:15:1 + --> $DIR/cyclomatic_complexity.rs:6:1 | LL | / fn main() { LL | | if true { @@ -14,7 +14,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 7 - --> $DIR/cyclomatic_complexity.rs:100:1 + --> $DIR/cyclomatic_complexity.rs:91:1 | LL | / fn kaboom() { LL | | let n = 0; @@ -28,7 +28,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:146:1 + --> $DIR/cyclomatic_complexity.rs:137:1 | LL | / fn lots_of_short_circuits() -> bool { LL | | true && false && true && false && true && false && true @@ -38,7 +38,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:151:1 + --> $DIR/cyclomatic_complexity.rs:142:1 | LL | / fn lots_of_short_circuits2() -> bool { LL | | true || false || true || false || true || false || true @@ -48,7 +48,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:156:1 + --> $DIR/cyclomatic_complexity.rs:147:1 | LL | / fn baa() { LL | | let x = || match 99 { @@ -62,7 +62,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:157:13 + --> $DIR/cyclomatic_complexity.rs:148:13 | LL | let x = || match 99 { | _____________^ @@ -77,7 +77,7 @@ LL | | }; = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:174:1 + --> $DIR/cyclomatic_complexity.rs:165:1 | LL | / fn bar() { LL | | match 99 { @@ -90,7 +90,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:193:1 + --> $DIR/cyclomatic_complexity.rs:184:1 | LL | / fn barr() { LL | | match 99 { @@ -104,7 +104,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 3 - --> $DIR/cyclomatic_complexity.rs:203:1 + --> $DIR/cyclomatic_complexity.rs:194:1 | LL | / fn barr2() { LL | | match 99 { @@ -118,7 +118,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:219:1 + --> $DIR/cyclomatic_complexity.rs:210:1 | LL | / fn barrr() { LL | | match 99 { @@ -132,7 +132,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 3 - --> $DIR/cyclomatic_complexity.rs:229:1 + --> $DIR/cyclomatic_complexity.rs:220:1 | LL | / fn barrr2() { LL | | match 99 { @@ -146,7 +146,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:245:1 + --> $DIR/cyclomatic_complexity.rs:236:1 | LL | / fn barrrr() { LL | | match 99 { @@ -160,7 +160,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 3 - --> $DIR/cyclomatic_complexity.rs:255:1 + --> $DIR/cyclomatic_complexity.rs:246:1 | LL | / fn barrrr2() { LL | | match 99 { @@ -174,7 +174,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 2 - --> $DIR/cyclomatic_complexity.rs:271:1 + --> $DIR/cyclomatic_complexity.rs:262:1 | LL | / fn cake() { LL | | if 4 == 5 { @@ -188,7 +188,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 4 - --> $DIR/cyclomatic_complexity.rs:281:1 + --> $DIR/cyclomatic_complexity.rs:272:1 | LL | / pub fn read_file(input_path: &str) -> String { LL | | use std::fs::File; @@ -202,7 +202,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:312:1 + --> $DIR/cyclomatic_complexity.rs:303:1 | LL | / fn void(void: Void) { LL | | if true { @@ -214,7 +214,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:325:1 + --> $DIR/cyclomatic_complexity.rs:316:1 | LL | / fn try() -> Result<i32, &'static str> { LL | | match 5 { @@ -227,7 +227,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:333:1 + --> $DIR/cyclomatic_complexity.rs:324:1 | LL | / fn try_again() -> Result<i32, &'static str> { LL | | let _ = try!(Ok(42)); @@ -241,7 +241,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 1 - --> $DIR/cyclomatic_complexity.rs:349:1 + --> $DIR/cyclomatic_complexity.rs:340:1 | LL | / fn early() -> Result<i32, &'static str> { LL | | return Ok(5); @@ -255,7 +255,7 @@ LL | | } = help: you could split it up into multiple smaller functions error: the function has a cyclomatic complexity of 8 - --> $DIR/cyclomatic_complexity.rs:363:1 + --> $DIR/cyclomatic_complexity.rs:354:1 | LL | / fn early_ret() -> i32 { LL | | let a = if true { 42 } else { return 0; }; diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index b1da9649f90..8b5028557d9 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::cyclomatic_complexity)] #![warn(unused)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.stderr b/tests/ui/cyclomatic_complexity_attr_used.stderr index dde803880ca..7b732119774 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.stderr +++ b/tests/ui/cyclomatic_complexity_attr_used.stderr @@ -1,5 +1,5 @@ error: the function has a cyclomatic complexity of 3 - --> $DIR/cyclomatic_complexity_attr_used.rs:18:1 + --> $DIR/cyclomatic_complexity_attr_used.rs:9:1 | LL | / fn kaboom() { LL | | if 42 == 43 { diff --git a/tests/ui/decimal_literal_representation.rs b/tests/ui/decimal_literal_representation.rs index d7823b0b819..d841f16757a 100644 --- a/tests/ui/decimal_literal_representation.rs +++ b/tests/ui/decimal_literal_representation.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] #[rustfmt::skip] diff --git a/tests/ui/decimal_literal_representation.stderr b/tests/ui/decimal_literal_representation.stderr index cc908ca11f3..3a535def197 100644 --- a/tests/ui/decimal_literal_representation.stderr +++ b/tests/ui/decimal_literal_representation.stderr @@ -1,5 +1,5 @@ error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:25:9 + --> $DIR/decimal_literal_representation.rs:16:9 | LL | 32_773, // 0x8005 | ^^^^^^ help: consider: `0x8005` @@ -7,25 +7,25 @@ LL | 32_773, // 0x8005 = note: `-D clippy::decimal-literal-representation` implied by `-D warnings` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:26:9 + --> $DIR/decimal_literal_representation.rs:17:9 | LL | 65_280, // 0xFF00 | ^^^^^^ help: consider: `0xFF00` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:27:9 + --> $DIR/decimal_literal_representation.rs:18:9 | LL | 2_131_750_927, // 0x7F0F_F00F | ^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:28:9 + --> $DIR/decimal_literal_representation.rs:19:9 | LL | 2_147_483_647, // 0x7FFF_FFFF | ^^^^^^^^^^^^^ help: consider: `0x7FFF_FFFF` error: integer literal has a better hexadecimal representation - --> $DIR/decimal_literal_representation.rs:29:9 + --> $DIR/decimal_literal_representation.rs:20:9 | LL | 4_042_322_160, // 0xF0F0_F0F0 | ^^^^^^^^^^^^^ help: consider: `0xF0F0_F0F0` diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index eaa367b0cb3..2f1490a7036 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::default_trait_access)] use std::default; diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index 9fcf359b72f..1f115aecca1 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,5 +1,5 @@ error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:17:22 + --> $DIR/default_trait_access.rs:8:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` @@ -7,43 +7,43 @@ LL | let s1: String = Default::default(); = note: `-D clippy::default-trait-access` implied by `-D warnings` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:21:22 + --> $DIR/default_trait_access.rs:12:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:23:22 + --> $DIR/default_trait_access.rs:14:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling std::string::String::default() is more clear than this expression - --> $DIR/default_trait_access.rs:27:22 + --> $DIR/default_trait_access.rs:18:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: Calling GenericDerivedDefault<std::string::String>::default() is more clear than this expression - --> $DIR/default_trait_access.rs:37:46 + --> $DIR/default_trait_access.rs:28:46 | LL | let s11: GenericDerivedDefault<String> = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()` error: Calling TupleDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:43:36 + --> $DIR/default_trait_access.rs:34:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: Calling ArrayDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:45:36 + --> $DIR/default_trait_access.rs:36:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: Calling TupleStructDerivedDefault::default() is more clear than this expression - --> $DIR/default_trait_access.rs:49:42 + --> $DIR/default_trait_access.rs:40:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 7a1657424ed..2e5c5b7ead1 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(str_to_string)] #[warn(string_to_string)] #[warn(unstable_as_slice)] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 3d1f016b9b9..4dbca0dea64 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,5 +1,5 @@ error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:10:8 + --> $DIR/deprecated.rs:1:8 | LL | #[warn(str_to_string)] | ^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | #[warn(str_to_string)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:11:8 + --> $DIR/deprecated.rs:2:8 | LL | #[warn(string_to_string)] | ^^^^^^^^^^^^^^^^ error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:12:8 + --> $DIR/deprecated.rs:3:8 | LL | #[warn(unstable_as_slice)] | ^^^^^^^^^^^^^^^^^ error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:13:8 + --> $DIR/deprecated.rs:4:8 | LL | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated.rs:14:8 + --> $DIR/deprecated.rs:5:8 | LL | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index a6020b61337..b7a672cd80a 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(untagged_unions)] #![allow(dead_code)] #![warn(clippy::expl_impl_clone_on_copy)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index b9629005597..fc87c7d1596 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -1,12 +1,12 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive.rs:25:10 + --> $DIR/derive.rs:16:10 | LL | #[derive(Hash)] | ^^^^ | = note: #[deny(clippy::derive_hash_xor_eq)] on by default note: `PartialEq` implemented here - --> $DIR/derive.rs:28:1 + --> $DIR/derive.rs:19:1 | LL | / impl PartialEq for Bar { LL | | fn eq(&self, _: &Bar) -> bool { @@ -16,13 +16,13 @@ LL | | } | |_^ error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> $DIR/derive.rs:34:10 + --> $DIR/derive.rs:25:10 | LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> $DIR/derive.rs:37:1 + --> $DIR/derive.rs:28:1 | LL | / impl PartialEq<Baz> for Baz { LL | | fn eq(&self, _: &Baz) -> bool { @@ -32,7 +32,7 @@ LL | | } | |_^ error: you are implementing `Hash` explicitly but have derived `PartialEq` - --> $DIR/derive.rs:46:1 + --> $DIR/derive.rs:37:1 | LL | / impl Hash for Bah { LL | | fn hash<H: Hasher>(&self, _: &mut H) {} @@ -40,13 +40,13 @@ LL | | } | |_^ | note: `PartialEq` implemented here - --> $DIR/derive.rs:43:10 + --> $DIR/derive.rs:34:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:53:1 + --> $DIR/derive.rs:44:1 | LL | / impl Clone for Qux { LL | | fn clone(&self) -> Self { @@ -57,7 +57,7 @@ LL | | } | = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:53:1 + --> $DIR/derive.rs:44:1 | LL | / impl Clone for Qux { LL | | fn clone(&self) -> Self { @@ -67,7 +67,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:77:1 + --> $DIR/derive.rs:68:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | fn clone(&self) -> Self { @@ -77,7 +77,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:77:1 + --> $DIR/derive.rs:68:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | fn clone(&self) -> Self { @@ -87,7 +87,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:89:1 + --> $DIR/derive.rs:80:1 | LL | / impl Clone for BigArray { LL | | fn clone(&self) -> Self { @@ -97,7 +97,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:89:1 + --> $DIR/derive.rs:80:1 | LL | / impl Clone for BigArray { LL | | fn clone(&self) -> Self { @@ -107,7 +107,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:101:1 + --> $DIR/derive.rs:92:1 | LL | / impl Clone for FnPtr { LL | | fn clone(&self) -> Self { @@ -117,7 +117,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:101:1 + --> $DIR/derive.rs:92:1 | LL | / impl Clone for FnPtr { LL | | fn clone(&self) -> Self { diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 3399dba7189..746afa47503 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(never_type)] #![warn(clippy::diverging_sub_expression)] #![allow(clippy::match_same_arms, clippy::logic_bug)] diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 1cfec07c560..70ff3cdd046 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -1,5 +1,5 @@ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:30:10 + --> $DIR/diverging_sub_expression.rs:21:10 | LL | b || diverge(); | ^^^^^^^^^ @@ -7,31 +7,31 @@ LL | b || diverge(); = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:31:10 + --> $DIR/diverging_sub_expression.rs:22:10 | LL | b || A.foo(); | ^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:40:26 + --> $DIR/diverging_sub_expression.rs:31:26 | LL | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:41:26 + --> $DIR/diverging_sub_expression.rs:32:26 | LL | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:44:26 + --> $DIR/diverging_sub_expression.rs:35:26 | LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:49:26 + --> $DIR/diverging_sub_expression.rs:40:26 | LL | _ => true || break, | ^^^^^ diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index dfc8be24a8b..7634341ba84 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(alloc)] #![feature(associated_type_defaults)] #![warn(clippy::linkedlist)] diff --git a/tests/ui/dlist.stderr b/tests/ui/dlist.stderr index 6b0413fdf23..cc4b8e7a3b4 100644 --- a/tests/ui/dlist.stderr +++ b/tests/ui/dlist.stderr @@ -1,5 +1,5 @@ error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:19:16 + --> $DIR/dlist.rs:10:16 | LL | type Baz = LinkedList<u8>; | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | type Baz = LinkedList<u8>; = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:20:12 + --> $DIR/dlist.rs:11:12 | LL | fn foo(LinkedList<u8>); | ^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn foo(LinkedList<u8>); = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:21:23 + --> $DIR/dlist.rs:12:23 | LL | const BAR: Option<LinkedList<u8>>; | ^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | const BAR: Option<LinkedList<u8>>; = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:32:15 + --> $DIR/dlist.rs:23:15 | LL | fn foo(_: LinkedList<u8>) {} | ^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | fn foo(_: LinkedList<u8>) {} = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:35:39 + --> $DIR/dlist.rs:26:39 | LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) { = help: a VecDeque might work error: I see you're using a LinkedList! Perhaps you meant some other data structure? - --> $DIR/dlist.rs:39:29 + --> $DIR/dlist.rs:30:29 | LL | pub fn test_ret() -> Option<LinkedList<u8>> { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index d4ba83a86f3..915fb3aae89 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! This file tests for the DOC_MARKDOWN lint #![allow(dead_code)] diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index 964e351348a..4a2ef448e84 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -1,5 +1,5 @@ error: you should put `DOC_MARKDOWN` between ticks in the documentation - --> $DIR/doc.rs:10:29 + --> $DIR/doc.rs:1:29 | LL | //! This file tests for the DOC_MARKDOWN lint | ^^^^^^^^^^^^ @@ -7,181 +7,181 @@ LL | //! This file tests for the DOC_MARKDOWN lint = note: `-D clippy::doc-markdown` implied by `-D warnings` error: you should put `foo_bar` between ticks in the documentation - --> $DIR/doc.rs:15:9 + --> $DIR/doc.rs:6:9 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^ error: you should put `foo::bar` between ticks in the documentation - --> $DIR/doc.rs:15:51 + --> $DIR/doc.rs:6:51 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^^ error: you should put `Foo::some_fun` between ticks in the documentation - --> $DIR/doc.rs:16:84 + --> $DIR/doc.rs:7:84 | LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ error: you should put `a::global:path` between ticks in the documentation - --> $DIR/doc.rs:18:15 + --> $DIR/doc.rs:9:15 | LL | /// Here be ::a::global:path. | ^^^^^^^^^^^^^^ error: you should put `NotInCodeBlock` between ticks in the documentation - --> $DIR/doc.rs:19:22 + --> $DIR/doc.rs:10:22 | LL | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:20:5 + --> $DIR/doc.rs:11:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:34:5 + --> $DIR/doc.rs:25:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:41:5 + --> $DIR/doc.rs:32:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:55:5 + --> $DIR/doc.rs:46:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:59:22 + --> $DIR/doc.rs:50:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:62:21 + --> $DIR/doc.rs:53:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:72:5 + --> $DIR/doc.rs:63:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:80:8 + --> $DIR/doc.rs:71:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:83:7 + --> $DIR/doc.rs:74:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:85:22 + --> $DIR/doc.rs:76:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:86:5 + --> $DIR/doc.rs:77:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:93:5 + --> $DIR/doc.rs:84:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:106:5 + --> $DIR/doc.rs:97:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:117:42 + --> $DIR/doc.rs:108:42 | LL | /** E.g. serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:122:5 + --> $DIR/doc.rs:113:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:123:1 + --> $DIR/doc.rs:114:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:128:42 + --> $DIR/doc.rs:119:42 | LL | /** E.g. serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:133:5 + --> $DIR/doc.rs:124:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:134:1 + --> $DIR/doc.rs:125:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:145:5 + --> $DIR/doc.rs:136:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:172:13 + --> $DIR/doc.rs:163:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:173:13 + --> $DIR/doc.rs:164:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:174:13 + --> $DIR/doc.rs:165:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:175:13 + --> $DIR/doc.rs:166:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:181:22 + --> $DIR/doc.rs:172:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed index fd98edb7555..bb6cdaa667d 100644 --- a/tests/ui/double_comparison.fixed +++ b/tests/ui/double_comparison.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index 5d201a13ff2..9a2a9068a28 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/double_comparison.stderr b/tests/ui/double_comparison.stderr index 31bab8f0112..5dcda7b3af4 100644 --- a/tests/ui/double_comparison.stderr +++ b/tests/ui/double_comparison.stderr @@ -1,5 +1,5 @@ error: This binary expression can be simplified - --> $DIR/double_comparison.rs:15:8 + --> $DIR/double_comparison.rs:6:8 | LL | if x == y || x < y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` @@ -7,43 +7,43 @@ LL | if x == y || x < y { = note: `-D clippy::double-comparisons` implied by `-D warnings` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:18:8 + --> $DIR/double_comparison.rs:9:8 | LL | if x < y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:21:8 + --> $DIR/double_comparison.rs:12:8 | LL | if x == y || x > y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:24:8 + --> $DIR/double_comparison.rs:15:8 | LL | if x > y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:27:8 + --> $DIR/double_comparison.rs:18:8 | LL | if x < y || x > y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:30:8 + --> $DIR/double_comparison.rs:21:8 | LL | if x > y || x < y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:33:8 + --> $DIR/double_comparison.rs:24:8 | LL | if x <= y && x >= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` error: This binary expression can be simplified - --> $DIR/double_comparison.rs:36:8 + --> $DIR/double_comparison.rs:27:8 | LL | if x >= y && x <= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index 7d65122cb5e..d47dfcb5ba1 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::double_neg)] fn main() { let x = 1; diff --git a/tests/ui/double_neg.stderr b/tests/ui/double_neg.stderr index 6ff18e5504d..d82ed05f054 100644 --- a/tests/ui/double_neg.stderr +++ b/tests/ui/double_neg.stderr @@ -1,5 +1,5 @@ error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op - --> $DIR/double_neg.rs:15:5 + --> $DIR/double_neg.rs:6:5 | LL | --x; | ^^^ diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 773179b2d46..c6f9bf77e12 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::double_parens)] #![allow(dead_code)] fn dummy_fn<T>(_: T) {} diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr index 0e7f62ca3e3..6336b1c259a 100644 --- a/tests/ui/double_parens.stderr +++ b/tests/ui/double_parens.stderr @@ -1,5 +1,5 @@ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:21:5 + --> $DIR/double_parens.rs:12:5 | LL | ((0)) | ^^^^^ @@ -7,31 +7,31 @@ LL | ((0)) = note: `-D clippy::double-parens` implied by `-D warnings` error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:25:14 + --> $DIR/double_parens.rs:16:14 | LL | dummy_fn((0)); | ^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:29:20 + --> $DIR/double_parens.rs:20:20 | LL | x.dummy_method((0)); | ^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:33:5 + --> $DIR/double_parens.rs:24:5 | LL | ((1, 2)) | ^^^^^^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:37:5 + --> $DIR/double_parens.rs:28:5 | LL | (()) | ^^^^ error: Consider removing unnecessary double parentheses - --> $DIR/double_parens.rs:59:16 + --> $DIR/double_parens.rs:50:16 | LL | assert_eq!(((1, 2)), (1, 2), "Error"); | ^^^^^^^^ diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index 2ea8954ff59..9ddd6d64701 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::drop_copy, clippy::forget_copy)] #![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)] diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 6fc69c4bcda..55c840d3480 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -1,73 +1,73 @@ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:42:5 + --> $DIR/drop_forget_copy.rs:33:5 | LL | drop(s1); | ^^^^^^^^ | = note: `-D clippy::drop-copy` implied by `-D warnings` note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:42:10 + --> $DIR/drop_forget_copy.rs:33:10 | LL | drop(s1); | ^^ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:43:5 + --> $DIR/drop_forget_copy.rs:34:5 | LL | drop(s2); | ^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:43:10 + --> $DIR/drop_forget_copy.rs:34:10 | LL | drop(s2); | ^^ error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:45:5 + --> $DIR/drop_forget_copy.rs:36:5 | LL | drop(s4); | ^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:45:10 + --> $DIR/drop_forget_copy.rs:36:10 | LL | drop(s4); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:48:5 + --> $DIR/drop_forget_copy.rs:39:5 | LL | forget(s1); | ^^^^^^^^^^ | = note: `-D clippy::forget-copy` implied by `-D warnings` note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:48:12 + --> $DIR/drop_forget_copy.rs:39:12 | LL | forget(s1); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:49:5 + --> $DIR/drop_forget_copy.rs:40:5 | LL | forget(s2); | ^^^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:49:12 + --> $DIR/drop_forget_copy.rs:40:12 | LL | forget(s2); | ^^ error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact. - --> $DIR/drop_forget_copy.rs:51:5 + --> $DIR/drop_forget_copy.rs:42:5 | LL | forget(s4); | ^^^^^^^^^^ | note: argument has type SomeStruct - --> $DIR/drop_forget_copy.rs:51:12 + --> $DIR/drop_forget_copy.rs:42:12 | LL | forget(s4); | ^^ diff --git a/tests/ui/drop_forget_ref.rs b/tests/ui/drop_forget_ref.rs index 6821d403322..b3c75bc5764 100644 --- a/tests/ui/drop_forget_ref.rs +++ b/tests/ui/drop_forget_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::drop_ref, clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg, clippy::similar_names, clippy::needless_pass_by_value)] diff --git a/tests/ui/drop_forget_ref.stderr b/tests/ui/drop_forget_ref.stderr index 005adceca50..8ffc369b882 100644 --- a/tests/ui/drop_forget_ref.stderr +++ b/tests/ui/drop_forget_ref.stderr @@ -1,217 +1,217 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:18:5 + --> $DIR/drop_forget_ref.rs:9:5 | LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:18:10 + --> $DIR/drop_forget_ref.rs:9:10 | LL | drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:19:5 + --> $DIR/drop_forget_ref.rs:10:5 | LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:19:12 + --> $DIR/drop_forget_ref.rs:10:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:22:5 + --> $DIR/drop_forget_ref.rs:13:5 | LL | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:22:10 + --> $DIR/drop_forget_ref.rs:13:10 | LL | drop(&owned1); | ^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:23:5 + --> $DIR/drop_forget_ref.rs:14:5 | LL | drop(&&owned1); | ^^^^^^^^^^^^^^ | note: argument has type &&SomeStruct - --> $DIR/drop_forget_ref.rs:23:10 + --> $DIR/drop_forget_ref.rs:14:10 | LL | drop(&&owned1); | ^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:24:5 + --> $DIR/drop_forget_ref.rs:15:5 | LL | drop(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:24:10 + --> $DIR/drop_forget_ref.rs:15:10 | LL | drop(&mut owned1); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:27:5 + --> $DIR/drop_forget_ref.rs:18:5 | LL | forget(&owned2); | ^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:27:12 + --> $DIR/drop_forget_ref.rs:18:12 | LL | forget(&owned2); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:28:5 + --> $DIR/drop_forget_ref.rs:19:5 | LL | forget(&&owned2); | ^^^^^^^^^^^^^^^^ | note: argument has type &&SomeStruct - --> $DIR/drop_forget_ref.rs:28:12 + --> $DIR/drop_forget_ref.rs:19:12 | LL | forget(&&owned2); | ^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:29:5 + --> $DIR/drop_forget_ref.rs:20:5 | LL | forget(&mut owned2); | ^^^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:29:12 + --> $DIR/drop_forget_ref.rs:20:12 | LL | forget(&mut owned2); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:33:5 + --> $DIR/drop_forget_ref.rs:24:5 | LL | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:33:10 + --> $DIR/drop_forget_ref.rs:24:10 | LL | drop(reference1); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:34:5 + --> $DIR/drop_forget_ref.rs:25:5 | LL | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:34:12 + --> $DIR/drop_forget_ref.rs:25:12 | LL | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:37:5 + --> $DIR/drop_forget_ref.rs:28:5 | LL | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:37:10 + --> $DIR/drop_forget_ref.rs:28:10 | LL | drop(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:39:5 + --> $DIR/drop_forget_ref.rs:30:5 | LL | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type &mut SomeStruct - --> $DIR/drop_forget_ref.rs:39:12 + --> $DIR/drop_forget_ref.rs:30:12 | LL | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:42:5 + --> $DIR/drop_forget_ref.rs:33:5 | LL | drop(reference4); | ^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:42:10 + --> $DIR/drop_forget_ref.rs:33:10 | LL | drop(reference4); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:43:5 + --> $DIR/drop_forget_ref.rs:34:5 | LL | forget(reference4); | ^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:43:12 + --> $DIR/drop_forget_ref.rs:34:12 | LL | forget(reference4); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:48:5 + --> $DIR/drop_forget_ref.rs:39:5 | LL | drop(&val); | ^^^^^^^^^^ | note: argument has type &T - --> $DIR/drop_forget_ref.rs:48:10 + --> $DIR/drop_forget_ref.rs:39:10 | LL | drop(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:54:5 + --> $DIR/drop_forget_ref.rs:45:5 | LL | forget(&val); | ^^^^^^^^^^^^ | note: argument has type &T - --> $DIR/drop_forget_ref.rs:54:12 + --> $DIR/drop_forget_ref.rs:45:12 | LL | forget(&val); | ^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_forget_ref.rs:62:5 + --> $DIR/drop_forget_ref.rs:53:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:62:20 + --> $DIR/drop_forget_ref.rs:53:20 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:65:5 + --> $DIR/drop_forget_ref.rs:56:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:65:22 + --> $DIR/drop_forget_ref.rs:56:22 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index da4e2a6dc8a..54d748c7ce2 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::duplicate_underscore_argument)] #[allow(dead_code, unused)] diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index e4bdd3f96b2..f71614a5fd1 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -1,5 +1,5 @@ error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult - --> $DIR/duplicate_underscore_argument.rs:13:23 + --> $DIR/duplicate_underscore_argument.rs:4:23 | LL | fn join_the_dark_side(darth: i32, _darth: i32) {} | ^^^^^ diff --git a/tests/ui/duration_subsec.rs b/tests/ui/duration_subsec.rs index 8c2dade34c0..d54d2f46eb7 100644 --- a/tests/ui/duration_subsec.rs +++ b/tests/ui/duration_subsec.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::duration_subsec)] use std::time::Duration; diff --git a/tests/ui/duration_subsec.stderr b/tests/ui/duration_subsec.stderr index e87c9839b33..249777e863c 100644 --- a/tests/ui/duration_subsec.stderr +++ b/tests/ui/duration_subsec.stderr @@ -1,5 +1,5 @@ error: Calling `subsec_millis()` is more concise than this calculation - --> $DIR/duration_subsec.rs:17:24 + --> $DIR/duration_subsec.rs:8:24 | LL | let bad_millis_1 = dur.subsec_micros() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` @@ -7,25 +7,25 @@ LL | let bad_millis_1 = dur.subsec_micros() / 1_000; = note: `-D clippy::duration-subsec` implied by `-D warnings` error: Calling `subsec_millis()` is more concise than this calculation - --> $DIR/duration_subsec.rs:18:24 + --> $DIR/duration_subsec.rs:9:24 | LL | let bad_millis_2 = dur.subsec_nanos() / 1_000_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:23:22 + --> $DIR/duration_subsec.rs:14:22 | LL | let bad_micros = dur.subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:28:13 + --> $DIR/duration_subsec.rs:19:13 | LL | let _ = (&dur).subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()` error: Calling `subsec_micros()` is more concise than this calculation - --> $DIR/duration_subsec.rs:32:13 + --> $DIR/duration_subsec.rs:23:13 | LL | let _ = dur.subsec_nanos() / NANOS_IN_MICRO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index 0776eae310c..879b3ac398e 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![warn(clippy::else_if_without_else)] diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 2c1ecbfdb86..27000906754 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -1,5 +1,5 @@ error: if expression with an `else if`, but without a final `else` - --> $DIR/else_if_without_else.rs:54:12 + --> $DIR/else_if_without_else.rs:45:12 | LL | } else if bla2() { | ____________^ @@ -12,7 +12,7 @@ LL | | } = help: add an `else` block here error: if expression with an `else if`, but without a final `else` - --> $DIR/else_if_without_else.rs:63:12 + --> $DIR/else_if_without_else.rs:54:12 | LL | } else if bla3() { | ____________^ diff --git a/tests/ui/empty_enum.rs b/tests/ui/empty_enum.rs index b47afc822f8..12428f29625 100644 --- a/tests/ui/empty_enum.rs +++ b/tests/ui/empty_enum.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] #![warn(clippy::empty_enum)] diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index d2e3688eb4d..223a14ed877 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -1,12 +1,12 @@ error: enum with no variants - --> $DIR/empty_enum.rs:13:1 + --> $DIR/empty_enum.rs:4:1 | LL | enum Empty {} | ^^^^^^^^^^^^^ | = note: `-D clippy::empty-enum` implied by `-D warnings` help: consider using the uninhabited type `!` or a wrapper around it - --> $DIR/empty_enum.rs:13:1 + --> $DIR/empty_enum.rs:4:1 | LL | enum Empty {} | ^^^^^^^^^^^^^ diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index ede1244df7e..1e067a54232 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::empty_line_after_outer_attr)] // This should produce a warning diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index 59939ea2858..0fb8dd8dbb1 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,5 +1,5 @@ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:13:1 + --> $DIR/empty_line_after_outer_attribute.rs:4:1 | LL | / #[crate_type = "lib"] LL | | @@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:25:1 + --> $DIR/empty_line_after_outer_attribute.rs:16:1 | LL | / #[crate_type = "lib"] LL | | @@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:30:1 + --> $DIR/empty_line_after_outer_attribute.rs:21:1 | LL | / #[crate_type = "lib"] LL | | @@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:37:1 + --> $DIR/empty_line_after_outer_attribute.rs:28:1 | LL | / #[crate_type = "lib"] LL | | @@ -35,7 +35,7 @@ LL | | enum Baz { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:45:1 + --> $DIR/empty_line_after_outer_attribute.rs:36:1 | LL | / #[crate_type = "lib"] LL | | @@ -43,7 +43,7 @@ LL | | struct Foo { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:53:1 + --> $DIR/empty_line_after_outer_attribute.rs:44:1 | LL | / #[crate_type = "lib"] LL | | diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 6c826716650..00d496e36f6 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused, clippy::needless_pass_by_value)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 78a179d07ef..efacec1e777 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -1,5 +1,5 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:19:5 + --> $DIR/entry.rs:10:5 | LL | / if !m.contains_key(&k) { LL | | m.insert(k, v); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::map-entry` implied by `-D warnings` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:25:5 + --> $DIR/entry.rs:16:5 | LL | / if !m.contains_key(&k) { LL | | foo(); @@ -18,7 +18,7 @@ LL | | } | |_____^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:32:5 + --> $DIR/entry.rs:23:5 | LL | / if !m.contains_key(&k) { LL | | m.insert(k, v) @@ -28,7 +28,7 @@ LL | | }; | |_____^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:40:5 + --> $DIR/entry.rs:31:5 | LL | / if m.contains_key(&k) { LL | | None @@ -38,7 +38,7 @@ LL | | }; | |_____^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:48:5 + --> $DIR/entry.rs:39:5 | LL | / if !m.contains_key(&k) { LL | | foo(); @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> $DIR/entry.rs:57:5 + --> $DIR/entry.rs:48:5 | LL | / if m.contains_key(&k) { LL | | None @@ -60,7 +60,7 @@ LL | | }; | |_____^ help: consider using: `m.entry(k)` error: usage of `contains_key` followed by `insert` on a `BTreeMap` - --> $DIR/entry.rs:66:5 + --> $DIR/entry.rs:57:5 | LL | / if !m.contains_key(&k) { LL | | foo(); diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index dde2896e415..e7b2526ca50 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all, clippy::pedantic)] #![allow(unused_imports, dead_code, clippy::missing_docs_in_private_items)] diff --git a/tests/ui/enum_glob_use.stderr b/tests/ui/enum_glob_use.stderr index 8b89856d4a4..a301703c298 100644 --- a/tests/ui/enum_glob_use.stderr +++ b/tests/ui/enum_glob_use.stderr @@ -1,5 +1,5 @@ error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:13:1 + --> $DIR/enum_glob_use.rs:4:1 | LL | use std::cmp::Ordering::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | use std::cmp::Ordering::*; = note: `-D clippy::enum-glob-use` implied by `-D warnings` error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:19:1 + --> $DIR/enum_glob_use.rs:10:1 | LL | use self::Enum::*; | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index 33472a7f83c..f3bbd3d9626 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(non_ascii_idents)] #![warn(clippy::all, clippy::pub_enum_variant_names)] #![allow(non_camel_case_types)] diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index 4555e1d0649..2835391de7f 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -1,5 +1,5 @@ error: Variant name ends with the enum's name - --> $DIR/enum_variants.rs:25:5 + --> $DIR/enum_variants.rs:16:5 | LL | cFoo, | ^^^^ @@ -7,25 +7,25 @@ LL | cFoo, = note: `-D clippy::enum-variant-names` implied by `-D warnings` error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:36:5 + --> $DIR/enum_variants.rs:27:5 | LL | FoodGood, | ^^^^^^^^ error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:37:5 + --> $DIR/enum_variants.rs:28:5 | LL | FoodMiddle, | ^^^^^^^^^^ error: Variant name starts with the enum's name - --> $DIR/enum_variants.rs:38:5 + --> $DIR/enum_variants.rs:29:5 | LL | FoodBad, | ^^^^^^^ error: All variants have the same prefix: `Food` - --> $DIR/enum_variants.rs:35:1 + --> $DIR/enum_variants.rs:26:1 | LL | / enum Food { LL | | FoodGood, @@ -37,7 +37,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `CallType` - --> $DIR/enum_variants.rs:45:1 + --> $DIR/enum_variants.rs:36:1 | LL | / enum BadCallType { LL | | CallTypeCall, @@ -49,7 +49,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `Constant` - --> $DIR/enum_variants.rs:57:1 + --> $DIR/enum_variants.rs:48:1 | LL | / enum Consts { LL | | ConstantInt, @@ -61,7 +61,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `With` - --> $DIR/enum_variants.rs:91:1 + --> $DIR/enum_variants.rs:82:1 | LL | / enum Seallll { LL | | WithOutCake, @@ -73,7 +73,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `Prefix` - --> $DIR/enum_variants.rs:97:1 + --> $DIR/enum_variants.rs:88:1 | LL | / enum NonCaps { LL | | Prefix的, @@ -85,7 +85,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: All variants have the same prefix: `With` - --> $DIR/enum_variants.rs:103:1 + --> $DIR/enum_variants.rs:94:1 | LL | / pub enum PubSeall { LL | | WithOutCake, diff --git a/tests/ui/enums_clike.rs b/tests/ui/enums_clike.rs index 9c1cf8e8614..789542b1351 100644 --- a/tests/ui/enums_clike.rs +++ b/tests/ui/enums_clike.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // ignore-x86 #![warn(clippy::all)] diff --git a/tests/ui/enums_clike.stderr b/tests/ui/enums_clike.stderr index f883529b996..c3390405094 100644 --- a/tests/ui/enums_clike.stderr +++ b/tests/ui/enums_clike.stderr @@ -1,5 +1,5 @@ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:17:5 + --> $DIR/enums_clike.rs:8:5 | LL | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ @@ -7,43 +7,43 @@ LL | X = 0x1_0000_0000, = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings` error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:24:5 + --> $DIR/enums_clike.rs:15:5 | LL | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:27:5 + --> $DIR/enums_clike.rs:18:5 | LL | A = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:34:5 + --> $DIR/enums_clike.rs:25:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:35:5 + --> $DIR/enums_clike.rs:26:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:37:5 + --> $DIR/enums_clike.rs:28:5 | LL | C = (std::i32::MIN as isize) - 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:43:5 + --> $DIR/enums_clike.rs:34:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: Clike enum variant discriminant is not portable to 32-bit targets - --> $DIR/enums_clike.rs:44:5 + --> $DIR/enums_clike.rs:35:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 020c7d795a4..cc0935ddb79 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[rustfmt::skip] #[warn(clippy::eq_op)] #[allow(clippy::identity_op, clippy::double_parens, clippy::many_single_char_names)] diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index a1a257095c2..2dabaf0d4db 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/eq_op.rs:44:5 + --> $DIR/eq_op.rs:35:5 | LL | true && true; | ^^^^^^^^^^^^ help: try: `true` @@ -7,37 +7,37 @@ LL | true && true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:46:5 + --> $DIR/eq_op.rs:37:5 | LL | true || true; | ^^^^^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:52:5 + --> $DIR/eq_op.rs:43:5 | LL | a == b && b == a; | ^^^^^^^^^^^^^^^^ help: try: `a == b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:53:5 + --> $DIR/eq_op.rs:44:5 | LL | a != b && b != a; | ^^^^^^^^^^^^^^^^ help: try: `a != b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:54:5 + --> $DIR/eq_op.rs:45:5 | LL | a < b && b > a; | ^^^^^^^^^^^^^^ help: try: `a < b` error: this boolean expression can be simplified - --> $DIR/eq_op.rs:55:5 + --> $DIR/eq_op.rs:46:5 | LL | a <= b && b >= a; | ^^^^^^^^^^^^^^^^ help: try: `a <= b` error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:17:5 + --> $DIR/eq_op.rs:8:5 | LL | 1 == 1; | ^^^^^^ @@ -45,157 +45,157 @@ LL | 1 == 1; = note: `-D clippy::eq-op` implied by `-D warnings` error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:18:5 + --> $DIR/eq_op.rs:9:5 | LL | "no" == "no"; | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:20:5 + --> $DIR/eq_op.rs:11:5 | LL | false != false; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> $DIR/eq_op.rs:21:5 + --> $DIR/eq_op.rs:12:5 | LL | 1.5 < 1.5; | ^^^^^^^^^ error: equal expressions as operands to `>=` - --> $DIR/eq_op.rs:22:5 + --> $DIR/eq_op.rs:13:5 | LL | 1u64 >= 1u64; | ^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:25:5 + --> $DIR/eq_op.rs:16:5 | LL | (1 as u64) & (1 as u64); | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `^` - --> $DIR/eq_op.rs:26:5 + --> $DIR/eq_op.rs:17:5 | LL | 1 ^ ((((((1)))))); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> $DIR/eq_op.rs:29:5 + --> $DIR/eq_op.rs:20:5 | LL | (-(2) < -(2)); | ^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:30:5 + --> $DIR/eq_op.rs:21:5 | LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:30:6 + --> $DIR/eq_op.rs:21:6 | LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> $DIR/eq_op.rs:30:27 + --> $DIR/eq_op.rs:21:27 | LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:31:5 + --> $DIR/eq_op.rs:22:5 | LL | (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:34:5 + --> $DIR/eq_op.rs:25:5 | LL | ([1] != [1]); | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:35:5 + --> $DIR/eq_op.rs:26:5 | LL | ((1, 2) != (1, 2)); | ^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:39:5 + --> $DIR/eq_op.rs:30:5 | LL | 1 + 1 == 2; | ^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:40:5 + --> $DIR/eq_op.rs:31:5 | LL | 1 - 1 == 0; | ^^^^^^^^^^ error: equal expressions as operands to `-` - --> $DIR/eq_op.rs:40:5 + --> $DIR/eq_op.rs:31:5 | LL | 1 - 1 == 0; | ^^^^^ error: equal expressions as operands to `-` - --> $DIR/eq_op.rs:42:5 + --> $DIR/eq_op.rs:33:5 | LL | 1 - 1; | ^^^^^ error: equal expressions as operands to `/` - --> $DIR/eq_op.rs:43:5 + --> $DIR/eq_op.rs:34:5 | LL | 1 / 1; | ^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:44:5 + --> $DIR/eq_op.rs:35:5 | LL | true && true; | ^^^^^^^^^^^^ error: equal expressions as operands to `||` - --> $DIR/eq_op.rs:46:5 + --> $DIR/eq_op.rs:37:5 | LL | true || true; | ^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:52:5 + --> $DIR/eq_op.rs:43:5 | LL | a == b && b == a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:53:5 + --> $DIR/eq_op.rs:44:5 | LL | a != b && b != a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:54:5 + --> $DIR/eq_op.rs:45:5 | LL | a < b && b > a; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> $DIR/eq_op.rs:55:5 + --> $DIR/eq_op.rs:46:5 | LL | a <= b && b >= a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:58:5 + --> $DIR/eq_op.rs:49:5 | LL | a == a; | ^^^^^^ error: taken reference of right operand - --> $DIR/eq_op.rs:96:13 + --> $DIR/eq_op.rs:87:13 | LL | let z = x & &y; | ^^^^-- @@ -205,7 +205,7 @@ LL | let z = x & &y; = note: `-D clippy::op-ref` implied by `-D warnings` error: equal expressions as operands to `/` - --> $DIR/eq_op.rs:104:20 + --> $DIR/eq_op.rs:95:20 | LL | const D: u32 = A / A; | ^^^^^ diff --git a/tests/ui/erasing_op.rs b/tests/ui/erasing_op.rs index d7166213194..1540062a4bc 100644 --- a/tests/ui/erasing_op.rs +++ b/tests/ui/erasing_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(clippy::no_effect)] #[warn(clippy::erasing_op)] fn main() { diff --git a/tests/ui/erasing_op.stderr b/tests/ui/erasing_op.stderr index 85548eefba7..e54ce85f98e 100644 --- a/tests/ui/erasing_op.stderr +++ b/tests/ui/erasing_op.stderr @@ -1,5 +1,5 @@ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:15:5 + --> $DIR/erasing_op.rs:6:5 | LL | x * 0; | ^^^^^ @@ -7,13 +7,13 @@ LL | x * 0; = note: `-D clippy::erasing-op` implied by `-D warnings` error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:16:5 + --> $DIR/erasing_op.rs:7:5 | LL | 0 & x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:17:5 + --> $DIR/erasing_op.rs:8:5 | LL | 0 / x; | ^^^^^ diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index cc65c6e6306..f582596eb56 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] #![allow(clippy::borrowed_box, clippy::needless_pass_by_value, clippy::unused_unit)] #![warn(clippy::boxed_local)] diff --git a/tests/ui/escape_analysis.stderr b/tests/ui/escape_analysis.stderr index ed7819ed429..8af211f8a1a 100644 --- a/tests/ui/escape_analysis.stderr +++ b/tests/ui/escape_analysis.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:43:13 + --> $DIR/escape_analysis.rs:34:13 | LL | fn warn_arg(x: Box<A>) { | ^ @@ -7,7 +7,7 @@ LL | fn warn_arg(x: Box<A>) { = note: `-D clippy::boxed-local` implied by `-D warnings` error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:134:12 + --> $DIR/escape_analysis.rs:125:12 | LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {} | ^^^^^^^^^^^ diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 7b39d1c4054..b39de4c15a4 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( unused, clippy::no_effect, diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index fb7daba1578..218e46b40a8 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure found - --> $DIR/eta.rs:22:27 + --> $DIR/eta.rs:13:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` @@ -7,19 +7,19 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:23:10 + --> $DIR/eta.rs:14:10 | LL | meta(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` error: redundant closure found - --> $DIR/eta.rs:24:27 + --> $DIR/eta.rs:15:27 | LL | let c = Some(1u8).map(|a| {1+2; foo}(a)); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `{1+2; foo}` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/eta.rs:26:21 + --> $DIR/eta.rs:17:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` @@ -27,7 +27,7 @@ LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:33:27 + --> $DIR/eta.rs:24:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index 82110d5e4f3..d806bc6d401 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::eval_order_dependence)] #[allow( unused_assignments, diff --git a/tests/ui/eval_order_dependence.stderr b/tests/ui/eval_order_dependence.stderr index 929650a7da8..8f4fa2228f7 100644 --- a/tests/ui/eval_order_dependence.stderr +++ b/tests/ui/eval_order_dependence.stderr @@ -1,48 +1,48 @@ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:24:9 + --> $DIR/eval_order_dependence.rs:15:9 | LL | } + x; | ^ | = note: `-D clippy::eval-order-dependence` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:22:9 + --> $DIR/eval_order_dependence.rs:13:9 | LL | x = 1; | ^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:27:5 + --> $DIR/eval_order_dependence.rs:18:5 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:28:9 + --> $DIR/eval_order_dependence.rs:19:9 | LL | x = 20; | ^^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:40:12 + --> $DIR/eval_order_dependence.rs:31:12 | LL | a: x, | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:42:13 + --> $DIR/eval_order_dependence.rs:33:13 | LL | x = 6; | ^^^^^ error: unsequenced read of a variable - --> $DIR/eval_order_dependence.rs:49:9 + --> $DIR/eval_order_dependence.rs:40:9 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:50:13 + --> $DIR/eval_order_dependence.rs:41:13 | LL | x = 20; | ^^^^^^ diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 59b252a3a80..d5fa903c23f 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::excessive_precision)] #![allow(clippy::print_literal)] diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 57c33c4719b..da8d9471bcc 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -1,5 +1,5 @@ error: float has excessive precision - --> $DIR/excessive_precision.rs:23:26 + --> $DIR/excessive_precision.rs:14:26 | LL | const BAD32_1: f32 = 0.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` @@ -7,103 +7,103 @@ LL | const BAD32_1: f32 = 0.123_456_789_f32; = note: `-D clippy::excessive-precision` implied by `-D warnings` error: float has excessive precision - --> $DIR/excessive_precision.rs:24:26 + --> $DIR/excessive_precision.rs:15:26 | LL | const BAD32_2: f32 = 0.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:25:26 + --> $DIR/excessive_precision.rs:16:26 | LL | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:26:29 + --> $DIR/excessive_precision.rs:17:29 | LL | const BAD32_EDGE: f32 = 1.000_000_9; | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` error: float has excessive precision - --> $DIR/excessive_precision.rs:28:26 + --> $DIR/excessive_precision.rs:19:26 | LL | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:29:26 + --> $DIR/excessive_precision.rs:20:26 | LL | const BAD64_2: f64 = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:30:26 + --> $DIR/excessive_precision.rs:21:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:33:22 + --> $DIR/excessive_precision.rs:24:22 | LL | println!("{:?}", 8.888_888_888_888_888_888_888); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` error: float has excessive precision - --> $DIR/excessive_precision.rs:44:22 + --> $DIR/excessive_precision.rs:35:22 | LL | let bad32: f32 = 1.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:45:26 + --> $DIR/excessive_precision.rs:36:26 | LL | let bad32_suf: f32 = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:46:21 + --> $DIR/excessive_precision.rs:37:21 | LL | let bad32_inf = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:48:22 + --> $DIR/excessive_precision.rs:39:22 | LL | let bad64: f64 = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:49:26 + --> $DIR/excessive_precision.rs:40:26 | LL | let bad64_suf: f64 = 0.123_456_789_012_345_67f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:50:21 + --> $DIR/excessive_precision.rs:41:21 | LL | let bad64_inf = 0.123_456_789_012_345_67; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:56:36 + --> $DIR/excessive_precision.rs:47:36 | LL | let bad_vec32: Vec<f32> = vec![0.123_456_789]; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:57:36 + --> $DIR/excessive_precision.rs:48:36 | LL | let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78` error: float has excessive precision - --> $DIR/excessive_precision.rs:61:24 + --> $DIR/excessive_precision.rs:52:24 | LL | let bad_e32: f32 = 1.123_456_788_888e-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10` error: float has excessive precision - --> $DIR/excessive_precision.rs:64:27 + --> $DIR/excessive_precision.rs:55:27 | LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 8afffa4d843..0f930f6a8a2 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::expect_fun_call)] #![allow(clippy::useless_format)] diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index 72a6995c1ce..09844e29911 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:36:26 + --> $DIR/expect_fun_call.rs:27:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,31 +7,31 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:39:26 + --> $DIR/expect_fun_call.rs:30:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:49:25 + --> $DIR/expect_fun_call.rs:40:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:52:25 + --> $DIR/expect_fun_call.rs:43:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:67:17 + --> $DIR/expect_fun_call.rs:58:17 | LL | Some("foo").expect({ &format!("error") }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { let msg = { &format!("error") }; panic!(msg) }))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:68:17 + --> $DIR/expect_fun_call.rs:59:17 | LL | Some("foo").expect(format!("error").as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("error"))` diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 75d905659d9..5efac85cf22 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::explicit_counter_loop)] fn main() { diff --git a/tests/ui/explicit_counter_loop.stderr b/tests/ui/explicit_counter_loop.stderr index caccaee84b9..b1cfb31432f 100644 --- a/tests/ui/explicit_counter_loop.stderr +++ b/tests/ui/explicit_counter_loop.stderr @@ -1,5 +1,5 @@ error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators - --> $DIR/explicit_counter_loop.rs:15:15 + --> $DIR/explicit_counter_loop.rs:6:15 | LL | for _v in &vec { | ^^^^ @@ -7,19 +7,19 @@ LL | for _v in &vec { = note: `-D clippy::explicit-counter-loop` implied by `-D warnings` error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators - --> $DIR/explicit_counter_loop.rs:21:15 + --> $DIR/explicit_counter_loop.rs:12:15 | LL | for _v in &vec { | ^^^^ error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators - --> $DIR/explicit_counter_loop.rs:60:19 + --> $DIR/explicit_counter_loop.rs:51:19 | LL | for ch in text.chars() { | ^^^^^^^^^^^^ error: the variable `count` is used as a loop counter. Consider using `for (count, item) in text.chars().enumerate()` or similar iterators - --> $DIR/explicit_counter_loop.rs:71:19 + --> $DIR/explicit_counter_loop.rs:62:19 | LL | for ch in text.chars() { | ^^^^^^^^^^^^ diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index 01a63b3a95f..6231a0b0588 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::explicit_write)] fn stdout() -> String { diff --git a/tests/ui/explicit_write.stderr b/tests/ui/explicit_write.stderr index 1072d9bd0d2..5fd2f8a3abf 100644 --- a/tests/ui/explicit_write.stderr +++ b/tests/ui/explicit_write.stderr @@ -1,5 +1,5 @@ error: use of `write!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:24:9 + --> $DIR/explicit_write.rs:15:9 | LL | write!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` @@ -7,43 +7,43 @@ LL | write!(std::io::stdout(), "test").unwrap(); = note: `-D clippy::explicit-write` implied by `-D warnings` error: use of `write!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:25:9 + --> $DIR/explicit_write.rs:16:9 | LL | write!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:26:9 + --> $DIR/explicit_write.rs:17:9 | LL | writeln!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:27:9 + --> $DIR/explicit_write.rs:18:9 | LL | writeln!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")` error: use of `stdout().write_fmt(...).unwrap()` - --> $DIR/explicit_write.rs:28:9 + --> $DIR/explicit_write.rs:19:9 | LL | std::io::stdout().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")` error: use of `stderr().write_fmt(...).unwrap()` - --> $DIR/explicit_write.rs:29:9 + --> $DIR/explicit_write.rs:20:9 | LL | std::io::stderr().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> $DIR/explicit_write.rs:32:9 + --> $DIR/explicit_write.rs:23:9 | LL | writeln!(std::io::stdout(), "test/ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")` error: use of `writeln!(stderr(), ...).unwrap()` - --> $DIR/explicit_write.rs:33:9 + --> $DIR/explicit_write.rs:24:9 | LL | writeln!(std::io::stderr(), "test/ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")` diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 0d8c369660b..679f4a7dc35 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::fallible_impl_from)] // docs example diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index 55efac7951a..8b847df65cd 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -1,5 +1,5 @@ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:14:1 + --> $DIR/fallible_impl_from.rs:5:1 | LL | / impl From<String> for Foo { LL | | fn from(s: String) -> Self { @@ -9,19 +9,19 @@ LL | | } | |_^ | note: lint level defined here - --> $DIR/fallible_impl_from.rs:10:9 + --> $DIR/fallible_impl_from.rs:1:9 | LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:16:13 + --> $DIR/fallible_impl_from.rs:7:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:35:1 + --> $DIR/fallible_impl_from.rs:26:1 | LL | / impl From<usize> for Invalid { LL | | fn from(i: usize) -> Invalid { @@ -34,14 +34,14 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:38:13 + --> $DIR/fallible_impl_from.rs:29:13 | LL | panic!(); | ^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:44:1 + --> $DIR/fallible_impl_from.rs:35:1 | LL | / impl From<Option<String>> for Invalid { LL | | fn from(s: Option<String>) -> Invalid { @@ -54,7 +54,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:46:17 + --> $DIR/fallible_impl_from.rs:37:17 | LL | let s = s.unwrap(); | ^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | panic!("{:?}", s); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:62:1 + --> $DIR/fallible_impl_from.rs:53:1 | LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid { LL | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid { @@ -81,7 +81,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail. note: potential failure(s) - --> $DIR/fallible_impl_from.rs:64:12 + --> $DIR/fallible_impl_from.rs:55:12 | LL | if s.parse::<u32>().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index 7ca74fd4b99..ef434245fd7 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index c10d673148a..9dfd91f6d64 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,5 +1,5 @@ error: called `filter(p).map(q)` on an `Iterator`. This is more succinctly expressed by calling `.filter_map(..)` instead. - --> $DIR/filter_methods.rs:14:21 + --> $DIR/filter_methods.rs:5:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` error: called `filter(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator. - --> $DIR/filter_methods.rs:16:21 + --> $DIR/filter_methods.rs:7:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -17,7 +17,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | |_______________________________________^ error: called `filter_map(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator. - --> $DIR/filter_methods.rs:22:21 + --> $DIR/filter_methods.rs:13:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -27,7 +27,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | |_______________________________________^ error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly expressed by only calling `.filter_map(..)` instead. - --> $DIR/filter_methods.rs:28:21 + --> $DIR/filter_methods.rs:19:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index 2d55e30a2d3..92d38527bbf 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::float_cmp)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)] diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index bdbbccee714..ddaf4b82497 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -1,36 +1,36 @@ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:69:5 + --> $DIR/float_cmp.rs:60:5 | LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() < error` | = note: `-D clippy::float-cmp` implied by `-D warnings` note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:69:5 + --> $DIR/float_cmp.rs:60:5 | LL | ONE as f64 != 2.0; | ^^^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:74:5 + --> $DIR/float_cmp.rs:65:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:74:5 + --> $DIR/float_cmp.rs:65:5 | LL | x == 1.0; | ^^^^^^^^ error: strict comparison of f32 or f64 - --> $DIR/float_cmp.rs:77:5 + --> $DIR/float_cmp.rs:68:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp.rs:77:5 + --> $DIR/float_cmp.rs:68:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index e02671e0dcc..887275c5e88 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::float_cmp_const)] #![allow(clippy::float_cmp)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/float_cmp_const.stderr b/tests/ui/float_cmp_const.stderr index 2b434f31814..9ec921e536a 100644 --- a/tests/ui/float_cmp_const.stderr +++ b/tests/ui/float_cmp_const.stderr @@ -1,84 +1,84 @@ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:27:5 + --> $DIR/float_cmp_const.rs:18:5 | LL | 1f32 == ONE; | ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error` | = note: `-D clippy::float-cmp-const` implied by `-D warnings` note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:27:5 + --> $DIR/float_cmp_const.rs:18:5 | LL | 1f32 == ONE; | ^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:28:5 + --> $DIR/float_cmp_const.rs:19:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:28:5 + --> $DIR/float_cmp_const.rs:19:5 | LL | TWO == ONE; | ^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:29:5 + --> $DIR/float_cmp_const.rs:20:5 | LL | TWO != ONE; | ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:29:5 + --> $DIR/float_cmp_const.rs:20:5 | LL | TWO != ONE; | ^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:30:5 + --> $DIR/float_cmp_const.rs:21:5 | LL | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:30:5 + --> $DIR/float_cmp_const.rs:21:5 | LL | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:31:5 + --> $DIR/float_cmp_const.rs:22:5 | LL | 1 as f32 == ONE; | ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(1 as f32 - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:31:5 + --> $DIR/float_cmp_const.rs:22:5 | LL | 1 as f32 == ONE; | ^^^^^^^^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:34:5 + --> $DIR/float_cmp_const.rs:25:5 | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:34:5 + --> $DIR/float_cmp_const.rs:25:5 | LL | v == ONE; | ^^^^^^^^ error: strict comparison of f32 or f64 constant - --> $DIR/float_cmp_const.rs:35:5 + --> $DIR/float_cmp_const.rs:26:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error` | note: std::f32::EPSILON and std::f64::EPSILON are available. - --> $DIR/float_cmp_const.rs:35:5 + --> $DIR/float_cmp_const.rs:26:5 | LL | v != ONE; | ^^^^^^^^ diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs index 9b48a965cb3..21573af870a 100644 --- a/tests/ui/fn_to_numeric_cast.rs +++ b/tests/ui/fn_to_numeric_cast.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // only-64bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/fn_to_numeric_cast.stderr b/tests/ui/fn_to_numeric_cast.stderr index 16605fd344a..e9549e157cd 100644 --- a/tests/ui/fn_to_numeric_cast.stderr +++ b/tests/ui/fn_to_numeric_cast.stderr @@ -1,5 +1,5 @@ error: casting function pointer `foo` to `i8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:19:13 + --> $DIR/fn_to_numeric_cast.rs:10:13 | LL | let _ = foo as i8; | ^^^^^^^^^ help: try: `foo as usize` @@ -7,19 +7,19 @@ LL | let _ = foo as i8; = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings` error: casting function pointer `foo` to `i16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:20:13 + --> $DIR/fn_to_numeric_cast.rs:11:13 | LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:21:13 + --> $DIR/fn_to_numeric_cast.rs:12:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i64` - --> $DIR/fn_to_numeric_cast.rs:22:13 + --> $DIR/fn_to_numeric_cast.rs:13:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` @@ -27,115 +27,115 @@ LL | let _ = foo as i64; = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i128` - --> $DIR/fn_to_numeric_cast.rs:23:13 + --> $DIR/fn_to_numeric_cast.rs:14:13 | LL | let _ = foo as i128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `isize` - --> $DIR/fn_to_numeric_cast.rs:24:13 + --> $DIR/fn_to_numeric_cast.rs:15:13 | LL | let _ = foo as isize; | ^^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:26:13 + --> $DIR/fn_to_numeric_cast.rs:17:13 | LL | let _ = foo as u8; | ^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:27:13 + --> $DIR/fn_to_numeric_cast.rs:18:13 | LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:28:13 + --> $DIR/fn_to_numeric_cast.rs:19:13 | LL | let _ = foo as u32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u64` - --> $DIR/fn_to_numeric_cast.rs:29:13 + --> $DIR/fn_to_numeric_cast.rs:20:13 | LL | let _ = foo as u64; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u128` - --> $DIR/fn_to_numeric_cast.rs:30:13 + --> $DIR/fn_to_numeric_cast.rs:21:13 | LL | let _ = foo as u128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `abc` to `i8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:43:13 + --> $DIR/fn_to_numeric_cast.rs:34:13 | LL | let _ = abc as i8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:44:13 + --> $DIR/fn_to_numeric_cast.rs:35:13 | LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:45:13 + --> $DIR/fn_to_numeric_cast.rs:36:13 | LL | let _ = abc as i32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i64` - --> $DIR/fn_to_numeric_cast.rs:46:13 + --> $DIR/fn_to_numeric_cast.rs:37:13 | LL | let _ = abc as i64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i128` - --> $DIR/fn_to_numeric_cast.rs:47:13 + --> $DIR/fn_to_numeric_cast.rs:38:13 | LL | let _ = abc as i128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `isize` - --> $DIR/fn_to_numeric_cast.rs:48:13 + --> $DIR/fn_to_numeric_cast.rs:39:13 | LL | let _ = abc as isize; | ^^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u8`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:50:13 + --> $DIR/fn_to_numeric_cast.rs:41:13 | LL | let _ = abc as u8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u16`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:51:13 + --> $DIR/fn_to_numeric_cast.rs:42:13 | LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:52:13 + --> $DIR/fn_to_numeric_cast.rs:43:13 | LL | let _ = abc as u32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u64` - --> $DIR/fn_to_numeric_cast.rs:53:13 + --> $DIR/fn_to_numeric_cast.rs:44:13 | LL | let _ = abc as u64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u128` - --> $DIR/fn_to_numeric_cast.rs:54:13 + --> $DIR/fn_to_numeric_cast.rs:45:13 | LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `f` to `i32`, which truncates the value - --> $DIR/fn_to_numeric_cast.rs:61:5 + --> $DIR/fn_to_numeric_cast.rs:52:5 | LL | f as i32 | ^^^^^^^^ help: try: `f as usize` diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs index 549187756ab..39a8d960a7e 100644 --- a/tests/ui/for_kv_map.rs +++ b/tests/ui/for_kv_map.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::for_kv_map)] #![allow(clippy::used_underscore_binding)] diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr index 7b65c58f58d..ebe758526ec 100644 --- a/tests/ui/for_kv_map.stderr +++ b/tests/ui/for_kv_map.stderr @@ -1,5 +1,5 @@ error: you seem to want to iterate on a map's values - --> $DIR/for_kv_map.rs:18:19 + --> $DIR/for_kv_map.rs:9:19 | LL | for (_, v) in &m { | ^^ @@ -11,7 +11,7 @@ LL | for v in m.values() { | ^ ^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_kv_map.rs:23:19 + --> $DIR/for_kv_map.rs:14:19 | LL | for (_, v) in &*m { | ^^^ @@ -21,7 +21,7 @@ LL | for v in (*m).values() { | ^ ^^^^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_kv_map.rs:31:19 + --> $DIR/for_kv_map.rs:22:19 | LL | for (_, v) in &mut m { | ^^^^^^ @@ -31,7 +31,7 @@ LL | for v in m.values_mut() { | ^ ^^^^^^^^^^^^^^ error: you seem to want to iterate on a map's values - --> $DIR/for_kv_map.rs:36:19 + --> $DIR/for_kv_map.rs:27:19 | LL | for (_, v) in &mut *m { | ^^^^^^^ @@ -41,7 +41,7 @@ LL | for v in (*m).values_mut() { | ^ ^^^^^^^^^^^^^^^^^ error: you seem to want to iterate on a map's keys - --> $DIR/for_kv_map.rs:42:24 + --> $DIR/for_kv_map.rs:33:24 | LL | for (k, _value) in rm { | ^^ diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index c172b0b3b77..f73bb41a9bb 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::collections::*; use std::rc::Rc; diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index 4ded425b321..50f10d6187b 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -1,5 +1,5 @@ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:50:14 + --> $DIR/for_loop.rs:41:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | for <item> in &vec { | ^^^^^^ ^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:59:14 + --> $DIR/for_loop.rs:50:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | for <item> in &vec { | ^^^^^^ ^^^^ error: the loop variable `j` is only used to index `STATIC`. - --> $DIR/for_loop.rs:64:14 + --> $DIR/for_loop.rs:55:14 | LL | for j in 0..4 { | ^^^^ @@ -31,7 +31,7 @@ LL | for <item> in &STATIC { | ^^^^^^ ^^^^^^^ error: the loop variable `j` is only used to index `CONST`. - --> $DIR/for_loop.rs:68:14 + --> $DIR/for_loop.rs:59:14 | LL | for j in 0..4 { | ^^^^ @@ -41,7 +41,7 @@ LL | for <item> in &CONST { | ^^^^^^ ^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:72:14 + --> $DIR/for_loop.rs:63:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | for (i, <item>) in vec.iter().enumerate() { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec2`. - --> $DIR/for_loop.rs:80:14 + --> $DIR/for_loop.rs:71:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | for <item> in vec2.iter().take(vec.len()) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:84:14 + --> $DIR/for_loop.rs:75:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | for <item> in vec.iter().skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:88:14 + --> $DIR/for_loop.rs:79:14 | LL | for i in 0..MAX_LEN { | ^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | for <item> in vec.iter().take(MAX_LEN) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:92:14 + --> $DIR/for_loop.rs:83:14 | LL | for i in 0..=MAX_LEN { | ^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | for <item> in vec.iter().take(MAX_LEN + 1) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:96:14 + --> $DIR/for_loop.rs:87:14 | LL | for i in 5..10 { | ^^^^^ @@ -101,7 +101,7 @@ LL | for <item> in vec.iter().take(10).skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/for_loop.rs:100:14 + --> $DIR/for_loop.rs:91:14 | LL | for i in 5..=10 { | ^^^^^^ @@ -111,7 +111,7 @@ LL | for <item> in vec.iter().take(10 + 1).skip(5) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:104:14 + --> $DIR/for_loop.rs:95:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | for (i, <item>) in vec.iter().enumerate().skip(5) { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is used to index `vec` - --> $DIR/for_loop.rs:108:14 + --> $DIR/for_loop.rs:99:14 | LL | for i in 5..10 { | ^^^^^ @@ -131,7 +131,7 @@ LL | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) { | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:112:14 + --> $DIR/for_loop.rs:103:14 | LL | for i in 10..0 { | ^^^^^ @@ -143,7 +143,7 @@ LL | for i in (0..10).rev() { | ^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:116:14 + --> $DIR/for_loop.rs:107:14 | LL | for i in 10..=0 { | ^^^^^^ @@ -153,7 +153,7 @@ LL | for i in (0...10).rev() { | ^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:120:14 + --> $DIR/for_loop.rs:111:14 | LL | for i in MAX_LEN..0 { | ^^^^^^^^^^ @@ -163,13 +163,13 @@ LL | for i in (0..MAX_LEN).rev() { | ^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:124:14 + --> $DIR/for_loop.rs:115:14 | LL | for i in 5..5 { | ^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:149:14 + --> $DIR/for_loop.rs:140:14 | LL | for i in 10..5 + 4 { | ^^^^^^^^^ @@ -179,7 +179,7 @@ LL | for i in (5 + 4..10).rev() { | ^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:153:14 + --> $DIR/for_loop.rs:144:14 | LL | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ @@ -189,13 +189,13 @@ LL | for i in ((3 - 1)..(5 + 2)).rev() { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:157:14 + --> $DIR/for_loop.rs:148:14 | LL | for i in (5 + 2)..(8 - 1) { | ^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:179:15 + --> $DIR/for_loop.rs:170:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -203,13 +203,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:181:15 + --> $DIR/for_loop.rs:172:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods` - --> $DIR/for_loop.rs:184:15 + --> $DIR/for_loop.rs:175:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -217,67 +217,67 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:187:15 + --> $DIR/for_loop.rs:178:15 | LL | for _v in array.into_iter() {} | ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&array` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:192:15 + --> $DIR/for_loop.rs:183:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:196:15 + --> $DIR/for_loop.rs:187:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:201:15 + --> $DIR/for_loop.rs:192:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:204:15 + --> $DIR/for_loop.rs:195:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:207:15 + --> $DIR/for_loop.rs:198:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:210:15 + --> $DIR/for_loop.rs:201:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:213:15 + --> $DIR/for_loop.rs:204:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:216:15 + --> $DIR/for_loop.rs:207:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:219:15 + --> $DIR/for_loop.rs:210:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop.rs:221:15 + --> $DIR/for_loop.rs:212:15 | LL | for _v in vec.iter().next() {} | ^^^^^^^^^^^^^^^^^ @@ -285,7 +285,7 @@ LL | for _v in vec.iter().next() {} = note: `-D clippy::iter-next-loop` implied by `-D warnings` error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/for_loop.rs:228:5 + --> $DIR/for_loop.rs:219:5 | LL | vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -293,7 +293,7 @@ LL | vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); = note: `-D clippy::unused-collect` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:372:14 + --> $DIR/for_loop.rs:363:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` @@ -301,31 +301,31 @@ LL | for i in 0..src.len() { = note: `-D clippy::manual-memcpy` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:377:14 + --> $DIR/for_loop.rs:368:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:382:14 + --> $DIR/for_loop.rs:373:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:387:14 + --> $DIR/for_loop.rs:378:14 | LL | for i in 11..src.len() { | ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:392:14 + --> $DIR/for_loop.rs:383:14 | LL | for i in 0..dst.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:405:14 + --> $DIR/for_loop.rs:396:14 | LL | for i in 10..256 { | ^^^^^^^ @@ -336,31 +336,31 @@ LL | dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) { | error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:417:14 + --> $DIR/for_loop.rs:408:14 | LL | for i in 10..LOOP_OFFSET { | ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:430:14 + --> $DIR/for_loop.rs:421:14 | LL | for i in 0..src_vec.len() { | ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:459:14 + --> $DIR/for_loop.rs:450:14 | LL | for i in from..from + src.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:463:14 + --> $DIR/for_loop.rs:454:14 | LL | for i in from..from + 3 { | ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])` error: it looks like you're manually copying between slices - --> $DIR/for_loop.rs:470:14 + --> $DIR/for_loop.rs:461:14 | LL | for i in 0..src.len() { | ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` diff --git a/tests/ui/for_loop_over_option_result.rs b/tests/ui/for_loop_over_option_result.rs index 37fd4e6d038..6b207b26b6b 100644 --- a/tests/ui/for_loop_over_option_result.rs +++ b/tests/ui/for_loop_over_option_result.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::for_loop_over_option, clippy::for_loop_over_result)] /// Tests for_loop_over_result and for_loop_over_option diff --git a/tests/ui/for_loop_over_option_result.stderr b/tests/ui/for_loop_over_option_result.stderr index f8a4212b253..5414bfcf9de 100644 --- a/tests/ui/for_loop_over_option_result.stderr +++ b/tests/ui/for_loop_over_option_result.stderr @@ -1,5 +1,5 @@ error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:20:14 + --> $DIR/for_loop_over_option_result.rs:11:14 | LL | for x in option { | ^^^^^^ @@ -8,7 +8,7 @@ LL | for x in option { = help: consider replacing `for x in option` with `if let Some(x) = option` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:25:14 + --> $DIR/for_loop_over_option_result.rs:16:14 | LL | for x in result { | ^^^^^^ @@ -17,7 +17,7 @@ LL | for x in result { = help: consider replacing `for x in result` with `if let Ok(x) = result` error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:29:14 + --> $DIR/for_loop_over_option_result.rs:20:14 | LL | for x in option.ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | for x in option.ok_or("x not found") { = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop_over_option_result.rs:35:14 + --> $DIR/for_loop_over_option_result.rs:26:14 | LL | for x in v.iter().next() { | ^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for x in v.iter().next() { = note: #[deny(clippy::iter_next_loop)] on by default error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:40:14 + --> $DIR/for_loop_over_option_result.rs:31:14 | LL | for x in v.iter().next().and(Some(0)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | for x in v.iter().next().and(Some(0)) { = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:44:14 + --> $DIR/for_loop_over_option_result.rs:35:14 | LL | for x in v.iter().next().ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | for x in v.iter().next().ok_or("x not found") { = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")` error: this loop never actually loops - --> $DIR/for_loop_over_option_result.rs:56:5 + --> $DIR/for_loop_over_option_result.rs:47:5 | LL | / while let Some(x) = option { LL | | println!("{}", x); @@ -60,7 +60,7 @@ LL | | } = note: #[deny(clippy::never_loop)] on by default error: this loop never actually loops - --> $DIR/for_loop_over_option_result.rs:62:5 + --> $DIR/for_loop_over_option_result.rs:53:5 | LL | / while let Ok(x) = result { LL | | println!("{}", x); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 6b1577e24ca..f2892c5b84a 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,13 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - #![allow(clippy::print_literal)] #![warn(clippy::useless_format)] diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 871fc8fba3e..d5f2711bb37 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:11:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` @@ -7,7 +7,7 @@ LL | format!("foo"); = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:23:5 + --> $DIR/format.rs:13:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` @@ -15,7 +15,7 @@ LL | format!("{}", "foo"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:27:5 + --> $DIR/format.rs:17:5 | LL | format!("{:+}", "foo"); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` @@ -23,7 +23,7 @@ LL | format!("{:+}", "foo"); // warn when the format makes no difference = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:28:5 + --> $DIR/format.rs:18:5 | LL | format!("{:<}", "foo"); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()` @@ -31,7 +31,7 @@ LL | format!("{:<}", "foo"); // warn when the format makes no difference = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:33:5 + --> $DIR/format.rs:23:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` @@ -39,7 +39,7 @@ LL | format!("{}", arg); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:37:5 + --> $DIR/format.rs:27:5 | LL | format!("{:+}", arg); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` @@ -47,7 +47,7 @@ LL | format!("{:+}", arg); // warn when the format makes no difference = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:38:5 + --> $DIR/format.rs:28:5 | LL | format!("{:<}", arg); // warn when the format makes no difference | ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()` @@ -55,7 +55,7 @@ LL | format!("{:<}", arg); // warn when the format makes no difference = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:65:5 + --> $DIR/format.rs:55:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `42.to_string()` @@ -63,7 +63,7 @@ LL | format!("{}", 42.to_string()); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: useless use of `format!` - --> $DIR/format.rs:67:5 + --> $DIR/format.rs:57:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `x.display().to_string()` diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index b74f778b129..904c05b068c 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(unused_variables)] #![allow(unused_assignments)] diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index 061540b9aa5..3d723ce71b9 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -1,5 +1,5 @@ error: this looks like an `else {..}` but the `else` is missing - --> $DIR/formatting.rs:21:6 + --> $DIR/formatting.rs:12:6 | LL | } { | ^ @@ -8,7 +8,7 @@ LL | } { = note: to remove this lint, add the missing `else` or add a new line before the next block error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:25:6 + --> $DIR/formatting.rs:16:6 | LL | } if foo() { | ^ @@ -16,7 +16,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:32:10 + --> $DIR/formatting.rs:23:10 | LL | } if foo() { | ^ @@ -24,7 +24,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/formatting.rs:40:10 + --> $DIR/formatting.rs:31:10 | LL | } if foo() { | ^ @@ -32,7 +32,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this is an `else {..}` but the formatting might hide it - --> $DIR/formatting.rs:49:6 + --> $DIR/formatting.rs:40:6 | LL | } else | ______^ @@ -42,7 +42,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else {..}` but the formatting might hide it - --> $DIR/formatting.rs:54:6 + --> $DIR/formatting.rs:45:6 | LL | } | ______^ @@ -53,7 +53,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:60:6 + --> $DIR/formatting.rs:51:6 | LL | } else | ______^ @@ -63,7 +63,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else if` but the formatting might hide it - --> $DIR/formatting.rs:65:6 + --> $DIR/formatting.rs:56:6 | LL | } | ______^ @@ -74,7 +74,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` - --> $DIR/formatting.rs:106:6 + --> $DIR/formatting.rs:97:6 | LL | a =- 35; | ^^^^ @@ -83,7 +83,7 @@ LL | a =- 35; = note: to remove this lint, use either `-=` or `= -` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> $DIR/formatting.rs:107:6 + --> $DIR/formatting.rs:98:6 | LL | a =* &191; | ^^^^ @@ -91,7 +91,7 @@ LL | a =* &191; = note: to remove this lint, use either `*=` or `= *` error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> $DIR/formatting.rs:110:6 + --> $DIR/formatting.rs:101:6 | LL | b =! false; | ^^^^ @@ -99,7 +99,7 @@ LL | b =! false; = note: to remove this lint, use either `!=` or `= !` error: possibly missing a comma here - --> $DIR/formatting.rs:119:19 + --> $DIR/formatting.rs:110:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -108,7 +108,7 @@ LL | -1, -2, -3 // <= no comma here = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> $DIR/formatting.rs:123:19 + --> $DIR/formatting.rs:114:19 | LL | -1, -2, -3 // <= no comma here | ^ diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 41963294815..500576d1dff 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(dead_code)] #![allow(unused_unsafe)] diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index b23d09309bb..150b50d9a7c 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -1,5 +1,5 @@ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:17:1 + --> $DIR/functions.rs:8:1 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f = note: `-D clippy::too-many-arguments` implied by `-D warnings` error: this function has too many arguments (8/7) - --> $DIR/functions.rs:34:5 + --> $DIR/functions.rs:25:5 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:43:5 + --> $DIR/functions.rs:34:5 | LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:52:34 + --> $DIR/functions.rs:43:34 | LL | println!("{}", unsafe { *p }); | ^ @@ -27,49 +27,49 @@ LL | println!("{}", unsafe { *p }); = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:53:35 + --> $DIR/functions.rs:44:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:54:33 + --> $DIR/functions.rs:45:33 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:65:30 + --> $DIR/functions.rs:56:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:66:31 + --> $DIR/functions.rs:57:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:67:29 + --> $DIR/functions.rs:58:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:76:34 + --> $DIR/functions.rs:67:34 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:77:35 + --> $DIR/functions.rs:68:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:78:33 + --> $DIR/functions.rs:69:33 | LL | unsafe { std::ptr::read(p) }; | ^ diff --git a/tests/ui/fxhash.rs b/tests/ui/fxhash.rs index 2299714132f..7d6cb4e1179 100644 --- a/tests/ui/fxhash.rs +++ b/tests/ui/fxhash.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::default_hash_types)] #![feature(rustc_private)] diff --git a/tests/ui/fxhash.stderr b/tests/ui/fxhash.stderr index 14fc4a8090b..a2dac670018 100644 --- a/tests/ui/fxhash.stderr +++ b/tests/ui/fxhash.stderr @@ -1,5 +1,5 @@ error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:16:24 + --> $DIR/fxhash.rs:7:24 | LL | use std::collections::{HashMap, HashSet}; | ^^^^^^^ help: use: `FxHashMap` @@ -7,31 +7,31 @@ LL | use std::collections::{HashMap, HashSet}; = note: `-D clippy::default-hash-types` implied by `-D warnings` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:16:33 + --> $DIR/fxhash.rs:7:33 | LL | use std::collections::{HashMap, HashSet}; | ^^^^^^^ help: use: `FxHashSet` error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:19:15 + --> $DIR/fxhash.rs:10:15 | LL | let _map: HashMap<String, String> = HashMap::default(); | ^^^^^^^ help: use: `FxHashMap` error: Prefer FxHashMap over HashMap, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:19:41 + --> $DIR/fxhash.rs:10:41 | LL | let _map: HashMap<String, String> = HashMap::default(); | ^^^^^^^ help: use: `FxHashMap` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:20:15 + --> $DIR/fxhash.rs:11:15 | LL | let _set: HashSet<String> = HashSet::default(); | ^^^^^^^ help: use: `FxHashSet` error: Prefer FxHashSet over HashSet, it has better performance and we don't need any collision prevention in clippy - --> $DIR/fxhash.rs:20:33 + --> $DIR/fxhash.rs:11:33 | LL | let _set: HashSet<String> = HashSet::default(); | ^^^^^^^ help: use: `FxHashSet` diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 021c0c2ff44..f9d52286355 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![allow(unused_mut)] diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index b041ba7b7c7..244a2ef25a1 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![allow(unused_mut)] diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index d4f699f5a72..dd3a5c68e0a 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -1,5 +1,5 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:42:17 + --> $DIR/get_unwrap.rs:33:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` @@ -7,73 +7,73 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::get-unwrap` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:43:17 + --> $DIR/get_unwrap.rs:34:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:44:17 + --> $DIR/get_unwrap.rs:35:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:45:17 + --> $DIR/get_unwrap.rs:36:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:46:17 + --> $DIR/get_unwrap.rs:37:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:47:17 + --> $DIR/get_unwrap.rs:38:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:50:21 + --> $DIR/get_unwrap.rs:41:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:55:9 + --> $DIR/get_unwrap.rs:46:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:56:9 + --> $DIR/get_unwrap.rs:47:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:57:9 + --> $DIR/get_unwrap.rs:48:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:58:9 + --> $DIR/get_unwrap.rs:49:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:67:17 + --> $DIR/get_unwrap.rs:58:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:68:17 + --> $DIR/get_unwrap.rs:59:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` diff --git a/tests/ui/ice-2636.rs b/tests/ui/ice-2636.rs index caf8c89390d..e0b58157590 100644 --- a/tests/ui/ice-2636.rs +++ b/tests/ui/ice-2636.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] enum Foo { diff --git a/tests/ui/ice-2636.stderr b/tests/ui/ice-2636.stderr index a6b150f9b90..aba8be4adcc 100644 --- a/tests/ui/ice-2636.stderr +++ b/tests/ui/ice-2636.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to both the expression and the patterns - --> $DIR/ice-2636.rs:21:9 + --> $DIR/ice-2636.rs:12:9 | LL | / match $foo { LL | | $ ( & $t => $ord, diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs index 6ba191b0b84..6491518af6c 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/identity_conversion.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::identity_conversion)] fn test_generic<T: Copy>(val: T) -> T { diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/identity_conversion.stderr index 4b0b958e285..73a1996180b 100644 --- a/tests/ui/identity_conversion.stderr +++ b/tests/ui/identity_conversion.stderr @@ -1,65 +1,65 @@ error: identical conversion - --> $DIR/identity_conversion.rs:13:13 + --> $DIR/identity_conversion.rs:4:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` | note: lint level defined here - --> $DIR/identity_conversion.rs:10:9 + --> $DIR/identity_conversion.rs:1:9 | LL | #![deny(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: identical conversion - --> $DIR/identity_conversion.rs:14:5 + --> $DIR/identity_conversion.rs:5:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: identical conversion - --> $DIR/identity_conversion.rs:26:22 + --> $DIR/identity_conversion.rs:17:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: identical conversion - --> $DIR/identity_conversion.rs:47:21 + --> $DIR/identity_conversion.rs:38:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:48:21 + --> $DIR/identity_conversion.rs:39:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:49:13 + --> $DIR/identity_conversion.rs:40:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:50:13 + --> $DIR/identity_conversion.rs:41:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: identical conversion - --> $DIR/identity_conversion.rs:51:13 + --> $DIR/identity_conversion.rs:42:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: identical conversion - --> $DIR/identity_conversion.rs:52:13 + --> $DIR/identity_conversion.rs:43:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: identical conversion - --> $DIR/identity_conversion.rs:53:21 + --> $DIR/identity_conversion.rs:44:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 299cd2a6786..ae2815d345a 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - const ONE: i64 = 1; const NEG_ONE: i64 = -1; const ZERO: i64 = 0; diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 8b42cfbf1ce..4742877706a 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -1,5 +1,5 @@ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:25:5 + --> $DIR/identity_op.rs:16:5 | LL | x + 0; | ^^^^^ @@ -7,43 +7,43 @@ LL | x + 0; = note: `-D clippy::identity-op` implied by `-D warnings` error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:26:5 + --> $DIR/identity_op.rs:17:5 | LL | x + (1 - 1); | ^^^^^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:28:5 + --> $DIR/identity_op.rs:19:5 | LL | 0 + x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:31:5 + --> $DIR/identity_op.rs:22:5 | LL | x | (0); | ^^^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:34:5 + --> $DIR/identity_op.rs:25:5 | LL | x * 1; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:35:5 + --> $DIR/identity_op.rs:26:5 | LL | 1 * x; | ^^^^^ error: the operation is ineffective. Consider reducing it to `x` - --> $DIR/identity_op.rs:41:5 + --> $DIR/identity_op.rs:32:5 | LL | -1 & x; | ^^^^^^ error: the operation is ineffective. Consider reducing it to `u` - --> $DIR/identity_op.rs:44:5 + --> $DIR/identity_op.rs:35:5 | LL | u & 255; | ^^^^^^^ diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 0179381fdc3..dc3fb1ceac9 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![warn(clippy::if_not_else)] diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index acdf543cc75..3694f5aec53 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -1,5 +1,5 @@ error: Unnecessary boolean `not` operation - --> $DIR/if_not_else.rs:18:5 + --> $DIR/if_not_else.rs:9:5 | LL | / if !bla() { LL | | println!("Bugs"); @@ -12,7 +12,7 @@ LL | | } = help: remove the `!` and swap the blocks of the if/else error: Unnecessary `!=` operation - --> $DIR/if_not_else.rs:23:5 + --> $DIR/if_not_else.rs:14:5 | LL | / if 4 != 5 { LL | | println!("Bugs"); diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index 398a8ccce44..1c46e3a5337 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] #![warn(clippy::multiple_inherent_impl)] diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 8bddd400f70..585d32845d2 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -1,5 +1,5 @@ error: Multiple implementations of this structure - --> $DIR/impl.rs:19:1 + --> $DIR/impl.rs:10:1 | LL | / impl MyStruct { LL | | fn second() {} @@ -8,7 +8,7 @@ LL | | } | = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings` note: First implementation here - --> $DIR/impl.rs:15:1 + --> $DIR/impl.rs:6:1 | LL | / impl MyStruct { LL | | fn first() {} @@ -16,7 +16,7 @@ LL | | } | |_^ error: Multiple implementations of this structure - --> $DIR/impl.rs:33:5 + --> $DIR/impl.rs:24:5 | LL | / impl super::MyStruct { LL | | fn third() {} @@ -24,7 +24,7 @@ LL | | } | |_____^ | note: First implementation here - --> $DIR/impl.rs:15:1 + --> $DIR/impl.rs:6:1 | LL | / impl MyStruct { LL | | fn first() {} diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index acd5a52ff38..064760e73f3 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] use std::cmp::Eq; diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 0c61dbc4c64..68e305f0cb4 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,5 +1,5 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:20:35 + --> $DIR/implicit_hasher.rs:11:35 | LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { | ^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:29:36 + --> $DIR/implicit_hasher.rs:20:36 | LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { | ^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:34:19 + --> $DIR/implicit_hasher.rs:25:19 | LL | impl Foo<i16> for HashMap<String, String> { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:51:32 + --> $DIR/implicit_hasher.rs:42:32 | LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { | ^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:56:19 + --> $DIR/implicit_hasher.rs:47:19 | LL | impl Foo<i16> for HashSet<String> { | ^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:23 + --> $DIR/implicit_hasher.rs:64:23 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:53 + --> $DIR/implicit_hasher.rs:64:53 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:77:43 + --> $DIR/implicit_hasher.rs:68:43 | LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { | ^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:85:33 + --> $DIR/implicit_hasher.rs:76:33 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:85:63 + --> $DIR/implicit_hasher.rs:76:63 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 46ead9bf0c5..0fe4a283abf 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::implicit_return)] fn test_end_of_fn() -> bool { diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr index 4c62a7d65c6..c07fced1259 100644 --- a/tests/ui/implicit_return.stderr +++ b/tests/ui/implicit_return.stderr @@ -1,5 +1,5 @@ error: missing return statement - --> $DIR/implicit_return.rs:17:5 + --> $DIR/implicit_return.rs:8:5 | LL | true | ^^^^ help: add `return` as shown: `return true` @@ -7,55 +7,55 @@ LL | true = note: `-D clippy::implicit-return` implied by `-D warnings` error: missing return statement - --> $DIR/implicit_return.rs:23:9 + --> $DIR/implicit_return.rs:14:9 | LL | true | ^^^^ help: add `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:25:9 + --> $DIR/implicit_return.rs:16:9 | LL | false | ^^^^^ help: add `return` as shown: `return false` error: missing return statement - --> $DIR/implicit_return.rs:33:17 + --> $DIR/implicit_return.rs:24:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing return statement - --> $DIR/implicit_return.rs:34:20 + --> $DIR/implicit_return.rs:25:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:41:9 + --> $DIR/implicit_return.rs:32:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:49:13 + --> $DIR/implicit_return.rs:40:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:58:13 + --> $DIR/implicit_return.rs:49:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:67:18 + --> $DIR/implicit_return.rs:58:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing return statement - --> $DIR/implicit_return.rs:68:16 + --> $DIR/implicit_return.rs:59:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index 31e34135bfc..529ab042610 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::inconsistent_digit_grouping)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/inconsistent_digit_grouping.stderr b/tests/ui/inconsistent_digit_grouping.stderr index ba909b94480..9b903d1764f 100644 --- a/tests/ui/inconsistent_digit_grouping.stderr +++ b/tests/ui/inconsistent_digit_grouping.stderr @@ -1,5 +1,5 @@ error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:22:16 + --> $DIR/inconsistent_digit_grouping.rs:13:16 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^ help: consider: `123_456` @@ -7,25 +7,25 @@ LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:22:26 + --> $DIR/inconsistent_digit_grouping.rs:13:26 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^ help: consider: `12_345_678` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:22:38 + --> $DIR/inconsistent_digit_grouping.rs:13:38 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^ help: consider: `1_234_567` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:22:48 + --> $DIR/inconsistent_digit_grouping.rs:13:48 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:22:64 + --> $DIR/inconsistent_digit_grouping.rs:13:64 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32` diff --git a/tests/ui/indexing_slicing.rs b/tests/ui/indexing_slicing.rs index a9e697e519f..f0bd39c0254 100644 --- a/tests/ui/indexing_slicing.rs +++ b/tests/ui/indexing_slicing.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(plugin)] #![warn(clippy::indexing_slicing)] #![warn(clippy::out_of_bounds_indexing)] diff --git a/tests/ui/indexing_slicing.stderr b/tests/ui/indexing_slicing.stderr index 2e7bff3e0d5..129fec0e97c 100644 --- a/tests/ui/indexing_slicing.stderr +++ b/tests/ui/indexing_slicing.stderr @@ -1,5 +1,5 @@ error: index out of bounds: the len is 4 but the index is 4 - --> $DIR/indexing_slicing.rs:25:5 + --> $DIR/indexing_slicing.rs:16:5 | LL | x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. | ^^^^ @@ -7,25 +7,25 @@ LL | x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on ar = note: #[deny(const_err)] on by default error: index out of bounds: the len is 4 but the index is 8 - --> $DIR/indexing_slicing.rs:26:5 + --> $DIR/indexing_slicing.rs:17:5 | LL | x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. | ^^^^^^^^^ error: index out of bounds: the len is 0 but the index is 0 - --> $DIR/indexing_slicing.rs:56:5 + --> $DIR/indexing_slicing.rs:47:5 | LL | empty[0]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. | ^^^^^^^^ error: index out of bounds: the len is 4 but the index is 15 - --> $DIR/indexing_slicing.rs:87:5 + --> $DIR/indexing_slicing.rs:78:5 | LL | x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. | ^^^^ error: indexing may panic. - --> $DIR/indexing_slicing.rs:20:5 + --> $DIR/indexing_slicing.rs:11:5 | LL | x[index]; | ^^^^^^^^ @@ -34,7 +34,7 @@ LL | x[index]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:21:6 + --> $DIR/indexing_slicing.rs:12:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | &x[index..]; = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:22:6 + --> $DIR/indexing_slicing.rs:13:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | &x[..index]; = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:23:6 + --> $DIR/indexing_slicing.rs:14:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | &x[index_from..index_to]; = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:24:6 + --> $DIR/indexing_slicing.rs:15:6 | LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from. = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:24:6 + --> $DIR/indexing_slicing.rs:15:6 | LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to]. | ^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | &x[index_from..][..index_to]; // Two lint reports, one for [index_from. = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:27:11 + --> $DIR/indexing_slicing.rs:18:11 | LL | &x[..=4]; | ^ @@ -82,13 +82,13 @@ LL | &x[..=4]; = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` error: range is out of bounds - --> $DIR/indexing_slicing.rs:28:11 + --> $DIR/indexing_slicing.rs:19:11 | LL | &x[1..5]; | ^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:29:6 + --> $DIR/indexing_slicing.rs:20:6 | LL | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. | ^^^^^^^^^^^^ @@ -96,37 +96,37 @@ LL | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10 = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:29:8 + --> $DIR/indexing_slicing.rs:20:8 | LL | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10]. | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:30:8 + --> $DIR/indexing_slicing.rs:21:8 | LL | &x[5..]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:31:10 + --> $DIR/indexing_slicing.rs:22:10 | LL | &x[..5]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:32:8 + --> $DIR/indexing_slicing.rs:23:8 | LL | &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>(); | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:33:12 + --> $DIR/indexing_slicing.rs:24:12 | LL | &x[0..=4]; | ^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:34:6 + --> $DIR/indexing_slicing.rs:25:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | &x[0..][..3]; = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:35:6 + --> $DIR/indexing_slicing.rs:26:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | &x[1..][..5]; = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:48:5 + --> $DIR/indexing_slicing.rs:39:5 | LL | y[0]; | ^^^^ @@ -150,7 +150,7 @@ LL | y[0]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:49:6 + --> $DIR/indexing_slicing.rs:40:6 | LL | &y[1..2]; | ^^^^^^^ @@ -158,7 +158,7 @@ LL | &y[1..2]; = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:50:6 + --> $DIR/indexing_slicing.rs:41:6 | LL | &y[0..=4]; | ^^^^^^^^ @@ -166,7 +166,7 @@ LL | &y[0..=4]; = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:51:6 + --> $DIR/indexing_slicing.rs:42:6 | LL | &y[..=4]; | ^^^^^^^ @@ -174,49 +174,49 @@ LL | &y[..=4]; = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:57:12 + --> $DIR/indexing_slicing.rs:48:12 | LL | &empty[1..5]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:58:16 + --> $DIR/indexing_slicing.rs:49:16 | LL | &empty[0..=4]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:59:15 + --> $DIR/indexing_slicing.rs:50:15 | LL | &empty[..=4]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:60:12 + --> $DIR/indexing_slicing.rs:51:12 | LL | &empty[1..]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:61:14 + --> $DIR/indexing_slicing.rs:52:14 | LL | &empty[..4]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:62:16 + --> $DIR/indexing_slicing.rs:53:16 | LL | &empty[0..=0]; | ^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:63:15 + --> $DIR/indexing_slicing.rs:54:15 | LL | &empty[..=0]; | ^ error: indexing may panic. - --> $DIR/indexing_slicing.rs:71:5 + --> $DIR/indexing_slicing.rs:62:5 | LL | v[0]; | ^^^^ @@ -224,7 +224,7 @@ LL | v[0]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:72:5 + --> $DIR/indexing_slicing.rs:63:5 | LL | v[10]; | ^^^^^ @@ -232,7 +232,7 @@ LL | v[10]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:73:5 + --> $DIR/indexing_slicing.rs:64:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -240,7 +240,7 @@ LL | v[1 << 3]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:74:6 + --> $DIR/indexing_slicing.rs:65:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -248,7 +248,7 @@ LL | &v[10..100]; = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:75:6 + --> $DIR/indexing_slicing.rs:66:6 | LL | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^^^^^^^^^^^^^ @@ -256,13 +256,13 @@ LL | &x[10..][..100]; // Two lint reports, one for [10..] and another for [. = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:75:8 + --> $DIR/indexing_slicing.rs:66:8 | LL | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100]. | ^^ error: slicing may panic. - --> $DIR/indexing_slicing.rs:76:6 + --> $DIR/indexing_slicing.rs:67:6 | LL | &v[10..]; | ^^^^^^^ @@ -270,7 +270,7 @@ LL | &v[10..]; = help: Consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic. - --> $DIR/indexing_slicing.rs:77:6 + --> $DIR/indexing_slicing.rs:68:6 | LL | &v[..100]; | ^^^^^^^^ @@ -278,7 +278,7 @@ LL | &v[..100]; = help: Consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:89:5 + --> $DIR/indexing_slicing.rs:80:5 | LL | v[N]; | ^^^^ @@ -286,7 +286,7 @@ LL | v[N]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic. - --> $DIR/indexing_slicing.rs:90:5 + --> $DIR/indexing_slicing.rs:81:5 | LL | v[M]; | ^^^^ @@ -294,13 +294,13 @@ LL | v[M]; = help: Consider using `.get(n)` or `.get_mut(n)` instead error: range is out of bounds - --> $DIR/indexing_slicing.rs:94:13 + --> $DIR/indexing_slicing.rs:85:13 | LL | &x[num..10]; // should trigger out of bounds error | ^^ error: range is out of bounds - --> $DIR/indexing_slicing.rs:95:8 + --> $DIR/indexing_slicing.rs:86:8 | LL | &x[10..num]; // should trigger out of bounds error | ^^ diff --git a/tests/ui/infallible_destructuring_match.rs b/tests/ui/infallible_destructuring_match.rs index 37ae19497d1..a34b06d5642 100644 --- a/tests/ui/infallible_destructuring_match.rs +++ b/tests/ui/infallible_destructuring_match.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(exhaustive_patterns, never_type)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/infallible_destructuring_match.stderr b/tests/ui/infallible_destructuring_match.stderr index 976957d35d7..b2b37b9bff7 100644 --- a/tests/ui/infallible_destructuring_match.stderr +++ b/tests/ui/infallible_destructuring_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:25:5 + --> $DIR/infallible_destructuring_match.rs:16:5 | LL | / let data = match wrapper { LL | | SingleVariantEnum::Variant(i) => i, @@ -9,7 +9,7 @@ LL | | }; = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings` error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:46:5 + --> $DIR/infallible_destructuring_match.rs:37:5 | LL | / let data = match wrapper { LL | | TupleStruct(i) => i, @@ -17,7 +17,7 @@ LL | | }; | |______^ help: try this: `let TupleStruct(data) = wrapper;` error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let` - --> $DIR/infallible_destructuring_match.rs:67:5 + --> $DIR/infallible_destructuring_match.rs:58:5 | LL | / let data = match wrapper { LL | | Ok(i) => i, diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index bd266368dc4..c324eb95777 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::iter::repeat; #[allow(clippy::trivially_copy_pass_by_ref)] fn square_is_lower_64(x: &u32) -> bool { diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index 288285d9aae..564c2b43778 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,5 +1,5 @@ error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/infinite_iter.rs:19:5 + --> $DIR/infinite_iter.rs:10:5 | LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,31 +7,31 @@ LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter = note: `-D clippy::unused-collect` implied by `-D warnings` error: infinite iteration detected - --> $DIR/infinite_iter.rs:19:5 + --> $DIR/infinite_iter.rs:10:5 | LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/infinite_iter.rs:17:8 + --> $DIR/infinite_iter.rs:8:8 | LL | #[deny(clippy::infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:20:5 + --> $DIR/infinite_iter.rs:11:5 | LL | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:21:5 + --> $DIR/infinite_iter.rs:12:5 | LL | (0..8_u64).chain(0..).max(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:26:5 + --> $DIR/infinite_iter.rs:17:5 | LL | / (0..8_u32) LL | | .rev() @@ -41,37 +41,37 @@ LL | | .for_each(|x| println!("{}", x)); // infinite iter | |________________________________________^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:32:5 + --> $DIR/infinite_iter.rs:23:5 | LL | (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:33:5 + --> $DIR/infinite_iter.rs:24:5 | LL | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:40:5 + --> $DIR/infinite_iter.rs:31:5 | LL | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/infinite_iter.rs:38:8 + --> $DIR/infinite_iter.rs:29:8 | LL | #[deny(clippy::maybe_infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:41:5 + --> $DIR/infinite_iter.rs:32:5 | LL | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:42:5 + --> $DIR/infinite_iter.rs:33:5 | LL | / (1..) LL | | .scan(0, |state, x| { @@ -82,31 +82,31 @@ LL | | .min(); // maybe infinite iter | |______________^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:48:5 + --> $DIR/infinite_iter.rs:39:5 | LL | (0..).find(|x| *x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:49:5 + --> $DIR/infinite_iter.rs:40:5 | LL | (0..).position(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:50:5 + --> $DIR/infinite_iter.rs:41:5 | LL | (0..).any(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:51:5 + --> $DIR/infinite_iter.rs:42:5 | LL | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:74:31 + --> $DIR/infinite_iter.rs:65:31 | LL | let _: HashSet<i32> = (0..).collect(); // Infinite iter | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index f9310321593..4df218aa4f3 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::trivially_copy_pass_by_ref)] fn fn_val(i: i32) -> i32 { diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 79efb18a83e..a3fc591c1b1 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:32:11 + --> $DIR/infinite_loop.rs:23:11 | LL | while y < 10 { | ^^^^^^ @@ -7,49 +7,49 @@ LL | while y < 10 { = note: #[deny(clippy::while_immutable_condition)] on by default error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:37:11 + --> $DIR/infinite_loop.rs:28:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:44:11 + --> $DIR/infinite_loop.rs:35:11 | LL | while !cond { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:88:11 + --> $DIR/infinite_loop.rs:79:11 | LL | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:93:11 + --> $DIR/infinite_loop.rs:84:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:97:11 + --> $DIR/infinite_loop.rs:88:11 | LL | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:112:11 + --> $DIR/infinite_loop.rs:103:11 | LL | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:117:11 + --> $DIR/infinite_loop.rs:108:11 | LL | while i < 3 { | ^^^^^ error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop. - --> $DIR/infinite_loop.rs:183:15 + --> $DIR/infinite_loop.rs:174:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs index d97e6d69941..af81feaa374 100644 --- a/tests/ui/inline_fn_without_body.rs +++ b/tests/ui/inline_fn_without_body.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/tests/ui/inline_fn_without_body.stderr b/tests/ui/inline_fn_without_body.stderr index 3c2b086968e..87d2da71280 100644 --- a/tests/ui/inline_fn_without_body.stderr +++ b/tests/ui/inline_fn_without_body.stderr @@ -1,5 +1,5 @@ error: use of `#[inline]` on trait method `default_inline` which has no body - --> $DIR/inline_fn_without_body.rs:14:5 + --> $DIR/inline_fn_without_body.rs:5:5 | LL | #[inline] | _____-^^^^^^^^ @@ -9,7 +9,7 @@ LL | | fn default_inline(); = note: `-D clippy::inline-fn-without-body` implied by `-D warnings` error: use of `#[inline]` on trait method `always_inline` which has no body - --> $DIR/inline_fn_without_body.rs:17:5 + --> $DIR/inline_fn_without_body.rs:8:5 | LL | #[inline(always)] | _____-^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | | fn always_inline(); | |____- help: remove error: use of `#[inline]` on trait method `never_inline` which has no body - --> $DIR/inline_fn_without_body.rs:20:5 + --> $DIR/inline_fn_without_body.rs:11:5 | LL | #[inline(never)] | _____-^^^^^^^^^^^^^^^ diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index ce6cd7888ee..42d8045244f 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] fn main() { diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 30bc2966619..4a783e50c67 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,5 +1,5 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:16:5 + --> $DIR/int_plus_one.rs:7:5 | LL | x >= y + 1; | ^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | x > y; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:17:5 + --> $DIR/int_plus_one.rs:8:5 | LL | y + 1 <= x; | ^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | y < x; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:19:5 + --> $DIR/int_plus_one.rs:10:5 | LL | x - 1 >= y; | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | x > y; | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` - --> $DIR/int_plus_one.rs:20:5 + --> $DIR/int_plus_one.rs:11:5 | LL | y <= x - 1; | ^^^^^^^^^^ diff --git a/tests/ui/invalid_ref.rs b/tests/ui/invalid_ref.rs index 0ec356280b6..4f04c5467d3 100644 --- a/tests/ui/invalid_ref.rs +++ b/tests/ui/invalid_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] #![feature(core_intrinsics)] diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index f4386362099..9966c347f6e 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,5 +1,5 @@ error: reference to zeroed memory - --> $DIR/invalid_ref.rs:33:24 + --> $DIR/invalid_ref.rs:24:24 | LL | let ref_zero: &T = std::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let ref_zero: &T = std::mem::zeroed(); // warning = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:37:24 + --> $DIR/invalid_ref.rs:28:24 | LL | let ref_zero: &T = core::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let ref_zero: &T = core::mem::zeroed(); // warning = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:41:24 + --> $DIR/invalid_ref.rs:32:24 | LL | let ref_zero: &T = std::intrinsics::init(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let ref_zero: &T = std::intrinsics::init(); // warning = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:45:26 + --> $DIR/invalid_ref.rs:36:26 | LL | let ref_uninit: &T = std::mem::uninitialized(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let ref_uninit: &T = std::mem::uninitialized(); // warning = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:49:26 + --> $DIR/invalid_ref.rs:40:26 | LL | let ref_uninit: &T = core::mem::uninitialized(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let ref_uninit: &T = core::mem::uninitialized(); // warning = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:53:26 + --> $DIR/invalid_ref.rs:44:26 | LL | let ref_uninit: &T = std::intrinsics::uninit(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/invalid_upcast_comparisons.rs b/tests/ui/invalid_upcast_comparisons.rs index 60f877b1ebe..697416dcee8 100644 --- a/tests/ui/invalid_upcast_comparisons.rs +++ b/tests/ui/invalid_upcast_comparisons.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::invalid_upcast_comparisons)] #![allow( unused, diff --git a/tests/ui/invalid_upcast_comparisons.stderr b/tests/ui/invalid_upcast_comparisons.stderr index 4bf92088337..03c3fb80aaa 100644 --- a/tests/ui/invalid_upcast_comparisons.stderr +++ b/tests/ui/invalid_upcast_comparisons.stderr @@ -1,5 +1,5 @@ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:30:5 + --> $DIR/invalid_upcast_comparisons.rs:21:5 | LL | (u8 as u32) > 300; | ^^^^^^^^^^^^^^^^^ @@ -7,157 +7,157 @@ LL | (u8 as u32) > 300; = note: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings` error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:31:5 + --> $DIR/invalid_upcast_comparisons.rs:22:5 | LL | (u8 as i32) > 300; | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:32:5 + --> $DIR/invalid_upcast_comparisons.rs:23:5 | LL | (u8 as u32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:33:5 + --> $DIR/invalid_upcast_comparisons.rs:24:5 | LL | (u8 as i32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:34:5 + --> $DIR/invalid_upcast_comparisons.rs:25:5 | LL | 300 < (u8 as u32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:35:5 + --> $DIR/invalid_upcast_comparisons.rs:26:5 | LL | 300 < (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:36:5 + --> $DIR/invalid_upcast_comparisons.rs:27:5 | LL | 300 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:37:5 + --> $DIR/invalid_upcast_comparisons.rs:28:5 | LL | 300 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:39:5 + --> $DIR/invalid_upcast_comparisons.rs:30:5 | LL | (u8 as u32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:40:5 + --> $DIR/invalid_upcast_comparisons.rs:31:5 | LL | (u8 as i32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:41:5 + --> $DIR/invalid_upcast_comparisons.rs:32:5 | LL | (u8 as u32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:42:5 + --> $DIR/invalid_upcast_comparisons.rs:33:5 | LL | (u8 as i32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:43:5 + --> $DIR/invalid_upcast_comparisons.rs:34:5 | LL | 300 >= (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:44:5 + --> $DIR/invalid_upcast_comparisons.rs:35:5 | LL | 300 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:45:5 + --> $DIR/invalid_upcast_comparisons.rs:36:5 | LL | 300 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:46:5 + --> $DIR/invalid_upcast_comparisons.rs:37:5 | LL | 300 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:49:5 + --> $DIR/invalid_upcast_comparisons.rs:40:5 | LL | (u8 as i32) < 0; | ^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:50:5 + --> $DIR/invalid_upcast_comparisons.rs:41:5 | LL | -5 != (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:52:5 + --> $DIR/invalid_upcast_comparisons.rs:43:5 | LL | (u8 as i32) >= 0; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:53:5 + --> $DIR/invalid_upcast_comparisons.rs:44:5 | LL | -5 == (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:56:5 + --> $DIR/invalid_upcast_comparisons.rs:47:5 | LL | 1337 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:57:5 + --> $DIR/invalid_upcast_comparisons.rs:48:5 | LL | 1337 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:59:5 + --> $DIR/invalid_upcast_comparisons.rs:50:5 | LL | 1337 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:60:5 + --> $DIR/invalid_upcast_comparisons.rs:51:5 | LL | 1337 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> $DIR/invalid_upcast_comparisons.rs:74:5 + --> $DIR/invalid_upcast_comparisons.rs:65:5 | LL | (u8 as i32) > -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:75:5 + --> $DIR/invalid_upcast_comparisons.rs:66:5 | LL | (u8 as i32) < -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> $DIR/invalid_upcast_comparisons.rs:91:5 + --> $DIR/invalid_upcast_comparisons.rs:82:5 | LL | -5 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/issue-3145.rs b/tests/ui/issue-3145.rs index 5c6392811b9..f497d5550af 100644 --- a/tests/ui/issue-3145.rs +++ b/tests/ui/issue-3145.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { println!("{}" a); //~ERROR expected token: `,` } diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr index c7a995c61d6..f3984f991a4 100644 --- a/tests/ui/issue-3145.stderr +++ b/tests/ui/issue-3145.stderr @@ -1,5 +1,5 @@ error: expected token: `,` - --> $DIR/issue-3145.rs:11:19 + --> $DIR/issue-3145.rs:2:19 | LL | println!("{}" a); //~ERROR expected token: `,` | ^ diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index a54da0b6a96..da580a1839a 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::while_let_on_iterator)] use std::iter::Iterator; diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr index 37599900312..d7125901335 100644 --- a/tests/ui/issue_2356.stderr +++ b/tests/ui/issue_2356.stderr @@ -1,11 +1,11 @@ error: this loop could be written as a `for` loop - --> $DIR/issue_2356.rs:24:29 + --> $DIR/issue_2356.rs:15:29 | LL | while let Some(e) = it.next() { | ^^^^^^^^^ help: try: `for e in it { .. }` | note: lint level defined here - --> $DIR/issue_2356.rs:10:9 + --> $DIR/issue_2356.rs:1:9 | LL | #![deny(clippy::while_let_on_iterator)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index fca19350558..c17a7cbc8d9 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::items_after_statements)] fn ok() { diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index 3024431244c..f8f010b5e5c 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -1,5 +1,5 @@ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:21:5 + --> $DIR/item_after_statement.rs:12:5 | LL | / fn foo() { LL | | println!("foo"); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::items-after-statements` implied by `-D warnings` error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:28:5 + --> $DIR/item_after_statement.rs:19:5 | LL | / fn foo() { LL | | println!("foo"); diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 0b9d2c36827..a65ca3bbb13 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index 037c33fbc3d..6948bd27679 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,5 +1,5 @@ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/iter_skip_next.rs:22:13 + --> $DIR/iter_skip_next.rs:13:13 | LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | let _ = some_vec.iter().skip(42).next(); = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/iter_skip_next.rs:23:13 + --> $DIR/iter_skip_next.rs:14:13 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/iter_skip_next.rs:24:13 + --> $DIR/iter_skip_next.rs:15:13 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^^^^^^^^ error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)` - --> $DIR/iter_skip_next.rs:25:14 + --> $DIR/iter_skip_next.rs:16:14 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index 80153efcb93..76c3414bb02 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::large_digit_groups)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/large_digit_groups.stderr b/tests/ui/large_digit_groups.stderr index 3f88aefda33..45aef91069b 100644 --- a/tests/ui/large_digit_groups.stderr +++ b/tests/ui/large_digit_groups.stderr @@ -1,5 +1,5 @@ error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:24:9 + --> $DIR/large_digit_groups.rs:15:9 | LL | 0b1_10110_i64, | ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64` @@ -7,31 +7,31 @@ LL | 0b1_10110_i64, = note: `-D clippy::large-digit-groups` implied by `-D warnings` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:25:9 + --> $DIR/large_digit_groups.rs:16:9 | LL | 0x1_23456_78901_usize, | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:26:9 + --> $DIR/large_digit_groups.rs:17:9 | LL | 1_23456_f32, | ^^^^^^^^^^^ help: consider: `123_456_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:27:9 + --> $DIR/large_digit_groups.rs:18:9 | LL | 1_23456.12_f32, | ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:28:9 + --> $DIR/large_digit_groups.rs:19:9 | LL | 1_23456.12345_f32, | ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f32` error: digit groups should be smaller - --> $DIR/large_digit_groups.rs:29:9 + --> $DIR/large_digit_groups.rs:20:9 | LL | 1_23456.12345_6_f32, | ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f32` diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 29a73e68d43..852ef5fec0e 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] #![allow(unused_variables)] #![warn(clippy::large_enum_variant)] diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index 839d16bd9a2..b13812612cb 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -1,5 +1,5 @@ error: large size difference between variants - --> $DIR/large_enum_variant.rs:16:5 + --> $DIR/large_enum_variant.rs:7:5 | LL | B([i32; 8000]), | ^^^^^^^^^^^^^^ @@ -11,19 +11,19 @@ LL | B(Box<[i32; 8000]>), | ^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:27:5 + --> $DIR/large_enum_variant.rs:18:5 | LL | C(T, [i32; 8000]), | ^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:27:5 + --> $DIR/large_enum_variant.rs:18:5 | LL | C(T, [i32; 8000]), | ^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:40:5 + --> $DIR/large_enum_variant.rs:31:5 | LL | ContainingLargeEnum(LargeEnum), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,31 +33,31 @@ LL | ContainingLargeEnum(Box<LargeEnum>), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:43:5 + --> $DIR/large_enum_variant.rs:34:5 | LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:43:5 + --> $DIR/large_enum_variant.rs:34:5 | LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:50:5 + --> $DIR/large_enum_variant.rs:41:5 | LL | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:50:5 + --> $DIR/large_enum_variant.rs:41:5 | LL | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:55:5 + --> $DIR/large_enum_variant.rs:46:5 | LL | StructLikeLarge2 { x: [i32; 8000] }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 7f4ba4f1523..05b863f3edc 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::len_without_is_empty, clippy::len_zero)] #![allow(dead_code, unused)] diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index f5f19e128b7..a8b2e2e4097 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -1,5 +1,5 @@ error: item `PubOne` has a public `len` method but no corresponding `is_empty` method - --> $DIR/len_zero.rs:15:1 + --> $DIR/len_zero.rs:6:1 | LL | / impl PubOne { LL | | pub fn len(self: &Self) -> isize { @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::len-without-is-empty` implied by `-D warnings` error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_zero.rs:64:1 + --> $DIR/len_zero.rs:55:1 | LL | / pub trait PubTraitsToo { LL | | fn len(self: &Self) -> isize; @@ -19,7 +19,7 @@ LL | | } | |_^ error: item `HasIsEmpty` has a public `len` method but a private `is_empty` method - --> $DIR/len_zero.rs:98:1 + --> $DIR/len_zero.rs:89:1 | LL | / impl HasIsEmpty { LL | | pub fn len(self: &Self) -> isize { @@ -31,7 +31,7 @@ LL | | } | |_^ error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty` method - --> $DIR/len_zero.rs:127:1 + --> $DIR/len_zero.rs:118:1 | LL | / impl HasWrongIsEmpty { LL | | pub fn len(self: &Self) -> isize { @@ -43,7 +43,7 @@ LL | | } | |_^ error: length comparison to zero - --> $DIR/len_zero.rs:148:8 + --> $DIR/len_zero.rs:139:8 | LL | if x.len() == 0 { | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()` @@ -51,85 +51,85 @@ LL | if x.len() == 0 { = note: `-D clippy::len-zero` implied by `-D warnings` error: length comparison to zero - --> $DIR/len_zero.rs:152:8 + --> $DIR/len_zero.rs:143:8 | LL | if "".len() == 0 {} | ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:167:8 + --> $DIR/len_zero.rs:158:8 | LL | if has_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:170:8 + --> $DIR/len_zero.rs:161:8 | LL | if has_is_empty.len() != 0 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:173:8 + --> $DIR/len_zero.rs:164:8 | LL | if has_is_empty.len() > 0 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:176:8 + --> $DIR/len_zero.rs:167:8 | LL | if has_is_empty.len() < 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:179:8 + --> $DIR/len_zero.rs:170:8 | LL | if has_is_empty.len() >= 1 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:190:8 + --> $DIR/len_zero.rs:181:8 | LL | if 0 == has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:193:8 + --> $DIR/len_zero.rs:184:8 | LL | if 0 != has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:196:8 + --> $DIR/len_zero.rs:187:8 | LL | if 0 < has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:199:8 + --> $DIR/len_zero.rs:190:8 | LL | if 1 <= has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> $DIR/len_zero.rs:202:8 + --> $DIR/len_zero.rs:193:8 | LL | if 1 > has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:216:8 + --> $DIR/len_zero.rs:207:8 | LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:229:8 + --> $DIR/len_zero.rs:220:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!b.is_empty()` error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_zero.rs:235:1 + --> $DIR/len_zero.rs:226:1 | LL | / pub trait DependsOnFoo: Foo { LL | | fn len(&mut self) -> usize; diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 26fdc46ac17..5bfa32dd56c 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( unused_variables, unused_assignments, diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index 7883a713c05..c53a63a541b 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -1,5 +1,5 @@ error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:72:5 + --> $DIR/let_if_seq.rs:63:5 | LL | / let mut foo = 0; LL | | if f() { @@ -11,7 +11,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:77:5 + --> $DIR/let_if_seq.rs:68:5 | LL | / let mut bar = 0; LL | | if f() { @@ -25,7 +25,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:85:5 + --> $DIR/let_if_seq.rs:76:5 | LL | / let quz; LL | | if f() { @@ -36,7 +36,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> $DIR/let_if_seq.rs:114:5 + --> $DIR/let_if_seq.rs:105:5 | LL | / let mut baz = 0; LL | | if f() { diff --git a/tests/ui/let_return.rs b/tests/ui/let_return.rs index eb012133376..d2e46621f9f 100644 --- a/tests/ui/let_return.rs +++ b/tests/ui/let_return.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] #![warn(clippy::let_and_return)] diff --git a/tests/ui/let_return.stderr b/tests/ui/let_return.stderr index c53d5cfb886..69c4720c9b3 100644 --- a/tests/ui/let_return.stderr +++ b/tests/ui/let_return.stderr @@ -1,24 +1,24 @@ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/let_return.rs:16:5 + --> $DIR/let_return.rs:7:5 | LL | x | ^ | = note: `-D clippy::let-and-return` implied by `-D warnings` note: this expression can be directly returned - --> $DIR/let_return.rs:15:13 + --> $DIR/let_return.rs:6:13 | LL | let x = 5; | ^ error: returning the result of a let binding from a block. Consider returning the expression directly. - --> $DIR/let_return.rs:22:9 + --> $DIR/let_return.rs:13:9 | LL | x | ^ | note: this expression can be directly returned - --> $DIR/let_return.rs:21:17 + --> $DIR/let_return.rs:12:17 | LL | let x = 5; | ^ diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 89cb190cc96..dc17c98f6a8 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::let_unit_value)] #![allow(unused_variables)] diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index 8929844180a..e1773a40225 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -1,5 +1,5 @@ error: this let-binding has unit value. Consider omitting `let _x =` - --> $DIR/let_unit.rs:20:5 + --> $DIR/let_unit.rs:11:5 | LL | let _x = println!("x"); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _x = println!("x"); = note: `-D clippy::let-unit-value` implied by `-D warnings` error: this let-binding has unit value. Consider omitting `let _a =` - --> $DIR/let_unit.rs:24:9 + --> $DIR/let_unit.rs:15:9 | LL | let _a = (); | ^^^^^^^^^^^^ diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index 110868404bd..46c8e1740a9 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::needless_lifetimes, clippy::extra_unused_lifetimes)] #![allow(dead_code, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/lifetimes.stderr b/tests/ui/lifetimes.stderr index abd11907b6d..18b8440089c 100644 --- a/tests/ui/lifetimes.stderr +++ b/tests/ui/lifetimes.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:13:1 + --> $DIR/lifetimes.rs:4:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:15:1 + --> $DIR/lifetimes.rs:6:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:23:1 + --> $DIR/lifetimes.rs:14:1 | LL | / fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { LL | | x @@ -21,7 +21,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:47:1 + --> $DIR/lifetimes.rs:38:1 | LL | / fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { LL | | Ok(x) @@ -29,7 +29,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:52:1 + --> $DIR/lifetimes.rs:43:1 | LL | / fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> LL | | where @@ -40,13 +40,13 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:63:1 + --> $DIR/lifetimes.rs:54:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:84:1 + --> $DIR/lifetimes.rs:75:1 | LL | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> LL | | where @@ -57,7 +57,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:117:5 + --> $DIR/lifetimes.rs:108:5 | LL | / fn self_and_out<'s>(&'s self) -> &'s u8 { LL | | &self.x @@ -65,13 +65,13 @@ LL | | } | |_____^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:125:5 + --> $DIR/lifetimes.rs:116:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:141:1 + --> $DIR/lifetimes.rs:132:1 | LL | / fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { LL | | unimplemented!() @@ -79,7 +79,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:171:1 + --> $DIR/lifetimes.rs:162:1 | LL | / fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { LL | | unimplemented!() @@ -87,7 +87,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:177:1 + --> $DIR/lifetimes.rs:168:1 | LL | / fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { LL | | unimplemented!() @@ -95,7 +95,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:196:1 + --> $DIR/lifetimes.rs:187:1 | LL | / fn named_input_elided_output<'a>(_arg: &'a str) -> &str { LL | | unimplemented!() @@ -103,7 +103,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:204:1 + --> $DIR/lifetimes.rs:195:1 | LL | / fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { LL | | unimplemented!() @@ -111,7 +111,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/lifetimes.rs:241:1 + --> $DIR/lifetimes.rs:232:1 | LL | / fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { LL | | unimplemented!() diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index 90e9a69a994..ef86b5240eb 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::large_digit_groups)] #![warn(clippy::mixed_case_hex_literals)] #![warn(clippy::unseparated_literal_suffix)] diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 6ceb25fd612..2a461dba457 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -1,5 +1,5 @@ error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:22:17 + --> $DIR/literals.rs:13:17 | LL | let fail1 = 0xabCD; | ^^^^^^ @@ -7,19 +7,19 @@ LL | let fail1 = 0xabCD; = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:23:17 + --> $DIR/literals.rs:14:17 | LL | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:24:17 + --> $DIR/literals.rs:15:17 | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:25:27 + --> $DIR/literals.rs:16:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | let fail_multi_zero = 000_123usize; = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` error: this is a decimal constant - --> $DIR/literals.rs:25:27 + --> $DIR/literals.rs:16:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -43,37 +43,37 @@ LL | let fail_multi_zero = 0o123usize; | ^^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:30:17 + --> $DIR/literals.rs:21:17 | LL | let fail3 = 1234i32; | ^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:31:17 + --> $DIR/literals.rs:22:17 | LL | let fail4 = 1234u32; | ^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:32:17 + --> $DIR/literals.rs:23:17 | LL | let fail5 = 1234isize; | ^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:33:17 + --> $DIR/literals.rs:24:17 | LL | let fail6 = 1234usize; | ^^^^^^^^^ error: float type suffix should be separated by an underscore - --> $DIR/literals.rs:34:17 + --> $DIR/literals.rs:25:17 | LL | let fail7 = 1.5f32; | ^^^^^^ error: this is a decimal constant - --> $DIR/literals.rs:38:17 + --> $DIR/literals.rs:29:17 | LL | let fail8 = 0123; | ^^^^ @@ -87,7 +87,7 @@ LL | let fail8 = 0o123; | ^^^^^ error: long literal lacking separators - --> $DIR/literals.rs:49:17 + --> $DIR/literals.rs:40:17 | LL | let fail9 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` @@ -95,25 +95,25 @@ LL | let fail9 = 0xabcdef; = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/literals.rs:50:18 + --> $DIR/literals.rs:41:18 | LL | let fail10 = 0xBAFEBAFE; | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> $DIR/literals.rs:51:18 + --> $DIR/literals.rs:42:18 | LL | let fail11 = 0xabcdeff; | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> $DIR/literals.rs:52:18 + --> $DIR/literals.rs:43:18 | LL | let fail12 = 0xabcabcabcabcabcabc; | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` error: digit groups should be smaller - --> $DIR/literals.rs:53:18 + --> $DIR/literals.rs:44:18 | LL | let fail13 = 0x1_23456_78901_usize; | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` @@ -121,7 +121,7 @@ LL | let fail13 = 0x1_23456_78901_usize; = note: `-D clippy::large-digit-groups` implied by `-D warnings` error: mistyped literal suffix - --> $DIR/literals.rs:55:18 + --> $DIR/literals.rs:46:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` @@ -129,25 +129,25 @@ LL | let fail14 = 2_32; = note: #[deny(clippy::mistyped_literal_suffixes)] on by default error: mistyped literal suffix - --> $DIR/literals.rs:56:18 + --> $DIR/literals.rs:47:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/literals.rs:57:18 + --> $DIR/literals.rs:48:18 | LL | let fail16 = 7_8; | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/literals.rs:58:18 + --> $DIR/literals.rs:49:18 | LL | let fail17 = 23_16; | ^^^^^ help: did you mean to write: `23_i16` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:60:18 + --> $DIR/literals.rs:51:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -155,61 +155,61 @@ LL | let fail19 = 12_3456_21; = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: mistyped literal suffix - --> $DIR/literals.rs:61:18 + --> $DIR/literals.rs:52:18 | LL | let fail20 = 2__8; | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/literals.rs:62:18 + --> $DIR/literals.rs:53:18 | LL | let fail21 = 4___16; | ^^^^^^ help: did you mean to write: `4_i16` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:63:18 + --> $DIR/literals.rs:54:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:64:18 + --> $DIR/literals.rs:55:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: mistyped literal suffix - --> $DIR/literals.rs:66:18 + --> $DIR/literals.rs:57:18 | LL | let fail24 = 12.34_64; | ^^^^^^^^ help: did you mean to write: `12.34_f64` error: mistyped literal suffix - --> $DIR/literals.rs:67:18 + --> $DIR/literals.rs:58:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> $DIR/literals.rs:68:18 + --> $DIR/literals.rs:59:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> $DIR/literals.rs:69:18 + --> $DIR/literals.rs:60:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> $DIR/literals.rs:70:18 + --> $DIR/literals.rs:61:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> $DIR/literals.rs:71:18 + --> $DIR/literals.rs:62:18 | LL | let fail29 = 42279.911_32; | ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32` diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index e6fb37f8120..a70cb2f6725 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 6253ae2150c..56b1f67bac9 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:14:22 + --> $DIR/map_clone.rs:5:22 | LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![5_i8; 6].iter().cloned()` @@ -7,13 +7,13 @@ LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); = note: `-D clippy::map-clone` implied by `-D warnings` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:15:26 + --> $DIR/map_clone.rs:6:26 | LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:16:23 + --> $DIR/map_clone.rs:7:23 | LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![42, 43].iter().cloned()` diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index 99b90a0df79..d0720c419c8 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index 931ef9b6248..822d27391f6 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` - --> $DIR/map_flatten.rs:14:21 + --> $DIR/map_flatten.rs:5:21 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using flat_map instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)` diff --git a/tests/ui/map_unit_fn.rs b/tests/ui/map_unit_fn.rs index 1d203a147ba..9a74da4e3b8 100644 --- a/tests/ui/map_unit_fn.rs +++ b/tests/ui/map_unit_fn.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] struct Mappable {} diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index fe5e94cf458..a7af8ce0108 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn match_bool() { let test: bool = true; diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index 78711c4ba4b..193e6c17238 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/match_bool.rs:38:11 + --> $DIR/match_bool.rs:29:11 | LL | match test && test { | ^^^^^^^^^^^^ help: try: `test` @@ -7,7 +7,7 @@ LL | match test && test { = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:13:5 + --> $DIR/match_bool.rs:4:5 | LL | / match test { LL | | true => 0, @@ -18,7 +18,7 @@ LL | | }; = note: `-D clippy::match-bool` implied by `-D warnings` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:19:5 + --> $DIR/match_bool.rs:10:5 | LL | / match option == 1 { LL | | true => 1, @@ -27,7 +27,7 @@ LL | | }; | |_____^ help: consider using an if/else expression: `if option == 1 { 1 } else { 0 }` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:24:5 + --> $DIR/match_bool.rs:15:5 | LL | / match test { LL | | true => (), @@ -44,7 +44,7 @@ LL | }; | error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:31:5 + --> $DIR/match_bool.rs:22:5 | LL | / match test { LL | | false => { @@ -61,7 +61,7 @@ LL | }; | error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:38:5 + --> $DIR/match_bool.rs:29:5 | LL | / match test && test { LL | | false => { @@ -78,7 +78,7 @@ LL | }; | error: equal expressions as operands to `&&` - --> $DIR/match_bool.rs:38:11 + --> $DIR/match_bool.rs:29:11 | LL | match test && test { | ^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL | match test && test { = note: #[deny(clippy::eq_op)] on by default error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:45:5 + --> $DIR/match_bool.rs:36:5 | LL | / match test { LL | | false => { diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 5350f933ae5..978ac5195d3 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(exclusive_range_pattern)] #![warn(clippy::match_overlapping_arm)] #![allow(clippy::redundant_pattern_matching)] diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index 3e978df842e..14eb378141b 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -1,60 +1,60 @@ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:20:9 + --> $DIR/match_overlapping_arm.rs:11:9 | LL | 0...10 => println!("0 ... 10"), | ^^^^^^ | = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` note: overlaps with this - --> $DIR/match_overlapping_arm.rs:21:9 + --> $DIR/match_overlapping_arm.rs:12:9 | LL | 0...11 => println!("0 ... 11"), | ^^^^^^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:26:9 + --> $DIR/match_overlapping_arm.rs:17:9 | LL | 0...5 => println!("0 ... 5"), | ^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:28:9 + --> $DIR/match_overlapping_arm.rs:19:9 | LL | FOO...11 => println!("0 ... 11"), | ^^^^^^^^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:34:9 + --> $DIR/match_overlapping_arm.rs:25:9 | LL | 0...5 => println!("0 ... 5"), | ^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:33:9 + --> $DIR/match_overlapping_arm.rs:24:9 | LL | 2 => println!("2"), | ^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:40:9 + --> $DIR/match_overlapping_arm.rs:31:9 | LL | 0...2 => println!("0 ... 2"), | ^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:39:9 + --> $DIR/match_overlapping_arm.rs:30:9 | LL | 2 => println!("2"), | ^ error: some ranges overlap - --> $DIR/match_overlapping_arm.rs:63:9 + --> $DIR/match_overlapping_arm.rs:54:9 | LL | 0..11 => println!("0 .. 11"), | ^^^^^ | note: overlaps with this - --> $DIR/match_overlapping_arm.rs:64:9 + --> $DIR/match_overlapping_arm.rs:55:9 | LL | 0...11 => println!("0 ... 11"), | ^^^^^^ diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index 8038433c564..013f12a1a0e 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(exclusive_range_pattern)] #![warn(clippy::all)] #![allow(unused, clippy::redundant_pattern_matching)] diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index 06ba6224855..a3714a69e6e 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:20:9 + --> $DIR/matches.rs:11:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ LL | None => println!("none"), | error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:31:5 + --> $DIR/matches.rs:22:5 | LL | / match tup { LL | | &(v, 1) => println!("{}", v), @@ -30,7 +30,7 @@ LL | (v, 1) => println!("{}", v), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/matches.rs:37:5 + --> $DIR/matches.rs:28:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -45,7 +45,7 @@ LL | None => println!("none"), | error: you don't need to add `&` to all patterns - --> $DIR/matches.rs:48:5 + --> $DIR/matches.rs:39:5 | LL | / if let &None = a { LL | | println!("none"); @@ -57,7 +57,7 @@ LL | if let None = *a { | ^^^^ ^^ error: you don't need to add `&` to both the expression and the patterns - --> $DIR/matches.rs:53:5 + --> $DIR/matches.rs:44:5 | LL | / if let &None = &b { LL | | println!("none"); @@ -69,7 +69,7 @@ LL | if let None = b { | ^^^^ ^ error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:64:9 + --> $DIR/matches.rs:55:9 | LL | Err(_) => panic!("err"), | ^^^^^^ @@ -78,26 +78,26 @@ LL | Err(_) => panic!("err"), = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:63:18 + --> $DIR/matches.rs:54:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | = note: `-D clippy::match-same-arms` implied by `-D warnings` note: same as this - --> $DIR/matches.rs:62:18 + --> $DIR/matches.rs:53:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:62:18 + --> $DIR/matches.rs:53:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:70:9 + --> $DIR/matches.rs:61:9 | LL | Err(_) => panic!(), | ^^^^^^ @@ -105,25 +105,25 @@ LL | Err(_) => panic!(), = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:69:18 + --> $DIR/matches.rs:60:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:68:18 + --> $DIR/matches.rs:59:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:68:18 + --> $DIR/matches.rs:59:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: Err(_) will match all errors, maybe not a good idea - --> $DIR/matches.rs:76:9 + --> $DIR/matches.rs:67:9 | LL | Err(_) => { | ^^^^^^ @@ -131,133 +131,133 @@ LL | Err(_) => { = note: to remove this warning, match each error separately or use unreachable macro error: this `match` has identical arm bodies - --> $DIR/matches.rs:75:18 + --> $DIR/matches.rs:66:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:74:18 + --> $DIR/matches.rs:65:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:74:18 + --> $DIR/matches.rs:65:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:84:18 + --> $DIR/matches.rs:75:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:83:18 + --> $DIR/matches.rs:74:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:83:18 + --> $DIR/matches.rs:74:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:91:18 + --> $DIR/matches.rs:82:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:90:18 + --> $DIR/matches.rs:81:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:90:18 + --> $DIR/matches.rs:81:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:97:18 + --> $DIR/matches.rs:88:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:96:18 + --> $DIR/matches.rs:87:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:96:18 + --> $DIR/matches.rs:87:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:103:18 + --> $DIR/matches.rs:94:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:102:18 + --> $DIR/matches.rs:93:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:102:18 + --> $DIR/matches.rs:93:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:126:29 + --> $DIR/matches.rs:117:29 | LL | (Ok(_), Some(x)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:125:29 + --> $DIR/matches.rs:116:29 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ note: consider refactoring into `(Ok(x), Some(_)) | (Ok(_), Some(x))` - --> $DIR/matches.rs:125:29 + --> $DIR/matches.rs:116:29 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: this `match` has identical arm bodies - --> $DIR/matches.rs:141:18 + --> $DIR/matches.rs:132:18 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^ | note: same as this - --> $DIR/matches.rs:140:18 + --> $DIR/matches.rs:131:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ note: consider refactoring into `Ok(3) | Ok(_)` - --> $DIR/matches.rs:140:18 + --> $DIR/matches.rs:131:18 | LL | Ok(3) => println!("ok"), | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: use as_ref() instead - --> $DIR/matches.rs:150:33 + --> $DIR/matches.rs:141:33 | LL | let borrowed: Option<&()> = match owned { | _________________________________^ @@ -269,7 +269,7 @@ LL | | }; = note: `-D clippy::match-as-ref` implied by `-D warnings` error: use as_mut() instead - --> $DIR/matches.rs:156:39 + --> $DIR/matches.rs:147:39 | LL | let borrow_mut: Option<&mut ()> = match mut_owned { | _______________________________________^ diff --git a/tests/ui/mem_discriminant.rs b/tests/ui/mem_discriminant.rs index 9d2d6f9503a..81f1628861e 100644 --- a/tests/ui/mem_discriminant.rs +++ b/tests/ui/mem_discriminant.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::mem_discriminant_non_enum)] use std::mem; diff --git a/tests/ui/mem_discriminant.stderr b/tests/ui/mem_discriminant.stderr index c445b96a90f..295545406ed 100644 --- a/tests/ui/mem_discriminant.stderr +++ b/tests/ui/mem_discriminant.stderr @@ -1,17 +1,17 @@ error: calling `mem::discriminant` on non-enum type `&str` - --> $DIR/mem_discriminant.rs:23:5 + --> $DIR/mem_discriminant.rs:14:5 | LL | mem::discriminant(&"hello"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/mem_discriminant.rs:10:9 + --> $DIR/mem_discriminant.rs:1:9 | LL | #![deny(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:24:5 + --> $DIR/mem_discriminant.rs:15:5 | LL | mem::discriminant(&&Some(2)); | ^^^^^^^^^^^^^^^^^^---------^ @@ -19,7 +19,7 @@ LL | mem::discriminant(&&Some(2)); | help: try dereferencing: `&Some(2)` error: calling `mem::discriminant` on non-enum type `&std::option::Option<u8>` - --> $DIR/mem_discriminant.rs:25:5 + --> $DIR/mem_discriminant.rs:16:5 | LL | mem::discriminant(&&None::<u8>); | ^^^^^^^^^^^^^^^^^^------------^ @@ -27,7 +27,7 @@ LL | mem::discriminant(&&None::<u8>); | help: try dereferencing: `&None::<u8>` error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:26:5 + --> $DIR/mem_discriminant.rs:17:5 | LL | mem::discriminant(&&Foo::One(5)); | ^^^^^^^^^^^^^^^^^^-------------^ @@ -35,7 +35,7 @@ LL | mem::discriminant(&&Foo::One(5)); | help: try dereferencing: `&Foo::One(5)` error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:27:5 + --> $DIR/mem_discriminant.rs:18:5 | LL | mem::discriminant(&&Foo::Two(5)); | ^^^^^^^^^^^^^^^^^^-------------^ @@ -43,13 +43,13 @@ LL | mem::discriminant(&&Foo::Two(5)); | help: try dereferencing: `&Foo::Two(5)` error: calling `mem::discriminant` on non-enum type `A` - --> $DIR/mem_discriminant.rs:28:5 + --> $DIR/mem_discriminant.rs:19:5 | LL | mem::discriminant(&A(Foo::One(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:32:5 + --> $DIR/mem_discriminant.rs:23:5 | LL | mem::discriminant(&ro); | ^^^^^^^^^^^^^^^^^^---^ @@ -57,7 +57,7 @@ LL | mem::discriminant(&ro); | help: try dereferencing: `ro` error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:33:5 + --> $DIR/mem_discriminant.rs:24:5 | LL | mem::discriminant(rro); | ^^^^^^^^^^^^^^^^^^---^ @@ -65,7 +65,7 @@ LL | mem::discriminant(rro); | help: try dereferencing: `*rro` error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:34:5 + --> $DIR/mem_discriminant.rs:25:5 | LL | mem::discriminant(&rro); | ^^^^^^^^^^^^^^^^^^----^ @@ -73,7 +73,7 @@ LL | mem::discriminant(&rro); | help: try dereferencing: `*rro` error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:38:13 + --> $DIR/mem_discriminant.rs:29:13 | LL | mem::discriminant($param) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | mem_discriminant_but_in_a_macro!(&rro); | in this macro invocation error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:45:5 + --> $DIR/mem_discriminant.rs:36:5 | LL | mem::discriminant(&rrrrro); | ^^^^^^^^^^^^^^^^^^-------^ @@ -93,7 +93,7 @@ LL | mem::discriminant(&rrrrro); | help: try dereferencing: `****rrrrro` error: calling `mem::discriminant` on non-enum type `&&&std::option::Option<i32>` - --> $DIR/mem_discriminant.rs:46:5 + --> $DIR/mem_discriminant.rs:37:5 | LL | mem::discriminant(*rrrrro); | ^^^^^^^^^^^^^^^^^^-------^ diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index b46f7007cd0..e5b35c098a2 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/mem_forget.stderr b/tests/ui/mem_forget.stderr index 292437d0019..16b95a1038a 100644 --- a/tests/ui/mem_forget.stderr +++ b/tests/ui/mem_forget.stderr @@ -1,5 +1,5 @@ error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:23:5 + --> $DIR/mem_forget.rs:14:5 | LL | memstuff::forget(six); | ^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | memstuff::forget(six); = note: `-D clippy::mem-forget` implied by `-D warnings` error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:26:5 + --> $DIR/mem_forget.rs:17:5 | LL | std::mem::forget(seven); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of mem::forget on Drop type - --> $DIR/mem_forget.rs:29:5 + --> $DIR/mem_forget.rs:20:5 | LL | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index edd3c031857..a0c340bb54b 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2019 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index fa99205d69a..6340d784d74 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // aux-build:option_helpers.rs #![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index ef3a4e2a423..99a0c0d59d1 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:44:5 + --> $DIR/methods.rs:35:5 | LL | pub fn add(self, other: T) -> T { self } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pub fn add(self, other: T) -> T { self } = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/methods.rs:55:17 + --> $DIR/methods.rs:46:17 | LL | fn into_u16(&self) -> u16 { 0 } | ^^^^^ @@ -15,19 +15,19 @@ LL | fn into_u16(&self) -> u16 { 0 } = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/methods.rs:57:21 + --> $DIR/methods.rs:48:21 | LL | fn to_something(self) -> u32 { 0 } | ^^^^ error: methods called `new` usually take no self; consider choosing a less ambiguous name - --> $DIR/methods.rs:59:12 + --> $DIR/methods.rs:50:12 | LL | fn new(self) -> Self { unimplemented!(); } | ^^^^ error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:120:13 + --> $DIR/methods.rs:111:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -39,7 +39,7 @@ LL | | .unwrap_or(0); // should lint even though this call is on = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:124:13 + --> $DIR/methods.rs:115:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -49,7 +49,7 @@ LL | | ).unwrap_or(0); | |____________________________^ error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:128:13 + --> $DIR/methods.rs:119:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -59,7 +59,7 @@ LL | | }); | |__________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:133:13 + --> $DIR/methods.rs:124:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:135:13 + --> $DIR/methods.rs:126:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -77,7 +77,7 @@ LL | | ).unwrap_or(None); | |_____________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:139:13 + --> $DIR/methods.rs:130:13 | LL | let _ = opt | _____________^ @@ -88,7 +88,7 @@ LL | | .unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:147:13 + --> $DIR/methods.rs:138:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -100,7 +100,7 @@ LL | | .unwrap_or_else(|| 0); // should lint even though this cal = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:151:13 + --> $DIR/methods.rs:142:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -110,7 +110,7 @@ LL | | ).unwrap_or_else(|| 0); | |____________________________________^ error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:155:13 + --> $DIR/methods.rs:146:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -120,7 +120,7 @@ LL | | ); | |_________________^ error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:164:13 + --> $DIR/methods.rs:155:13 | LL | let _ = opt.map_or(None, |x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using and_then instead: `opt.and_then(|x| Some(x + 1))` @@ -128,7 +128,7 @@ LL | let _ = opt.map_or(None, |x| Some(x + 1)); = note: `-D clippy::option-map-or-none` implied by `-D warnings` error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:166:13 + --> $DIR/methods.rs:157:13 | LL | let _ = opt.map_or(None, |x| { | _____________^ @@ -144,7 +144,7 @@ LL | }); | error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:191:13 + --> $DIR/methods.rs:182:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:194:13 + --> $DIR/methods.rs:185:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -163,7 +163,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:209:13 + --> $DIR/methods.rs:200:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: replace `find(|&x| *x < 0).is_some()` with `any(|&x| *x < 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:212:13 + --> $DIR/methods.rs:203:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -182,7 +182,7 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:218:13 + --> $DIR/methods.rs:209:13 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ LL | let _ = v.iter().position(|&x| x < 0).is_some(); = note: replace `position(|&x| x < 0).is_some()` with `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:221:13 + --> $DIR/methods.rs:212:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -200,7 +200,7 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:227:13 + --> $DIR/methods.rs:218:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); = note: replace `rposition(|&x| x < 0).is_some()` with `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:230:13 + --> $DIR/methods.rs:221:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -218,7 +218,7 @@ LL | | ).is_some(); | |______________________________^ error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:265:22 + --> $DIR/methods.rs:256:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` @@ -226,73 +226,73 @@ LL | with_constructor.unwrap_or(make()); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/methods.rs:268:5 + --> $DIR/methods.rs:259:5 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:271:21 + --> $DIR/methods.rs:262:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:274:14 + --> $DIR/methods.rs:265:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:277:19 + --> $DIR/methods.rs:268:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/methods.rs:280:5 + --> $DIR/methods.rs:271:5 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/methods.rs:283:5 + --> $DIR/methods.rs:274:5 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:286:14 + --> $DIR/methods.rs:277:14 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| vec![])` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:291:21 + --> $DIR/methods.rs:282:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/methods.rs:294:19 + --> $DIR/methods.rs:285:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/methods.rs:297:21 + --> $DIR/methods.rs:288:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/methods.rs:300:21 + --> $DIR/methods.rs:291:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:311:23 + --> $DIR/methods.rs:302:23 | LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -300,43 +300,43 @@ LL | let bad_vec = some_vec.iter().nth(3); = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:312:26 + --> $DIR/methods.rs:303:26 | LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:313:31 + --> $DIR/methods.rs:304:31 | LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable - --> $DIR/methods.rs:314:29 + --> $DIR/methods.rs:305:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:319:23 + --> $DIR/methods.rs:310:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:322:26 + --> $DIR/methods.rs:313:26 | LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable - --> $DIR/methods.rs:325:29 + --> $DIR/methods.rs:316:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message - --> $DIR/methods.rs:337:13 + --> $DIR/methods.rs:328:13 | LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index cf68bb61100..8307d4b3019 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] use std::cmp::max as my_max; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index a6ad34f02b8..6d68d39e8d3 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -1,5 +1,5 @@ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:21:5 + --> $DIR/min_max.rs:12:5 | LL | min(1, max(3, x)); | ^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | min(1, max(3, x)); = note: `-D clippy::min-max` implied by `-D warnings` error: this min/max combination leads to constant result - --> $DIR/min_max.rs:22:5 + --> $DIR/min_max.rs:13:5 | LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:23:5 + --> $DIR/min_max.rs:14:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:24:5 + --> $DIR/min_max.rs:15:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:26:5 + --> $DIR/min_max.rs:17:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:38:5 + --> $DIR/min_max.rs:29:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this min/max combination leads to constant result - --> $DIR/min_max.rs:39:5 + --> $DIR/min_max.rs:30:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index 5de2ada5a41..cb311dfb361 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -1,25 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* This file incorporates work covered by the following copyright and - * permission notice: - * Copyright 2013 The Rust Project Developers. See the COPYRIGHT - * file at the top-level directory of this distribution and at - * http://rust-lang.org/COPYRIGHT. - * - * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or - * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license - * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your - * option. This file may not be copied, modified, or distributed - * except according to those terms. - */ - #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing-doc.stderr index 35c12786284..a3ae62217a2 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing-doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:32:1 + --> $DIR/missing-doc.rs:10:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing-doc.rs:11:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc.rs:35:1 + --> $DIR/missing-doc.rs:13:1 | LL | / struct Foo { LL | | a: isize, @@ -22,19 +22,19 @@ LL | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:36:5 + --> $DIR/missing-doc.rs:14:5 | LL | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:37:5 + --> $DIR/missing-doc.rs:15:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc.rs:40:1 + --> $DIR/missing-doc.rs:18:1 | LL | / pub struct PubFoo { LL | | pub a: isize, @@ -43,43 +43,43 @@ LL | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:41:5 + --> $DIR/missing-doc.rs:19:5 | LL | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:42:5 + --> $DIR/missing-doc.rs:20:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:51:1 + --> $DIR/missing-doc.rs:29:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:52:1 + --> $DIR/missing-doc.rs:30:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:56:1 + --> $DIR/missing-doc.rs:34:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:57:1 + --> $DIR/missing-doc.rs:35:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for a trait - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing-doc.rs:53:1 | LL | / pub trait C { LL | | fn foo(&self); @@ -88,55 +88,55 @@ LL | | } | |_^ error: missing documentation for a trait method - --> $DIR/missing-doc.rs:76:5 + --> $DIR/missing-doc.rs:54:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for a trait method - --> $DIR/missing-doc.rs:77:5 + --> $DIR/missing-doc.rs:55:5 | LL | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc.rs:87:5 + --> $DIR/missing-doc.rs:65:5 | LL | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc.rs:88:5 + --> $DIR/missing-doc.rs:66:5 | LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:99:5 + --> $DIR/missing-doc.rs:77:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:100:5 + --> $DIR/missing-doc.rs:78:5 | LL | fn bar() {} | ^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:104:5 + --> $DIR/missing-doc.rs:82:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for a method - --> $DIR/missing-doc.rs:107:5 + --> $DIR/missing-doc.rs:85:5 | LL | fn foo2() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:134:1 + --> $DIR/missing-doc.rs:112:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -145,31 +145,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:135:5 + --> $DIR/missing-doc.rs:113:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:135:12 + --> $DIR/missing-doc.rs:113:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:135:22 + --> $DIR/missing-doc.rs:113:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:136:5 + --> $DIR/missing-doc.rs:114:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:139:1 + --> $DIR/missing-doc.rs:117:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -177,43 +177,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:140:5 + --> $DIR/missing-doc.rs:118:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:140:15 + --> $DIR/missing-doc.rs:118:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:160:1 + --> $DIR/missing-doc.rs:138:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:167:1 + --> $DIR/missing-doc.rs:145:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:169:1 + --> $DIR/missing-doc.rs:147:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:176:1 + --> $DIR/missing-doc.rs:154:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:178:1 + --> $DIR/missing-doc.rs:156:1 | LL | / mod internal_impl { LL | | /// dox @@ -225,31 +225,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:181:5 + --> $DIR/missing-doc.rs:159:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:182:5 + --> $DIR/missing-doc.rs:160:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:183:5 + --> $DIR/missing-doc.rs:161:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:188:9 + --> $DIR/missing-doc.rs:166:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:189:9 + --> $DIR/missing-doc.rs:167:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing_inline.rs b/tests/ui/missing_inline.rs index c9e946e14e6..2b2ea6c94c2 100644 --- a/tests/ui/missing_inline.rs +++ b/tests/ui/missing_inline.rs @@ -1,24 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* This file incorporates work covered by the following copyright and - * permission notice: - * Copyright 2013 The Rust Project Developers. See the COPYRIGHT - * file at the top-level directory of this distribution and at - * http://rust-lang.org/COPYRIGHT. - * - * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or - * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license - * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your - * option. This file may not be copied, modified, or distributed - * except according to those terms. - */ #![warn(clippy::missing_inline_in_public_items)] #![crate_type = "dylib"] // When denying at the crate level, be sure to not get random warnings from the diff --git a/tests/ui/missing_inline.stderr b/tests/ui/missing_inline.stderr index efe9a3b1399..40b92b7647b 100644 --- a/tests/ui/missing_inline.stderr +++ b/tests/ui/missing_inline.stderr @@ -1,5 +1,5 @@ error: missing `#[inline]` for a function - --> $DIR/missing_inline.rs:40:1 + --> $DIR/missing_inline.rs:19:1 | LL | pub fn pub_foo() {} // missing #[inline] | ^^^^^^^^^^^^^^^^^^^ @@ -7,31 +7,31 @@ LL | pub fn pub_foo() {} // missing #[inline] = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` error: missing `#[inline]` for a default trait method - --> $DIR/missing_inline.rs:56:5 + --> $DIR/missing_inline.rs:35:5 | LL | fn PubBar_b() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:70:5 + --> $DIR/missing_inline.rs:49:5 | LL | fn PubBar_a() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:71:5 + --> $DIR/missing_inline.rs:50:5 | LL | fn PubBar_b() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:72:5 + --> $DIR/missing_inline.rs:51:5 | LL | fn PubBar_c() {} // missing #[inline] | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> $DIR/missing_inline.rs:82:5 + --> $DIR/missing_inline.rs:61:5 | LL | pub fn PubFooImpl() {} // missing #[inline] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index 730055931c4..a23aba9164a 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::module_inception)] mod foo { diff --git a/tests/ui/module_inception.stderr b/tests/ui/module_inception.stderr index f4d4692e259..77564dce9eb 100644 --- a/tests/ui/module_inception.stderr +++ b/tests/ui/module_inception.stderr @@ -1,5 +1,5 @@ error: module has the same name as its containing module - --> $DIR/module_inception.rs:14:9 + --> $DIR/module_inception.rs:5:9 | LL | / mod bar { LL | | mod foo {} @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::module-inception` implied by `-D warnings` error: module has the same name as its containing module - --> $DIR/module_inception.rs:19:5 + --> $DIR/module_inception.rs:10:5 | LL | / mod foo { LL | | mod bar {} diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index 4db4f56de46..1719845cb21 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] diff --git a/tests/ui/module_name_repetitions.stderr b/tests/ui/module_name_repetitions.stderr index 866156e3b74..5bce2c9ba60 100644 --- a/tests/ui/module_name_repetitions.stderr +++ b/tests/ui/module_name_repetitions.stderr @@ -1,5 +1,5 @@ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:15:5 + --> $DIR/module_name_repetitions.rs:6:5 | LL | pub fn foo_bar() {} | ^^^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | pub fn foo_bar() {} = note: `-D clippy::module-name-repetitions` implied by `-D warnings` error: item name ends with its containing module's name - --> $DIR/module_name_repetitions.rs:16:5 + --> $DIR/module_name_repetitions.rs:7:5 | LL | pub fn bar_foo() {} | ^^^^^^^^^^^^^^^^^^^ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:17:5 + --> $DIR/module_name_repetitions.rs:8:5 | LL | pub struct FooCake {} | ^^^^^^^^^^^^^^^^^^^^^ error: item name ends with its containing module's name - --> $DIR/module_name_repetitions.rs:18:5 + --> $DIR/module_name_repetitions.rs:9:5 | LL | pub enum CakeFoo {} | ^^^^^^^^^^^^^^^^^^^ error: item name starts with its containing module's name - --> $DIR/module_name_repetitions.rs:19:5 + --> $DIR/module_name_repetitions.rs:10:5 | LL | pub struct Foo7Bar; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index f7c0c16abad..81603175ab4 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::modulo_one)] #![allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 36f06c74077..a7feeb56ebc 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,5 +1,5 @@ error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:14:5 + --> $DIR/modulo_one.rs:5:5 | LL | 10 % 1; | ^^^^^^ diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 8a9da42083d..8f9ed7ed637 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::mut_from_ref)] diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index 544d1aa5f14..4787999920b 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -1,60 +1,60 @@ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:16:39 + --> $DIR/mut_from_ref.rs:7:39 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^^^^ | = note: `-D clippy::mut-from-ref` implied by `-D warnings` note: immutable borrow here - --> $DIR/mut_from_ref.rs:16:29 + --> $DIR/mut_from_ref.rs:7:29 | LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { | ^^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:22:25 + --> $DIR/mut_from_ref.rs:13:25 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:22:16 + --> $DIR/mut_from_ref.rs:13:16 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:31:21 + --> $DIR/mut_from_ref.rs:22:21 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:31:12 + --> $DIR/mut_from_ref.rs:22:12 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:35:50 + --> $DIR/mut_from_ref.rs:26:50 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:35:25 + --> $DIR/mut_from_ref.rs:26:25 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> $DIR/mut_from_ref.rs:39:67 + --> $DIR/mut_from_ref.rs:30:67 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> $DIR/mut_from_ref.rs:39:27 + --> $DIR/mut_from_ref.rs:30:27 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index e8239007cb3..8965cef66de 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] #![warn(clippy::mut_mut)] diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index ed926637563..6fa5dbfc29f 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:13:11 + --> $DIR/mut_mut.rs:4:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:29:17 + --> $DIR/mut_mut.rs:20:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:23:9 + --> $DIR/mut_mut.rs:14:9 | LL | &mut $p | ^^^^^^^ @@ -22,37 +22,37 @@ LL | let mut z = mut_ptr!(&mut 3u32); | ------------------- in this macro invocation error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:31:21 + --> $DIR/mut_mut.rs:22:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:32 + --> $DIR/mut_mut.rs:26:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:16 + --> $DIR/mut_mut.rs:26:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:40:37 + --> $DIR/mut_mut.rs:31:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:40:16 + --> $DIR/mut_mut.rs:31:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:40:21 + --> $DIR/mut_mut.rs:31:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/mut_range_bound.rs b/tests/ui/mut_range_bound.rs index 23dddcdd158..1348dd2a3d8 100644 --- a/tests/ui/mut_range_bound.rs +++ b/tests/ui/mut_range_bound.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] fn main() { diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index ce3ae6cb2a5..50e94efde53 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -1,5 +1,5 @@ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:25:9 + --> $DIR/mut_range_bound.rs:16:9 | LL | m = 5; | ^^^^^ @@ -7,25 +7,25 @@ LL | m = 5; = note: `-D clippy::mut-range-bound` implied by `-D warnings` error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:32:9 + --> $DIR/mut_range_bound.rs:23:9 | LL | m *= 2; | ^^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:40:9 + --> $DIR/mut_range_bound.rs:31:9 | LL | m = 5; | ^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:41:9 + --> $DIR/mut_range_bound.rs:32:9 | LL | n = 7; | ^^^^^ error: attempt to mutate range bound within loop; note that the range of the loop is unchanged - --> $DIR/mut_range_bound.rs:55:22 + --> $DIR/mut_range_bound.rs:46:22 | LL | let n = &mut m; // warning | ^ diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index 882ed7e1dd3..c4379e0ea1c 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused_variables, clippy::trivially_copy_pass_by_ref)] fn takes_an_immutable_reference(a: &i32) {} diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index 1fe31e26f6e..fa8c82ae0f3 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,5 +1,5 @@ error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:26:34 + --> $DIR/mut_reference.rs:17:34 | LL | takes_an_immutable_reference(&mut 42); | ^^^^^^^ @@ -7,13 +7,13 @@ LL | takes_an_immutable_reference(&mut 42); = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` error: The function/method `as_ptr` doesn't need a mutable reference - --> $DIR/mut_reference.rs:28:12 + --> $DIR/mut_reference.rs:19:12 | LL | as_ptr(&mut 42); | ^^^^^^^ error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:32:44 + --> $DIR/mut_reference.rs:23:44 | LL | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 5c4e180408c..b9d78b7f479 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![warn(clippy::mutex_integer)] diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 77a05ca13f4..1b0f5c1571b 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -1,5 +1,5 @@ error: Consider using an AtomicBool instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:15:5 + --> $DIR/mutex_atomic.rs:6:5 | LL | Mutex::new(true); | ^^^^^^^^^^^^^^^^ @@ -7,31 +7,31 @@ LL | Mutex::new(true); = note: `-D clippy::mutex-atomic` implied by `-D warnings` error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:16:5 + --> $DIR/mutex_atomic.rs:7:5 | LL | Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:17:5 + --> $DIR/mutex_atomic.rs:8:5 | LL | Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:19:5 + --> $DIR/mutex_atomic.rs:10:5 | LL | Mutex::new(&x as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:20:5 + --> $DIR/mutex_atomic.rs:11:5 | LL | Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:21:5 + --> $DIR/mutex_atomic.rs:12:5 | LL | Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | Mutex::new(0u32); = note: `-D clippy::mutex-integer` implied by `-D warnings` error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>. - --> $DIR/mutex_atomic.rs:22:5 + --> $DIR/mutex_atomic.rs:13:5 | LL | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_bool.rs b/tests/ui/needless_bool.rs index c82f102c294..87493ab8c3d 100644 --- a/tests/ui/needless_bool.rs +++ b/tests/ui/needless_bool.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::needless_bool)] use std::cell::Cell; diff --git a/tests/ui/needless_bool.stderr b/tests/ui/needless_bool.stderr index a0c4ae9561d..c829bf97dd2 100644 --- a/tests/ui/needless_bool.stderr +++ b/tests/ui/needless_bool.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression will always return true - --> $DIR/needless_bool.rs:40:5 + --> $DIR/needless_bool.rs:31:5 | LL | / if x { LL | | true @@ -11,7 +11,7 @@ LL | | }; = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression will always return false - --> $DIR/needless_bool.rs:45:5 + --> $DIR/needless_bool.rs:36:5 | LL | / if x { LL | | false @@ -21,7 +21,7 @@ LL | | }; | |_____^ error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:50:5 + --> $DIR/needless_bool.rs:41:5 | LL | / if x { LL | | true @@ -31,7 +31,7 @@ LL | | }; | |_____^ help: you can reduce it to: `x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:55:5 + --> $DIR/needless_bool.rs:46:5 | LL | / if x { LL | | false @@ -41,7 +41,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:60:5 + --> $DIR/needless_bool.rs:51:5 | LL | / if x && y { LL | | false @@ -51,7 +51,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression will always return true - --> $DIR/needless_bool.rs:83:5 + --> $DIR/needless_bool.rs:74:5 | LL | / if x { LL | | return true; @@ -61,7 +61,7 @@ LL | | }; | |_____^ error: this if-then-else expression will always return false - --> $DIR/needless_bool.rs:92:5 + --> $DIR/needless_bool.rs:83:5 | LL | / if x { LL | | return false; @@ -71,7 +71,7 @@ LL | | }; | |_____^ error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:101:5 + --> $DIR/needless_bool.rs:92:5 | LL | / if x { LL | | return true; @@ -81,7 +81,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:110:5 + --> $DIR/needless_bool.rs:101:5 | LL | / if x && y { LL | | return true; @@ -91,7 +91,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:119:5 + --> $DIR/needless_bool.rs:110:5 | LL | / if x { LL | | return false; @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/needless_bool.rs:128:5 + --> $DIR/needless_bool.rs:119:5 | LL | / if x && y { LL | | return false; @@ -111,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/needless_bool.rs:136:8 + --> $DIR/needless_bool.rs:127:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -119,19 +119,19 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/needless_bool.rs:140:8 + --> $DIR/needless_bool.rs:131:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/needless_bool.rs:150:8 + --> $DIR/needless_bool.rs:141:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/needless_bool.rs:151:8 + --> $DIR/needless_bool.rs:142:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index bfc6e82cb55..a59254625dc 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::borrow::Cow; #[allow(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index ace40665c0c..40744160f65 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:22:15 + --> $DIR/needless_borrow.rs:13:15 | LL | let c = x(&&a); | ^^^ help: change this to: `&a` @@ -7,19 +7,19 @@ LL | let c = x(&&a); = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:29:17 + --> $DIR/needless_borrow.rs:20:17 | LL | if let Some(ref cake) = Some(&5) {} | ^^^^^^^^ help: change this to: `cake` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:36:15 + --> $DIR/needless_borrow.rs:27:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrow.rs:58:34 + --> $DIR/needless_borrow.rs:49:34 | LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); | ^^^^^^ help: try removing the `&ref` part and just keep: `a` @@ -27,13 +27,13 @@ LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrow.rs:59:30 + --> $DIR/needless_borrow.rs:50:30 | LL | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^^ help: try removing the `&ref` part and just keep: `a` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:59:31 + --> $DIR/needless_borrow.rs:50:31 | LL | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^ help: change this to: `a` diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 3897c86f53a..968a9f354bc 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::needless_borrowed_reference)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index b7ea9499f38..1b8067f1d6d 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -1,5 +1,5 @@ error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:14:34 + --> $DIR/needless_borrowed_ref.rs:5:34 | LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); | ^^^^^^ help: try removing the `&ref` part and just keep: `a` @@ -7,19 +7,19 @@ LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:19:17 + --> $DIR/needless_borrowed_ref.rs:10:17 | LL | if let Some(&ref v) = thingy { | ^^^^^^ help: try removing the `&ref` part and just keep: `v` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:48:27 + --> $DIR/needless_borrowed_ref.rs:39:27 | LL | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` error: this pattern takes a reference on something that is being de-referenced - --> $DIR/needless_borrowed_ref.rs:48:38 + --> $DIR/needless_borrowed_ref.rs:39:38 | LL | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index df449e3184f..d4815f60f51 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::collections::{BTreeSet, HashMap, HashSet}; #[warn(clippy::needless_collect)] diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index c4cb187c34e..684c501c5b5 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -1,5 +1,5 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:28 + --> $DIR/needless_collect.rs:7:28 | LL | let len = sample.iter().collect::<Vec<_>>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` @@ -7,19 +7,19 @@ LL | let len = sample.iter().collect::<Vec<_>>().len(); = note: `-D clippy::needless-collect` implied by `-D warnings` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:17:21 + --> $DIR/needless_collect.rs:8:21 | LL | if sample.iter().collect::<Vec<_>>().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:20:27 + --> $DIR/needless_collect.rs:11:27 | LL | sample.iter().cloned().collect::<Vec<_>>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|&x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:21:34 + --> $DIR/needless_collect.rs:12:34 | LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 6d9b9499dce..8bb1ba6edb5 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - macro_rules! zero { ($x:expr) => { $x == 0 diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 60c853c18ad..763eaf3a70e 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -1,6 +1,6 @@ error: This else block is redundant. - --> $DIR/needless_continue.rs:36:16 + --> $DIR/needless_continue.rs:27:16 | LL | } else { | ________________^ @@ -37,7 +37,7 @@ LL | | } error: There is no need for an explicit `else` block for this `if` expression - --> $DIR/needless_continue.rs:51:9 + --> $DIR/needless_continue.rs:42:9 | LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { LL | | continue; diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index ec9df9fb3d3..427bce988bd 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::needless_pass_by_value)] #![allow( dead_code, diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index d9ce5909172..31f43bf16ba 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -1,5 +1,5 @@ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:24:23 + --> $DIR/needless_pass_by_value.rs:15:23 | LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> { | ^^^^^^ help: consider changing the type to: `&[T]` @@ -7,25 +7,25 @@ LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T = note: `-D clippy::needless-pass-by-value` implied by `-D warnings` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:38:11 + --> $DIR/needless_pass_by_value.rs:29:11 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:38:22 + --> $DIR/needless_pass_by_value.rs:29:22 | LL | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:44:71 + --> $DIR/needless_pass_by_value.rs:35:71 | LL | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:56:18 + --> $DIR/needless_pass_by_value.rs:47:18 | LL | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -36,13 +36,13 @@ LL | match *x { | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:69:24 + --> $DIR/needless_pass_by_value.rs:60:24 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:69:36 + --> $DIR/needless_pass_by_value.rs:60:36 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ @@ -55,19 +55,19 @@ LL | let Wrapper(_) = *y; // still not moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:85:49 + --> $DIR/needless_pass_by_value.rs:76:49 | LL | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:87:18 + --> $DIR/needless_pass_by_value.rs:78:18 | LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:87:29 + --> $DIR/needless_pass_by_value.rs:78:29 | LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^ @@ -81,13 +81,13 @@ LL | let _ = t.to_string(); | ^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:87:40 + --> $DIR/needless_pass_by_value.rs:78:40 | LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:87:53 + --> $DIR/needless_pass_by_value.rs:78:53 | LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) { | ^^^^^^^^ @@ -101,61 +101,61 @@ LL | let _ = v.to_owned(); | ^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:100:12 + --> $DIR/needless_pass_by_value.rs:91:12 | LL | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:101:12 + --> $DIR/needless_pass_by_value.rs:92:12 | LL | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:110:23 + --> $DIR/needless_pass_by_value.rs:101:23 | LL | fn baz(&self, _u: U, _s: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:110:30 + --> $DIR/needless_pass_by_value.rs:101:30 | LL | fn baz(&self, _u: U, _s: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:132:24 + --> $DIR/needless_pass_by_value.rs:123:24 | LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:130:1 + --> $DIR/needless_pass_by_value.rs:121:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:138:29 + --> $DIR/needless_pass_by_value.rs:129:29 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:130:1 + --> $DIR/needless_pass_by_value.rs:121:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:138:45 + --> $DIR/needless_pass_by_value.rs:129:45 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:130:1 + --> $DIR/needless_pass_by_value.rs:121:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,13 +168,13 @@ LL | let CopyWrapper(_) = *y; // still not moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:138:61 + --> $DIR/needless_pass_by_value.rs:129:61 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ | help: consider marking this type as Copy - --> $DIR/needless_pass_by_value.rs:130:1 + --> $DIR/needless_pass_by_value.rs:121:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,13 +185,13 @@ LL | let CopyWrapper(s) = *z; // moved | error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:150:40 + --> $DIR/needless_pass_by_value.rs:141:40 | LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> $DIR/needless_pass_by_value.rs:155:20 + --> $DIR/needless_pass_by_value.rs:146:20 | LL | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index 28f71d98fe7..3142210f9bf 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![crate_type = "proc-macro"] #![warn(clippy::needless_pass_by_value)] diff --git a/tests/ui/needless_range_loop.rs b/tests/ui/needless_range_loop.rs index f3d47eede48..a073cc0cfa3 100644 --- a/tests/ui/needless_range_loop.rs +++ b/tests/ui/needless_range_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn calc_idx(i: usize) -> usize { (i + i + 20) % 4 } diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index 73b1d9841eb..7044fc17617 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -1,5 +1,5 @@ error: the loop variable `i` is only used to index `ns`. - --> $DIR/needless_range_loop.rs:17:14 + --> $DIR/needless_range_loop.rs:8:14 | LL | for i in 3..10 { | ^^^^^ @@ -11,7 +11,7 @@ LL | for <item> in ns.iter().take(10).skip(3) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `ms`. - --> $DIR/needless_range_loop.rs:38:14 + --> $DIR/needless_range_loop.rs:29:14 | LL | for i in 0..ms.len() { | ^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | for <item> in &mut ms { | ^^^^^^ ^^^^^^^ error: the loop variable `i` is only used to index `ms`. - --> $DIR/needless_range_loop.rs:44:14 + --> $DIR/needless_range_loop.rs:35:14 | LL | for i in 0..ms.len() { | ^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | for <item> in &mut ms { | ^^^^^^ ^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/needless_range_loop.rs:68:14 + --> $DIR/needless_range_loop.rs:59:14 | LL | for i in x..x + 4 { | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | for <item> in vec.iter_mut().skip(x).take(4) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `vec`. - --> $DIR/needless_range_loop.rs:75:14 + --> $DIR/needless_range_loop.rs:66:14 | LL | for i in x..=x + 4 { | ^^^^^^^^^ @@ -51,7 +51,7 @@ LL | for <item> in vec.iter_mut().skip(x).take(4 + 1) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `arr`. - --> $DIR/needless_range_loop.rs:81:14 + --> $DIR/needless_range_loop.rs:72:14 | LL | for i in 0..3 { | ^^^^ @@ -61,7 +61,7 @@ LL | for <item> in &arr { | ^^^^^^ ^^^^ error: the loop variable `i` is only used to index `arr`. - --> $DIR/needless_range_loop.rs:85:14 + --> $DIR/needless_range_loop.rs:76:14 | LL | for i in 0..2 { | ^^^^ @@ -71,7 +71,7 @@ LL | for <item> in arr.iter().take(2) { | ^^^^^^ ^^^^^^^^^^^^^^^^^^ error: the loop variable `i` is only used to index `arr`. - --> $DIR/needless_range_loop.rs:89:14 + --> $DIR/needless_range_loop.rs:80:14 | LL | for i in 1..3 { | ^^^^ diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 101be5946f4..939233dbecb 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::needless_return)] fn test_end_of_fn() -> bool { diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index bf1083862ed..d7132ce4950 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded return statement - --> $DIR/needless_return.rs:17:5 + --> $DIR/needless_return.rs:8:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` @@ -7,43 +7,43 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded return statement - --> $DIR/needless_return.rs:21:5 + --> $DIR/needless_return.rs:12:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:26:9 + --> $DIR/needless_return.rs:17:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:28:9 + --> $DIR/needless_return.rs:19:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return` as shown: `false` error: unneeded return statement - --> $DIR/needless_return.rs:34:17 + --> $DIR/needless_return.rs:25:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return` as shown: `false` error: unneeded return statement - --> $DIR/needless_return.rs:36:13 + --> $DIR/needless_return.rs:27:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:43:9 + --> $DIR/needless_return.rs:34:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return` as shown: `true` error: unneeded return statement - --> $DIR/needless_return.rs:45:16 + --> $DIR/needless_return.rs:36:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return` as shown: `true` diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index 891c446b0ea..bfa005a19f9 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::needless_update)] #![allow(clippy::no_effect)] diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr index 6c4ea68771b..133c834880d 100644 --- a/tests/ui/needless_update.stderr +++ b/tests/ui/needless_update.stderr @@ -1,5 +1,5 @@ error: struct update has no effect, all the fields in the struct have already been specified - --> $DIR/needless_update.rs:22:23 + --> $DIR/needless_update.rs:13:23 | LL | S { a: 1, b: 1, ..base }; | ^^^^ diff --git a/tests/ui/neg_cmp_op_on_partial_ord.rs b/tests/ui/neg_cmp_op_on_partial_ord.rs index 6c132f85f0a..856a430ba2b 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //! This test case utilizes `f64` an easy example for `PartialOrd` only types //! but the lint itself actually validates any expression where the left //! operand implements `PartialOrd` but not `Ord`. diff --git a/tests/ui/neg_cmp_op_on_partial_ord.stderr b/tests/ui/neg_cmp_op_on_partial_ord.stderr index f1df2b1d98a..d05fd34ce33 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.stderr +++ b/tests/ui/neg_cmp_op_on_partial_ord.stderr @@ -1,5 +1,5 @@ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:24:21 + --> $DIR/neg_cmp_op_on_partial_ord.rs:15:21 | LL | let _not_less = !(a_value < another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | let _not_less = !(a_value < another_value); = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings` error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:27:30 + --> $DIR/neg_cmp_op_on_partial_ord.rs:18:30 | LL | let _not_less_or_equal = !(a_value <= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:30:24 + --> $DIR/neg_cmp_op_on_partial_ord.rs:21:24 | LL | let _not_greater = !(a_value > another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:33:33 + --> $DIR/neg_cmp_op_on_partial_ord.rs:24:33 | LL | let _not_greater_or_equal = !(a_value >= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index f5f7525922c..d4a20ce9db1 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/neg_multiply.stderr b/tests/ui/neg_multiply.stderr index 4c6d8e8d5dd..05554655451 100644 --- a/tests/ui/neg_multiply.stderr +++ b/tests/ui/neg_multiply.stderr @@ -1,5 +1,5 @@ error: Negation by multiplying with -1 - --> $DIR/neg_multiply.rs:36:5 + --> $DIR/neg_multiply.rs:27:5 | LL | x * -1; | ^^^^^^ @@ -7,7 +7,7 @@ LL | x * -1; = note: `-D clippy::neg-multiply` implied by `-D warnings` error: Negation by multiplying with -1 - --> $DIR/neg_multiply.rs:38:5 + --> $DIR/neg_multiply.rs:29:5 | LL | -1 * x; | ^^^^^^ diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index d5a108b0b27..abcec3e92f6 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( clippy::single_match, unused_assignments, diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index 95b1a04e783..416e14d676e 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -1,5 +1,5 @@ error: this loop never actually loops - --> $DIR/never_loop.rs:19:5 + --> $DIR/never_loop.rs:10:5 | LL | / loop { LL | | // clippy::never_loop @@ -13,7 +13,7 @@ LL | | } = note: #[deny(clippy::never_loop)] on by default error: this loop never actually loops - --> $DIR/never_loop.rs:41:5 + --> $DIR/never_loop.rs:32:5 | LL | / loop { LL | | // never loops @@ -23,7 +23,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:61:5 + --> $DIR/never_loop.rs:52:5 | LL | / loop { LL | | // never loops @@ -35,7 +35,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:63:9 + --> $DIR/never_loop.rs:54:9 | LL | / while i == 0 { LL | | // never loops @@ -44,7 +44,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:75:9 + --> $DIR/never_loop.rs:66:9 | LL | / loop { LL | | // never loops @@ -56,7 +56,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:111:5 + --> $DIR/never_loop.rs:102:5 | LL | / while let Some(y) = x { LL | | // never loops @@ -65,7 +65,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:118:5 + --> $DIR/never_loop.rs:109:5 | LL | / for x in 0..10 { LL | | // never loops @@ -77,7 +77,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:166:5 + --> $DIR/never_loop.rs:157:5 | LL | / 'outer: while a { LL | | // never loops @@ -89,7 +89,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:181:9 + --> $DIR/never_loop.rs:172:9 | LL | / while false { LL | | break 'label; diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 07d0a6bb05e..82aec070b40 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(const_fn)] #![allow(dead_code)] #![warn(clippy::new_without_default)] diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 9157f60a7e4..cd8e2837f08 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,5 +1,5 @@ error: you should consider deriving a `Default` implementation for `Foo` - --> $DIR/new_without_default.rs:17:5 + --> $DIR/new_without_default.rs:8:5 | LL | / pub fn new() -> Foo { LL | | Foo @@ -13,7 +13,7 @@ LL | #[derive(Default)] | error: you should consider deriving a `Default` implementation for `Bar` - --> $DIR/new_without_default.rs:25:5 + --> $DIR/new_without_default.rs:16:5 | LL | / pub fn new() -> Self { LL | | Bar @@ -25,7 +25,7 @@ LL | #[derive(Default)] | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> $DIR/new_without_default.rs:89:5 + --> $DIR/new_without_default.rs:80:5 | LL | / pub fn new() -> LtKo<'c> { LL | | unimplemented!() diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 6b51c50dcde..8fbfcb79860 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] #![warn(clippy::no_effect)] #![allow(dead_code)] diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index cc3b069f0b5..834b9056e31 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:74:5 + --> $DIR/no_effect.rs:65:5 | LL | 0; | ^^ @@ -7,145 +7,145 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:75:5 + --> $DIR/no_effect.rs:66:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:76:5 + --> $DIR/no_effect.rs:67:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:77:5 + --> $DIR/no_effect.rs:68:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:78:5 + --> $DIR/no_effect.rs:69:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:79:5 + --> $DIR/no_effect.rs:70:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:80:5 + --> $DIR/no_effect.rs:71:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:81:5 + --> $DIR/no_effect.rs:72:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:82:5 + --> $DIR/no_effect.rs:73:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:83:5 + --> $DIR/no_effect.rs:74:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:84:5 + --> $DIR/no_effect.rs:75:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:85:5 + --> $DIR/no_effect.rs:76:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:86:5 + --> $DIR/no_effect.rs:77:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:87:5 + --> $DIR/no_effect.rs:78:5 | LL | box 42; | ^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:88:5 + --> $DIR/no_effect.rs:79:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:89:5 + --> $DIR/no_effect.rs:80:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:90:5 + --> $DIR/no_effect.rs:81:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:91:5 + --> $DIR/no_effect.rs:82:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:93:5 + --> $DIR/no_effect.rs:84:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:85:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:86:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:87:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:88:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:90:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:92:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/non_copy_const.rs b/tests/ui/non_copy_const.rs index 591e1994ee3..bd8b7521d14 100644 --- a/tests/ui/non_copy_const.rs +++ b/tests/ui/non_copy_const.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(const_string_new, const_vec_new)] #![allow(clippy::ref_in_deref, dead_code)] diff --git a/tests/ui/non_copy_const.stderr b/tests/ui/non_copy_const.stderr index 6b592b681c9..a9584ceb7ec 100644 --- a/tests/ui/non_copy_const.stderr +++ b/tests/ui/non_copy_const.stderr @@ -1,5 +1,5 @@ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:19:1 + --> $DIR/non_copy_const.rs:10:1 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable = note: #[deny(clippy::declare_interior_mutable_const)] on by default error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:20:1 + --> $DIR/non_copy_const.rs:11:1 | LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable | help: make this a static item: `static` error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:21:1 + --> $DIR/non_copy_const.rs:12:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], V | help: make this a static item: `static` error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:26:9 + --> $DIR/non_copy_const.rs:17:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -34,49 +34,49 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable | ------------------------------------------ in this macro invocation error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:50:5 + --> $DIR/non_copy_const.rs:41:5 | LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:54:5 + --> $DIR/non_copy_const.rs:45:5 | LL | const INPUT: T; | ^^^^^^^^^^^^^^^ | help: consider requiring `T` to be `Copy` - --> $DIR/non_copy_const.rs:54:18 + --> $DIR/non_copy_const.rs:45:18 | LL | const INPUT: T; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:57:5 + --> $DIR/non_copy_const.rs:48:5 | LL | const ASSOC: Self::NonCopyType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy` - --> $DIR/non_copy_const.rs:57:18 + --> $DIR/non_copy_const.rs:48:18 | LL | const ASSOC: Self::NonCopyType; | ^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:61:5 + --> $DIR/non_copy_const.rs:52:5 | LL | const AN_INPUT: T = Self::INPUT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `T` to be `Copy` - --> $DIR/non_copy_const.rs:61:21 + --> $DIR/non_copy_const.rs:52:21 | LL | const AN_INPUT: T = Self::INPUT; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:26:9 + --> $DIR/non_copy_const.rs:17:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -85,49 +85,49 @@ LL | declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior muta | ----------------------------------------------- in this macro invocation error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:70:5 + --> $DIR/non_copy_const.rs:61:5 | LL | const SELF_2: Self; | ^^^^^^^^^^^^^^^^^^^ | help: consider requiring `Self` to be `Copy` - --> $DIR/non_copy_const.rs:70:19 + --> $DIR/non_copy_const.rs:61:19 | LL | const SELF_2: Self; | ^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:91:5 + --> $DIR/non_copy_const.rs:82:5 | LL | const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:94:5 + --> $DIR/non_copy_const.rs:85:5 | LL | const U_SELF: U = U::SELF_2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `U` to be `Copy` - --> $DIR/non_copy_const.rs:94:19 + --> $DIR/non_copy_const.rs:85:19 | LL | const U_SELF: U = U::SELF_2; | ^ error: a const item should never be interior mutable - --> $DIR/non_copy_const.rs:97:5 + --> $DIR/non_copy_const.rs:88:5 | LL | const T_ASSOC: T::NonCopyType = T::ASSOC; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy` - --> $DIR/non_copy_const.rs:97:20 + --> $DIR/non_copy_const.rs:88:20 | LL | const T_ASSOC: T::NonCopyType = T::ASSOC; | ^^^^^^^^^^^^^^ error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:104:5 + --> $DIR/non_copy_const.rs:95:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -136,7 +136,7 @@ LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:105:16 + --> $DIR/non_copy_const.rs:96:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -144,7 +144,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:107:5 + --> $DIR/non_copy_const.rs:98:5 | LL | ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:108:16 + --> $DIR/non_copy_const.rs:99:16 | LL | assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability | ^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL | assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR inte = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:111:22 + --> $DIR/non_copy_const.rs:102:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -168,7 +168,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:112:25 + --> $DIR/non_copy_const.rs:103:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -176,7 +176,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:113:27 + --> $DIR/non_copy_const.rs:104:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -184,7 +184,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:114:26 + --> $DIR/non_copy_const.rs:105:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -192,7 +192,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:125:14 + --> $DIR/non_copy_const.rs:116:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:126:14 + --> $DIR/non_copy_const.rs:117:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:127:19 + --> $DIR/non_copy_const.rs:118:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -216,7 +216,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:128:14 + --> $DIR/non_copy_const.rs:119:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -224,7 +224,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:129:13 + --> $DIR/non_copy_const.rs:120:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:135:13 + --> $DIR/non_copy_const.rs:126:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:140:5 + --> $DIR/non_copy_const.rs:131:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -248,7 +248,7 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:141:16 + --> $DIR/non_copy_const.rs:132:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -256,7 +256,7 @@ LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:154:5 + --> $DIR/non_copy_const.rs:145:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -264,7 +264,7 @@ LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a const item with interior mutability should not be borrowed - --> $DIR/non_copy_const.rs:155:16 + --> $DIR/non_copy_const.rs:146:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index 86c9edc821d..b1d7d8e52a8 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all, clippy::similar_names)] #![allow(unused, clippy::println_empty_string)] diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 8729db18dff..f4274b87cdc 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,110 +1,110 @@ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:24:9 + --> $DIR/non_expressive_names.rs:15:9 | LL | let bpple: i32; | ^^^^^ | = note: `-D clippy::similar-names` implied by `-D warnings` note: existing binding defined here - --> $DIR/non_expressive_names.rs:22:9 + --> $DIR/non_expressive_names.rs:13:9 | LL | let apple: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `b_pple` - --> $DIR/non_expressive_names.rs:24:9 + --> $DIR/non_expressive_names.rs:15:9 | LL | let bpple: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:26:9 + --> $DIR/non_expressive_names.rs:17:9 | LL | let cpple: i32; | ^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:22:9 + --> $DIR/non_expressive_names.rs:13:9 | LL | let apple: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `c_pple` - --> $DIR/non_expressive_names.rs:26:9 + --> $DIR/non_expressive_names.rs:17:9 | LL | let cpple: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:50:9 + --> $DIR/non_expressive_names.rs:41:9 | LL | let bluby: i32; | ^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:49:9 + --> $DIR/non_expressive_names.rs:40:9 | LL | let blubx: i32; | ^^^^^ help: separate the discriminating character by an underscore like: `blub_y` - --> $DIR/non_expressive_names.rs:50:9 + --> $DIR/non_expressive_names.rs:41:9 | LL | let bluby: i32; | ^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:54:9 + --> $DIR/non_expressive_names.rs:45:9 | LL | let coke: i32; | ^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:52:9 + --> $DIR/non_expressive_names.rs:43:9 | LL | let cake: i32; | ^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:72:9 + --> $DIR/non_expressive_names.rs:63:9 | LL | let xyzeabc: i32; | ^^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:70:9 + --> $DIR/non_expressive_names.rs:61:9 | LL | let xyz1abc: i32; | ^^^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:76:9 + --> $DIR/non_expressive_names.rs:67:9 | LL | let parsee: i32; | ^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:74:9 + --> $DIR/non_expressive_names.rs:65:9 | LL | let parser: i32; | ^^^^^^ help: separate the discriminating character by an underscore like: `parse_e` - --> $DIR/non_expressive_names.rs:76:9 + --> $DIR/non_expressive_names.rs:67:9 | LL | let parsee: i32; | ^^^^^^ error: binding's name is too similar to existing binding - --> $DIR/non_expressive_names.rs:90:16 + --> $DIR/non_expressive_names.rs:81:16 | LL | bpple: sprang, | ^^^^^^ | note: existing binding defined here - --> $DIR/non_expressive_names.rs:89:16 + --> $DIR/non_expressive_names.rs:80:16 | LL | apple: spring, | ^^^^^^ error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:125:17 + --> $DIR/non_expressive_names.rs:116:17 | LL | let e: i32; | ^ @@ -112,25 +112,25 @@ LL | let e: i32; = note: `-D clippy::many-single-char-names` implied by `-D warnings` error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:128:17 + --> $DIR/non_expressive_names.rs:119:17 | LL | let e: i32; | ^ error: 6th binding whose name is just one char - --> $DIR/non_expressive_names.rs:129:17 + --> $DIR/non_expressive_names.rs:120:17 | LL | let f: i32; | ^ error: 5th binding whose name is just one char - --> $DIR/non_expressive_names.rs:133:13 + --> $DIR/non_expressive_names.rs:124:13 | LL | e => panic!(), | ^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:143:9 + --> $DIR/non_expressive_names.rs:134:9 | LL | let _1 = 1; //~ERROR Consider a more descriptive name | ^^ @@ -138,31 +138,31 @@ LL | let _1 = 1; //~ERROR Consider a more descriptive name = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings` error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:144:9 + --> $DIR/non_expressive_names.rs:135:9 | LL | let ____1 = 1; //~ERROR Consider a more descriptive name | ^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:145:9 + --> $DIR/non_expressive_names.rs:136:9 | LL | let __1___2 = 12; //~ERROR Consider a more descriptive name | ^^^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:165:13 + --> $DIR/non_expressive_names.rs:156:13 | LL | let _1 = 1; | ^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:166:13 + --> $DIR/non_expressive_names.rs:157:13 | LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> $DIR/non_expressive_names.rs:167:13 + --> $DIR/non_expressive_names.rs:158:13 | LL | let __1___2 = 12; | ^^^^^^^ diff --git a/tests/ui/ok_expect.rs b/tests/ui/ok_expect.rs index b121aae788c..ff68d38c73b 100644 --- a/tests/ui/ok_expect.rs +++ b/tests/ui/ok_expect.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::io; struct MyError(()); // doesn't implement Debug diff --git a/tests/ui/ok_expect.stderr b/tests/ui/ok_expect.stderr index 4ccca10a463..99e62313183 100644 --- a/tests/ui/ok_expect.stderr +++ b/tests/ui/ok_expect.stderr @@ -1,5 +1,5 @@ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:23:5 + --> $DIR/ok_expect.rs:14:5 | LL | res.ok().expect("disaster!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | res.ok().expect("disaster!"); = note: `-D clippy::ok-expect` implied by `-D warnings` error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:29:5 + --> $DIR/ok_expect.rs:20:5 | LL | res3.ok().expect("whoof"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:31:5 + --> $DIR/ok_expect.rs:22:5 | LL | res4.ok().expect("argh"); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:33:5 + --> $DIR/ok_expect.rs:24:5 | LL | res5.ok().expect("oops"); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result` - --> $DIR/ok_expect.rs:35:5 + --> $DIR/ok_expect.rs:26:5 | LL | res6.ok().expect("meh"); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index 3ede64ce3aa..61db3113052 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::if_let_some_result)] fn str_to_int(x: &str) -> i32 { diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr index 4567493a7c2..e3e6c5c4634 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/ok_if_let.stderr @@ -1,5 +1,5 @@ error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:13:5 + --> $DIR/ok_if_let.rs:4:5 | LL | / if let Some(y) = x.parse().ok() { LL | | y diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index 1112b6794cf..bf43deca12c 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused_variables, clippy::blacklisted_name)] use std::collections::HashSet; diff --git a/tests/ui/op_ref.stderr b/tests/ui/op_ref.stderr index 956e2ee754c..f5c5b970261 100644 --- a/tests/ui/op_ref.stderr +++ b/tests/ui/op_ref.stderr @@ -1,5 +1,5 @@ error: needlessly taken reference of both operands - --> $DIR/op_ref.rs:19:15 + --> $DIR/op_ref.rs:10:15 | LL | let foo = &5 - &6; | ^^^^^^^ @@ -11,7 +11,7 @@ LL | let foo = 5 - 6; | ^ ^ error: taken reference of right operand - --> $DIR/op_ref.rs:27:8 + --> $DIR/op_ref.rs:18:8 | LL | if b < &a { | ^^^^-- diff --git a/tests/ui/open_options.rs b/tests/ui/open_options.rs index f4d0af94b3f..9063fafbcd0 100644 --- a/tests/ui/open_options.rs +++ b/tests/ui/open_options.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::fs::OpenOptions; #[allow(unused_must_use)] diff --git a/tests/ui/open_options.stderr b/tests/ui/open_options.stderr index 55c0429800b..addb0c4e1a5 100644 --- a/tests/ui/open_options.stderr +++ b/tests/ui/open_options.stderr @@ -1,5 +1,5 @@ error: file opened with "truncate" and "read" - --> $DIR/open_options.rs:15:5 + --> $DIR/open_options.rs:6:5 | LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | OpenOptions::new().read(true).truncate(true).open("foo.txt"); = note: `-D clippy::nonsensical-open-options` implied by `-D warnings` error: file opened with "append" and "truncate" - --> $DIR/open_options.rs:16:5 + --> $DIR/open_options.rs:7:5 | LL | OpenOptions::new().append(true).truncate(true).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "read" is called more than once - --> $DIR/open_options.rs:18:5 + --> $DIR/open_options.rs:9:5 | LL | OpenOptions::new().read(true).read(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "create" is called more than once - --> $DIR/open_options.rs:19:5 + --> $DIR/open_options.rs:10:5 | LL | OpenOptions::new().create(true).create(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "write" is called more than once - --> $DIR/open_options.rs:20:5 + --> $DIR/open_options.rs:11:5 | LL | OpenOptions::new().write(true).write(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "append" is called more than once - --> $DIR/open_options.rs:21:5 + --> $DIR/open_options.rs:12:5 | LL | OpenOptions::new().append(true).append(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the method "truncate" is called more than once - --> $DIR/open_options.rs:22:5 + --> $DIR/open_options.rs:13:5 | LL | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_map_unit_fn.rs b/tests/ui/option_map_unit_fn.rs index db473f9b41e..1d2a3a17ee0 100644 --- a/tests/ui/option_map_unit_fn.rs +++ b/tests/ui/option_map_unit_fn.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::option_map_unit_fn)] #![allow(unused)] diff --git a/tests/ui/option_map_unit_fn.stderr b/tests/ui/option_map_unit_fn.stderr index 18ddcec5edd..16e355ad0b2 100644 --- a/tests/ui/option_map_unit_fn.stderr +++ b/tests/ui/option_map_unit_fn.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:41:5 + --> $DIR/option_map_unit_fn.rs:32:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:43:5 + --> $DIR/option_map_unit_fn.rs:34:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Some(x_field) = x.field { do_nothing(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:45:5 + --> $DIR/option_map_unit_fn.rs:36:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Some(x_field) = x.field { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:51:5 + --> $DIR/option_map_unit_fn.rs:42:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:53:5 + --> $DIR/option_map_unit_fn.rs:44:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:56:5 + --> $DIR/option_map_unit_fn.rs:47:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:58:5 + --> $DIR/option_map_unit_fn.rs:49:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:60:5 + --> $DIR/option_map_unit_fn.rs:51:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:62:5 + --> $DIR/option_map_unit_fn.rs:53:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:65:5 + --> $DIR/option_map_unit_fn.rs:56:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:67:5 + --> $DIR/option_map_unit_fn.rs:58:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:69:5 + --> $DIR/option_map_unit_fn.rs:60:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:71:5 + --> $DIR/option_map_unit_fn.rs:62:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:76:5 + --> $DIR/option_map_unit_fn.rs:67:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:78:5 + --> $DIR/option_map_unit_fn.rs:69:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:80:5 + --> $DIR/option_map_unit_fn.rs:71:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:83:5 + --> $DIR/option_map_unit_fn.rs:74:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:86:5 + --> $DIR/option_map_unit_fn.rs:77:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -145,7 +145,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:88:5 + --> $DIR/option_map_unit_fn.rs:79:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -153,7 +153,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:92:5 + --> $DIR/option_map_unit_fn.rs:83:5 | LL | x.field.map(|value| { | _____^ @@ -167,7 +167,7 @@ LL | || }); | error: called `map(f)` on an Option value where `f` is a unit closure - --> $DIR/option_map_unit_fn.rs:96:5 + --> $DIR/option_map_unit_fn.rs:87:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -175,7 +175,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | help: try this: `if let Some(value) = x.field { ... }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:99:5 + --> $DIR/option_map_unit_fn.rs:90:5 | LL | Some(42).map(diverge); | ^^^^^^^^^^^^^^^^^^^^^- @@ -183,7 +183,7 @@ LL | Some(42).map(diverge); | help: try this: `if let Some(_) = Some(42) { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:100:5 + --> $DIR/option_map_unit_fn.rs:91:5 | LL | "12".parse::<i32>().ok().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -191,7 +191,7 @@ LL | "12".parse::<i32>().ok().map(diverge); | help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:101:5 + --> $DIR/option_map_unit_fn.rs:92:5 | LL | Some(plus_one(1)).map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -199,7 +199,7 @@ LL | Some(plus_one(1)).map(do_nothing); | help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }` error: called `map(f)` on an Option value where `f` is a unit function - --> $DIR/option_map_unit_fn.rs:105:5 + --> $DIR/option_map_unit_fn.rs:96:5 | LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index fcfd4e6ea56..e2e649a8108 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn input(_: Option<Option<u8>>) {} fn output() -> Option<Option<u8>> { diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 992f14c825f..9e9425cf954 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,5 +1,5 @@ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:10:13 + --> $DIR/option_option.rs:1:13 | LL | fn input(_: Option<Option<u8>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -7,49 +7,49 @@ LL | fn input(_: Option<Option<u8>>) {} = note: `-D clippy::option-option` implied by `-D warnings` error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:12:16 + --> $DIR/option_option.rs:3:16 | LL | fn output() -> Option<Option<u8>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:16:27 + --> $DIR/option_option.rs:7:27 | LL | fn output_nested() -> Vec<Option<Option<u8>>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:21:30 + --> $DIR/option_option.rs:12:30 | LL | fn output_nested_nested() -> Option<Option<Option<u8>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:26:8 + --> $DIR/option_option.rs:17:8 | LL | x: Option<Option<u8>>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:30:23 + --> $DIR/option_option.rs:21:23 | LL | fn struct_fn() -> Option<Option<u8>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:36:22 + --> $DIR/option_option.rs:27:22 | LL | fn trait_fn() -> Option<Option<u8>>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:40:11 + --> $DIR/option_option.rs:31:11 | LL | Tuple(Option<Option<u8>>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:41:17 + --> $DIR/option_option.rs:32:17 | LL | Struct { x: Option<Option<u8>> }, | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index a5cff3df9d7..84332040dba 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::many_single_char_names)] #![warn(clippy::overflow_check_conditional)] diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 078a1a5941c..ad66135d326 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -1,5 +1,5 @@ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:17:8 + --> $DIR/overflow_check_conditional.rs:8:8 | LL | if a + b < a {} | ^^^^^^^^^ @@ -7,43 +7,43 @@ LL | if a + b < a {} = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:18:8 + --> $DIR/overflow_check_conditional.rs:9:8 | LL | if a > a + b {} | ^^^^^^^^^ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:19:8 + --> $DIR/overflow_check_conditional.rs:10:8 | LL | if a + b < b {} | ^^^^^^^^^ error: You are trying to use classic C overflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:20:8 + --> $DIR/overflow_check_conditional.rs:11:8 | LL | if b > a + b {} | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:21:8 + --> $DIR/overflow_check_conditional.rs:12:8 | LL | if a - b > b {} | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:22:8 + --> $DIR/overflow_check_conditional.rs:13:8 | LL | if b < a - b {} | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:23:8 + --> $DIR/overflow_check_conditional.rs:14:8 | LL | if a - b > a {} | ^^^^^^^^^ error: You are trying to use classic C underflow conditions that will fail in Rust. - --> $DIR/overflow_check_conditional.rs:24:8 + --> $DIR/overflow_check_conditional.rs:15:8 | LL | if a < a - b {} | ^^^^^^^^^ diff --git a/tests/ui/panic_unimplemented.rs b/tests/ui/panic_unimplemented.rs index 93dec197ff5..f205e07cd30 100644 --- a/tests/ui/panic_unimplemented.rs +++ b/tests/ui/panic_unimplemented.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::panic_params, clippy::unimplemented)] fn missing() { diff --git a/tests/ui/panic_unimplemented.stderr b/tests/ui/panic_unimplemented.stderr index 7bc83a287c1..588fa187b4a 100644 --- a/tests/ui/panic_unimplemented.stderr +++ b/tests/ui/panic_unimplemented.stderr @@ -1,5 +1,5 @@ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:14:16 + --> $DIR/panic_unimplemented.rs:5:16 | LL | panic!("{}"); | ^^^^ @@ -7,25 +7,25 @@ LL | panic!("{}"); = note: `-D clippy::panic-params` implied by `-D warnings` error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:16:16 + --> $DIR/panic_unimplemented.rs:7:16 | LL | panic!("{:?}"); | ^^^^^^ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:18:23 + --> $DIR/panic_unimplemented.rs:9:23 | LL | assert!(true, "here be missing values: {}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:21:12 + --> $DIR/panic_unimplemented.rs:12:12 | LL | panic!("{{{this}}}"); | ^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> $DIR/panic_unimplemented.rs:64:5 + --> $DIR/panic_unimplemented.rs:55:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/partialeq_ne_impl.rs b/tests/ui/partialeq_ne_impl.rs index e1e0413fcea..1338d3c74d5 100644 --- a/tests/ui/partialeq_ne_impl.rs +++ b/tests/ui/partialeq_ne_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] struct Foo; diff --git a/tests/ui/partialeq_ne_impl.stderr b/tests/ui/partialeq_ne_impl.stderr index ac040acc306..b92da4511b4 100644 --- a/tests/ui/partialeq_ne_impl.stderr +++ b/tests/ui/partialeq_ne_impl.stderr @@ -1,5 +1,5 @@ error: re-implementing `PartialEq::ne` is unnecessary - --> $DIR/partialeq_ne_impl.rs:18:5 + --> $DIR/partialeq_ne_impl.rs:9:5 | LL | / fn ne(&self, _: &Foo) -> bool { LL | | false diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index e10afdb86b8..576e6c9ab92 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] #![warn(clippy::all)] diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index 74e8b9ae776..39dc034a014 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,5 +1,5 @@ error: the `y @ _` pattern can be written as just `y` - --> $DIR/patterns.rs:17:9 + --> $DIR/patterns.rs:8:9 | LL | y @ _ => (), | ^^^^^ diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 82009cd3873..e4f65b46ea0 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::precedence)] #[allow(clippy::identity_op)] #[allow(clippy::eq_op)] diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 2d917b3cbdb..01c59a5b8ea 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -1,5 +1,5 @@ error: operator precedence can trip the unwary - --> $DIR/precedence.rs:24:5 + --> $DIR/precedence.rs:15:5 | LL | 1 << 2 + 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)` @@ -7,49 +7,49 @@ LL | 1 << 2 + 3; = note: `-D clippy::precedence` implied by `-D warnings` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:25:5 + --> $DIR/precedence.rs:16:5 | LL | 1 + 2 << 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:26:5 + --> $DIR/precedence.rs:17:5 | LL | 4 >> 1 + 1; | ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:27:5 + --> $DIR/precedence.rs:18:5 | LL | 1 + 3 >> 2; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:28:5 + --> $DIR/precedence.rs:19:5 | LL | 1 ^ 1 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:29:5 + --> $DIR/precedence.rs:20:5 | LL | 3 | 2 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)` error: operator precedence can trip the unwary - --> $DIR/precedence.rs:30:5 + --> $DIR/precedence.rs:21:5 | LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` error: unary minus has lower precedence than method call - --> $DIR/precedence.rs:31:5 + --> $DIR/precedence.rs:22:5 | LL | -1i32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())` error: unary minus has lower precedence than method call - --> $DIR/precedence.rs:32:5 + --> $DIR/precedence.rs:23:5 | LL | -1f32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` diff --git a/tests/ui/print.rs b/tests/ui/print.rs index a43482cba62..366ccc2b3bd 100644 --- a/tests/ui/print.rs +++ b/tests/ui/print.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::print_literal, clippy::write_literal)] #![warn(clippy::print_stdout, clippy::use_debug)] diff --git a/tests/ui/print.stderr b/tests/ui/print.stderr index 9635011b906..12c5a0bdaa0 100644 --- a/tests/ui/print.stderr +++ b/tests/ui/print.stderr @@ -1,5 +1,5 @@ error: use of `Debug`-based formatting - --> $DIR/print.rs:20:19 + --> $DIR/print.rs:11:19 | LL | write!(f, "{:?}", 43.1415) | ^^^^^^ @@ -7,13 +7,13 @@ LL | write!(f, "{:?}", 43.1415) = note: `-D clippy::use-debug` implied by `-D warnings` error: use of `Debug`-based formatting - --> $DIR/print.rs:27:19 + --> $DIR/print.rs:18:19 | LL | write!(f, "{:?}", 42.718) | ^^^^^^ error: use of `println!` - --> $DIR/print.rs:32:5 + --> $DIR/print.rs:23:5 | LL | println!("Hello"); | ^^^^^^^^^^^^^^^^^ @@ -21,37 +21,37 @@ LL | println!("Hello"); = note: `-D clippy::print-stdout` implied by `-D warnings` error: use of `print!` - --> $DIR/print.rs:33:5 + --> $DIR/print.rs:24:5 | LL | print!("Hello"); | ^^^^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:35:5 + --> $DIR/print.rs:26:5 | LL | print!("Hello {}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:37:5 + --> $DIR/print.rs:28:5 | LL | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:37:12 + --> $DIR/print.rs:28:12 | LL | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^ error: use of `print!` - --> $DIR/print.rs:39:5 + --> $DIR/print.rs:30:5 | LL | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> $DIR/print.rs:39:12 + --> $DIR/print.rs:30:12 | LL | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^ diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 74756384067..40ed18e9302 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::print_literal)] fn main() { diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index be55795d1ac..fc502e9f71d 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/print_literal.rs:31:71 + --> $DIR/print_literal.rs:22:71 | LL | println!("{} of {:b} people know binary, the other half doesn't", 1, 2); | ^ @@ -7,79 +7,79 @@ LL | println!("{} of {:b} people know binary, the other half doesn't", 1, 2) = note: `-D clippy::print-literal` implied by `-D warnings` error: literal with an empty format string - --> $DIR/print_literal.rs:32:24 + --> $DIR/print_literal.rs:23:24 | LL | print!("Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:33:36 + --> $DIR/print_literal.rs:24:36 | LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:34:26 + --> $DIR/print_literal.rs:25:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:35:30 + --> $DIR/print_literal.rs:26:30 | LL | println!("10 / 4 is {}", 2.5); | ^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:36:28 + --> $DIR/print_literal.rs:27:28 | LL | println!("2 + 1 = {}", 3); | ^ error: literal with an empty format string - --> $DIR/print_literal.rs:41:25 + --> $DIR/print_literal.rs:32:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:41:34 + --> $DIR/print_literal.rs:32:34 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:42:25 + --> $DIR/print_literal.rs:33:25 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:42:34 + --> $DIR/print_literal.rs:33:34 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:45:35 + --> $DIR/print_literal.rs:36:35 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:45:50 + --> $DIR/print_literal.rs:36:50 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:46:35 + --> $DIR/print_literal.rs:37:35 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/print_literal.rs:46:50 + --> $DIR/print_literal.rs:37:50 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index 351fd60bc36..991cd7311e5 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::print_literal)] #![warn(clippy::print_with_newline)] diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 2d76e447145..a731212be87 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -1,5 +1,5 @@ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:14:5 + --> $DIR/print_with_newline.rs:5:5 | LL | print!("Hello/n"); | ^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | print!("Hello/n"); = note: `-D clippy::print-with-newline` implied by `-D warnings` error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:15:5 + --> $DIR/print_with_newline.rs:6:5 | LL | print!("Hello {}/n", "world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:16:5 + --> $DIR/print_with_newline.rs:7:5 | LL | print!("Hello {} {}/n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead - --> $DIR/print_with_newline.rs:17:5 + --> $DIR/print_with_newline.rs:8:5 | LL | print!("{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 4ca151453fe..4e84511d7b0 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 21f944916db..9fdfb03a366 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 2370a3f1e28..689624a0fa0 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -1,5 +1,5 @@ error: using `println!("")` - --> $DIR/println_empty_string.rs:14:5 + --> $DIR/println_empty_string.rs:5:5 | LL | println!(""); | ^^^^^^^^^^^^ help: replace it with: `println!()` @@ -7,7 +7,7 @@ LL | println!(""); = note: `-D clippy::println-empty-string` implied by `-D warnings` error: using `println!("")` - --> $DIR/println_empty_string.rs:17:14 + --> $DIR/println_empty_string.rs:8:14 | LL | _ => println!(""), | ^^^^^^^^^^^^ help: replace it with: `println!()` diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 0d7a829888e..1ce6081bf94 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused, clippy::many_single_char_names)] #![warn(clippy::ptr_arg)] diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index af5003c9b95..34516368e5e 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:15:14 + --> $DIR/ptr_arg.rs:6:14 | LL | fn do_vec(x: &Vec<i64>) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,19 +7,19 @@ LL | fn do_vec(x: &Vec<i64>) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:24:14 + --> $DIR/ptr_arg.rs:15:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:37:18 + --> $DIR/ptr_arg.rs:28:18 | LL | fn do_vec(x: &Vec<i64>); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices. - --> $DIR/ptr_arg.rs:50:14 + --> $DIR/ptr_arg.rs:41:14 | LL | fn cloned(x: &Vec<u8>) -> Vec<u8> { | ^^^^^^^^ @@ -37,7 +37,7 @@ LL | x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:59:18 + --> $DIR/ptr_arg.rs:50:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -59,7 +59,7 @@ LL | x.to_string() | error: writing `&String` instead of `&str` involves a new object where a slice will do. - --> $DIR/ptr_arg.rs:67:44 + --> $DIR/ptr_arg.rs:58:44 | LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) { | ^^^^^^^ @@ -77,7 +77,7 @@ LL | let c = y; | ^ error: using a reference to `Cow` is not recommended. - --> $DIR/ptr_arg.rs:81:25 + --> $DIR/ptr_arg.rs:72:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index c9f58896ae1..ebdd6c4003d 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 23eb4c6ce8a..3416c4b727a 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix fn main() { diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr index 98e3ff92a6e..b5c7a03e277 100644 --- a/tests/ui/ptr_offset_with_cast.stderr +++ b/tests/ui/ptr_offset_with_cast.stderr @@ -1,5 +1,5 @@ error: use of `offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:21:9 + --> $DIR/ptr_offset_with_cast.rs:12:9 | LL | ptr.offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` @@ -7,7 +7,7 @@ LL | ptr.offset(offset_usize as isize); = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:25:9 + --> $DIR/ptr_offset_with_cast.rs:16:9 | LL | ptr.wrapping_offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 7e749d164ca..56ccf1d432f 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn some_func(a: Option<u32>) -> Option<u32> { if a.is_none() { return None; diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index a0b87813770..522501d58c6 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:11:5 + --> $DIR/question_mark.rs:2:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:56:9 + --> $DIR/question_mark.rs:47:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace_it_with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:60:9 + --> $DIR/question_mark.rs:51:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace_it_with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:64:17 + --> $DIR/question_mark.rs:55:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace_it_with: `Some(self.opt?)` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:81:9 + --> $DIR/question_mark.rs:72:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -44,7 +44,7 @@ LL | | } | |_________^ help: replace_it_with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:89:9 + --> $DIR/question_mark.rs:80:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -52,7 +52,7 @@ LL | | } | |_________^ help: replace_it_with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:97:9 + --> $DIR/question_mark.rs:88:9 | LL | / if self.opt.is_none() { LL | | return None; diff --git a/tests/ui/range.rs b/tests/ui/range.rs index 1eab67e20d0..d0c5cc93bd9 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct NotARange; impl NotARange { fn step_by(&self, _: u32) {} diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index b9a0a10c207..387d1f674cb 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -1,5 +1,5 @@ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:17:13 + --> $DIR/range.rs:8:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | let _ = (0..1).step_by(0); = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:21:13 + --> $DIR/range.rs:12:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:22:13 + --> $DIR/range.rs:13:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:25:13 + --> $DIR/range.rs:16:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: It is more idiomatic to use v1.iter().enumerate() - --> $DIR/range.rs:33:14 + --> $DIR/range.rs:24:14 | LL | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _x = v1.iter().zip(0..v1.len()); = note: `-D clippy::range-zip-with-len` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:37:13 + --> $DIR/range.rs:28:13 | LL | let _ = v1.iter().step_by(2 / 3); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index d8c955ba73f..54aec853d3b 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn f() -> usize { 42 } diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index b1c93933ccc..9ebc22e1625 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:19:14 + --> $DIR/range_plus_minus_one.rs:10:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {} = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:22:14 + --> $DIR/range_plus_minus_one.rs:13:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:25:14 + --> $DIR/range_plus_minus_one.rs:16:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:14 + --> $DIR/range_plus_minus_one.rs:22:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:35:13 + --> $DIR/range_plus_minus_one.rs:26:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -33,19 +33,19 @@ LL | let _ = ..=11 - 1; = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:36:13 + --> $DIR/range_plus_minus_one.rs:27:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:37:13 + --> $DIR/range_plus_minus_one.rs:28:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:38:13 + --> $DIR/range_plus_minus_one.rs:29:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 09d4d392725..6e9ad71e55b 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,12 +1,3 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::redundant_clone)] use std::ffi::OsString; diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index aef6b9b3d2f..c8f6cacab2b 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -1,120 +1,120 @@ error: redundant clone - --> $DIR/redundant_clone.rs:16:41 + --> $DIR/redundant_clone.rs:7:41 | LL | let _ = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` note: this value is dropped without further use - --> $DIR/redundant_clone.rs:16:13 + --> $DIR/redundant_clone.rs:7:13 | LL | let _ = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:19:14 + --> $DIR/redundant_clone.rs:10:14 | LL | let _ = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:19:13 + --> $DIR/redundant_clone.rs:10:13 | LL | let _ = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:22:14 + --> $DIR/redundant_clone.rs:13:14 | LL | let _ = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:22:13 + --> $DIR/redundant_clone.rs:13:13 | LL | let _ = s.to_string(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:25:14 + --> $DIR/redundant_clone.rs:16:14 | LL | let _ = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:25:13 + --> $DIR/redundant_clone.rs:16:13 | LL | let _ = s.to_owned(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:27:41 + --> $DIR/redundant_clone.rs:18:41 | LL | let _ = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:27:13 + --> $DIR/redundant_clone.rs:18:13 | LL | let _ = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:29:41 + --> $DIR/redundant_clone.rs:20:41 | LL | let _ = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:29:13 + --> $DIR/redundant_clone.rs:20:13 | LL | let _ = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:31:28 + --> $DIR/redundant_clone.rs:22:28 | LL | let _ = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:31:13 + --> $DIR/redundant_clone.rs:22:13 | LL | let _ = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:33:28 + --> $DIR/redundant_clone.rs:24:28 | LL | let _ = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:33:13 + --> $DIR/redundant_clone.rs:24:13 | LL | let _ = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:40:18 + --> $DIR/redundant_clone.rs:31:18 | LL | let _ = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:40:13 + --> $DIR/redundant_clone.rs:31:13 | LL | let _ = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:50:22 + --> $DIR/redundant_clone.rs:41:22 | LL | (a.clone(), a.clone()) | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:50:21 + --> $DIR/redundant_clone.rs:41:21 | LL | (a.clone(), a.clone()) | ^ diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index 46c56922974..2304871f213 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::redundant_closure_call)] fn main() { diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call.stderr index 6a41a07bd95..9c827fd8f17 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call.stderr @@ -1,5 +1,5 @@ error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:21:5 + --> $DIR/redundant_closure_call.rs:12:5 | LL | i = closure(); | ^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | i = closure(); = note: `-D clippy::redundant-closure-call` implied by `-D warnings` error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:24:5 + --> $DIR/redundant_closure_call.rs:15:5 | LL | i = closure(3); | ^^^^^^^^^^^^^^ error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:13:13 + --> $DIR/redundant_closure_call.rs:4:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: Try doing something like: : `42` error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:16:17 + --> $DIR/redundant_closure_call.rs:7:17 | LL | let mut k = (|m| m + 1)(i); | ^^^^^^^^^^^^^^ error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:18:9 + --> $DIR/redundant_closure_call.rs:9:9 | LL | k = (|a, b| a * b)(1, 5); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index 60569372e5d..f5c3fa66224 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::redundant_field_names)] #![allow(unused_variables)] #![feature(inclusive_range, inclusive_range_fields, inclusive_range_methods)] diff --git a/tests/ui/redundant_field_names.stderr b/tests/ui/redundant_field_names.stderr index 5675f8beb7a..7976292df22 100644 --- a/tests/ui/redundant_field_names.stderr +++ b/tests/ui/redundant_field_names.stderr @@ -1,5 +1,5 @@ error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:43:9 + --> $DIR/redundant_field_names.rs:34:9 | LL | gender: gender, | ^^^^^^^^^^^^^^ help: replace it with: `gender` @@ -7,37 +7,37 @@ LL | gender: gender, = note: `-D clippy::redundant-field-names` implied by `-D warnings` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:44:9 + --> $DIR/redundant_field_names.rs:35:9 | LL | age: age, | ^^^^^^^^ help: replace it with: `age` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:65:25 + --> $DIR/redundant_field_names.rs:56:25 | LL | let _ = RangeFrom { start: start }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:66:23 + --> $DIR/redundant_field_names.rs:57:23 | LL | let _ = RangeTo { end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:67:21 + --> $DIR/redundant_field_names.rs:58:21 | LL | let _ = Range { start: start, end: end }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:67:35 + --> $DIR/redundant_field_names.rs:58:35 | LL | let _ = Range { start: start, end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> $DIR/redundant_field_names.rs:69:32 + --> $DIR/redundant_field_names.rs:60:32 | LL | let _ = RangeToInclusive { end: end }; | ^^^^^^^^ help: replace it with: `end` diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 3744695a535..8e8d4b59ba4 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 0511fbc7e09..baed95d6f2e 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:14:12 + --> $DIR/redundant_pattern_matching.rs:5:12 | LL | if let Ok(_) = Ok::<i32, i32>(42) {} | -------^^^^^------------------------ help: try this: `if Ok::<i32, i32>(42).is_ok()` @@ -7,25 +7,25 @@ LL | if let Ok(_) = Ok::<i32, i32>(42) {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:16:12 + --> $DIR/redundant_pattern_matching.rs:7:12 | LL | if let Err(_) = Err::<i32, i32>(42) {} | -------^^^^^^------------------------- help: try this: `if Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:18:12 + --> $DIR/redundant_pattern_matching.rs:9:12 | LL | if let None = None::<()> {} | -------^^^^---------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:20:12 + --> $DIR/redundant_pattern_matching.rs:11:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^-------------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:34:5 + --> $DIR/redundant_pattern_matching.rs:25:5 | LL | / match Ok::<i32, i32>(42) { LL | | Ok(_) => true, @@ -34,7 +34,7 @@ LL | | }; | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:39:5 + --> $DIR/redundant_pattern_matching.rs:30:5 | LL | / match Ok::<i32, i32>(42) { LL | | Ok(_) => false, @@ -43,7 +43,7 @@ LL | | }; | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:44:5 + --> $DIR/redundant_pattern_matching.rs:35:5 | LL | / match Err::<i32, i32>(42) { LL | | Ok(_) => false, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:49:5 + --> $DIR/redundant_pattern_matching.rs:40:5 | LL | / match Err::<i32, i32>(42) { LL | | Ok(_) => true, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:54:5 + --> $DIR/redundant_pattern_matching.rs:45:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -70,7 +70,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:59:5 + --> $DIR/redundant_pattern_matching.rs:50:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs index bab0c21ffd9..c63997fa858 100644 --- a/tests/ui/reference.rs +++ b/tests/ui/reference.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn get_number() -> usize { 10 } diff --git a/tests/ui/reference.stderr b/tests/ui/reference.stderr index eaaacc7bcbe..aea95a7fa9f 100644 --- a/tests/ui/reference.stderr +++ b/tests/ui/reference.stderr @@ -1,5 +1,5 @@ error: immediately dereferencing a reference - --> $DIR/reference.rs:25:13 + --> $DIR/reference.rs:16:13 | LL | let b = *&a; | ^^^ help: try this: `a` @@ -7,61 +7,61 @@ LL | let b = *&a; = note: `-D clippy::deref-addrof` implied by `-D warnings` error: immediately dereferencing a reference - --> $DIR/reference.rs:27:13 + --> $DIR/reference.rs:18:13 | LL | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try this: `get_number()` error: immediately dereferencing a reference - --> $DIR/reference.rs:32:13 + --> $DIR/reference.rs:23:13 | LL | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` error: immediately dereferencing a reference - --> $DIR/reference.rs:36:13 + --> $DIR/reference.rs:27:13 | LL | let b = *&(a); | ^^^^^ help: try this: `(a)` error: immediately dereferencing a reference - --> $DIR/reference.rs:38:13 + --> $DIR/reference.rs:29:13 | LL | let b = *(&a); | ^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/reference.rs:41:13 + --> $DIR/reference.rs:32:13 | LL | let b = *((&a)); | ^^^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/reference.rs:43:13 + --> $DIR/reference.rs:34:13 | LL | let b = *&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/reference.rs:45:14 + --> $DIR/reference.rs:36:14 | LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/reference.rs:49:14 + --> $DIR/reference.rs:40:14 | LL | let b = **&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/reference.rs:53:17 + --> $DIR/reference.rs:44:17 | LL | let y = *&mut x; | ^^^^^^^ help: try this: `x` error: immediately dereferencing a reference - --> $DIR/reference.rs:60:18 + --> $DIR/reference.rs:51:18 | LL | let y = **&mut &mut x; | ^^^^^^^^^^^^ help: try this: `&mut x` diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 2d9c3482850..b523fa5b711 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused)] #![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)] diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index b6a4f6eb2af..1394a9b63bc 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -1,5 +1,5 @@ error: trivial regex - --> $DIR/regex.rs:22:45 + --> $DIR/regex.rs:13:45 | LL | let pipe_in_wrong_position = Regex::new("|"); | ^^^ @@ -8,7 +8,7 @@ LL | let pipe_in_wrong_position = Regex::new("|"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:23:60 + --> $DIR/regex.rs:14:60 | LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); | ^^^ @@ -16,7 +16,7 @@ LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); = help: the regex is unlikely to be useful as it is error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:24:42 + --> $DIR/regex.rs:15:42 | LL | let wrong_char_ranice = Regex::new("[z-a]"); | ^^^ @@ -24,19 +24,19 @@ LL | let wrong_char_ranice = Regex::new("[z-a]"); = note: `-D clippy::invalid-regex` implied by `-D warnings` error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:25:37 + --> $DIR/regex.rs:16:37 | LL | let some_unicode = Regex::new("[é-è]"); | ^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:27:33 + --> $DIR/regex.rs:18:33 | LL | let some_regex = Regex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: trivial regex - --> $DIR/regex.rs:29:53 + --> $DIR/regex.rs:20:53 | LL | let binary_pipe_in_wrong_position = BRegex::new("|"); | ^^^ @@ -44,43 +44,43 @@ LL | let binary_pipe_in_wrong_position = BRegex::new("|"); = help: the regex is unlikely to be useful as it is error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:30:41 + --> $DIR/regex.rs:21:41 | LL | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:31:56 + --> $DIR/regex.rs:22:56 | LL | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:43:37 + --> $DIR/regex.rs:34:37 | LL | let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ error: regex syntax error on position 0: unclosed group - --> $DIR/regex.rs:44:39 + --> $DIR/regex.rs:35:39 | LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:46:45 + --> $DIR/regex.rs:37:45 | LL | let raw_string_error = Regex::new(r"[...//...]"); | ^^ error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:47:46 + --> $DIR/regex.rs:38:46 | LL | let raw_string_error = Regex::new(r#"[...//...]"#); | ^^ error: trivial regex - --> $DIR/regex.rs:51:33 + --> $DIR/regex.rs:42:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:53:48 + --> $DIR/regex.rs:44:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:55:42 + --> $DIR/regex.rs:46:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -104,7 +104,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:57:40 + --> $DIR/regex.rs:48:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -112,7 +112,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:59:39 + --> $DIR/regex.rs:50:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -120,7 +120,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:61:39 + --> $DIR/regex.rs:52:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:63:40 + --> $DIR/regex.rs:54:40 | LL | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ @@ -136,7 +136,7 @@ LL | let trivial_backslash = Regex::new("a/.b"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:66:36 + --> $DIR/regex.rs:57:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -144,7 +144,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:68:36 + --> $DIR/regex.rs:59:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -152,7 +152,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:70:36 + --> $DIR/regex.rs:61:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -160,7 +160,7 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:72:44 + --> $DIR/regex.rs:63:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index eb08f1de63d..bd916fa7196 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(stutter)] #[warn(clippy::stutter)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 074e3527e8a..58d2c98f890 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: unknown lint: `stutter` - --> $DIR/rename.rs:10:10 + --> $DIR/rename.rs:1:10 | LL | #![allow(stutter)] | ^^^^^^^ @@ -7,7 +7,7 @@ LL | #![allow(stutter)] = note: `-D unknown-lints` implied by `-D warnings` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:12:8 + --> $DIR/rename.rs:3:8 | LL | #[warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` @@ -15,7 +15,7 @@ LL | #[warn(clippy::stutter)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:15:8 + --> $DIR/rename.rs:6:8 | LL | #[warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` diff --git a/tests/ui/replace_consts.rs b/tests/ui/replace_consts.rs index ca3d3b13edc..225d9bcbc0f 100644 --- a/tests/ui/replace_consts.rs +++ b/tests/ui/replace_consts.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(integer_atomics)] #![allow(clippy::blacklisted_name)] #![deny(clippy::replace_consts)] diff --git a/tests/ui/replace_consts.stderr b/tests/ui/replace_consts.stderr index e45f490463c..a2887fd4aad 100644 --- a/tests/ui/replace_consts.stderr +++ b/tests/ui/replace_consts.stderr @@ -1,215 +1,215 @@ error: using `ATOMIC_BOOL_INIT` - --> $DIR/replace_consts.rs:22:17 + --> $DIR/replace_consts.rs:13:17 | LL | { let foo = ATOMIC_BOOL_INIT; }; | ^^^^^^^^^^^^^^^^ help: try this: `AtomicBool::new(false)` | note: lint level defined here - --> $DIR/replace_consts.rs:12:9 + --> $DIR/replace_consts.rs:3:9 | LL | #![deny(clippy::replace_consts)] | ^^^^^^^^^^^^^^^^^^^^^^ error: using `ATOMIC_ISIZE_INIT` - --> $DIR/replace_consts.rs:23:17 + --> $DIR/replace_consts.rs:14:17 | LL | { let foo = ATOMIC_ISIZE_INIT; }; | ^^^^^^^^^^^^^^^^^ help: try this: `AtomicIsize::new(0)` error: using `ATOMIC_I8_INIT` - --> $DIR/replace_consts.rs:24:17 + --> $DIR/replace_consts.rs:15:17 | LL | { let foo = ATOMIC_I8_INIT; }; | ^^^^^^^^^^^^^^ help: try this: `AtomicI8::new(0)` error: using `ATOMIC_I16_INIT` - --> $DIR/replace_consts.rs:25:17 + --> $DIR/replace_consts.rs:16:17 | LL | { let foo = ATOMIC_I16_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI16::new(0)` error: using `ATOMIC_I32_INIT` - --> $DIR/replace_consts.rs:26:17 + --> $DIR/replace_consts.rs:17:17 | LL | { let foo = ATOMIC_I32_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI32::new(0)` error: using `ATOMIC_I64_INIT` - --> $DIR/replace_consts.rs:27:17 + --> $DIR/replace_consts.rs:18:17 | LL | { let foo = ATOMIC_I64_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicI64::new(0)` error: using `ATOMIC_USIZE_INIT` - --> $DIR/replace_consts.rs:28:17 + --> $DIR/replace_consts.rs:19:17 | LL | { let foo = ATOMIC_USIZE_INIT; }; | ^^^^^^^^^^^^^^^^^ help: try this: `AtomicUsize::new(0)` error: using `ATOMIC_U8_INIT` - --> $DIR/replace_consts.rs:29:17 + --> $DIR/replace_consts.rs:20:17 | LL | { let foo = ATOMIC_U8_INIT; }; | ^^^^^^^^^^^^^^ help: try this: `AtomicU8::new(0)` error: using `ATOMIC_U16_INIT` - --> $DIR/replace_consts.rs:30:17 + --> $DIR/replace_consts.rs:21:17 | LL | { let foo = ATOMIC_U16_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU16::new(0)` error: using `ATOMIC_U32_INIT` - --> $DIR/replace_consts.rs:31:17 + --> $DIR/replace_consts.rs:22:17 | LL | { let foo = ATOMIC_U32_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU32::new(0)` error: using `ATOMIC_U64_INIT` - --> $DIR/replace_consts.rs:32:17 + --> $DIR/replace_consts.rs:23:17 | LL | { let foo = ATOMIC_U64_INIT; }; | ^^^^^^^^^^^^^^^ help: try this: `AtomicU64::new(0)` error: using `MIN` - --> $DIR/replace_consts.rs:34:17 + --> $DIR/replace_consts.rs:25:17 | LL | { let foo = std::isize::MIN; }; | ^^^^^^^^^^^^^^^ help: try this: `isize::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:35:17 + --> $DIR/replace_consts.rs:26:17 | LL | { let foo = std::i8::MIN; }; | ^^^^^^^^^^^^ help: try this: `i8::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:36:17 + --> $DIR/replace_consts.rs:27:17 | LL | { let foo = std::i16::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i16::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:37:17 + --> $DIR/replace_consts.rs:28:17 | LL | { let foo = std::i32::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i32::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:38:17 + --> $DIR/replace_consts.rs:29:17 | LL | { let foo = std::i64::MIN; }; | ^^^^^^^^^^^^^ help: try this: `i64::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:39:17 + --> $DIR/replace_consts.rs:30:17 | LL | { let foo = std::i128::MIN; }; | ^^^^^^^^^^^^^^ help: try this: `i128::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:40:17 + --> $DIR/replace_consts.rs:31:17 | LL | { let foo = std::usize::MIN; }; | ^^^^^^^^^^^^^^^ help: try this: `usize::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:41:17 + --> $DIR/replace_consts.rs:32:17 | LL | { let foo = std::u8::MIN; }; | ^^^^^^^^^^^^ help: try this: `u8::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:42:17 + --> $DIR/replace_consts.rs:33:17 | LL | { let foo = std::u16::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u16::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:43:17 + --> $DIR/replace_consts.rs:34:17 | LL | { let foo = std::u32::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u32::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:44:17 + --> $DIR/replace_consts.rs:35:17 | LL | { let foo = std::u64::MIN; }; | ^^^^^^^^^^^^^ help: try this: `u64::min_value()` error: using `MIN` - --> $DIR/replace_consts.rs:45:17 + --> $DIR/replace_consts.rs:36:17 | LL | { let foo = std::u128::MIN; }; | ^^^^^^^^^^^^^^ help: try this: `u128::min_value()` error: using `MAX` - --> $DIR/replace_consts.rs:47:17 + --> $DIR/replace_consts.rs:38:17 | LL | { let foo = std::isize::MAX; }; | ^^^^^^^^^^^^^^^ help: try this: `isize::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:48:17 + --> $DIR/replace_consts.rs:39:17 | LL | { let foo = std::i8::MAX; }; | ^^^^^^^^^^^^ help: try this: `i8::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:49:17 + --> $DIR/replace_consts.rs:40:17 | LL | { let foo = std::i16::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i16::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:50:17 + --> $DIR/replace_consts.rs:41:17 | LL | { let foo = std::i32::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i32::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:51:17 + --> $DIR/replace_consts.rs:42:17 | LL | { let foo = std::i64::MAX; }; | ^^^^^^^^^^^^^ help: try this: `i64::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:52:17 + --> $DIR/replace_consts.rs:43:17 | LL | { let foo = std::i128::MAX; }; | ^^^^^^^^^^^^^^ help: try this: `i128::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:53:17 + --> $DIR/replace_consts.rs:44:17 | LL | { let foo = std::usize::MAX; }; | ^^^^^^^^^^^^^^^ help: try this: `usize::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:54:17 + --> $DIR/replace_consts.rs:45:17 | LL | { let foo = std::u8::MAX; }; | ^^^^^^^^^^^^ help: try this: `u8::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:55:17 + --> $DIR/replace_consts.rs:46:17 | LL | { let foo = std::u16::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u16::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:56:17 + --> $DIR/replace_consts.rs:47:17 | LL | { let foo = std::u32::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u32::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:57:17 + --> $DIR/replace_consts.rs:48:17 | LL | { let foo = std::u64::MAX; }; | ^^^^^^^^^^^^^ help: try this: `u64::max_value()` error: using `MAX` - --> $DIR/replace_consts.rs:58:17 + --> $DIR/replace_consts.rs:49:17 | LL | { let foo = std::u128::MAX; }; | ^^^^^^^^^^^^^^ help: try this: `u128::max_value()` diff --git a/tests/ui/result_map_unit_fn.rs b/tests/ui/result_map_unit_fn.rs index 3d731c9b350..a8e891d8db0 100644 --- a/tests/ui/result_map_unit_fn.rs +++ b/tests/ui/result_map_unit_fn.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] #![allow(unused)] diff --git a/tests/ui/result_map_unit_fn.stderr b/tests/ui/result_map_unit_fn.stderr index e462a07ad51..9f9025152e2 100644 --- a/tests/ui/result_map_unit_fn.stderr +++ b/tests/ui/result_map_unit_fn.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:43:5 + --> $DIR/result_map_unit_fn.rs:34:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:45:5 + --> $DIR/result_map_unit_fn.rs:36:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Ok(x_field) = x.field { do_nothing(...) }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:47:5 + --> $DIR/result_map_unit_fn.rs:38:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Ok(x_field) = x.field { diverge(...) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:53:5 + --> $DIR/result_map_unit_fn.rs:44:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_result_nothing(value + captured)); | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:55:5 + --> $DIR/result_map_unit_fn.rs:46:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:58:5 + --> $DIR/result_map_unit_fn.rs:49:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:60:5 + --> $DIR/result_map_unit_fn.rs:51:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:62:5 + --> $DIR/result_map_unit_fn.rs:53:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:64:5 + --> $DIR/result_map_unit_fn.rs:55:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:67:5 + --> $DIR/result_map_unit_fn.rs:58:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:69:5 + --> $DIR/result_map_unit_fn.rs:60:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:71:5 + --> $DIR/result_map_unit_fn.rs:62:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:73:5 + --> $DIR/result_map_unit_fn.rs:64:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:78:5 + --> $DIR/result_map_unit_fn.rs:69:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:80:5 + --> $DIR/result_map_unit_fn.rs:71:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:82:5 + --> $DIR/result_map_unit_fn.rs:73:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:85:5 + --> $DIR/result_map_unit_fn.rs:76:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:88:5 + --> $DIR/result_map_unit_fn.rs:79:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -145,7 +145,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:90:5 + --> $DIR/result_map_unit_fn.rs:81:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -153,7 +153,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:94:5 + --> $DIR/result_map_unit_fn.rs:85:5 | LL | x.field.map(|value| { | _____^ @@ -167,7 +167,7 @@ LL | || }); | error: called `map(f)` on an Result value where `f` is a unit closure - --> $DIR/result_map_unit_fn.rs:98:5 + --> $DIR/result_map_unit_fn.rs:89:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -175,7 +175,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:102:5 + --> $DIR/result_map_unit_fn.rs:93:5 | LL | "12".parse::<i32>().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -183,7 +183,7 @@ LL | "12".parse::<i32>().map(diverge); | help: try this: `if let Ok(_) = "12".parse::<i32>() { diverge(...) }` error: called `map(f)` on an Result value where `f` is a unit function - --> $DIR/result_map_unit_fn.rs:108:5 + --> $DIR/result_map_unit_fn.rs:99:5 | LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/result_map_unwrap_or_else.rs b/tests/ui/result_map_unwrap_or_else.rs index 0481e4ec1b0..40751bfebe6 100644 --- a/tests/ui/result_map_unwrap_or_else.rs +++ b/tests/ui/result_map_unwrap_or_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2019 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // aux-build:option_helpers.rs //! Checks implementation of `RESULT_MAP_UNWRAP_OR_ELSE` diff --git a/tests/ui/result_map_unwrap_or_else.stderr b/tests/ui/result_map_unwrap_or_else.stderr index 9f03de669e4..7674b91c128 100644 --- a/tests/ui/result_map_unwrap_or_else.stderr +++ b/tests/ui/result_map_unwrap_or_else.stderr @@ -1,5 +1,5 @@ error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:24:13 + --> $DIR/result_map_unwrap_or_else.rs:15:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even t = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:26:13 + --> $DIR/result_map_unwrap_or_else.rs:17:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:27:13 + --> $DIR/result_map_unwrap_or_else.rs:18:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index c52fd065dbe..5843344eba8 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::serde_api_misuse)] #![allow(dead_code)] diff --git a/tests/ui/serde.stderr b/tests/ui/serde.stderr index 61e54d53468..760c9c9908a 100644 --- a/tests/ui/serde.stderr +++ b/tests/ui/serde.stderr @@ -1,5 +1,5 @@ error: you should not implement `visit_string` without also implementing `visit_str` - --> $DIR/serde.rs:48:5 + --> $DIR/serde.rs:39:5 | LL | / fn visit_string<E>(self, _v: String) -> Result<Self::Value, E> LL | | where diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index e960a6252be..a9c77aca66f 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn( clippy::all, clippy::pedantic, diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 158933e9672..ada8b07d69b 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,135 +1,135 @@ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:29:5 + --> $DIR/shadow.rs:20:5 | LL | let x = &mut x; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:28:13 + --> $DIR/shadow.rs:19:13 | LL | let mut x = 1; | ^ error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:30:5 + --> $DIR/shadow.rs:21:5 | LL | let x = { x }; | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:20:9 | LL | let x = &mut x; | ^ error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:31:5 + --> $DIR/shadow.rs:22:5 | LL | let x = (&*x); | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:21:9 | LL | let x = { x }; | ^ error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:23:9 | LL | let x = { *x + 1 }; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:32:13 + --> $DIR/shadow.rs:23:13 | LL | let x = { *x + 1 }; | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:22:9 | LL | let x = (&*x); | ^ error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:33:9 + --> $DIR/shadow.rs:24:9 | LL | let x = id(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:33:13 + --> $DIR/shadow.rs:24:13 | LL | let x = id(x); | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:23:9 | LL | let x = { *x + 1 }; | ^ error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:34:9 + --> $DIR/shadow.rs:25:9 | LL | let x = (1, x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:34:13 + --> $DIR/shadow.rs:25:13 | LL | let x = (1, x); | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:33:9 + --> $DIR/shadow.rs:24:9 | LL | let x = id(x); | ^ error: `x` is shadowed by `first(x)` which reuses the original value - --> $DIR/shadow.rs:35:9 + --> $DIR/shadow.rs:26:9 | LL | let x = first(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:35:13 + --> $DIR/shadow.rs:26:13 | LL | let x = first(x); | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:34:9 + --> $DIR/shadow.rs:25:9 | LL | let x = (1, x); | ^ error: `x` is shadowed by `y` - --> $DIR/shadow.rs:37:9 + --> $DIR/shadow.rs:28:9 | LL | let x = y; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:37:13 + --> $DIR/shadow.rs:28:13 | LL | let x = y; | ^ note: previous binding is here - --> $DIR/shadow.rs:35:9 + --> $DIR/shadow.rs:26:9 | LL | let x = first(x); | ^ error: `x` shadows a previous declaration - --> $DIR/shadow.rs:39:5 + --> $DIR/shadow.rs:30:5 | LL | let x; | ^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:37:9 + --> $DIR/shadow.rs:28:9 | LL | let x = y; | ^ diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index efe9920dd88..84e736fe080 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::short_circuit_statement)] fn main() { diff --git a/tests/ui/short_circuit_statement.stderr b/tests/ui/short_circuit_statement.stderr index 4141a003fc4..a526766f698 100644 --- a/tests/ui/short_circuit_statement.stderr +++ b/tests/ui/short_circuit_statement.stderr @@ -1,5 +1,5 @@ error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:13:5 + --> $DIR/short_circuit_statement.rs:4:5 | LL | f() && g(); | ^^^^^^^^^^^ help: replace it with: `if f() { g(); }` @@ -7,13 +7,13 @@ LL | f() && g(); = note: `-D clippy::short-circuit-statement` implied by `-D warnings` error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:14:5 + --> $DIR/short_circuit_statement.rs:5:5 | LL | f() || g(); | ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> $DIR/short_circuit_statement.rs:15:5 + --> $DIR/short_circuit_statement.rs:6:5 | LL | 1 == 2 || g(); | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index c3c399f0ce3..220b855ead5 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix use std::collections::HashSet; diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index cf2fe66236a..9650eb2af32 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix use std::collections::HashSet; diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 7bc92a96536..82ef00bfee8 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -1,5 +1,5 @@ error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:16:13 + --> $DIR/single_char_pattern.rs:7:13 | LL | x.split("x"); | ^^^ help: try using a char instead: `'x'` @@ -7,115 +7,115 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:33:16 + --> $DIR/single_char_pattern.rs:24:16 | LL | x.contains("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:34:19 + --> $DIR/single_char_pattern.rs:25:19 | LL | x.starts_with("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:35:17 + --> $DIR/single_char_pattern.rs:26:17 | LL | x.ends_with("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:36:12 + --> $DIR/single_char_pattern.rs:27:12 | LL | x.find("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:13 + --> $DIR/single_char_pattern.rs:28:13 | LL | x.rfind("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:38:14 + --> $DIR/single_char_pattern.rs:29:14 | LL | x.rsplit("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:24 + --> $DIR/single_char_pattern.rs:30:24 | LL | x.split_terminator("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:40:25 + --> $DIR/single_char_pattern.rs:31:25 | LL | x.rsplit_terminator("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:41:17 + --> $DIR/single_char_pattern.rs:32:17 | LL | x.splitn(0, "x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:42:18 + --> $DIR/single_char_pattern.rs:33:18 | LL | x.rsplitn(0, "x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:43:15 + --> $DIR/single_char_pattern.rs:34:15 | LL | x.matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:44:16 + --> $DIR/single_char_pattern.rs:35:16 | LL | x.rmatches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:45:21 + --> $DIR/single_char_pattern.rs:36:21 | LL | x.match_indices("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:46:22 + --> $DIR/single_char_pattern.rs:37:22 | LL | x.rmatch_indices("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:47:26 + --> $DIR/single_char_pattern.rs:38:26 | LL | x.trim_start_matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:48:24 + --> $DIR/single_char_pattern.rs:39:24 | LL | x.trim_end_matches("x"); | ^^^ help: try using a char instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:50:13 + --> $DIR/single_char_pattern.rs:41:13 | LL | x.split("/n"); | ^^^^ help: try using a char instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:55:31 + --> $DIR/single_char_pattern.rs:46:31 | LL | x.replace(";", ",").split(","); // issue #2978 | ^^^ help: try using a char instead: `','` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:56:19 + --> $DIR/single_char_pattern.rs:47:19 | LL | x.starts_with("/x03"); // issue #2996 | ^^^^^^ help: try using a char instead: `'/x03'` diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 5a1bde3de32..99e88019cb8 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::single_match)] fn dummy() {} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 41776030800..445f702d0ce 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:17:5 + --> $DIR/single_match.rs:8:5 | LL | / match x { LL | | Some(y) => { @@ -18,7 +18,7 @@ LL | }; | error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:25:5 + --> $DIR/single_match.rs:16:5 | LL | / match x { LL | | // Note the missing block braces. @@ -30,7 +30,7 @@ LL | | } | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:34:5 + --> $DIR/single_match.rs:25:5 | LL | / match z { LL | | (2...3, 7...9) => dummy(), @@ -39,7 +39,7 @@ LL | | }; | |_____^ help: try this: `if let (2...3, 7...9) = z { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:63:5 + --> $DIR/single_match.rs:54:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -48,7 +48,7 @@ LL | | }; | |_____^ help: try this: `if let Some(y) = x { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:68:5 + --> $DIR/single_match.rs:59:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -57,7 +57,7 @@ LL | | }; | |_____^ help: try this: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:75:5 + --> $DIR/single_match.rs:66:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 18c26f7fc26..37a99de8832 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::single_match_else)] enum ExprNode { diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index ff780ad9667..3f29f5aaf6a 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:21:5 + --> $DIR/single_match_else.rs:12:5 | LL | / match ExprNode::Butterflies { LL | | ExprNode::ExprAddrOf => Some(&NODE), diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index cf11384467c..c5ae3ff769b 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::iter::repeat; fn main() { diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 319234386ac..5d2788ec260 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -1,5 +1,5 @@ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:22:5 + --> $DIR/slow_vector_initialization.rs:13:5 | LL | let mut vec1 = Vec::with_capacity(len); | ----------------------- help: consider replace allocation with: `vec![0; len]` @@ -9,7 +9,7 @@ LL | vec1.extend(repeat(0).take(len)); = note: `-D clippy::slow-vector-initialization` implied by `-D warnings` error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:26:5 + --> $DIR/slow_vector_initialization.rs:17:5 | LL | let mut vec2 = Vec::with_capacity(len - 10); | ---------------------------- help: consider replace allocation with: `vec![0; len - 10]` @@ -17,7 +17,7 @@ LL | vec2.extend(repeat(0).take(len - 10)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:40:5 + --> $DIR/slow_vector_initialization.rs:31:5 | LL | let mut resized_vec = Vec::with_capacity(30); | ---------------------- help: consider replace allocation with: `vec![0; 30]` @@ -25,7 +25,7 @@ LL | resized_vec.resize(30, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:43:5 + --> $DIR/slow_vector_initialization.rs:34:5 | LL | let mut extend_vec = Vec::with_capacity(30); | ---------------------- help: consider replace allocation with: `vec![0; 30]` @@ -33,7 +33,7 @@ LL | extend_vec.extend(repeat(0).take(30)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:50:5 + --> $DIR/slow_vector_initialization.rs:41:5 | LL | let mut vec1 = Vec::with_capacity(len); | ----------------------- help: consider replace allocation with: `vec![0; len]` @@ -41,7 +41,7 @@ LL | vec1.resize(len, 0); | ^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:58:5 + --> $DIR/slow_vector_initialization.rs:49:5 | LL | let mut vec3 = Vec::with_capacity(len - 10); | ---------------------------- help: consider replace allocation with: `vec![0; len - 10]` @@ -49,7 +49,7 @@ LL | vec3.resize(len - 10, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: slow zero-filling initialization - --> $DIR/slow_vector_initialization.rs:62:5 + --> $DIR/slow_vector_initialization.rs:53:5 | LL | vec1 = Vec::with_capacity(10); | ---------------------- help: consider replace allocation with: `vec![0; 10]` diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index 529c2487f54..a94c8c336df 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] fn main() {} diff --git a/tests/ui/starts_ends_with.stderr b/tests/ui/starts_ends_with.stderr index ed1ccad9814..0f95484da54 100644 --- a/tests/ui/starts_ends_with.stderr +++ b/tests/ui/starts_ends_with.stderr @@ -1,5 +1,5 @@ error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:16:5 + --> $DIR/starts_ends_with.rs:7:5 | LL | "".chars().next() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')` @@ -7,19 +7,19 @@ LL | "".chars().next() == Some(' '); = note: `-D clippy::chars-next-cmp` implied by `-D warnings` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:17:5 + --> $DIR/starts_ends_with.rs:8:5 | LL | Some(' ') != "".chars().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:22:8 + --> $DIR/starts_ends_with.rs:13:8 | LL | if s.chars().next().unwrap() == 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:26:8 + --> $DIR/starts_ends_with.rs:17:8 | LL | if s.chars().next_back().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` @@ -27,49 +27,49 @@ LL | if s.chars().next_back().unwrap() == 'o' { = note: `-D clippy::chars-last-cmp` implied by `-D warnings` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:30:8 + --> $DIR/starts_ends_with.rs:21:8 | LL | if s.chars().last().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` error: you should use the `starts_with` method - --> $DIR/starts_ends_with.rs:34:8 + --> $DIR/starts_ends_with.rs:25:8 | LL | if s.chars().next().unwrap() != 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:38:8 + --> $DIR/starts_ends_with.rs:29:8 | LL | if s.chars().next_back().unwrap() != 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:42:8 + --> $DIR/starts_ends_with.rs:33:8 | LL | if s.chars().last().unwrap() != 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:50:5 + --> $DIR/starts_ends_with.rs:41:5 | LL | "".chars().last() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:51:5 + --> $DIR/starts_ends_with.rs:42:5 | LL | Some(' ') != "".chars().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:52:5 + --> $DIR/starts_ends_with.rs:43:5 | LL | "".chars().next_back() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> $DIR/starts_ends_with.rs:53:5 + --> $DIR/starts_ends_with.rs:44:5 | LL | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index 7463baff2af..1883a9f8325 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[derive(Copy, Clone)] diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 3a2ad2695de..07d0baa1be6 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[derive(Copy, Clone)] diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index 5638dd87ed1..6af8c9e1662 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -1,5 +1,5 @@ error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:27:5 + --> $DIR/string_extend.rs:18:5 | LL | s.extend(abc.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` @@ -7,13 +7,13 @@ LL | s.extend(abc.chars()); = note: `-D clippy::string-extend-chars` implied by `-D warnings` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:30:5 + --> $DIR/string_extend.rs:21:5 | LL | s.extend("abc".chars()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:33:5 + --> $DIR/string_extend.rs:24:5 | LL | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index e15e80c1928..f0808eca829 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::string_add)] #[allow(clippy::string_add_assign)] fn add_only() { diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index a8c80939b55..e2e997f58e6 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> $DIR/strings.rs:17:9 + --> $DIR/strings.rs:8:9 | LL | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` @@ -7,7 +7,7 @@ LL | x = x + "."; = note: `-D clippy::assign-op-pattern` implied by `-D warnings` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:17:13 + --> $DIR/strings.rs:8:13 | LL | x = x + "."; | ^^^^^^^ @@ -15,13 +15,13 @@ LL | x = x + "."; = note: `-D clippy::string-add` implied by `-D warnings` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:21:13 + --> $DIR/strings.rs:12:13 | LL | let z = y + "..."; | ^^^^^^^^^ error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:31:9 + --> $DIR/strings.rs:22:9 | LL | x = x + "."; | ^^^^^^^^^^^ @@ -29,31 +29,31 @@ LL | x = x + "."; = note: `-D clippy::string-add-assign` implied by `-D warnings` error: manual implementation of an assign operation - --> $DIR/strings.rs:31:9 + --> $DIR/strings.rs:22:9 | LL | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:45:9 + --> $DIR/strings.rs:36:9 | LL | x = x + "."; | ^^^^^^^^^^^ error: manual implementation of an assign operation - --> $DIR/strings.rs:45:9 + --> $DIR/strings.rs:36:9 | LL | x = x + "."; | ^^^^^^^^^^^ help: replace it with: `x += "."` error: you added something to a string. Consider using `String::push_str()` instead - --> $DIR/strings.rs:49:13 + --> $DIR/strings.rs:40:13 | LL | let z = y + "..."; | ^^^^^^^^^ error: calling `as_bytes()` on a string literal - --> $DIR/strings.rs:57:14 + --> $DIR/strings.rs:48:14 | LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` @@ -61,13 +61,13 @@ LL | let bs = "hello there".as_bytes(); = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` error: calling `as_bytes()` on a string literal - --> $DIR/strings.rs:59:14 + --> $DIR/strings.rs:50:14 | LL | let bs = r###"raw string with three ### in it and some " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with three ### in it and some " ""###` error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/strings.rs:66:22 + --> $DIR/strings.rs:57:22 | LL | let includestr = include_str!("entry.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry.rs")` diff --git a/tests/ui/suspicious_arithmetic_impl.rs b/tests/ui/suspicious_arithmetic_impl.rs index ed845b7647a..6ee924d3b2e 100644 --- a/tests/ui/suspicious_arithmetic_impl.rs +++ b/tests/ui/suspicious_arithmetic_impl.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::suspicious_arithmetic_impl)] use std::ops::{Add, AddAssign, Div, Mul, Sub}; diff --git a/tests/ui/suspicious_arithmetic_impl.stderr b/tests/ui/suspicious_arithmetic_impl.stderr index 71cb08c77d7..f818f7b3d95 100644 --- a/tests/ui/suspicious_arithmetic_impl.stderr +++ b/tests/ui/suspicious_arithmetic_impl.stderr @@ -1,5 +1,5 @@ error: Suspicious use of binary operator in `Add` impl - --> $DIR/suspicious_arithmetic_impl.rs:20:20 + --> $DIR/suspicious_arithmetic_impl.rs:11:20 | LL | Foo(self.0 - other.0) | ^ @@ -7,7 +7,7 @@ LL | Foo(self.0 - other.0) = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` error: Suspicious use of binary operator in `AddAssign` impl - --> $DIR/suspicious_arithmetic_impl.rs:26:23 + --> $DIR/suspicious_arithmetic_impl.rs:17:23 | LL | *self = *self - other; | ^ diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 20fa9c87574..77cfc16ff6e 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(clippy::blacklisted_name, unused_assignments)] diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 25afaccd754..5d818cf2056 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:17:5 + --> $DIR/swap.rs:8:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -9,7 +9,7 @@ LL | | foo[1] = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:26:5 + --> $DIR/swap.rs:17:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -17,7 +17,7 @@ LL | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:35:5 + --> $DIR/swap.rs:26:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -25,7 +25,7 @@ LL | | foo[1] = temp; | |_________________^ help: try: `foo.swap(0, 1)` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:54:7 + --> $DIR/swap.rs:45:7 | LL | ; let t = a; | _______^ @@ -36,7 +36,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:63:7 + --> $DIR/swap.rs:54:7 | LL | ; let t = c.0; | _______^ @@ -47,7 +47,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:51:5 + --> $DIR/swap.rs:42:5 | LL | / a = b; LL | | b = a; @@ -57,7 +57,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:60:5 + --> $DIR/swap.rs:51:5 | LL | / c.0 = a; LL | | a = c.0; diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index 5581f5be766..c6c315d5fab 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::temporary_assignment)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 13ece2858b9..4efe2d4bb67 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:56:5 + --> $DIR/temporary_assignment.rs:47:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1; = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:57:5 + --> $DIR/temporary_assignment.rs:48:5 | LL | / MultiStruct { LL | | structure: Struct { field: 0 }, @@ -17,37 +17,37 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:62:5 + --> $DIR/temporary_assignment.rs:53:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:63:5 + --> $DIR/temporary_assignment.rs:54:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:65:5 + --> $DIR/temporary_assignment.rs:56:5 | LL | A.0 = 2; | ^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:66:5 + --> $DIR/temporary_assignment.rs:57:5 | LL | B.field = 2; | ^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:67:5 + --> $DIR/temporary_assignment.rs:58:5 | LL | C.structure.field = 2; | ^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:68:5 + --> $DIR/temporary_assignment.rs:59:5 | LL | D.array[0] = 2; | ^^^^^^^^^^^^^^ diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index b051746bbd4..711fb4f8aed 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(unused)] diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index 7b7a46d9f8e..00a753c6ac2 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -1,5 +1,5 @@ error: `ref` directly on a function argument is ignored. Consider using a reference type instead. - --> $DIR/toplevel_ref_arg.rs:13:15 + --> $DIR/toplevel_ref_arg.rs:4:15 | LL | fn the_answer(ref mut x: u8) { | ^^^^^^^^^ @@ -7,25 +7,25 @@ LL | fn the_answer(ref mut x: u8) { = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:24:9 + --> $DIR/toplevel_ref_arg.rs:15:9 | LL | let ref x = 1; | ----^^^^^----- help: try: `let x = &1;` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:26:9 + --> $DIR/toplevel_ref_arg.rs:17:9 | LL | let ref y: (&_, u8) = (&1, 2); | ----^^^^^--------------------- help: try: `let y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:28:9 + --> $DIR/toplevel_ref_arg.rs:19:9 | LL | let ref z = 1 + 2; | ----^^^^^--------- help: try: `let z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:30:9 + --> $DIR/toplevel_ref_arg.rs:21:9 | LL | let ref mut z = 1 + 2; | ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);` diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 9afb3399c59..4ee5ecffb87 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(stmt_expr_attributes)] #![allow(unused_parens)] diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr index 1675eb44efd..61289b24471 100644 --- a/tests/ui/trailing_zeros.stderr +++ b/tests/ui/trailing_zeros.stderr @@ -1,5 +1,5 @@ error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:16:5 + --> $DIR/trailing_zeros.rs:7:5 | LL | (x & 0b1111 == 0); // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4` @@ -7,7 +7,7 @@ LL | (x & 0b1111 == 0); // suggest trailing_zeros = note: `-D clippy::verbose-bit-mask` implied by `-D warnings` error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/trailing_zeros.rs:17:13 + --> $DIR/trailing_zeros.rs:8:13 | LL | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index b27014201cd..86964f8480a 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] extern crate core; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index a6e87a72104..ceee86d224d 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a type (`&'a T`) to itself - --> $DIR/transmute.rs:28:20 + --> $DIR/transmute.rs:19:20 | LL | let _: &'a T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | let _: &'a T = core::intrinsics::transmute(t); = note: `-D clippy::useless-transmute` implied by `-D warnings` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:32:23 + --> $DIR/transmute.rs:23:23 | LL | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:34:21 + --> $DIR/transmute.rs:25:21 | LL | let _: *mut T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> $DIR/transmute.rs:36:23 + --> $DIR/transmute.rs:27:23 | LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> $DIR/transmute.rs:41:17 + --> $DIR/transmute.rs:32:17 | LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` @@ -33,103 +33,103 @@ LL | let _: &T = std::mem::transmute(p); = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:44:21 + --> $DIR/transmute.rs:35:21 | LL | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> $DIR/transmute.rs:47:17 + --> $DIR/transmute.rs:38:17 | LL | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:50:21 + --> $DIR/transmute.rs:41:21 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> $DIR/transmute.rs:53:17 + --> $DIR/transmute.rs:44:17 | LL | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> $DIR/transmute.rs:56:21 + --> $DIR/transmute.rs:47:21 | LL | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> $DIR/transmute.rs:59:17 + --> $DIR/transmute.rs:50:17 | LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`) - --> $DIR/transmute.rs:70:32 + --> $DIR/transmute.rs:61:32 | LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)` error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`) - --> $DIR/transmute.rs:72:33 + --> $DIR/transmute.rs:63:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> $DIR/transmute.rs:76:14 + --> $DIR/transmute.rs:67:14 | LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:82:27 + --> $DIR/transmute.rs:73:27 | LL | let _: Vec<i32> = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:84:27 + --> $DIR/transmute.rs:75:27 | LL | let _: Vec<i32> = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:86:27 + --> $DIR/transmute.rs:77:27 | LL | let _: Vec<i32> = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:88:27 + --> $DIR/transmute.rs:79:27 | LL | let _: Vec<i32> = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> $DIR/transmute.rs:90:27 + --> $DIR/transmute.rs:81:27 | LL | let _: Vec<i32> = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> $DIR/transmute.rs:98:31 + --> $DIR/transmute.rs:89:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> $DIR/transmute.rs:102:31 + --> $DIR/transmute.rs:93:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:117:24 + --> $DIR/transmute.rs:108:24 | LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,25 +137,25 @@ LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); = note: `-D clippy::crosspointer-transmute` implied by `-D warnings` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:119:24 + --> $DIR/transmute.rs:110:24 | LL | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> $DIR/transmute.rs:121:31 + --> $DIR/transmute.rs:112:31 | LL | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> $DIR/transmute.rs:123:29 + --> $DIR/transmute.rs:114:29 | LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:129:28 + --> $DIR/transmute.rs:120:28 | LL | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` @@ -163,13 +163,13 @@ LL | let _: char = unsafe { std::mem::transmute(0_u32) }; = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:130:28 + --> $DIR/transmute.rs:121:28 | LL | let _: char = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:135:28 + --> $DIR/transmute.rs:126:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -177,7 +177,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:140:27 + --> $DIR/transmute.rs:131:27 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -185,13 +185,13 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:141:27 + --> $DIR/transmute.rs:132:27 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:145:28 + --> $DIR/transmute.rs:136:28 | LL | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` @@ -199,13 +199,13 @@ LL | let _: &str = unsafe { std::mem::transmute(b) }; = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:146:32 + --> $DIR/transmute.rs:137:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:178:29 + --> $DIR/transmute.rs:169:29 | LL | let _: *const f32 = std::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32` @@ -213,31 +213,31 @@ LL | let _: *const f32 = std::mem::transmute(ptr); = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:179:27 + --> $DIR/transmute.rs:170:27 | LL | let _: *mut f32 = std::mem::transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32` error: transmute from a reference to a reference - --> $DIR/transmute.rs:181:23 + --> $DIR/transmute.rs:172:23 | LL | let _: &f32 = std::mem::transmute(&1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:182:23 + --> $DIR/transmute.rs:173:23 | LL | let _: &f64 = std::mem::transmute(&1f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:185:27 + --> $DIR/transmute.rs:176:27 | LL | let _: &mut f32 = std::mem::transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:186:37 + --> $DIR/transmute.rs:177:37 | LL | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index dd96e2dabe1..1b50133d391 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-x86_64 #[warn(wrong_transmute)] diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index fbc298e3a06..aee5152d647 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-x86 //no-ignore-x86_64 diff --git a/tests/ui/transmute_64bit.stderr b/tests/ui/transmute_64bit.stderr index bbca3bc0b36..457050ec504 100644 --- a/tests/ui/transmute_64bit.stderr +++ b/tests/ui/transmute_64bit.stderr @@ -1,5 +1,5 @@ error: transmute from a `f64` to a pointer - --> $DIR/transmute_64bit.rs:16:31 + --> $DIR/transmute_64bit.rs:7:31 | LL | let _: *const usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _: *const usize = std::mem::transmute(6.0f64); = note: `-D clippy::wrong-transmute` implied by `-D warnings` error: transmute from a `f64` to a pointer - --> $DIR/transmute_64bit.rs:18:29 + --> $DIR/transmute_64bit.rs:9:29 | LL | let _: *mut usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 94e0113e56c..c12d9856501 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( clippy::many_single_char_names, clippy::blacklisted_name, diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 6f2967bc392..754069b421c 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:56:11 + --> $DIR/trivially_copy_pass_by_ref.rs:47:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -7,85 +7,85 @@ LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:56:20 + --> $DIR/trivially_copy_pass_by_ref.rs:47:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:56:29 + --> $DIR/trivially_copy_pass_by_ref.rs:47:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:63:12 + --> $DIR/trivially_copy_pass_by_ref.rs:54:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:63:22 + --> $DIR/trivially_copy_pass_by_ref.rs:54:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:63:31 + --> $DIR/trivially_copy_pass_by_ref.rs:54:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:63:40 + --> $DIR/trivially_copy_pass_by_ref.rs:54:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:65:16 + --> $DIR/trivially_copy_pass_by_ref.rs:56:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:65:25 + --> $DIR/trivially_copy_pass_by_ref.rs:56:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:65:34 + --> $DIR/trivially_copy_pass_by_ref.rs:56:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:77:16 + --> $DIR/trivially_copy_pass_by_ref.rs:68:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:77:25 + --> $DIR/trivially_copy_pass_by_ref.rs:68:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:77:34 + --> $DIR/trivially_copy_pass_by_ref.rs:68:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:81:34 + --> $DIR/trivially_copy_pass_by_ref.rs:72:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument is passed by reference, but would be more efficient if passed by value - --> $DIR/trivially_copy_pass_by_ref.rs:85:37 + --> $DIR/trivially_copy_pass_by_ref.rs:76:37 | LL | fn trait_method2(&self, _color: &Color); | ^^^^^^ help: consider passing by value instead: `Color` diff --git a/tests/ui/ty_fn_sig.rs b/tests/ui/ty_fn_sig.rs index 17027306367..9e2753dcb18 100644 --- a/tests/ui/ty_fn_sig.rs +++ b/tests/ui/ty_fn_sig.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Regression test pub fn retry<F: Fn()>(f: F) { diff --git a/tests/ui/types.rs b/tests/ui/types.rs index f0ede2fd48c..45846d6eef8 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // should not warn on lossy casting in constant types // because not supported yet const C: i32 = 42; diff --git a/tests/ui/types.stderr b/tests/ui/types.stderr index 76dc07aef31..97cce7add03 100644 --- a/tests/ui/types.stderr +++ b/tests/ui/types.stderr @@ -1,5 +1,5 @@ error: casting i32 to i64 may become silently lossy if types change - --> $DIR/types.rs:18:22 + --> $DIR/types.rs:9:22 | LL | let c_i64: i64 = c as i64; | ^^^^^^^^ help: try: `i64::from(c)` diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 0e1200db227..deec885b85d 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[warn(clippy::zero_width_space)] fn zero() { print!("Here >​< is a ZWS, and ​another"); diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 9b78271e1fa..c60dcdaec1d 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,5 +1,5 @@ error: zero-width space detected - --> $DIR/unicode.rs:12:12 + --> $DIR/unicode.rs:3:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | print!("Here >​< is a ZWS, and ​another"); ""Here >/u{200B}< is a ZWS, and /u{200B}another"" error: non-nfc unicode sequence detected - --> $DIR/unicode.rs:18:12 + --> $DIR/unicode.rs:9:12 | LL | print!("̀àh?"); | ^^^^^ @@ -19,7 +19,7 @@ LL | print!("̀àh?"); ""̀àh?"" error: literal non-ASCII character detected - --> $DIR/unicode.rs:24:12 + --> $DIR/unicode.rs:15:12 | LL | print!("Üben!"); | ^^^^^^^ diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 571882ced0f..7e421a0d605 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::unit_arg)] #![allow(clippy::no_effect)] diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 013016574ff..1da00b6f5e9 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:9 + --> $DIR/unit_arg.rs:23:9 | LL | foo({}); | ^^ @@ -11,7 +11,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:9 + --> $DIR/unit_arg.rs:24:9 | LL | foo({ | _________^ @@ -24,7 +24,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:36:9 + --> $DIR/unit_arg.rs:27:9 | LL | foo(foo(1)); | ^^^^^^ @@ -34,7 +34,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:37:9 + --> $DIR/unit_arg.rs:28:9 | LL | foo({ | _________^ @@ -48,7 +48,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:41:10 + --> $DIR/unit_arg.rs:32:10 | LL | foo3({}, 2, 2); | ^^ @@ -58,7 +58,7 @@ LL | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:43:11 + --> $DIR/unit_arg.rs:34:11 | LL | b.bar({ | ___________^ diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index 0bc87f43c15..48c22f7f875 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::unit_cmp)] #![allow(clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 481891b99b0..56293403043 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -1,5 +1,5 @@ error: ==-comparison of unit values detected. This will always be true - --> $DIR/unit_cmp.rs:21:8 + --> $DIR/unit_cmp.rs:12:8 | LL | if { | ________^ @@ -12,7 +12,7 @@ LL | | } {} = note: `-D clippy::unit-cmp` implied by `-D warnings` error: >-comparison of unit values detected. This will always be false - --> $DIR/unit_cmp.rs:27:8 + --> $DIR/unit_cmp.rs:18:8 | LL | if { | ________^ diff --git a/tests/ui/unknown_clippy_lints.rs b/tests/ui/unknown_clippy_lints.rs index e583614a93c..0a93c814d96 100644 --- a/tests/ui/unknown_clippy_lints.rs +++ b/tests/ui/unknown_clippy_lints.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::All)] #![warn(clippy::pedantic)] diff --git a/tests/ui/unknown_clippy_lints.stderr b/tests/ui/unknown_clippy_lints.stderr index f83a51728e7..3c86432a972 100644 --- a/tests/ui/unknown_clippy_lints.stderr +++ b/tests/ui/unknown_clippy_lints.stderr @@ -1,5 +1,5 @@ error: unknown clippy lint: clippy::if_not_els - --> $DIR/unknown_clippy_lints.rs:13:8 + --> $DIR/unknown_clippy_lints.rs:4:8 | LL | #[warn(clippy::if_not_els)] | ^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[warn(clippy::if_not_els)] = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` error: unknown clippy lint: clippy::All - --> $DIR/unknown_clippy_lints.rs:10:10 + --> $DIR/unknown_clippy_lints.rs:1:10 | LL | #![allow(clippy::All)] | ^^^^^^^^^^^ help: lowercase the lint name: `all` diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 40c4b4961e9..fee6b30a97b 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::clone_on_ref_ptr)] #![allow(unused)] diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 604902e5d6d..5cd9b2d337f 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -1,5 +1,5 @@ error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:26:5 + --> $DIR/unnecessary_clone.rs:17:5 | LL | 42.clone(); | ^^^^^^^^^^ help: try removing the `clone` call: `42` @@ -7,19 +7,19 @@ LL | 42.clone(); = note: `-D clippy::clone-on-copy` implied by `-D warnings` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:30:5 + --> $DIR/unnecessary_clone.rs:21:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:33:5 + --> $DIR/unnecessary_clone.rs:24:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:43:5 + --> $DIR/unnecessary_clone.rs:34:5 | LL | rc.clone(); | ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)` @@ -27,43 +27,43 @@ LL | rc.clone(); = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:46:5 + --> $DIR/unnecessary_clone.rs:37:5 | LL | arc.clone(); | ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:49:5 + --> $DIR/unnecessary_clone.rs:40:5 | LL | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:52:5 + --> $DIR/unnecessary_clone.rs:43:5 | LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:56:29 + --> $DIR/unnecessary_clone.rs:47:29 | LL | let _: Arc<SomeTrait> = x.clone(); | ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:60:5 + --> $DIR/unnecessary_clone.rs:51:5 | LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:62:5 + --> $DIR/unnecessary_clone.rs:53:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:68:22 + --> $DIR/unnecessary_clone.rs:59:22 | LL | let z: &Vec<_> = y.clone(); | ^^^^^^^^^ @@ -79,7 +79,7 @@ LL | let z: &Vec<_> = &std::vec::Vec<i32>::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/unnecessary_clone.rs:75:26 + --> $DIR/unnecessary_clone.rs:66:26 | LL | let v2: Vec<isize> = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | let v2: Vec<isize> = v.iter().cloned().collect(); = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:111:20 + --> $DIR/unnecessary_clone.rs:102:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs index a0c183a58cc..af858e4abcf 100644 --- a/tests/ui/unnecessary_filter_map.rs +++ b/tests/ui/unnecessary_filter_map.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); let _ = (0..4).filter_map(|x| { diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr index 09f8973708f..041829c3c78 100644 --- a/tests/ui/unnecessary_filter_map.stderr +++ b/tests/ui/unnecessary_filter_map.stderr @@ -1,5 +1,5 @@ error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:11:13 + --> $DIR/unnecessary_filter_map.rs:2:13 | LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings` error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:12:13 + --> $DIR/unnecessary_filter_map.rs:3:13 | LL | let _ = (0..4).filter_map(|x| { | _____________^ @@ -19,7 +19,7 @@ LL | | }); | |______^ error: this `.filter_map` can be written more simply using `.filter` - --> $DIR/unnecessary_filter_map.rs:18:13 + --> $DIR/unnecessary_filter_map.rs:9:13 | LL | let _ = (0..4).filter_map(|x| match x { | _____________^ @@ -29,7 +29,7 @@ LL | | }); | |______^ error: this `.filter_map` can be written more simply using `.map` - --> $DIR/unnecessary_filter_map.rs:23:13 + --> $DIR/unnecessary_filter_map.rs:14:13 | LL | let _ = (0..4).filter_map(|x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 4b4a6ee044c..62198e21ef7 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { // Can be replaced by .any diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index 2c2349bd3bc..07414b400c1 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -1,5 +1,5 @@ error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:13:19 + --> $DIR/unnecessary_fold.rs:4:19 | LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` @@ -7,25 +7,25 @@ LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); = note: `-D clippy::unnecessary-fold` implied by `-D warnings` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:15:19 + --> $DIR/unnecessary_fold.rs:6:19 | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:17:19 + --> $DIR/unnecessary_fold.rs:8:19 | LL | let _ = (0..3).fold(0, |acc, x| acc + x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.sum()` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:19:19 + --> $DIR/unnecessary_fold.rs:10:19 | LL | let _ = (0..3).fold(1, |acc, x| acc * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.product()` error: this `.fold` can be written more succinctly using another method - --> $DIR/unnecessary_fold.rs:24:34 + --> $DIR/unnecessary_fold.rs:15:34 | LL | let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 34e1112f006..3c6796fea7b 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] #![allow(clippy::deref_addrof)] #![warn(clippy::unnecessary_operation)] diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index e46002dd97b..826bf6e2c28 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: statement can be reduced - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:45:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` @@ -7,109 +7,109 @@ LL | Tuple(get_number()); = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:46:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:47:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:48:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:49:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:50:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:60:5 + --> $DIR/unnecessary_operation.rs:51:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:52:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:53:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:54:5 | LL | box get_number(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:55:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:56:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:57:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:58:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:68:5 + --> $DIR/unnecessary_operation.rs:59:5 | LL | [42, 55][get_number() as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_number() as usize;` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:69:5 + --> $DIR/unnecessary_operation.rs:60:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:70:5 + --> $DIR/unnecessary_operation.rs:61:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:71:5 + --> $DIR/unnecessary_operation.rs:62:5 | LL | [42; 55][get_number() as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_number() as usize;` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:72:5 + --> $DIR/unnecessary_operation.rs:63:5 | LL | / { LL | | get_number() @@ -117,7 +117,7 @@ LL | | }; | |______^ help: replace it with: `get_number();` error: statement can be reduced - --> $DIR/unnecessary_operation.rs:75:5 + --> $DIR/unnecessary_operation.rs:66:5 | LL | / FooString { LL | | s: String::from("blah"), diff --git a/tests/ui/unnecessary_ref.fixed b/tests/ui/unnecessary_ref.fixed index 3617641a116..f7b94118d4e 100644 --- a/tests/ui/unnecessary_ref.fixed +++ b/tests/ui/unnecessary_ref.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![feature(stmt_expr_attributes)] diff --git a/tests/ui/unnecessary_ref.rs b/tests/ui/unnecessary_ref.rs index 48101c87a54..4e585b9b96b 100644 --- a/tests/ui/unnecessary_ref.rs +++ b/tests/ui/unnecessary_ref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![feature(stmt_expr_attributes)] diff --git a/tests/ui/unnecessary_ref.stderr b/tests/ui/unnecessary_ref.stderr index 863a6389e7f..89adca3b1ad 100644 --- a/tests/ui/unnecessary_ref.stderr +++ b/tests/ui/unnecessary_ref.stderr @@ -1,11 +1,11 @@ error: Creating a reference that is immediately dereferenced. - --> $DIR/unnecessary_ref.rs:22:17 + --> $DIR/unnecessary_ref.rs:13:17 | LL | let inner = (&outer).inner; | ^^^^^^^^ help: try this: `outer` | note: lint level defined here - --> $DIR/unnecessary_ref.rs:19:8 + --> $DIR/unnecessary_ref.rs:10:8 | LL | #[deny(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index 14676c1e76f..fa639aa70d6 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::unneeded_field_pattern)] #[allow(dead_code, unused)] diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index 23e35923f83..e7b92ce1e19 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -1,5 +1,5 @@ error: You matched a field with a wildcard pattern. Consider using `..` instead - --> $DIR/unneeded_field_pattern.rs:23:15 + --> $DIR/unneeded_field_pattern.rs:14:15 | LL | Foo { a: _, b: 0, .. } => {}, | ^^^^ @@ -8,7 +8,7 @@ LL | Foo { a: _, b: 0, .. } => {}, = help: Try with `Foo { b: 0, .. }` error: All the struct fields are matched to a wildcard pattern, consider using `..`. - --> $DIR/unneeded_field_pattern.rs:25:9 + --> $DIR/unneeded_field_pattern.rs:16:9 | LL | Foo { a: _, b: _, c: _ } => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index 4c466035a04..eede10c771c 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::unreadable_literal)] diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 8ade2f6a863..6523f70186f 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #[warn(clippy::unreadable_literal)] diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 68580485853..8334139120e 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,5 +1,5 @@ error: long literal lacking separators - --> $DIR/unreadable_literal.rs:26:16 + --> $DIR/unreadable_literal.rs:17:16 | LL | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` @@ -7,25 +7,25 @@ LL | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32) = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:26:30 + --> $DIR/unreadable_literal.rs:17:30 | LL | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:26:51 + --> $DIR/unreadable_literal.rs:17:51 | LL | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:26:63 + --> $DIR/unreadable_literal.rs:17:63 | LL | let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:28:19 + --> $DIR/unreadable_literal.rs:19:19 | LL | let bad_sci = 1.123456e1; | ^^^^^^^^^^ help: consider: `1.123_456e1` diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index bfab077375d..a1f616733bd 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused_imports)] #![allow(dead_code)] #![warn(clippy::unsafe_removed_from_name)] diff --git a/tests/ui/unsafe_removed_from_name.stderr b/tests/ui/unsafe_removed_from_name.stderr index cdc2b907ec5..1b1c62430b2 100644 --- a/tests/ui/unsafe_removed_from_name.stderr +++ b/tests/ui/unsafe_removed_from_name.stderr @@ -1,5 +1,5 @@ error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCell` - --> $DIR/unsafe_removed_from_name.rs:14:1 + --> $DIR/unsafe_removed_from_name.rs:5:1 | LL | use std::cell::UnsafeCell as TotallySafeCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | use std::cell::UnsafeCell as TotallySafeCell; = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCellAgain` - --> $DIR/unsafe_removed_from_name.rs:16:1 + --> $DIR/unsafe_removed_from_name.rs:7:1 | LL | use std::cell::UnsafeCell as TotallySafeCellAgain; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed "unsafe" from the name of `Unsafe` in use as `LieAboutModSafety` - --> $DIR/unsafe_removed_from_name.rs:30:1 + --> $DIR/unsafe_removed_from_name.rs:21:1 | LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 4e721527249..c8a38f9fe57 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] #![warn(clippy::unused_io_amount)] diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 528d35ebdef..2d00338193c 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -1,5 +1,5 @@ error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:16:5 + --> $DIR/unused_io_amount.rs:7:5 | LL | try!(s.write(b"test")); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | try!(s.write(b"test")); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:18:5 + --> $DIR/unused_io_amount.rs:9:5 | LL | try!(s.read(&mut buf)); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,25 +16,25 @@ LL | try!(s.read(&mut buf)); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:23:5 + --> $DIR/unused_io_amount.rs:14:5 | LL | s.write(b"test")?; | ^^^^^^^^^^^^^^^^^ error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:25:5 + --> $DIR/unused_io_amount.rs:16:5 | LL | s.read(&mut buf)?; | ^^^^^^^^^^^^^^^^^ error: handle written amount returned or use `Write::write_all` instead - --> $DIR/unused_io_amount.rs:30:5 + --> $DIR/unused_io_amount.rs:21:5 | LL | s.write(b"test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: handle read amount returned or use `Read::read_exact` instead - --> $DIR/unused_io_amount.rs:32:5 + --> $DIR/unused_io_amount.rs:23:5 | LL | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs index 8db29dcf3fc..ae963ad6969 100644 --- a/tests/ui/unused_labels.rs +++ b/tests/ui/unused_labels.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code, clippy::items_after_statements, clippy::never_loop)] #![warn(clippy::unused_label)] diff --git a/tests/ui/unused_labels.stderr b/tests/ui/unused_labels.stderr index 07ff5083ed2..d2ca0f1b57f 100644 --- a/tests/ui/unused_labels.stderr +++ b/tests/ui/unused_labels.stderr @@ -1,5 +1,5 @@ error: unused label `'label` - --> $DIR/unused_labels.rs:14:5 + --> $DIR/unused_labels.rs:5:5 | LL | / 'label: for i in 1..2 { LL | | if i > 4 { @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::unused-label` implied by `-D warnings` error: unused label `'a` - --> $DIR/unused_labels.rs:28:5 + --> $DIR/unused_labels.rs:19:5 | LL | / 'a: loop { LL | | break; @@ -19,7 +19,7 @@ LL | | } | |_____^ error: unused label `'same_label_in_two_fns` - --> $DIR/unused_labels.rs:41:5 + --> $DIR/unused_labels.rs:32:5 | LL | / 'same_label_in_two_fns: loop { LL | | let _ = 1; diff --git a/tests/ui/unused_lt.rs b/tests/ui/unused_lt.rs index 99e80103f1f..ba7c42b3a90 100644 --- a/tests/ui/unused_lt.rs +++ b/tests/ui/unused_lt.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow( unused, dead_code, diff --git a/tests/ui/unused_lt.stderr b/tests/ui/unused_lt.stderr index 30ce7b68578..bf4aedd52a9 100644 --- a/tests/ui/unused_lt.stderr +++ b/tests/ui/unused_lt.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:23:14 + --> $DIR/unused_lt.rs:14:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,13 +7,13 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:25:25 + --> $DIR/unused_lt.rs:16:25 | LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/unused_lt.rs:50:10 + --> $DIR/unused_lt.rs:41:10 | LL | fn x<'a>(&self) {} | ^^ diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index 88f0b9687be..8d56d2051e2 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // compile-pass // The output for humans should just highlight the whole span without showing diff --git a/tests/ui/unused_unit.stderr b/tests/ui/unused_unit.stderr index ac76d75b176..c4cb643cb71 100644 --- a/tests/ui/unused_unit.stderr +++ b/tests/ui/unused_unit.stderr @@ -1,5 +1,5 @@ error: unneeded unit return type - --> $DIR/unused_unit.rs:25:59 + --> $DIR/unused_unit.rs:15:59 | LL | pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> | ___________________________________________________________^ @@ -7,43 +7,43 @@ LL | | () | |__________^ help: remove the `-> ()` | note: lint level defined here - --> $DIR/unused_unit.rs:19:9 + --> $DIR/unused_unit.rs:9:9 | LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ error: unneeded unit return type - --> $DIR/unused_unit.rs:35:19 + --> $DIR/unused_unit.rs:25:19 | LL | fn into(self) -> () { | ^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> $DIR/unused_unit.rs:36:9 + --> $DIR/unused_unit.rs:26:9 | LL | () | ^^ help: remove the final `()` error: unneeded unit return type - --> $DIR/unused_unit.rs:40:18 + --> $DIR/unused_unit.rs:30:18 | LL | fn return_unit() -> () { () } | ^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> $DIR/unused_unit.rs:40:26 + --> $DIR/unused_unit.rs:30:26 | LL | fn return_unit() -> () { () } | ^^ help: remove the final `()` error: unneeded `()` - --> $DIR/unused_unit.rs:47:14 + --> $DIR/unused_unit.rs:37:14 | LL | break(); | ^^ help: remove the `()` error: unneeded `()` - --> $DIR/unused_unit.rs:49:11 + --> $DIR/unused_unit.rs:39:11 | LL | return(); | ^^ help: remove the `()` diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index 8573f78d43b..bfb41e43947 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] fn main() { diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index 3970b68de7a..c3a7464fd47 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:13:47 + --> $DIR/unwrap_or.rs:4:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` @@ -7,7 +7,7 @@ LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()) = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:17:47 + --> $DIR/unwrap_or.rs:8:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` diff --git a/tests/ui/update-all-references.sh b/tests/ui/update-all-references.sh index acc38f15fbd..f438d442ca1 100755 --- a/tests/ui/update-all-references.sh +++ b/tests/ui/update-all-references.sh @@ -1,14 +1,4 @@ #!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. # A script to update the references for all tests. The idea is that # you do a run, which will generate files in the build directory diff --git a/tests/ui/update-references.sh b/tests/ui/update-references.sh index d6995985a3b..c553e4ef2e3 100755 --- a/tests/ui/update-references.sh +++ b/tests/ui/update-references.sh @@ -1,14 +1,4 @@ #!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. # A script to update the references for particular tests. The idea is # that you do a run, which will generate files in the build directory diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index a117ce5894b..b839aead95a 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::use_self)] #![allow(dead_code)] #![allow(clippy::should_implement_trait)] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 72b60db7fd2..9d23433ba64 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> $DIR/use_self.rs:20:21 + --> $DIR/use_self.rs:11:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -7,133 +7,133 @@ LL | fn new() -> Foo { = note: `-D clippy::use-self` implied by `-D warnings` error: unnecessary structure name repetition - --> $DIR/use_self.rs:21:13 + --> $DIR/use_self.rs:12:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:23:22 + --> $DIR/use_self.rs:14:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:24:13 + --> $DIR/use_self.rs:15:13 | LL | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:29:25 + --> $DIR/use_self.rs:20:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:30:13 + --> $DIR/use_self.rs:21:13 | LL | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:95:22 + --> $DIR/use_self.rs:86:22 | LL | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:95:31 + --> $DIR/use_self.rs:86:31 | LL | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:99:37 + --> $DIR/use_self.rs:90:37 | LL | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:99:53 + --> $DIR/use_self.rs:90:53 | LL | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:103:30 + --> $DIR/use_self.rs:94:30 | LL | fn mut_refs(p1: &mut Bad) -> &mut Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:103:43 + --> $DIR/use_self.rs:94:43 | LL | fn mut_refs(p1: &mut Bad) -> &mut Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:107:28 + --> $DIR/use_self.rs:98:28 | LL | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:107:46 + --> $DIR/use_self.rs:98:46 | LL | fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:109:20 + --> $DIR/use_self.rs:100:20 | LL | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:109:28 + --> $DIR/use_self.rs:100:28 | LL | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:110:13 + --> $DIR/use_self.rs:101:13 | LL | Bad::default() | ^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:115:23 + --> $DIR/use_self.rs:106:23 | LL | type Output = Bad; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:117:27 + --> $DIR/use_self.rs:108:27 | LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:117:35 + --> $DIR/use_self.rs:108:35 | LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:209:56 + --> $DIR/use_self.rs:200:56 | LL | fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:224:13 + --> $DIR/use_self.rs:215:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:232:25 + --> $DIR/use_self.rs:223:25 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -142,7 +142,7 @@ LL | use_self_expand!(); // Should lint in local macros | ------------------- in this macro invocation error: unnecessary structure name repetition - --> $DIR/use_self.rs:233:17 + --> $DIR/use_self.rs:224:17 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` @@ -151,13 +151,13 @@ LL | use_self_expand!(); // Should lint in local macros | ------------------- in this macro invocation error: unnecessary structure name repetition - --> $DIR/use_self.rs:255:29 + --> $DIR/use_self.rs:246:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:256:21 + --> $DIR/use_self.rs:247:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index bd20cc5f48a..702f1793ed5 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::all)] #![allow(clippy::blacklisted_name)] #![warn(clippy::used_underscore_binding)] diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 798dde2ea0e..2e2f2056d84 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,5 +1,5 @@ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:23:5 + --> $DIR/used_underscore_binding.rs:14:5 | LL | _foo + 1 | ^^^^ @@ -7,25 +7,25 @@ LL | _foo + 1 = note: `-D clippy::used-underscore-binding` implied by `-D warnings` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:28:20 + --> $DIR/used_underscore_binding.rs:19:20 | LL | println!("{}", _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:29:16 + --> $DIR/used_underscore_binding.rs:20:16 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:29:22 + --> $DIR/used_underscore_binding.rs:20:22 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used. - --> $DIR/used_underscore_binding.rs:42:5 + --> $DIR/used_underscore_binding.rs:33:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/useful_asref.rs b/tests/ui/useful_asref.rs index d7e56af2590..a9f0170a79c 100644 --- a/tests/ui/useful_asref.rs +++ b/tests/ui/useful_asref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::useless_asref)] trait Trait { diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index 34c0f5095db..fe3dae5fc4c 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![deny(clippy::useless_asref)] #![allow(clippy::trivially_copy_pass_by_ref)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 2e4a7f80444..cc594559032 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -1,71 +1,71 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:50:18 + --> $DIR/useless_asref.rs:41:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` | note: lint level defined here - --> $DIR/useless_asref.rs:10:9 + --> $DIR/useless_asref.rs:1:9 | LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:52:20 + --> $DIR/useless_asref.rs:43:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:56:21 + --> $DIR/useless_asref.rs:47:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:58:20 + --> $DIR/useless_asref.rs:49:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:65:20 + --> $DIR/useless_asref.rs:56:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:67:18 + --> $DIR/useless_asref.rs:58:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:72:21 + --> $DIR/useless_asref.rs:63:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:74:20 + --> $DIR/useless_asref.rs:65:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:77:16 + --> $DIR/useless_asref.rs:68:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:127:13 + --> $DIR/useless_asref.rs:118:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:129:12 + --> $DIR/useless_asref.rs:120:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 2d7a9ae04d1..7da251101f5 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::useless_attribute)] #[allow(dead_code)] diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index b9340ce8c02..2f7a010fc3e 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -1,5 +1,5 @@ error: useless lint attribute - --> $DIR/useless_attribute.rs:12:1 + --> $DIR/useless_attribute.rs:3:1 | LL | #[allow(dead_code)] | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]` @@ -7,7 +7,7 @@ LL | #[allow(dead_code)] = note: `-D clippy::useless-attribute` implied by `-D warnings` error: useless lint attribute - --> $DIR/useless_attribute.rs:13:1 + --> $DIR/useless_attribute.rs:4:1 | LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)` diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index 2eaba1c408a..e73a791891f 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![warn(clippy::useless_vec)] diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 1648215ed35..3eb960f53d7 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![warn(clippy::useless_vec)] diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 96dd187ccc5..37e28ebddb5 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -1,5 +1,5 @@ error: useless use of `vec!` - --> $DIR/vec.rs:32:14 + --> $DIR/vec.rs:23:14 | LL | on_slice(&vec![]); | ^^^^^^^ help: you can use a slice directly: `&[]` @@ -7,31 +7,31 @@ LL | on_slice(&vec![]); = note: `-D clippy::useless-vec` implied by `-D warnings` error: useless use of `vec!` - --> $DIR/vec.rs:35:14 + --> $DIR/vec.rs:26:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:38:14 + --> $DIR/vec.rs:29:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:41:14 + --> $DIR/vec.rs:32:14 | LL | on_slice(&vec!(1, 2)); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:44:14 + --> $DIR/vec.rs:35:14 | LL | on_slice(&vec![1; 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` error: useless use of `vec!` - --> $DIR/vec.rs:57:14 + --> $DIR/vec.rs:48:14 | LL | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index e4c7047df91..283a2d43c04 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::while_let_loop, clippy::empty_loop, clippy::while_let_on_iterator)] #![allow(dead_code, clippy::never_loop, unused, clippy::cyclomatic_complexity)] diff --git a/tests/ui/while_loop.stderr b/tests/ui/while_loop.stderr index 0e6c97e48d4..dde98da46c3 100644 --- a/tests/ui/while_loop.stderr +++ b/tests/ui/while_loop.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:15:5 + --> $DIR/while_loop.rs:6:5 | LL | / loop { LL | | if let Some(_x) = y { @@ -13,7 +13,7 @@ LL | | } = note: `-D clippy::while-let-loop` implied by `-D warnings` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:29:5 + --> $DIR/while_loop.rs:20:5 | LL | / loop { LL | | match y { @@ -24,7 +24,7 @@ LL | | } | |_____^ help: try: `while let Some(_x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:35:5 + --> $DIR/while_loop.rs:26:5 | LL | / loop { LL | | let x = match y { @@ -36,7 +36,7 @@ LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:43:5 + --> $DIR/while_loop.rs:34:5 | LL | / loop { LL | | let x = match y { @@ -48,7 +48,7 @@ LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:71:5 + --> $DIR/while_loop.rs:62:5 | LL | / loop { LL | | let (e, l) = match "".split_whitespace().next() { @@ -60,7 +60,7 @@ LL | | } | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:81:33 + --> $DIR/while_loop.rs:72:33 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^ help: try: `for x in iter { .. }` @@ -68,19 +68,19 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:86:25 + --> $DIR/while_loop.rs:77:25 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^ help: try: `for x in iter { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:91:25 + --> $DIR/while_loop.rs:82:25 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^ help: try: `for _ in iter { .. }` error: this loop could be written as a `while let` loop - --> $DIR/while_loop.rs:134:5 + --> $DIR/while_loop.rs:125:5 | LL | / loop { LL | | let _ = match iter.next() { @@ -92,7 +92,7 @@ LL | | } | |_____^ help: try: `while let Some(ele) = iter.next() { .. }` error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body. - --> $DIR/while_loop.rs:139:9 + --> $DIR/while_loop.rs:130:9 | LL | loop {} | ^^^^^^^ @@ -100,13 +100,13 @@ LL | loop {} = note: `-D clippy::empty-loop` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:197:29 + --> $DIR/while_loop.rs:188:29 | LL | while let Some(v) = y.next() { | ^^^^^^^^ help: try: `for v in y { .. }` error: this loop could be written as a `for` loop - --> $DIR/while_loop.rs:225:26 + --> $DIR/while_loop.rs:216:26 | LL | while let Some(..) = values.iter().next() { | ^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in values.iter() { .. }` diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 0ba1943e6d8..d8205c5eb67 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(unused_must_use)] #![warn(clippy::write_literal)] diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 7daf52a4445..54a787fe555 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/write_literal.rs:36:79 + --> $DIR/write_literal.rs:27:79 | LL | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2); | ^ @@ -7,79 +7,79 @@ LL | writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't = note: `-D clippy::write-literal` implied by `-D warnings` error: literal with an empty format string - --> $DIR/write_literal.rs:37:32 + --> $DIR/write_literal.rs:28:32 | LL | write!(&mut v, "Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:38:44 + --> $DIR/write_literal.rs:29:44 | LL | writeln!(&mut v, "Hello {} {}", world, "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:39:34 + --> $DIR/write_literal.rs:30:34 | LL | writeln!(&mut v, "Hello {}", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:40:38 + --> $DIR/write_literal.rs:31:38 | LL | writeln!(&mut v, "10 / 4 is {}", 2.5); | ^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:41:36 + --> $DIR/write_literal.rs:32:36 | LL | writeln!(&mut v, "2 + 1 = {}", 3); | ^ error: literal with an empty format string - --> $DIR/write_literal.rs:46:33 + --> $DIR/write_literal.rs:37:33 | LL | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:46:42 + --> $DIR/write_literal.rs:37:42 | LL | writeln!(&mut v, "{0} {1}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:47:33 + --> $DIR/write_literal.rs:38:33 | LL | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:47:42 + --> $DIR/write_literal.rs:38:42 | LL | writeln!(&mut v, "{1} {0}", "hello", "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:50:43 + --> $DIR/write_literal.rs:41:43 | LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:50:58 + --> $DIR/write_literal.rs:41:58 | LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:51:43 + --> $DIR/write_literal.rs:42:43 | LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ error: literal with an empty format string - --> $DIR/write_literal.rs:51:58 + --> $DIR/write_literal.rs:42:58 | LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index 5d8543e578d..2f53d4561af 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(clippy::write_literal)] #![warn(clippy::write_with_newline)] diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index c18ec184876..1f4395c2621 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -1,5 +1,5 @@ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:19:5 + --> $DIR/write_with_newline.rs:10:5 | LL | write!(&mut v, "Hello/n"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | write!(&mut v, "Hello/n"); = note: `-D clippy::write-with-newline` implied by `-D warnings` error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:20:5 + --> $DIR/write_with_newline.rs:11:5 | LL | write!(&mut v, "Hello {}/n", "world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:21:5 + --> $DIR/write_with_newline.rs:12:5 | LL | write!(&mut v, "Hello {} {}/n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:22:5 + --> $DIR/write_with_newline.rs:13:5 | LL | write!(&mut v, "{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead - --> $DIR/write_with_newline.rs:41:5 + --> $DIR/write_with_newline.rs:32:5 | LL | write!(&mut v, "//n"); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/writeln_empty_string.fixed b/tests/ui/writeln_empty_string.fixed index 68b8185083d..c3ac15b0375 100644 --- a/tests/ui/writeln_empty_string.fixed +++ b/tests/ui/writeln_empty_string.fixed @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/writeln_empty_string.rs b/tests/ui/writeln_empty_string.rs index ba43552af23..9a8894b6c0d 100644 --- a/tests/ui/writeln_empty_string.rs +++ b/tests/ui/writeln_empty_string.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/writeln_empty_string.stderr b/tests/ui/writeln_empty_string.stderr index 119710c0cdb..99635229b3e 100644 --- a/tests/ui/writeln_empty_string.stderr +++ b/tests/ui/writeln_empty_string.stderr @@ -1,5 +1,5 @@ error: using `writeln!(&mut v, "")` - --> $DIR/writeln_empty_string.rs:20:5 + --> $DIR/writeln_empty_string.rs:11:5 | LL | writeln!(&mut v, ""); | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)` @@ -7,7 +7,7 @@ LL | writeln!(&mut v, ""); = note: `-D clippy::writeln-empty-string` implied by `-D warnings` error: using `writeln!(&mut suggestion, "")` - --> $DIR/writeln_empty_string.rs:23:5 + --> $DIR/writeln_empty_string.rs:14:5 | LL | writeln!(&mut suggestion, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)` diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 3c69c9ad03f..bdffb5af87e 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![warn(clippy::wrong_self_convention)] #![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code, clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index f9d20cb3d47..0d0eb19cd07 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:26:17 + --> $DIR/wrong_self_convention.rs:17:17 | LL | fn from_i32(self) {} | ^^^^ @@ -7,67 +7,67 @@ LL | fn from_i32(self) {} = note: `-D clippy::wrong-self-convention` implied by `-D warnings` error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:32:21 + --> $DIR/wrong_self_convention.rs:23:21 | LL | pub fn from_i64(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:44:15 + --> $DIR/wrong_self_convention.rs:35:15 | LL | fn as_i32(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:46:17 + --> $DIR/wrong_self_convention.rs:37:17 | LL | fn into_i32(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:48:15 + --> $DIR/wrong_self_convention.rs:39:15 | LL | fn is_i32(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:50:15 + --> $DIR/wrong_self_convention.rs:41:15 | LL | fn to_i32(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:52:17 + --> $DIR/wrong_self_convention.rs:43:17 | LL | fn from_i32(self) {} | ^^^^ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:54:19 + --> $DIR/wrong_self_convention.rs:45:19 | LL | pub fn as_i64(self) {} | ^^^^ error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:55:21 + --> $DIR/wrong_self_convention.rs:46:21 | LL | pub fn into_i64(&self) {} | ^^^^^ error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:56:19 + --> $DIR/wrong_self_convention.rs:47:19 | LL | pub fn is_i64(self) {} | ^^^^ error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:57:19 + --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn to_i64(self) {} | ^^^^ error: methods called `from_*` usually take no self; consider choosing a less ambiguous name - --> $DIR/wrong_self_convention.rs:58:21 + --> $DIR/wrong_self_convention.rs:49:21 | LL | pub fn from_i64(self) {} | ^^^^ diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index 68e9437273f..09db130a764 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(unused_variables)] #[warn(clippy::zero_divided_by_zero)] fn main() { diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index 653a76c6978..763859f54fb 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -1,5 +1,5 @@ error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:13:15 + --> $DIR/zero_div_zero.rs:4:15 | LL | let nan = 0.0 / 0.0; | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let nan = 0.0 / 0.0; = note: #[deny(clippy::eq_op)] on by default error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:13:15 + --> $DIR/zero_div_zero.rs:4:15 | LL | let nan = 0.0 / 0.0; | ^^^^^^^^^ @@ -16,13 +16,13 @@ LL | let nan = 0.0 / 0.0; = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:14:19 + --> $DIR/zero_div_zero.rs:5:19 | LL | let f64_nan = 0.0 / 0.0f64; | ^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:14:19 + --> $DIR/zero_div_zero.rs:5:19 | LL | let f64_nan = 0.0 / 0.0f64; | ^^^^^^^^^^^^ @@ -30,13 +30,13 @@ LL | let f64_nan = 0.0 / 0.0f64; = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:15:25 + --> $DIR/zero_div_zero.rs:6:25 | LL | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:15:25 + --> $DIR/zero_div_zero.rs:6:25 | LL | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ @@ -44,13 +44,13 @@ LL | let other_f64_nan = 0.0f64 / 0.0; = help: Consider using `std::f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` - --> $DIR/zero_div_zero.rs:16:28 + --> $DIR/zero_div_zero.rs:7:28 | LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | ^^^^^^^^^^^^^^^ error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:16:28 + --> $DIR/zero_div_zero.rs:7:28 | LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index 9930b8a4c6b..2291c77d56e 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[allow(unused_variables)] fn main() { let x = 0 as *const usize; diff --git a/tests/ui/zero_ptr.stderr b/tests/ui/zero_ptr.stderr index 5aa5e275ee6..b79c3457b9b 100644 --- a/tests/ui/zero_ptr.stderr +++ b/tests/ui/zero_ptr.stderr @@ -1,5 +1,5 @@ error: `0 as *const _` detected. Consider using `ptr::null()` - --> $DIR/zero_ptr.rs:12:13 + --> $DIR/zero_ptr.rs:3:13 | LL | let x = 0 as *const usize; | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let x = 0 as *const usize; = note: `-D clippy::zero-ptr` implied by `-D warnings` error: `0 as *mut _` detected. Consider using `ptr::null_mut()` - --> $DIR/zero_ptr.rs:13:13 + --> $DIR/zero_ptr.rs:4:13 | LL | let y = 0 as *mut f64; | ^^^^^^^^^^^^^ diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 945e35f4ebf..9e00571c9d5 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -1,12 +1,3 @@ -// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use semver::VersionReq; #[test] diff --git a/util/cov.sh b/util/cov.sh index d927a5cfcd0..3f9a6b06f72 100755 --- a/util/cov.sh +++ b/util/cov.sh @@ -1,16 +1,5 @@ #!/usr/bin/bash -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - - # This run `kcov` on Clippy. The coverage report will be at # `./target/cov/index.html`. # `compile-test` is special. `kcov` does not work directly on it so these files diff --git a/util/export.py b/util/export.py index d8598ed8037..827b1e31905 100755 --- a/util/export.py +++ b/util/export.py @@ -1,16 +1,5 @@ #!/usr/bin/env python -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - - # Build the gh-pages import re diff --git a/util/lintlib.py b/util/lintlib.py index 098fcf256a6..1c49ab770d5 100644 --- a/util/lintlib.py +++ b/util/lintlib.py @@ -1,13 +1,3 @@ -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - # Common utils for the several housekeeping scripts. import os diff --git a/util/update_lints.py b/util/update_lints.py index 4467b5c0cf7..1800fa05c90 100755 --- a/util/update_lints.py +++ b/util/update_lints.py @@ -1,15 +1,5 @@ #!/usr/bin/env python -# Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - import sys def main(): -- cgit 1.4.1-3-g733a5 From 94a6eb0695679c46387075c70efaaffb5b73cee0 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Sat, 26 Jan 2019 11:10:13 +0200 Subject: Fix dogfood tests on Appveyor This introduces a work-around for a bug in rustup.rs when excuting cargo from a custom toolchain. Instead of trusting rustup to invoke cargo from one of the release channels we just invoke nightly cargo directly. --- src/main.rs | 6 ++++++ tests/dogfood.rs | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index eefababb96d..20466fc567d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,6 +97,12 @@ where }) .map(|p| ("CARGO_TARGET_DIR", p)); + // Run the dogfood tests directly on nightly cargo. This is required due + // to a bug in rustup.rs when running cargo on custom toolchains. See issue #3118. + if std::env::var_os("CLIPPY_DOGFOOD").is_some() && cfg!(windows) { + args.insert(0, "+nightly".to_string()); + } + let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 87fe5887bcc..27a3d84da41 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -1,6 +1,6 @@ #[test] fn dogfood() { - if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) { + if option_env!("RUSTC_TEST_SUITE").is_some() { return; } let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -30,7 +30,7 @@ fn dogfood() { #[test] fn dogfood_tests() { - if option_env!("RUSTC_TEST_SUITE").is_some() || cfg!(windows) { + if option_env!("RUSTC_TEST_SUITE").is_some() { return; } let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); -- cgit 1.4.1-3-g733a5 From e9e0a7e3bd0619626ad03db4b641a368d3555bcc Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Sat, 26 Jan 2019 20:40:55 +0100 Subject: rustup https://github.com/rust-lang/rust/pull/57726 --- clippy_lints/src/approx_const.rs | 4 ++ clippy_lints/src/arithmetic.rs | 4 ++ clippy_lints/src/assertions_on_constants.rs | 4 ++ clippy_lints/src/assign_ops.rs | 4 ++ clippy_lints/src/attrs.rs | 8 ++++ clippy_lints/src/bit_mask.rs | 3 ++ clippy_lints/src/blacklisted_name.rs | 3 ++ clippy_lints/src/block_in_if_condition.rs | 4 ++ clippy_lints/src/booleans.rs | 4 ++ clippy_lints/src/bytecount.rs | 4 ++ clippy_lints/src/cargo_common_metadata.rs | 4 ++ clippy_lints/src/collapsible_if.rs | 4 ++ clippy_lints/src/const_static_lifetime.rs | 4 ++ clippy_lints/src/copies.rs | 4 ++ clippy_lints/src/copy_iterator.rs | 4 ++ clippy_lints/src/cyclomatic_complexity.rs | 4 ++ clippy_lints/src/default_trait_access.rs | 4 ++ clippy_lints/src/derive.rs | 4 ++ clippy_lints/src/doc.rs | 4 ++ clippy_lints/src/double_comparison.rs | 4 ++ clippy_lints/src/double_parens.rs | 4 ++ clippy_lints/src/drop_forget_ref.rs | 4 ++ clippy_lints/src/duration_subsec.rs | 4 ++ clippy_lints/src/else_if_without_else.rs | 4 ++ clippy_lints/src/empty_enum.rs | 4 ++ clippy_lints/src/entry.rs | 4 ++ clippy_lints/src/enum_clike.rs | 4 ++ clippy_lints/src/enum_glob_use.rs | 4 ++ clippy_lints/src/enum_variants.rs | 4 ++ clippy_lints/src/eq_op.rs | 4 ++ clippy_lints/src/erasing_op.rs | 4 ++ clippy_lints/src/escape.rs | 4 ++ clippy_lints/src/eta_reduction.rs | 4 ++ clippy_lints/src/eval_order_dependence.rs | 4 ++ clippy_lints/src/excessive_precision.rs | 4 ++ clippy_lints/src/explicit_write.rs | 4 ++ clippy_lints/src/fallible_impl_from.rs | 4 ++ clippy_lints/src/format.rs | 4 ++ clippy_lints/src/formatting.rs | 4 ++ clippy_lints/src/functions.rs | 4 ++ clippy_lints/src/identity_conversion.rs | 4 ++ clippy_lints/src/identity_op.rs | 4 ++ clippy_lints/src/if_not_else.rs | 4 ++ clippy_lints/src/implicit_return.rs | 4 ++ clippy_lints/src/indexing_slicing.rs | 4 ++ clippy_lints/src/infallible_destructuring_match.rs | 4 ++ clippy_lints/src/infinite_iter.rs | 4 ++ clippy_lints/src/inherent_impl.rs | 4 ++ clippy_lints/src/inline_fn_without_body.rs | 4 ++ clippy_lints/src/int_plus_one.rs | 4 ++ clippy_lints/src/invalid_ref.rs | 4 ++ clippy_lints/src/items_after_statements.rs | 4 ++ clippy_lints/src/large_enum_variant.rs | 4 ++ clippy_lints/src/len_zero.rs | 4 ++ clippy_lints/src/let_if_seq.rs | 4 ++ clippy_lints/src/lib.rs | 13 +++++-- clippy_lints/src/lifetimes.rs | 4 ++ clippy_lints/src/literal_representation.rs | 8 ++++ clippy_lints/src/loops.rs | 4 ++ clippy_lints/src/map_clone.rs | 4 ++ clippy_lints/src/map_unit_fn.rs | 4 ++ clippy_lints/src/matches.rs | 4 ++ clippy_lints/src/mem_discriminant.rs | 4 ++ clippy_lints/src/mem_forget.rs | 4 ++ clippy_lints/src/mem_replace.rs | 4 ++ clippy_lints/src/methods/mod.rs | 4 ++ clippy_lints/src/minmax.rs | 4 ++ clippy_lints/src/misc.rs | 4 ++ clippy_lints/src/misc_early.rs | 4 ++ clippy_lints/src/missing_doc.rs | 4 ++ clippy_lints/src/missing_inline.rs | 4 ++ clippy_lints/src/multiple_crate_versions.rs | 4 ++ clippy_lints/src/mut_mut.rs | 4 ++ clippy_lints/src/mut_reference.rs | 4 ++ clippy_lints/src/mutex_atomic.rs | 4 ++ clippy_lints/src/needless_bool.rs | 8 ++++ clippy_lints/src/needless_borrow.rs | 4 ++ clippy_lints/src/needless_borrowed_ref.rs | 4 ++ clippy_lints/src/needless_continue.rs | 4 ++ clippy_lints/src/needless_pass_by_value.rs | 4 ++ clippy_lints/src/needless_update.rs | 4 ++ clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 4 ++ clippy_lints/src/neg_multiply.rs | 4 ++ clippy_lints/src/new_without_default.rs | 4 ++ clippy_lints/src/no_effect.rs | 4 ++ clippy_lints/src/non_copy_const.rs | 4 ++ clippy_lints/src/non_expressive_names.rs | 4 ++ clippy_lints/src/ok_if_let.rs | 4 ++ clippy_lints/src/open_options.rs | 4 ++ clippy_lints/src/overflow_check_conditional.rs | 4 ++ clippy_lints/src/panic_unimplemented.rs | 4 ++ clippy_lints/src/partialeq_ne_impl.rs | 4 ++ clippy_lints/src/precedence.rs | 4 ++ clippy_lints/src/ptr.rs | 4 ++ clippy_lints/src/ptr_offset_with_cast.rs | 4 ++ clippy_lints/src/question_mark.rs | 4 ++ clippy_lints/src/ranges.rs | 4 ++ clippy_lints/src/redundant_clone.rs | 4 ++ clippy_lints/src/redundant_field_names.rs | 4 ++ clippy_lints/src/redundant_pattern_matching.rs | 4 ++ clippy_lints/src/reference.rs | 8 ++++ clippy_lints/src/regex.rs | 4 ++ clippy_lints/src/replace_consts.rs | 4 ++ clippy_lints/src/returns.rs | 4 ++ clippy_lints/src/serde_api.rs | 4 ++ clippy_lints/src/shadow.rs | 4 ++ clippy_lints/src/slow_vector_initialization.rs | 4 ++ clippy_lints/src/strings.rs | 8 ++++ clippy_lints/src/suspicious_trait_impl.rs | 4 ++ clippy_lints/src/swap.rs | 4 ++ clippy_lints/src/temporary_assignment.rs | 4 ++ clippy_lints/src/transmute.rs | 4 ++ clippy_lints/src/trivially_copy_pass_by_ref.rs | 4 ++ clippy_lints/src/types.rs | 44 ++++++++++++++++++++++ clippy_lints/src/unicode.rs | 4 ++ clippy_lints/src/unsafe_removed_from_name.rs | 4 ++ clippy_lints/src/unused_io_amount.rs | 4 ++ clippy_lints/src/unused_label.rs | 4 ++ clippy_lints/src/unwrap.rs | 4 ++ clippy_lints/src/use_self.rs | 4 ++ clippy_lints/src/utils/author.rs | 4 ++ clippy_lints/src/utils/inspector.rs | 4 ++ clippy_lints/src/utils/internal_lints.rs | 15 ++++++++ clippy_lints/src/vec.rs | 4 ++ clippy_lints/src/wildcard_dependencies.rs | 4 ++ clippy_lints/src/write.rs | 4 ++ clippy_lints/src/zero_div_zero.rs | 4 ++ src/driver.rs | 2 +- tests/ui/lint_without_lint_pass.rs | 4 ++ 129 files changed, 588 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 8410408312f..337139e1b1d 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -60,6 +60,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(APPROX_CONSTANT) } + + fn name(&self) -> &'static str { + "ApproxConstant" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index efa53ff94c3..e14c79374ba 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -52,6 +52,10 @@ impl LintPass for Arithmetic { fn get_lints(&self) -> LintArray { lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC) } + + fn name(&self) -> &'static str { + "Arithmetic" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a148cb1c3a6..d420de3a4db 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -34,6 +34,10 @@ impl LintPass for AssertionsOnConstants { fn get_lints(&self) -> LintArray { lint_array![ASSERTIONS_ON_CONSTANTS] } + + fn name(&self) -> &'static str { + "AssertionsOnConstants" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants { diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index ad77ee3a3fa..329bab5cf1c 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -57,6 +57,10 @@ impl LintPass for AssignOps { fn get_lints(&self) -> LintArray { lint_array!(ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP) } + + fn name(&self) -> &'static str { + "AssignOps" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 9e4dd52c414..4a5eb378d5a 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -199,6 +199,10 @@ impl LintPass for AttrPass { UNKNOWN_CLIPPY_LINTS, ) } + + fn name(&self) -> &'static str { + "Attributes" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass { @@ -500,6 +504,10 @@ impl LintPass for CfgAttrPass { fn get_lints(&self) -> LintArray { lint_array!(DEPRECATED_CFG_ATTR,) } + + fn name(&self) -> &'static str { + "DeprecatedCfgAttribute" + } } impl EarlyLintPass for CfgAttrPass { diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index b08d9961d25..ef0943875d2 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -108,6 +108,9 @@ impl LintPass for BitMask { fn get_lints(&self) -> LintArray { lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK) } + fn name(&self) -> &'static str { + "BitMask" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask { diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index 64b3be8f302..9606b2eda32 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -37,6 +37,9 @@ impl LintPass for BlackListedName { fn get_lints(&self) -> LintArray { lint_array!(BLACKLISTED_NAME) } + fn name(&self) -> &'static str { + "BlacklistedName" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlackListedName { diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 6e850931e6b..8abcfb4cfd6 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -49,6 +49,10 @@ impl LintPass for BlockInIfCondition { fn get_lints(&self) -> LintArray { lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT) } + + fn name(&self) -> &'static str { + "BlockInIfCondition" + } } struct ExVisitor<'a, 'tcx: 'a> { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 8b1a56e3b6e..6b53dd908de 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -58,6 +58,10 @@ impl LintPass for NonminimalBool { fn get_lints(&self) -> LintArray { lint_array!(NONMINIMAL_BOOL, LOGIC_BUG) } + + fn name(&self) -> &'static str { + "NonminimalBool" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonminimalBool { diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 794b43f4db5..b677ef71583 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -38,6 +38,10 @@ impl LintPass for ByteCount { fn get_lints(&self) -> LintArray { lint_array!(NAIVE_BYTECOUNT) } + + fn name(&self) -> &'static str { + "ByteCount" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount { diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index c60d10cd009..124b11cc78c 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -62,6 +62,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(CARGO_COMMON_METADATA) } + + fn name(&self) -> &'static str { + "CargoCommonMetadata" + } } impl EarlyLintPass for Pass { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 10cbc9e6ccd..c236706f02f 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -78,6 +78,10 @@ impl LintPass for CollapsibleIf { fn get_lints(&self) -> LintArray { lint_array!(COLLAPSIBLE_IF) } + + fn name(&self) -> &'static str { + "CollapsibleIf" + } } impl EarlyLintPass for CollapsibleIf { diff --git a/clippy_lints/src/const_static_lifetime.rs b/clippy_lints/src/const_static_lifetime.rs index 229a411ce06..7315184c8bd 100644 --- a/clippy_lints/src/const_static_lifetime.rs +++ b/clippy_lints/src/const_static_lifetime.rs @@ -32,6 +32,10 @@ impl LintPass for StaticConst { fn get_lints(&self) -> LintArray { lint_array!(CONST_STATIC_LIFETIME) } + + fn name(&self) -> &'static str { + "StaticConst" + } } impl StaticConst { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 3676519adc1..6bb75cf8064 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -110,6 +110,10 @@ impl LintPass for CopyAndPaste { fn get_lints(&self) -> LintArray { lint_array![IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS] } + + fn name(&self) -> &'static str { + "CopyAndPaste" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index 3d0df7424f1..59eef9e39dc 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -35,6 +35,10 @@ impl LintPass for CopyIterator { fn get_lints(&self) -> LintArray { lint_array![COPY_ITERATOR] } + + fn name(&self) -> &'static str { + "CopyIterator" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator { diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs index 9170f1e8ecf..c6358aed4bd 100644 --- a/clippy_lints/src/cyclomatic_complexity.rs +++ b/clippy_lints/src/cyclomatic_complexity.rs @@ -42,6 +42,10 @@ impl LintPass for CyclomaticComplexity { fn get_lints(&self) -> LintArray { lint_array!(CYCLOMATIC_COMPLEXITY) } + + fn name(&self) -> &'static str { + "CyclomaticComplexity" + } } impl CyclomaticComplexity { diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index c4b39dc0f0a..7b3899b2f49 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -35,6 +35,10 @@ impl LintPass for DefaultTraitAccess { fn get_lints(&self) -> LintArray { lint_array!(DEFAULT_TRAIT_ACCESS) } + + fn name(&self) -> &'static str { + "DefaultTraitAccess" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a2bf0098ab8..9580fbbe4c1 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -68,6 +68,10 @@ impl LintPass for Derive { fn get_lints(&self) -> LintArray { lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ) } + + fn name(&self) -> &'static str { + "Derive" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index e96ef9ac621..87135fb88b6 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -48,6 +48,10 @@ impl LintPass for Doc { fn get_lints(&self) -> LintArray { lint_array![DOC_MARKDOWN] } + + fn name(&self) -> &'static str { + "DocMarkdown" + } } impl EarlyLintPass for Doc { diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index fc4af438d44..6c6b53b0b98 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -37,6 +37,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(DOUBLE_COMPARISONS) } + + fn name(&self) -> &'static str { + "DoubleComparisons" + } } impl<'a, 'tcx> Pass { diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 38381b069f0..71b2f5f51a7 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -29,6 +29,10 @@ impl LintPass for DoubleParens { fn get_lints(&self) -> LintArray { lint_array!(DOUBLE_PARENS) } + + fn name(&self) -> &'static str { + "DoubleParens" + } } impl EarlyLintPass for DoubleParens { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 4a2a38f6ea1..b437d603005 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -112,6 +112,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY) } + + fn name(&self) -> &'static str { + "DropForgetRef" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 3ac98c71644..3935099fdce 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -36,6 +36,10 @@ impl LintPass for DurationSubsec { fn get_lints(&self) -> LintArray { lint_array!(DURATION_SUBSEC) } + + fn name(&self) -> &'static str { + "DurationSubsec" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec { diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index f633d81764b..c01ad486484 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -46,6 +46,10 @@ impl LintPass for ElseIfWithoutElse { fn get_lints(&self) -> LintArray { lint_array!(ELSE_IF_WITHOUT_ELSE) } + + fn name(&self) -> &'static str { + "ElseIfWithoutElse" + } } impl EarlyLintPass for ElseIfWithoutElse { diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index 71e84bf1b47..ab80625f685 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -30,6 +30,10 @@ impl LintPass for EmptyEnum { fn get_lints(&self) -> LintArray { lint_array!(EMPTY_ENUM) } + + fn name(&self) -> &'static str { + "EmptyEnum" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum { diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 646a2569bbe..8de881d0425 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -44,6 +44,10 @@ impl LintPass for HashMapLint { fn get_lints(&self) -> LintArray { lint_array!(MAP_ENTRY) } + + fn name(&self) -> &'static str { + "HashMap" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint { diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index ab9bc6cd0ca..46501d55497 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -40,6 +40,10 @@ impl LintPass for UnportableVariant { fn get_lints(&self) -> LintArray { lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT) } + + fn name(&self) -> &'static str { + "UnportableVariant" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 9402c2a5aad..4806736682f 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -32,6 +32,10 @@ impl LintPass for EnumGlobUse { fn get_lints(&self) -> LintArray { lint_array!(ENUM_GLOB_USE) } + + fn name(&self) -> &'static str { + "EnumGlobUse" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index ffaa8b2811a..74d61c0f6a0 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -124,6 +124,10 @@ impl LintPass for EnumVariantNames { MODULE_INCEPTION ) } + + fn name(&self) -> &'static str { + "EnumVariantNames" + } } fn var2str(var: &Variant) -> LocalInternedString { diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 93132534a76..38c9a05b44c 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -52,6 +52,10 @@ impl LintPass for EqOp { fn get_lints(&self) -> LintArray { lint_array!(EQ_OP, OP_REF) } + + fn name(&self) -> &'static str { + "EqOp" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index fea31855543..a1d851377eb 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -32,6 +32,10 @@ impl LintPass for ErasingOp { fn get_lints(&self) -> LintArray { lint_array!(ERASING_OP) } + + fn name(&self) -> &'static str { + "ErasingOp" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index a7b47fd1e54..a276579b1b5 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -52,6 +52,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(BOXED_LOCAL) } + + fn name(&self) -> &'static str { + "BoxedLocal" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 624d215492f..cc86aee7def 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -36,6 +36,10 @@ impl LintPass for EtaPass { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_CLOSURE) } + + fn name(&self) -> &'static str { + "EtaReduction" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass { diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 2b4b0d40239..8c933ef74d2 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -61,6 +61,10 @@ impl LintPass for EvalOrderDependence { fn get_lints(&self) -> LintArray { lint_array!(EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION) } + + fn name(&self) -> &'static str { + "EvalOrderDependence" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence { diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index f17b82ab33d..27e033f688d 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -41,6 +41,10 @@ impl LintPass for ExcessivePrecision { fn get_lints(&self) -> LintArray { lint_array!(EXCESSIVE_PRECISION) } + + fn name(&self) -> &'static str { + "ExcessivePrecision" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 0bbc85a0416..2be2bb058bb 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -31,6 +31,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(EXPLICIT_WRITE) } + + fn name(&self) -> &'static str { + "ExplicitWrite" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 2d11b3bd947..3669e8998a4 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -34,6 +34,10 @@ impl LintPass for FallibleImplFrom { fn get_lints(&self) -> LintArray { lint_array!(FALLIBLE_IMPL_FROM) } + + fn name(&self) -> &'static str { + "FallibleImpleFrom" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 90e19af15d0..f14c281fcc9 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -40,6 +40,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array![USELESS_FORMAT] } + + fn name(&self) -> &'static str { + "UselessFormat" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 6459e7b81c6..ecc6f9565d0 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -89,6 +89,10 @@ impl LintPass for Formatting { POSSIBLE_MISSING_COMMA ) } + + fn name(&self) -> &'static str { + "Formatting" + } } impl EarlyLintPass for Formatting { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index a2b7d31b183..cb69e96c8e4 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -74,6 +74,10 @@ impl LintPass for Functions { fn get_lints(&self) -> LintArray { lint_array!(TOO_MANY_ARGUMENTS, NOT_UNSAFE_PTR_ARG_DEREF) } + + fn name(&self) -> &'static str { + "Functions" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index d0e1ee57748..2c0e389119f 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -34,6 +34,10 @@ impl LintPass for IdentityConversion { fn get_lints(&self) -> LintArray { lint_array!(IDENTITY_CONVERSION) } + + fn name(&self) -> &'static str { + "IdentityConversion" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 862c289fce1..89d41c79629 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -30,6 +30,10 @@ impl LintPass for IdentityOp { fn get_lints(&self) -> LintArray { lint_array!(IDENTITY_OP) } + + fn name(&self) -> &'static str { + "IdentityOp" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 19554c7e207..38213141de3 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -44,6 +44,10 @@ impl LintPass for IfNotElse { fn get_lints(&self) -> LintArray { lint_array!(IF_NOT_ELSE) } + + fn name(&self) -> &'static str { + "IfNotElse" + } } impl EarlyLintPass for IfNotElse { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 073c37eefc5..b25b3bce652 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -114,6 +114,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(IMPLICIT_RETURN) } + + fn name(&self) -> &'static str { + "ImplicitReturn" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index b4893c759c8..19e2283dc07 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -91,6 +91,10 @@ impl LintPass for IndexingSlicing { fn get_lints(&self) -> LintArray { lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING) } + + fn name(&self) -> &'static str { + "IndexSlicing" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs index 5d0c5a4a79d..704b583f813 100644 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ b/clippy_lints/src/infallible_destructuring_match.rs @@ -47,6 +47,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(INFALLIBLE_DESTRUCTURING_MATCH) } + + fn name(&self) -> &'static str { + "InfallibleDestructingMatch" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index c25c4ec488f..9f2bcd48787 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -45,6 +45,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(INFINITE_ITER, MAYBE_INFINITE_ITER) } + + fn name(&self) -> &'static str { + "InfiniteIter" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 52aa73d7a10..5585ce4cbef 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -56,6 +56,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(MULTIPLE_INHERENT_IMPL) } + + fn name(&self) -> &'static str { + "MultipleInherientImpl" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index a092f86658b..bdc17ab4624 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -35,6 +35,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(INLINE_FN_WITHOUT_BODY) } + + fn name(&self) -> &'static str { + "InlineFnWithoutBody" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 547052f3429..aee3b7cc542 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -36,6 +36,10 @@ impl LintPass for IntPlusOne { fn get_lints(&self) -> LintArray { lint_array!(INT_PLUS_ONE) } + + fn name(&self) -> &'static str { + "IntPlusOne" + } } // cases: diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index 03b099b4393..90649535958 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -32,6 +32,10 @@ impl LintPass for InvalidRef { fn get_lints(&self) -> LintArray { lint_array!(INVALID_REF) } + + fn name(&self) -> &'static str { + "InvalidRef" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef { diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 0af8c3dd5cb..dd283d897a5 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -40,6 +40,10 @@ impl LintPass for ItemsAfterStatements { fn get_lints(&self) -> LintArray { lint_array!(ITEMS_AFTER_STATEMENTS) } + + fn name(&self) -> &'static str { + "ItemsAfterStatements" + } } impl EarlyLintPass for ItemsAfterStatements { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index d5bc2a8fad7..0b3cf07e50a 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -46,6 +46,10 @@ impl LintPass for LargeEnumVariant { fn get_lints(&self) -> LintArray { lint_array!(LARGE_ENUM_VARIANT) } + + fn name(&self) -> &'static str { + "LargeEnumVariant" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index b15ba5a4783..2764cd6ffd9 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -77,6 +77,10 @@ impl LintPass for LenZero { fn get_lints(&self) -> LintArray { lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY) } + + fn name(&self) -> &'static str { + "LenZero" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 5154c6d4d08..3eb25cfb36a 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -60,6 +60,10 @@ impl LintPass for LetIfSeq { fn get_lints(&self) -> LintArray { lint_array!(USELESS_LET_IF_SEQ) } + + fn name(&self) -> &'static str { + "LetIfSeq" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d77c3c64a2..4683d353ccf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -212,15 +212,22 @@ pub fn register_pre_expansion_lints( store: &mut rustc::lint::LintStore, conf: &Conf, ) { - store.register_pre_expansion_pass(Some(session), box write::Pass); - store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames); + store.register_pre_expansion_pass(Some(session), true, false, box write::Pass); store.register_pre_expansion_pass( Some(session), + true, + false, + box redundant_field_names::RedundantFieldNames, + ); + store.register_pre_expansion_pass( + Some(session), + true, + false, box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold: conf.single_char_binding_names_threshold, }, ); - store.register_pre_expansion_pass(Some(session), box attrs::CfgAttrPass); + store.register_pre_expansion_pass(Some(session), true, false, box attrs::CfgAttrPass); } pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index f7512446c87..5562d750dac 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -61,6 +61,10 @@ impl LintPass for LifetimePass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES) } + + fn name(&self) -> &'static str { + "LifeTimes" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index d6e6ffa61b3..801e54f055c 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -346,6 +346,10 @@ impl LintPass for LiteralDigitGrouping { MISTYPED_LITERAL_SUFFIXES, ) } + + fn name(&self) -> &'static str { + "LiteralDigitGrouping" + } } impl EarlyLintPass for LiteralDigitGrouping { @@ -493,6 +497,10 @@ impl LintPass for LiteralRepresentation { fn get_lints(&self) -> LintArray { lint_array!(DECIMAL_LITERAL_REPRESENTATION) } + + fn name(&self) -> &'static str { + "DecimalLiteralRepresentation" + } } impl EarlyLintPass for LiteralRepresentation { diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 70ff86087ea..64e76c09989 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -465,6 +465,10 @@ impl LintPass for Pass { WHILE_IMMUTABLE_CONDITION, ) } + + fn name(&self) -> &'static str { + "Loops" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 4db0ca759db..49bd8f650e5 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -46,6 +46,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(MAP_CLONE) } + + fn name(&self) -> &'static str { + "MapClone" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index ad5761f5f04..bd4b4043824 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -81,6 +81,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN) } + + fn name(&self) -> &'static str { + "MapUnit" + } } fn is_unit_type(ty: ty::Ty<'_>) -> bool { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index b003da44236..adb8dab5c42 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -202,6 +202,10 @@ impl LintPass for MatchPass { MATCH_AS_REF ) } + + fn name(&self) -> &'static str { + "Matches" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass { diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index a75959e58fa..a40b1eab2c7 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -31,6 +31,10 @@ impl LintPass for MemDiscriminant { fn get_lints(&self) -> LintArray { lint_array![MEM_DISCRIMINANT_NON_ENUM] } + + fn name(&self) -> &'static str { + "MemDiscriminant" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemDiscriminant { diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index f83a8b5f7fe..0f25070318e 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -27,6 +27,10 @@ impl LintPass for MemForget { fn get_lints(&self) -> LintArray { lint_array![MEM_FORGET] } + + fn name(&self) -> &'static str { + "MemForget" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index d649895e33f..1b43794bcb7 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -36,6 +36,10 @@ impl LintPass for MemReplace { fn get_lints(&self) -> LintArray { lint_array![MEM_REPLACE_OPTION_WITH_NONE] } + + fn name(&self) -> &'static str { + "MemReplace" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4126b78e676..16c3e1fb631 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -814,6 +814,10 @@ impl LintPass for Pass { INTO_ITER_ON_REF, ) } + + fn name(&self) -> &'static str { + "Methods" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index beea667dd43..19bede8a280 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -31,6 +31,10 @@ impl LintPass for MinMaxPass { fn get_lints(&self) -> LintArray { lint_array!(MIN_MAX) } + + fn name(&self) -> &'static str { + "MinMax" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 88a6d62ee6d..01f5a633387 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -242,6 +242,10 @@ impl LintPass for Pass { FLOAT_CMP_CONST ) } + + fn name(&self) -> &'static str { + "MiscLints" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 2cda1accc56..eb35da05908 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -187,6 +187,10 @@ impl LintPass for MiscEarly { BUILTIN_TYPE_SHADOW ) } + + fn name(&self) -> &'static str { + "MiscEarlyLints" + } } // Used to find `return` statements or equivalents e.g. `?` diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 22084bd12cb..9fd67e2fcbf 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -90,6 +90,10 @@ impl LintPass for MissingDoc { fn get_lints(&self) -> LintArray { lint_array![MISSING_DOCS_IN_PRIVATE_ITEMS] } + + fn name(&self) -> &'static str { + "MissingDoc" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index e9d0d2d77f1..754215799e5 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -83,6 +83,10 @@ impl LintPass for MissingInline { fn get_lints(&self) -> LintArray { lint_array![MISSING_INLINE_IN_PUBLIC_ITEMS] } + + fn name(&self) -> &'static str { + "MissingInline" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline { diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index 6a042fa8c0a..f772fa2b21c 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -37,6 +37,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(MULTIPLE_CRATE_VERSIONS) } + + fn name(&self) -> &'static str { + "MultipleCrateVersions" + } } impl EarlyLintPass for Pass { diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 9aa3cce9d4b..b244c7f3031 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -30,6 +30,10 @@ impl LintPass for MutMut { fn get_lints(&self) -> LintArray { lint_array!(MUT_MUT) } + + fn name(&self) -> &'static str { + "MutMut" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut { diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 5293c80ca2b..716abbe31fe 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -30,6 +30,10 @@ impl LintPass for UnnecessaryMutPassed { fn get_lints(&self) -> LintArray { lint_array!(UNNECESSARY_MUT_PASSED) } + + fn name(&self) -> &'static str { + "UnneccessaryMutPassed" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index b85f4b8ad30..fa0e8288b30 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -53,6 +53,10 @@ impl LintPass for MutexAtomic { fn get_lints(&self) -> LintArray { lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER) } + + fn name(&self) -> &'static str { + "Mutex" + } } pub struct MutexAtomic; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 3b1fea465f5..49f607f525d 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -61,6 +61,10 @@ impl LintPass for NeedlessBool { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_BOOL) } + + fn name(&self) -> &'static str { + "NeedlessBool" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { @@ -141,6 +145,10 @@ impl LintPass for BoolComparison { fn get_lints(&self) -> LintArray { lint_array!(BOOL_COMPARISON) } + + fn name(&self) -> &'static str { + "BoolComparison" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index f21cbe8b9ad..a35f31a9803 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -39,6 +39,10 @@ impl LintPass for NeedlessBorrow { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_BORROW) } + + fn name(&self) -> &'static str { + "NeedlessBorrow" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 792e38e1875..6a0032f91b3 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -58,6 +58,10 @@ impl LintPass for NeedlessBorrowedRef { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_BORROWED_REFERENCE) } + + fn name(&self) -> &'static str { + "NeedlessBorrowedRef" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef { diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 0b5ea255d7f..19d7ab32fea 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -107,6 +107,10 @@ impl LintPass for NeedlessContinue { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_CONTINUE) } + + fn name(&self) -> &'static str { + "NeedlessContinue" + } } impl EarlyLintPass for NeedlessContinue { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index cb1fe475a1e..88eb36534b5 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -56,6 +56,10 @@ impl LintPass for NeedlessPassByValue { fn get_lints(&self) -> LintArray { lint_array![NEEDLESS_PASS_BY_VALUE] } + + fn name(&self) -> &'static str { + "NeedlessPassByValue" + } } macro_rules! need { diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index ab22e2c19b3..1d91feddcbe 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -33,6 +33,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_UPDATE) } + + fn name(&self) -> &'static str { + "NeedUpdate" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 919c771ccf5..50031dd68cf 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -48,6 +48,10 @@ impl LintPass for NoNegCompOpForPartialOrd { fn get_lints(&self) -> LintArray { lint_array!(NEG_CMP_OP_ON_PARTIAL_ORD) } + + fn name(&self) -> &'static str { + "NoNegCompOpForPartialOrd" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 846794d8b99..b207433b5ab 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -30,6 +30,10 @@ impl LintPass for NegMultiply { fn get_lints(&self) -> LintArray { lint_array!(NEG_MULTIPLY) } + + fn name(&self) -> &'static str { + "NegMultiply" + } } #[allow(clippy::match_same_arms)] diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 37e0446faed..f851ae4638e 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -93,6 +93,10 @@ impl LintPass for NewWithoutDefault { fn get_lints(&self) -> LintArray { lint_array!(NEW_WITHOUT_DEFAULT) } + + fn name(&self) -> &'static str { + "NewWithoutDefault" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 648c198df08..7799e8fecf2 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -100,6 +100,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(NO_EFFECT, UNNECESSARY_OPERATION) } + + fn name(&self) -> &'static str { + "NoEffect" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 11295c3c092..cbf6099dd7d 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -147,6 +147,10 @@ impl LintPass for NonCopyConst { fn get_lints(&self) -> LintArray { lint_array!(DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST) } + + fn name(&self) -> &'static str { + "NonCopyConst" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index f39cae46de0..3bdf2c38d23 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -71,6 +71,10 @@ impl LintPass for NonExpressiveNames { fn get_lints(&self) -> LintArray { lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS) } + + fn name(&self) -> &'static str { + "NoneExpressiveNames" + } } struct ExistingName { diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index 5f15662c90c..0789df0d76b 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -41,6 +41,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(IF_LET_SOME_RESULT) } + + fn name(&self) -> &'static str { + "OkIfLet" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index fe572d86c1b..31a6caa50d6 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -30,6 +30,10 @@ impl LintPass for NonSensical { fn get_lints(&self) -> LintArray { lint_array!(NONSENSICAL_OPEN_OPTIONS) } + + fn name(&self) -> &'static str { + "OpenOptions" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSensical { diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index d76a9f96eff..d424e8bcaad 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -28,6 +28,10 @@ impl LintPass for OverflowCheckConditional { fn get_lints(&self) -> LintArray { lint_array!(OVERFLOW_CHECK_CONDITIONAL) } + + fn name(&self) -> &'static str { + "OverflowCheckConditional" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional { diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index f5c3a26e080..d0f7487c24a 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -48,6 +48,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(PANIC_PARAMS, UNIMPLEMENTED) } + + fn name(&self) -> &'static str { + "PanicUnimplemented" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 03d2d5d3bab..b9d5102ccd6 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -35,6 +35,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(PARTIALEQ_NE_IMPL) } + + fn name(&self) -> &'static str { + "PartialEqNeImpl" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 44e82984c54..ed03a8c6aa7 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -35,6 +35,10 @@ impl LintPass for Precedence { fn get_lints(&self) -> LintArray { lint_array!(PRECEDENCE) } + + fn name(&self) -> &'static str { + "Precedence" + } } impl EarlyLintPass for Precedence { diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 87cd9892893..6b2528248b5 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -102,6 +102,10 @@ impl LintPass for PointerPass { fn get_lints(&self) -> LintArray { lint_array!(PTR_ARG, CMP_NULL, MUT_FROM_REF) } + + fn name(&self) -> &'static str { + "Ptr" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 32d330ac171..4ff3f7643ba 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -46,6 +46,10 @@ impl lint::LintPass for Pass { fn get_lints(&self) -> lint::LintArray { lint_array!(PTR_OFFSET_WITH_CAST) } + + fn name(&self) -> &'static str { + "PtrOffsetWithCast" + } } impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 03f6ea12e00..b30cbe4ce9a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -41,6 +41,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(QUESTION_MARK) } + + fn name(&self) -> &'static str { + "QuestionMark" + } } impl Pass { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 2e01afc2258..ef600184ebe 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -97,6 +97,10 @@ impl LintPass for Pass { RANGE_MINUS_ONE ) } + + fn name(&self) -> &'static str { + "Ranges" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index f584ef19d5a..59d1a4297a5 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -73,6 +73,10 @@ impl LintPass for RedundantClone { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_CLONE) } + + fn name(&self) -> &'static str { + "RedundantClone" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 9076d67cb14..aeb7bb6493c 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -38,6 +38,10 @@ impl LintPass for RedundantFieldNames { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_FIELD_NAMES) } + + fn name(&self) -> &'static str { + "RedundantFieldNames" + } } impl EarlyLintPass for RedundantFieldNames { diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs index bc61ee8e7e3..1cf0838415f 100644 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ b/clippy_lints/src/redundant_pattern_matching.rs @@ -49,6 +49,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(REDUNDANT_PATTERN_MATCHING) } + + fn name(&self) -> &'static str { + "RedundantPatternMatching" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 8d2543ef618..3a5af498017 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -30,6 +30,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(DEREF_ADDROF) } + + fn name(&self) -> &'static str { + "DerefAddrOf" + } } fn without_parens(mut e: &Expr) -> &Expr { @@ -84,6 +88,10 @@ impl LintPass for DerefPass { fn get_lints(&self) -> LintArray { lint_array!(REF_IN_DEREF) } + + fn name(&self) -> &'static str { + "RefInDeref" + } } impl EarlyLintPass for DerefPass { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 6a58a6e73c7..0171c2a5283 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -76,6 +76,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX) } + + fn name(&self) -> &'static str { + "Regex" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index ea51e4711cd..16c8cc3bc47 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -35,6 +35,10 @@ impl LintPass for ReplaceConsts { fn get_lints(&self) -> LintArray { lint_array!(REPLACE_CONSTS) } + + fn name(&self) -> &'static str { + "ReplaceConsts" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index d81d04b81d3..83b4d7f9112 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -180,6 +180,10 @@ impl LintPass for ReturnPass { fn get_lints(&self) -> LintArray { lint_array!(NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT) } + + fn name(&self) -> &'static str { + "Return" + } } impl EarlyLintPass for ReturnPass { diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index da8675b38da..8090ed7fbcf 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -25,6 +25,10 @@ impl LintPass for Serde { fn get_lints(&self) -> LintArray { lint_array!(SERDE_API_MISUSE) } + + fn name(&self) -> &'static str { + "SerdeAPI" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index c99b00bb98f..1f341bd22ee 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -82,6 +82,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED) } + + fn name(&self) -> &'static str { + "Shadow" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index aea414065d8..0765e4e11be 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -37,6 +37,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(SLOW_VECTOR_INITIALIZATION,) } + + fn name(&self) -> &'static str { + "SlowVectorInit" + } } /// `VecAllocation` contains data regarding a vector allocated with `with_capacity` and then diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ffec764fd5e..71784397463 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -79,6 +79,10 @@ impl LintPass for StringAdd { fn get_lints(&self) -> LintArray { lint_array!(STRING_ADD, STRING_ADD_ASSIGN) } + + fn name(&self) -> &'static str { + "StringAdd" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd { @@ -151,6 +155,10 @@ impl LintPass for StringLitAsBytes { fn get_lints(&self) -> LintArray { lint_array!(STRING_LIT_AS_BYTES) } + + fn name(&self) -> &'static str { + "StringLiteralAsBytes" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index c6dd9504857..5f0e49dd7e6 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -57,6 +57,10 @@ impl LintPass for SuspiciousImpl { fn get_lints(&self) -> LintArray { lint_array![SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL] } + + fn name(&self) -> &'static str { + "SuspiciousImpl" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index ddf33fcc411..860707c8239 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -57,6 +57,10 @@ impl LintPass for Swap { fn get_lints(&self) -> LintArray { lint_array![MANUAL_SWAP, ALMOST_SWAPPED] } + + fn name(&self) -> &'static str { + "Swap" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap { diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index c8a01c3668c..0d8cfedf414 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -44,6 +44,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(TEMPORARY_ASSIGNMENT) } + + fn name(&self) -> &'static str { + "TemporaryAssignment" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 02205cfbd68..88371df0dca 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -219,6 +219,10 @@ impl LintPass for Transmute { TRANSMUTE_INT_TO_FLOAT, ) } + + fn name(&self) -> &'static str { + "Transmute" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 5ab73758301..4e3bb7d329e 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -142,6 +142,10 @@ impl LintPass for TriviallyCopyPassByRef { fn get_lints(&self) -> LintArray { lint_array![TRIVIALLY_COPY_PASS_BY_REF] } + + fn name(&self) -> &'static str { + "TrivallyCopyPassByRef" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 898fd5a9808..4683ffb4c85 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -168,6 +168,10 @@ impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX) } + + fn name(&self) -> &'static str { + "Types" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { @@ -467,6 +471,10 @@ impl LintPass for LetPass { fn get_lints(&self) -> LintArray { lint_array!(LET_UNIT_VALUE) } + + fn name(&self) -> &'static str { + "LetUnitValue" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetPass { @@ -531,6 +539,10 @@ impl LintPass for UnitCmp { fn get_lints(&self) -> LintArray { lint_array!(UNIT_CMP) } + + fn name(&self) -> &'static str { + "UnicCmp" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp { @@ -586,6 +598,10 @@ impl LintPass for UnitArg { fn get_lints(&self) -> LintArray { lint_array!(UNIT_ARG) } + + fn name(&self) -> &'static str { + "UnitArg" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { @@ -1073,6 +1089,10 @@ impl LintPass for CastPass { FN_TO_NUMERIC_CAST_WITH_TRUNCATION, ) } + + fn name(&self) -> &'static str { + "Casts" + } } // Check if the given type is either `core::ffi::c_void` or @@ -1278,6 +1298,10 @@ impl LintPass for TypeComplexityPass { fn get_lints(&self) -> LintArray { lint_array!(TYPE_COMPLEXITY) } + + fn name(&self) -> &'static str { + "TypeComplexityPass" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { @@ -1442,6 +1466,10 @@ impl LintPass for CharLitAsU8 { fn get_lints(&self) -> LintArray { lint_array!(CHAR_LIT_AS_U8) } + + fn name(&self) -> &'static str { + "CharLiteralAsU8" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 { @@ -1500,6 +1528,10 @@ impl LintPass for AbsurdExtremeComparisons { fn get_lints(&self) -> LintArray { lint_array!(ABSURD_EXTREME_COMPARISONS) } + + fn name(&self) -> &'static str { + "AbsurdExtremeComparisons" + } } enum ExtremeType { @@ -1675,6 +1707,10 @@ impl LintPass for InvalidUpcastComparisons { fn get_lints(&self) -> LintArray { lint_array!(INVALID_UPCAST_COMPARISONS) } + + fn name(&self) -> &'static str { + "InvalidUpcastComparisons" + } } #[derive(Copy, Clone, Debug, Eq)] @@ -1918,6 +1954,10 @@ impl LintPass for ImplicitHasher { fn get_lints(&self) -> LintArray { lint_array!(IMPLICIT_HASHER) } + + fn name(&self) -> &'static str { + "ImplicitHasher" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { @@ -2265,6 +2305,10 @@ impl LintPass for RefToMut { fn get_lints(&self) -> LintArray { lint_array!(CAST_REF_TO_MUT) } + + fn name(&self) -> &'static str { + "RefToMut" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RefToMut { diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index d9207fd2131..d1f39a5e2c2 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -65,6 +65,10 @@ impl LintPass for Unicode { fn get_lints(&self) -> LintArray { lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC) } + + fn name(&self) -> &'static str { + "Unicode" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unicode { diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 6beda8ce706..6cf1a582a65 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -32,6 +32,10 @@ impl LintPass for UnsafeNameRemoval { fn get_lints(&self) -> LintArray { lint_array!(UNSAFE_REMOVED_FROM_NAME) } + + fn name(&self) -> &'static str { + "UnsafeNameRemoval" + } } impl EarlyLintPass for UnsafeNameRemoval { diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 27deb0d9945..d54cd3bba03 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -36,6 +36,10 @@ impl LintPass for UnusedIoAmount { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_IO_AMOUNT) } + + fn name(&self) -> &'static str { + "UnusedIoAmount" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index d53fd265d37..29d76a05118 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -39,6 +39,10 @@ impl LintPass for UnusedLabel { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_LABEL) } + + fn name(&self) -> &'static str { + "UnusedLable" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 369b33363b5..196715f77d7 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -184,6 +184,10 @@ impl<'a> LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(PANICKING_UNWRAP, UNNECESSARY_UNWRAP) } + + fn name(&self) -> &'static str { + "Unwrap" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 88cf01987b5..1f1d9ddbfec 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -51,6 +51,10 @@ impl LintPass for UseSelf { fn get_lints(&self) -> LintArray { lint_array!(USE_SELF) } + + fn name(&self) -> &'static str { + "UseSelf" + } } const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 9623c6cbdad..19c3f3ad230 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -53,6 +53,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(LINT_AUTHOR) } + + fn name(&self) -> &'static str { + "Author" + } } fn prelude() { diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 4116f8ffbaf..758d1d2d365 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -35,6 +35,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(DEEP_CODE_INSPECTION) } + + fn name(&self) -> &'static str { + "DeepCodeInspector" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 788fc434d51..78950493699 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -98,6 +98,10 @@ impl LintPass for Clippy { fn get_lints(&self) -> LintArray { lint_array!(CLIPPY_LINTS_INTERNAL) } + + fn name(&self) -> &'static str { + "ClippyLintsInternal" + } } impl EarlyLintPass for Clippy { @@ -139,6 +143,9 @@ impl LintPass for LintWithoutLintPass { fn get_lints(&self) -> LintArray { lint_array!(LINT_WITHOUT_LINT_PASS) } + fn name(&self) -> &'static str { + "LintWithoutLintPass" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass { @@ -248,6 +255,10 @@ impl LintPass for DefaultHashTypes { fn get_lints(&self) -> LintArray { lint_array!(DEFAULT_HASH_TYPES) } + + fn name(&self) -> &'static str { + "DefaultHashType" + } } impl EarlyLintPass for DefaultHashTypes { @@ -293,6 +304,10 @@ impl LintPass for CompilerLintFunctions { fn get_lints(&self) -> LintArray { lint_array!(COMPILER_LINT_FUNCTIONS) } + + fn name(&self) -> &'static str { + "CompileLintFunctions" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 407722bc66e..a99b6ca840c 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -32,6 +32,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(USELESS_VEC) } + + fn name(&self) -> &'static str { + "UselessVec" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index fb88b1371f7..8ccf2c69cc7 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -33,6 +33,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(WILDCARD_DEPENDENCIES) } + + fn name(&self) -> &'static str { + "WildcardDependencies" + } } impl EarlyLintPass for Pass { diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index c8c291c8cc8..36f7fee969b 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -175,6 +175,10 @@ impl LintPass for Pass { WRITE_LITERAL ) } + + fn name(&self) -> &'static str { + "Write" + } } impl EarlyLintPass for Pass { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 962d42e631e..a806be95432 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -28,6 +28,10 @@ impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(ZERO_DIVIDED_BY_ZERO) } + + fn name(&self) -> &'static str { + "ZeroDiv" + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { diff --git a/src/driver.rs b/src/driver.rs index 2faa77785bb..1ce6f6b7c49 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -123,7 +123,7 @@ pub fn main() { let sess = &state.session; let mut ls = sess.lint_store.borrow_mut(); for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); + ls.register_early_pass(Some(sess), true, false, pass); } for pass in late_lint_passes { ls.register_late_pass(Some(sess), true, pass); diff --git a/tests/ui/lint_without_lint_pass.rs b/tests/ui/lint_without_lint_pass.rs index 1f2fcd8faf6..a6f10a006db 100644 --- a/tests/ui/lint_without_lint_pass.rs +++ b/tests/ui/lint_without_lint_pass.rs @@ -25,6 +25,10 @@ impl lint::LintPass for Pass { fn get_lints(&self) -> lint::LintArray { lint_array!(TEST_LINT_REGISTERED) } + + fn name(&self) -> &'static str { + "TEST_LINT" + } } fn main() {} -- cgit 1.4.1-3-g733a5 From 1169066a0b501ae508461181b76c37d7e3b8ae6a Mon Sep 17 00:00:00 2001 From: Araam Borhanian <dobbybabee@gmail.com> Date: Sun, 13 Jan 2019 10:19:02 -0500 Subject: Adding lint for too many lines. --- clippy_lints/src/assign_ops.rs | 1 + clippy_lints/src/bit_mask.rs | 1 + clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/functions.rs | 77 +++++++++++++- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/loops.rs | 2 + clippy_lints/src/methods/mod.rs | 2 + clippy_lints/src/needless_pass_by_value.rs | 1 + clippy_lints/src/non_expressive_names.rs | 1 + clippy_lints/src/ptr.rs | 1 + clippy_lints/src/redundant_clone.rs | 1 + clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/types.rs | 7 +- clippy_lints/src/utils/author.rs | 2 + clippy_lints/src/utils/conf.rs | 2 + clippy_lints/src/utils/hir_utils.rs | 2 +- src/driver.rs | 1 + .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/functions_maxlines.rs | 112 +++++++++++++++++++++ tests/ui/functions_maxlines.stderr | 16 +++ tests/ui/matches.rs | 2 +- 21 files changed, 228 insertions(+), 13 deletions(-) create mode 100644 tests/ui/functions_maxlines.rs create mode 100644 tests/ui/functions_maxlines.stderr (limited to 'src') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index cc44b514ea7..2ef2a184746 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -64,6 +64,7 @@ impl LintPass for AssignOps { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { + #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { match &expr.node { hir::ExprKind::AssignOp(op, lhs, rhs) => { diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index d4e30376199..f052ad6e5ac 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -177,6 +177,7 @@ fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp } } +#[allow(clippy::too_many_lines)] fn check_bit_mask( cx: &LateContext<'_, '_>, bit_op: BinOpKind, diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 57291dd24ee..2602ad45986 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -59,7 +59,7 @@ impl LintPass for EqOp { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { - #[allow(clippy::similar_names)] + #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprKind::Binary(op, ref left, ref right) = e.node { if in_macro(e.span) { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index cb69e96c8e4..9710eba21ad 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,4 +1,4 @@ -use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function}; +use crate::utils::{iter_input_pats, snippet, span_lint, type_is_unsafe_function}; use matches::matches; use rustc::hir; use rustc::hir::def::Def; @@ -31,6 +31,22 @@ declare_clippy_lint! { "functions with too many arguments" } +/// **What it does:** Checks for functions with a large amount of lines. +/// +/// **Why is this bad?** Functions with a lot of lines are harder to understand +/// due to having to look at a larger amount of code to understand what the +/// function is doing. Consider splitting the body of the function into +/// multiple functions. +/// +/// **Known problems:** None. +/// +/// ``` +declare_clippy_lint! { + pub TOO_MANY_LINES, + pedantic, + "functions with too many lines" +} + /// **What it does:** Checks for public functions that dereferences raw pointer /// arguments but are not marked unsafe. /// @@ -62,17 +78,21 @@ declare_clippy_lint! { #[derive(Copy, Clone)] pub struct Functions { threshold: u64, + max_lines: u64 } impl Functions { - pub fn new(threshold: u64) -> Self { - Self { threshold } + pub fn new(threshold: u64, max_lines: u64) -> Self { + Self { + threshold, + max_lines + } } } impl LintPass for Functions { fn get_lints(&self) -> LintArray { - lint_array!(TOO_MANY_ARGUMENTS, NOT_UNSAFE_PTR_ARG_DEREF) + lint_array!(TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF) } fn name(&self) -> &'static str { @@ -123,6 +143,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } self.check_raw_ptr(cx, unsafety, decl, body, nodeid); + self.check_line_number(cx, span); } fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { @@ -153,6 +174,54 @@ impl<'a, 'tcx> Functions { } } + fn check_line_number(self, cx: &LateContext, span: Span) { + let code_snippet = snippet(cx, span, ".."); + let mut line_count = 0; + let mut in_comment = false; + for mut line in code_snippet.lines() { + if in_comment { + let end_comment_loc = match line.find("*/") { + Some(i) => i, + None => continue + }; + in_comment = false; + line = &line[end_comment_loc..]; + } + line = line.trim_left(); + if line.is_empty() || line.starts_with("//") { continue; } + if line.contains("/*") { + let mut count_line: bool = !line.starts_with("/*"); + let close_counts = line.match_indices("*/").count(); + let open_counts = line.match_indices("/*").count(); + + if close_counts > 1 || open_counts > 1 { + line_count += 1; + } else if close_counts == 1 { + match line.find("*/") { + Some(i) => { + line = line[i..].trim_left(); + if !line.is_empty() && !line.starts_with("//") { + count_line = true; + } + }, + None => continue + } + } else { + in_comment = true; + } + if count_line { line_count += 1; } + } else { + // No multipart comment, no single comment, non-empty string. + line_count += 1; + } + } + + if line_count > self.max_lines { + span_lint(cx, TOO_MANY_LINES, span, + "This function has a large number of lines.") + } + } + fn check_raw_ptr( self, cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 52cc2a88da4..8e8657c9d02 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -290,6 +290,7 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { } } +#[allow(clippy::too_many_lines)] #[rustfmt::skip] pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { let mut store = reg.sess.lint_store.borrow_mut(); @@ -427,7 +428,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new( conf.blacklisted_names.iter().cloned().collect() )); - reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold)); + reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold, conf.too_many_lines_threshold)); reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents.iter().cloned().collect())); reg.register_late_lint_pass(box neg_multiply::NegMultiply); reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); @@ -527,6 +528,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { enum_glob_use::ENUM_GLOB_USE, enum_variants::MODULE_NAME_REPETITIONS, enum_variants::PUB_ENUM_VARIANT_NAMES, + functions::TOO_MANY_LINES, if_not_else::IF_NOT_ELSE, infinite_iter::MAYBE_INFINITE_ITER, items_after_statements::ITEMS_AFTER_STATEMENTS, diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 4d6cc75135e..06266257d1e 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -472,6 +472,7 @@ impl LintPass for Pass { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { + #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { // we don't want to check expanded macros if in_macro(expr.span) { @@ -1066,6 +1067,7 @@ fn detect_manual_memcpy<'a, 'tcx>( /// Check for looping over a range and then indexing a sequence with it. /// The iteratee must be a range literal. +#[allow(clippy::too_many_lines)] fn check_for_loop_range<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 20ffc1fd406..4ce2ae03b9f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1005,6 +1005,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } /// Checks for the `OR_FUN_CALL` lint. +#[allow(clippy::too_many_lines)] fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. fn check_unwrap_or_default( @@ -1151,6 +1152,7 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa } /// Checks for the `EXPECT_FUN_CALL` lint. +#[allow(clippy::too_many_lines)] fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or // `&str` diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 73c0ed72d3b..a8cc5eeec9f 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -73,6 +73,7 @@ macro_rules! need { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { + #[allow(clippy::too_many_lines)] fn check_fn( &mut self, cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 3bdf2c38d23..fbf60db28ee 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -158,6 +158,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { ); } } + #[allow(clippy::too_many_lines)] fn check_name(&mut self, span: Span, name: Name) { let interned_name = name.as_str(); if interned_name.chars().any(char::is_uppercase) { diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index b990b7ab2bd..5a54971f49e 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -151,6 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass { } } +#[allow(clippy::too_many_lines)] fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<BodyId>) { let fn_def_id = cx.tcx.hir().local_def_id(fn_id); let sig = cx.tcx.fn_sig(fn_def_id); diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 7ac147c8ac1..5c994d8a2bc 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -80,6 +80,7 @@ impl LintPass for RedundantClone { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { + #[allow(clippy::too_many_lines)] fn check_fn( &mut self, cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 90cfcd56c3b..56e1aa4a4e1 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -226,7 +226,7 @@ impl LintPass for Transmute { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { - #[allow(clippy::similar_names)] + #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { if let ExprKind::Call(ref path_expr, ref args) = e.node { if let ExprKind::Path(ref qpath) = path_expr.node { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 939dd27c441..e81df4af383 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -240,8 +240,9 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) /// /// The parameter `is_local` distinguishes the context of the type; types from /// local bindings should only be checked for the `BORROWED_BOX` lint. -fn check_ty(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool) { - if in_macro(hir_ty.span) { +#[allow(clippy::too_many_lines)] +fn check_ty(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool) { + if in_macro(ast_ty.span) { return; } match hir_ty.node { @@ -1968,7 +1969,7 @@ impl LintPass for ImplicitHasher { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { - #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { use syntax_pos::BytePos; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 19c3f3ad230..5a76b965d26 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -194,6 +194,7 @@ struct PrintVisitor { } impl<'tcx> Visitor<'tcx> for PrintVisitor { + #[allow(clippy::too_many_lines)] fn visit_expr(&mut self, expr: &Expr) { print!(" if let ExprKind::"); let current = format!("{}.node", self.current); @@ -506,6 +507,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { } } + #[allow(clippy::too_many_lines)] fn visit_pat(&mut self, pat: &Pat) { print!(" if let PatKind::"); let current = format!("{}.node", self.current); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 55256a25427..4ab274e598f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -148,6 +148,8 @@ define_Conf! { (literal_representation_threshold, "literal_representation_threshold", 16384 => u64), /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>), + /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have + (too_many_lines_threshold, "too_many_lines_threshold", 101 => u64), } impl Default for Conf { diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index a176830be26..2b0b0e7121f 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -389,7 +389,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> { .hash(&mut self.s); } - #[allow(clippy::many_single_char_names)] + #[allow(clippy::many_single_char_names, clippy::too_many_lines)] pub fn hash_expr(&mut self, e: &Expr) { if let Some(e) = constant_simple(self.cx, self.tables, e) { return e.hash(&mut self.s); diff --git a/src/driver.rs b/src/driver.rs index 1ce6f6b7c49..b41895f3c2b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -20,6 +20,7 @@ fn show_version() { println!(env!("CARGO_PKG_VERSION")); } +#[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); exit( diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 05a04fb377a..ec2ac20684b 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `third-party` +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `third-party` error: aborting due to previous error diff --git a/tests/ui/functions_maxlines.rs b/tests/ui/functions_maxlines.rs new file mode 100644 index 00000000000..5d8baf438df --- /dev/null +++ b/tests/ui/functions_maxlines.rs @@ -0,0 +1,112 @@ +#![warn(clippy::all, clippy::pedantic)] + +// TOO_MANY_LINES +fn good_lines() { + /* println!("This is good."); */ + // println!("This is good."); + /* */ // println!("This is good."); + /* */ // println!("This is good."); + /* */ // println!("This is good."); + /* */ // println!("This is good."); + /* println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); */ + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); + println!("This is good."); +} + +fn bad_lines() { + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); +} + +fn main() {} diff --git a/tests/ui/functions_maxlines.stderr b/tests/ui/functions_maxlines.stderr new file mode 100644 index 00000000000..9e1b2fe568a --- /dev/null +++ b/tests/ui/functions_maxlines.stderr @@ -0,0 +1,16 @@ +error: This function has a large number of lines. + --> $DIR/functions_maxlines.rs:59:1 + | +LL | / fn bad_lines() { +LL | | println!("This is bad."); +LL | | println!("This is bad."); +LL | | println!("This is bad."); +... | +LL | | println!("This is bad."); +LL | | } + | |_^ + | + = note: `-D clippy::too-many-lines` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index 013f12a1a0e..a40b80378ef 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -1,6 +1,6 @@ #![feature(exclusive_range_pattern)] #![warn(clippy::all)] -#![allow(unused, clippy::redundant_pattern_matching)] +#![allow(unused, clippy::redundant_pattern_matching, clippy::too_many_lines)] #![warn(clippy::match_same_arms)] fn dummy() {} -- cgit 1.4.1-3-g733a5 From b5fd0108b3a6b8a9626645ac174cf653de576135 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge <jsgf@fb.com> Date: Tue, 15 Jan 2019 10:56:09 -0800 Subject: clippy-driver: more robust test to see if we're clippy-enabled Rather than looking for a fixed --emit arg set, just check to see if we're emitting metadata at all. This makes it more robust to being invoked by tools other than cargo (or if cargo changes its invocation). Issue #3663 --- Cargo.toml | 1 - src/driver.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 868f21c1a49..c3710485027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ path = "src/main.rs" [[bin]] name = "clippy-driver" -test = false path = "src/driver.rs" [dependencies] diff --git a/src/driver.rs b/src/driver.rs index b41895f3c2b..d290e403a31 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -20,6 +20,46 @@ fn show_version() { println!(env!("CARGO_PKG_VERSION")); } +/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If +/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. +fn arg_value<'a>( + args: impl IntoIterator<Item = &'a String>, + find_arg: &str, + pred: impl Fn(&str) -> bool, +) -> Option<&'a str> { + let mut args = args.into_iter().map(String::as_str); + + while let Some(arg) = args.next() { + let arg: Vec<_> = arg.splitn(2, '=').collect(); + if arg.get(0) != Some(&find_arg) { + continue; + } + + let value = arg.get(1).cloned().or_else(|| args.next()); + if value.as_ref().map_or(false, |p| pred(p)) { + return value; + } + } + None +} + +#[test] +fn test_arg_value() { + let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"] + .iter() + .map(|s| s.to_string()) + .collect(); + + assert_eq!(arg_value(None, "--foobar", |_| true), None); + assert_eq!(arg_value(&args, "--bar", |_| false), None); + assert_eq!(arg_value(&args, "--bar", |_| true), Some("bar")); + assert_eq!(arg_value(&args, "--bar", |p| p == "bar"), Some("bar")); + assert_eq!(arg_value(&args, "--bar", |p| p == "foo"), None); + assert_eq!(arg_value(&args, "--foobar", |p| p == "foo"), None); + assert_eq!(arg_value(&args, "--foobar", |p| p == "123"), Some("123")); + assert_eq!(arg_value(&args, "--foo", |_| true), None); +} + #[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); @@ -79,7 +119,7 @@ pub fn main() { // crate is // linted but not built let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") - || orig_args.iter().any(|s| s == "--emit=dep-info,metadata"); + || arg_value(&orig_args, "--emit", |val| val.split(',').any(|e| e == "metadata")).is_some(); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); -- cgit 1.4.1-3-g733a5 From 71d03ae29b175c5e99f4e978e90bab830cfbd530 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge <jsgf@fb.com> Date: Tue, 15 Jan 2019 11:39:23 -0800 Subject: clippy-driver: if --sysroot is specified on the command line, use that If the user explicitly sets sysroot on the command line, then use that value. Issue #3663 --- src/driver.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index d290e403a31..fbff693f887 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -72,8 +72,19 @@ pub fn main() { exit(0); } - let sys_root = option_env!("SYSROOT") - .map(String::from) + let mut orig_args: Vec<String> = env::args().collect(); + + // Get the sysroot, looking from most specific to this invocation to the least: + // - command line + // - runtime environment + // - SYSROOT + // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN + // - sysroot from rustc in the path + // - compile-time environment + let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); + let have_sys_root_arg = sys_root_arg.is_some(); + let sys_root = sys_root_arg + .map(|s| s.to_string()) .or_else(|| std::env::var("SYSROOT").ok()) .or_else(|| { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -89,11 +100,11 @@ pub fn main() { .and_then(|out| String::from_utf8(out.stdout).ok()) .map(|s| s.trim().to_owned()) }) + .or_else(|| option_env!("SYSROOT").map(String::from)) .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let mut orig_args: Vec<String> = env::args().collect(); if orig_args.len() <= 1 { std::process::exit(1); } @@ -104,7 +115,7 @@ pub fn main() { // this conditional check for the --sysroot flag is there so users can call // `clippy_driver` directly // without having to pass --sysroot or anything - let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { + let mut args: Vec<String> = if have_sys_root_arg { orig_args.clone() } else { orig_args -- cgit 1.4.1-3-g733a5 From 993e8ace8e82d28fc891d9cc84fa4b06754c3b58 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge <jeremy@goop.org> Date: Sat, 26 Jan 2019 16:44:52 -0800 Subject: Drive-by cleanups to cargo-clippy. No functional change. --- src/main.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 20466fc567d..208262ca30f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,10 +61,8 @@ where { let mut args = vec!["check".to_owned()]; - let mut found_dashes = false; for arg in old_args.by_ref() { - found_dashes |= arg == "--"; - if found_dashes { + if arg == "--" { break; } args.push(arg); @@ -82,11 +80,7 @@ where let target_dir = std::env::var_os("CLIPPY_DOGFOOD") .map(|_| { std::env::var_os("CARGO_MANIFEST_DIR").map_or_else( - || { - let mut fallback = std::ffi::OsString::new(); - fallback.push("clippy_dogfood"); - fallback - }, + || std::ffi::OsString::from("clippy_dogfood"), |d| { std::path::PathBuf::from(d) .join("target") -- cgit 1.4.1-3-g733a5 From 16881390e1f1d7cbf2737e0d78560d4eaa3bb8c1 Mon Sep 17 00:00:00 2001 From: Grzegorz <grzegorz.bartoszek@thaumatec.com> Date: Sun, 10 Feb 2019 13:35:44 +0100 Subject: removing redundant closures in the whole project --- clippy_dev/src/lib.rs | 4 ++-- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/cargo_common_metadata.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/non_expressive_names.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/mod.rs | 5 ++++- rustc_tools_util/src/lib.rs | 4 ++-- src/driver.rs | 4 ++-- tests/missing-test-files.rs | 2 +- tests/ui/map_clone.fixed | 1 + tests/ui/map_clone.rs | 1 + tests/ui/map_clone.stderr | 8 ++++---- 14 files changed, 24 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 1c7f372af6b..7fad43029ac 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -47,7 +47,7 @@ impl Lint { name: name.to_lowercase(), group: group.to_string(), desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), - deprecation: deprecation.map(|d| d.to_string()), + deprecation: deprecation.map(std::string::ToString::to_string), module: module.to_string(), } } @@ -178,7 +178,7 @@ fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> { // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. WalkDir::new("../clippy_lints/src") .into_iter() - .filter_map(|f| f.ok()) + .filter_map(std::result::Result::ok) .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 89dbba56130..a72944bbe02 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -326,7 +326,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_, '_>, items: &[NestedMetaItem]) { lint.span, &format!("unknown clippy lint: clippy::{}", name), |db| { - if name.as_str().chars().any(|c| c.is_uppercase()) { + if name.as_str().chars().any(char::is_uppercase) { let name_lower = name.as_str().to_lowercase(); match lint_store.check_lint_name( &name_lower, diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 124b11cc78c..1d37c03ff45 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -53,7 +53,7 @@ fn is_empty_str(value: &Option<String>) -> bool { fn is_empty_vec(value: &[String]) -> bool { // This works because empty iterators return true - value.iter().all(|v| v.is_empty()) + value.iter().all(std::string::String::is_empty) } pub struct Pass; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5a9364eddb6..759b3173978 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -267,7 +267,7 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { } }); - let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref())); + let (conf, errors) = utils::conf::read(file_name.as_ref().map(std::convert::AsRef::as_ref)); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4ce2ae03b9f..c9b27ef1615 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -829,7 +829,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let (method_names, arg_lists) = method_calls(expr, 2); let method_names: Vec<LocalInternedString> = method_names.iter().map(|s| s.as_str()).collect(); - let method_names: Vec<&str> = method_names.iter().map(|s| s.as_ref()).collect(); + let method_names: Vec<&str> = method_names.iter().map(std::convert::AsRef::as_ref).collect(); match method_names.as_slice() { ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false), @@ -1695,7 +1695,7 @@ fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Op if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node { if path.ident.name == "iter" && may_slice(cx, cx.tables.expr_ty(&args[0])) { - sugg::Sugg::hir_opt(cx, &args[0]).map(|sugg| sugg.addr()) + sugg::Sugg::hir_opt(cx, &args[0]).map(sugg::Sugg::addr) } else { None } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index fbf60db28ee..b1cd1910f5b 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -241,7 +241,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) continue; } - split_at = interned_name.chars().next().map(|c| c.len_utf8()); + split_at = interned_name.chars().next().map(char::len_utf8); } } span_lint_and_then( diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index b0b4394ebb8..ff802dbb3a8 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -14,7 +14,7 @@ use toml; pub fn file_from_args( args: &[source_map::Spanned<ast::NestedMetaItemKind>], ) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> { - for arg in args.iter().filter_map(|a| a.meta_item()) { + for arg in args.iter().filter_map(syntax::source_map::Spanned::meta_item) { if arg.name() == "conf_file" { return match arg.node { ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index a8b6a756b78..b5221bca007 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -142,7 +142,10 @@ pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> pub fn get_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Vec<&'static str> { let mut apb = AbsolutePathBuffer { names: vec![] }; tcx.push_item_path(&mut apb, def_id, false); - apb.names.iter().map(|n| n.get()).collect() + apb.names + .iter() + .map(syntax_pos::symbol::LocalInternedString::get) + .collect() } /// Check if type is struct, enum or union type with given def path. diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index f13fa12ccca..19c27754839 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -9,8 +9,8 @@ macro_rules! get_version_info { let crate_name = String::from(env!("CARGO_PKG_NAME")); let host_compiler = $crate::get_channel(); - let commit_hash = option_env!("GIT_HASH").map(|s| s.to_string()); - let commit_date = option_env!("COMMIT_DATE").map(|s| s.to_string()); + let commit_hash = option_env!("GIT_HASH").map(str::to_string); + let commit_date = option_env!("COMMIT_DATE").map(str::to_string); VersionInfo { major, diff --git a/src/driver.rs b/src/driver.rs index fbff693f887..34fc6fc7f9f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -47,7 +47,7 @@ fn arg_value<'a>( fn test_arg_value() { let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"] .iter() - .map(|s| s.to_string()) + .map(std::string::ToString::to_string) .collect(); assert_eq!(arg_value(None, "--foobar", |_| true), None); @@ -84,7 +84,7 @@ pub fn main() { let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); let have_sys_root_arg = sys_root_arg.is_some(); let sys_root = sys_root_arg - .map(|s| s.to_string()) + .map(std::string::ToString::to_string) .or_else(|| std::env::var("SYSROOT").ok()) .or_else(|| { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index bd0cee75644..d87bb4be3c3 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -32,7 +32,7 @@ fn explore_directory(dir: &Path) -> Vec<String> { let mut missing_files: Vec<String> = Vec::new(); let mut current_file = String::new(); let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect(); - files.sort_by_key(|e| e.path()); + files.sort_by_key(std::fs::DirEntry::path); for entry in &files { let path = entry.path(); if path.is_dir() { diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index af417815ed1..d804e838d5a 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -3,6 +3,7 @@ #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::redundant_closure)] fn main() { let _: Vec<i8> = vec![5_i8; 6].iter().cloned().collect(); diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 7dd2ce30202..d98cd939d8c 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -3,6 +3,7 @@ #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::redundant_closure)] fn main() { let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 504f4a01a4c..db7fa4f52fc 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:8:22 + --> $DIR/map_clone.rs:9:22 | LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![5_i8; 6].iter().cloned()` @@ -7,19 +7,19 @@ LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect(); = note: `-D clippy::map-clone` implied by `-D warnings` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:9:26 + --> $DIR/map_clone.rs:10:26 | LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: You are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:10:23 + --> $DIR/map_clone.rs:11:23 | LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![42, 43].iter().cloned()` error: You are needlessly cloning iterator elements - --> $DIR/map_clone.rs:22:29 + --> $DIR/map_clone.rs:23:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: Remove the map call -- cgit 1.4.1-3-g733a5 From c9d79c0c5e1052de6de9cb4eb395314452a1dbf2 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Tue, 26 Feb 2019 08:43:47 +0200 Subject: Remove `#[feature(try_from)]` `try_from` is now stable. --- clippy_lints/src/lib.rs | 1 - src/driver.rs | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1e2e861ea27..1acf2aa8ad2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -9,7 +9,6 @@ #![recursion_limit = "256"] #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![feature(crate_visibility_modifier)] -#![feature(try_from)] // FIXME: switch to something more ergonomic here, once available. // (currently there is no way to opt into sysroot crates w/o `extern crate`) diff --git a/src/driver.rs b/src/driver.rs index 34fc6fc7f9f..93ed964e04d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,7 +1,6 @@ // error-pattern:yummy #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(try_from)] #![allow(clippy::missing_docs_in_private_items)] // FIXME: switch to something more ergonomic here, once available. -- cgit 1.4.1-3-g733a5 From 0d4a19c0d113cde4c6cd6baaf6c48efed0113a58 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker <john.kare.alsaker@gmail.com> Date: Fri, 1 Feb 2019 23:28:14 +0100 Subject: Use the new rustc interface --- src/driver.rs | 116 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 93ed964e04d..1430ba70fbe 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -9,9 +9,10 @@ extern crate rustc_driver; #[allow(unused_extern_crates)] extern crate rustc_plugin; -use self::rustc_driver::{driver::CompileController, Compilation}; +#[allow(unused_extern_crates)] +extern crate rustc_interface; -use std::convert::TryInto; +use rustc_interface::interface; use std::path::Path; use std::process::{exit, Command}; @@ -60,10 +61,58 @@ fn test_arg_value() { } #[allow(clippy::too_many_lines)] + +struct ClippyCallbacks; + +impl rustc_driver::Callbacks for ClippyCallbacks { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + let sess = compiler.session(); + let mut registry = rustc_plugin::registry::Registry::new( + sess, + compiler.parse().expect( + "at this compilation stage \ + the crate must be parsed", + ).peek().span, + ); + registry.args_hidden = Some(Vec::new()); + + let conf = clippy_lints::read_conf(®istry); + clippy_lints::register_plugins(&mut registry, &conf); + + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, false, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, (to, deprecated_name)) in lint_groups { + ls.register_group(Some(sess), true, name, deprecated_name, to); + } + clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); + clippy_lints::register_renamed(&mut ls); + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + + // Continue execution + true + } +} + pub fn main() { rustc_driver::init_rustc_env_logger(); exit( - rustc_driver::run(move || { + rustc_driver::report_ices_to_stderr_if_any(move || { use std::env; if std::env::args().any(|a| a == "--version" || a == "-V") { @@ -144,58 +193,15 @@ pub fn main() { } } - let mut controller = CompileController::basic(); - if clippy_enabled { - controller.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 crate must be parsed", - ) - .span, - ); - registry.args_hidden = Some(Vec::new()); - - let conf = clippy_lints::read_conf(®istry); - clippy_lints::register_plugins(&mut registry, &conf); - - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, false, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); - } - clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); - clippy_lints::register_renamed(&mut ls); - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - }); - } - controller.compilation_done.stop = Compilation::Stop; - + let mut clippy = ClippyCallbacks; + let mut default = rustc_driver::DefaultCallbacks; + let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { + &mut clippy + } else { + &mut default + }; let args = args; - rustc_driver::run_compiler(&args, Box::new(controller), None, None) - }) - .try_into() - .expect("exit code too large"), + rustc_driver::run_compiler(&args, callbacks, None, None) + }).and_then(|result| result).is_err() as i32 ) } -- cgit 1.4.1-3-g733a5 From 1388f2488e09ae30a32eaf40f83d64c766ffa1e6 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker <john.kare.alsaker@gmail.com> Date: Sun, 10 Mar 2019 12:00:17 +0100 Subject: rustfmt --- src/driver.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 1430ba70fbe..e5925653655 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -8,9 +8,9 @@ #[allow(unused_extern_crates)] extern crate rustc_driver; #[allow(unused_extern_crates)] -extern crate rustc_plugin; -#[allow(unused_extern_crates)] extern crate rustc_interface; +#[allow(unused_extern_crates)] +extern crate rustc_plugin; use rustc_interface::interface; use std::path::Path; @@ -69,10 +69,14 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let sess = compiler.session(); let mut registry = rustc_plugin::registry::Registry::new( sess, - compiler.parse().expect( - "at this compilation stage \ - the crate must be parsed", - ).peek().span, + compiler + .parse() + .expect( + "at this compilation stage \ + the crate must be parsed", + ) + .peek() + .span, ); registry.args_hidden = Some(Vec::new()); @@ -195,13 +199,12 @@ pub fn main() { let mut clippy = ClippyCallbacks; let mut default = rustc_driver::DefaultCallbacks; - let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { - &mut clippy - } else { - &mut default - }; + let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = + if clippy_enabled { &mut clippy } else { &mut default }; let args = args; rustc_driver::run_compiler(&args, callbacks, None, None) - }).and_then(|result| result).is_err() as i32 + }) + .and_then(|result| result) + .is_err() as i32, ) } -- cgit 1.4.1-3-g733a5 From d43966a1760069180fad2ec05f9c2e33391d6c42 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro <alexreg@me.com> Date: Thu, 31 Jan 2019 01:15:29 +0000 Subject: Various cosmetic improvements. --- clippy_dev/src/lib.rs | 4 +- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 22 ++-- clippy_lints/src/assign_ops.rs | 18 ++-- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/block_in_if_condition.rs | 4 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/consts.rs | 42 ++++---- clippy_lints/src/copies.rs | 6 +- clippy_lints/src/deprecated_lints.rs | 2 +- clippy_lints/src/doc.rs | 4 +- clippy_lints/src/else_if_without_else.rs | 6 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/erasing_op.rs | 11 +- clippy_lints/src/escape.rs | 22 ++-- clippy_lints/src/eta_reduction.rs | 10 +- clippy_lints/src/eval_order_dependence.rs | 4 +- clippy_lints/src/identity_op.rs | 9 +- clippy_lints/src/indexing_slicing.rs | 4 +- clippy_lints/src/infinite_iter.rs | 11 +- clippy_lints/src/len_zero.rs | 6 +- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/lifetimes.rs | 9 +- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops.rs | 20 ++-- clippy_lints/src/matches.rs | 8 +- clippy_lints/src/methods/mod.rs | 46 ++++---- clippy_lints/src/misc.rs | 27 ++--- clippy_lints/src/misc_early.rs | 2 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/non_copy_const.rs | 34 +++--- clippy_lints/src/question_mark.rs | 16 +-- clippy_lints/src/ranges.rs | 27 ++--- clippy_lints/src/returns.rs | 5 +- clippy_lints/src/shadow.rs | 4 +- clippy_lints/src/slow_vector_initialization.rs | 6 +- clippy_lints/src/strings.rs | 9 +- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/types.rs | 46 ++++---- clippy_lints/src/use_self.rs | 9 +- clippy_lints/src/utils/camel_case.rs | 4 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/higher.rs | 4 +- clippy_lints/src/utils/hir_utils.rs | 10 +- clippy_lints/src/utils/mod.rs | 124 +++++++++++----------- clippy_lints/src/utils/sugg.rs | 20 ++-- clippy_lints/src/utils/usage.rs | 5 +- clippy_lints/src/vec.rs | 2 +- src/driver.rs | 2 +- src/lib.rs | 2 +- tests/ui/block_in_if_condition.rs | 2 +- tests/ui/cast_alignment.rs | 2 +- tests/ui/cast_ref_to_mut.rs | 4 +- tests/ui/crashes/ice-2760.rs | 2 +- tests/ui/crashes/ice-2774.rs | 6 +- tests/ui/crashes/used_underscore_binding_macro.rs | 2 +- tests/ui/dlist.rs | 2 +- tests/ui/doc.rs | 12 +-- tests/ui/doc.stderr | 2 +- tests/ui/format.rs | 24 ++--- tests/ui/if_same_then_else.rs | 4 +- tests/ui/len_zero.rs | 33 +++--- tests/ui/lifetimes.rs | 79 ++++++++------ tests/ui/matches.rs | 18 ++-- tests/ui/methods.rs | 86 +++++++-------- tests/ui/needless_borrowed_ref.rs | 8 +- tests/ui/toplevel_ref_arg.rs | 2 +- tests/ui/unicode.rs | 4 +- tests/ui/used_underscore_binding.rs | 14 +-- tests/ui/while_loop.rs | 2 +- 73 files changed, 501 insertions(+), 461 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 3efee458cdc..31b0a98c1ab 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -191,7 +191,7 @@ pub struct FileChange { pub new_lines: String, } -/// Replace a region in a file delimited by two lines matching regexes. +/// Replaces a region in a file delimited by two lines matching regexes. /// /// `path` is the relative path to the file on which you want to perform the replacement. /// @@ -225,7 +225,7 @@ where file_change } -/// Replace a region in a text delimited by two lines matching regexes. +/// Replaces a region in a text delimited by two lines matching regexes. /// /// * `text` is the input text on which you want to perform the replacement /// * `start` is a `&str` that describes the delimiter line before the region you want to replace. diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 28c536df0c5..fa586ad45c2 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -104,7 +104,7 @@ fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, mod } } -/// Returns false if the number of significant figures in `value` are +/// Returns `false` if the number of significant figures in `value` are /// less than `min_digits`; otherwise, returns true if `value` is equal /// to `constant`, rounded to the number of digits present in `value`. fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 8d366034ba5..5522cd6e41e 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,13 +1,14 @@ +use if_chain::if_chain; +use rustc::hir::{Expr, ExprKind}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_tool_lint, lint_array}; + use crate::consts::{constant, Constant}; -use crate::rustc::hir::{Expr, ExprKind}; -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast::LitKind; use crate::utils::{in_macro, is_direct_expn_of, span_help_and_lint}; -use if_chain::if_chain; declare_clippy_lint! { - /// **What it does:** Check to call assert!(true/false) + /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls. /// /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a /// panic!() or unreachable!() @@ -15,17 +16,18 @@ declare_clippy_lint! { /// **Known problems:** None /// /// **Example:** - /// ```no_run - /// assert!(false); + /// ```rust + /// assert!(false) /// // or - /// assert!(true); + /// assert!(true) /// // or /// const B: bool = false; - /// assert!(B); + /// assert!(B) /// ``` pub ASSERTIONS_ON_CONSTANTS, style, - "assert!(true/false) will be optimized out by the compiler/should probably be replaced by a panic!() or unreachable!()" + "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, \ + and should probably be replaced by a `panic!()` or `unreachable!()`" } pub struct AssertionsOnConstants; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 9e0b87bc377..720a3e0c546 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -1,13 +1,15 @@ -use crate::utils::{ - get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq, -}; -use crate::utils::{higher, sugg}; use if_chain::if_chain; +use rustc_errors::Applicability; use rustc::hir; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; -use rustc_errors::Applicability; + +use crate::utils::{ + get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, + SpanlessEq, +}; +use crate::utils::{higher, sugg}; declare_clippy_lint! { /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` @@ -19,7 +21,7 @@ declare_clippy_lint! { /// implementations that differ from the regular `Op` impl. /// /// **Example:** - /// ```ignore + /// ```rust /// let mut a = 5; /// ... /// a = a + b; @@ -36,12 +38,12 @@ declare_clippy_lint! { /// op= b`. /// /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have - /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore it suggests both. + /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. /// If `a op= a op b` is really the correct behaviour it should be /// written as `a = a op a op b` as it's less confusing. /// /// **Example:** - /// ```ignore + /// ```rust /// let mut a = 5; /// ... /// a += a + b; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 52af7e2d93b..c57b1c5366c 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -70,7 +70,7 @@ declare_clippy_lint! { /// ``` pub INEFFECTIVE_BIT_MASK, correctness, - "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`" + "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" } declare_clippy_lint! { diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 400a6a61a6e..f16631a5eff 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// ``` pub BLOCK_IN_IF_CONDITION_EXPR, style, - "braces that can be eliminated in conditions, e.g. `if { true } ...`" + "braces that can be eliminated in conditions, e.g., `if { true } ...`" } declare_clippy_lint! { @@ -39,7 +39,7 @@ declare_clippy_lint! { /// ``` pub BLOCK_IN_IF_CONDITION_STMT, style, - "complex blocks in conditions, e.g. `if { let x = true; x } ...`" + "complex blocks in conditions, e.g., `if { let x = true; x } ...`" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index dd4934f9090..00e0787a927 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -68,7 +68,7 @@ declare_clippy_lint! { /// ``` pub COLLAPSIBLE_IF, style, - "`if`s that can be collapsed (e.g. `if x { if y { ... } }` and `else { if x { ... } }`)" + "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 306395ed5be..8d71eb54277 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -21,27 +21,27 @@ use syntax_pos::symbol::Symbol; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant { - /// a String "abc" + /// A `String` (e.g., "abc"). Str(String), - /// a Binary String b"abc" + /// A binary string (e.g., `b"abc"`). Binary(Lrc<Vec<u8>>), - /// a single char 'a' + /// A single `char` (e.g., `'a'`). Char(char), - /// an integer's bit representation + /// An integer's bit representation. Int(u128), - /// an f32 + /// An `f32`. F32(f32), - /// an f64 + /// An `f64`. F64(f64), - /// true or false + /// `true` or `false`. Bool(bool), - /// an array of constants + /// An array of constants. Vec(Vec<Constant>), - /// also an array, but with only one constant, repeated N times + /// Also an array, but with only one constant, repeated N times. Repeat(Box<Constant>, u64), - /// a tuple of constants + /// A tuple of constants. Tuple(Vec<Constant>), - /// a literal with syntax error + /// A literal with syntax error. Err(Symbol), } @@ -53,15 +53,15 @@ impl PartialEq for Constant { (&Constant::Char(l), &Constant::Char(r)) => l == r, (&Constant::Int(l), &Constant::Int(r)) => l == r, (&Constant::F64(l), &Constant::F64(r)) => { - // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have - // `Fw32 == Fw64` so don’t compare them - // to_bits is required to catch non-matching 0.0, -0.0, and NaNs + // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have + // `Fw32 == Fw64`, so don’t compare them. + // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs. l.to_bits() == r.to_bits() }, (&Constant::F32(l), &Constant::F32(r)) => { - // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have - // `Fw32 == Fw64` so don’t compare them - // to_bits is required to catch non-matching 0.0, -0.0, and NaNs + // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have + // `Fw32 == Fw64`, so don’t compare them. + // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs. f64::from(l).to_bits() == f64::from(r).to_bits() }, (&Constant::Bool(l), &Constant::Bool(r)) => l == r, @@ -69,7 +69,8 @@ impl PartialEq for Constant { l == r }, (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv, - _ => false, // TODO: Are there inter-type equalities? + // TODO: are there inter-type equalities? + _ => false, } } } @@ -142,12 +143,13 @@ impl Constant { x => x, } }, - _ => None, // TODO: Are there any useful inter-type orderings? + // TODO: are there any useful inter-type orderings? + _ => None, } } } -/// parse a `LitKind` to a `Constant` +/// Parses a `LitKind` to a `Constant`. pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant { use syntax::ast::*; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index c6fbb38250c..39fc1025807 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -239,9 +239,9 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) { } } -/// Return the list of condition expressions and the list of blocks in a +/// Returns the list of condition expressions and the list of blocks in a /// sequence of `if/else`. -/// Eg. would return `([a, b], [c, d, e])` for the expression +/// E.g., this returns `([a, b], [c, d, e])` for the expression /// `if a { c } else if b { d } else { e }`. fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) { let mut conds = SmallVec::new(); @@ -272,7 +272,7 @@ fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) (conds, blocks) } -/// Return the list of bindings in a pattern. +/// Returns the list of bindings in a pattern. fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> { fn bindings_impl<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 7cb04d7a95b..62cef778917 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -90,7 +90,7 @@ declare_deprecated_lint! { /// counterparts, so this lint may suggest a change in behavior or the code may not compile. declare_deprecated_lint! { pub ASSIGN_OPS, - "using compound assignment operators (e.g. `+=`) is harmless" + "using compound assignment operators (e.g., `+=`) is harmless" } /// **What it does:** Nothing. This lint has been deprecated. diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index dda4ab7c3b0..27e066375be 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -257,8 +257,8 @@ fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &st } fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) { - /// Checks if a string is camel-case, ie. contains at least two uppercase - /// letter (`Clippy` is + /// Checks if a string is camel-case, i.e., contains at least two uppercase + /// letters (`Clippy` is /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded /// (`IDs` is ok). fn is_camel_case(s: &str) -> bool { diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index a306cff6eba..01380fd9680 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,4 +1,4 @@ -//! lint on if expressions with an else if, but without a final else branch +//! Lint on if expressions with an else if, but without a final else branch. use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use rustc::{declare_tool_lint, lint_array}; @@ -10,7 +10,7 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. /// - /// **Why is this bad?** Some coding guidelines require this (e.g. MISRA-C:2004 Rule 14.10). + /// **Why is this bad?** Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). /// /// **Known problems:** None. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// } else if x.is_negative() { /// b(); /// } else { - /// // we don't care about zero + /// // We don't care about zero. /// } /// ``` pub ELSE_IF_WITHOUT_ELSE, diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 44eba7a9fcb..903700f1aac 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ``` pub EQ_OP, correctness, - "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)" + "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" } declare_clippy_lint! { diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 247b3f678d8..bd53e622217 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,12 +1,13 @@ -use crate::consts::{constant_simple, Constant}; -use crate::utils::{in_macro, span_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; use syntax::source_map::Span; +use crate::consts::{constant_simple, Constant}; +use crate::utils::{in_macro, span_lint}; + declare_clippy_lint! { - /// **What it does:** Checks for erasing operations, e.g. `x * 0`. + /// **What it does:** Checks for erasing operations, e.g., `x * 0`. /// /// **Why is this bad?** The whole expression can be replaced by zero. /// This is most likely not the intended outcome and should probably be @@ -15,14 +16,14 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```ignore + /// ```rust /// 0 / x; /// 0 * x; /// x & 0 /// ``` pub ERASING_OP, correctness, - "using erasing operations, e.g. `x * 0` or `y & 0`" + "using erasing operations, e.g., `x * 0` or `y & 0`" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index c84552d60c1..2c6bfae6efe 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,4 +1,3 @@ -use crate::utils::span_lint; use rustc::hir::intravisit as visit; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -10,6 +9,8 @@ use rustc::util::nodemap::HirIdSet; use rustc::{declare_tool_lint, lint_array}; use syntax::source_map::Span; +use crate::utils::span_lint; + pub struct Pass { pub too_large_for_stack: u64, } @@ -67,7 +68,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { _: Span, hir_id: HirId, ) { - // If the method is an impl for a trait, don't warn + // If the method is an impl for a trait, don't warn. let parent_id = cx.tcx.hir().get_parent_item(hir_id); let parent_node = cx.tcx.hir().find_by_hir_id(parent_id); @@ -102,7 +103,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) { if let Categorization::Local(lid) = cmt.cat { if let Move(DirectRefMove) = mode { - // moved out or in. clearly can't be localized + // Moved out or in. Clearly can't be localized. self.set.remove(&lid); } } @@ -158,20 +159,20 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { ) { if let Categorization::Local(lid) = cmt.cat { match loan_cause { - // x.foo() - // Used without autodereffing (i.e. x.clone()) + // `x.foo()` + // Used without autoderef-ing (i.e., `x.clone()`). LoanCause::AutoRef | - // &x - // foo(&x) where no extra autoreffing is happening + // `&x` + // `foo(&x)` where no extra autoref-ing is happening. LoanCause::AddrOf | - // `match x` can move + // `match x` can move. LoanCause::MatchDiscriminant => { self.set.remove(&lid); } - // do nothing for matches, etc. These can't escape + // Do nothing for matches, etc. These can't escape. _ => {} } } @@ -182,8 +183,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { - // Large types need to be boxed to avoid stack - // overflows. + // Large types need to be boxed to avoid stack overflows. if ty.is_box() { self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack } else { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 29ee6ae1fed..81c359f25ae 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,4 +1,3 @@ -use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function}; use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass}; @@ -6,6 +5,8 @@ use rustc::ty; use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; +use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function}; + pub struct EtaPass; declare_clippy_lint! { @@ -19,18 +20,17 @@ declare_clippy_lint! { /// **Known problems:** If creating the closure inside the closure has a side- /// effect then moving the closure creation out will change when that side- /// effect runs. - /// See https://github.com/rust-lang/rust-clippy/issues/1439 for more - /// details. + /// See rust-lang/rust-clippy#1439 for more details. /// /// **Example:** - /// ```ignore + /// ```rust /// xs.map(|x| foo(x)) /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. pub REDUNDANT_CLOSURE, style, - "redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)" + "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)" } impl LintPass for EtaPass { diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 6bba31b15c1..90e6102dd84 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -286,7 +286,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> St /// A visitor that looks for reads from a variable. struct ReadVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, - /// The id of the variable we're looking for. + /// The ID of the variable we're looking for. var: ast::NodeId, /// The expressions where the write to the variable occurred (for reporting /// in the lint). @@ -351,7 +351,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { } } -/// Returns true if `expr` is the LHS of an assignment, like `expr = ...`. +/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`. fn is_in_assignment_position(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { if let Some(parent) = get_parent_expr(cx, expr) { if let ExprKind::Assign(ref lhs, _) = parent.node { diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 06546be817b..6d15e37454c 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,13 +1,14 @@ -use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, in_macro, snippet, span_lint, unsext}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::ty; use rustc::{declare_tool_lint, lint_array}; use syntax::source_map::Span; +use crate::consts::{constant_simple, Constant}; +use crate::utils::{clip, in_macro, snippet, span_lint, unsext}; + declare_clippy_lint! { - /// **What it does:** Checks for identity operations, e.g. `x + 0`. + /// **What it does:** Checks for identity operations, e.g., `x + 0`. /// /// **Why is this bad?** This code can be removed without changing the /// meaning. So it just obscures what's going on. Delete it mercilessly. @@ -20,7 +21,7 @@ declare_clippy_lint! { /// ``` pub IDENTITY_OP, complexity, - "using identity operations, e.g. `x + 0` or `y / 1`" + "using identity operations, e.g., `x + 0` or `y / 1`" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 696ce74b022..07fcec85863 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -103,7 +103,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { if let ExprKind::Index(ref array, ref index) = &expr.node { let ty = cx.tables.expr_ty(array); if let Some(range) = higher::range(cx, index) { - // Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..] + // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] if let ty::Array(_, s) = ty.sty { let size: u128 = s.assert_usize(cx.tcx).unwrap().into(); @@ -149,7 +149,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing { utils::span_help_and_lint(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg); } else { - // Catchall non-range index, i.e. [n] or [n << m] + // Catchall non-range index, i.e., [n] or [n << m] if let ty::Array(..) = ty.sty { // Index is a constant uint. if let Some(..) = constant(cx, cx.tables, index) { diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 1cee5348f44..689cd8fd3b0 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,13 +1,14 @@ -use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; +use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint}; + declare_clippy_lint! { /// **What it does:** Checks for iteration that is guaranteed to be infinite. /// /// **Why is this bad?** While there may be places where this is acceptable - /// (e.g. in event streams), in most cases this is simply an error. + /// (e.g., in event streams), in most cases this is simply an error. /// /// **Known problems:** None. /// @@ -26,7 +27,7 @@ declare_clippy_lint! { /// **What it does:** Checks for iteration that may be infinite. /// /// **Why is this bad?** While there may be places where this is acceptable - /// (e.g. in event streams), in most cases this is simply an error. + /// (e.g., in event streams), in most cases this is simply an error. /// /// **Known problems:** The code may have a condition to stop iteration, but /// this lint is not clever enough to analyze it. @@ -122,8 +123,8 @@ use self::Heuristic::{All, Always, Any, First}; /// a slice of (method name, number of args, heuristic, bounds) tuples /// that will be used to determine whether the method in question /// returns an infinite or possibly infinite iterator. The finiteness -/// is an upper bound, e.g. some methods can return a possibly -/// infinite iterator at worst, e.g. `take_while`. +/// is an upper bound, e.g., some methods can return a possibly +/// infinite iterator at worst, e.g., `take_while`. static HEURISTICS: &[(&str, usize, Heuristic, Finiteness)] = &[ ("zip", 2, All, Infinite), ("chain", 2, Any, Infinite), diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index cd7ae45c62a..4762ce760c9 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -274,9 +274,9 @@ fn check_len( } } -/// Check if this type has an `is_empty` method. +/// Checks if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { - /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`. + /// Gets an `AssociatedItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool { if let ty::AssociatedKind::Method = item.kind { if item.ident.name == "is_empty" { @@ -291,7 +291,7 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { } } - /// Check the inherent impl's items for an `is_empty(self)` method. + /// Checks 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(id) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d9c426fa77..4a7f23bc858 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -11,7 +11,7 @@ #![feature(crate_visibility_modifier)] // FIXME: switch to something more ergonomic here, once available. -// (currently there is no way to opt into sysroot crates w/o `extern crate`) +// (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] extern crate fmt_macros; #[allow(unused_extern_crates)] @@ -407,7 +407,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { ); store.register_removed( "assign_ops", - "using compound assignment operators (e.g. `+=`) is harmless", + "using compound assignment operators (e.g., `+=`) is harmless", ); store.register_removed( "if_let_redundant_pattern_matching", diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 0d417fb8b6b..9c07c9a94e0 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,5 +1,3 @@ -use crate::reexport::*; -use crate::utils::{last_path_segment, span_lint}; use matches::matches; use rustc::hir::def::Def; use rustc::hir::intravisit::*; @@ -10,6 +8,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use syntax::source_map::Span; use syntax::symbol::keywords; +use crate::reexport::*; +use crate::utils::{last_path_segment, span_lint}; + declare_clippy_lint! { /// **What it does:** Checks for lifetime annotations which can be removed by /// relying on lifetime elision. @@ -19,7 +20,7 @@ declare_clippy_lint! { /// them leads to more readable code. /// /// **Known problems:** Potential false negatives: we bail out if the function - /// has a `where` clause where lifetimes are mentioned. + /// has a where-clause where lifetimes are mentioned. /// /// **Example:** /// ```rust @@ -384,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { } } -/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to +/// Are any lifetimes mentioned in the where-clause? If yes, we don't try to /// reason about elision. fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool { for predicate in &where_clause.predicates { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7df8cbe95e9..5c2ca4b1c93 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -112,7 +112,7 @@ pub(super) enum Radix { } impl Radix { - /// Return a reasonable digit group size for this radix. + /// Returns a reasonable digit group size for this radix. crate fn suggest_grouping(&self) -> usize { match *self { Radix::Binary | Radix::Hexadecimal => 4, diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 9fe6504bd42..186ffbc6450 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -727,7 +727,7 @@ fn never_loop_expr(expr: &Expr, main_loop_id: HirId) -> NeverLoopResult { ExprKind::Continue(d) => { let id = d .target_id - .expect("target id can only be missing in the presence of compilation errors"); + .expect("target ID can only be missing in the presence of compilation errors"); if id == main_loop_id { NeverLoopResult::MayContinueMainLoop } else { @@ -953,7 +953,7 @@ fn get_indexed_assignments<'a, 'tcx>( } } -/// Check for for loops that sequentially copy items from one slice-like +/// Checks for for loops that sequentially copy items from one slice-like /// object to another. fn detect_manual_memcpy<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, @@ -1065,7 +1065,7 @@ fn detect_manual_memcpy<'a, 'tcx>( } } -/// Check for looping over a range and then indexing a sequence with it. +/// Checks for looping over a range and then indexing a sequence with it. /// The iteratee must be a range literal. #[allow(clippy::too_many_lines)] fn check_for_loop_range<'a, 'tcx>( @@ -1413,7 +1413,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex } } -/// Check for `for` loops over `Option`s and `Results` +/// Checks for `for` loops over `Option`s and `Results` fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr) { let ty = cx.tables.expr_ty(arg); if match_type(cx, ty, &paths::OPTION) { @@ -1507,7 +1507,7 @@ fn check_for_loop_explicit_counter<'a, 'tcx>( } } -/// Check for the `FOR_KV_MAP` lint. +/// Checks for the `FOR_KV_MAP` lint. fn check_for_loop_over_map_kv<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, @@ -1673,7 +1673,7 @@ fn check_for_mutation( delegate.mutation_span() } -/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. +/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `'_'`. fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool { match *pat { PatKind::Wild => true, @@ -1967,7 +1967,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { } } -/// Return true if the type of expr is one that provides `IntoIterator` impls +/// Returns `true` if the type of expr is one that provides `IntoIterator` impls /// for `&T` and `&mut T`, such as `Vec`. #[rustfmt::skip] fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr) -> bool { @@ -2022,7 +2022,7 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> { } } -/// Return true if expr contains a single break expr without destination label +/// Returns `true` if expr contains a single break expr without destination label /// and /// passed expression. The expression may be within a block. fn is_simple_break_expr(expr: &Expr) -> bool { @@ -2102,7 +2102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } } -/// Check whether a variable is initialized to zero at the start of a loop. +/// Checks whether a variable is initialized to zero at the start of a loop. struct InitializeVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, // context reference end_expr: &'tcx Expr, // the for loop. Stop scanning here. @@ -2336,7 +2336,7 @@ fn path_name(e: &Expr) -> Option<Name> { fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, expr: &'tcx Expr) { if constant(cx, cx.tables, cond).is_some() { - // A pure constant condition (e.g. while false) is not linted. + // A pure constant condition (e.g., while false) is not linted. return; } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 580d22845b0..e81bdd83426 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// ``` pub SINGLE_MATCH, style, - "a match statement with a single nontrivial arm (i.e. where the other arm is `_ => {}`) instead of `if let`" + "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`" } declare_clippy_lint! { @@ -335,7 +335,7 @@ fn check_single_match_opt_like( let path = match arms[1].pats[0].node { PatKind::TupleStruct(ref path, ref inner, _) => { - // contains any non wildcard patterns? e.g. Err(err) + // contains any non wildcard patterns? e.g., Err(err) if !inner.iter().all(is_wild) { return; } @@ -639,7 +639,7 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: & } } -/// Get all arms that are unbounded `PatRange`s. +/// Gets all arms that are unbounded `PatRange`s. fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> { arms.iter() .flat_map(|arm| { @@ -687,7 +687,7 @@ pub struct SpannedRange<T> { type TypedRanges = Vec<SpannedRange<u128>>; -/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway +/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway /// and other types than /// `Uint` and `Int` probably don't make sense. fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 42de11d6dac..d7ab3505765 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,12 +1,10 @@ -use crate::utils::paths; -use crate::utils::sugg; -use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, is_expn_of, - is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, - match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, -}; +mod option_map_unwrap_or; +mod unnecessary_filter_map; + +use std::borrow::Cow; +use std::fmt; +use std::iter; + use if_chain::if_chain; use matches::matches; use rustc::hir; @@ -15,15 +13,19 @@ use rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, use rustc::ty::{self, Predicate, Ty}; use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; -use std::borrow::Cow; -use std::fmt; -use std::iter; use syntax::ast; use syntax::source_map::{BytePos, Span}; use syntax::symbol::LocalInternedString; -mod option_map_unwrap_or; -mod unnecessary_filter_map; +use crate::utils::paths; +use crate::utils::sugg; +use crate::utils::{ + get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, is_expn_of, + is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, + match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, + single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, +}; #[derive(Clone)] pub struct Pass; @@ -55,7 +57,7 @@ declare_clippy_lint! { /// and propagate errors upwards with `try!`. /// /// Even if you want to panic on errors, not all `Error`s implement good - /// messages on display. Therefore it may be beneficial to look at the places + /// messages on display. Therefore, it may be beneficial to look at the places /// where they may get displayed. Activate this lint to do just that. /// /// **Known problems:** None. @@ -399,7 +401,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer, /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified - /// function syntax instead (e.g. `Rc::clone(foo)`). + /// function syntax instead (e.g., `Rc::clone(foo)`). /// /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak /// can obscure the fact that only the pointer is being cloned, not the underlying @@ -458,7 +460,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for string methods that receive a single-character - /// `str` as an argument, e.g. `_.split("x")`. + /// `str` as an argument, e.g., `_.split("x")`. /// /// **Why is this bad?** Performing these methods using a `char` is faster than /// using a `str`. @@ -469,7 +471,7 @@ declare_clippy_lint! { /// `_.split("x")` could be `_.split('x')` pub SINGLE_CHAR_PATTERN, perf, - "using a single-character str where a char could be used, e.g. `_.split(\"x\")`" + "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" } declare_clippy_lint! { @@ -1008,7 +1010,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { /// Checks for the `OR_FUN_CALL` lint. #[allow(clippy::too_many_lines)] fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { - /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. fn check_unwrap_or_default( cx: &LateContext<'_, '_>, name: &str, @@ -1057,7 +1059,7 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa false } - /// Check for `*or(foo())`. + /// Checks for `*or(foo())`. #[allow(clippy::too_many_arguments)] fn check_general_case( cx: &LateContext<'_, '_>, @@ -1546,7 +1548,7 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: cx, UNNECESSARY_FOLD, fold_span, - // TODO #2371 don't suggest e.g. .any(|x| f(x)) if we can suggest .any(f) + // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) "this `.fold` can be written more succinctly using another method", "try", sugg, @@ -2348,7 +2350,7 @@ impl SelfKind { // Self types in the HIR are desugared to explicit self types. So it will // always be `self: // SomeType`, - // where SomeType can be `Self` or an explicit impl self type (e.g. `Foo` if + // where SomeType can be `Self` or an explicit impl self type (e.g., `Foo` if // the impl is on `Foo`) // Thus, we only need to test equality against the impl self type or if it is // an explicit diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index f62d723e6aa..47969317524 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,10 +1,3 @@ -use crate::consts::{constant, Constant}; -use crate::utils::sugg::Sugg; -use crate::utils::{ - get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats, - last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty, - SpanlessEq, -}; use if_chain::if_chain; use matches::matches; use rustc::hir::intravisit::FnKind; @@ -16,6 +9,14 @@ use rustc_errors::Applicability; use syntax::ast::LitKind; use syntax::source_map::{ExpnFormat, Span}; +use crate::consts::{constant, Constant}; +use crate::utils::{ + get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats, + last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty, + SpanlessEq, +}; +use crate::utils::sugg::Sugg; + declare_clippy_lint! { /// **What it does:** Checks for function arguments and let bindings denoted as /// `ref`. @@ -31,10 +32,10 @@ declare_clippy_lint! { /// /// **Known problems:** If the argument is dereferenced within the function, /// removing the `ref` will lead to errors. This can be fixed by removing the - /// dereferences, e.g. changing `*x` to `x` within the function. + /// dereferences, e.g., changing `*x` to `x` within the function. /// /// **Example:** - /// ```ignore + /// ```rust /// fn foo(ref x: u8) -> bool { /// .. /// } @@ -99,7 +100,7 @@ declare_clippy_lint! { /// ``` pub CMP_OWNED, perf, - "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`" + "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`" } declare_clippy_lint! { @@ -552,7 +553,7 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) { lint_span, "this creates an owned instance just for comparison", |db| { - // this also catches PartialEq implementations that call to_owned + // This also catches `PartialEq` implementations that call `to_owned`. if other_gets_derefed { db.span_label(lint_span, "try implementing the comparison without allocating"); return; @@ -590,7 +591,7 @@ fn is_used(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { } } -/// Test whether an expression is in a macro expansion (e.g. something +/// Tests whether an expression is in a macro expansion (e.g., something /// generated by /// `#[derive(...)`] or the like). fn in_attributes_expansion(expr: &Expr) -> bool { @@ -601,7 +602,7 @@ fn in_attributes_expansion(expr: &Expr) -> bool { .map_or(false, |info| matches!(info.format, ExpnFormat::MacroAttribute(_))) } -/// Test whether `def` is a variable defined outside a macro. +/// Tests 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, _, _) => !in_macro(cx.tcx.hir().span(id)), diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index e42f0bfae89..3d41195f349 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -194,7 +194,7 @@ impl LintPass for MiscEarly { } } -// Used to find `return` statements or equivalents e.g. `?` +// Used to find `return` statements or equivalents e.g., `?` struct ReturnVisitor { found_return: bool, } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 41b5f6f3833..f37f7213503 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -20,7 +20,7 @@ declare_clippy_lint! { /// ``` pub MUT_MUT, pedantic, - "usage of double-mut refs, e.g. `&mut &mut ...`" + "usage of double-mut refs, e.g., `&mut &mut ...`" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 2a4f2bb1450..6e81ecac05f 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// ``` pub NEEDLESS_BOOL, complexity, - "if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`" + "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`" } declare_clippy_lint! { @@ -51,7 +51,7 @@ declare_clippy_lint! { /// ``` pub BOOL_COMPARISON, complexity, - "comparing a variable to a boolean, e.g. `if x == true` or `if x != true`" + "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" } #[derive(Copy, Clone)] diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index a3748d87a83..15d378bdd7f 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -176,7 +176,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { // // * Exclude a type that is specifically bounded by `Borrow`. - // * Exclude a type whose reference also fulfills its bound. (e.g. `std::convert::AsRef`, + // * Exclude a type whose reference also fulfills its bound. (e.g., `std::convert::AsRef`, // `serde::Serialize`) let (implements_borrow_trait, all_borrowable_trait) = { let preds = preds diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index eb8a19f2bbb..7b074f438f4 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -8,7 +8,7 @@ use crate::utils::{self, paths, span_lint}; declare_clippy_lint! { /// **What it does:** /// Checks for the usage of negated comparison operators on types which only implement - /// `PartialOrd` (e.g. `f64`). + /// `PartialOrd` (e.g., `f64`). /// /// **Why is this bad?** /// These operators make it easy to forget that the underlying types actually allow not only three diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 21130e36e46..9c184e8c54b 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,8 +1,9 @@ -//! Checks for uses of const which the type is not Freeze (Cell-free). +//! Checks for uses of const which the type is not `Freeze` (`Cell`-free). //! //! This lint is **deny** by default. -use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then}; +use std::ptr; + use rustc::hir::def::Def; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass}; @@ -11,14 +12,15 @@ use rustc::ty::{self, TypeFlags}; use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; use rustc_typeck::hir_ty_to_ty; -use std::ptr; use syntax_pos::{Span, DUMMY_SP}; +use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then}; + declare_clippy_lint! { /// **What it does:** Checks for declaration of `const` items which is interior - /// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc). + /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). /// - /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e. + /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e., /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` /// or `AtomicXxxx` will be created, which defeats the whole purpose of using /// these types in the first place. @@ -27,7 +29,7 @@ declare_clippy_lint! { /// variable is wanted, or replaced by a `const fn` if a constructor is wanted. /// /// **Known problems:** A "non-constant" const item is a legacy way to supply an - /// initialized value to downstream `static` items (e.g. the + /// initialized value to downstream `static` items (e.g., the /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. /// @@ -51,10 +53,10 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks if `const` items which is interior mutable (e.g. - /// contains a `Cell`, `Mutex`, `AtomicXxxx` etc) has been borrowed directly. + /// **What it does:** Checks if `const` items which is interior mutable (e.g., + /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. /// - /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e. + /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e., /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` /// or `AtomicXxxx` will be created, which defeats the whole purpose of using /// these types in the first place. @@ -108,8 +110,8 @@ impl Source { fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, source: Source) { if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) { - // an UnsafeCell is !Copy, and an UnsafeCell is also the only type which - // is !Freeze, thus if our type is Copy we can be sure it must be Freeze + // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which + // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze` // as well. return; } @@ -179,7 +181,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { if let ImplItemKind::Const(hir_ty, ..) = &impl_item.node { let item_hir_id = cx.tcx.hir().get_parent_node_by_hir_id(impl_item.hir_id); let item = cx.tcx.hir().expect_item_by_hir_id(item_hir_id); - // ensure the impl is an inherent impl. + // Ensure the impl is an inherent impl. if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node { let ty = hir_ty_to_ty(cx.tcx, hir_ty); verify_ty_bound( @@ -201,13 +203,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { return; } - // make sure it is a const item. + // Make sure it is a const item. match cx.tables.qpath_def(qpath, expr.hir_id) { Def::Const(_) | Def::AssociatedConst(_) => {}, _ => return, }; - // climb up to resolve any field access and explicit referencing. + // Climb up to resolve any field access and explicit referencing. let mut cur_expr = expr; let mut dereferenced_expr = expr; let mut needs_check_adjustment = true; @@ -219,7 +221,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find_by_hir_id(parent_id) { match &parent_expr.node { ExprKind::AddrOf(..) => { - // `&e` => `e` must be referenced + // `&e` => `e` must be referenced. needs_check_adjustment = false; }, ExprKind::Field(..) => { @@ -260,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst { adjustments[i - 1].target } } else { - // No borrow adjustments = the entire const is moved. + // No borrow adjustments means the entire const is moved. return; } } else { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 762401098e6..b9a8759da85 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,19 +1,19 @@ -use crate::utils::sugg::Sugg; use if_chain::if_chain; +use rustc::{declare_tool_lint, lint_array}; use rustc::hir::def::Def; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use rustc_errors::Applicability; use syntax::ptr::P; -use crate::utils::paths::*; use crate::utils::{match_def_path, match_type, span_lint_and_then, SpanlessEq}; -use rustc_errors::Applicability; +use crate::utils::paths::*; +use crate::utils::sugg::Sugg; declare_clippy_lint! { - /// **What it does:** Checks for expressions that could be replaced by the question mark operator + /// **What it does:** Checks for expressions that could be replaced by the question mark operator. /// - /// **Why is this bad?** Question mark usage is more idiomatic + /// **Why is this bad?** Question mark usage is more idiomatic. /// /// **Known problems:** None /// @@ -48,11 +48,11 @@ impl LintPass for Pass { } impl Pass { - /// Check if the given expression on the given context matches the following structure: + /// Checks if the given expression on the given context matches the following structure: /// /// ```ignore /// if option.is_none() { - /// return None; + /// return `None`; /// } /// ``` /// diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 928f209fc44..18dfb963230 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,6 +1,3 @@ -use crate::utils::sugg::Sugg; -use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq}; -use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then}; use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -9,6 +6,10 @@ use rustc_errors::Applicability; use syntax::ast::RangeLimits; use syntax::source_map::Spanned; +use crate::utils::sugg::Sugg; +use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq}; +use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then}; + declare_clippy_lint! { /// **What it does:** Checks for calling `.step_by(0)` on iterators, /// which never terminates. @@ -48,7 +49,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for exclusive ranges where 1 is added to the - /// upper bound, e.g. `x..(y+1)`. + /// upper bound, e.g., `x..(y+1)`. /// /// **Why is this bad?** The code is more readable with an inclusive range /// like `x..=y`. @@ -56,7 +57,7 @@ declare_clippy_lint! { /// **Known problems:** Will add unnecessary pair of parentheses when the /// expression is not wrapped in a pair but starts with a opening parenthesis /// and ends with a closing one. - /// I.e: `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. + /// I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. /// /// **Example:** /// ```rust @@ -69,7 +70,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for inclusive ranges where 1 is subtracted from - /// the upper bound, e.g. `x..=(y-1)`. + /// the upper bound, e.g., `x..=(y-1)`. /// /// **Why is this bad?** The code is more readable with an exclusive range /// like `x..y`. @@ -123,16 +124,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let iter = &args[0].node; let zip_arg = &args[1]; if_chain! { - // .iter() call + // `.iter()` call if let ExprKind::MethodCall(ref iter_path, _, ref iter_args ) = *iter; if iter_path.ident.name == "iter"; - // range expression in .zip() call: 0..x.len() + // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg); if is_integer_literal(start, 0); - // .len() call + // `.len()` call if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.node; if len_path.ident.name == "len" && len_args.len() == 1; - // .iter() and .len() called on same Path + // `.iter()` and `.len()` called on same `Path` if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].node; if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].node; if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); @@ -147,7 +148,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } - // exclusive range plus one: x..(y+1) + // exclusive range plus one: `x..(y+1)` if_chain! { if let Some(higher::Range { start, @@ -186,7 +187,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } - // inclusive range minus one: x..=(y-1) + // inclusive range minus one: `x..=(y-1)` if_chain! { if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr); if let Some(y) = y_minus_one(end); @@ -213,7 +214,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { - // No need for walk_ptrs_ty here because step_by moves self, so it + // No need for `walk_ptrs_ty` here because `step_by` moves `self`, so it // can't be called on a borrowed range. let ty = cx.tables.expr_ty_adjusted(expr); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 789ce8948fa..5458fa51c7c 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,4 +1,3 @@ -use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint}; use if_chain::if_chain; use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use rustc::{declare_tool_lint, lint_array}; @@ -8,6 +7,8 @@ use syntax::source_map::Span; use syntax::visit::FnKind; use syntax_pos::BytePos; +use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint}; + declare_clippy_lint! { /// **What it does:** Checks for return statements at the end of a block. /// @@ -69,7 +70,7 @@ declare_clippy_lint! { /// statement look like a function call. /// /// **Known problems:** The lint currently misses unit return types in types, - /// e.g. the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`. + /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`. /// /// **Example:** /// ```rust diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 9572dc7acb5..99580affef6 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ``` pub SHADOW_SAME, restriction, - "rebinding a name to itself, e.g. `let mut x = &mut x`" + "rebinding a name to itself, e.g., `let mut x = &mut x`" } declare_clippy_lint! { @@ -49,7 +49,7 @@ declare_clippy_lint! { /// ``` pub SHADOW_REUSE, restriction, - "rebinding a name to an expression that re-uses the original value, e.g. `let x = x + 1`" + "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`" } declare_clippy_lint! { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 7b4fd773212..9a6676588cb 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -194,13 +194,13 @@ impl Pass { struct VectorInitializationVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, - /// Contains the information + /// Contains the information. vec_alloc: VecAllocation<'tcx>, - /// Contains, if found, the slow initialization expression + /// Contains, the slow initialization expression, if one was found. slow_expression: Option<InitializationType<'tcx>>, - /// true if the initialization of the vector has been found on the visited block + /// `true` if the initialization of the vector has been found on the visited block. initialization_found: bool, } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 0f6603f9d28..cd23722bef4 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,11 +1,12 @@ -use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; use syntax::source_map::Spanned; +use crate::utils::SpanlessEq; +use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; + declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without /// `let`!). @@ -35,7 +36,7 @@ declare_clippy_lint! { /// `Add` implementation is asymmetric (the other operand need not be `String`, /// but `x` does), while addition as mathematically defined is symmetric, also /// the `String::push_str(_)` function is a perfectly good replacement. - /// Therefore some dislike it and wish not to have it in their code. + /// Therefore, some dislike it and wish not to have it in their code. /// /// That said, other people think that string addition, having a long tradition /// in other languages is actually fine, which is why we decided to make this @@ -58,7 +59,7 @@ declare_clippy_lint! { /// **What it does:** Checks for the `as_bytes` method called on string literals /// that contain only ASCII characters. /// - /// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used + /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used /// instead. They are shorter but less discoverable than `as_bytes()`. /// /// **Known Problems:** None. diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 65bd62863a0..2c4bfe7358d 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } } -/// Get the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is +/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is /// not available , use /// the type's `ToString` implementation. In weird cases it could lead to types /// with invalid `'_` diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index e9fee8e0223..889f6023c38 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1,12 +1,9 @@ #![allow(clippy::default_hash_types)] -use crate::consts::{constant, Constant}; -use crate::utils::paths; -use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, in_macro, int_bits, last_path_segment, - match_def_path, match_path, multispan_sugg, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, - span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext, AbsolutePathBuffer, -}; +use std::borrow::Cow; +use std::cmp::Ordering; +use std::collections::BTreeMap; + use if_chain::if_chain; use rustc::hir; use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; @@ -18,13 +15,18 @@ use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; -use std::borrow::Cow; -use std::cmp::Ordering; -use std::collections::BTreeMap; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::errors::DiagnosticBuilder; use syntax::source_map::Span; +use crate::consts::{constant, Constant}; +use crate::utils::paths; +use crate::utils::{ + clip, comparisons, differing_macro_contexts, higher, in_constant, in_macro, int_bits, last_path_segment, + match_def_path, match_path, multispan_sugg, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, + span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext, AbsolutePathBuffer, +}; + /// Handles all the linting of funky types pub struct TypePass; @@ -174,7 +176,7 @@ impl LintPass for TypePass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass { fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _: &Body, _: Span, id: HirId) { - // skip trait implementations, see #605 + // Skip trait implementations; see issue #605. if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_hir_id(cx.tcx.hir().get_parent_item(id)) { if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node { return; @@ -213,7 +215,7 @@ fn check_fn_decl(cx: &LateContext<'_, '_>, decl: &FnDecl) { } } -/// Check if `qpath` has last segment with type parameter matching `path` +/// Checks if `qpath` has last segment with type parameter matching `path` fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) -> bool { let last = last_path_segment(qpath); if_chain! { @@ -389,7 +391,7 @@ fn check_ty_rptr(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool, lt: }); then { if is_any_trait(inner) { - // Ignore `Box<Any>` types, see #1884 for details. + // Ignore `Box<Any>` types; see issue #1884 for details. return; } @@ -698,7 +700,7 @@ declare_clippy_lint! { /// ``` pub CAST_PRECISION_LOSS, pedantic, - "casts that cause loss of precision, e.g. `x as f32` where `x: u64`" + "casts that cause loss of precision, e.g., `x as f32` where `x: u64`" } declare_clippy_lint! { @@ -719,7 +721,7 @@ declare_clippy_lint! { /// ``` pub CAST_SIGN_LOSS, pedantic, - "casts from signed types to unsigned types, e.g. `x as u32` where `x: i32`" + "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`" } declare_clippy_lint! { @@ -741,13 +743,13 @@ declare_clippy_lint! { /// ``` pub CAST_POSSIBLE_TRUNCATION, pedantic, - "casts that may cause truncation of the value, e.g. `x as u8` where `x: u32`, or `x as i32` where `x: f32`" + "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`" } declare_clippy_lint! { /// **What it does:** Checks for casts from an unsigned type to a signed type of /// the same size. Performing such a cast is a 'no-op' for the compiler, - /// i.e. nothing is changed at the bit level, and the binary representation of + /// i.e., nothing is changed at the bit level, and the binary representation of /// the value is reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. @@ -764,7 +766,7 @@ declare_clippy_lint! { /// ``` pub CAST_POSSIBLE_WRAP, pedantic, - "casts that may cause wrapping around the value, e.g. `x as i32` where `x: u32` and `x > i32::MAX`" + "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`" } declare_clippy_lint! { @@ -796,7 +798,7 @@ declare_clippy_lint! { /// ``` pub CAST_LOSSLESS, complexity, - "casts using `as` that are known to be lossless, e.g. `x as u64` where `x: u8`" + "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" } declare_clippy_lint! { @@ -812,7 +814,7 @@ declare_clippy_lint! { /// ``` pub UNNECESSARY_CAST, complexity, - "cast to the same type, e.g. `x as i32` where `x: i32`" + "cast to the same type, e.g., `x as i32` where `x: i32`" } declare_clippy_lint! { @@ -1528,14 +1530,14 @@ declare_clippy_lint! { /// `max < x` are probably mistakes. /// /// **Known problems:** For `usize` the size of the current compile target will - /// be assumed (e.g. 64 bits on 64 bit systems). This means code that uses such + /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such /// a comparison to detect target pointer width will trigger this lint. One can /// use `mem::sizeof` and compare its value or conditional compilation /// attributes /// like `#[cfg(target_pointer_width = "64")] ..` instead. /// /// **Example:** - /// ```ignore + /// ```rust /// vec.len() <= 0 /// 100 > std::i32::MAX /// ``` diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5144e8076ab..a2fc8bcc4a6 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,4 +1,3 @@ -use crate::utils::span_lint_and_sugg; use if_chain::if_chain; use rustc::hir::def::{CtorKind, Def}; use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor}; @@ -9,6 +8,8 @@ use rustc::{declare_tool_lint, lint_array}; use rustc_errors::Applicability; use syntax_pos::symbol::keywords::SelfUpper; +use crate::utils::span_lint_and_sugg; + declare_clippy_lint! { /// **What it does:** Checks for unnecessary repetition of structure name when a /// replacement with `Self` is applicable. @@ -60,9 +61,9 @@ impl LintPass for UseSelf { const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) { - // path segments only include actual path, no methods or fields + // Path segments only include actual path, no methods or fields. let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span; - // only take path up to the end of last_path_span + // Only take path up to the end of last_path_span. let span = path.span.with_hi(last_path_span.hi()); span_lint_and_sugg( @@ -149,7 +150,7 @@ fn check_trait_method_impl_decl<'a, 'tcx: 'a>( // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature. // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for - // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self` + // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self` // and use `impl_ty` to check its concrete type. for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip( impl_method_sig diff --git a/clippy_lints/src/utils/camel_case.rs b/clippy_lints/src/utils/camel_case.rs index b49287b30d1..48fbc79298e 100644 --- a/clippy_lints/src/utils/camel_case.rs +++ b/clippy_lints/src/utils/camel_case.rs @@ -1,4 +1,4 @@ -/// Return the index of the character after the first camel-case component of +/// Returns the index of the character after the first camel-case component of /// `s`. pub fn until(s: &str) -> usize { let mut iter = s.char_indices(); @@ -32,7 +32,7 @@ pub fn until(s: &str) -> usize { } } -/// Return index of the last camel-case component of `s`. +/// Returns index of the last camel-case component of `s`. pub fn from(s: &str) -> usize { let mut iter = s.char_indices().rev(); if let Some((_, first)) = iter.next() { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 9efaeeb2e37..64243203b7f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -10,7 +10,7 @@ use std::{env, fmt, fs, io, path}; use syntax::{ast, source_map}; use toml; -/// Get the configuration file from arguments. +/// Gets the configuration file from arguments. pub fn file_from_args( args: &[source_map::Spanned<ast::NestedMetaItemKind>], ) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> { diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 9095c49a2ac..bb4c18ea2bb 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -9,7 +9,7 @@ use rustc::lint::LateContext; use rustc::{hir, ty}; use syntax::ast; -/// Convert a hir binary operator to the corresponding `ast` type. +/// Converts a hir binary operator to the corresponding `ast` type. pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind { match op { hir::BinOpKind::Eq => ast::BinOpKind::Eq, @@ -46,7 +46,7 @@ pub struct Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. pub fn range<'a, 'b, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'b hir::Expr) -> Option<Range<'b>> { - /// Find the field named `name` in the field. Always return `Some` for + /// Finds 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.ident.name == name)?.expr; diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 53876fef579..e084ed8224c 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -40,7 +40,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } } - /// Check whether two statements are the same. + /// Checks whether two statements are the same. pub fn eq_stmt(&mut self, left: &Stmt, right: &Stmt) -> bool { match (&left.node, &right.node) { (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => { @@ -55,7 +55,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { } } - /// Check whether two blocks are the same. + /// Checks whether two blocks are the same. pub fn eq_block(&mut self, left: &Block, right: &Block) -> bool { over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) @@ -186,7 +186,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { left.name == right.name } - /// Check whether two patterns are the same. + /// Checks whether two patterns are the same. pub fn eq_pat(&mut self, left: &Pat, right: &Pat) -> bool { match (&left.node, &right.node) { (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), @@ -328,7 +328,7 @@ fn swap_binop<'a>(binop: BinOpKind, lhs: &'a Expr, rhs: &'a Expr) -> Option<(Bin } } -/// Check if the two `Option`s are both `None` or some equal values as per +/// Checks if the two `Option`s are both `None` or some equal values as per /// `eq_fn`. fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool where @@ -338,7 +338,7 @@ where .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) } -/// Check if two slices are equal as per `eq_fn`. +/// Checks if two slices are equal as per `eq_fn`. fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool where F: FnMut(&X, &X) -> bool, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 7615afd407e..036c5306f25 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1,4 +1,25 @@ -use crate::reexport::*; +pub mod attrs; +pub mod author; +pub mod camel_case; +pub mod comparisons; +pub mod conf; +pub mod constants; +mod diagnostics; +pub mod higher; +mod hir_utils; +pub mod inspector; +pub mod internal_lints; +pub mod paths; +pub mod ptr; +pub mod sugg; +pub mod usage; +pub use self::attrs::*; +pub use self::diagnostics::*; +pub use self::hir_utils::{SpanlessEq, SpanlessHash}; + +use std::borrow::Cow; +use std::mem; + use if_chain::if_chain; use matches::matches; use rustc::hir; @@ -17,36 +38,16 @@ use rustc::ty::{ }; use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; -use std::borrow::Cow; -use std::mem; use syntax::ast::{self, LitKind}; use syntax::attr; use syntax::source_map::{Span, DUMMY_SP}; use syntax::symbol; use syntax::symbol::{keywords, Symbol}; -pub mod attrs; -pub mod author; -pub mod camel_case; -pub mod comparisons; -pub mod conf; -pub mod constants; -mod diagnostics; -pub mod higher; -mod hir_utils; -pub mod inspector; -pub mod internal_lints; -pub mod paths; -pub mod ptr; -pub mod sugg; -pub mod usage; -pub use self::attrs::*; -pub use self::diagnostics::*; -pub use self::hir_utils::{SpanlessEq, SpanlessHash}; +use crate::reexport::*; -/// Returns true if the two spans come from differing expansions (i.e. one is -/// from a macro and one -/// isn't). +/// Returns `true` if the two spans come from differing expansions (i.e., one is +/// from a macro and one isn't). pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt() != lhs.ctxt() } @@ -88,7 +89,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { } } -/// Returns true if this `expn_info` was expanded by any macro. +/// Returns `true` if this `expn_info` was expanded by any macro. pub fn in_macro(span: Span) -> bool { span.ctxt().outer().expn_info().is_some() } @@ -112,7 +113,7 @@ impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer { } } -/// Check if a `DefId`'s path matches the given absolute type path usage. +/// Checks if a `DefId`'s path matches the given absolute type path usage. /// /// # Examples /// ```rust,ignore @@ -128,7 +129,7 @@ pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> apb.names.len() == path.len() && apb.names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b) } -/// Get the absolute path of `def_id` as a vector of `&str`. +/// Gets the absolute path of `def_id` as a vector of `&str`. /// /// # Examples /// ```rust,ignore @@ -146,7 +147,7 @@ pub fn get_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Vec<&'static str> .collect() } -/// Check if type is struct, enum or union type with given def path. +/// Checks if type is struct, enum or union type with given def path. pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool { match ty.sty { ty::Adt(adt, _) => match_def_path(cx.tcx, adt.did, path), @@ -154,7 +155,7 @@ pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool { } } -/// Check if the method call given in `expr` belongs to given trait. +/// Checks if the method call given in `expr` belongs to given trait. pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) -> bool { let method_call = cx.tables.type_dependent_defs()[expr.hir_id]; let trt_id = cx.tcx.trait_of_item(method_call.def_id()); @@ -165,7 +166,7 @@ pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) } } -/// Check if an expression references a variable of the given name. +/// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr, var: Name) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.node { if path.segments.len() == 1 && path.segments[0].ident.name == var { @@ -190,7 +191,7 @@ pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> { } } -/// Match a `QPath` against a slice of segment string literals. +/// Matches a `QPath` against a slice of segment string literals. /// /// There is also `match_path` if you are dealing with a `rustc::hir::Path` instead of a /// `rustc::hir::QPath`. @@ -213,7 +214,7 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool { } } -/// Match a `Path` against a slice of segment string literals. +/// Matches a `Path` against a slice of segment string literals. /// /// There is also `match_qpath` if you are dealing with a `rustc::hir::QPath` instead of a /// `rustc::hir::Path`. @@ -237,7 +238,7 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name == *b) } -/// Match a `Path` against a slice of segment string literals, e.g. +/// Matches a `Path` against a slice of segment string literals, e.g. /// /// # Examples /// ```rust,ignore @@ -251,7 +252,7 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name == *b) } -/// Get the definition associated to a path. +/// Gets the definition associated to a path. pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def> { let crates = cx.tcx.crates(); let krate = crates.iter().find(|&&krate| cx.tcx.crate_name(krate) == path[0]); @@ -298,7 +299,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<DefId } } -/// Check whether a type implements a trait. +/// Checks whether a type implements a trait. /// See also `get_trait_def_id`. pub fn implements_trait<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, @@ -320,7 +321,7 @@ pub fn implements_trait<'a, 'tcx>( .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) } -/// Get the `hir::TraitRef` of the trait the given method is implemented for +/// Gets the `hir::TraitRef` of the trait the given method is implemented for. /// /// Use this if you want to find the `TraitRef` of the `Add` trait in this example: /// @@ -347,7 +348,7 @@ pub fn trait_ref_of_method(cx: &LateContext<'_, '_>, hir_id: HirId) -> Option<Tr None } -/// Check whether this type implements Drop. +/// Checks whether this type implements `Drop`. pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), @@ -355,12 +356,12 @@ pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { } } -/// Resolve the definition of a node from its `HirId`. +/// Resolves the definition of a node from its `HirId`. pub fn resolve_node(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> def::Def { cx.tables.qpath_def(qpath, id) } -/// Return the method names and argument list of nested method call expressions that make up +/// Returns the method names and argument list of nested method call expressions that make up /// `expr`. pub fn method_calls<'a>(expr: &'a Expr, max_depth: usize) -> (Vec<Symbol>, Vec<&'a [Expr]>) { let mut method_names = Vec::with_capacity(max_depth); @@ -383,7 +384,7 @@ pub fn method_calls<'a>(expr: &'a Expr, max_depth: usize) -> (Vec<Symbol>, Vec<& (method_names, arg_lists) } -/// Match an `Expr` against a chain of methods, and return the matched `Expr`s. +/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s. /// /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, /// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` @@ -408,11 +409,12 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a return None; } } - matched.reverse(); // reverse `matched`, so that it is in the same order as `methods` + // Reverse `matched` so that it is in the same order as `methods`. + matched.reverse(); Some(matched) } -/// Returns true if the provided `def_id` is an entrypoint to a program +/// Returns `true` if the provided `def_id` is an entrypoint to a program. pub fn is_entrypoint_fn(cx: &LateContext<'_, '_>, def_id: DefId) -> bool { if let Some((entry_fn_def_id, _)) = cx.tcx.entry_fn(LOCAL_CRATE) { return def_id == entry_fn_def_id; @@ -420,7 +422,7 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_, '_>, def_id: DefId) -> bool { false } -/// Get the name of the item the expression is in, if available. +/// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); match cx.tcx.hir().find_by_hir_id(parent_id) { @@ -432,7 +434,7 @@ pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> { } } -/// Get the name of a `Pat`, if any +/// Gets the name of a `Pat`, if any pub fn get_pat_name(pat: &Pat) -> Option<Name> { match pat.node { PatKind::Binding(.., ref spname, _) => Some(spname.name), @@ -458,14 +460,14 @@ impl<'tcx> Visitor<'tcx> for ContainsName { } } -/// check if an `Expr` contains a certain name +/// Checks if an `Expr` contains a certain name. pub fn contains_name(name: Name, expr: &Expr) -> bool { let mut cn = ContainsName { name, result: false }; cn.visit_expr(expr); cn.result } -/// Convert a span to a code snippet if available, otherwise use default. +/// Converts a span to a code snippet if available, otherwise use default. /// /// This is useful if you want to provide suggestions for your lint or more generally, if you want /// to convert a given `Span` to a `str`. @@ -510,12 +512,12 @@ pub fn snippet_with_macro_callsite<'a, 'b, T: LintContext<'b>>(cx: &T, span: Spa snippet(cx, span.source_callsite(), default) } -/// Convert a span to a code snippet. Returns `None` if not available. +/// Converts a span to a code snippet. Returns `None` if not available. pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> { cx.sess().source_map().span_to_snippet(span).ok() } -/// Convert a span (from a block) to a code snippet if available, otherwise use +/// Converts a span (from a block) to a code snippet if available, otherwise use /// default. /// This trims the code of indentation, except for the first line. Use it for /// blocks or block-like @@ -612,7 +614,7 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_ } } -/// Get a parent expressions if any – this is useful to constrain a lint. +/// Gets a parent expressions if any – this is useful to constrain a lint. pub fn get_parent_expr<'c>(cx: &'c LateContext<'_, '_>, e: &Expr) -> Option<&'c Expr> { let map = &cx.tcx.hir(); let hir_id = e.hir_id; @@ -656,7 +658,7 @@ pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: HirId } } -/// Return the base type for HIR references and pointers. +/// Returns the base type for HIR references and pointers. pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty { match ty.node { TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), @@ -664,7 +666,7 @@ pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty { } } -/// Return the base type for references and raw pointers. +/// Returns the base type for references and raw pointers. pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { match ty.sty { ty::Ref(_, ty, _) => walk_ptrs_ty(ty), @@ -672,7 +674,7 @@ pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> { } } -/// Return the base type for references and raw pointers, and count reference +/// Returns the base type for references and raw pointers, and count reference /// depth. pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { @@ -684,7 +686,7 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { inner(ty, 0) } -/// Check whether the given expression is a constant literal of the given value. +/// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr, value: u128) -> bool { // FIXME: use constant folding if let ExprKind::Lit(ref spanned) = expr.node { @@ -706,7 +708,7 @@ pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool { cx.tables.adjustments().get(e.hir_id).is_some() } -/// Return the pre-expansion span if is this comes from an expansion of the +/// Returns the pre-expansion span if is this comes from an expansion of the /// macro `name`. /// See also `is_direct_expn_of`. pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { @@ -725,7 +727,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { } } -/// Return the pre-expansion span if is this directly comes from an expansion +/// Returns the pre-expansion span if is this directly comes from an expansion /// of the macro `name`. /// The difference with `is_expn_of` is that in /// ```rust,ignore @@ -754,7 +756,7 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: hir::HirId) -> T cx.tcx.erase_late_bound_regions(&ret_ty) } -/// Check if two types are the same. +/// Checks if two types are the same. /// /// This discards any lifetime annotations, too. // FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for @@ -768,7 +770,7 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok()) } -/// Return whether the given type is an `unsafe` function. +/// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe, @@ -780,7 +782,7 @@ pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { ty.is_copy_modulo_regions(cx.tcx.global_tcx(), cx.param_env, DUMMY_SP) } -/// Return whether a pattern is refutable. +/// Returns `true` if a pattern is refutable. pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat) -> bool { fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> bool { matches!( @@ -869,7 +871,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl, body: &'tcx Body) -> impl Iterator<I (0..decl.inputs.len()).map(move |i| &body.arguments[i]) } -/// Check if a given expression is a match expression +/// Checks if a given expression is a match expression /// expanded from `?` operator or `try` macro. pub fn is_try<'a>(cx: &'_ LateContext<'_, '_>, expr: &'a Expr) -> Option<&'a Expr> { fn is_ok(cx: &'_ LateContext<'_, '_>, arm: &Arm) -> bool { @@ -916,7 +918,7 @@ pub fn is_try<'a>(cx: &'_ LateContext<'_, '_>, expr: &'a Expr) -> Option<&'a Exp None } -/// Returns true if the lint is allowed in the current context +/// Returns `true` if the lint is allowed in the current context /// /// Useful for skipping long running code when it's unnecessary pub fn is_allowed(cx: &LateContext<'_, '_>, lint: &'static Lint, id: HirId) -> bool { @@ -960,7 +962,7 @@ pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 { (u << amt) >> amt } -/// Remove block comments from the given Vec of lines +/// Removes block comments from the given `Vec` of lines. /// /// # Examples /// diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 7ff7b71ffa4..231d5ce90d6 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -240,9 +240,9 @@ impl<'a> Sugg<'a> { } } - /// Add parenthesis to any expression that might need them. Suitable to the + /// Adds parenthesis to any expression that might need them. Suitable to the /// `self` argument of - /// a method call (eg. to build `bar.foo()` or `(1 + 2).foo()`). + /// a method call (e.g., to build `bar.foo()` or `(1 + 2).foo()`). pub fn maybe_par(self) -> Self { match self { Sugg::NonParen(..) => self, @@ -289,7 +289,7 @@ struct ParenHelper<T> { } impl<T> ParenHelper<T> { - /// Build a `ParenHelper`. + /// Builds a `ParenHelper`. fn new(paren: bool, wrapped: T) -> Self { Self { paren, wrapped } } @@ -305,7 +305,7 @@ impl<T: Display> Display for ParenHelper<T> { } } -/// Build the string for `<op><expr>` adding parenthesis when necessary. +/// Builds the string for `<op><expr>` adding parenthesis when necessary. /// /// For convenience, the operator is taken as a string because all unary /// operators have the same @@ -314,7 +314,7 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into()) } -/// Build the string for `<lhs> <op> <rhs>` adding parenthesis when necessary. +/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary. /// /// Precedence of shift operator relative to other arithmetic operation is /// often confusing so @@ -413,7 +413,7 @@ enum Associativity { Right, } -/// Return the associativity/fixity of an operator. The difference with +/// Returns the associativity/fixity of an operator. The difference with /// `AssocOp::fixity` is that /// an operator can be both left and right associative (such as `+`: /// `a + b + c == (a + b) + c == a + (b + c)`. @@ -433,7 +433,7 @@ fn associativity(op: &AssocOp) -> Associativity { } } -/// Convert a `hir::BinOp` to the corresponding assigning binary operator. +/// Converts a `hir::BinOp` to the corresponding assigning binary operator. fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { use syntax::parse::token::BinOpToken::*; @@ -460,7 +460,7 @@ fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { }) } -/// Convert an `ast::BinOp` to the corresponding assigning binary operator. +/// Converts an `ast::BinOp` to the corresponding assigning binary operator. fn astbinop2assignop(op: ast::BinOp) -> AssocOp { use syntax::ast::BinOpKind::*; use syntax::parse::token::BinOpToken; @@ -480,13 +480,13 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp { }) } -/// Return the indentation before `span` if there are nothing but `[ \t]` +/// Returns the indentation before `span` if there are nothing but `[ \t]` /// before it on its line. fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> { let lo = cx.sess().source_map().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') { - // we can mix char and byte positions here because we only consider `[ \t]` + // We can mix char and byte positions here because we only consider `[ \t]`. if lo.col == CharPos(pos) { Some(line[..pos].into()) } else { diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index f4c89a8caec..521ddbc0865 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,7 +1,6 @@ -use rustc::lint::LateContext; - use rustc::hir::def::Def; use rustc::hir::*; +use rustc::lint::LateContext; use rustc::middle::expr_use_visitor::*; use rustc::middle::mem_categorization::cmt_; use rustc::middle::mem_categorization::Categorization; @@ -9,7 +8,7 @@ use rustc::ty; use rustc_data_structures::fx::FxHashSet; use syntax::source_map::Span; -/// Returns a set of mutated local variable ids or None if mutations could not be determined. +/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'a, 'tcx: 'a>(expr: &'tcx Expr, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> { let mut delegate = MutVarsDelegate { used_mutably: FxHashSet::default(), diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index cd53029e834..51cedfef0f7 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -106,7 +106,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA ); } -/// Return the item type of the vector (ie. the `T` in `Vec<T>`). +/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`). fn vec_type(ty: Ty<'_>) -> Ty<'_> { if let ty::Adt(_, substs) = ty.sty { substs.type_at(0) diff --git a/src/driver.rs b/src/driver.rs index e5925653655..82326bf780c 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -4,7 +4,7 @@ #![allow(clippy::missing_docs_in_private_items)] // FIXME: switch to something more ergonomic here, once available. -// (currently there is no way to opt into sysroot crates w/o `extern crate`) +// (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] extern crate rustc_driver; #[allow(unused_extern_crates)] diff --git a/src/lib.rs b/src/lib.rs index be0c10c8ff2..63af1283bcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ #![warn(rust_2018_idioms)] // FIXME: switch to something more ergonomic here, once available. -// (currently there is no way to opt into sysroot crates w/o `extern crate`) +// (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] extern crate rustc_driver; #[allow(unused_extern_crates)] diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index 17ee1cd6873..08fafc736af 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -49,7 +49,7 @@ fn pred_test() { let v = 3; let sky = "blue"; // 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 + , andadd some extra // expressions to make sure linter isn't confused by them. if v == 3 && sky == "blue" diff --git a/tests/ui/cast_alignment.rs b/tests/ui/cast_alignment.rs index 2814fe6c03d..08450ba1176 100644 --- a/tests/ui/cast_alignment.rs +++ b/tests/ui/cast_alignment.rs @@ -12,7 +12,7 @@ fn main() { (&1u8 as *const u8) as *const u16; (&mut 1u8 as *mut u8) as *mut u16; - /* These should be okay */ + /* These should be ok */ // not a pointer type 1u8 as u16; diff --git a/tests/ui/cast_ref_to_mut.rs b/tests/ui/cast_ref_to_mut.rs index 967e8e46739..089e5cfabe4 100644 --- a/tests/ui/cast_ref_to_mut.rs +++ b/tests/ui/cast_ref_to_mut.rs @@ -2,8 +2,8 @@ #![allow(clippy::no_effect)] extern "C" { - // NB. Mutability can be easily incorrect in FFI calls, as - // in C, the default are mutable pointers. + // N.B., mutability can be easily incorrect in FFI calls -- as + // in C, the default is mutable pointers. fn ffi(c: *mut u8); fn int_ffi(c: *mut i32); } diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index fddf8252329..f146adbce41 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -9,7 +9,7 @@ /// /// error[E0277]: the trait bound `T: Foo` is not satisfied /// -/// See https://github.com/rust-lang/rust-clippy/issues/2760 +// See rust-lang/rust-clippy#2760. trait Foo { type Bar; diff --git a/tests/ui/crashes/ice-2774.rs b/tests/ui/crashes/ice-2774.rs index fdc671a84e0..d44b0fae820 100644 --- a/tests/ui/crashes/ice-2774.rs +++ b/tests/ui/crashes/ice-2774.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -/// See https://github.com/rust-lang/rust-clippy/issues/2774 +// See rust-lang/rust-clippy#2774. #[derive(Eq, PartialEq, Debug, Hash)] pub struct Bar { @@ -11,14 +11,14 @@ pub struct Bar { pub struct Foo {} #[allow(clippy::implicit_hasher)] -// This should not cause a 'cannot relate bound region' ICE +// This should not cause a "cannot relate bound region" ICE. pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { let mut foos = HashSet::new(); foos.extend(bars.iter().map(|b| &b.foo)); } #[allow(clippy::implicit_hasher)] -// Also this should not cause a 'cannot relate bound region' ICE +// Also, this should not cause a "cannot relate bound region" ICE. pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) { let mut foos = HashSet::new(); foos.extend(bars.iter().map(|b| &b.foo)); diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs index 3030786aea6..6d2124c12fe 100644 --- a/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/tests/ui/crashes/used_underscore_binding_macro.rs @@ -3,7 +3,7 @@ #[macro_use] extern crate serde_derive; -/// Test that we do not lint for unused underscores in a `MacroAttribute` +/// Tests that we do not lint for unused underscores in a `MacroAttribute` /// expansion #[deny(clippy::used_underscore_binding)] #[derive(Deserialize)] diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index 7634341ba84..a8fc06af1d9 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -12,7 +12,7 @@ trait Foo { const BAR: Option<LinkedList<u8>>; } -// ok, we don’t want to warn for implementations, see #605 +// Ok, we don’t want to warn for implementations; see issue #605. impl Foo for LinkedList<u8> { fn foo(_: LinkedList<u8>) {} const BAR: Option<LinkedList<u8>> = None; diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index be0989347fa..039ce5d9c42 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -1,4 +1,4 @@ -//! This file tests for the DOC_MARKDOWN lint +//! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code)] #![warn(clippy::doc_markdown)] @@ -6,7 +6,7 @@ #![rustfmt::skip] /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) -/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun +/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun /// which should be reported only once despite being __doubly bad__. /// Here be ::a::global:path. /// That's not code ~NotInCodeBlock~. @@ -71,7 +71,7 @@ fn main() { } /// ## CamelCaseThing -/// Talks about `CamelCaseThing`. Titles should be ignored, see issue #897. +/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897. /// /// # CamelCaseThing /// @@ -107,7 +107,7 @@ fn issue883() { fn multiline() { } -/** E.g. serialization of an empty list: FooBar +/** E.g., serialization of an empty list: FooBar ``` That's in a code block: `PackedNode` ``` @@ -118,7 +118,7 @@ be_sure_we_got_to_the_end_of_it fn issue1073() { } -/** E.g. serialization of an empty list: FooBar +/** E.g., serialization of an empty list: FooBar ``` That's in a code block: PackedNode ``` @@ -129,7 +129,7 @@ be_sure_we_got_to_the_end_of_it fn issue1073_alt() { } -/// Test more than three quotes: +/// Tests more than three quotes: /// ```` /// DoNotWarn /// ``` diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index ca1cac59dad..3279ad8831d 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -21,7 +21,7 @@ LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot t error: you should put `Foo::some_fun` between ticks in the documentation --> $DIR/doc.rs:9:84 | -LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun +LL | /, andThis /_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ error: you should put `a::global:path` between ticks in the documentation diff --git a/tests/ui/format.rs b/tests/ui/format.rs index e974a4957ea..f6f6258e82d 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -13,44 +13,44 @@ fn main() { format!("foo"); format!("{}", "foo"); - format!("{:?}", "foo"); // don't warn about debug + format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); - format!("{:+}", "foo"); // warn when the format makes no difference - format!("{:<}", "foo"); // warn when the format makes no difference + format!("{:+}", "foo"); // Warn when the format makes no difference. + format!("{:<}", "foo"); // Warn when the format makes no difference. format!("foo {}", "bar"); format!("{} bar", "foo"); let arg: String = "".to_owned(); format!("{}", arg); - format!("{:?}", arg); // don't warn about debug + format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); - format!("{:+}", arg); // warn when the format makes no difference - format!("{:<}", arg); // warn when the format makes no difference + format!("{:+}", arg); // Warn when the format makes no difference. + format!("{:<}", arg); // Warn when the format makes no difference. format!("foo {}", arg); format!("{} bar", arg); - // we don’t want to warn for non-string args, see #697 + // We don’t want to warn for non-string args; see issue #697. format!("{}", 42); format!("{:?}", 42); format!("{:+}", 42); format!("foo {}", 42); format!("{} bar", 42); - // we only want to warn about `format!` itself + // We only want to warn about `format!` itself. println!("foo"); println!("{}", "foo"); println!("foo {}", "foo"); println!("{}", 42); println!("foo {}", 42); - // A format! inside a macro should not trigger a warning + // A `format!` inside a macro should not trigger a warning. foo!("should not warn"); - // precision on string means slicing without panicking on size: - format!("{:.1}", "foo"); // could be "foo"[..1] - format!("{:.10}", "foo"); // could not be "foo"[..10] + // Precision on string means slicing without panicking on size. + format!("{:.1}", "foo"); // could be `"foo"[..1]` + format!("{:.10}", "foo"); // could not be `"foo"[..10]` format!("{:.prec$}", "foo", prec = 1); format!("{:.prec$}", "foo", prec = 10); diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 71f228c32bd..0ec933e8784 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -232,7 +232,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { return Ok(&foo[0..]); } - // false positive if_same_then_else, let(x,y) vs let(y,x), see #3559 + // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559. if true { let foo = ""; let (x, y) = (1, 2); @@ -244,7 +244,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { } } -// Issue #2423. This was causing an ICE +// Issue #2423. This was causing an ICE. fn func() { if true { f(&[0; 62]); diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 05b863f3edc..db97c2427f3 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -10,13 +10,13 @@ impl PubOne { } impl PubOne { - // A second impl for this struct - the error span shouldn't mention this + // A second impl for this struct -- the error span shouldn't mention this. pub fn irrelevant(self: &Self) -> bool { false } } -// Identical to PubOne, but with an allow attribute on the impl complaining len +// Identical to `PubOne`, but with an `allow` attribute on the impl complaining `len`. pub struct PubAllowed; #[allow(clippy::len_without_is_empty)] @@ -26,8 +26,8 @@ impl PubAllowed { } } -// No allow attribute on this impl block, but that doesn't matter - we only require one on the -// impl containing len. +// No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the +// impl containing `len`. impl PubAllowed { pub fn irrelevant(self: &Self) -> bool { false @@ -38,7 +38,7 @@ struct NotPubOne; impl NotPubOne { pub fn len(self: &Self) -> isize { - // no error, len is pub but `NotPubOne` is not exported anyway + // No error; `len` is pub but `NotPubOne` is not exported anyway. 1 } } @@ -47,7 +47,7 @@ struct One; impl One { fn len(self: &Self) -> isize { - // no error, len is private, see #1085 + // No error; `len` is private; see issue #1085. 1 } } @@ -63,7 +63,8 @@ impl PubTraitsToo for One { } trait TraitsToo { - fn len(self: &Self) -> isize; // no error, len is private, see #1085 + fn len(self: &Self) -> isize; + // No error; `len` is private; see issue #1085. } impl TraitsToo for One { @@ -130,7 +131,7 @@ pub trait Empty { } pub trait InheritingEmpty: Empty { - //must not trigger LEN_WITHOUT_IS_EMPTY + // Must not trigger `LEN_WITHOUT_IS_EMPTY`. fn len(&self) -> isize; } @@ -144,13 +145,13 @@ fn main() { let y = One; if y.len() == 0 { - //no error because One does not have .is_empty() + // No error; `One` does not have `.is_empty()`. println!("This should not happen either!"); } let z: &TraitsToo = &y; if z.len() > 0 { - //no error, because TraitsToo has no .is_empty() method + // No error; `TraitsToo` has no `.is_empty()` method. println!("Nor should this!"); } @@ -171,11 +172,11 @@ fn main() { println!("Or this!"); } if has_is_empty.len() > 1 { - // no error + // No error. println!("This can happen."); } if has_is_empty.len() <= 1 { - // no error + // No error. println!("This can happen."); } if 0 == has_is_empty.len() { @@ -194,11 +195,11 @@ fn main() { println!("Or this!"); } if 1 < has_is_empty.len() { - // no error + // No error. println!("This can happen."); } if 1 >= has_is_empty.len() { - // no error + // No error. println!("This can happen."); } assert!(!has_is_empty.is_empty()); @@ -211,7 +212,7 @@ fn main() { let has_wrong_is_empty = HasWrongIsEmpty; if has_wrong_is_empty.len() == 0 { - //no error as HasWrongIsEmpty does not have .is_empty() + // No error; `HasWrongIsEmpty` does not have `.is_empty()`. println!("Or this!"); } } @@ -220,7 +221,7 @@ fn test_slice(b: &[u8]) { if b.len() != 0 {} } -// this used to ICE +// This used to ICE. pub trait Foo: Sized {} pub trait DependsOnFoo: Foo { diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index 46c8e1740a9..2cb236fa3bc 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -5,9 +5,11 @@ fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} -fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {} // no error, same lifetime on two params +// No error; same lifetime on two params. +fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {} -fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {} // no error, static involved +// No error; static involved. +fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {} fn mut_and_static_input(_x: &mut u8, _y: &'static str) {} @@ -15,31 +17,36 @@ fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x } +// No error; multiple input refs. fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x -} // no error, multiple input refs +} +// No error; multiple input refs. fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x -} // no error, multiple input refs +} +// No error; static involved. fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x -} // no error, static involved +} +// No error. fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) -} // no error +} +// No error; two input refs. fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() -} // no error, two input refs +} fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) } -// where clause, but without lifetimes +// Where-clause, but without lifetimes. fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy, @@ -49,25 +56,29 @@ where type Ref<'r> = &'r u8; -fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} // no error, same lifetime on two params +// No error; same lifetime on two params. +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} -fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} // no error, bounded lifetime +// No error; bounded lifetime. +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} +// No error; bounded lifetime. fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a, { -} // no error, bounded lifetime +} struct Lt<'a, I: 'static> { x: &'a I, } +// No error; fn bound references `'a`. fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> where - F: Fn(Lt<'a, I>) -> Lt<'a, I>, // no error, fn bound references 'a + F: Fn(Lt<'a, I>) -> Lt<'a, I>, { unreachable!() } @@ -79,8 +90,8 @@ where unreachable!() } +// No error; see below. fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) { - // no error, see below f(x); } @@ -88,10 +99,11 @@ fn fn_bound_3_cannot_elide() { let x = 42; let p = &x; let mut q = &x; - fn_bound_3(p, |y| q = y); // this will fail if we elides lifetimes of `fn_bound_3` + // This will fail if we elide lifetimes of `fn_bound_3`. + fn_bound_3(p, |y| q = y); } -// no error, multiple input refs +// No error; multiple input refs. fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () { if cond { x @@ -109,20 +121,24 @@ impl X { &self.x } + // No error; multiple input refs. fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x - } // no error, multiple input refs + } fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} - fn self_and_same_in<'s>(&'s self, _x: &'s u8) {} // no error, same lifetimes on two params + // No error; same lifetimes on two params. + fn self_and_same_in<'s>(&'s self, _x: &'s u8) {} } struct Foo<'a>(&'a u8); impl<'a> Foo<'a> { - fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method - fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist + // No error; lifetime `'a` not defined in method. + fn self_shared_lifetime(&self, _: &'a u8) {} + // No error; bounds exist. + fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} } fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 { @@ -133,17 +149,17 @@ fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() } -// no warning, two input lifetimes (named on the reference, anonymous on Foo) +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { unimplemented!() } -// no warning, two input lifetimes (anonymous on the reference, named on Foo) +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { unimplemented!() } -// no warning, two input lifetimes +// No warning; two input lifetimes. fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { unimplemented!() } @@ -152,13 +168,13 @@ trait WithLifetime<'a> {} type WithLifetimeAlias<'a> = WithLifetime<'a>; -// should not warn because it won't build without the lifetime +// Should not warn because it won't build without the lifetime. fn trait_obj_elided<'a>(_arg: &'a WithLifetime) -> &'a str { unimplemented!() } -// this should warn because there is no lifetime on Drop, so this would be -// unambiguous if we elided the lifetime +// Should warn because there is no lifetime on `Drop`, so this would be +// unambiguous if we elided the lifetime. fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() } @@ -169,17 +185,17 @@ fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() } -// no warning, two input lifetimes (named on the reference, anonymous on Foo) +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { unimplemented!() } -// no warning, two input lifetimes (anonymous on the reference, named on Foo) +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { unimplemented!() } -// no warning, two input lifetimes +// No warning; two input lifetimes. fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { unimplemented!() } @@ -199,12 +215,12 @@ fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { unimplemented!() } -// don't warn on these, see #292 +// Don't warn on these; see issue #292. fn trait_bound_bug<'a, T: WithLifetime<'a>>() { unimplemented!() } -// #740 +// See issue #740. struct Test { vec: Vec<usize>, } @@ -224,8 +240,7 @@ fn test<'a>(x: &'a [u8]) -> u8 { *y } -// #3284 - Give a hint regarding lifetime in return type - +// Issue #3284: give hint regarding lifetime in return type. struct Cow<'a> { x: &'a str, } diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index c7c84b5d9c0..b711367d123 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -13,7 +13,7 @@ fn ref_pats() { &None => println!("none"), } match v { - // this doesn't trigger, we have a different pattern + // This doesn't trigger; we have a different pattern. &Some(v) => println!("some"), other => println!("other"), } @@ -23,13 +23,13 @@ fn ref_pats() { &(v, 1) => println!("{}", v), _ => println!("none"), } - // special case: using & both in expr and pats + // Special case: using `&` both in expr and pats. let w = Some(0); match &w { &Some(v) => println!("{:?}", v), &None => println!("none"), } - // false positive: only wildcard pattern + // False positive: only wildcard pattern. let w = Some(0); match w { _ => println!("none"), @@ -69,14 +69,14 @@ fn match_wild_err_arm() { }, } - // allowed when not with `panic!` block + // Allowed when not with `panic!` block. match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), Err(_) => println!("err"), } - // allowed when used with `unreachable!` + // Allowed when used with `unreachable!`. match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), @@ -97,14 +97,14 @@ fn match_wild_err_arm() { }, } - // no warning because of the guard + // No warning because of the guard. match x { Ok(x) if x * x == 64 => println!("ok"), Ok(_) => println!("ok"), Err(_) => println!("err"), } - // this used to be a false positive, see #1996 + // This used to be a false positive; see issue #1996. match x { Ok(3) => println!("ok"), Ok(x) if x * x == 64 => println!("ok 64"), @@ -118,14 +118,14 @@ fn match_wild_err_arm() { _ => println!("err"), } - // no warning because of the different types for x + // No warning; different types for `x`. match (x, Some(1.0f64)) { (Ok(x), Some(_)) => println!("ok {}", x), (Ok(_), Some(x)) => println!("ok {}", x), _ => println!("err"), } - // because of a bug, no warning was generated for this case before #2251 + // Because of a bug, no warning was generated for this case before #2251. match x { Ok(_tmp) => println!("ok"), Ok(3) => println!("ok"), diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index b93cd6150d7..46a16f75c7b 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -49,19 +49,20 @@ impl T { true } - // no error, self is a ref + // No error; self is a ref. fn sub(&self, other: T) -> &T { self } - // no error, different #arguments + // No error; different number of arguments. fn div(self) -> T { self } - fn rem(self, other: T) {} // no error, wrong return type + // No error; wrong return type. + fn rem(self, other: T) {} - // fine + // Fine fn into_u32(self) -> u32 { 0 } @@ -84,7 +85,7 @@ struct Lt<'a> { } impl<'a> Lt<'a> { - // The lifetime is different, but that’s irrelevant, see #734 + // The lifetime is different, but that’s irrelevant; see issue #734. #[allow(clippy::needless_lifetimes)] pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() @@ -96,7 +97,7 @@ struct Lt2<'a> { } impl<'a> Lt2<'a> { - // The lifetime is different, but that’s irrelevant, see #734 + // The lifetime is different, but that’s irrelevant; see issue #734. pub fn new(s: &str) -> Lt2 { unimplemented!() } @@ -107,7 +108,7 @@ struct Lt3<'a> { } impl<'a> Lt3<'a> { - // The lifetime is different, but that’s irrelevant, see #734 + // The lifetime is different, but that’s irrelevant; see issue #734. pub fn new() -> Lt3<'static> { unimplemented!() } @@ -120,7 +121,7 @@ impl U { fn new() -> Self { U } - // ok because U is Copy + // Ok because `U` is `Copy`. fn to_something(self) -> u32 { 0 } @@ -138,7 +139,7 @@ impl<T> V<T> { impl Mul<T> for T { type Output = T; - // no error, obviously + // No error, obviously. fn mul(self, other: T) -> T { self } @@ -152,12 +153,12 @@ impl Mul<T> for T { fn option_methods() { let opt = Some(1); - // Check OPTION_MAP_UNWRAP_OR - // single line case + // Check `OPTION_MAP_UNWRAP_OR`. + // Single line case. let _ = opt.map(|x| x + 1) - - .unwrap_or(0); // should lint even though this call is on a separate line - // multi line cases + // Should lint even though this call is on a separate line. + .unwrap_or(0); + // Multi-line cases. let _ = opt.map(|x| { x + 1 } @@ -166,9 +167,9 @@ fn option_methods() { .unwrap_or({ 0 }); - // single line `map(f).unwrap_or(None)` case + // Single line `map(f).unwrap_or(None)` case. let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); - // multiline `map(f).unwrap_or(None)` cases + // Multi-line `map(f).unwrap_or(None)` cases. let _ = opt.map(|x| { Some(x + 1) } @@ -189,9 +190,9 @@ fn option_methods() { // Check OPTION_MAP_UNWRAP_OR_ELSE // single line case let _ = opt.map(|x| x + 1) - - .unwrap_or_else(|| 0); // should lint even though this call is on a separate line - // multi line cases + // Should lint even though this call is on a separate line. + .unwrap_or_else(|| 0); + // Multi-line cases. let _ = opt.map(|x| { x + 1 } @@ -200,20 +201,21 @@ fn option_methods() { .unwrap_or_else(|| 0 ); - // macro case - let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint + // Macro case. + // Should not lint. + let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); - // Check OPTION_MAP_OR_NONE - // single line case + // Check `OPTION_MAP_OR_NONE`. + // Single line case. let _ = opt.map_or(None, |x| Some(x + 1)); - // multi line case + // Multi-line case. let _ = opt.map_or(None, |x| { Some(x + 1) } ); } -/// Struct to generate false positives for things with .iter() +/// Struct to generate false positives for things with `.iter()`. #[derive(Copy, Clone)] struct HasIter; @@ -227,65 +229,65 @@ impl HasIter { } } -/// Checks implementation of `FILTER_NEXT` lint +/// Checks implementation of `FILTER_NEXT` lint. #[rustfmt::skip] fn filter_next() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - // check single-line case + // Single-line case. let _ = v.iter().filter(|&x| *x < 0).next(); - // check multi-line case + // Multi-line case. let _ = v.iter().filter(|&x| { *x < 0 } ).next(); - // check that we don't lint if the caller is not an Iterator + // Check that hat we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); } -/// Checks implementation of `SEARCH_IS_SOME` lint +/// Checks implementation of `SEARCH_IS_SOME` lint. #[rustfmt::skip] fn search_is_some() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - // check `find().is_some()`, single-line + // Check `find().is_some()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_some(); - // check `find().is_some()`, multi-line + // Check `find().is_some()`, multi-line case. let _ = v.iter().find(|&x| { *x < 0 } ).is_some(); - // check `position().is_some()`, single-line + // Check `position().is_some()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_some(); - // check `position().is_some()`, multi-line + // Check `position().is_some()`, multi-line case. let _ = v.iter().position(|&x| { x < 0 } ).is_some(); - // check `rposition().is_some()`, single-line + // Check `rposition().is_some()`, single-line case. let _ = v.iter().rposition(|&x| x < 0).is_some(); - // check `rposition().is_some()`, multi-line + // Check `rposition().is_some()`, multi-line case. let _ = v.iter().rposition(|&x| { x < 0 } ).is_some(); - // check that we don't lint if the caller is not an Iterator + // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.find().is_some(); let _ = foo.position().is_some(); let _ = foo.rposition().is_some(); } -/// Checks implementation of the `OR_FUN_CALL` lint +/// Checks implementation of the `OR_FUN_CALL` lint. fn or_fun_call() { struct Foo; @@ -348,14 +350,14 @@ fn or_fun_call() { let _ = stringy.unwrap_or("".to_owned()); } -/// Checks implementation of `ITER_NTH` lint +/// Checks implementation of `ITER_NTH` lint. fn iter_nth() { let mut some_vec = vec![0, 1, 2, 3]; let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect(); { - // Make sure we lint `.iter()` for relevant types + // Make sure we lint `.iter()` for relevant types. let bad_vec = some_vec.iter().nth(3); let bad_slice = &some_vec[..].iter().nth(3); let bad_boxed_slice = boxed_slice.iter().nth(3); @@ -363,7 +365,7 @@ fn iter_nth() { } { - // Make sure we lint `.iter_mut()` for relevant types + // Make sure we lint `.iter_mut()` for relevant types. let bad_vec = some_vec.iter_mut().nth(3); } { @@ -373,7 +375,7 @@ fn iter_nth() { let bad_vec_deque = some_vec_deque.iter_mut().nth(3); } - // Make sure we don't lint for non-relevant types + // Make sure we don't lint for non-relevant types. let false_positive = HasIter; let ok = false_positive.iter().nth(3); let ok_mut = false_positive.iter_mut().nth(3); diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 968a9f354bc..c76f4de9b07 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -14,12 +14,12 @@ fn main() { let mut var2 = 5; let thingy2 = Some(&mut var2); if let Some(&mut ref mut v) = thingy2 { - // ^ should *not* be linted + // ^ should **not** be linted // v is borrowed as mutable. *v = 10; } if let Some(&mut ref v) = thingy2 { - // ^ should *not* be linted + // ^ should **not** be linted // here, v is borrowed as immutable. // can't do that: //*v = 15; @@ -37,7 +37,7 @@ enum Animal { fn foo(a: &Animal, b: &Animal) { match (a, b) { (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' - // ^ and ^ should *not* be linted - (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should *not* be linted + // ^ and ^ should **not** be linted + (&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted } } diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 711fb4f8aed..3bc0448234e 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -20,6 +20,6 @@ fn main() { let ref mut z = 1 + 2; - let (ref x, _) = (1, 2); // okay, not top level + let (ref x, _) = (1, 2); // ok, not top level println!("The answer is {}.", x); } diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index deec885b85d..27db9594f3b 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -7,13 +7,13 @@ fn zero() { #[warn(clippy::unicode_not_nfc)] fn canon() { print!("̀àh?"); - print!("a\u{0300}h?"); // also okay + print!("a\u{0300}h?"); // also ok } #[warn(clippy::non_ascii_literal)] fn uni() { print!("Üben!"); - print!("\u{DC}ben!"); // this is okay + print!("\u{DC}ben!"); // this is ok } fn main() { diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 702f1793ed5..550e16a4a20 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -9,12 +9,12 @@ macro_rules! test_macro { }}; } -/// Test that we lint if we use a binding with a single leading underscore +/// Tests that we lint if we use a binding with a single leading underscore fn prefix_underscore(_foo: u32) -> u32 { _foo + 1 } -/// Test that we lint if we use a `_`-variable defined outside within a macro expansion +/// Tests that we lint if we use a `_`-variable defined outside within a macro expansion fn in_macro(_foo: u32) { println!("{}", _foo); assert_eq!(_foo, _foo); @@ -27,23 +27,23 @@ struct StructFieldTest { _underscore_field: u32, } -/// Test that we lint the use of a struct field which is prefixed with an underscore +/// Tests that we lint the use of a struct field which is prefixed with an underscore fn in_struct_field() { let mut s = StructFieldTest { _underscore_field: 0 }; s._underscore_field += 1; } -/// Test that we do not lint if the underscore is not a prefix +/// Tests that we do not lint if the underscore is not a prefix fn non_prefix_underscore(some_foo: u32) -> u32 { some_foo + 1 } -/// Test that we do not lint if we do not use the binding (simple case) +/// Tests that we do not lint if we do not use the binding (simple case) fn unused_underscore_simple(_foo: u32) -> u32 { 1 } -/// Test that we do not lint if we do not use the binding (complex case). This checks for +/// Tests that we do not lint if we do not use the binding (complex case). This checks for /// compatibility with the built-in `unused_variables` lint. fn unused_underscore_complex(mut _foo: u32) -> u32 { _foo += 1; @@ -64,7 +64,7 @@ enum _EnumTest { _Value(_StructTest), } -/// Test that we do not lint for non-variable bindings +/// Tests that we do not lint for non-variable bindings fn non_variables() { _fn_test(); let _s = _StructTest; diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index d6921578721..ee7f7306a4b 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -118,7 +118,7 @@ fn main() { // regression test (#360) // this should not panic -// it's okay if further iterations of the lint +// it's ok if further iterations of the lint // cause this function to trigger it fn no_panic<T>(slice: &[T]) { let mut iter = slice.iter(); -- cgit 1.4.1-3-g733a5 From c730de955e6098359cef8ec37c90627402a41e1e Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Tue, 12 Mar 2019 07:32:02 +0100 Subject: Remove some unused features and `error-pattern`s --- src/driver.rs | 3 --- src/lib.rs | 1 - src/main.rs | 5 ----- 3 files changed, 9 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 82326bf780c..01358f46dd7 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,7 +1,4 @@ -// error-pattern:yummy -#![feature(box_syntax)] #![feature(rustc_private)] -#![allow(clippy::missing_docs_in_private_items)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/src/lib.rs b/src/lib.rs index 63af1283bcc..86174a6b316 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ // error-pattern:cargo-clippy #![feature(plugin_registrar)] #![feature(rustc_private)] -#![allow(clippy::missing_docs_in_private_items)] #![warn(rust_2018_idioms)] // FIXME: switch to something more ergonomic here, once available. diff --git a/src/main.rs b/src/main.rs index 208262ca30f..e0b2bcc7266 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,3 @@ -// error-pattern:yummy -#![feature(box_syntax)] -#![feature(rustc_private)] -#![allow(clippy::missing_docs_in_private_items)] - use rustc_tools_util::*; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. -- cgit 1.4.1-3-g733a5 From 491f72442e891973cf447813794ab472383c810b Mon Sep 17 00:00:00 2001 From: Félix Fischer <felix91gr@gmail.com> Date: Fri, 29 Mar 2019 01:47:09 -0300 Subject: Updated source to match with recent rustc `master` toolchain changes --- clippy_lints/src/enum_glob_use.rs | 3 ++- clippy_lints/src/lifetimes.rs | 3 ++- src/driver.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index 37575f10f19..afdf27376d8 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -39,9 +39,10 @@ impl LintPass for EnumGlobUse { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: HirId) { + let map = cx.tcx.hir(); // only check top level `use` statements for item in &m.item_ids { - self.lint_item(cx, cx.tcx.hir().expect_item(item.id)); + self.lint_item(cx, map.expect_item(map.hir_to_node_id(item.id))); } } } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 4b2ba60090f..cd717e586e7 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -356,7 +356,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { self.collect_anonymous_lifetimes(path, ty); }, TyKind::Def(item, _) => { - if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir().expect_item(item.id).node { + let map = self.cx.tcx.hir(); + if let ItemKind::Existential(ref exist_ty) = map.expect_item(map.hir_to_node_id(item.id)).node { for bound in &exist_ty.bounds { if let GenericBound::Outlives(_) = *bound { self.record(&None); diff --git a/src/driver.rs b/src/driver.rs index 01358f46dd7..0b5c259ec4e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -93,7 +93,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { ls.register_early_pass(Some(sess), true, false, pass); } for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); + ls.register_late_pass(Some(sess), true, false, pass); } for (name, (to, deprecated_name)) in lint_groups { -- cgit 1.4.1-3-g733a5 From 414c34c300f3716c03ae034bd72e4db3170cf0b8 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Sat, 30 Mar 2019 15:58:14 +0100 Subject: rustup 41316f0449025394fdca6606d3fdb3b8f37a9872 --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 0b5c259ec4e..834d11861c0 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -93,7 +93,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { ls.register_early_pass(Some(sess), true, false, pass); } for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, false, pass); + ls.register_late_pass(Some(sess), true, false, false, pass); } for (name, (to, deprecated_name)) in lint_groups { -- cgit 1.4.1-3-g733a5 From 6967cf59a4f5664d97086ddccd8cc9b29778d0b7 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Tue, 30 Apr 2019 11:10:31 +0200 Subject: clippy-driver: use rustc_tools_util to get version info. This will add git hash information to `clippy-driver -V` output. --- clippy_lints/src/consts.rs | 2 +- src/driver.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 3aa826d8bed..e86e51b7f88 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -344,7 +344,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } ret }, - // FIXME: cover all useable cases. + // FIXME: cover all usable cases. _ => None, } } diff --git a/src/driver.rs b/src/driver.rs index 834d11861c0..f4a656722b9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -10,13 +10,11 @@ extern crate rustc_interface; extern crate rustc_plugin; use rustc_interface::interface; +use rustc_tools_util::*; + use std::path::Path; use std::process::{exit, Command}; -fn show_version() { - println!(env!("CARGO_PKG_VERSION")); -} - /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a>( @@ -117,7 +115,8 @@ pub fn main() { use std::env; if std::env::args().any(|a| a == "--version" || a == "-V") { - show_version(); + let version_info = rustc_tools_util::get_version_info!(); + println!("{}", version_info); exit(0); } -- cgit 1.4.1-3-g733a5 From cf88c8487a2f827f8af0a369a63b3601e4c9f04c Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Tue, 4 Jun 2019 17:32:03 -0700 Subject: initial commit for help improvements on clippy-driver --- clippy_dev/src/main.rs | 22 + src/driver.rs | 36 + src/lintlist.rs | 2274 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2332 insertions(+) create mode 100644 src/lintlist.rs (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 45d4d13ed86..1c3c53ad49f 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -87,6 +87,28 @@ fn print_lints() { fn update_lints(update_mode: &UpdateMode) { let lint_list: Vec<Lint> = gather_all().collect(); + + std::fs::write( + "../src/lintlist.rs", + &format!( + "\ +/// Lint data parsed from the Clippy source code. +#[derive(Clone, PartialEq, Debug)] +pub struct Lint {{ + pub name: &'static str, + pub group: &'static str, + pub desc: &'static str, + pub deprecation: Option<&'static str>, + pub module: &'static str, +}} + +pub const ALL_LINTS: [Lint; {}] = {:#?};", + lint_list.len(), + lint_list + ), + ) + .expect("can write to file"); + let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect(); let lint_count = usable_lints.len(); diff --git a/src/driver.rs b/src/driver.rs index f4a656722b9..dc4ff3e8e2a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -15,6 +15,8 @@ use rustc_tools_util::*; use std::path::Path; use std::process::{exit, Command}; +mod lintlist; + /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a>( @@ -120,6 +122,40 @@ pub fn main() { exit(0); } + if std::env::args().any(|a| a == "--help" || a == "-h") { + println!( + "\ +Checks a package to catch common mistakes and improve your Rust code. + +Usage: + cargo clippy [options] [--] [<opts>...] + +Common options: + -h, --help Print this message + -V, --version Print version info and exit + +Other options are the same as `cargo check`. + +To allow or deny a lint from the command line you can use `cargo clippy --` +with: + + -W --warn OPT Set lint warnings + -A --allow OPT Set lint allowed + -D --deny OPT Set lint denied + -F --forbid OPT Set lint forbidden + +You can use tool lints to allow or deny lints from your code, eg.: + + #[allow(clippy::needless_lifetimes)] +" + ); + + for lint in &lintlist::ALL_LINTS[..] { + println!("clippy::{},", lint.name); + } + exit(0); + } + let mut orig_args: Vec<String> = env::args().collect(); // Get the sysroot, looking from most specific to this invocation to the least: diff --git a/src/lintlist.rs b/src/lintlist.rs new file mode 100644 index 00000000000..be4d4fc008a --- /dev/null +++ b/src/lintlist.rs @@ -0,0 +1,2274 @@ +/// Lint data parsed from the Clippy source code. +#[derive(Clone, PartialEq, Debug)] +pub struct Lint { + pub name: &'static str, + pub group: &'static str, + pub desc: &'static str, + pub deprecation: Option<&'static str>, + pub module: &'static str, +} + +pub const ALL_LINTS: [Lint; 320] = [ + Lint { + name: "too_many_arguments", + group: "complexity", + desc: "functions with too many arguments", + deprecation: None, + module: "functions", + }, + Lint { + name: "too_many_lines", + group: "pedantic", + desc: "functions with too many lines", + deprecation: None, + module: "functions", + }, + Lint { + name: "not_unsafe_ptr_arg_deref", + group: "correctness", + desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", + deprecation: None, + module: "functions", + }, + Lint { + name: "precedence", + group: "complexity", + desc: "operations where precedence may be unclear", + deprecation: None, + module: "precedence", + }, + Lint { + name: "single_match", + group: "style", + desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", + deprecation: None, + module: "matches", + }, + Lint { + name: "single_match_else", + group: "pedantic", + desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_ref_pats", + group: "style", + desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_bool", + group: "style", + desc: "a match on a boolean expression instead of an `if..else` block", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_overlapping_arm", + group: "style", + desc: "a match with overlapping arms", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_wild_err_arm", + group: "style", + desc: "a match with `Err(_)` arm and take drastic actions", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_as_ref", + group: "complexity", + desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", + deprecation: None, + module: "matches", + }, + Lint { + name: "wildcard_enum_match_arm", + group: "restriction", + desc: "a wildcard enum match arm using `_`", + deprecation: None, + module: "matches", + }, + Lint { + name: "option_map_unit_fn", + group: "complexity", + desc: "using `option.map(f)`, where f is a function or closure that returns ()", + deprecation: None, + module: "map_unit_fn", + }, + Lint { + name: "result_map_unit_fn", + group: "complexity", + desc: "using `result.map(f)`, where f is a function or closure that returns ()", + deprecation: None, + module: "map_unit_fn", + }, + Lint { + name: "else_if_without_else", + group: "restriction", + desc: "if expression with an `else if`, but without a final `else` branch", + deprecation: None, + module: "else_if_without_else", + }, + Lint { + name: "fallible_impl_from", + group: "nursery", + desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", + deprecation: None, + module: "fallible_impl_from", + }, + Lint { + name: "missing_docs_in_private_items", + group: "restriction", + desc: "detects missing documentation for public and private members", + deprecation: None, + module: "missing_doc", + }, + Lint { + name: "unused_label", + group: "complexity", + desc: "unused labels", + deprecation: None, + module: "unused_label", + }, + Lint { + name: "missing_inline_in_public_items", + group: "restriction", + desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", + deprecation: None, + module: "missing_inline", + }, + Lint { + name: "wildcard_dependencies", + group: "cargo", + desc: "wildcard dependencies being used", + deprecation: None, + module: "wildcard_dependencies", + }, + Lint { + name: "neg_multiply", + group: "style", + desc: "multiplying integers with -1", + deprecation: None, + module: "neg_multiply", + }, + Lint { + name: "unsafe_removed_from_name", + group: "style", + desc: "`unsafe` removed from API names on import", + deprecation: None, + module: "unsafe_removed_from_name", + }, + Lint { + name: "drop_bounds", + group: "correctness", + desc: "Bounds of the form `T: Drop` are useless", + deprecation: None, + module: "drop_bounds", + }, + Lint { + name: "integer_arithmetic", + group: "restriction", + desc: "any integer arithmetic statement", + deprecation: None, + module: "arithmetic", + }, + Lint { + name: "float_arithmetic", + group: "restriction", + desc: "any floating-point arithmetic statement", + deprecation: None, + module: "arithmetic", + }, + Lint { + name: "derive_hash_xor_eq", + group: "correctness", + desc: "deriving `Hash` but implementing `PartialEq` explicitly", + deprecation: None, + module: "derive", + }, + Lint { + name: "expl_impl_clone_on_copy", + group: "pedantic", + desc: "implementing `Clone` explicitly on `Copy` types", + deprecation: None, + module: "derive", + }, + Lint { + name: "enum_clike_unportable_variant", + group: "correctness", + desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", + deprecation: None, + module: "enum_clike", + }, + Lint { + name: "serde_api_misuse", + group: "correctness", + desc: "various things that will negatively affect your serde experience", + deprecation: None, + module: "serde_api", + }, + Lint { + name: "replace_consts", + group: "pedantic", + desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", + deprecation: None, + module: "replace_consts", + }, + Lint { + name: "unnecessary_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that cannot fail", + deprecation: None, + module: "unwrap", + }, + Lint { + name: "panicking_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that will always fail", + deprecation: None, + module: "unwrap", + }, + Lint { + name: "transmuting_null", + group: "correctness", + desc: "transmutes from a null pointer to a reference, which is undefined behavior", + deprecation: None, + module: "transmuting_null", + }, + Lint { + name: "assertions_on_constants", + group: "style", + desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", + deprecation: None, + module: "assertions_on_constants", + }, + Lint { + name: "shadow_same", + group: "restriction", + desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", + deprecation: None, + module: "shadow", + }, + Lint { + name: "shadow_reuse", + group: "restriction", + desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", + deprecation: None, + module: "shadow", + }, + Lint { + name: "shadow_unrelated", + group: "pedantic", + desc: "rebinding a name without even using the original value", + deprecation: None, + module: "shadow", + }, + Lint { + name: "use_self", + group: "pedantic", + desc: "Unnecessary structure name repetition whereas `Self` is applicable", + deprecation: None, + module: "use_self", + }, + Lint { + name: "declare_interior_mutable_const", + group: "correctness", + desc: "declaring const with interior mutability", + deprecation: None, + module: "non_copy_const", + }, + Lint { + name: "borrow_interior_mutable_const", + group: "correctness", + desc: "referencing const with interior mutability", + deprecation: None, + module: "non_copy_const", + }, + Lint { + name: "inline_always", + group: "pedantic", + desc: "use of `#[inline(always)]`", + deprecation: None, + module: "attrs", + }, + Lint { + name: "useless_attribute", + group: "correctness", + desc: "use of lint attributes on `extern crate` items", + deprecation: None, + module: "attrs", + }, + Lint { + name: "deprecated_semver", + group: "correctness", + desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", + deprecation: None, + module: "attrs", + }, + Lint { + name: "empty_line_after_outer_attr", + group: "nursery", + desc: "empty line after outer attribute", + deprecation: None, + module: "attrs", + }, + Lint { + name: "unknown_clippy_lints", + group: "style", + desc: "unknown_lints for scoped Clippy lints", + deprecation: None, + module: "attrs", + }, + Lint { + name: "deprecated_cfg_attr", + group: "complexity", + desc: "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`", + deprecation: None, + module: "attrs", + }, + Lint { + name: "excessive_precision", + group: "style", + desc: "excessive precision for float literal", + deprecation: None, + module: "excessive_precision", + }, + Lint { + name: "items_after_statements", + group: "pedantic", + desc: "blocks where an item comes after a statement", + deprecation: None, + module: "items_after_statements", + }, + Lint { + name: "multiple_inherent_impl", + group: "restriction", + desc: "Multiple inherent impl that could be grouped", + deprecation: None, + module: "inherent_impl", + }, + Lint { + name: "invalid_regex", + group: "correctness", + desc: "invalid regular expressions", + deprecation: None, + module: "regex", + }, + Lint { + name: "trivial_regex", + group: "style", + desc: "trivial regular expressions", + deprecation: None, + module: "regex", + }, + Lint { + name: "regex_macro", + group: "style", + desc: "use of `regex!(_)` instead of `Regex::new(_)`", + deprecation: None, + module: "regex", + }, + Lint { + name: "question_mark", + group: "style", + desc: "checks for expressions that could be replaced by the question mark operator", + deprecation: None, + module: "question_mark", + }, + Lint { + name: "partialeq_ne_impl", + group: "complexity", + desc: "re-implementing `PartialEq::ne`", + deprecation: None, + module: "partialeq_ne_impl", + }, + Lint { + name: "suspicious_assignment_formatting", + group: "style", + desc: "suspicious formatting of `*=`, `-=` or `!=`", + deprecation: None, + module: "formatting", + }, + Lint { + name: "suspicious_else_formatting", + group: "style", + desc: "suspicious formatting of `else`", + deprecation: None, + module: "formatting", + }, + Lint { + name: "possible_missing_comma", + group: "correctness", + desc: "possible missing comma in array", + deprecation: None, + module: "formatting", + }, + Lint { + name: "dbg_macro", + group: "restriction", + desc: "`dbg!` macro is intended as a debugging tool", + deprecation: None, + module: "dbg_macro", + }, + Lint { + name: "needless_borrowed_reference", + group: "complexity", + desc: "taking a needless borrowed reference", + deprecation: None, + module: "needless_borrowed_ref", + }, + Lint { + name: "missing_const_for_fn", + group: "nursery", + desc: "Lint functions definitions that could be made `const fn`", + deprecation: None, + module: "missing_const_for_fn", + }, + Lint { + name: "eq_op", + group: "correctness", + desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", + deprecation: None, + module: "eq_op", + }, + Lint { + name: "op_ref", + group: "style", + desc: "taking a reference to satisfy the type constraints on `==`", + deprecation: None, + module: "eq_op", + }, + Lint { + name: "identity_op", + group: "complexity", + desc: "using identity operations, e.g., `x + 0` or `y / 1`", + deprecation: None, + module: "identity_op", + }, + Lint { + name: "boxed_local", + group: "perf", + desc: "using `Box<T>` where unnecessary", + deprecation: None, + module: "escape", + }, + Lint { + name: "mem_forget", + group: "restriction", + desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", + deprecation: None, + module: "mem_forget", + }, + Lint { + name: "duration_subsec", + group: "complexity", + desc: "checks for calculation of subsecond microseconds or milliseconds", + deprecation: None, + module: "duration_subsec", + }, + Lint { + name: "blacklisted_name", + group: "style", + desc: "usage of a blacklisted/placeholder name", + deprecation: None, + module: "blacklisted_name", + }, + Lint { + name: "nonminimal_bool", + group: "complexity", + desc: "boolean expressions that can be written more concisely", + deprecation: None, + module: "booleans", + }, + Lint { + name: "logic_bug", + group: "correctness", + desc: "boolean expressions that contain terminals which can be eliminated", + deprecation: None, + module: "booleans", + }, + Lint { + name: "useless_format", + group: "complexity", + desc: "useless use of `format!`", + deprecation: None, + module: "format", + }, + Lint { + name: "needless_bool", + group: "complexity", + desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", + deprecation: None, + module: "needless_bool", + }, + Lint { + name: "bool_comparison", + group: "complexity", + desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", + deprecation: None, + module: "needless_bool", + }, + Lint { + name: "enum_glob_use", + group: "pedantic", + desc: "use items that import all variants of an enum", + deprecation: None, + module: "enum_glob_use", + }, + Lint { + name: "zero_divided_by_zero", + group: "complexity", + desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", + deprecation: None, + module: "zero_div_zero", + }, + Lint { + name: "unnecessary_mut_passed", + group: "style", + desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", + deprecation: None, + module: "mut_reference", + }, + Lint { + name: "out_of_bounds_indexing", + group: "correctness", + desc: "out of bounds constant indexing", + deprecation: None, + module: "indexing_slicing", + }, + Lint { + name: "indexing_slicing", + group: "restriction", + desc: "indexing/slicing usage", + deprecation: None, + module: "indexing_slicing", + }, + Lint { + name: "implicit_return", + group: "restriction", + desc: "use a return statement like `return expr` instead of an expression", + deprecation: None, + module: "implicit_return", + }, + Lint { + name: "enum_variant_names", + group: "style", + desc: "enums where all variants share a prefix/postfix", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "pub_enum_variant_names", + group: "pedantic", + desc: "enums where all variants share a prefix/postfix", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "module_name_repetitions", + group: "pedantic", + desc: "type names prefixed/postfixed with their containing module\'s name", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "module_inception", + group: "style", + desc: "modules that have the same name as their parent module", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "deep_code_inspection", + group: "internal_warn", + desc: "helper to dump info about code", + deprecation: None, + module: "inspector", + }, + Lint { + name: "lint_author", + group: "internal_warn", + desc: "helper for writing lints", + deprecation: None, + module: "author", + }, + Lint { + name: "clippy_lints_internal", + group: "internal", + desc: "various things that will negatively affect your clippy experience", + deprecation: None, + module: "internal_lints", + }, + Lint { + name: "lint_without_lint_pass", + group: "internal", + desc: "declaring a lint without associating it in a LintPass", + deprecation: None, + module: "internal_lints", + }, + Lint { + name: "compiler_lint_functions", + group: "internal", + desc: "usage of the lint functions of the compiler instead of the utils::* variant", + deprecation: None, + module: "internal_lints", + }, + Lint { + name: "neg_cmp_op_on_partial_ord", + group: "complexity", + desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", + deprecation: None, + module: "neg_cmp_op_on_partial_ord", + }, + Lint { + name: "unused_io_amount", + group: "correctness", + desc: "unused written/read amount", + deprecation: None, + module: "unused_io_amount", + }, + Lint { + name: "infallible_destructuring_match", + group: "style", + desc: "a match statement with a single infallible arm instead of a `let`", + deprecation: None, + module: "infallible_destructuring_match", + }, + Lint { + name: "nonsensical_open_options", + group: "correctness", + desc: "nonsensical combination of options for opening a file", + deprecation: None, + module: "open_options", + }, + Lint { + name: "mut_mut", + group: "pedantic", + desc: "usage of double-mut refs, e.g., `&mut &mut ...`", + deprecation: None, + module: "mut_mut", + }, + Lint { + name: "mutex_atomic", + group: "perf", + desc: "using a mutex where an atomic value could be used instead", + deprecation: None, + module: "mutex_atomic", + }, + Lint { + name: "mutex_integer", + group: "nursery", + desc: "using a mutex for an integer type", + deprecation: None, + module: "mutex_atomic", + }, + Lint { + name: "doc_markdown", + group: "pedantic", + desc: "presence of `_`, `::` or camel-case outside backticks in documentation", + deprecation: None, + module: "doc", + }, + Lint { + name: "deref_addrof", + group: "complexity", + desc: "use of `*&` or `*&mut` in an expression", + deprecation: None, + module: "reference", + }, + Lint { + name: "ref_in_deref", + group: "complexity", + desc: "Use of reference in auto dereference expression.", + deprecation: None, + module: "reference", + }, + Lint { + name: "similar_names", + group: "pedantic", + desc: "similarly named items and bindings", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "many_single_char_names", + group: "style", + desc: "too many single character bindings", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "just_underscores_and_digits", + group: "style", + desc: "unclear name", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "manual_memcpy", + group: "perf", + desc: "manually copying items between slices", + deprecation: None, + module: "loops", + }, + Lint { + name: "needless_range_loop", + group: "style", + desc: "for-looping over a range of indices where an iterator over items would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_iter_loop", + group: "pedantic", + desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_into_iter_loop", + group: "pedantic", + desc: "for-looping over `_.into_iter()` when `_` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "iter_next_loop", + group: "correctness", + desc: "for-looping over `_.next()` which is probably not intended", + deprecation: None, + module: "loops", + }, + Lint { + name: "for_loop_over_option", + group: "correctness", + desc: "for-looping over an `Option`, which is more clearly expressed as an `if let`", + deprecation: None, + module: "loops", + }, + Lint { + name: "for_loop_over_result", + group: "correctness", + desc: "for-looping over a `Result`, which is more clearly expressed as an `if let`", + deprecation: None, + module: "loops", + }, + Lint { + name: "while_let_loop", + group: "complexity", + desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", + deprecation: None, + module: "loops", + }, + Lint { + name: "unused_collect", + group: "perf", + desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", + deprecation: None, + module: "loops", + }, + Lint { + name: "needless_collect", + group: "perf", + desc: "collecting an iterator when collect is not needed", + deprecation: None, + module: "loops", + }, + Lint { + name: "reverse_range_loop", + group: "correctness", + desc: "iteration over an empty range, such as `10..0` or `5..5`", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_counter_loop", + group: "complexity", + desc: "for-looping with an explicit counter when `_.enumerate()` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "empty_loop", + group: "style", + desc: "empty `loop {}`, which should block or sleep", + deprecation: None, + module: "loops", + }, + Lint { + name: "while_let_on_iterator", + group: "style", + desc: "using a while-let loop instead of a for loop on an iterator", + deprecation: None, + module: "loops", + }, + Lint { + name: "for_kv_map", + group: "style", + desc: "looping on a map using `iter` when `keys` or `values` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "never_loop", + group: "correctness", + desc: "any loop that will always `break` or `return`", + deprecation: None, + module: "loops", + }, + Lint { + name: "mut_range_bound", + group: "complexity", + desc: "for loop over a range where one of the bounds is a mutable variable", + deprecation: None, + module: "loops", + }, + Lint { + name: "while_immutable_condition", + group: "correctness", + desc: "variables used within while expression are not mutated in the body", + deprecation: None, + module: "loops", + }, + Lint { + name: "needless_update", + group: "complexity", + desc: "using `Foo { ..base }` when there are no missing fields", + deprecation: None, + module: "needless_update", + }, + Lint { + name: "block_in_if_condition_expr", + group: "style", + desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", + deprecation: None, + module: "block_in_if_condition", + }, + Lint { + name: "block_in_if_condition_stmt", + group: "style", + desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", + deprecation: None, + module: "block_in_if_condition", + }, + Lint { + name: "drop_ref", + group: "correctness", + desc: "calls to `std::mem::drop` with a reference instead of an owned value", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "forget_ref", + group: "correctness", + desc: "calls to `std::mem::forget` with a reference instead of an owned value", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "drop_copy", + group: "correctness", + desc: "calls to `std::mem::drop` with a value that implements Copy", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "forget_copy", + group: "correctness", + desc: "calls to `std::mem::forget` with a value that implements Copy", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "manual_swap", + group: "complexity", + desc: "manual swap of two variables", + deprecation: None, + module: "swap", + }, + Lint { + name: "almost_swapped", + group: "correctness", + desc: "`foo = bar; bar = foo` sequence", + deprecation: None, + module: "swap", + }, + Lint { + name: "redundant_pattern_matching", + group: "style", + desc: "use the proper utility function avoiding an `if let`", + deprecation: None, + module: "redundant_pattern_matching", + }, + Lint { + name: "bad_bit_mask", + group: "correctness", + desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "ineffective_bit_mask", + group: "correctness", + desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "verbose_bit_mask", + group: "style", + desc: "expressions where a bit mask is less readable than the corresponding method call", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "inline_fn_without_body", + group: "correctness", + desc: "use of `#[inline]` on trait methods without bodies", + deprecation: None, + module: "inline_fn_without_body", + }, + Lint { + name: "iterator_step_by_zero", + group: "correctness", + desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", + deprecation: None, + module: "ranges", + }, + Lint { + name: "range_zip_with_len", + group: "complexity", + desc: "zipping iterator with a range when `enumerate()` would do", + deprecation: None, + module: "ranges", + }, + Lint { + name: "range_plus_one", + group: "complexity", + desc: "`x..(y+1)` reads better as `x..=y`", + deprecation: None, + module: "ranges", + }, + Lint { + name: "range_minus_one", + group: "complexity", + desc: "`x..=(y-1)` reads better as `x..y`", + deprecation: None, + module: "ranges", + }, + Lint { + name: "redundant_closure", + group: "style", + desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", + deprecation: None, + module: "eta_reduction", + }, + Lint { + name: "redundant_closure_for_method_calls", + group: "pedantic", + desc: "redundant closures for method calls", + deprecation: None, + module: "eta_reduction", + }, + Lint { + name: "needless_continue", + group: "pedantic", + desc: "`continue` statements that can be replaced by a rearrangement of code", + deprecation: None, + module: "needless_continue", + }, + Lint { + name: "cognitive_complexity", + group: "complexity", + desc: "functions that should be split up into multiple functions", + deprecation: None, + module: "cognitive_complexity", + }, + Lint { + name: "println_empty_string", + group: "style", + desc: "using `println!(\"\")` with an empty string", + deprecation: None, + module: "write", + }, + Lint { + name: "print_with_newline", + group: "style", + desc: "using `print!()` with a format string that ends in a single newline", + deprecation: None, + module: "write", + }, + Lint { + name: "print_stdout", + group: "restriction", + desc: "printing on stdout", + deprecation: None, + module: "write", + }, + Lint { + name: "use_debug", + group: "restriction", + desc: "use of `Debug`-based formatting", + deprecation: None, + module: "write", + }, + Lint { + name: "print_literal", + group: "style", + desc: "printing a literal with a format string", + deprecation: None, + module: "write", + }, + Lint { + name: "writeln_empty_string", + group: "style", + desc: "using `writeln!(buf, \"\")` with an empty string", + deprecation: None, + module: "write", + }, + Lint { + name: "write_with_newline", + group: "style", + desc: "using `write!()` with a format string that ends in a single newline", + deprecation: None, + module: "write", + }, + Lint { + name: "write_literal", + group: "style", + desc: "writing a literal with a format string", + deprecation: None, + module: "write", + }, + Lint { + name: "collapsible_if", + group: "style", + desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", + deprecation: None, + module: "collapsible_if", + }, + Lint { + name: "needless_pass_by_value", + group: "pedantic", + desc: "functions taking arguments by value, but not consuming them in its body", + deprecation: None, + module: "needless_pass_by_value", + }, + Lint { + name: "identity_conversion", + group: "complexity", + desc: "using always-identical `Into`/`From`/`IntoIter` conversions", + deprecation: None, + module: "identity_conversion", + }, + Lint { + name: "cargo_common_metadata", + group: "cargo", + desc: "common metadata is defined in `Cargo.toml`", + deprecation: None, + module: "cargo_common_metadata", + }, + Lint { + name: "overflow_check_conditional", + group: "complexity", + desc: "overflow checks inspired by C which are likely to panic", + deprecation: None, + module: "overflow_check_conditional", + }, + Lint { + name: "min_max", + group: "correctness", + desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant", + deprecation: None, + module: "minmax", + }, + Lint { + name: "no_effect", + group: "complexity", + desc: "statements with no effect", + deprecation: None, + module: "no_effect", + }, + Lint { + name: "unnecessary_operation", + group: "complexity", + desc: "outer expressions with no effect", + deprecation: None, + module: "no_effect", + }, + Lint { + name: "should_assert_eq", + group: "Deprecated", + desc: "`assert!()` will be more flexible with RFC 2011", + deprecation: Some( + "`assert!()` will be more flexible with RFC 2011", + ), + module: "deprecated_lints", + }, + Lint { + name: "extend_from_slice", + group: "Deprecated", + desc: "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", + deprecation: Some( + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", + ), + module: "deprecated_lints", + }, + Lint { + name: "range_step_by_zero", + group: "Deprecated", + desc: "`iterator.step_by(0)` panics nowadays", + deprecation: Some( + "`iterator.step_by(0)` panics nowadays", + ), + module: "deprecated_lints", + }, + Lint { + name: "unstable_as_slice", + group: "Deprecated", + desc: "`Vec::as_slice` has been stabilized in 1.7", + deprecation: Some( + "`Vec::as_slice` has been stabilized in 1.7", + ), + module: "deprecated_lints", + }, + Lint { + name: "unstable_as_mut_slice", + group: "Deprecated", + desc: "`Vec::as_mut_slice` has been stabilized in 1.7", + deprecation: Some( + "`Vec::as_mut_slice` has been stabilized in 1.7", + ), + module: "deprecated_lints", + }, + Lint { + name: "str_to_string", + group: "Deprecated", + desc: "using `str::to_string` is common even today and specialization will likely happen soon", + deprecation: Some( + "using `str::to_string` is common even today and specialization will likely happen soon", + ), + module: "deprecated_lints", + }, + Lint { + name: "string_to_string", + group: "Deprecated", + desc: "using `string::to_string` is common even today and specialization will likely happen soon", + deprecation: Some( + "using `string::to_string` is common even today and specialization will likely happen soon", + ), + module: "deprecated_lints", + }, + Lint { + name: "misaligned_transmute", + group: "Deprecated", + desc: "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", + deprecation: Some( + "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", + ), + module: "deprecated_lints", + }, + Lint { + name: "assign_ops", + group: "Deprecated", + desc: "using compound assignment operators (e.g., `+=`) is harmless", + deprecation: Some( + "using compound assignment operators (e.g., `+=`) is harmless", + ), + module: "deprecated_lints", + }, + Lint { + name: "if_let_redundant_pattern_matching", + group: "Deprecated", + desc: "this lint has been changed to redundant_pattern_matching", + deprecation: Some( + "this lint has been changed to redundant_pattern_matching", + ), + module: "deprecated_lints", + }, + Lint { + name: "unsafe_vector_initialization", + group: "Deprecated", + desc: "the replacement suggested by this lint had substantially different behavior", + deprecation: Some( + "the replacement suggested by this lint had substantially different behavior", + ), + module: "deprecated_lints", + }, + Lint { + name: "int_plus_one", + group: "complexity", + desc: "instead of using x >= y + 1, use x > y", + deprecation: None, + module: "int_plus_one", + }, + Lint { + name: "map_entry", + group: "perf", + desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", + deprecation: None, + module: "entry", + }, + Lint { + name: "option_unwrap_used", + group: "restriction", + desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", + deprecation: None, + module: "methods", + }, + Lint { + name: "result_unwrap_used", + group: "restriction", + desc: "using `Result.unwrap()`, which might be better handled", + deprecation: None, + module: "methods", + }, + Lint { + name: "should_implement_trait", + group: "style", + desc: "defining a method that should be implementing a std trait", + deprecation: None, + module: "methods", + }, + Lint { + name: "wrong_self_convention", + group: "style", + desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + deprecation: None, + module: "methods", + }, + Lint { + name: "wrong_pub_self_convention", + group: "restriction", + desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + deprecation: None, + module: "methods", + }, + Lint { + name: "ok_expect", + group: "style", + desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_map_unwrap_or", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_map_unwrap_or_else", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "result_map_unwrap_or_else", + group: "pedantic", + desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_map_or_none", + group: "style", + desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "filter_next", + group: "complexity", + desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "map_flatten", + group: "pedantic", + desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "filter_map", + group: "pedantic", + desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "filter_map_next", + group: "pedantic", + desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "find_map", + group: "pedantic", + desc: "using a combination of `find` and `map` can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "search_is_some", + group: "complexity", + desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + deprecation: None, + module: "methods", + }, + Lint { + name: "chars_next_cmp", + group: "complexity", + desc: "using `.chars().next()` to check if a string starts with a char", + deprecation: None, + module: "methods", + }, + Lint { + name: "or_fun_call", + group: "perf", + desc: "using any `*or` method with a function call, which suggests `*or_else`", + deprecation: None, + module: "methods", + }, + Lint { + name: "expect_fun_call", + group: "perf", + desc: "using any `expect` method with a function call", + deprecation: None, + module: "methods", + }, + Lint { + name: "clone_on_copy", + group: "complexity", + desc: "using `clone` on a `Copy` type", + deprecation: None, + module: "methods", + }, + Lint { + name: "clone_on_ref_ptr", + group: "restriction", + desc: "using \'clone\' on a ref-counted pointer", + deprecation: None, + module: "methods", + }, + Lint { + name: "clone_double_ref", + group: "correctness", + desc: "using `clone` on `&&T`", + deprecation: None, + module: "methods", + }, + Lint { + name: "new_ret_no_self", + group: "style", + desc: "not returning `Self` in a `new` method", + deprecation: None, + module: "methods", + }, + Lint { + name: "single_char_pattern", + group: "perf", + desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", + deprecation: None, + module: "methods", + }, + Lint { + name: "temporary_cstring_as_ptr", + group: "correctness", + desc: "getting the inner pointer of a temporary `CString`", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_nth", + group: "perf", + desc: "using `.iter().nth()` on a standard library type with O(1) element access", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_skip_next", + group: "style", + desc: "using `.skip(x).next()` on an iterator", + deprecation: None, + module: "methods", + }, + Lint { + name: "get_unwrap", + group: "restriction", + desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", + deprecation: None, + module: "methods", + }, + Lint { + name: "string_extend_chars", + group: "style", + desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_cloned_collect", + group: "style", + desc: "using `.cloned().collect()` on slice to create a `Vec`", + deprecation: None, + module: "methods", + }, + Lint { + name: "chars_last_cmp", + group: "style", + desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", + deprecation: None, + module: "methods", + }, + Lint { + name: "useless_asref", + group: "complexity", + desc: "using `as_ref` where the types before and after the call are the same", + deprecation: None, + module: "methods", + }, + Lint { + name: "unnecessary_fold", + group: "style", + desc: "using `fold` when a more succinct alternative exists", + deprecation: None, + module: "methods", + }, + Lint { + name: "unnecessary_filter_map", + group: "complexity", + desc: "using `filter_map` when a more succinct alternative exists", + deprecation: None, + module: "methods", + }, + Lint { + name: "into_iter_on_array", + group: "correctness", + desc: "using `.into_iter()` on an array", + deprecation: None, + module: "methods", + }, + Lint { + name: "into_iter_on_ref", + group: "style", + desc: "using `.into_iter()` on a reference", + deprecation: None, + module: "methods", + }, + Lint { + name: "needless_return", + group: "style", + desc: "using a return statement like `return expr;` where an expression would suffice", + deprecation: None, + module: "returns", + }, + Lint { + name: "let_and_return", + group: "style", + desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", + deprecation: None, + module: "returns", + }, + Lint { + name: "unused_unit", + group: "style", + desc: "needless unit expression", + deprecation: None, + module: "returns", + }, + Lint { + name: "copy_iterator", + group: "pedantic", + desc: "implementing `Iterator` on a `Copy` type", + deprecation: None, + module: "copy_iterator", + }, + Lint { + name: "ifs_same_cond", + group: "correctness", + desc: "consecutive `ifs` with the same condition", + deprecation: None, + module: "copies", + }, + Lint { + name: "if_same_then_else", + group: "correctness", + desc: "if with the same *then* and *else* blocks", + deprecation: None, + module: "copies", + }, + Lint { + name: "match_same_arms", + group: "pedantic", + desc: "`match` with identical arm bodies", + deprecation: None, + module: "copies", + }, + Lint { + name: "checked_conversions", + group: "pedantic", + desc: "`try_from` could replace manual bounds checking when casting", + deprecation: None, + module: "checked_conversions", + }, + Lint { + name: "eval_order_dependence", + group: "complexity", + desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", + deprecation: None, + module: "eval_order_dependence", + }, + Lint { + name: "diverging_sub_expression", + group: "complexity", + desc: "whether an expression contains a diverging sub expression", + deprecation: None, + module: "eval_order_dependence", + }, + Lint { + name: "map_clone", + group: "style", + desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", + deprecation: None, + module: "map_clone", + }, + Lint { + name: "ptr_offset_with_cast", + group: "complexity", + desc: "unneeded pointer offset cast", + deprecation: None, + module: "ptr_offset_with_cast", + }, + Lint { + name: "infinite_iter", + group: "correctness", + desc: "infinite iteration", + deprecation: None, + module: "infinite_iter", + }, + Lint { + name: "maybe_infinite_iter", + group: "pedantic", + desc: "possible infinite iteration", + deprecation: None, + module: "infinite_iter", + }, + Lint { + name: "default_trait_access", + group: "pedantic", + desc: "checks for literal calls to Default::default()", + deprecation: None, + module: "default_trait_access", + }, + Lint { + name: "double_parens", + group: "complexity", + desc: "Warn on unnecessary double parentheses", + deprecation: None, + module: "double_parens", + }, + Lint { + name: "multiple_crate_versions", + group: "cargo", + desc: "multiple versions of the same crate being used", + deprecation: None, + module: "multiple_crate_versions", + }, + Lint { + name: "suspicious_arithmetic_impl", + group: "correctness", + desc: "suspicious use of operators in impl of arithmetic trait", + deprecation: None, + module: "suspicious_trait_impl", + }, + Lint { + name: "suspicious_op_assign_impl", + group: "correctness", + desc: "suspicious use of operators in impl of OpAssign trait", + deprecation: None, + module: "suspicious_trait_impl", + }, + Lint { + name: "mem_discriminant_non_enum", + group: "correctness", + desc: "calling mem::descriminant on non-enum type", + deprecation: None, + module: "mem_discriminant", + }, + Lint { + name: "path_buf_push_overwrite", + group: "nursery", + desc: "calling `push` with file system root on `PathBuf` can overwrite it", + deprecation: None, + module: "path_buf_push_overwrite", + }, + Lint { + name: "get_last_with_len", + group: "complexity", + desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", + deprecation: None, + module: "get_last_with_len", + }, + Lint { + name: "redundant_field_names", + group: "style", + desc: "checks for fields in struct literals where shorthands could be used", + deprecation: None, + module: "redundant_field_names", + }, + Lint { + name: "redundant_clone", + group: "nursery", + desc: "`clone()` of an owned value that is going to be dropped immediately", + deprecation: None, + module: "redundant_clone", + }, + Lint { + name: "ptr_arg", + group: "style", + desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", + deprecation: None, + module: "ptr", + }, + Lint { + name: "cmp_null", + group: "style", + desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", + deprecation: None, + module: "ptr", + }, + Lint { + name: "mut_from_ref", + group: "correctness", + desc: "fns that create mutable refs from immutable ref args", + deprecation: None, + module: "ptr", + }, + Lint { + name: "empty_enum", + group: "pedantic", + desc: "enum with no variants", + deprecation: None, + module: "empty_enum", + }, + Lint { + name: "unneeded_field_pattern", + group: "style", + desc: "struct fields bound to a wildcard instead of using `..`", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "duplicate_underscore_argument", + group: "style", + desc: "function arguments having names which only differ by an underscore", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "redundant_closure_call", + group: "complexity", + desc: "throwaway closures called in the expression they are defined", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "double_neg", + group: "style", + desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "mixed_case_hex_literals", + group: "style", + desc: "hex literals whose letter digits are not consistently upper- or lowercased", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "unseparated_literal_suffix", + group: "pedantic", + desc: "literals whose suffix is not separated by an underscore", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "zero_prefixed_literal", + group: "complexity", + desc: "integer literals starting with `0`", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "builtin_type_shadow", + group: "style", + desc: "shadowing a builtin type", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "useless_vec", + group: "perf", + desc: "useless `vec!`", + deprecation: None, + module: "vec", + }, + Lint { + name: "explicit_write", + group: "complexity", + desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", + deprecation: None, + module: "explicit_write", + }, + Lint { + name: "toplevel_ref_arg", + group: "style", + desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", + deprecation: None, + module: "misc", + }, + Lint { + name: "cmp_nan", + group: "correctness", + desc: "comparisons to NAN, which will always return false, probably not intended", + deprecation: None, + module: "misc", + }, + Lint { + name: "float_cmp", + group: "correctness", + desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", + deprecation: None, + module: "misc", + }, + Lint { + name: "cmp_owned", + group: "perf", + desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", + deprecation: None, + module: "misc", + }, + Lint { + name: "modulo_one", + group: "correctness", + desc: "taking a number modulo 1, which always returns 0", + deprecation: None, + module: "misc", + }, + Lint { + name: "redundant_pattern", + group: "style", + desc: "using `name @ _` in a pattern", + deprecation: None, + module: "misc", + }, + Lint { + name: "used_underscore_binding", + group: "pedantic", + desc: "using a binding which is prefixed with an underscore", + deprecation: None, + module: "misc", + }, + Lint { + name: "short_circuit_statement", + group: "complexity", + desc: "using a short circuit boolean condition as a statement", + deprecation: None, + module: "misc", + }, + Lint { + name: "zero_ptr", + group: "style", + desc: "using 0 as *{const, mut} T", + deprecation: None, + module: "misc", + }, + Lint { + name: "float_cmp_const", + group: "restriction", + desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", + deprecation: None, + module: "misc", + }, + Lint { + name: "string_add_assign", + group: "pedantic", + desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", + deprecation: None, + module: "strings", + }, + Lint { + name: "string_add", + group: "restriction", + desc: "using `x + ..` where x is a `String` instead of `push_str()`", + deprecation: None, + module: "strings", + }, + Lint { + name: "string_lit_as_bytes", + group: "style", + desc: "calling `as_bytes` on a string literal instead of using a byte string literal", + deprecation: None, + module: "strings", + }, + Lint { + name: "trivially_copy_pass_by_ref", + group: "perf", + desc: "functions taking small copyable arguments by reference", + deprecation: None, + module: "trivially_copy_pass_by_ref", + }, + Lint { + name: "double_comparisons", + group: "complexity", + desc: "unnecessary double comparisons that can be simplified", + deprecation: None, + module: "double_comparison", + }, + Lint { + name: "approx_constant", + group: "correctness", + desc: "the approximate of a known float constant (in `std::fXX::consts`)", + deprecation: None, + module: "approx_const", + }, + Lint { + name: "assign_op_pattern", + group: "style", + desc: "assigning the result of an operation on a variable to that same variable", + deprecation: None, + module: "assign_ops", + }, + Lint { + name: "misrefactored_assign_op", + group: "complexity", + desc: "having a variable on both sides of an assign op", + deprecation: None, + module: "assign_ops", + }, + Lint { + name: "erasing_op", + group: "correctness", + desc: "using erasing operations, e.g., `x * 0` or `y & 0`", + deprecation: None, + module: "erasing_op", + }, + Lint { + name: "wrong_transmute", + group: "correctness", + desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", + deprecation: None, + module: "transmute", + }, + Lint { + name: "useless_transmute", + group: "complexity", + desc: "transmutes that have the same to and from types or could be a cast/coercion", + deprecation: None, + module: "transmute", + }, + Lint { + name: "crosspointer_transmute", + group: "complexity", + desc: "transmutes that have to or from types that are a pointer to the other", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_ptr_to_ref", + group: "complexity", + desc: "transmutes from a pointer to a reference type", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_char", + group: "complexity", + desc: "transmutes from an integer to a `char`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_bytes_to_str", + group: "complexity", + desc: "transmutes from a `&[u8]` to a `&str`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_bool", + group: "complexity", + desc: "transmutes from an integer to a `bool`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_float", + group: "complexity", + desc: "transmutes from an integer to a float", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_ptr_to_ptr", + group: "complexity", + desc: "transmutes from a pointer to a pointer / a reference to a reference", + deprecation: None, + module: "transmute", + }, + Lint { + name: "needless_borrow", + group: "nursery", + desc: "taking a reference that is going to be automatically dereferenced", + deprecation: None, + module: "needless_borrow", + }, + Lint { + name: "if_not_else", + group: "pedantic", + desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", + deprecation: None, + module: "if_not_else", + }, + Lint { + name: "naive_bytecount", + group: "perf", + desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values", + deprecation: None, + module: "bytecount", + }, + Lint { + name: "zero_width_space", + group: "correctness", + desc: "using a zero-width space in a string literal, which is confusing", + deprecation: None, + module: "unicode", + }, + Lint { + name: "non_ascii_literal", + group: "pedantic", + desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", + deprecation: None, + module: "unicode", + }, + Lint { + name: "unicode_not_nfc", + group: "pedantic", + desc: "using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", + deprecation: None, + module: "unicode", + }, + Lint { + name: "len_zero", + group: "style", + desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", + deprecation: None, + module: "len_zero", + }, + Lint { + name: "len_without_is_empty", + group: "style", + desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", + deprecation: None, + module: "len_zero", + }, + Lint { + name: "useless_let_if_seq", + group: "style", + desc: "unidiomatic `let mut` declaration followed by initialization in `if`", + deprecation: None, + module: "let_if_seq", + }, + Lint { + name: "large_enum_variant", + group: "perf", + desc: "large size difference between variants on an enum", + deprecation: None, + module: "large_enum_variant", + }, + Lint { + name: "new_without_default", + group: "style", + desc: "`fn new() -> Self` method without `Default` implementation", + deprecation: None, + module: "new_without_default", + }, + Lint { + name: "box_vec", + group: "perf", + desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap", + deprecation: None, + module: "types", + }, + Lint { + name: "vec_box", + group: "complexity", + desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap", + deprecation: None, + module: "types", + }, + Lint { + name: "option_option", + group: "complexity", + desc: "usage of `Option<Option<T>>`", + deprecation: None, + module: "types", + }, + Lint { + name: "linkedlist", + group: "pedantic", + desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", + deprecation: None, + module: "types", + }, + Lint { + name: "borrowed_box", + group: "complexity", + desc: "a borrow of a boxed type", + deprecation: None, + module: "types", + }, + Lint { + name: "let_unit_value", + group: "style", + desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", + deprecation: None, + module: "types", + }, + Lint { + name: "unit_cmp", + group: "correctness", + desc: "comparing unit values", + deprecation: None, + module: "types", + }, + Lint { + name: "unit_arg", + group: "complexity", + desc: "passing unit to a function", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_precision_loss", + group: "pedantic", + desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_sign_loss", + group: "pedantic", + desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_possible_truncation", + group: "pedantic", + desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_possible_wrap", + group: "pedantic", + desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_lossless", + group: "complexity", + desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", + deprecation: None, + module: "types", + }, + Lint { + name: "unnecessary_cast", + group: "complexity", + desc: "cast to the same type, e.g., `x as i32` where `x: i32`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_ptr_alignment", + group: "correctness", + desc: "cast from a pointer to a more-strictly-aligned pointer", + deprecation: None, + module: "types", + }, + Lint { + name: "fn_to_numeric_cast", + group: "style", + desc: "casting a function pointer to a numeric type other than usize", + deprecation: None, + module: "types", + }, + Lint { + name: "fn_to_numeric_cast_with_truncation", + group: "style", + desc: "casting a function pointer to a numeric type not wide enough to store the address", + deprecation: None, + module: "types", + }, + Lint { + name: "type_complexity", + group: "complexity", + desc: "usage of very complex types that might be better factored into `type` definitions", + deprecation: None, + module: "types", + }, + Lint { + name: "char_lit_as_u8", + group: "complexity", + desc: "casting a character literal to u8", + deprecation: None, + module: "types", + }, + Lint { + name: "absurd_extreme_comparisons", + group: "correctness", + desc: "a comparison with a maximum or minimum value that is always true or false", + deprecation: None, + module: "types", + }, + Lint { + name: "invalid_upcast_comparisons", + group: "pedantic", + desc: "a comparison involving an upcast which is always true or false", + deprecation: None, + module: "types", + }, + Lint { + name: "implicit_hasher", + group: "style", + desc: "missing generalization over different hashers", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_ref_to_mut", + group: "correctness", + desc: "a cast of reference to a mutable pointer", + deprecation: None, + module: "types", + }, + Lint { + name: "needless_lifetimes", + group: "complexity", + desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", + deprecation: None, + module: "lifetimes", + }, + Lint { + name: "extra_unused_lifetimes", + group: "complexity", + desc: "unused lifetimes in function definitions", + deprecation: None, + module: "lifetimes", + }, + Lint { + name: "temporary_assignment", + group: "complexity", + desc: "assignments to temporaries", + deprecation: None, + module: "temporary_assignment", + }, + Lint { + name: "slow_vector_initialization", + group: "perf", + desc: "slow vector initialization", + deprecation: None, + module: "slow_vector_initialization", + }, + Lint { + name: "unreadable_literal", + group: "style", + desc: "long integer literal without underscores", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "mistyped_literal_suffixes", + group: "correctness", + desc: "mistyped literal suffix", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "inconsistent_digit_grouping", + group: "style", + desc: "integer literals with digits grouped inconsistently", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "large_digit_groups", + group: "pedantic", + desc: "grouping digits into groups that are too large", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "decimal_literal_representation", + group: "restriction", + desc: "using decimal representation when hexadecimal would be better", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "if_let_some_result", + group: "style", + desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", + deprecation: None, + module: "ok_if_let", + }, + Lint { + name: "panic_params", + group: "style", + desc: "missing parameters in `panic!` calls", + deprecation: None, + module: "panic_unimplemented", + }, + Lint { + name: "unimplemented", + group: "restriction", + desc: "`unimplemented!` should not be present in production code", + deprecation: None, + module: "panic_unimplemented", + }, + Lint { + name: "invalid_ref", + group: "correctness", + desc: "creation of invalid reference", + deprecation: None, + module: "invalid_ref", + }, + Lint { + name: "mem_replace_option_with_none", + group: "style", + desc: "replacing an `Option` with `None` instead of `take()`", + deprecation: None, + module: "mem_replace", + }, + Lint { + name: "const_static_lifetime", + group: "style", + desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", + deprecation: None, + module: "const_static_lifetime", + }, +]; \ No newline at end of file -- cgit 1.4.1-3-g733a5 From f6367c41dc2f8d262c741100b24396afc62d9389 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Sat, 8 Jun 2019 11:29:27 -0700 Subject: switch to sorted usable lints --- clippy_dev/src/main.rs | 15 +- src/lintlist.rs | 2354 +++++++++++++++++++++++------------------------- 2 files changed, 1121 insertions(+), 1248 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 3a54a067943..4c50cc3b81e 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -88,10 +88,18 @@ fn print_lints() { fn update_lints(update_mode: &UpdateMode) { let lint_list: Vec<Lint> = gather_all().collect(); + let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect(); + let lint_count = usable_lints.len(); + + let mut sorted_usable_lints = usable_lints.clone(); + sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); + std::fs::write( "../src/lintlist.rs", &format!( "\ +//! This file is managed by util/dev update_lints. Do not edit. + /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Debug)] pub struct Lint {{ @@ -103,15 +111,12 @@ pub struct Lint {{ }} pub const ALL_LINTS: [Lint; {}] = {:#?};\n", - lint_list.len(), - lint_list + sorted_usable_lints.len(), + sorted_usable_lints ), ) .expect("can write to file"); - let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect(); - let lint_count = usable_lints.len(); - let mut file_change = replace_region_in_file( "../README.md", r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#, diff --git a/src/lintlist.rs b/src/lintlist.rs index be4d4fc008a..113f993dd8a 100644 --- a/src/lintlist.rs +++ b/src/lintlist.rs @@ -1,3 +1,5 @@ +//! This file is managed by util/dev update_lints. Do not edit. + /// Lint data parsed from the Clippy source code. #[derive(Clone, PartialEq, Debug)] pub struct Lint { @@ -8,321 +10,300 @@ pub struct Lint { pub module: &'static str, } -pub const ALL_LINTS: [Lint; 320] = [ - Lint { - name: "too_many_arguments", - group: "complexity", - desc: "functions with too many arguments", - deprecation: None, - module: "functions", - }, +pub const ALL_LINTS: [Lint; 304] = [ Lint { - name: "too_many_lines", - group: "pedantic", - desc: "functions with too many lines", + name: "absurd_extreme_comparisons", + group: "correctness", + desc: "a comparison with a maximum or minimum value that is always true or false", deprecation: None, - module: "functions", + module: "types", }, Lint { - name: "not_unsafe_ptr_arg_deref", + name: "almost_swapped", group: "correctness", - desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", + desc: "`foo = bar; bar = foo` sequence", deprecation: None, - module: "functions", + module: "swap", }, Lint { - name: "precedence", - group: "complexity", - desc: "operations where precedence may be unclear", + name: "approx_constant", + group: "correctness", + desc: "the approximate of a known float constant (in `std::fXX::consts`)", deprecation: None, - module: "precedence", + module: "approx_const", }, Lint { - name: "single_match", + name: "assertions_on_constants", group: "style", - desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", + desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", deprecation: None, - module: "matches", + module: "assertions_on_constants", }, Lint { - name: "single_match_else", - group: "pedantic", - desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", + name: "assign_op_pattern", + group: "style", + desc: "assigning the result of an operation on a variable to that same variable", deprecation: None, - module: "matches", + module: "assign_ops", }, Lint { - name: "match_ref_pats", - group: "style", - desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", + name: "bad_bit_mask", + group: "correctness", + desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", deprecation: None, - module: "matches", + module: "bit_mask", }, Lint { - name: "match_bool", + name: "blacklisted_name", group: "style", - desc: "a match on a boolean expression instead of an `if..else` block", + desc: "usage of a blacklisted/placeholder name", deprecation: None, - module: "matches", + module: "blacklisted_name", }, Lint { - name: "match_overlapping_arm", + name: "block_in_if_condition_expr", group: "style", - desc: "a match with overlapping arms", + desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", deprecation: None, - module: "matches", + module: "block_in_if_condition", }, Lint { - name: "match_wild_err_arm", + name: "block_in_if_condition_stmt", group: "style", - desc: "a match with `Err(_)` arm and take drastic actions", + desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", deprecation: None, - module: "matches", + module: "block_in_if_condition", }, Lint { - name: "match_as_ref", + name: "bool_comparison", group: "complexity", - desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", + desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", deprecation: None, - module: "matches", + module: "needless_bool", }, Lint { - name: "wildcard_enum_match_arm", - group: "restriction", - desc: "a wildcard enum match arm using `_`", + name: "borrow_interior_mutable_const", + group: "correctness", + desc: "referencing const with interior mutability", deprecation: None, - module: "matches", + module: "non_copy_const", }, Lint { - name: "option_map_unit_fn", + name: "borrowed_box", group: "complexity", - desc: "using `option.map(f)`, where f is a function or closure that returns ()", + desc: "a borrow of a boxed type", deprecation: None, - module: "map_unit_fn", + module: "types", }, Lint { - name: "result_map_unit_fn", - group: "complexity", - desc: "using `result.map(f)`, where f is a function or closure that returns ()", + name: "box_vec", + group: "perf", + desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap", deprecation: None, - module: "map_unit_fn", + module: "types", }, Lint { - name: "else_if_without_else", - group: "restriction", - desc: "if expression with an `else if`, but without a final `else` branch", + name: "boxed_local", + group: "perf", + desc: "using `Box<T>` where unnecessary", deprecation: None, - module: "else_if_without_else", + module: "escape", }, Lint { - name: "fallible_impl_from", - group: "nursery", - desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", + name: "builtin_type_shadow", + group: "style", + desc: "shadowing a builtin type", deprecation: None, - module: "fallible_impl_from", + module: "misc_early", }, Lint { - name: "missing_docs_in_private_items", - group: "restriction", - desc: "detects missing documentation for public and private members", + name: "cargo_common_metadata", + group: "cargo", + desc: "common metadata is defined in `Cargo.toml`", deprecation: None, - module: "missing_doc", + module: "cargo_common_metadata", }, Lint { - name: "unused_label", + name: "cast_lossless", group: "complexity", - desc: "unused labels", + desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", deprecation: None, - module: "unused_label", + module: "types", }, Lint { - name: "missing_inline_in_public_items", - group: "restriction", - desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", + name: "cast_possible_truncation", + group: "pedantic", + desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", deprecation: None, - module: "missing_inline", + module: "types", }, Lint { - name: "wildcard_dependencies", - group: "cargo", - desc: "wildcard dependencies being used", + name: "cast_possible_wrap", + group: "pedantic", + desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", deprecation: None, - module: "wildcard_dependencies", + module: "types", }, Lint { - name: "neg_multiply", - group: "style", - desc: "multiplying integers with -1", + name: "cast_precision_loss", + group: "pedantic", + desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", deprecation: None, - module: "neg_multiply", + module: "types", }, Lint { - name: "unsafe_removed_from_name", - group: "style", - desc: "`unsafe` removed from API names on import", + name: "cast_ptr_alignment", + group: "correctness", + desc: "cast from a pointer to a more-strictly-aligned pointer", deprecation: None, - module: "unsafe_removed_from_name", + module: "types", }, Lint { - name: "drop_bounds", + name: "cast_ref_to_mut", group: "correctness", - desc: "Bounds of the form `T: Drop` are useless", + desc: "a cast of reference to a mutable pointer", deprecation: None, - module: "drop_bounds", + module: "types", }, Lint { - name: "integer_arithmetic", - group: "restriction", - desc: "any integer arithmetic statement", + name: "cast_sign_loss", + group: "pedantic", + desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", deprecation: None, - module: "arithmetic", + module: "types", }, Lint { - name: "float_arithmetic", - group: "restriction", - desc: "any floating-point arithmetic statement", + name: "char_lit_as_u8", + group: "complexity", + desc: "casting a character literal to u8", deprecation: None, - module: "arithmetic", + module: "types", }, Lint { - name: "derive_hash_xor_eq", - group: "correctness", - desc: "deriving `Hash` but implementing `PartialEq` explicitly", + name: "chars_last_cmp", + group: "style", + desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", deprecation: None, - module: "derive", + module: "methods", }, Lint { - name: "expl_impl_clone_on_copy", - group: "pedantic", - desc: "implementing `Clone` explicitly on `Copy` types", + name: "chars_next_cmp", + group: "complexity", + desc: "using `.chars().next()` to check if a string starts with a char", deprecation: None, - module: "derive", + module: "methods", }, Lint { - name: "enum_clike_unportable_variant", - group: "correctness", - desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", + name: "checked_conversions", + group: "pedantic", + desc: "`try_from` could replace manual bounds checking when casting", deprecation: None, - module: "enum_clike", + module: "checked_conversions", }, Lint { - name: "serde_api_misuse", + name: "clone_double_ref", group: "correctness", - desc: "various things that will negatively affect your serde experience", - deprecation: None, - module: "serde_api", - }, - Lint { - name: "replace_consts", - group: "pedantic", - desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", + desc: "using `clone` on `&&T`", deprecation: None, - module: "replace_consts", + module: "methods", }, Lint { - name: "unnecessary_unwrap", - group: "nursery", - desc: "checks for calls of unwrap[_err]() that cannot fail", + name: "clone_on_copy", + group: "complexity", + desc: "using `clone` on a `Copy` type", deprecation: None, - module: "unwrap", + module: "methods", }, Lint { - name: "panicking_unwrap", - group: "nursery", - desc: "checks for calls of unwrap[_err]() that will always fail", + name: "clone_on_ref_ptr", + group: "restriction", + desc: "using \'clone\' on a ref-counted pointer", deprecation: None, - module: "unwrap", + module: "methods", }, Lint { - name: "transmuting_null", + name: "cmp_nan", group: "correctness", - desc: "transmutes from a null pointer to a reference, which is undefined behavior", + desc: "comparisons to NAN, which will always return false, probably not intended", deprecation: None, - module: "transmuting_null", + module: "misc", }, Lint { - name: "assertions_on_constants", + name: "cmp_null", group: "style", - desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", + desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", deprecation: None, - module: "assertions_on_constants", + module: "ptr", }, Lint { - name: "shadow_same", - group: "restriction", - desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", + name: "cmp_owned", + group: "perf", + desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", deprecation: None, - module: "shadow", + module: "misc", }, Lint { - name: "shadow_reuse", - group: "restriction", - desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", + name: "cognitive_complexity", + group: "complexity", + desc: "functions that should be split up into multiple functions", deprecation: None, - module: "shadow", + module: "cognitive_complexity", }, Lint { - name: "shadow_unrelated", - group: "pedantic", - desc: "rebinding a name without even using the original value", + name: "collapsible_if", + group: "style", + desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", deprecation: None, - module: "shadow", + module: "collapsible_if", }, Lint { - name: "use_self", - group: "pedantic", - desc: "Unnecessary structure name repetition whereas `Self` is applicable", + name: "const_static_lifetime", + group: "style", + desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", deprecation: None, - module: "use_self", + module: "const_static_lifetime", }, Lint { - name: "declare_interior_mutable_const", - group: "correctness", - desc: "declaring const with interior mutability", + name: "copy_iterator", + group: "pedantic", + desc: "implementing `Iterator` on a `Copy` type", deprecation: None, - module: "non_copy_const", + module: "copy_iterator", }, Lint { - name: "borrow_interior_mutable_const", - group: "correctness", - desc: "referencing const with interior mutability", + name: "crosspointer_transmute", + group: "complexity", + desc: "transmutes that have to or from types that are a pointer to the other", deprecation: None, - module: "non_copy_const", + module: "transmute", }, Lint { - name: "inline_always", - group: "pedantic", - desc: "use of `#[inline(always)]`", + name: "dbg_macro", + group: "restriction", + desc: "`dbg!` macro is intended as a debugging tool", deprecation: None, - module: "attrs", + module: "dbg_macro", }, Lint { - name: "useless_attribute", - group: "correctness", - desc: "use of lint attributes on `extern crate` items", + name: "decimal_literal_representation", + group: "restriction", + desc: "using decimal representation when hexadecimal would be better", deprecation: None, - module: "attrs", + module: "literal_representation", }, Lint { - name: "deprecated_semver", + name: "declare_interior_mutable_const", group: "correctness", - desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", - deprecation: None, - module: "attrs", - }, - Lint { - name: "empty_line_after_outer_attr", - group: "nursery", - desc: "empty line after outer attribute", + desc: "declaring const with interior mutability", deprecation: None, - module: "attrs", + module: "non_copy_const", }, Lint { - name: "unknown_clippy_lints", - group: "style", - desc: "unknown_lints for scoped Clippy lints", + name: "default_trait_access", + group: "pedantic", + desc: "checks for literal calls to Default::default()", deprecation: None, - module: "attrs", + module: "default_trait_access", }, Lint { name: "deprecated_cfg_attr", @@ -332,137 +313,88 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "attrs", }, Lint { - name: "excessive_precision", - group: "style", - desc: "excessive precision for float literal", - deprecation: None, - module: "excessive_precision", - }, - Lint { - name: "items_after_statements", - group: "pedantic", - desc: "blocks where an item comes after a statement", + name: "deprecated_semver", + group: "correctness", + desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", deprecation: None, - module: "items_after_statements", + module: "attrs", }, Lint { - name: "multiple_inherent_impl", - group: "restriction", - desc: "Multiple inherent impl that could be grouped", + name: "deref_addrof", + group: "complexity", + desc: "use of `*&` or `*&mut` in an expression", deprecation: None, - module: "inherent_impl", + module: "reference", }, Lint { - name: "invalid_regex", + name: "derive_hash_xor_eq", group: "correctness", - desc: "invalid regular expressions", - deprecation: None, - module: "regex", - }, - Lint { - name: "trivial_regex", - group: "style", - desc: "trivial regular expressions", + desc: "deriving `Hash` but implementing `PartialEq` explicitly", deprecation: None, - module: "regex", + module: "derive", }, Lint { - name: "regex_macro", - group: "style", - desc: "use of `regex!(_)` instead of `Regex::new(_)`", + name: "diverging_sub_expression", + group: "complexity", + desc: "whether an expression contains a diverging sub expression", deprecation: None, - module: "regex", + module: "eval_order_dependence", }, Lint { - name: "question_mark", - group: "style", - desc: "checks for expressions that could be replaced by the question mark operator", + name: "doc_markdown", + group: "pedantic", + desc: "presence of `_`, `::` or camel-case outside backticks in documentation", deprecation: None, - module: "question_mark", + module: "doc", }, Lint { - name: "partialeq_ne_impl", + name: "double_comparisons", group: "complexity", - desc: "re-implementing `PartialEq::ne`", + desc: "unnecessary double comparisons that can be simplified", deprecation: None, - module: "partialeq_ne_impl", + module: "double_comparison", }, Lint { - name: "suspicious_assignment_formatting", + name: "double_neg", group: "style", - desc: "suspicious formatting of `*=`, `-=` or `!=`", + desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", deprecation: None, - module: "formatting", + module: "misc_early", }, Lint { - name: "suspicious_else_formatting", - group: "style", - desc: "suspicious formatting of `else`", + name: "double_parens", + group: "complexity", + desc: "Warn on unnecessary double parentheses", deprecation: None, - module: "formatting", + module: "double_parens", }, Lint { - name: "possible_missing_comma", + name: "drop_bounds", group: "correctness", - desc: "possible missing comma in array", - deprecation: None, - module: "formatting", - }, - Lint { - name: "dbg_macro", - group: "restriction", - desc: "`dbg!` macro is intended as a debugging tool", - deprecation: None, - module: "dbg_macro", - }, - Lint { - name: "needless_borrowed_reference", - group: "complexity", - desc: "taking a needless borrowed reference", + desc: "Bounds of the form `T: Drop` are useless", deprecation: None, - module: "needless_borrowed_ref", + module: "drop_bounds", }, Lint { - name: "missing_const_for_fn", - group: "nursery", - desc: "Lint functions definitions that could be made `const fn`", + name: "drop_copy", + group: "correctness", + desc: "calls to `std::mem::drop` with a value that implements Copy", deprecation: None, - module: "missing_const_for_fn", + module: "drop_forget_ref", }, Lint { - name: "eq_op", + name: "drop_ref", group: "correctness", - desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", + desc: "calls to `std::mem::drop` with a reference instead of an owned value", deprecation: None, - module: "eq_op", + module: "drop_forget_ref", }, Lint { - name: "op_ref", + name: "duplicate_underscore_argument", group: "style", - desc: "taking a reference to satisfy the type constraints on `==`", - deprecation: None, - module: "eq_op", - }, - Lint { - name: "identity_op", - group: "complexity", - desc: "using identity operations, e.g., `x + 0` or `y / 1`", - deprecation: None, - module: "identity_op", - }, - Lint { - name: "boxed_local", - group: "perf", - desc: "using `Box<T>` where unnecessary", - deprecation: None, - module: "escape", - }, - Lint { - name: "mem_forget", - group: "restriction", - desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", + desc: "function arguments having names which only differ by an underscore", deprecation: None, - module: "mem_forget", + module: "misc_early", }, Lint { name: "duration_subsec", @@ -472,46 +404,39 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "duration_subsec", }, Lint { - name: "blacklisted_name", - group: "style", - desc: "usage of a blacklisted/placeholder name", - deprecation: None, - module: "blacklisted_name", - }, - Lint { - name: "nonminimal_bool", - group: "complexity", - desc: "boolean expressions that can be written more concisely", + name: "else_if_without_else", + group: "restriction", + desc: "if expression with an `else if`, but without a final `else` branch", deprecation: None, - module: "booleans", + module: "else_if_without_else", }, Lint { - name: "logic_bug", - group: "correctness", - desc: "boolean expressions that contain terminals which can be eliminated", + name: "empty_enum", + group: "pedantic", + desc: "enum with no variants", deprecation: None, - module: "booleans", + module: "empty_enum", }, Lint { - name: "useless_format", - group: "complexity", - desc: "useless use of `format!`", + name: "empty_line_after_outer_attr", + group: "nursery", + desc: "empty line after outer attribute", deprecation: None, - module: "format", + module: "attrs", }, Lint { - name: "needless_bool", - group: "complexity", - desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", + name: "empty_loop", + group: "style", + desc: "empty `loop {}`, which should block or sleep", deprecation: None, - module: "needless_bool", + module: "loops", }, Lint { - name: "bool_comparison", - group: "complexity", - desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", + name: "enum_clike_unportable_variant", + group: "correctness", + desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", deprecation: None, - module: "needless_bool", + module: "enum_clike", }, Lint { name: "enum_glob_use", @@ -520,41 +445,6 @@ pub const ALL_LINTS: [Lint; 320] = [ deprecation: None, module: "enum_glob_use", }, - Lint { - name: "zero_divided_by_zero", - group: "complexity", - desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", - deprecation: None, - module: "zero_div_zero", - }, - Lint { - name: "unnecessary_mut_passed", - group: "style", - desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", - deprecation: None, - module: "mut_reference", - }, - Lint { - name: "out_of_bounds_indexing", - group: "correctness", - desc: "out of bounds constant indexing", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "indexing_slicing", - group: "restriction", - desc: "indexing/slicing usage", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "implicit_return", - group: "restriction", - desc: "use a return statement like `return expr` instead of an expression", - deprecation: None, - module: "implicit_return", - }, Lint { name: "enum_variant_names", group: "style", @@ -563,184 +453,156 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "enum_variants", }, Lint { - name: "pub_enum_variant_names", - group: "pedantic", - desc: "enums where all variants share a prefix/postfix", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "module_name_repetitions", - group: "pedantic", - desc: "type names prefixed/postfixed with their containing module\'s name", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "module_inception", - group: "style", - desc: "modules that have the same name as their parent module", + name: "eq_op", + group: "correctness", + desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", deprecation: None, - module: "enum_variants", + module: "eq_op", }, Lint { - name: "deep_code_inspection", - group: "internal_warn", - desc: "helper to dump info about code", + name: "erasing_op", + group: "correctness", + desc: "using erasing operations, e.g., `x * 0` or `y & 0`", deprecation: None, - module: "inspector", + module: "erasing_op", }, Lint { - name: "lint_author", - group: "internal_warn", - desc: "helper for writing lints", + name: "eval_order_dependence", + group: "complexity", + desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", deprecation: None, - module: "author", + module: "eval_order_dependence", }, Lint { - name: "clippy_lints_internal", - group: "internal", - desc: "various things that will negatively affect your clippy experience", + name: "excessive_precision", + group: "style", + desc: "excessive precision for float literal", deprecation: None, - module: "internal_lints", + module: "excessive_precision", }, Lint { - name: "lint_without_lint_pass", - group: "internal", - desc: "declaring a lint without associating it in a LintPass", + name: "expect_fun_call", + group: "perf", + desc: "using any `expect` method with a function call", deprecation: None, - module: "internal_lints", + module: "methods", }, Lint { - name: "compiler_lint_functions", - group: "internal", - desc: "usage of the lint functions of the compiler instead of the utils::* variant", + name: "expl_impl_clone_on_copy", + group: "pedantic", + desc: "implementing `Clone` explicitly on `Copy` types", deprecation: None, - module: "internal_lints", + module: "derive", }, Lint { - name: "neg_cmp_op_on_partial_ord", + name: "explicit_counter_loop", group: "complexity", - desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", - deprecation: None, - module: "neg_cmp_op_on_partial_ord", - }, - Lint { - name: "unused_io_amount", - group: "correctness", - desc: "unused written/read amount", + desc: "for-looping with an explicit counter when `_.enumerate()` would do", deprecation: None, - module: "unused_io_amount", + module: "loops", }, Lint { - name: "infallible_destructuring_match", - group: "style", - desc: "a match statement with a single infallible arm instead of a `let`", + name: "explicit_into_iter_loop", + group: "pedantic", + desc: "for-looping over `_.into_iter()` when `_` would do", deprecation: None, - module: "infallible_destructuring_match", + module: "loops", }, Lint { - name: "nonsensical_open_options", - group: "correctness", - desc: "nonsensical combination of options for opening a file", + name: "explicit_iter_loop", + group: "pedantic", + desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", deprecation: None, - module: "open_options", + module: "loops", }, Lint { - name: "mut_mut", - group: "pedantic", - desc: "usage of double-mut refs, e.g., `&mut &mut ...`", + name: "explicit_write", + group: "complexity", + desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", deprecation: None, - module: "mut_mut", + module: "explicit_write", }, Lint { - name: "mutex_atomic", - group: "perf", - desc: "using a mutex where an atomic value could be used instead", + name: "extra_unused_lifetimes", + group: "complexity", + desc: "unused lifetimes in function definitions", deprecation: None, - module: "mutex_atomic", + module: "lifetimes", }, Lint { - name: "mutex_integer", + name: "fallible_impl_from", group: "nursery", - desc: "using a mutex for an integer type", + desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", deprecation: None, - module: "mutex_atomic", + module: "fallible_impl_from", }, Lint { - name: "doc_markdown", + name: "filter_map", group: "pedantic", - desc: "presence of `_`, `::` or camel-case outside backticks in documentation", + desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", deprecation: None, - module: "doc", + module: "methods", }, Lint { - name: "deref_addrof", - group: "complexity", - desc: "use of `*&` or `*&mut` in an expression", + name: "filter_map_next", + group: "pedantic", + desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", deprecation: None, - module: "reference", + module: "methods", }, Lint { - name: "ref_in_deref", + name: "filter_next", group: "complexity", - desc: "Use of reference in auto dereference expression.", + desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", deprecation: None, - module: "reference", + module: "methods", }, Lint { - name: "similar_names", + name: "find_map", group: "pedantic", - desc: "similarly named items and bindings", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "many_single_char_names", - group: "style", - desc: "too many single character bindings", + desc: "using a combination of `find` and `map` can usually be written as a single method call", deprecation: None, - module: "non_expressive_names", + module: "methods", }, Lint { - name: "just_underscores_and_digits", - group: "style", - desc: "unclear name", + name: "float_arithmetic", + group: "restriction", + desc: "any floating-point arithmetic statement", deprecation: None, - module: "non_expressive_names", + module: "arithmetic", }, Lint { - name: "manual_memcpy", - group: "perf", - desc: "manually copying items between slices", + name: "float_cmp", + group: "correctness", + desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", deprecation: None, - module: "loops", + module: "misc", }, Lint { - name: "needless_range_loop", - group: "style", - desc: "for-looping over a range of indices where an iterator over items would do", + name: "float_cmp_const", + group: "restriction", + desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", deprecation: None, - module: "loops", + module: "misc", }, Lint { - name: "explicit_iter_loop", - group: "pedantic", - desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", + name: "fn_to_numeric_cast", + group: "style", + desc: "casting a function pointer to a numeric type other than usize", deprecation: None, - module: "loops", + module: "types", }, Lint { - name: "explicit_into_iter_loop", - group: "pedantic", - desc: "for-looping over `_.into_iter()` when `_` would do", + name: "fn_to_numeric_cast_with_truncation", + group: "style", + desc: "casting a function pointer to a numeric type not wide enough to store the address", deprecation: None, - module: "loops", + module: "types", }, Lint { - name: "iter_next_loop", - group: "correctness", - desc: "for-looping over `_.next()` which is probably not intended", + name: "for_kv_map", + group: "style", + desc: "looping on a map using `iter` when `keys` or `values` would do", deprecation: None, module: "loops", }, @@ -759,326 +621,403 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "loops", }, Lint { - name: "while_let_loop", - group: "complexity", - desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", + name: "forget_copy", + group: "correctness", + desc: "calls to `std::mem::forget` with a value that implements Copy", deprecation: None, - module: "loops", + module: "drop_forget_ref", }, Lint { - name: "unused_collect", - group: "perf", - desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", + name: "forget_ref", + group: "correctness", + desc: "calls to `std::mem::forget` with a reference instead of an owned value", deprecation: None, - module: "loops", + module: "drop_forget_ref", }, Lint { - name: "needless_collect", - group: "perf", - desc: "collecting an iterator when collect is not needed", + name: "get_last_with_len", + group: "complexity", + desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", deprecation: None, - module: "loops", + module: "get_last_with_len", }, Lint { - name: "reverse_range_loop", - group: "correctness", - desc: "iteration over an empty range, such as `10..0` or `5..5`", + name: "get_unwrap", + group: "restriction", + desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", deprecation: None, - module: "loops", + module: "methods", }, Lint { - name: "explicit_counter_loop", + name: "identity_conversion", group: "complexity", - desc: "for-looping with an explicit counter when `_.enumerate()` would do", + desc: "using always-identical `Into`/`From`/`IntoIter` conversions", deprecation: None, - module: "loops", + module: "identity_conversion", }, Lint { - name: "empty_loop", - group: "style", - desc: "empty `loop {}`, which should block or sleep", + name: "identity_op", + group: "complexity", + desc: "using identity operations, e.g., `x + 0` or `y / 1`", deprecation: None, - module: "loops", + module: "identity_op", }, Lint { - name: "while_let_on_iterator", + name: "if_let_some_result", group: "style", - desc: "using a while-let loop instead of a for loop on an iterator", + desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", deprecation: None, - module: "loops", + module: "ok_if_let", }, Lint { - name: "for_kv_map", - group: "style", - desc: "looping on a map using `iter` when `keys` or `values` would do", + name: "if_not_else", + group: "pedantic", + desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", deprecation: None, - module: "loops", + module: "if_not_else", }, Lint { - name: "never_loop", + name: "if_same_then_else", group: "correctness", - desc: "any loop that will always `break` or `return`", + desc: "if with the same *then* and *else* blocks", deprecation: None, - module: "loops", + module: "copies", }, Lint { - name: "mut_range_bound", - group: "complexity", - desc: "for loop over a range where one of the bounds is a mutable variable", + name: "ifs_same_cond", + group: "correctness", + desc: "consecutive `ifs` with the same condition", deprecation: None, - module: "loops", + module: "copies", }, Lint { - name: "while_immutable_condition", - group: "correctness", - desc: "variables used within while expression are not mutated in the body", + name: "implicit_hasher", + group: "style", + desc: "missing generalization over different hashers", deprecation: None, - module: "loops", + module: "types", }, Lint { - name: "needless_update", - group: "complexity", - desc: "using `Foo { ..base }` when there are no missing fields", + name: "implicit_return", + group: "restriction", + desc: "use a return statement like `return expr` instead of an expression", deprecation: None, - module: "needless_update", + module: "implicit_return", }, Lint { - name: "block_in_if_condition_expr", + name: "inconsistent_digit_grouping", group: "style", - desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", + desc: "integer literals with digits grouped inconsistently", deprecation: None, - module: "block_in_if_condition", + module: "literal_representation", }, Lint { - name: "block_in_if_condition_stmt", - group: "style", - desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", + name: "indexing_slicing", + group: "restriction", + desc: "indexing/slicing usage", deprecation: None, - module: "block_in_if_condition", + module: "indexing_slicing", }, Lint { - name: "drop_ref", + name: "ineffective_bit_mask", group: "correctness", - desc: "calls to `std::mem::drop` with a reference instead of an owned value", + desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", deprecation: None, - module: "drop_forget_ref", + module: "bit_mask", }, Lint { - name: "forget_ref", - group: "correctness", - desc: "calls to `std::mem::forget` with a reference instead of an owned value", + name: "infallible_destructuring_match", + group: "style", + desc: "a match statement with a single infallible arm instead of a `let`", deprecation: None, - module: "drop_forget_ref", + module: "infallible_destructuring_match", }, Lint { - name: "drop_copy", + name: "infinite_iter", group: "correctness", - desc: "calls to `std::mem::drop` with a value that implements Copy", + desc: "infinite iteration", deprecation: None, - module: "drop_forget_ref", + module: "infinite_iter", }, Lint { - name: "forget_copy", + name: "inline_always", + group: "pedantic", + desc: "use of `#[inline(always)]`", + deprecation: None, + module: "attrs", + }, + Lint { + name: "inline_fn_without_body", group: "correctness", - desc: "calls to `std::mem::forget` with a value that implements Copy", + desc: "use of `#[inline]` on trait methods without bodies", deprecation: None, - module: "drop_forget_ref", + module: "inline_fn_without_body", }, Lint { - name: "manual_swap", + name: "int_plus_one", group: "complexity", - desc: "manual swap of two variables", + desc: "instead of using x >= y + 1, use x > y", deprecation: None, - module: "swap", + module: "int_plus_one", }, Lint { - name: "almost_swapped", + name: "integer_arithmetic", + group: "restriction", + desc: "any integer arithmetic statement", + deprecation: None, + module: "arithmetic", + }, + Lint { + name: "into_iter_on_array", group: "correctness", - desc: "`foo = bar; bar = foo` sequence", + desc: "using `.into_iter()` on an array", deprecation: None, - module: "swap", + module: "methods", }, Lint { - name: "redundant_pattern_matching", + name: "into_iter_on_ref", group: "style", - desc: "use the proper utility function avoiding an `if let`", + desc: "using `.into_iter()` on a reference", deprecation: None, - module: "redundant_pattern_matching", + module: "methods", }, Lint { - name: "bad_bit_mask", + name: "invalid_ref", group: "correctness", - desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", + desc: "creation of invalid reference", deprecation: None, - module: "bit_mask", + module: "invalid_ref", }, Lint { - name: "ineffective_bit_mask", + name: "invalid_regex", group: "correctness", - desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", + desc: "invalid regular expressions", deprecation: None, - module: "bit_mask", + module: "regex", }, Lint { - name: "verbose_bit_mask", + name: "invalid_upcast_comparisons", + group: "pedantic", + desc: "a comparison involving an upcast which is always true or false", + deprecation: None, + module: "types", + }, + Lint { + name: "items_after_statements", + group: "pedantic", + desc: "blocks where an item comes after a statement", + deprecation: None, + module: "items_after_statements", + }, + Lint { + name: "iter_cloned_collect", group: "style", - desc: "expressions where a bit mask is less readable than the corresponding method call", + desc: "using `.cloned().collect()` on slice to create a `Vec`", deprecation: None, - module: "bit_mask", + module: "methods", }, Lint { - name: "inline_fn_without_body", + name: "iter_next_loop", group: "correctness", - desc: "use of `#[inline]` on trait methods without bodies", + desc: "for-looping over `_.next()` which is probably not intended", deprecation: None, - module: "inline_fn_without_body", + module: "loops", + }, + Lint { + name: "iter_nth", + group: "perf", + desc: "using `.iter().nth()` on a standard library type with O(1) element access", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_skip_next", + group: "style", + desc: "using `.skip(x).next()` on an iterator", + deprecation: None, + module: "methods", }, Lint { name: "iterator_step_by_zero", group: "correctness", desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", deprecation: None, - module: "ranges", + module: "ranges", + }, + Lint { + name: "just_underscores_and_digits", + group: "style", + desc: "unclear name", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "large_digit_groups", + group: "pedantic", + desc: "grouping digits into groups that are too large", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "large_enum_variant", + group: "perf", + desc: "large size difference between variants on an enum", + deprecation: None, + module: "large_enum_variant", }, Lint { - name: "range_zip_with_len", - group: "complexity", - desc: "zipping iterator with a range when `enumerate()` would do", + name: "len_without_is_empty", + group: "style", + desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", deprecation: None, - module: "ranges", + module: "len_zero", }, Lint { - name: "range_plus_one", - group: "complexity", - desc: "`x..(y+1)` reads better as `x..=y`", + name: "len_zero", + group: "style", + desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", deprecation: None, - module: "ranges", + module: "len_zero", }, Lint { - name: "range_minus_one", - group: "complexity", - desc: "`x..=(y-1)` reads better as `x..y`", + name: "let_and_return", + group: "style", + desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", deprecation: None, - module: "ranges", + module: "returns", }, Lint { - name: "redundant_closure", + name: "let_unit_value", group: "style", - desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", + desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", deprecation: None, - module: "eta_reduction", + module: "types", }, Lint { - name: "redundant_closure_for_method_calls", + name: "linkedlist", group: "pedantic", - desc: "redundant closures for method calls", + desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", deprecation: None, - module: "eta_reduction", + module: "types", }, Lint { - name: "needless_continue", - group: "pedantic", - desc: "`continue` statements that can be replaced by a rearrangement of code", + name: "logic_bug", + group: "correctness", + desc: "boolean expressions that contain terminals which can be eliminated", deprecation: None, - module: "needless_continue", + module: "booleans", }, Lint { - name: "cognitive_complexity", + name: "manual_memcpy", + group: "perf", + desc: "manually copying items between slices", + deprecation: None, + module: "loops", + }, + Lint { + name: "manual_swap", group: "complexity", - desc: "functions that should be split up into multiple functions", + desc: "manual swap of two variables", deprecation: None, - module: "cognitive_complexity", + module: "swap", }, Lint { - name: "println_empty_string", + name: "many_single_char_names", group: "style", - desc: "using `println!(\"\")` with an empty string", + desc: "too many single character bindings", deprecation: None, - module: "write", + module: "non_expressive_names", }, Lint { - name: "print_with_newline", + name: "map_clone", group: "style", - desc: "using `print!()` with a format string that ends in a single newline", + desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", deprecation: None, - module: "write", + module: "map_clone", }, Lint { - name: "print_stdout", - group: "restriction", - desc: "printing on stdout", + name: "map_entry", + group: "perf", + desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", deprecation: None, - module: "write", + module: "entry", }, Lint { - name: "use_debug", - group: "restriction", - desc: "use of `Debug`-based formatting", + name: "map_flatten", + group: "pedantic", + desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", deprecation: None, - module: "write", + module: "methods", }, Lint { - name: "print_literal", - group: "style", - desc: "printing a literal with a format string", + name: "match_as_ref", + group: "complexity", + desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", deprecation: None, - module: "write", + module: "matches", }, Lint { - name: "writeln_empty_string", + name: "match_bool", group: "style", - desc: "using `writeln!(buf, \"\")` with an empty string", + desc: "a match on a boolean expression instead of an `if..else` block", deprecation: None, - module: "write", + module: "matches", }, Lint { - name: "write_with_newline", + name: "match_overlapping_arm", group: "style", - desc: "using `write!()` with a format string that ends in a single newline", + desc: "a match with overlapping arms", deprecation: None, - module: "write", + module: "matches", }, Lint { - name: "write_literal", + name: "match_ref_pats", group: "style", - desc: "writing a literal with a format string", + desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", deprecation: None, - module: "write", + module: "matches", }, Lint { - name: "collapsible_if", + name: "match_same_arms", + group: "pedantic", + desc: "`match` with identical arm bodies", + deprecation: None, + module: "copies", + }, + Lint { + name: "match_wild_err_arm", group: "style", - desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", + desc: "a match with `Err(_)` arm and take drastic actions", deprecation: None, - module: "collapsible_if", + module: "matches", }, Lint { - name: "needless_pass_by_value", + name: "maybe_infinite_iter", group: "pedantic", - desc: "functions taking arguments by value, but not consuming them in its body", + desc: "possible infinite iteration", deprecation: None, - module: "needless_pass_by_value", + module: "infinite_iter", }, Lint { - name: "identity_conversion", - group: "complexity", - desc: "using always-identical `Into`/`From`/`IntoIter` conversions", + name: "mem_discriminant_non_enum", + group: "correctness", + desc: "calling mem::descriminant on non-enum type", deprecation: None, - module: "identity_conversion", + module: "mem_discriminant", }, Lint { - name: "cargo_common_metadata", - group: "cargo", - desc: "common metadata is defined in `Cargo.toml`", + name: "mem_forget", + group: "restriction", + desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", deprecation: None, - module: "cargo_common_metadata", + module: "mem_forget", }, Lint { - name: "overflow_check_conditional", - group: "complexity", - desc: "overflow checks inspired by C which are likely to panic", + name: "mem_replace_option_with_none", + group: "style", + desc: "replacing an `Option` with `None` instead of `take()`", deprecation: None, - module: "overflow_check_conditional", + module: "mem_replace", }, Lint { name: "min_max", @@ -1088,285 +1027,214 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "minmax", }, Lint { - name: "no_effect", + name: "misrefactored_assign_op", group: "complexity", - desc: "statements with no effect", + desc: "having a variable on both sides of an assign op", deprecation: None, - module: "no_effect", + module: "assign_ops", }, Lint { - name: "unnecessary_operation", - group: "complexity", - desc: "outer expressions with no effect", + name: "missing_const_for_fn", + group: "nursery", + desc: "Lint functions definitions that could be made `const fn`", deprecation: None, - module: "no_effect", + module: "missing_const_for_fn", }, Lint { - name: "should_assert_eq", - group: "Deprecated", - desc: "`assert!()` will be more flexible with RFC 2011", - deprecation: Some( - "`assert!()` will be more flexible with RFC 2011", - ), - module: "deprecated_lints", - }, - Lint { - name: "extend_from_slice", - group: "Deprecated", - desc: "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", - deprecation: Some( - "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", - ), - module: "deprecated_lints", - }, - Lint { - name: "range_step_by_zero", - group: "Deprecated", - desc: "`iterator.step_by(0)` panics nowadays", - deprecation: Some( - "`iterator.step_by(0)` panics nowadays", - ), - module: "deprecated_lints", - }, - Lint { - name: "unstable_as_slice", - group: "Deprecated", - desc: "`Vec::as_slice` has been stabilized in 1.7", - deprecation: Some( - "`Vec::as_slice` has been stabilized in 1.7", - ), - module: "deprecated_lints", - }, - Lint { - name: "unstable_as_mut_slice", - group: "Deprecated", - desc: "`Vec::as_mut_slice` has been stabilized in 1.7", - deprecation: Some( - "`Vec::as_mut_slice` has been stabilized in 1.7", - ), - module: "deprecated_lints", - }, - Lint { - name: "str_to_string", - group: "Deprecated", - desc: "using `str::to_string` is common even today and specialization will likely happen soon", - deprecation: Some( - "using `str::to_string` is common even today and specialization will likely happen soon", - ), - module: "deprecated_lints", - }, - Lint { - name: "string_to_string", - group: "Deprecated", - desc: "using `string::to_string` is common even today and specialization will likely happen soon", - deprecation: Some( - "using `string::to_string` is common even today and specialization will likely happen soon", - ), - module: "deprecated_lints", - }, - Lint { - name: "misaligned_transmute", - group: "Deprecated", - desc: "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", - deprecation: Some( - "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", - ), - module: "deprecated_lints", - }, - Lint { - name: "assign_ops", - group: "Deprecated", - desc: "using compound assignment operators (e.g., `+=`) is harmless", - deprecation: Some( - "using compound assignment operators (e.g., `+=`) is harmless", - ), - module: "deprecated_lints", - }, - Lint { - name: "if_let_redundant_pattern_matching", - group: "Deprecated", - desc: "this lint has been changed to redundant_pattern_matching", - deprecation: Some( - "this lint has been changed to redundant_pattern_matching", - ), - module: "deprecated_lints", - }, - Lint { - name: "unsafe_vector_initialization", - group: "Deprecated", - desc: "the replacement suggested by this lint had substantially different behavior", - deprecation: Some( - "the replacement suggested by this lint had substantially different behavior", - ), - module: "deprecated_lints", + name: "missing_docs_in_private_items", + group: "restriction", + desc: "detects missing documentation for public and private members", + deprecation: None, + module: "missing_doc", }, Lint { - name: "int_plus_one", - group: "complexity", - desc: "instead of using x >= y + 1, use x > y", + name: "missing_inline_in_public_items", + group: "restriction", + desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", deprecation: None, - module: "int_plus_one", + module: "missing_inline", }, Lint { - name: "map_entry", - group: "perf", - desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", + name: "mistyped_literal_suffixes", + group: "correctness", + desc: "mistyped literal suffix", deprecation: None, - module: "entry", + module: "literal_representation", }, Lint { - name: "option_unwrap_used", - group: "restriction", - desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", + name: "mixed_case_hex_literals", + group: "style", + desc: "hex literals whose letter digits are not consistently upper- or lowercased", deprecation: None, - module: "methods", + module: "misc_early", }, Lint { - name: "result_unwrap_used", - group: "restriction", - desc: "using `Result.unwrap()`, which might be better handled", + name: "module_inception", + group: "style", + desc: "modules that have the same name as their parent module", deprecation: None, - module: "methods", + module: "enum_variants", }, Lint { - name: "should_implement_trait", - group: "style", - desc: "defining a method that should be implementing a std trait", + name: "module_name_repetitions", + group: "pedantic", + desc: "type names prefixed/postfixed with their containing module\'s name", deprecation: None, - module: "methods", + module: "enum_variants", }, Lint { - name: "wrong_self_convention", - group: "style", - desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + name: "modulo_one", + group: "correctness", + desc: "taking a number modulo 1, which always returns 0", deprecation: None, - module: "methods", + module: "misc", }, Lint { - name: "wrong_pub_self_convention", + name: "multiple_crate_versions", + group: "cargo", + desc: "multiple versions of the same crate being used", + deprecation: None, + module: "multiple_crate_versions", + }, + Lint { + name: "multiple_inherent_impl", group: "restriction", - desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + desc: "Multiple inherent impl that could be grouped", deprecation: None, - module: "methods", + module: "inherent_impl", }, Lint { - name: "ok_expect", - group: "style", - desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", + name: "mut_from_ref", + group: "correctness", + desc: "fns that create mutable refs from immutable ref args", deprecation: None, - module: "methods", + module: "ptr", }, Lint { - name: "option_map_unwrap_or", + name: "mut_mut", group: "pedantic", - desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", + desc: "usage of double-mut refs, e.g., `&mut &mut ...`", + deprecation: None, + module: "mut_mut", + }, + Lint { + name: "mut_range_bound", + group: "complexity", + desc: "for loop over a range where one of the bounds is a mutable variable", deprecation: None, - module: "methods", + module: "loops", }, Lint { - name: "option_map_unwrap_or_else", - group: "pedantic", - desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", + name: "mutex_atomic", + group: "perf", + desc: "using a mutex where an atomic value could be used instead", deprecation: None, - module: "methods", + module: "mutex_atomic", }, Lint { - name: "result_map_unwrap_or_else", - group: "pedantic", - desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", + name: "mutex_integer", + group: "nursery", + desc: "using a mutex for an integer type", deprecation: None, - module: "methods", + module: "mutex_atomic", }, Lint { - name: "option_map_or_none", - group: "style", - desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", + name: "naive_bytecount", + group: "perf", + desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values", deprecation: None, - module: "methods", + module: "bytecount", }, Lint { - name: "filter_next", + name: "needless_bool", group: "complexity", - desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", + desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", deprecation: None, - module: "methods", + module: "needless_bool", }, Lint { - name: "map_flatten", - group: "pedantic", - desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", + name: "needless_borrow", + group: "nursery", + desc: "taking a reference that is going to be automatically dereferenced", deprecation: None, - module: "methods", + module: "needless_borrow", }, Lint { - name: "filter_map", - group: "pedantic", - desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", + name: "needless_borrowed_reference", + group: "complexity", + desc: "taking a needless borrowed reference", deprecation: None, - module: "methods", + module: "needless_borrowed_ref", }, Lint { - name: "filter_map_next", - group: "pedantic", - desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", + name: "needless_collect", + group: "perf", + desc: "collecting an iterator when collect is not needed", deprecation: None, - module: "methods", + module: "loops", }, Lint { - name: "find_map", + name: "needless_continue", group: "pedantic", - desc: "using a combination of `find` and `map` can usually be written as a single method call", + desc: "`continue` statements that can be replaced by a rearrangement of code", deprecation: None, - module: "methods", + module: "needless_continue", }, Lint { - name: "search_is_some", + name: "needless_lifetimes", group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", deprecation: None, - module: "methods", + module: "lifetimes", }, Lint { - name: "chars_next_cmp", - group: "complexity", - desc: "using `.chars().next()` to check if a string starts with a char", + name: "needless_pass_by_value", + group: "pedantic", + desc: "functions taking arguments by value, but not consuming them in its body", deprecation: None, - module: "methods", + module: "needless_pass_by_value", }, Lint { - name: "or_fun_call", - group: "perf", - desc: "using any `*or` method with a function call, which suggests `*or_else`", + name: "needless_range_loop", + group: "style", + desc: "for-looping over a range of indices where an iterator over items would do", deprecation: None, - module: "methods", + module: "loops", }, Lint { - name: "expect_fun_call", - group: "perf", - desc: "using any `expect` method with a function call", + name: "needless_return", + group: "style", + desc: "using a return statement like `return expr;` where an expression would suffice", deprecation: None, - module: "methods", + module: "returns", }, Lint { - name: "clone_on_copy", + name: "needless_update", group: "complexity", - desc: "using `clone` on a `Copy` type", + desc: "using `Foo { ..base }` when there are no missing fields", deprecation: None, - module: "methods", + module: "needless_update", }, Lint { - name: "clone_on_ref_ptr", - group: "restriction", - desc: "using \'clone\' on a ref-counted pointer", + name: "neg_cmp_op_on_partial_ord", + group: "complexity", + desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", deprecation: None, - module: "methods", + module: "neg_cmp_op_on_partial_ord", }, Lint { - name: "clone_double_ref", + name: "neg_multiply", + group: "style", + desc: "multiplying integers with -1", + deprecation: None, + module: "neg_multiply", + }, + Lint { + name: "never_loop", group: "correctness", - desc: "using `clone` on `&&T`", + desc: "any loop that will always `break` or `return`", deprecation: None, - module: "methods", + module: "loops", }, Lint { name: "new_ret_no_self", @@ -1376,256 +1244,242 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "methods", }, Lint { - name: "single_char_pattern", - group: "perf", - desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", + name: "new_without_default", + group: "style", + desc: "`fn new() -> Self` method without `Default` implementation", deprecation: None, - module: "methods", + module: "new_without_default", }, Lint { - name: "temporary_cstring_as_ptr", - group: "correctness", - desc: "getting the inner pointer of a temporary `CString`", + name: "no_effect", + group: "complexity", + desc: "statements with no effect", deprecation: None, - module: "methods", + module: "no_effect", }, Lint { - name: "iter_nth", - group: "perf", - desc: "using `.iter().nth()` on a standard library type with O(1) element access", + name: "non_ascii_literal", + group: "pedantic", + desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", deprecation: None, - module: "methods", + module: "unicode", }, Lint { - name: "iter_skip_next", - group: "style", - desc: "using `.skip(x).next()` on an iterator", + name: "nonminimal_bool", + group: "complexity", + desc: "boolean expressions that can be written more concisely", deprecation: None, - module: "methods", + module: "booleans", }, Lint { - name: "get_unwrap", - group: "restriction", - desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", + name: "nonsensical_open_options", + group: "correctness", + desc: "nonsensical combination of options for opening a file", deprecation: None, - module: "methods", + module: "open_options", }, Lint { - name: "string_extend_chars", - group: "style", - desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", + name: "not_unsafe_ptr_arg_deref", + group: "correctness", + desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", deprecation: None, - module: "methods", + module: "functions", }, Lint { - name: "iter_cloned_collect", + name: "ok_expect", group: "style", - desc: "using `.cloned().collect()` on slice to create a `Vec`", + desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", deprecation: None, module: "methods", }, Lint { - name: "chars_last_cmp", + name: "op_ref", group: "style", - desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", - deprecation: None, - module: "methods", - }, - Lint { - name: "useless_asref", - group: "complexity", - desc: "using `as_ref` where the types before and after the call are the same", + desc: "taking a reference to satisfy the type constraints on `==`", deprecation: None, - module: "methods", + module: "eq_op", }, Lint { - name: "unnecessary_fold", + name: "option_map_or_none", group: "style", - desc: "using `fold` when a more succinct alternative exists", + desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", deprecation: None, module: "methods", }, Lint { - name: "unnecessary_filter_map", + name: "option_map_unit_fn", group: "complexity", - desc: "using `filter_map` when a more succinct alternative exists", + desc: "using `option.map(f)`, where f is a function or closure that returns ()", deprecation: None, - module: "methods", + module: "map_unit_fn", }, Lint { - name: "into_iter_on_array", - group: "correctness", - desc: "using `.into_iter()` on an array", + name: "option_map_unwrap_or", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", deprecation: None, module: "methods", }, Lint { - name: "into_iter_on_ref", - group: "style", - desc: "using `.into_iter()` on a reference", + name: "option_map_unwrap_or_else", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", deprecation: None, module: "methods", }, Lint { - name: "needless_return", - group: "style", - desc: "using a return statement like `return expr;` where an expression would suffice", - deprecation: None, - module: "returns", - }, - Lint { - name: "let_and_return", - group: "style", - desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", + name: "option_option", + group: "complexity", + desc: "usage of `Option<Option<T>>`", deprecation: None, - module: "returns", + module: "types", }, Lint { - name: "unused_unit", - group: "style", - desc: "needless unit expression", + name: "option_unwrap_used", + group: "restriction", + desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", deprecation: None, - module: "returns", + module: "methods", }, Lint { - name: "copy_iterator", - group: "pedantic", - desc: "implementing `Iterator` on a `Copy` type", + name: "or_fun_call", + group: "perf", + desc: "using any `*or` method with a function call, which suggests `*or_else`", deprecation: None, - module: "copy_iterator", + module: "methods", }, Lint { - name: "ifs_same_cond", + name: "out_of_bounds_indexing", group: "correctness", - desc: "consecutive `ifs` with the same condition", + desc: "out of bounds constant indexing", deprecation: None, - module: "copies", + module: "indexing_slicing", }, Lint { - name: "if_same_then_else", - group: "correctness", - desc: "if with the same *then* and *else* blocks", + name: "overflow_check_conditional", + group: "complexity", + desc: "overflow checks inspired by C which are likely to panic", deprecation: None, - module: "copies", + module: "overflow_check_conditional", }, Lint { - name: "match_same_arms", - group: "pedantic", - desc: "`match` with identical arm bodies", + name: "panic_params", + group: "style", + desc: "missing parameters in `panic!` calls", deprecation: None, - module: "copies", + module: "panic_unimplemented", }, Lint { - name: "checked_conversions", - group: "pedantic", - desc: "`try_from` could replace manual bounds checking when casting", + name: "panicking_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that will always fail", deprecation: None, - module: "checked_conversions", + module: "unwrap", }, Lint { - name: "eval_order_dependence", + name: "partialeq_ne_impl", group: "complexity", - desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", + desc: "re-implementing `PartialEq::ne`", deprecation: None, - module: "eval_order_dependence", + module: "partialeq_ne_impl", }, Lint { - name: "diverging_sub_expression", - group: "complexity", - desc: "whether an expression contains a diverging sub expression", + name: "path_buf_push_overwrite", + group: "nursery", + desc: "calling `push` with file system root on `PathBuf` can overwrite it", deprecation: None, - module: "eval_order_dependence", + module: "path_buf_push_overwrite", }, Lint { - name: "map_clone", - group: "style", - desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", + name: "possible_missing_comma", + group: "correctness", + desc: "possible missing comma in array", deprecation: None, - module: "map_clone", + module: "formatting", }, Lint { - name: "ptr_offset_with_cast", + name: "precedence", group: "complexity", - desc: "unneeded pointer offset cast", + desc: "operations where precedence may be unclear", deprecation: None, - module: "ptr_offset_with_cast", + module: "precedence", }, Lint { - name: "infinite_iter", - group: "correctness", - desc: "infinite iteration", + name: "print_literal", + group: "style", + desc: "printing a literal with a format string", deprecation: None, - module: "infinite_iter", + module: "write", }, Lint { - name: "maybe_infinite_iter", - group: "pedantic", - desc: "possible infinite iteration", + name: "print_stdout", + group: "restriction", + desc: "printing on stdout", deprecation: None, - module: "infinite_iter", + module: "write", }, Lint { - name: "default_trait_access", - group: "pedantic", - desc: "checks for literal calls to Default::default()", + name: "print_with_newline", + group: "style", + desc: "using `print!()` with a format string that ends in a single newline", deprecation: None, - module: "default_trait_access", + module: "write", }, Lint { - name: "double_parens", - group: "complexity", - desc: "Warn on unnecessary double parentheses", + name: "println_empty_string", + group: "style", + desc: "using `println!(\"\")` with an empty string", deprecation: None, - module: "double_parens", + module: "write", }, Lint { - name: "multiple_crate_versions", - group: "cargo", - desc: "multiple versions of the same crate being used", + name: "ptr_arg", + group: "style", + desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", deprecation: None, - module: "multiple_crate_versions", + module: "ptr", }, Lint { - name: "suspicious_arithmetic_impl", - group: "correctness", - desc: "suspicious use of operators in impl of arithmetic trait", + name: "ptr_offset_with_cast", + group: "complexity", + desc: "unneeded pointer offset cast", deprecation: None, - module: "suspicious_trait_impl", + module: "ptr_offset_with_cast", }, Lint { - name: "suspicious_op_assign_impl", - group: "correctness", - desc: "suspicious use of operators in impl of OpAssign trait", + name: "pub_enum_variant_names", + group: "pedantic", + desc: "enums where all variants share a prefix/postfix", deprecation: None, - module: "suspicious_trait_impl", + module: "enum_variants", }, Lint { - name: "mem_discriminant_non_enum", - group: "correctness", - desc: "calling mem::descriminant on non-enum type", + name: "question_mark", + group: "style", + desc: "checks for expressions that could be replaced by the question mark operator", deprecation: None, - module: "mem_discriminant", + module: "question_mark", }, Lint { - name: "path_buf_push_overwrite", - group: "nursery", - desc: "calling `push` with file system root on `PathBuf` can overwrite it", + name: "range_minus_one", + group: "complexity", + desc: "`x..=(y-1)` reads better as `x..y`", deprecation: None, - module: "path_buf_push_overwrite", + module: "ranges", }, Lint { - name: "get_last_with_len", + name: "range_plus_one", group: "complexity", - desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", + desc: "`x..(y+1)` reads better as `x..=y`", deprecation: None, - module: "get_last_with_len", + module: "ranges", }, Lint { - name: "redundant_field_names", - group: "style", - desc: "checks for fields in struct literals where shorthands could be used", + name: "range_zip_with_len", + group: "complexity", + desc: "zipping iterator with a range when `enumerate()` would do", deprecation: None, - module: "redundant_field_names", + module: "ranges", }, Lint { name: "redundant_clone", @@ -1635,179 +1489,179 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "redundant_clone", }, Lint { - name: "ptr_arg", + name: "redundant_closure", group: "style", - desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", + desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", deprecation: None, - module: "ptr", + module: "eta_reduction", }, Lint { - name: "cmp_null", - group: "style", - desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", + name: "redundant_closure_call", + group: "complexity", + desc: "throwaway closures called in the expression they are defined", deprecation: None, - module: "ptr", + module: "misc_early", }, Lint { - name: "mut_from_ref", - group: "correctness", - desc: "fns that create mutable refs from immutable ref args", + name: "redundant_closure_for_method_calls", + group: "pedantic", + desc: "redundant closures for method calls", deprecation: None, - module: "ptr", + module: "eta_reduction", }, Lint { - name: "empty_enum", - group: "pedantic", - desc: "enum with no variants", + name: "redundant_field_names", + group: "style", + desc: "checks for fields in struct literals where shorthands could be used", deprecation: None, - module: "empty_enum", + module: "redundant_field_names", }, Lint { - name: "unneeded_field_pattern", + name: "redundant_pattern", group: "style", - desc: "struct fields bound to a wildcard instead of using `..`", + desc: "using `name @ _` in a pattern", deprecation: None, - module: "misc_early", + module: "misc", }, Lint { - name: "duplicate_underscore_argument", + name: "redundant_pattern_matching", group: "style", - desc: "function arguments having names which only differ by an underscore", + desc: "use the proper utility function avoiding an `if let`", deprecation: None, - module: "misc_early", + module: "redundant_pattern_matching", }, Lint { - name: "redundant_closure_call", + name: "ref_in_deref", group: "complexity", - desc: "throwaway closures called in the expression they are defined", + desc: "Use of reference in auto dereference expression.", deprecation: None, - module: "misc_early", + module: "reference", }, Lint { - name: "double_neg", + name: "regex_macro", group: "style", - desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", + desc: "use of `regex!(_)` instead of `Regex::new(_)`", deprecation: None, - module: "misc_early", + module: "regex", }, Lint { - name: "mixed_case_hex_literals", - group: "style", - desc: "hex literals whose letter digits are not consistently upper- or lowercased", + name: "replace_consts", + group: "pedantic", + desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", deprecation: None, - module: "misc_early", + module: "replace_consts", }, Lint { - name: "unseparated_literal_suffix", - group: "pedantic", - desc: "literals whose suffix is not separated by an underscore", + name: "result_map_unit_fn", + group: "complexity", + desc: "using `result.map(f)`, where f is a function or closure that returns ()", deprecation: None, - module: "misc_early", + module: "map_unit_fn", }, Lint { - name: "zero_prefixed_literal", - group: "complexity", - desc: "integer literals starting with `0`", + name: "result_map_unwrap_or_else", + group: "pedantic", + desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", deprecation: None, - module: "misc_early", + module: "methods", }, Lint { - name: "builtin_type_shadow", - group: "style", - desc: "shadowing a builtin type", + name: "result_unwrap_used", + group: "restriction", + desc: "using `Result.unwrap()`, which might be better handled", deprecation: None, - module: "misc_early", + module: "methods", }, Lint { - name: "useless_vec", - group: "perf", - desc: "useless `vec!`", + name: "reverse_range_loop", + group: "correctness", + desc: "iteration over an empty range, such as `10..0` or `5..5`", deprecation: None, - module: "vec", + module: "loops", }, Lint { - name: "explicit_write", + name: "search_is_some", group: "complexity", - desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", + desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", deprecation: None, - module: "explicit_write", + module: "methods", }, Lint { - name: "toplevel_ref_arg", - group: "style", - desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", + name: "serde_api_misuse", + group: "correctness", + desc: "various things that will negatively affect your serde experience", deprecation: None, - module: "misc", + module: "serde_api", }, Lint { - name: "cmp_nan", - group: "correctness", - desc: "comparisons to NAN, which will always return false, probably not intended", + name: "shadow_reuse", + group: "restriction", + desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", deprecation: None, - module: "misc", + module: "shadow", }, Lint { - name: "float_cmp", - group: "correctness", - desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", + name: "shadow_same", + group: "restriction", + desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", deprecation: None, - module: "misc", + module: "shadow", }, Lint { - name: "cmp_owned", - group: "perf", - desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", + name: "shadow_unrelated", + group: "pedantic", + desc: "rebinding a name without even using the original value", deprecation: None, - module: "misc", + module: "shadow", }, Lint { - name: "modulo_one", - group: "correctness", - desc: "taking a number modulo 1, which always returns 0", + name: "short_circuit_statement", + group: "complexity", + desc: "using a short circuit boolean condition as a statement", deprecation: None, module: "misc", }, Lint { - name: "redundant_pattern", + name: "should_implement_trait", group: "style", - desc: "using `name @ _` in a pattern", + desc: "defining a method that should be implementing a std trait", deprecation: None, - module: "misc", + module: "methods", }, Lint { - name: "used_underscore_binding", + name: "similar_names", group: "pedantic", - desc: "using a binding which is prefixed with an underscore", + desc: "similarly named items and bindings", deprecation: None, - module: "misc", + module: "non_expressive_names", }, Lint { - name: "short_circuit_statement", - group: "complexity", - desc: "using a short circuit boolean condition as a statement", + name: "single_char_pattern", + group: "perf", + desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", deprecation: None, - module: "misc", + module: "methods", }, Lint { - name: "zero_ptr", + name: "single_match", group: "style", - desc: "using 0 as *{const, mut} T", + desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", deprecation: None, - module: "misc", + module: "matches", }, Lint { - name: "float_cmp_const", - group: "restriction", - desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", + name: "single_match_else", + group: "pedantic", + desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", deprecation: None, - module: "misc", + module: "matches", }, Lint { - name: "string_add_assign", - group: "pedantic", - desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", + name: "slow_vector_initialization", + group: "perf", + desc: "slow vector initialization", deprecation: None, - module: "strings", + module: "slow_vector_initialization", }, Lint { name: "string_add", @@ -1817,88 +1671,88 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "strings", }, Lint { - name: "string_lit_as_bytes", - group: "style", - desc: "calling `as_bytes` on a string literal instead of using a byte string literal", + name: "string_add_assign", + group: "pedantic", + desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", deprecation: None, module: "strings", }, Lint { - name: "trivially_copy_pass_by_ref", - group: "perf", - desc: "functions taking small copyable arguments by reference", + name: "string_extend_chars", + group: "style", + desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", deprecation: None, - module: "trivially_copy_pass_by_ref", + module: "methods", }, Lint { - name: "double_comparisons", - group: "complexity", - desc: "unnecessary double comparisons that can be simplified", + name: "string_lit_as_bytes", + group: "style", + desc: "calling `as_bytes` on a string literal instead of using a byte string literal", deprecation: None, - module: "double_comparison", + module: "strings", }, Lint { - name: "approx_constant", + name: "suspicious_arithmetic_impl", group: "correctness", - desc: "the approximate of a known float constant (in `std::fXX::consts`)", + desc: "suspicious use of operators in impl of arithmetic trait", deprecation: None, - module: "approx_const", + module: "suspicious_trait_impl", }, Lint { - name: "assign_op_pattern", + name: "suspicious_assignment_formatting", group: "style", - desc: "assigning the result of an operation on a variable to that same variable", + desc: "suspicious formatting of `*=`, `-=` or `!=`", deprecation: None, - module: "assign_ops", + module: "formatting", }, Lint { - name: "misrefactored_assign_op", - group: "complexity", - desc: "having a variable on both sides of an assign op", + name: "suspicious_else_formatting", + group: "style", + desc: "suspicious formatting of `else`", deprecation: None, - module: "assign_ops", + module: "formatting", }, Lint { - name: "erasing_op", + name: "suspicious_op_assign_impl", group: "correctness", - desc: "using erasing operations, e.g., `x * 0` or `y & 0`", + desc: "suspicious use of operators in impl of OpAssign trait", deprecation: None, - module: "erasing_op", + module: "suspicious_trait_impl", }, Lint { - name: "wrong_transmute", - group: "correctness", - desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", + name: "temporary_assignment", + group: "complexity", + desc: "assignments to temporaries", deprecation: None, - module: "transmute", + module: "temporary_assignment", }, Lint { - name: "useless_transmute", - group: "complexity", - desc: "transmutes that have the same to and from types or could be a cast/coercion", + name: "temporary_cstring_as_ptr", + group: "correctness", + desc: "getting the inner pointer of a temporary `CString`", deprecation: None, - module: "transmute", + module: "methods", }, Lint { - name: "crosspointer_transmute", + name: "too_many_arguments", group: "complexity", - desc: "transmutes that have to or from types that are a pointer to the other", + desc: "functions with too many arguments", deprecation: None, - module: "transmute", + module: "functions", }, Lint { - name: "transmute_ptr_to_ref", - group: "complexity", - desc: "transmutes from a pointer to a reference type", + name: "too_many_lines", + group: "pedantic", + desc: "functions with too many lines", deprecation: None, - module: "transmute", + module: "functions", }, Lint { - name: "transmute_int_to_char", - group: "complexity", - desc: "transmutes from an integer to a `char`", + name: "toplevel_ref_arg", + group: "style", + desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", deprecation: None, - module: "transmute", + module: "misc", }, Lint { name: "transmute_bytes_to_str", @@ -1914,6 +1768,13 @@ pub const ALL_LINTS: [Lint; 320] = [ deprecation: None, module: "transmute", }, + Lint { + name: "transmute_int_to_char", + group: "complexity", + desc: "transmutes from an integer to a `char`", + deprecation: None, + module: "transmute", + }, Lint { name: "transmute_int_to_float", group: "complexity", @@ -1929,39 +1790,39 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "transmute", }, Lint { - name: "needless_borrow", - group: "nursery", - desc: "taking a reference that is going to be automatically dereferenced", + name: "transmute_ptr_to_ref", + group: "complexity", + desc: "transmutes from a pointer to a reference type", deprecation: None, - module: "needless_borrow", + module: "transmute", }, Lint { - name: "if_not_else", - group: "pedantic", - desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", + name: "transmuting_null", + group: "correctness", + desc: "transmutes from a null pointer to a reference, which is undefined behavior", deprecation: None, - module: "if_not_else", + module: "transmuting_null", }, Lint { - name: "naive_bytecount", - group: "perf", - desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values", + name: "trivial_regex", + group: "style", + desc: "trivial regular expressions", deprecation: None, - module: "bytecount", + module: "regex", }, Lint { - name: "zero_width_space", - group: "correctness", - desc: "using a zero-width space in a string literal, which is confusing", + name: "trivially_copy_pass_by_ref", + group: "perf", + desc: "functions taking small copyable arguments by reference", deprecation: None, - module: "unicode", + module: "trivially_copy_pass_by_ref", }, Lint { - name: "non_ascii_literal", - group: "pedantic", - desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", + name: "type_complexity", + group: "complexity", + desc: "usage of very complex types that might be better factored into `type` definitions", deprecation: None, - module: "unicode", + module: "types", }, Lint { name: "unicode_not_nfc", @@ -1971,304 +1832,311 @@ pub const ALL_LINTS: [Lint; 320] = [ module: "unicode", }, Lint { - name: "len_zero", - group: "style", - desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", + name: "unimplemented", + group: "restriction", + desc: "`unimplemented!` should not be present in production code", deprecation: None, - module: "len_zero", + module: "panic_unimplemented", }, Lint { - name: "len_without_is_empty", - group: "style", - desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", + name: "unit_arg", + group: "complexity", + desc: "passing unit to a function", deprecation: None, - module: "len_zero", + module: "types", }, Lint { - name: "useless_let_if_seq", + name: "unit_cmp", + group: "correctness", + desc: "comparing unit values", + deprecation: None, + module: "types", + }, + Lint { + name: "unknown_clippy_lints", group: "style", - desc: "unidiomatic `let mut` declaration followed by initialization in `if`", + desc: "unknown_lints for scoped Clippy lints", deprecation: None, - module: "let_if_seq", + module: "attrs", }, Lint { - name: "large_enum_variant", - group: "perf", - desc: "large size difference between variants on an enum", + name: "unnecessary_cast", + group: "complexity", + desc: "cast to the same type, e.g., `x as i32` where `x: i32`", deprecation: None, - module: "large_enum_variant", + module: "types", }, Lint { - name: "new_without_default", + name: "unnecessary_filter_map", + group: "complexity", + desc: "using `filter_map` when a more succinct alternative exists", + deprecation: None, + module: "methods", + }, + Lint { + name: "unnecessary_fold", group: "style", - desc: "`fn new() -> Self` method without `Default` implementation", + desc: "using `fold` when a more succinct alternative exists", deprecation: None, - module: "new_without_default", + module: "methods", }, Lint { - name: "box_vec", - group: "perf", - desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap", + name: "unnecessary_mut_passed", + group: "style", + desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", deprecation: None, - module: "types", + module: "mut_reference", }, Lint { - name: "vec_box", + name: "unnecessary_operation", group: "complexity", - desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap", + desc: "outer expressions with no effect", + deprecation: None, + module: "no_effect", + }, + Lint { + name: "unnecessary_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that cannot fail", + deprecation: None, + module: "unwrap", + }, + Lint { + name: "unneeded_field_pattern", + group: "style", + desc: "struct fields bound to a wildcard instead of using `..`", deprecation: None, - module: "types", + module: "misc_early", }, Lint { - name: "option_option", - group: "complexity", - desc: "usage of `Option<Option<T>>`", + name: "unreadable_literal", + group: "style", + desc: "long integer literal without underscores", deprecation: None, - module: "types", + module: "literal_representation", }, Lint { - name: "linkedlist", - group: "pedantic", - desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", + name: "unsafe_removed_from_name", + group: "style", + desc: "`unsafe` removed from API names on import", deprecation: None, - module: "types", + module: "unsafe_removed_from_name", }, Lint { - name: "borrowed_box", - group: "complexity", - desc: "a borrow of a boxed type", + name: "unseparated_literal_suffix", + group: "pedantic", + desc: "literals whose suffix is not separated by an underscore", deprecation: None, - module: "types", + module: "misc_early", }, Lint { - name: "let_unit_value", - group: "style", - desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", + name: "unused_collect", + group: "perf", + desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", deprecation: None, - module: "types", + module: "loops", }, Lint { - name: "unit_cmp", + name: "unused_io_amount", group: "correctness", - desc: "comparing unit values", + desc: "unused written/read amount", deprecation: None, - module: "types", + module: "unused_io_amount", }, Lint { - name: "unit_arg", + name: "unused_label", group: "complexity", - desc: "passing unit to a function", + desc: "unused labels", deprecation: None, - module: "types", + module: "unused_label", }, Lint { - name: "cast_precision_loss", - group: "pedantic", - desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", + name: "unused_unit", + group: "style", + desc: "needless unit expression", deprecation: None, - module: "types", + module: "returns", }, Lint { - name: "cast_sign_loss", - group: "pedantic", - desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", + name: "use_debug", + group: "restriction", + desc: "use of `Debug`-based formatting", deprecation: None, - module: "types", + module: "write", }, Lint { - name: "cast_possible_truncation", + name: "use_self", group: "pedantic", - desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", + desc: "Unnecessary structure name repetition whereas `Self` is applicable", deprecation: None, - module: "types", + module: "use_self", }, Lint { - name: "cast_possible_wrap", + name: "used_underscore_binding", group: "pedantic", - desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_lossless", - group: "complexity", - desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", + desc: "using a binding which is prefixed with an underscore", deprecation: None, - module: "types", + module: "misc", }, Lint { - name: "unnecessary_cast", + name: "useless_asref", group: "complexity", - desc: "cast to the same type, e.g., `x as i32` where `x: i32`", + desc: "using `as_ref` where the types before and after the call are the same", deprecation: None, - module: "types", + module: "methods", }, Lint { - name: "cast_ptr_alignment", + name: "useless_attribute", group: "correctness", - desc: "cast from a pointer to a more-strictly-aligned pointer", + desc: "use of lint attributes on `extern crate` items", deprecation: None, - module: "types", + module: "attrs", }, Lint { - name: "fn_to_numeric_cast", - group: "style", - desc: "casting a function pointer to a numeric type other than usize", + name: "useless_format", + group: "complexity", + desc: "useless use of `format!`", deprecation: None, - module: "types", + module: "format", }, Lint { - name: "fn_to_numeric_cast_with_truncation", + name: "useless_let_if_seq", group: "style", - desc: "casting a function pointer to a numeric type not wide enough to store the address", - deprecation: None, - module: "types", - }, - Lint { - name: "type_complexity", - group: "complexity", - desc: "usage of very complex types that might be better factored into `type` definitions", + desc: "unidiomatic `let mut` declaration followed by initialization in `if`", deprecation: None, - module: "types", + module: "let_if_seq", }, Lint { - name: "char_lit_as_u8", + name: "useless_transmute", group: "complexity", - desc: "casting a character literal to u8", + desc: "transmutes that have the same to and from types or could be a cast/coercion", deprecation: None, - module: "types", + module: "transmute", }, Lint { - name: "absurd_extreme_comparisons", - group: "correctness", - desc: "a comparison with a maximum or minimum value that is always true or false", + name: "useless_vec", + group: "perf", + desc: "useless `vec!`", deprecation: None, - module: "types", + module: "vec", }, Lint { - name: "invalid_upcast_comparisons", - group: "pedantic", - desc: "a comparison involving an upcast which is always true or false", + name: "vec_box", + group: "complexity", + desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap", deprecation: None, module: "types", }, Lint { - name: "implicit_hasher", + name: "verbose_bit_mask", group: "style", - desc: "missing generalization over different hashers", + desc: "expressions where a bit mask is less readable than the corresponding method call", deprecation: None, - module: "types", + module: "bit_mask", }, Lint { - name: "cast_ref_to_mut", + name: "while_immutable_condition", group: "correctness", - desc: "a cast of reference to a mutable pointer", + desc: "variables used within while expression are not mutated in the body", deprecation: None, - module: "types", + module: "loops", }, Lint { - name: "needless_lifetimes", + name: "while_let_loop", group: "complexity", - desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", + desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", deprecation: None, - module: "lifetimes", + module: "loops", }, Lint { - name: "extra_unused_lifetimes", - group: "complexity", - desc: "unused lifetimes in function definitions", + name: "while_let_on_iterator", + group: "style", + desc: "using a while-let loop instead of a for loop on an iterator", deprecation: None, - module: "lifetimes", + module: "loops", }, Lint { - name: "temporary_assignment", - group: "complexity", - desc: "assignments to temporaries", + name: "wildcard_dependencies", + group: "cargo", + desc: "wildcard dependencies being used", deprecation: None, - module: "temporary_assignment", + module: "wildcard_dependencies", }, Lint { - name: "slow_vector_initialization", - group: "perf", - desc: "slow vector initialization", + name: "wildcard_enum_match_arm", + group: "restriction", + desc: "a wildcard enum match arm using `_`", deprecation: None, - module: "slow_vector_initialization", + module: "matches", }, Lint { - name: "unreadable_literal", + name: "write_literal", group: "style", - desc: "long integer literal without underscores", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "mistyped_literal_suffixes", - group: "correctness", - desc: "mistyped literal suffix", + desc: "writing a literal with a format string", deprecation: None, - module: "literal_representation", + module: "write", }, Lint { - name: "inconsistent_digit_grouping", + name: "write_with_newline", group: "style", - desc: "integer literals with digits grouped inconsistently", + desc: "using `write!()` with a format string that ends in a single newline", deprecation: None, - module: "literal_representation", + module: "write", }, Lint { - name: "large_digit_groups", - group: "pedantic", - desc: "grouping digits into groups that are too large", + name: "writeln_empty_string", + group: "style", + desc: "using `writeln!(buf, \"\")` with an empty string", deprecation: None, - module: "literal_representation", + module: "write", }, Lint { - name: "decimal_literal_representation", + name: "wrong_pub_self_convention", group: "restriction", - desc: "using decimal representation when hexadecimal would be better", + desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", deprecation: None, - module: "literal_representation", + module: "methods", }, Lint { - name: "if_let_some_result", + name: "wrong_self_convention", group: "style", - desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", + desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", deprecation: None, - module: "ok_if_let", + module: "methods", }, Lint { - name: "panic_params", - group: "style", - desc: "missing parameters in `panic!` calls", + name: "wrong_transmute", + group: "correctness", + desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", deprecation: None, - module: "panic_unimplemented", + module: "transmute", }, Lint { - name: "unimplemented", - group: "restriction", - desc: "`unimplemented!` should not be present in production code", + name: "zero_divided_by_zero", + group: "complexity", + desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", deprecation: None, - module: "panic_unimplemented", + module: "zero_div_zero", }, Lint { - name: "invalid_ref", - group: "correctness", - desc: "creation of invalid reference", + name: "zero_prefixed_literal", + group: "complexity", + desc: "integer literals starting with `0`", deprecation: None, - module: "invalid_ref", + module: "misc_early", }, Lint { - name: "mem_replace_option_with_none", + name: "zero_ptr", group: "style", - desc: "replacing an `Option` with `None` instead of `take()`", + desc: "using 0 as *{const, mut} T", deprecation: None, - module: "mem_replace", + module: "misc", }, Lint { - name: "const_static_lifetime", - group: "style", - desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", + name: "zero_width_space", + group: "correctness", + desc: "using a zero-width space in a string literal, which is confusing", deprecation: None, - module: "const_static_lifetime", + module: "unicode", }, -]; \ No newline at end of file +]; -- cgit 1.4.1-3-g733a5 From 5abcff2be5a7c698376c1495fc267f07d7f25e1c Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Sat, 8 Jun 2019 11:47:24 -0700 Subject: move Lint static def into its own module --- clippy_dev/src/main.rs | 13 +- src/lintlist.rs | 2142 ------------------------------------------------ src/lintlist/lint.rs | 9 + src/lintlist/mod.rs | 2135 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2147 insertions(+), 2152 deletions(-) delete mode 100644 src/lintlist.rs create mode 100644 src/lintlist/lint.rs create mode 100644 src/lintlist/mod.rs (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 4c50cc3b81e..e33b052cf28 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -95,20 +95,13 @@ fn update_lints(update_mode: &UpdateMode) { sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); std::fs::write( - "../src/lintlist.rs", + "../src/lintlist/mod.rs", &format!( "\ //! This file is managed by util/dev update_lints. Do not edit. -/// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] -pub struct Lint {{ - pub name: &'static str, - pub group: &'static str, - pub desc: &'static str, - pub deprecation: Option<&'static str>, - pub module: &'static str, -}} +mod lint; +use lint::Lint; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", sorted_usable_lints.len(), diff --git a/src/lintlist.rs b/src/lintlist.rs deleted file mode 100644 index 113f993dd8a..00000000000 --- a/src/lintlist.rs +++ /dev/null @@ -1,2142 +0,0 @@ -//! This file is managed by util/dev update_lints. Do not edit. - -/// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] -pub struct Lint { - pub name: &'static str, - pub group: &'static str, - pub desc: &'static str, - pub deprecation: Option<&'static str>, - pub module: &'static str, -} - -pub const ALL_LINTS: [Lint; 304] = [ - Lint { - name: "absurd_extreme_comparisons", - group: "correctness", - desc: "a comparison with a maximum or minimum value that is always true or false", - deprecation: None, - module: "types", - }, - Lint { - name: "almost_swapped", - group: "correctness", - desc: "`foo = bar; bar = foo` sequence", - deprecation: None, - module: "swap", - }, - Lint { - name: "approx_constant", - group: "correctness", - desc: "the approximate of a known float constant (in `std::fXX::consts`)", - deprecation: None, - module: "approx_const", - }, - Lint { - name: "assertions_on_constants", - group: "style", - desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", - deprecation: None, - module: "assertions_on_constants", - }, - Lint { - name: "assign_op_pattern", - group: "style", - desc: "assigning the result of an operation on a variable to that same variable", - deprecation: None, - module: "assign_ops", - }, - Lint { - name: "bad_bit_mask", - group: "correctness", - desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "blacklisted_name", - group: "style", - desc: "usage of a blacklisted/placeholder name", - deprecation: None, - module: "blacklisted_name", - }, - Lint { - name: "block_in_if_condition_expr", - group: "style", - desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", - deprecation: None, - module: "block_in_if_condition", - }, - Lint { - name: "block_in_if_condition_stmt", - group: "style", - desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", - deprecation: None, - module: "block_in_if_condition", - }, - Lint { - name: "bool_comparison", - group: "complexity", - desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", - deprecation: None, - module: "needless_bool", - }, - Lint { - name: "borrow_interior_mutable_const", - group: "correctness", - desc: "referencing const with interior mutability", - deprecation: None, - module: "non_copy_const", - }, - Lint { - name: "borrowed_box", - group: "complexity", - desc: "a borrow of a boxed type", - deprecation: None, - module: "types", - }, - Lint { - name: "box_vec", - group: "perf", - desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap", - deprecation: None, - module: "types", - }, - Lint { - name: "boxed_local", - group: "perf", - desc: "using `Box<T>` where unnecessary", - deprecation: None, - module: "escape", - }, - Lint { - name: "builtin_type_shadow", - group: "style", - desc: "shadowing a builtin type", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "cargo_common_metadata", - group: "cargo", - desc: "common metadata is defined in `Cargo.toml`", - deprecation: None, - module: "cargo_common_metadata", - }, - Lint { - name: "cast_lossless", - group: "complexity", - desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_possible_truncation", - group: "pedantic", - desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_possible_wrap", - group: "pedantic", - desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_precision_loss", - group: "pedantic", - desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_ptr_alignment", - group: "correctness", - desc: "cast from a pointer to a more-strictly-aligned pointer", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_ref_to_mut", - group: "correctness", - desc: "a cast of reference to a mutable pointer", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_sign_loss", - group: "pedantic", - desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", - deprecation: None, - module: "types", - }, - Lint { - name: "char_lit_as_u8", - group: "complexity", - desc: "casting a character literal to u8", - deprecation: None, - module: "types", - }, - Lint { - name: "chars_last_cmp", - group: "style", - desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", - deprecation: None, - module: "methods", - }, - Lint { - name: "chars_next_cmp", - group: "complexity", - desc: "using `.chars().next()` to check if a string starts with a char", - deprecation: None, - module: "methods", - }, - Lint { - name: "checked_conversions", - group: "pedantic", - desc: "`try_from` could replace manual bounds checking when casting", - deprecation: None, - module: "checked_conversions", - }, - Lint { - name: "clone_double_ref", - group: "correctness", - desc: "using `clone` on `&&T`", - deprecation: None, - module: "methods", - }, - Lint { - name: "clone_on_copy", - group: "complexity", - desc: "using `clone` on a `Copy` type", - deprecation: None, - module: "methods", - }, - Lint { - name: "clone_on_ref_ptr", - group: "restriction", - desc: "using \'clone\' on a ref-counted pointer", - deprecation: None, - module: "methods", - }, - Lint { - name: "cmp_nan", - group: "correctness", - desc: "comparisons to NAN, which will always return false, probably not intended", - deprecation: None, - module: "misc", - }, - Lint { - name: "cmp_null", - group: "style", - desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", - deprecation: None, - module: "ptr", - }, - Lint { - name: "cmp_owned", - group: "perf", - desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", - deprecation: None, - module: "misc", - }, - Lint { - name: "cognitive_complexity", - group: "complexity", - desc: "functions that should be split up into multiple functions", - deprecation: None, - module: "cognitive_complexity", - }, - Lint { - name: "collapsible_if", - group: "style", - desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", - deprecation: None, - module: "collapsible_if", - }, - Lint { - name: "const_static_lifetime", - group: "style", - desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", - deprecation: None, - module: "const_static_lifetime", - }, - Lint { - name: "copy_iterator", - group: "pedantic", - desc: "implementing `Iterator` on a `Copy` type", - deprecation: None, - module: "copy_iterator", - }, - Lint { - name: "crosspointer_transmute", - group: "complexity", - desc: "transmutes that have to or from types that are a pointer to the other", - deprecation: None, - module: "transmute", - }, - Lint { - name: "dbg_macro", - group: "restriction", - desc: "`dbg!` macro is intended as a debugging tool", - deprecation: None, - module: "dbg_macro", - }, - Lint { - name: "decimal_literal_representation", - group: "restriction", - desc: "using decimal representation when hexadecimal would be better", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "declare_interior_mutable_const", - group: "correctness", - desc: "declaring const with interior mutability", - deprecation: None, - module: "non_copy_const", - }, - Lint { - name: "default_trait_access", - group: "pedantic", - desc: "checks for literal calls to Default::default()", - deprecation: None, - module: "default_trait_access", - }, - Lint { - name: "deprecated_cfg_attr", - group: "complexity", - desc: "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`", - deprecation: None, - module: "attrs", - }, - Lint { - name: "deprecated_semver", - group: "correctness", - desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", - deprecation: None, - module: "attrs", - }, - Lint { - name: "deref_addrof", - group: "complexity", - desc: "use of `*&` or `*&mut` in an expression", - deprecation: None, - module: "reference", - }, - Lint { - name: "derive_hash_xor_eq", - group: "correctness", - desc: "deriving `Hash` but implementing `PartialEq` explicitly", - deprecation: None, - module: "derive", - }, - Lint { - name: "diverging_sub_expression", - group: "complexity", - desc: "whether an expression contains a diverging sub expression", - deprecation: None, - module: "eval_order_dependence", - }, - Lint { - name: "doc_markdown", - group: "pedantic", - desc: "presence of `_`, `::` or camel-case outside backticks in documentation", - deprecation: None, - module: "doc", - }, - Lint { - name: "double_comparisons", - group: "complexity", - desc: "unnecessary double comparisons that can be simplified", - deprecation: None, - module: "double_comparison", - }, - Lint { - name: "double_neg", - group: "style", - desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "double_parens", - group: "complexity", - desc: "Warn on unnecessary double parentheses", - deprecation: None, - module: "double_parens", - }, - Lint { - name: "drop_bounds", - group: "correctness", - desc: "Bounds of the form `T: Drop` are useless", - deprecation: None, - module: "drop_bounds", - }, - Lint { - name: "drop_copy", - group: "correctness", - desc: "calls to `std::mem::drop` with a value that implements Copy", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "drop_ref", - group: "correctness", - desc: "calls to `std::mem::drop` with a reference instead of an owned value", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "duplicate_underscore_argument", - group: "style", - desc: "function arguments having names which only differ by an underscore", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "duration_subsec", - group: "complexity", - desc: "checks for calculation of subsecond microseconds or milliseconds", - deprecation: None, - module: "duration_subsec", - }, - Lint { - name: "else_if_without_else", - group: "restriction", - desc: "if expression with an `else if`, but without a final `else` branch", - deprecation: None, - module: "else_if_without_else", - }, - Lint { - name: "empty_enum", - group: "pedantic", - desc: "enum with no variants", - deprecation: None, - module: "empty_enum", - }, - Lint { - name: "empty_line_after_outer_attr", - group: "nursery", - desc: "empty line after outer attribute", - deprecation: None, - module: "attrs", - }, - Lint { - name: "empty_loop", - group: "style", - desc: "empty `loop {}`, which should block or sleep", - deprecation: None, - module: "loops", - }, - Lint { - name: "enum_clike_unportable_variant", - group: "correctness", - desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", - deprecation: None, - module: "enum_clike", - }, - Lint { - name: "enum_glob_use", - group: "pedantic", - desc: "use items that import all variants of an enum", - deprecation: None, - module: "enum_glob_use", - }, - Lint { - name: "enum_variant_names", - group: "style", - desc: "enums where all variants share a prefix/postfix", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "eq_op", - group: "correctness", - desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", - deprecation: None, - module: "eq_op", - }, - Lint { - name: "erasing_op", - group: "correctness", - desc: "using erasing operations, e.g., `x * 0` or `y & 0`", - deprecation: None, - module: "erasing_op", - }, - Lint { - name: "eval_order_dependence", - group: "complexity", - desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", - deprecation: None, - module: "eval_order_dependence", - }, - Lint { - name: "excessive_precision", - group: "style", - desc: "excessive precision for float literal", - deprecation: None, - module: "excessive_precision", - }, - Lint { - name: "expect_fun_call", - group: "perf", - desc: "using any `expect` method with a function call", - deprecation: None, - module: "methods", - }, - Lint { - name: "expl_impl_clone_on_copy", - group: "pedantic", - desc: "implementing `Clone` explicitly on `Copy` types", - deprecation: None, - module: "derive", - }, - Lint { - name: "explicit_counter_loop", - group: "complexity", - desc: "for-looping with an explicit counter when `_.enumerate()` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_into_iter_loop", - group: "pedantic", - desc: "for-looping over `_.into_iter()` when `_` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_iter_loop", - group: "pedantic", - desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_write", - group: "complexity", - desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", - deprecation: None, - module: "explicit_write", - }, - Lint { - name: "extra_unused_lifetimes", - group: "complexity", - desc: "unused lifetimes in function definitions", - deprecation: None, - module: "lifetimes", - }, - Lint { - name: "fallible_impl_from", - group: "nursery", - desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", - deprecation: None, - module: "fallible_impl_from", - }, - Lint { - name: "filter_map", - group: "pedantic", - desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "filter_map_next", - group: "pedantic", - desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "filter_next", - group: "complexity", - desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "find_map", - group: "pedantic", - desc: "using a combination of `find` and `map` can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "float_arithmetic", - group: "restriction", - desc: "any floating-point arithmetic statement", - deprecation: None, - module: "arithmetic", - }, - Lint { - name: "float_cmp", - group: "correctness", - desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", - deprecation: None, - module: "misc", - }, - Lint { - name: "float_cmp_const", - group: "restriction", - desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", - deprecation: None, - module: "misc", - }, - Lint { - name: "fn_to_numeric_cast", - group: "style", - desc: "casting a function pointer to a numeric type other than usize", - deprecation: None, - module: "types", - }, - Lint { - name: "fn_to_numeric_cast_with_truncation", - group: "style", - desc: "casting a function pointer to a numeric type not wide enough to store the address", - deprecation: None, - module: "types", - }, - Lint { - name: "for_kv_map", - group: "style", - desc: "looping on a map using `iter` when `keys` or `values` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "for_loop_over_option", - group: "correctness", - desc: "for-looping over an `Option`, which is more clearly expressed as an `if let`", - deprecation: None, - module: "loops", - }, - Lint { - name: "for_loop_over_result", - group: "correctness", - desc: "for-looping over a `Result`, which is more clearly expressed as an `if let`", - deprecation: None, - module: "loops", - }, - Lint { - name: "forget_copy", - group: "correctness", - desc: "calls to `std::mem::forget` with a value that implements Copy", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "forget_ref", - group: "correctness", - desc: "calls to `std::mem::forget` with a reference instead of an owned value", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "get_last_with_len", - group: "complexity", - desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", - deprecation: None, - module: "get_last_with_len", - }, - Lint { - name: "get_unwrap", - group: "restriction", - desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", - deprecation: None, - module: "methods", - }, - Lint { - name: "identity_conversion", - group: "complexity", - desc: "using always-identical `Into`/`From`/`IntoIter` conversions", - deprecation: None, - module: "identity_conversion", - }, - Lint { - name: "identity_op", - group: "complexity", - desc: "using identity operations, e.g., `x + 0` or `y / 1`", - deprecation: None, - module: "identity_op", - }, - Lint { - name: "if_let_some_result", - group: "style", - desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", - deprecation: None, - module: "ok_if_let", - }, - Lint { - name: "if_not_else", - group: "pedantic", - desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", - deprecation: None, - module: "if_not_else", - }, - Lint { - name: "if_same_then_else", - group: "correctness", - desc: "if with the same *then* and *else* blocks", - deprecation: None, - module: "copies", - }, - Lint { - name: "ifs_same_cond", - group: "correctness", - desc: "consecutive `ifs` with the same condition", - deprecation: None, - module: "copies", - }, - Lint { - name: "implicit_hasher", - group: "style", - desc: "missing generalization over different hashers", - deprecation: None, - module: "types", - }, - Lint { - name: "implicit_return", - group: "restriction", - desc: "use a return statement like `return expr` instead of an expression", - deprecation: None, - module: "implicit_return", - }, - Lint { - name: "inconsistent_digit_grouping", - group: "style", - desc: "integer literals with digits grouped inconsistently", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "indexing_slicing", - group: "restriction", - desc: "indexing/slicing usage", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "ineffective_bit_mask", - group: "correctness", - desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "infallible_destructuring_match", - group: "style", - desc: "a match statement with a single infallible arm instead of a `let`", - deprecation: None, - module: "infallible_destructuring_match", - }, - Lint { - name: "infinite_iter", - group: "correctness", - desc: "infinite iteration", - deprecation: None, - module: "infinite_iter", - }, - Lint { - name: "inline_always", - group: "pedantic", - desc: "use of `#[inline(always)]`", - deprecation: None, - module: "attrs", - }, - Lint { - name: "inline_fn_without_body", - group: "correctness", - desc: "use of `#[inline]` on trait methods without bodies", - deprecation: None, - module: "inline_fn_without_body", - }, - Lint { - name: "int_plus_one", - group: "complexity", - desc: "instead of using x >= y + 1, use x > y", - deprecation: None, - module: "int_plus_one", - }, - Lint { - name: "integer_arithmetic", - group: "restriction", - desc: "any integer arithmetic statement", - deprecation: None, - module: "arithmetic", - }, - Lint { - name: "into_iter_on_array", - group: "correctness", - desc: "using `.into_iter()` on an array", - deprecation: None, - module: "methods", - }, - Lint { - name: "into_iter_on_ref", - group: "style", - desc: "using `.into_iter()` on a reference", - deprecation: None, - module: "methods", - }, - Lint { - name: "invalid_ref", - group: "correctness", - desc: "creation of invalid reference", - deprecation: None, - module: "invalid_ref", - }, - Lint { - name: "invalid_regex", - group: "correctness", - desc: "invalid regular expressions", - deprecation: None, - module: "regex", - }, - Lint { - name: "invalid_upcast_comparisons", - group: "pedantic", - desc: "a comparison involving an upcast which is always true or false", - deprecation: None, - module: "types", - }, - Lint { - name: "items_after_statements", - group: "pedantic", - desc: "blocks where an item comes after a statement", - deprecation: None, - module: "items_after_statements", - }, - Lint { - name: "iter_cloned_collect", - group: "style", - desc: "using `.cloned().collect()` on slice to create a `Vec`", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_next_loop", - group: "correctness", - desc: "for-looping over `_.next()` which is probably not intended", - deprecation: None, - module: "loops", - }, - Lint { - name: "iter_nth", - group: "perf", - desc: "using `.iter().nth()` on a standard library type with O(1) element access", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_skip_next", - group: "style", - desc: "using `.skip(x).next()` on an iterator", - deprecation: None, - module: "methods", - }, - Lint { - name: "iterator_step_by_zero", - group: "correctness", - desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", - deprecation: None, - module: "ranges", - }, - Lint { - name: "just_underscores_and_digits", - group: "style", - desc: "unclear name", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "large_digit_groups", - group: "pedantic", - desc: "grouping digits into groups that are too large", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "large_enum_variant", - group: "perf", - desc: "large size difference between variants on an enum", - deprecation: None, - module: "large_enum_variant", - }, - Lint { - name: "len_without_is_empty", - group: "style", - desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", - deprecation: None, - module: "len_zero", - }, - Lint { - name: "len_zero", - group: "style", - desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", - deprecation: None, - module: "len_zero", - }, - Lint { - name: "let_and_return", - group: "style", - desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", - deprecation: None, - module: "returns", - }, - Lint { - name: "let_unit_value", - group: "style", - desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", - deprecation: None, - module: "types", - }, - Lint { - name: "linkedlist", - group: "pedantic", - desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", - deprecation: None, - module: "types", - }, - Lint { - name: "logic_bug", - group: "correctness", - desc: "boolean expressions that contain terminals which can be eliminated", - deprecation: None, - module: "booleans", - }, - Lint { - name: "manual_memcpy", - group: "perf", - desc: "manually copying items between slices", - deprecation: None, - module: "loops", - }, - Lint { - name: "manual_swap", - group: "complexity", - desc: "manual swap of two variables", - deprecation: None, - module: "swap", - }, - Lint { - name: "many_single_char_names", - group: "style", - desc: "too many single character bindings", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "map_clone", - group: "style", - desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", - deprecation: None, - module: "map_clone", - }, - Lint { - name: "map_entry", - group: "perf", - desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", - deprecation: None, - module: "entry", - }, - Lint { - name: "map_flatten", - group: "pedantic", - desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "match_as_ref", - group: "complexity", - desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_bool", - group: "style", - desc: "a match on a boolean expression instead of an `if..else` block", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_overlapping_arm", - group: "style", - desc: "a match with overlapping arms", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_ref_pats", - group: "style", - desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_same_arms", - group: "pedantic", - desc: "`match` with identical arm bodies", - deprecation: None, - module: "copies", - }, - Lint { - name: "match_wild_err_arm", - group: "style", - desc: "a match with `Err(_)` arm and take drastic actions", - deprecation: None, - module: "matches", - }, - Lint { - name: "maybe_infinite_iter", - group: "pedantic", - desc: "possible infinite iteration", - deprecation: None, - module: "infinite_iter", - }, - Lint { - name: "mem_discriminant_non_enum", - group: "correctness", - desc: "calling mem::descriminant on non-enum type", - deprecation: None, - module: "mem_discriminant", - }, - Lint { - name: "mem_forget", - group: "restriction", - desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", - deprecation: None, - module: "mem_forget", - }, - Lint { - name: "mem_replace_option_with_none", - group: "style", - desc: "replacing an `Option` with `None` instead of `take()`", - deprecation: None, - module: "mem_replace", - }, - Lint { - name: "min_max", - group: "correctness", - desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant", - deprecation: None, - module: "minmax", - }, - Lint { - name: "misrefactored_assign_op", - group: "complexity", - desc: "having a variable on both sides of an assign op", - deprecation: None, - module: "assign_ops", - }, - Lint { - name: "missing_const_for_fn", - group: "nursery", - desc: "Lint functions definitions that could be made `const fn`", - deprecation: None, - module: "missing_const_for_fn", - }, - Lint { - name: "missing_docs_in_private_items", - group: "restriction", - desc: "detects missing documentation for public and private members", - deprecation: None, - module: "missing_doc", - }, - Lint { - name: "missing_inline_in_public_items", - group: "restriction", - desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", - deprecation: None, - module: "missing_inline", - }, - Lint { - name: "mistyped_literal_suffixes", - group: "correctness", - desc: "mistyped literal suffix", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "mixed_case_hex_literals", - group: "style", - desc: "hex literals whose letter digits are not consistently upper- or lowercased", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "module_inception", - group: "style", - desc: "modules that have the same name as their parent module", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "module_name_repetitions", - group: "pedantic", - desc: "type names prefixed/postfixed with their containing module\'s name", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "modulo_one", - group: "correctness", - desc: "taking a number modulo 1, which always returns 0", - deprecation: None, - module: "misc", - }, - Lint { - name: "multiple_crate_versions", - group: "cargo", - desc: "multiple versions of the same crate being used", - deprecation: None, - module: "multiple_crate_versions", - }, - Lint { - name: "multiple_inherent_impl", - group: "restriction", - desc: "Multiple inherent impl that could be grouped", - deprecation: None, - module: "inherent_impl", - }, - Lint { - name: "mut_from_ref", - group: "correctness", - desc: "fns that create mutable refs from immutable ref args", - deprecation: None, - module: "ptr", - }, - Lint { - name: "mut_mut", - group: "pedantic", - desc: "usage of double-mut refs, e.g., `&mut &mut ...`", - deprecation: None, - module: "mut_mut", - }, - Lint { - name: "mut_range_bound", - group: "complexity", - desc: "for loop over a range where one of the bounds is a mutable variable", - deprecation: None, - module: "loops", - }, - Lint { - name: "mutex_atomic", - group: "perf", - desc: "using a mutex where an atomic value could be used instead", - deprecation: None, - module: "mutex_atomic", - }, - Lint { - name: "mutex_integer", - group: "nursery", - desc: "using a mutex for an integer type", - deprecation: None, - module: "mutex_atomic", - }, - Lint { - name: "naive_bytecount", - group: "perf", - desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values", - deprecation: None, - module: "bytecount", - }, - Lint { - name: "needless_bool", - group: "complexity", - desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", - deprecation: None, - module: "needless_bool", - }, - Lint { - name: "needless_borrow", - group: "nursery", - desc: "taking a reference that is going to be automatically dereferenced", - deprecation: None, - module: "needless_borrow", - }, - Lint { - name: "needless_borrowed_reference", - group: "complexity", - desc: "taking a needless borrowed reference", - deprecation: None, - module: "needless_borrowed_ref", - }, - Lint { - name: "needless_collect", - group: "perf", - desc: "collecting an iterator when collect is not needed", - deprecation: None, - module: "loops", - }, - Lint { - name: "needless_continue", - group: "pedantic", - desc: "`continue` statements that can be replaced by a rearrangement of code", - deprecation: None, - module: "needless_continue", - }, - Lint { - name: "needless_lifetimes", - group: "complexity", - desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", - deprecation: None, - module: "lifetimes", - }, - Lint { - name: "needless_pass_by_value", - group: "pedantic", - desc: "functions taking arguments by value, but not consuming them in its body", - deprecation: None, - module: "needless_pass_by_value", - }, - Lint { - name: "needless_range_loop", - group: "style", - desc: "for-looping over a range of indices where an iterator over items would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "needless_return", - group: "style", - desc: "using a return statement like `return expr;` where an expression would suffice", - deprecation: None, - module: "returns", - }, - Lint { - name: "needless_update", - group: "complexity", - desc: "using `Foo { ..base }` when there are no missing fields", - deprecation: None, - module: "needless_update", - }, - Lint { - name: "neg_cmp_op_on_partial_ord", - group: "complexity", - desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", - deprecation: None, - module: "neg_cmp_op_on_partial_ord", - }, - Lint { - name: "neg_multiply", - group: "style", - desc: "multiplying integers with -1", - deprecation: None, - module: "neg_multiply", - }, - Lint { - name: "never_loop", - group: "correctness", - desc: "any loop that will always `break` or `return`", - deprecation: None, - module: "loops", - }, - Lint { - name: "new_ret_no_self", - group: "style", - desc: "not returning `Self` in a `new` method", - deprecation: None, - module: "methods", - }, - Lint { - name: "new_without_default", - group: "style", - desc: "`fn new() -> Self` method without `Default` implementation", - deprecation: None, - module: "new_without_default", - }, - Lint { - name: "no_effect", - group: "complexity", - desc: "statements with no effect", - deprecation: None, - module: "no_effect", - }, - Lint { - name: "non_ascii_literal", - group: "pedantic", - desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", - deprecation: None, - module: "unicode", - }, - Lint { - name: "nonminimal_bool", - group: "complexity", - desc: "boolean expressions that can be written more concisely", - deprecation: None, - module: "booleans", - }, - Lint { - name: "nonsensical_open_options", - group: "correctness", - desc: "nonsensical combination of options for opening a file", - deprecation: None, - module: "open_options", - }, - Lint { - name: "not_unsafe_ptr_arg_deref", - group: "correctness", - desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", - deprecation: None, - module: "functions", - }, - Lint { - name: "ok_expect", - group: "style", - desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", - deprecation: None, - module: "methods", - }, - Lint { - name: "op_ref", - group: "style", - desc: "taking a reference to satisfy the type constraints on `==`", - deprecation: None, - module: "eq_op", - }, - Lint { - name: "option_map_or_none", - group: "style", - desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_map_unit_fn", - group: "complexity", - desc: "using `option.map(f)`, where f is a function or closure that returns ()", - deprecation: None, - module: "map_unit_fn", - }, - Lint { - name: "option_map_unwrap_or", - group: "pedantic", - desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_map_unwrap_or_else", - group: "pedantic", - desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_option", - group: "complexity", - desc: "usage of `Option<Option<T>>`", - deprecation: None, - module: "types", - }, - Lint { - name: "option_unwrap_used", - group: "restriction", - desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "or_fun_call", - group: "perf", - desc: "using any `*or` method with a function call, which suggests `*or_else`", - deprecation: None, - module: "methods", - }, - Lint { - name: "out_of_bounds_indexing", - group: "correctness", - desc: "out of bounds constant indexing", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "overflow_check_conditional", - group: "complexity", - desc: "overflow checks inspired by C which are likely to panic", - deprecation: None, - module: "overflow_check_conditional", - }, - Lint { - name: "panic_params", - group: "style", - desc: "missing parameters in `panic!` calls", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "panicking_unwrap", - group: "nursery", - desc: "checks for calls of unwrap[_err]() that will always fail", - deprecation: None, - module: "unwrap", - }, - Lint { - name: "partialeq_ne_impl", - group: "complexity", - desc: "re-implementing `PartialEq::ne`", - deprecation: None, - module: "partialeq_ne_impl", - }, - Lint { - name: "path_buf_push_overwrite", - group: "nursery", - desc: "calling `push` with file system root on `PathBuf` can overwrite it", - deprecation: None, - module: "path_buf_push_overwrite", - }, - Lint { - name: "possible_missing_comma", - group: "correctness", - desc: "possible missing comma in array", - deprecation: None, - module: "formatting", - }, - Lint { - name: "precedence", - group: "complexity", - desc: "operations where precedence may be unclear", - deprecation: None, - module: "precedence", - }, - Lint { - name: "print_literal", - group: "style", - desc: "printing a literal with a format string", - deprecation: None, - module: "write", - }, - Lint { - name: "print_stdout", - group: "restriction", - desc: "printing on stdout", - deprecation: None, - module: "write", - }, - Lint { - name: "print_with_newline", - group: "style", - desc: "using `print!()` with a format string that ends in a single newline", - deprecation: None, - module: "write", - }, - Lint { - name: "println_empty_string", - group: "style", - desc: "using `println!(\"\")` with an empty string", - deprecation: None, - module: "write", - }, - Lint { - name: "ptr_arg", - group: "style", - desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", - deprecation: None, - module: "ptr", - }, - Lint { - name: "ptr_offset_with_cast", - group: "complexity", - desc: "unneeded pointer offset cast", - deprecation: None, - module: "ptr_offset_with_cast", - }, - Lint { - name: "pub_enum_variant_names", - group: "pedantic", - desc: "enums where all variants share a prefix/postfix", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "question_mark", - group: "style", - desc: "checks for expressions that could be replaced by the question mark operator", - deprecation: None, - module: "question_mark", - }, - Lint { - name: "range_minus_one", - group: "complexity", - desc: "`x..=(y-1)` reads better as `x..y`", - deprecation: None, - module: "ranges", - }, - Lint { - name: "range_plus_one", - group: "complexity", - desc: "`x..(y+1)` reads better as `x..=y`", - deprecation: None, - module: "ranges", - }, - Lint { - name: "range_zip_with_len", - group: "complexity", - desc: "zipping iterator with a range when `enumerate()` would do", - deprecation: None, - module: "ranges", - }, - Lint { - name: "redundant_clone", - group: "nursery", - desc: "`clone()` of an owned value that is going to be dropped immediately", - deprecation: None, - module: "redundant_clone", - }, - Lint { - name: "redundant_closure", - group: "style", - desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", - deprecation: None, - module: "eta_reduction", - }, - Lint { - name: "redundant_closure_call", - group: "complexity", - desc: "throwaway closures called in the expression they are defined", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "redundant_closure_for_method_calls", - group: "pedantic", - desc: "redundant closures for method calls", - deprecation: None, - module: "eta_reduction", - }, - Lint { - name: "redundant_field_names", - group: "style", - desc: "checks for fields in struct literals where shorthands could be used", - deprecation: None, - module: "redundant_field_names", - }, - Lint { - name: "redundant_pattern", - group: "style", - desc: "using `name @ _` in a pattern", - deprecation: None, - module: "misc", - }, - Lint { - name: "redundant_pattern_matching", - group: "style", - desc: "use the proper utility function avoiding an `if let`", - deprecation: None, - module: "redundant_pattern_matching", - }, - Lint { - name: "ref_in_deref", - group: "complexity", - desc: "Use of reference in auto dereference expression.", - deprecation: None, - module: "reference", - }, - Lint { - name: "regex_macro", - group: "style", - desc: "use of `regex!(_)` instead of `Regex::new(_)`", - deprecation: None, - module: "regex", - }, - Lint { - name: "replace_consts", - group: "pedantic", - desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", - deprecation: None, - module: "replace_consts", - }, - Lint { - name: "result_map_unit_fn", - group: "complexity", - desc: "using `result.map(f)`, where f is a function or closure that returns ()", - deprecation: None, - module: "map_unit_fn", - }, - Lint { - name: "result_map_unwrap_or_else", - group: "pedantic", - desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "result_unwrap_used", - group: "restriction", - desc: "using `Result.unwrap()`, which might be better handled", - deprecation: None, - module: "methods", - }, - Lint { - name: "reverse_range_loop", - group: "correctness", - desc: "iteration over an empty range, such as `10..0` or `5..5`", - deprecation: None, - module: "loops", - }, - Lint { - name: "search_is_some", - group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "serde_api_misuse", - group: "correctness", - desc: "various things that will negatively affect your serde experience", - deprecation: None, - module: "serde_api", - }, - Lint { - name: "shadow_reuse", - group: "restriction", - desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", - deprecation: None, - module: "shadow", - }, - Lint { - name: "shadow_same", - group: "restriction", - desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", - deprecation: None, - module: "shadow", - }, - Lint { - name: "shadow_unrelated", - group: "pedantic", - desc: "rebinding a name without even using the original value", - deprecation: None, - module: "shadow", - }, - Lint { - name: "short_circuit_statement", - group: "complexity", - desc: "using a short circuit boolean condition as a statement", - deprecation: None, - module: "misc", - }, - Lint { - name: "should_implement_trait", - group: "style", - desc: "defining a method that should be implementing a std trait", - deprecation: None, - module: "methods", - }, - Lint { - name: "similar_names", - group: "pedantic", - desc: "similarly named items and bindings", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "single_char_pattern", - group: "perf", - desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", - deprecation: None, - module: "methods", - }, - Lint { - name: "single_match", - group: "style", - desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", - deprecation: None, - module: "matches", - }, - Lint { - name: "single_match_else", - group: "pedantic", - desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", - deprecation: None, - module: "matches", - }, - Lint { - name: "slow_vector_initialization", - group: "perf", - desc: "slow vector initialization", - deprecation: None, - module: "slow_vector_initialization", - }, - Lint { - name: "string_add", - group: "restriction", - desc: "using `x + ..` where x is a `String` instead of `push_str()`", - deprecation: None, - module: "strings", - }, - Lint { - name: "string_add_assign", - group: "pedantic", - desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", - deprecation: None, - module: "strings", - }, - Lint { - name: "string_extend_chars", - group: "style", - desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", - deprecation: None, - module: "methods", - }, - Lint { - name: "string_lit_as_bytes", - group: "style", - desc: "calling `as_bytes` on a string literal instead of using a byte string literal", - deprecation: None, - module: "strings", - }, - Lint { - name: "suspicious_arithmetic_impl", - group: "correctness", - desc: "suspicious use of operators in impl of arithmetic trait", - deprecation: None, - module: "suspicious_trait_impl", - }, - Lint { - name: "suspicious_assignment_formatting", - group: "style", - desc: "suspicious formatting of `*=`, `-=` or `!=`", - deprecation: None, - module: "formatting", - }, - Lint { - name: "suspicious_else_formatting", - group: "style", - desc: "suspicious formatting of `else`", - deprecation: None, - module: "formatting", - }, - Lint { - name: "suspicious_op_assign_impl", - group: "correctness", - desc: "suspicious use of operators in impl of OpAssign trait", - deprecation: None, - module: "suspicious_trait_impl", - }, - Lint { - name: "temporary_assignment", - group: "complexity", - desc: "assignments to temporaries", - deprecation: None, - module: "temporary_assignment", - }, - Lint { - name: "temporary_cstring_as_ptr", - group: "correctness", - desc: "getting the inner pointer of a temporary `CString`", - deprecation: None, - module: "methods", - }, - Lint { - name: "too_many_arguments", - group: "complexity", - desc: "functions with too many arguments", - deprecation: None, - module: "functions", - }, - Lint { - name: "too_many_lines", - group: "pedantic", - desc: "functions with too many lines", - deprecation: None, - module: "functions", - }, - Lint { - name: "toplevel_ref_arg", - group: "style", - desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", - deprecation: None, - module: "misc", - }, - Lint { - name: "transmute_bytes_to_str", - group: "complexity", - desc: "transmutes from a `&[u8]` to a `&str`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_bool", - group: "complexity", - desc: "transmutes from an integer to a `bool`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_char", - group: "complexity", - desc: "transmutes from an integer to a `char`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_float", - group: "complexity", - desc: "transmutes from an integer to a float", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_ptr_to_ptr", - group: "complexity", - desc: "transmutes from a pointer to a pointer / a reference to a reference", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_ptr_to_ref", - group: "complexity", - desc: "transmutes from a pointer to a reference type", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmuting_null", - group: "correctness", - desc: "transmutes from a null pointer to a reference, which is undefined behavior", - deprecation: None, - module: "transmuting_null", - }, - Lint { - name: "trivial_regex", - group: "style", - desc: "trivial regular expressions", - deprecation: None, - module: "regex", - }, - Lint { - name: "trivially_copy_pass_by_ref", - group: "perf", - desc: "functions taking small copyable arguments by reference", - deprecation: None, - module: "trivially_copy_pass_by_ref", - }, - Lint { - name: "type_complexity", - group: "complexity", - desc: "usage of very complex types that might be better factored into `type` definitions", - deprecation: None, - module: "types", - }, - Lint { - name: "unicode_not_nfc", - group: "pedantic", - desc: "using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", - deprecation: None, - module: "unicode", - }, - Lint { - name: "unimplemented", - group: "restriction", - desc: "`unimplemented!` should not be present in production code", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "unit_arg", - group: "complexity", - desc: "passing unit to a function", - deprecation: None, - module: "types", - }, - Lint { - name: "unit_cmp", - group: "correctness", - desc: "comparing unit values", - deprecation: None, - module: "types", - }, - Lint { - name: "unknown_clippy_lints", - group: "style", - desc: "unknown_lints for scoped Clippy lints", - deprecation: None, - module: "attrs", - }, - Lint { - name: "unnecessary_cast", - group: "complexity", - desc: "cast to the same type, e.g., `x as i32` where `x: i32`", - deprecation: None, - module: "types", - }, - Lint { - name: "unnecessary_filter_map", - group: "complexity", - desc: "using `filter_map` when a more succinct alternative exists", - deprecation: None, - module: "methods", - }, - Lint { - name: "unnecessary_fold", - group: "style", - desc: "using `fold` when a more succinct alternative exists", - deprecation: None, - module: "methods", - }, - Lint { - name: "unnecessary_mut_passed", - group: "style", - desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", - deprecation: None, - module: "mut_reference", - }, - Lint { - name: "unnecessary_operation", - group: "complexity", - desc: "outer expressions with no effect", - deprecation: None, - module: "no_effect", - }, - Lint { - name: "unnecessary_unwrap", - group: "nursery", - desc: "checks for calls of unwrap[_err]() that cannot fail", - deprecation: None, - module: "unwrap", - }, - Lint { - name: "unneeded_field_pattern", - group: "style", - desc: "struct fields bound to a wildcard instead of using `..`", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "unreadable_literal", - group: "style", - desc: "long integer literal without underscores", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "unsafe_removed_from_name", - group: "style", - desc: "`unsafe` removed from API names on import", - deprecation: None, - module: "unsafe_removed_from_name", - }, - Lint { - name: "unseparated_literal_suffix", - group: "pedantic", - desc: "literals whose suffix is not separated by an underscore", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "unused_collect", - group: "perf", - desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", - deprecation: None, - module: "loops", - }, - Lint { - name: "unused_io_amount", - group: "correctness", - desc: "unused written/read amount", - deprecation: None, - module: "unused_io_amount", - }, - Lint { - name: "unused_label", - group: "complexity", - desc: "unused labels", - deprecation: None, - module: "unused_label", - }, - Lint { - name: "unused_unit", - group: "style", - desc: "needless unit expression", - deprecation: None, - module: "returns", - }, - Lint { - name: "use_debug", - group: "restriction", - desc: "use of `Debug`-based formatting", - deprecation: None, - module: "write", - }, - Lint { - name: "use_self", - group: "pedantic", - desc: "Unnecessary structure name repetition whereas `Self` is applicable", - deprecation: None, - module: "use_self", - }, - Lint { - name: "used_underscore_binding", - group: "pedantic", - desc: "using a binding which is prefixed with an underscore", - deprecation: None, - module: "misc", - }, - Lint { - name: "useless_asref", - group: "complexity", - desc: "using `as_ref` where the types before and after the call are the same", - deprecation: None, - module: "methods", - }, - Lint { - name: "useless_attribute", - group: "correctness", - desc: "use of lint attributes on `extern crate` items", - deprecation: None, - module: "attrs", - }, - Lint { - name: "useless_format", - group: "complexity", - desc: "useless use of `format!`", - deprecation: None, - module: "format", - }, - Lint { - name: "useless_let_if_seq", - group: "style", - desc: "unidiomatic `let mut` declaration followed by initialization in `if`", - deprecation: None, - module: "let_if_seq", - }, - Lint { - name: "useless_transmute", - group: "complexity", - desc: "transmutes that have the same to and from types or could be a cast/coercion", - deprecation: None, - module: "transmute", - }, - Lint { - name: "useless_vec", - group: "perf", - desc: "useless `vec!`", - deprecation: None, - module: "vec", - }, - Lint { - name: "vec_box", - group: "complexity", - desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap", - deprecation: None, - module: "types", - }, - Lint { - name: "verbose_bit_mask", - group: "style", - desc: "expressions where a bit mask is less readable than the corresponding method call", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "while_immutable_condition", - group: "correctness", - desc: "variables used within while expression are not mutated in the body", - deprecation: None, - module: "loops", - }, - Lint { - name: "while_let_loop", - group: "complexity", - desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", - deprecation: None, - module: "loops", - }, - Lint { - name: "while_let_on_iterator", - group: "style", - desc: "using a while-let loop instead of a for loop on an iterator", - deprecation: None, - module: "loops", - }, - Lint { - name: "wildcard_dependencies", - group: "cargo", - desc: "wildcard dependencies being used", - deprecation: None, - module: "wildcard_dependencies", - }, - Lint { - name: "wildcard_enum_match_arm", - group: "restriction", - desc: "a wildcard enum match arm using `_`", - deprecation: None, - module: "matches", - }, - Lint { - name: "write_literal", - group: "style", - desc: "writing a literal with a format string", - deprecation: None, - module: "write", - }, - Lint { - name: "write_with_newline", - group: "style", - desc: "using `write!()` with a format string that ends in a single newline", - deprecation: None, - module: "write", - }, - Lint { - name: "writeln_empty_string", - group: "style", - desc: "using `writeln!(buf, \"\")` with an empty string", - deprecation: None, - module: "write", - }, - Lint { - name: "wrong_pub_self_convention", - group: "restriction", - desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", - deprecation: None, - module: "methods", - }, - Lint { - name: "wrong_self_convention", - group: "style", - desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", - deprecation: None, - module: "methods", - }, - Lint { - name: "wrong_transmute", - group: "correctness", - desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", - deprecation: None, - module: "transmute", - }, - Lint { - name: "zero_divided_by_zero", - group: "complexity", - desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", - deprecation: None, - module: "zero_div_zero", - }, - Lint { - name: "zero_prefixed_literal", - group: "complexity", - desc: "integer literals starting with `0`", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "zero_ptr", - group: "style", - desc: "using 0 as *{const, mut} T", - deprecation: None, - module: "misc", - }, - Lint { - name: "zero_width_space", - group: "correctness", - desc: "using a zero-width space in a string literal, which is confusing", - deprecation: None, - module: "unicode", - }, -]; diff --git a/src/lintlist/lint.rs b/src/lintlist/lint.rs new file mode 100644 index 00000000000..a4dd0747059 --- /dev/null +++ b/src/lintlist/lint.rs @@ -0,0 +1,9 @@ +/// Lint data parsed from the Clippy source code. +#[derive(Clone, PartialEq, Debug)] +pub struct Lint { + pub name: &'static str, + pub group: &'static str, + pub desc: &'static str, + pub deprecation: Option<&'static str>, + pub module: &'static str, +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs new file mode 100644 index 00000000000..cf367bcc632 --- /dev/null +++ b/src/lintlist/mod.rs @@ -0,0 +1,2135 @@ +//! This file is managed by util/dev update_lints. Do not edit. + +mod lint; +use lint::Lint; + +pub const ALL_LINTS: [Lint; 304] = [ + Lint { + name: "absurd_extreme_comparisons", + group: "correctness", + desc: "a comparison with a maximum or minimum value that is always true or false", + deprecation: None, + module: "types", + }, + Lint { + name: "almost_swapped", + group: "correctness", + desc: "`foo = bar; bar = foo` sequence", + deprecation: None, + module: "swap", + }, + Lint { + name: "approx_constant", + group: "correctness", + desc: "the approximate of a known float constant (in `std::fXX::consts`)", + deprecation: None, + module: "approx_const", + }, + Lint { + name: "assertions_on_constants", + group: "style", + desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", + deprecation: None, + module: "assertions_on_constants", + }, + Lint { + name: "assign_op_pattern", + group: "style", + desc: "assigning the result of an operation on a variable to that same variable", + deprecation: None, + module: "assign_ops", + }, + Lint { + name: "bad_bit_mask", + group: "correctness", + desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "blacklisted_name", + group: "style", + desc: "usage of a blacklisted/placeholder name", + deprecation: None, + module: "blacklisted_name", + }, + Lint { + name: "block_in_if_condition_expr", + group: "style", + desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", + deprecation: None, + module: "block_in_if_condition", + }, + Lint { + name: "block_in_if_condition_stmt", + group: "style", + desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", + deprecation: None, + module: "block_in_if_condition", + }, + Lint { + name: "bool_comparison", + group: "complexity", + desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", + deprecation: None, + module: "needless_bool", + }, + Lint { + name: "borrow_interior_mutable_const", + group: "correctness", + desc: "referencing const with interior mutability", + deprecation: None, + module: "non_copy_const", + }, + Lint { + name: "borrowed_box", + group: "complexity", + desc: "a borrow of a boxed type", + deprecation: None, + module: "types", + }, + Lint { + name: "box_vec", + group: "perf", + desc: "usage of `Box<Vec<T>>`, vector elements are already on the heap", + deprecation: None, + module: "types", + }, + Lint { + name: "boxed_local", + group: "perf", + desc: "using `Box<T>` where unnecessary", + deprecation: None, + module: "escape", + }, + Lint { + name: "builtin_type_shadow", + group: "style", + desc: "shadowing a builtin type", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "cargo_common_metadata", + group: "cargo", + desc: "common metadata is defined in `Cargo.toml`", + deprecation: None, + module: "cargo_common_metadata", + }, + Lint { + name: "cast_lossless", + group: "complexity", + desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_possible_truncation", + group: "pedantic", + desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_possible_wrap", + group: "pedantic", + desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_precision_loss", + group: "pedantic", + desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_ptr_alignment", + group: "correctness", + desc: "cast from a pointer to a more-strictly-aligned pointer", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_ref_to_mut", + group: "correctness", + desc: "a cast of reference to a mutable pointer", + deprecation: None, + module: "types", + }, + Lint { + name: "cast_sign_loss", + group: "pedantic", + desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", + deprecation: None, + module: "types", + }, + Lint { + name: "char_lit_as_u8", + group: "complexity", + desc: "casting a character literal to u8", + deprecation: None, + module: "types", + }, + Lint { + name: "chars_last_cmp", + group: "style", + desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", + deprecation: None, + module: "methods", + }, + Lint { + name: "chars_next_cmp", + group: "complexity", + desc: "using `.chars().next()` to check if a string starts with a char", + deprecation: None, + module: "methods", + }, + Lint { + name: "checked_conversions", + group: "pedantic", + desc: "`try_from` could replace manual bounds checking when casting", + deprecation: None, + module: "checked_conversions", + }, + Lint { + name: "clone_double_ref", + group: "correctness", + desc: "using `clone` on `&&T`", + deprecation: None, + module: "methods", + }, + Lint { + name: "clone_on_copy", + group: "complexity", + desc: "using `clone` on a `Copy` type", + deprecation: None, + module: "methods", + }, + Lint { + name: "clone_on_ref_ptr", + group: "restriction", + desc: "using \'clone\' on a ref-counted pointer", + deprecation: None, + module: "methods", + }, + Lint { + name: "cmp_nan", + group: "correctness", + desc: "comparisons to NAN, which will always return false, probably not intended", + deprecation: None, + module: "misc", + }, + Lint { + name: "cmp_null", + group: "style", + desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", + deprecation: None, + module: "ptr", + }, + Lint { + name: "cmp_owned", + group: "perf", + desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", + deprecation: None, + module: "misc", + }, + Lint { + name: "cognitive_complexity", + group: "complexity", + desc: "functions that should be split up into multiple functions", + deprecation: None, + module: "cognitive_complexity", + }, + Lint { + name: "collapsible_if", + group: "style", + desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", + deprecation: None, + module: "collapsible_if", + }, + Lint { + name: "const_static_lifetime", + group: "style", + desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", + deprecation: None, + module: "const_static_lifetime", + }, + Lint { + name: "copy_iterator", + group: "pedantic", + desc: "implementing `Iterator` on a `Copy` type", + deprecation: None, + module: "copy_iterator", + }, + Lint { + name: "crosspointer_transmute", + group: "complexity", + desc: "transmutes that have to or from types that are a pointer to the other", + deprecation: None, + module: "transmute", + }, + Lint { + name: "dbg_macro", + group: "restriction", + desc: "`dbg!` macro is intended as a debugging tool", + deprecation: None, + module: "dbg_macro", + }, + Lint { + name: "decimal_literal_representation", + group: "restriction", + desc: "using decimal representation when hexadecimal would be better", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "declare_interior_mutable_const", + group: "correctness", + desc: "declaring const with interior mutability", + deprecation: None, + module: "non_copy_const", + }, + Lint { + name: "default_trait_access", + group: "pedantic", + desc: "checks for literal calls to Default::default()", + deprecation: None, + module: "default_trait_access", + }, + Lint { + name: "deprecated_cfg_attr", + group: "complexity", + desc: "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`", + deprecation: None, + module: "attrs", + }, + Lint { + name: "deprecated_semver", + group: "correctness", + desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", + deprecation: None, + module: "attrs", + }, + Lint { + name: "deref_addrof", + group: "complexity", + desc: "use of `*&` or `*&mut` in an expression", + deprecation: None, + module: "reference", + }, + Lint { + name: "derive_hash_xor_eq", + group: "correctness", + desc: "deriving `Hash` but implementing `PartialEq` explicitly", + deprecation: None, + module: "derive", + }, + Lint { + name: "diverging_sub_expression", + group: "complexity", + desc: "whether an expression contains a diverging sub expression", + deprecation: None, + module: "eval_order_dependence", + }, + Lint { + name: "doc_markdown", + group: "pedantic", + desc: "presence of `_`, `::` or camel-case outside backticks in documentation", + deprecation: None, + module: "doc", + }, + Lint { + name: "double_comparisons", + group: "complexity", + desc: "unnecessary double comparisons that can be simplified", + deprecation: None, + module: "double_comparison", + }, + Lint { + name: "double_neg", + group: "style", + desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "double_parens", + group: "complexity", + desc: "Warn on unnecessary double parentheses", + deprecation: None, + module: "double_parens", + }, + Lint { + name: "drop_bounds", + group: "correctness", + desc: "Bounds of the form `T: Drop` are useless", + deprecation: None, + module: "drop_bounds", + }, + Lint { + name: "drop_copy", + group: "correctness", + desc: "calls to `std::mem::drop` with a value that implements Copy", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "drop_ref", + group: "correctness", + desc: "calls to `std::mem::drop` with a reference instead of an owned value", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "duplicate_underscore_argument", + group: "style", + desc: "function arguments having names which only differ by an underscore", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "duration_subsec", + group: "complexity", + desc: "checks for calculation of subsecond microseconds or milliseconds", + deprecation: None, + module: "duration_subsec", + }, + Lint { + name: "else_if_without_else", + group: "restriction", + desc: "if expression with an `else if`, but without a final `else` branch", + deprecation: None, + module: "else_if_without_else", + }, + Lint { + name: "empty_enum", + group: "pedantic", + desc: "enum with no variants", + deprecation: None, + module: "empty_enum", + }, + Lint { + name: "empty_line_after_outer_attr", + group: "nursery", + desc: "empty line after outer attribute", + deprecation: None, + module: "attrs", + }, + Lint { + name: "empty_loop", + group: "style", + desc: "empty `loop {}`, which should block or sleep", + deprecation: None, + module: "loops", + }, + Lint { + name: "enum_clike_unportable_variant", + group: "correctness", + desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", + deprecation: None, + module: "enum_clike", + }, + Lint { + name: "enum_glob_use", + group: "pedantic", + desc: "use items that import all variants of an enum", + deprecation: None, + module: "enum_glob_use", + }, + Lint { + name: "enum_variant_names", + group: "style", + desc: "enums where all variants share a prefix/postfix", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "eq_op", + group: "correctness", + desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", + deprecation: None, + module: "eq_op", + }, + Lint { + name: "erasing_op", + group: "correctness", + desc: "using erasing operations, e.g., `x * 0` or `y & 0`", + deprecation: None, + module: "erasing_op", + }, + Lint { + name: "eval_order_dependence", + group: "complexity", + desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", + deprecation: None, + module: "eval_order_dependence", + }, + Lint { + name: "excessive_precision", + group: "style", + desc: "excessive precision for float literal", + deprecation: None, + module: "excessive_precision", + }, + Lint { + name: "expect_fun_call", + group: "perf", + desc: "using any `expect` method with a function call", + deprecation: None, + module: "methods", + }, + Lint { + name: "expl_impl_clone_on_copy", + group: "pedantic", + desc: "implementing `Clone` explicitly on `Copy` types", + deprecation: None, + module: "derive", + }, + Lint { + name: "explicit_counter_loop", + group: "complexity", + desc: "for-looping with an explicit counter when `_.enumerate()` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_into_iter_loop", + group: "pedantic", + desc: "for-looping over `_.into_iter()` when `_` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_iter_loop", + group: "pedantic", + desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "explicit_write", + group: "complexity", + desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", + deprecation: None, + module: "explicit_write", + }, + Lint { + name: "extra_unused_lifetimes", + group: "complexity", + desc: "unused lifetimes in function definitions", + deprecation: None, + module: "lifetimes", + }, + Lint { + name: "fallible_impl_from", + group: "nursery", + desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", + deprecation: None, + module: "fallible_impl_from", + }, + Lint { + name: "filter_map", + group: "pedantic", + desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "filter_map_next", + group: "pedantic", + desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "filter_next", + group: "complexity", + desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "find_map", + group: "pedantic", + desc: "using a combination of `find` and `map` can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "float_arithmetic", + group: "restriction", + desc: "any floating-point arithmetic statement", + deprecation: None, + module: "arithmetic", + }, + Lint { + name: "float_cmp", + group: "correctness", + desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", + deprecation: None, + module: "misc", + }, + Lint { + name: "float_cmp_const", + group: "restriction", + desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", + deprecation: None, + module: "misc", + }, + Lint { + name: "fn_to_numeric_cast", + group: "style", + desc: "casting a function pointer to a numeric type other than usize", + deprecation: None, + module: "types", + }, + Lint { + name: "fn_to_numeric_cast_with_truncation", + group: "style", + desc: "casting a function pointer to a numeric type not wide enough to store the address", + deprecation: None, + module: "types", + }, + Lint { + name: "for_kv_map", + group: "style", + desc: "looping on a map using `iter` when `keys` or `values` would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "for_loop_over_option", + group: "correctness", + desc: "for-looping over an `Option`, which is more clearly expressed as an `if let`", + deprecation: None, + module: "loops", + }, + Lint { + name: "for_loop_over_result", + group: "correctness", + desc: "for-looping over a `Result`, which is more clearly expressed as an `if let`", + deprecation: None, + module: "loops", + }, + Lint { + name: "forget_copy", + group: "correctness", + desc: "calls to `std::mem::forget` with a value that implements Copy", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "forget_ref", + group: "correctness", + desc: "calls to `std::mem::forget` with a reference instead of an owned value", + deprecation: None, + module: "drop_forget_ref", + }, + Lint { + name: "get_last_with_len", + group: "complexity", + desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", + deprecation: None, + module: "get_last_with_len", + }, + Lint { + name: "get_unwrap", + group: "restriction", + desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", + deprecation: None, + module: "methods", + }, + Lint { + name: "identity_conversion", + group: "complexity", + desc: "using always-identical `Into`/`From`/`IntoIter` conversions", + deprecation: None, + module: "identity_conversion", + }, + Lint { + name: "identity_op", + group: "complexity", + desc: "using identity operations, e.g., `x + 0` or `y / 1`", + deprecation: None, + module: "identity_op", + }, + Lint { + name: "if_let_some_result", + group: "style", + desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", + deprecation: None, + module: "ok_if_let", + }, + Lint { + name: "if_not_else", + group: "pedantic", + desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", + deprecation: None, + module: "if_not_else", + }, + Lint { + name: "if_same_then_else", + group: "correctness", + desc: "if with the same *then* and *else* blocks", + deprecation: None, + module: "copies", + }, + Lint { + name: "ifs_same_cond", + group: "correctness", + desc: "consecutive `ifs` with the same condition", + deprecation: None, + module: "copies", + }, + Lint { + name: "implicit_hasher", + group: "style", + desc: "missing generalization over different hashers", + deprecation: None, + module: "types", + }, + Lint { + name: "implicit_return", + group: "restriction", + desc: "use a return statement like `return expr` instead of an expression", + deprecation: None, + module: "implicit_return", + }, + Lint { + name: "inconsistent_digit_grouping", + group: "style", + desc: "integer literals with digits grouped inconsistently", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "indexing_slicing", + group: "restriction", + desc: "indexing/slicing usage", + deprecation: None, + module: "indexing_slicing", + }, + Lint { + name: "ineffective_bit_mask", + group: "correctness", + desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "infallible_destructuring_match", + group: "style", + desc: "a match statement with a single infallible arm instead of a `let`", + deprecation: None, + module: "infallible_destructuring_match", + }, + Lint { + name: "infinite_iter", + group: "correctness", + desc: "infinite iteration", + deprecation: None, + module: "infinite_iter", + }, + Lint { + name: "inline_always", + group: "pedantic", + desc: "use of `#[inline(always)]`", + deprecation: None, + module: "attrs", + }, + Lint { + name: "inline_fn_without_body", + group: "correctness", + desc: "use of `#[inline]` on trait methods without bodies", + deprecation: None, + module: "inline_fn_without_body", + }, + Lint { + name: "int_plus_one", + group: "complexity", + desc: "instead of using x >= y + 1, use x > y", + deprecation: None, + module: "int_plus_one", + }, + Lint { + name: "integer_arithmetic", + group: "restriction", + desc: "any integer arithmetic statement", + deprecation: None, + module: "arithmetic", + }, + Lint { + name: "into_iter_on_array", + group: "correctness", + desc: "using `.into_iter()` on an array", + deprecation: None, + module: "methods", + }, + Lint { + name: "into_iter_on_ref", + group: "style", + desc: "using `.into_iter()` on a reference", + deprecation: None, + module: "methods", + }, + Lint { + name: "invalid_ref", + group: "correctness", + desc: "creation of invalid reference", + deprecation: None, + module: "invalid_ref", + }, + Lint { + name: "invalid_regex", + group: "correctness", + desc: "invalid regular expressions", + deprecation: None, + module: "regex", + }, + Lint { + name: "invalid_upcast_comparisons", + group: "pedantic", + desc: "a comparison involving an upcast which is always true or false", + deprecation: None, + module: "types", + }, + Lint { + name: "items_after_statements", + group: "pedantic", + desc: "blocks where an item comes after a statement", + deprecation: None, + module: "items_after_statements", + }, + Lint { + name: "iter_cloned_collect", + group: "style", + desc: "using `.cloned().collect()` on slice to create a `Vec`", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_next_loop", + group: "correctness", + desc: "for-looping over `_.next()` which is probably not intended", + deprecation: None, + module: "loops", + }, + Lint { + name: "iter_nth", + group: "perf", + desc: "using `.iter().nth()` on a standard library type with O(1) element access", + deprecation: None, + module: "methods", + }, + Lint { + name: "iter_skip_next", + group: "style", + desc: "using `.skip(x).next()` on an iterator", + deprecation: None, + module: "methods", + }, + Lint { + name: "iterator_step_by_zero", + group: "correctness", + desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", + deprecation: None, + module: "ranges", + }, + Lint { + name: "just_underscores_and_digits", + group: "style", + desc: "unclear name", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "large_digit_groups", + group: "pedantic", + desc: "grouping digits into groups that are too large", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "large_enum_variant", + group: "perf", + desc: "large size difference between variants on an enum", + deprecation: None, + module: "large_enum_variant", + }, + Lint { + name: "len_without_is_empty", + group: "style", + desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", + deprecation: None, + module: "len_zero", + }, + Lint { + name: "len_zero", + group: "style", + desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", + deprecation: None, + module: "len_zero", + }, + Lint { + name: "let_and_return", + group: "style", + desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", + deprecation: None, + module: "returns", + }, + Lint { + name: "let_unit_value", + group: "style", + desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", + deprecation: None, + module: "types", + }, + Lint { + name: "linkedlist", + group: "pedantic", + desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", + deprecation: None, + module: "types", + }, + Lint { + name: "logic_bug", + group: "correctness", + desc: "boolean expressions that contain terminals which can be eliminated", + deprecation: None, + module: "booleans", + }, + Lint { + name: "manual_memcpy", + group: "perf", + desc: "manually copying items between slices", + deprecation: None, + module: "loops", + }, + Lint { + name: "manual_swap", + group: "complexity", + desc: "manual swap of two variables", + deprecation: None, + module: "swap", + }, + Lint { + name: "many_single_char_names", + group: "style", + desc: "too many single character bindings", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "map_clone", + group: "style", + desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", + deprecation: None, + module: "map_clone", + }, + Lint { + name: "map_entry", + group: "perf", + desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", + deprecation: None, + module: "entry", + }, + Lint { + name: "map_flatten", + group: "pedantic", + desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", + deprecation: None, + module: "methods", + }, + Lint { + name: "match_as_ref", + group: "complexity", + desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_bool", + group: "style", + desc: "a match on a boolean expression instead of an `if..else` block", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_overlapping_arm", + group: "style", + desc: "a match with overlapping arms", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_ref_pats", + group: "style", + desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", + deprecation: None, + module: "matches", + }, + Lint { + name: "match_same_arms", + group: "pedantic", + desc: "`match` with identical arm bodies", + deprecation: None, + module: "copies", + }, + Lint { + name: "match_wild_err_arm", + group: "style", + desc: "a match with `Err(_)` arm and take drastic actions", + deprecation: None, + module: "matches", + }, + Lint { + name: "maybe_infinite_iter", + group: "pedantic", + desc: "possible infinite iteration", + deprecation: None, + module: "infinite_iter", + }, + Lint { + name: "mem_discriminant_non_enum", + group: "correctness", + desc: "calling mem::descriminant on non-enum type", + deprecation: None, + module: "mem_discriminant", + }, + Lint { + name: "mem_forget", + group: "restriction", + desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", + deprecation: None, + module: "mem_forget", + }, + Lint { + name: "mem_replace_option_with_none", + group: "style", + desc: "replacing an `Option` with `None` instead of `take()`", + deprecation: None, + module: "mem_replace", + }, + Lint { + name: "min_max", + group: "correctness", + desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant", + deprecation: None, + module: "minmax", + }, + Lint { + name: "misrefactored_assign_op", + group: "complexity", + desc: "having a variable on both sides of an assign op", + deprecation: None, + module: "assign_ops", + }, + Lint { + name: "missing_const_for_fn", + group: "nursery", + desc: "Lint functions definitions that could be made `const fn`", + deprecation: None, + module: "missing_const_for_fn", + }, + Lint { + name: "missing_docs_in_private_items", + group: "restriction", + desc: "detects missing documentation for public and private members", + deprecation: None, + module: "missing_doc", + }, + Lint { + name: "missing_inline_in_public_items", + group: "restriction", + desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", + deprecation: None, + module: "missing_inline", + }, + Lint { + name: "mistyped_literal_suffixes", + group: "correctness", + desc: "mistyped literal suffix", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "mixed_case_hex_literals", + group: "style", + desc: "hex literals whose letter digits are not consistently upper- or lowercased", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "module_inception", + group: "style", + desc: "modules that have the same name as their parent module", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "module_name_repetitions", + group: "pedantic", + desc: "type names prefixed/postfixed with their containing module\'s name", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "modulo_one", + group: "correctness", + desc: "taking a number modulo 1, which always returns 0", + deprecation: None, + module: "misc", + }, + Lint { + name: "multiple_crate_versions", + group: "cargo", + desc: "multiple versions of the same crate being used", + deprecation: None, + module: "multiple_crate_versions", + }, + Lint { + name: "multiple_inherent_impl", + group: "restriction", + desc: "Multiple inherent impl that could be grouped", + deprecation: None, + module: "inherent_impl", + }, + Lint { + name: "mut_from_ref", + group: "correctness", + desc: "fns that create mutable refs from immutable ref args", + deprecation: None, + module: "ptr", + }, + Lint { + name: "mut_mut", + group: "pedantic", + desc: "usage of double-mut refs, e.g., `&mut &mut ...`", + deprecation: None, + module: "mut_mut", + }, + Lint { + name: "mut_range_bound", + group: "complexity", + desc: "for loop over a range where one of the bounds is a mutable variable", + deprecation: None, + module: "loops", + }, + Lint { + name: "mutex_atomic", + group: "perf", + desc: "using a mutex where an atomic value could be used instead", + deprecation: None, + module: "mutex_atomic", + }, + Lint { + name: "mutex_integer", + group: "nursery", + desc: "using a mutex for an integer type", + deprecation: None, + module: "mutex_atomic", + }, + Lint { + name: "naive_bytecount", + group: "perf", + desc: "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values", + deprecation: None, + module: "bytecount", + }, + Lint { + name: "needless_bool", + group: "complexity", + desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", + deprecation: None, + module: "needless_bool", + }, + Lint { + name: "needless_borrow", + group: "nursery", + desc: "taking a reference that is going to be automatically dereferenced", + deprecation: None, + module: "needless_borrow", + }, + Lint { + name: "needless_borrowed_reference", + group: "complexity", + desc: "taking a needless borrowed reference", + deprecation: None, + module: "needless_borrowed_ref", + }, + Lint { + name: "needless_collect", + group: "perf", + desc: "collecting an iterator when collect is not needed", + deprecation: None, + module: "loops", + }, + Lint { + name: "needless_continue", + group: "pedantic", + desc: "`continue` statements that can be replaced by a rearrangement of code", + deprecation: None, + module: "needless_continue", + }, + Lint { + name: "needless_lifetimes", + group: "complexity", + desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", + deprecation: None, + module: "lifetimes", + }, + Lint { + name: "needless_pass_by_value", + group: "pedantic", + desc: "functions taking arguments by value, but not consuming them in its body", + deprecation: None, + module: "needless_pass_by_value", + }, + Lint { + name: "needless_range_loop", + group: "style", + desc: "for-looping over a range of indices where an iterator over items would do", + deprecation: None, + module: "loops", + }, + Lint { + name: "needless_return", + group: "style", + desc: "using a return statement like `return expr;` where an expression would suffice", + deprecation: None, + module: "returns", + }, + Lint { + name: "needless_update", + group: "complexity", + desc: "using `Foo { ..base }` when there are no missing fields", + deprecation: None, + module: "needless_update", + }, + Lint { + name: "neg_cmp_op_on_partial_ord", + group: "complexity", + desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", + deprecation: None, + module: "neg_cmp_op_on_partial_ord", + }, + Lint { + name: "neg_multiply", + group: "style", + desc: "multiplying integers with -1", + deprecation: None, + module: "neg_multiply", + }, + Lint { + name: "never_loop", + group: "correctness", + desc: "any loop that will always `break` or `return`", + deprecation: None, + module: "loops", + }, + Lint { + name: "new_ret_no_self", + group: "style", + desc: "not returning `Self` in a `new` method", + deprecation: None, + module: "methods", + }, + Lint { + name: "new_without_default", + group: "style", + desc: "`fn new() -> Self` method without `Default` implementation", + deprecation: None, + module: "new_without_default", + }, + Lint { + name: "no_effect", + group: "complexity", + desc: "statements with no effect", + deprecation: None, + module: "no_effect", + }, + Lint { + name: "non_ascii_literal", + group: "pedantic", + desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", + deprecation: None, + module: "unicode", + }, + Lint { + name: "nonminimal_bool", + group: "complexity", + desc: "boolean expressions that can be written more concisely", + deprecation: None, + module: "booleans", + }, + Lint { + name: "nonsensical_open_options", + group: "correctness", + desc: "nonsensical combination of options for opening a file", + deprecation: None, + module: "open_options", + }, + Lint { + name: "not_unsafe_ptr_arg_deref", + group: "correctness", + desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", + deprecation: None, + module: "functions", + }, + Lint { + name: "ok_expect", + group: "style", + desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", + deprecation: None, + module: "methods", + }, + Lint { + name: "op_ref", + group: "style", + desc: "taking a reference to satisfy the type constraints on `==`", + deprecation: None, + module: "eq_op", + }, + Lint { + name: "option_map_or_none", + group: "style", + desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_map_unit_fn", + group: "complexity", + desc: "using `option.map(f)`, where f is a function or closure that returns ()", + deprecation: None, + module: "map_unit_fn", + }, + Lint { + name: "option_map_unwrap_or", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_map_unwrap_or_else", + group: "pedantic", + desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "option_option", + group: "complexity", + desc: "usage of `Option<Option<T>>`", + deprecation: None, + module: "types", + }, + Lint { + name: "option_unwrap_used", + group: "restriction", + desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", + deprecation: None, + module: "methods", + }, + Lint { + name: "or_fun_call", + group: "perf", + desc: "using any `*or` method with a function call, which suggests `*or_else`", + deprecation: None, + module: "methods", + }, + Lint { + name: "out_of_bounds_indexing", + group: "correctness", + desc: "out of bounds constant indexing", + deprecation: None, + module: "indexing_slicing", + }, + Lint { + name: "overflow_check_conditional", + group: "complexity", + desc: "overflow checks inspired by C which are likely to panic", + deprecation: None, + module: "overflow_check_conditional", + }, + Lint { + name: "panic_params", + group: "style", + desc: "missing parameters in `panic!` calls", + deprecation: None, + module: "panic_unimplemented", + }, + Lint { + name: "panicking_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that will always fail", + deprecation: None, + module: "unwrap", + }, + Lint { + name: "partialeq_ne_impl", + group: "complexity", + desc: "re-implementing `PartialEq::ne`", + deprecation: None, + module: "partialeq_ne_impl", + }, + Lint { + name: "path_buf_push_overwrite", + group: "nursery", + desc: "calling `push` with file system root on `PathBuf` can overwrite it", + deprecation: None, + module: "path_buf_push_overwrite", + }, + Lint { + name: "possible_missing_comma", + group: "correctness", + desc: "possible missing comma in array", + deprecation: None, + module: "formatting", + }, + Lint { + name: "precedence", + group: "complexity", + desc: "operations where precedence may be unclear", + deprecation: None, + module: "precedence", + }, + Lint { + name: "print_literal", + group: "style", + desc: "printing a literal with a format string", + deprecation: None, + module: "write", + }, + Lint { + name: "print_stdout", + group: "restriction", + desc: "printing on stdout", + deprecation: None, + module: "write", + }, + Lint { + name: "print_with_newline", + group: "style", + desc: "using `print!()` with a format string that ends in a single newline", + deprecation: None, + module: "write", + }, + Lint { + name: "println_empty_string", + group: "style", + desc: "using `println!(\"\")` with an empty string", + deprecation: None, + module: "write", + }, + Lint { + name: "ptr_arg", + group: "style", + desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", + deprecation: None, + module: "ptr", + }, + Lint { + name: "ptr_offset_with_cast", + group: "complexity", + desc: "unneeded pointer offset cast", + deprecation: None, + module: "ptr_offset_with_cast", + }, + Lint { + name: "pub_enum_variant_names", + group: "pedantic", + desc: "enums where all variants share a prefix/postfix", + deprecation: None, + module: "enum_variants", + }, + Lint { + name: "question_mark", + group: "style", + desc: "checks for expressions that could be replaced by the question mark operator", + deprecation: None, + module: "question_mark", + }, + Lint { + name: "range_minus_one", + group: "complexity", + desc: "`x..=(y-1)` reads better as `x..y`", + deprecation: None, + module: "ranges", + }, + Lint { + name: "range_plus_one", + group: "complexity", + desc: "`x..(y+1)` reads better as `x..=y`", + deprecation: None, + module: "ranges", + }, + Lint { + name: "range_zip_with_len", + group: "complexity", + desc: "zipping iterator with a range when `enumerate()` would do", + deprecation: None, + module: "ranges", + }, + Lint { + name: "redundant_clone", + group: "nursery", + desc: "`clone()` of an owned value that is going to be dropped immediately", + deprecation: None, + module: "redundant_clone", + }, + Lint { + name: "redundant_closure", + group: "style", + desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", + deprecation: None, + module: "eta_reduction", + }, + Lint { + name: "redundant_closure_call", + group: "complexity", + desc: "throwaway closures called in the expression they are defined", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "redundant_closure_for_method_calls", + group: "pedantic", + desc: "redundant closures for method calls", + deprecation: None, + module: "eta_reduction", + }, + Lint { + name: "redundant_field_names", + group: "style", + desc: "checks for fields in struct literals where shorthands could be used", + deprecation: None, + module: "redundant_field_names", + }, + Lint { + name: "redundant_pattern", + group: "style", + desc: "using `name @ _` in a pattern", + deprecation: None, + module: "misc", + }, + Lint { + name: "redundant_pattern_matching", + group: "style", + desc: "use the proper utility function avoiding an `if let`", + deprecation: None, + module: "redundant_pattern_matching", + }, + Lint { + name: "ref_in_deref", + group: "complexity", + desc: "Use of reference in auto dereference expression.", + deprecation: None, + module: "reference", + }, + Lint { + name: "regex_macro", + group: "style", + desc: "use of `regex!(_)` instead of `Regex::new(_)`", + deprecation: None, + module: "regex", + }, + Lint { + name: "replace_consts", + group: "pedantic", + desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", + deprecation: None, + module: "replace_consts", + }, + Lint { + name: "result_map_unit_fn", + group: "complexity", + desc: "using `result.map(f)`, where f is a function or closure that returns ()", + deprecation: None, + module: "map_unit_fn", + }, + Lint { + name: "result_map_unwrap_or_else", + group: "pedantic", + desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", + deprecation: None, + module: "methods", + }, + Lint { + name: "result_unwrap_used", + group: "restriction", + desc: "using `Result.unwrap()`, which might be better handled", + deprecation: None, + module: "methods", + }, + Lint { + name: "reverse_range_loop", + group: "correctness", + desc: "iteration over an empty range, such as `10..0` or `5..5`", + deprecation: None, + module: "loops", + }, + Lint { + name: "search_is_some", + group: "complexity", + desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + deprecation: None, + module: "methods", + }, + Lint { + name: "serde_api_misuse", + group: "correctness", + desc: "various things that will negatively affect your serde experience", + deprecation: None, + module: "serde_api", + }, + Lint { + name: "shadow_reuse", + group: "restriction", + desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", + deprecation: None, + module: "shadow", + }, + Lint { + name: "shadow_same", + group: "restriction", + desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", + deprecation: None, + module: "shadow", + }, + Lint { + name: "shadow_unrelated", + group: "pedantic", + desc: "rebinding a name without even using the original value", + deprecation: None, + module: "shadow", + }, + Lint { + name: "short_circuit_statement", + group: "complexity", + desc: "using a short circuit boolean condition as a statement", + deprecation: None, + module: "misc", + }, + Lint { + name: "should_implement_trait", + group: "style", + desc: "defining a method that should be implementing a std trait", + deprecation: None, + module: "methods", + }, + Lint { + name: "similar_names", + group: "pedantic", + desc: "similarly named items and bindings", + deprecation: None, + module: "non_expressive_names", + }, + Lint { + name: "single_char_pattern", + group: "perf", + desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", + deprecation: None, + module: "methods", + }, + Lint { + name: "single_match", + group: "style", + desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", + deprecation: None, + module: "matches", + }, + Lint { + name: "single_match_else", + group: "pedantic", + desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", + deprecation: None, + module: "matches", + }, + Lint { + name: "slow_vector_initialization", + group: "perf", + desc: "slow vector initialization", + deprecation: None, + module: "slow_vector_initialization", + }, + Lint { + name: "string_add", + group: "restriction", + desc: "using `x + ..` where x is a `String` instead of `push_str()`", + deprecation: None, + module: "strings", + }, + Lint { + name: "string_add_assign", + group: "pedantic", + desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", + deprecation: None, + module: "strings", + }, + Lint { + name: "string_extend_chars", + group: "style", + desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", + deprecation: None, + module: "methods", + }, + Lint { + name: "string_lit_as_bytes", + group: "style", + desc: "calling `as_bytes` on a string literal instead of using a byte string literal", + deprecation: None, + module: "strings", + }, + Lint { + name: "suspicious_arithmetic_impl", + group: "correctness", + desc: "suspicious use of operators in impl of arithmetic trait", + deprecation: None, + module: "suspicious_trait_impl", + }, + Lint { + name: "suspicious_assignment_formatting", + group: "style", + desc: "suspicious formatting of `*=`, `-=` or `!=`", + deprecation: None, + module: "formatting", + }, + Lint { + name: "suspicious_else_formatting", + group: "style", + desc: "suspicious formatting of `else`", + deprecation: None, + module: "formatting", + }, + Lint { + name: "suspicious_op_assign_impl", + group: "correctness", + desc: "suspicious use of operators in impl of OpAssign trait", + deprecation: None, + module: "suspicious_trait_impl", + }, + Lint { + name: "temporary_assignment", + group: "complexity", + desc: "assignments to temporaries", + deprecation: None, + module: "temporary_assignment", + }, + Lint { + name: "temporary_cstring_as_ptr", + group: "correctness", + desc: "getting the inner pointer of a temporary `CString`", + deprecation: None, + module: "methods", + }, + Lint { + name: "too_many_arguments", + group: "complexity", + desc: "functions with too many arguments", + deprecation: None, + module: "functions", + }, + Lint { + name: "too_many_lines", + group: "pedantic", + desc: "functions with too many lines", + deprecation: None, + module: "functions", + }, + Lint { + name: "toplevel_ref_arg", + group: "style", + desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", + deprecation: None, + module: "misc", + }, + Lint { + name: "transmute_bytes_to_str", + group: "complexity", + desc: "transmutes from a `&[u8]` to a `&str`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_bool", + group: "complexity", + desc: "transmutes from an integer to a `bool`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_char", + group: "complexity", + desc: "transmutes from an integer to a `char`", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_int_to_float", + group: "complexity", + desc: "transmutes from an integer to a float", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_ptr_to_ptr", + group: "complexity", + desc: "transmutes from a pointer to a pointer / a reference to a reference", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmute_ptr_to_ref", + group: "complexity", + desc: "transmutes from a pointer to a reference type", + deprecation: None, + module: "transmute", + }, + Lint { + name: "transmuting_null", + group: "correctness", + desc: "transmutes from a null pointer to a reference, which is undefined behavior", + deprecation: None, + module: "transmuting_null", + }, + Lint { + name: "trivial_regex", + group: "style", + desc: "trivial regular expressions", + deprecation: None, + module: "regex", + }, + Lint { + name: "trivially_copy_pass_by_ref", + group: "perf", + desc: "functions taking small copyable arguments by reference", + deprecation: None, + module: "trivially_copy_pass_by_ref", + }, + Lint { + name: "type_complexity", + group: "complexity", + desc: "usage of very complex types that might be better factored into `type` definitions", + deprecation: None, + module: "types", + }, + Lint { + name: "unicode_not_nfc", + group: "pedantic", + desc: "using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", + deprecation: None, + module: "unicode", + }, + Lint { + name: "unimplemented", + group: "restriction", + desc: "`unimplemented!` should not be present in production code", + deprecation: None, + module: "panic_unimplemented", + }, + Lint { + name: "unit_arg", + group: "complexity", + desc: "passing unit to a function", + deprecation: None, + module: "types", + }, + Lint { + name: "unit_cmp", + group: "correctness", + desc: "comparing unit values", + deprecation: None, + module: "types", + }, + Lint { + name: "unknown_clippy_lints", + group: "style", + desc: "unknown_lints for scoped Clippy lints", + deprecation: None, + module: "attrs", + }, + Lint { + name: "unnecessary_cast", + group: "complexity", + desc: "cast to the same type, e.g., `x as i32` where `x: i32`", + deprecation: None, + module: "types", + }, + Lint { + name: "unnecessary_filter_map", + group: "complexity", + desc: "using `filter_map` when a more succinct alternative exists", + deprecation: None, + module: "methods", + }, + Lint { + name: "unnecessary_fold", + group: "style", + desc: "using `fold` when a more succinct alternative exists", + deprecation: None, + module: "methods", + }, + Lint { + name: "unnecessary_mut_passed", + group: "style", + desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", + deprecation: None, + module: "mut_reference", + }, + Lint { + name: "unnecessary_operation", + group: "complexity", + desc: "outer expressions with no effect", + deprecation: None, + module: "no_effect", + }, + Lint { + name: "unnecessary_unwrap", + group: "nursery", + desc: "checks for calls of unwrap[_err]() that cannot fail", + deprecation: None, + module: "unwrap", + }, + Lint { + name: "unneeded_field_pattern", + group: "style", + desc: "struct fields bound to a wildcard instead of using `..`", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "unreadable_literal", + group: "style", + desc: "long integer literal without underscores", + deprecation: None, + module: "literal_representation", + }, + Lint { + name: "unsafe_removed_from_name", + group: "style", + desc: "`unsafe` removed from API names on import", + deprecation: None, + module: "unsafe_removed_from_name", + }, + Lint { + name: "unseparated_literal_suffix", + group: "pedantic", + desc: "literals whose suffix is not separated by an underscore", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "unused_collect", + group: "perf", + desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", + deprecation: None, + module: "loops", + }, + Lint { + name: "unused_io_amount", + group: "correctness", + desc: "unused written/read amount", + deprecation: None, + module: "unused_io_amount", + }, + Lint { + name: "unused_label", + group: "complexity", + desc: "unused labels", + deprecation: None, + module: "unused_label", + }, + Lint { + name: "unused_unit", + group: "style", + desc: "needless unit expression", + deprecation: None, + module: "returns", + }, + Lint { + name: "use_debug", + group: "restriction", + desc: "use of `Debug`-based formatting", + deprecation: None, + module: "write", + }, + Lint { + name: "use_self", + group: "pedantic", + desc: "Unnecessary structure name repetition whereas `Self` is applicable", + deprecation: None, + module: "use_self", + }, + Lint { + name: "used_underscore_binding", + group: "pedantic", + desc: "using a binding which is prefixed with an underscore", + deprecation: None, + module: "misc", + }, + Lint { + name: "useless_asref", + group: "complexity", + desc: "using `as_ref` where the types before and after the call are the same", + deprecation: None, + module: "methods", + }, + Lint { + name: "useless_attribute", + group: "correctness", + desc: "use of lint attributes on `extern crate` items", + deprecation: None, + module: "attrs", + }, + Lint { + name: "useless_format", + group: "complexity", + desc: "useless use of `format!`", + deprecation: None, + module: "format", + }, + Lint { + name: "useless_let_if_seq", + group: "style", + desc: "unidiomatic `let mut` declaration followed by initialization in `if`", + deprecation: None, + module: "let_if_seq", + }, + Lint { + name: "useless_transmute", + group: "complexity", + desc: "transmutes that have the same to and from types or could be a cast/coercion", + deprecation: None, + module: "transmute", + }, + Lint { + name: "useless_vec", + group: "perf", + desc: "useless `vec!`", + deprecation: None, + module: "vec", + }, + Lint { + name: "vec_box", + group: "complexity", + desc: "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap", + deprecation: None, + module: "types", + }, + Lint { + name: "verbose_bit_mask", + group: "style", + desc: "expressions where a bit mask is less readable than the corresponding method call", + deprecation: None, + module: "bit_mask", + }, + Lint { + name: "while_immutable_condition", + group: "correctness", + desc: "variables used within while expression are not mutated in the body", + deprecation: None, + module: "loops", + }, + Lint { + name: "while_let_loop", + group: "complexity", + desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", + deprecation: None, + module: "loops", + }, + Lint { + name: "while_let_on_iterator", + group: "style", + desc: "using a while-let loop instead of a for loop on an iterator", + deprecation: None, + module: "loops", + }, + Lint { + name: "wildcard_dependencies", + group: "cargo", + desc: "wildcard dependencies being used", + deprecation: None, + module: "wildcard_dependencies", + }, + Lint { + name: "wildcard_enum_match_arm", + group: "restriction", + desc: "a wildcard enum match arm using `_`", + deprecation: None, + module: "matches", + }, + Lint { + name: "write_literal", + group: "style", + desc: "writing a literal with a format string", + deprecation: None, + module: "write", + }, + Lint { + name: "write_with_newline", + group: "style", + desc: "using `write!()` with a format string that ends in a single newline", + deprecation: None, + module: "write", + }, + Lint { + name: "writeln_empty_string", + group: "style", + desc: "using `writeln!(buf, \"\")` with an empty string", + deprecation: None, + module: "write", + }, + Lint { + name: "wrong_pub_self_convention", + group: "restriction", + desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + deprecation: None, + module: "methods", + }, + Lint { + name: "wrong_self_convention", + group: "style", + desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", + deprecation: None, + module: "methods", + }, + Lint { + name: "wrong_transmute", + group: "correctness", + desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", + deprecation: None, + module: "transmute", + }, + Lint { + name: "zero_divided_by_zero", + group: "complexity", + desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", + deprecation: None, + module: "zero_div_zero", + }, + Lint { + name: "zero_prefixed_literal", + group: "complexity", + desc: "integer literals starting with `0`", + deprecation: None, + module: "misc_early", + }, + Lint { + name: "zero_ptr", + group: "style", + desc: "using 0 as *{const, mut} T", + deprecation: None, + module: "misc", + }, + Lint { + name: "zero_width_space", + group: "correctness", + desc: "using a zero-width space in a string literal, which is confusing", + deprecation: None, + module: "unicode", + }, +]; -- cgit 1.4.1-3-g733a5 From 296794dec5698abda5cacf644049cafc627a1bb6 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Sat, 8 Jun 2019 14:19:16 -0700 Subject: prelim arg parse --- clippy_dev/src/main.rs | 4 +- src/driver.rs | 156 ++++++++++++++++++++++++++++++++++++++++++------- src/lintlist/mod.rs | 4 +- 3 files changed, 139 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index e33b052cf28..e3a4378d524 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -100,8 +100,8 @@ fn update_lints(update_mode: &UpdateMode) { "\ //! This file is managed by util/dev update_lints. Do not edit. -mod lint; -use lint::Lint; +pub mod lint; +pub use lint::Lint; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", sorted_usable_lints.len(), diff --git a/src/driver.rs b/src/driver.rs index dc4ff3e8e2a..395d96a28e8 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -110,21 +110,108 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } } -pub fn main() { - rustc_driver::init_rustc_env_logger(); - exit( - rustc_driver::report_ices_to_stderr_if_any(move || { - use std::env; +fn describe_lints() { + use lintlist::*; - if std::env::args().any(|a| a == "--version" || a == "-V") { - let version_info = rustc_tools_util::get_version_info!(); - println!("{}", version_info); - exit(0); - } + println!( + " +Available lint options: + -W <foo> Warn about <foo> + -A <foo> Allow <foo> + -D <foo> Deny <foo> + -F <foo> Forbid <foo> (deny <foo> and all attempts to override) - if std::env::args().any(|a| a == "--help" || a == "-h") { - println!( - "\ +" + ); + + let mut lints: Vec<_> = ALL_LINTS.iter().collect(); + // The sort doesn't case-fold but it's doubtful we care. + lints.sort_by_cached_key(|x: &&Lint| ("unknown", x.name)); + + let max_name_len = lints + .iter() + .map(|lint| lint.name.len()) + .map(|len| len + "clippy::".len()) + .max() + .unwrap_or(0); + + let padded = |x: &str| { + let mut s = " ".repeat(max_name_len - x.chars().count()); + s.push_str(x); + s + }; + + let scoped = |x: &str| format!("clippy::{}", x); + + println!("Lint checks provided by clippy:\n"); + println!(" {} {:7.7} meaning", padded("name"), "default"); + println!(" {} {:7.7} -------", padded("----"), "-------"); + + let print_lints = |lints: Vec<&Lint>| { + for lint in lints { + let name = lint.name.replace("_", "-"); + println!(" {} {:7.7} {}", padded(&scoped(&name)), "unknown", lint.desc); + } + println!("\n"); + }; + + print_lints(lints); + + // let max_name_len = max("warnings".len(), + // plugin_groups.iter() + // .chain(&builtin_groups) + // .map(|&(s, _)| s.chars().count()) + // .max() + // .unwrap_or(0)); + + // let padded = |x: &str| { + // let mut s = " ".repeat(max_name_len - x.chars().count()); + // s.push_str(x); + // s + // }; + + // println!("Lint groups provided by rustc:\n"); + // println!(" {} {}", padded("name"), "sub-lints"); + // println!(" {} {}", padded("----"), "---------"); + // println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings"); + + // let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| { + // for (name, to) in lints { + // let name = name.to_lowercase().replace("_", "-"); + // let desc = to.into_iter() + // .map(|x| x.to_string().replace("_", "-")) + // .collect::<Vec<String>>() + // .join(", "); + // println!(" {} {}", padded(&name), desc); + // } + // println!("\n"); + // }; + + // print_lint_groups(builtin_groups); + + // match (loaded_plugins, plugin.len(), plugin_groups.len()) { + // (false, 0, _) | (false, _, 0) => { + // println!("Compiler plugins can provide additional lints and lint groups. To see a \ + // listing of these, re-run `rustc -W help` with a crate filename."); + // } + // (false, ..) => panic!("didn't load lint plugins but got them anyway!"), + // (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), + // (true, l, g) => { + // if l > 0 { + // println!("Lint checks provided by plugins loaded by this crate:\n"); + // print_lints(plugin); + // } + // if g > 0 { + // println!("Lint groups provided by plugins loaded by this crate:\n"); + // print_lint_groups(plugin_groups); + // } + // } + // } +} + +fn display_help() { + println!( + "\ Checks a package to catch common mistakes and improve your Rust code. Usage: @@ -148,11 +235,18 @@ You can use tool lints to allow or deny lints from your code, eg.: #[allow(clippy::needless_lifetimes)] " - ); + ); +} - for lint in &lintlist::ALL_LINTS[..] { - println!("clippy::{},", lint.name); - } +pub fn main() { + rustc_driver::init_rustc_env_logger(); + exit( + rustc_driver::report_ices_to_stderr_if_any(move || { + use std::env; + + if std::env::args().any(|a| a == "--version" || a == "-V") { + let version_info = rustc_tools_util::get_version_info!(); + println!("{}", version_info); exit(0); } @@ -189,13 +283,33 @@ You can use tool lints to allow or deny lints from your code, eg.: // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - if orig_args.len() <= 1 { - std::process::exit(1); - } - if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) { + let wrapper_mode = Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()); + + if wrapper_mode { // we still want to be able to invoke it normally though orig_args.remove(1); } + + if !wrapper_mode && std::env::args().any(|a| a == "--help" || a == "-h") { + display_help(); + exit(0); + } + + let args: Vec<_> = std::env::args().collect(); + + if !wrapper_mode + && args.windows(2).any(|args| { + args[1] == "help" + && match args[0].as_str() { + "-W" | "-A" | "-D" | "-F" => true, + _ => false, + } + }) + { + describe_lints(); + exit(0); + } + // this conditional check for the --sysroot flag is there so users can call // `clippy_driver` directly // without having to pass --sysroot or anything diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index cf367bcc632..ea26224b3e4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1,7 +1,7 @@ //! This file is managed by util/dev update_lints. Do not edit. -mod lint; -use lint::Lint; +pub mod lint; +pub use lint::Lint; pub const ALL_LINTS: [Lint; 304] = [ Lint { -- cgit 1.4.1-3-g733a5 From 07ccec86a5e497f47c4f91f8bcba45d356ded292 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Sat, 8 Jun 2019 14:49:33 -0700 Subject: group printing --- src/driver.rs | 85 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 395d96a28e8..94c89d82c8f 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -112,6 +112,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { fn describe_lints() { use lintlist::*; + use std::collections::HashSet; println!( " @@ -143,11 +144,13 @@ Available lint options: let scoped = |x: &str| format!("clippy::{}", x); + let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect(); + println!("Lint checks provided by clippy:\n"); println!(" {} {:7.7} meaning", padded("name"), "default"); println!(" {} {:7.7} -------", padded("----"), "-------"); - let print_lints = |lints: Vec<&Lint>| { + let print_lints = |lints: &[&Lint]| { for lint in lints { let name = lint.name.replace("_", "-"); println!(" {} {:7.7} {}", padded(&scoped(&name)), "unknown", lint.desc); @@ -155,37 +158,44 @@ Available lint options: println!("\n"); }; - print_lints(lints); - - // let max_name_len = max("warnings".len(), - // plugin_groups.iter() - // .chain(&builtin_groups) - // .map(|&(s, _)| s.chars().count()) - // .max() - // .unwrap_or(0)); - - // let padded = |x: &str| { - // let mut s = " ".repeat(max_name_len - x.chars().count()); - // s.push_str(x); - // s - // }; - - // println!("Lint groups provided by rustc:\n"); - // println!(" {} {}", padded("name"), "sub-lints"); - // println!(" {} {}", padded("----"), "---------"); - // println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings"); - - // let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| { - // for (name, to) in lints { - // let name = name.to_lowercase().replace("_", "-"); - // let desc = to.into_iter() - // .map(|x| x.to_string().replace("_", "-")) - // .collect::<Vec<String>>() - // .join(", "); - // println!(" {} {}", padded(&name), desc); - // } - // println!("\n"); - // }; + print_lints(&lints); + + let max_name_len = std::cmp::max( + "warnings".len(), + lint_groups + .iter() + .map(|group| group.len()) + .map(|len| len + "clippy::".len()) + .max() + .unwrap_or(0), + ); + + let padded = |x: &str| { + let mut s = " ".repeat(max_name_len - x.chars().count()); + s.push_str(x); + s + }; + + println!("Lint groups provided by rustc:\n"); + println!(" {} sub-lints", padded("name")); + println!(" {} ---------", padded("----")); + // println!(" {} all lints that are set to issue warnings", padded("warnings")); + + let print_lint_groups = || { + for group in lint_groups { + let name = group.to_lowercase().replace("_", "-"); + let desc = lints.iter() + .filter(|&lint| lint.group == group) + .map(|lint| lint.name) + .map(|name| name.replace("_", "-")) + .collect::<Vec<String>>() + .join(", "); + println!(" {} {}", padded(&name), desc); + } + println!("\n"); + }; + + print_lint_groups(); // print_lint_groups(builtin_groups); @@ -295,17 +305,18 @@ pub fn main() { exit(0); } - let args: Vec<_> = std::env::args().collect(); - - if !wrapper_mode - && args.windows(2).any(|args| { + let should_describe_lints = || { + let args: Vec<_> = std::env::args().collect(); + args.windows(2).any(|args| { args[1] == "help" && match args[0].as_str() { "-W" | "-A" | "-D" | "-F" => true, _ => false, } }) - { + }; + + if !wrapper_mode && should_describe_lints() { describe_lints(); exit(0); } -- cgit 1.4.1-3-g733a5 From cfd7e0d5fd356f492f5c165afbccaa3839222b28 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Sat, 8 Jun 2019 17:08:16 -0700 Subject: show default lint levels --- clippy_dev/src/main.rs | 1 + src/driver.rs | 37 ++++++++++++------------------------- src/lintlist/lint.rs | 30 ++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 1 + 4 files changed, 44 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index e3a4378d524..d4f798a3cae 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -102,6 +102,7 @@ fn update_lints(update_mode: &UpdateMode) { pub mod lint; pub use lint::Lint; +pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", sorted_usable_lints.len(), diff --git a/src/driver.rs b/src/driver.rs index 94c89d82c8f..9f9aba2c060 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -125,9 +125,17 @@ Available lint options: " ); + let lint_level = |lint: &Lint| { + LINT_LEVELS + .iter() + .find(|level_mapping| level_mapping.0 == lint.group) + .map(|(_, level)| level) + .unwrap() + }; + let mut lints: Vec<_> = ALL_LINTS.iter().collect(); // The sort doesn't case-fold but it's doubtful we care. - lints.sort_by_cached_key(|x: &&Lint| ("unknown", x.name)); + lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name)); let max_name_len = lints .iter() @@ -153,7 +161,7 @@ Available lint options: let print_lints = |lints: &[&Lint]| { for lint in lints { let name = lint.name.replace("_", "-"); - println!(" {} {:7.7} {}", padded(&scoped(&name)), "unknown", lint.desc); + println!(" {} {:7.7} {}", padded(&scoped(&name)), lint_level(lint), lint.desc); } println!("\n"); }; @@ -179,12 +187,12 @@ Available lint options: println!("Lint groups provided by rustc:\n"); println!(" {} sub-lints", padded("name")); println!(" {} ---------", padded("----")); - // println!(" {} all lints that are set to issue warnings", padded("warnings")); let print_lint_groups = || { for group in lint_groups { let name = group.to_lowercase().replace("_", "-"); - let desc = lints.iter() + let desc = lints + .iter() .filter(|&lint| lint.group == group) .map(|lint| lint.name) .map(|name| name.replace("_", "-")) @@ -196,27 +204,6 @@ Available lint options: }; print_lint_groups(); - - // print_lint_groups(builtin_groups); - - // match (loaded_plugins, plugin.len(), plugin_groups.len()) { - // (false, 0, _) | (false, _, 0) => { - // println!("Compiler plugins can provide additional lints and lint groups. To see a \ - // listing of these, re-run `rustc -W help` with a crate filename."); - // } - // (false, ..) => panic!("didn't load lint plugins but got them anyway!"), - // (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), - // (true, l, g) => { - // if l > 0 { - // println!("Lint checks provided by plugins loaded by this crate:\n"); - // print_lints(plugin); - // } - // if g > 0 { - // println!("Lint groups provided by plugins loaded by this crate:\n"); - // print_lint_groups(plugin_groups); - // } - // } - // } } fn display_help() { diff --git a/src/lintlist/lint.rs b/src/lintlist/lint.rs index a4dd0747059..44c4a528907 100644 --- a/src/lintlist/lint.rs +++ b/src/lintlist/lint.rs @@ -7,3 +7,33 @@ pub struct Lint { pub deprecation: Option<&'static str>, pub module: &'static str, } + +#[derive(PartialOrd, PartialEq, Ord, Eq)] +pub enum LintLevel { + Allow, + Warn, + Deny, +} + +impl std::fmt::Display for LintLevel { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = match self { + LintLevel::Allow => "allow", + LintLevel::Warn => "warn", + LintLevel::Deny => "deny", + }; + + write!(f, "{}", s) + } +} + +pub const LINT_LEVELS: [(&str, LintLevel); 8] = [ + ("correctness", LintLevel::Deny), + ("style", LintLevel::Warn), + ("complexity", LintLevel::Warn), + ("perf", LintLevel::Warn), + ("restriction", LintLevel::Allow), + ("pedantic", LintLevel::Allow), + ("nursery", LintLevel::Allow), + ("cargo", LintLevel::Allow), +]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index ea26224b3e4..3c93c41b4dc 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2,6 +2,7 @@ pub mod lint; pub use lint::Lint; +pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; 304] = [ Lint { -- cgit 1.4.1-3-g733a5 From 73259d68db9ce4cbdc281c80b9c3a2965028744d Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Mon, 10 Jun 2019 11:03:51 -0700 Subject: fix padding and put clippy someplaces --- clippy_dev/src/main.rs | 1 + src/driver.rs | 9 +++++++-- src/lintlist/lint.rs | 12 ------------ src/lintlist/mod.rs | 1 + 4 files changed, 9 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index d4f798a3cae..612300a2d62 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -103,6 +103,7 @@ fn update_lints(update_mode: &UpdateMode) { pub mod lint; pub use lint::Lint; pub use lint::LINT_LEVELS; +pub use lint::LintLevel; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", sorted_usable_lints.len(), diff --git a/src/driver.rs b/src/driver.rs index 9f9aba2c060..624d4fd4ad5 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -130,6 +130,11 @@ Available lint options: .iter() .find(|level_mapping| level_mapping.0 == lint.group) .map(|(_, level)| level) + .map(|level| match level { + LintLevel::Allow => "allow", + LintLevel::Warn => "warn", + LintLevel::Deny => "deny", + }) .unwrap() }; @@ -184,7 +189,7 @@ Available lint options: s }; - println!("Lint groups provided by rustc:\n"); + println!("Lint groups provided by clippy:\n"); println!(" {} sub-lints", padded("name")); println!(" {} ---------", padded("----")); @@ -198,7 +203,7 @@ Available lint options: .map(|name| name.replace("_", "-")) .collect::<Vec<String>>() .join(", "); - println!(" {} {}", padded(&name), desc); + println!(" {} {}", padded(&scoped(&name)), desc); } println!("\n"); }; diff --git a/src/lintlist/lint.rs b/src/lintlist/lint.rs index 44c4a528907..65e5e8472ba 100644 --- a/src/lintlist/lint.rs +++ b/src/lintlist/lint.rs @@ -15,18 +15,6 @@ pub enum LintLevel { Deny, } -impl std::fmt::Display for LintLevel { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let s = match self { - LintLevel::Allow => "allow", - LintLevel::Warn => "warn", - LintLevel::Deny => "deny", - }; - - write!(f, "{}", s) - } -} - pub const LINT_LEVELS: [(&str, LintLevel); 8] = [ ("correctness", LintLevel::Deny), ("style", LintLevel::Warn), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 3c93c41b4dc..50f67c71167 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -3,6 +3,7 @@ pub mod lint; pub use lint::Lint; pub use lint::LINT_LEVELS; +pub use lint::LintLevel; pub const ALL_LINTS: [Lint; 304] = [ Lint { -- cgit 1.4.1-3-g733a5 From 113ae891d927e4a0e4b4f79f60cd477b3a2ff8cc Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Mon, 10 Jun 2019 11:14:54 -0700 Subject: run rustfmt --- clippy_dev/src/main.rs | 2 +- src/driver.rs | 7 ++++++- src/lintlist/mod.rs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 612300a2d62..b793112b3f9 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -102,8 +102,8 @@ fn update_lints(update_mode: &UpdateMode) { pub mod lint; pub use lint::Lint; -pub use lint::LINT_LEVELS; pub use lint::LintLevel; +pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", sorted_usable_lints.len(), diff --git a/src/driver.rs b/src/driver.rs index 624d4fd4ad5..6ccd09962d3 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -166,7 +166,12 @@ Available lint options: let print_lints = |lints: &[&Lint]| { for lint in lints { let name = lint.name.replace("_", "-"); - println!(" {} {:7.7} {}", padded(&scoped(&name)), lint_level(lint), lint.desc); + println!( + " {} {:7.7} {}", + padded(&scoped(&name)), + lint_level(lint), + lint.desc + ); } println!("\n"); }; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 50f67c71167..2fc0853a4de 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2,8 +2,8 @@ pub mod lint; pub use lint::Lint; -pub use lint::LINT_LEVELS; pub use lint::LintLevel; +pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; 304] = [ Lint { -- cgit 1.4.1-3-g733a5 From a2bf96f1c607096a7dfac8065e7bd7a0be72974e Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Mon, 10 Jun 2019 15:47:31 -0700 Subject: make it pass dogfood --- clippy_dev/src/main.rs | 4 ++-- src/driver.rs | 29 +++++++++++++++-------------- src/lintlist/lint.rs | 20 ++++++++++---------- src/lintlist/mod.rs | 4 ++-- 4 files changed, 29 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index b793112b3f9..fedbb661763 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -98,11 +98,11 @@ fn update_lints(update_mode: &UpdateMode) { "../src/lintlist/mod.rs", &format!( "\ -//! This file is managed by util/dev update_lints. Do not edit. +//! This file is managed by `util/dev update_lints`. Do not edit. pub mod lint; +pub use lint::Level; pub use lint::Lint; -pub use lint::LintLevel; pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; {}] = {:#?};\n", diff --git a/src/driver.rs b/src/driver.rs index 6ccd09962d3..468951cd4b0 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -110,6 +110,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } } +#[allow(clippy::find_map, clippy::filter_map)] fn describe_lints() { use lintlist::*; use std::collections::HashSet; @@ -129,11 +130,10 @@ Available lint options: LINT_LEVELS .iter() .find(|level_mapping| level_mapping.0 == lint.group) - .map(|(_, level)| level) - .map(|level| match level { - LintLevel::Allow => "allow", - LintLevel::Warn => "warn", - LintLevel::Deny => "deny", + .map(|(_, level)| match level { + Level::Allow => "allow", + Level::Warn => "warn", + Level::Deny => "deny", }) .unwrap() }; @@ -142,7 +142,7 @@ Available lint options: // The sort doesn't case-fold but it's doubtful we care. lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name)); - let max_name_len = lints + let max_lint_name_len = lints .iter() .map(|lint| lint.name.len()) .map(|len| len + "clippy::".len()) @@ -150,7 +150,7 @@ Available lint options: .unwrap_or(0); let padded = |x: &str| { - let mut s = " ".repeat(max_name_len - x.chars().count()); + let mut s = " ".repeat(max_lint_name_len - x.chars().count()); s.push_str(x); s }; @@ -178,8 +178,8 @@ Available lint options: print_lints(&lints); - let max_name_len = std::cmp::max( - "warnings".len(), + let max_group_name_len = std::cmp::max( + "all".len(), lint_groups .iter() .map(|group| group.len()) @@ -188,15 +188,16 @@ Available lint options: .unwrap_or(0), ); - let padded = |x: &str| { - let mut s = " ".repeat(max_name_len - x.chars().count()); + let padded_group = |x: &str| { + let mut s = " ".repeat(max_group_name_len - x.chars().count()); s.push_str(x); s }; println!("Lint groups provided by clippy:\n"); - println!(" {} sub-lints", padded("name")); - println!(" {} ---------", padded("----")); + println!(" {} sub-lints", padded_group("name")); + println!(" {} ---------", padded_group("----")); + println!(" {} the set of all clippy lints", padded_group("clippy::all")); let print_lint_groups = || { for group in lint_groups { @@ -208,7 +209,7 @@ Available lint options: .map(|name| name.replace("_", "-")) .collect::<Vec<String>>() .join(", "); - println!(" {} {}", padded(&scoped(&name)), desc); + println!(" {} {}", padded_group(&scoped(&name)), desc); } println!("\n"); }; diff --git a/src/lintlist/lint.rs b/src/lintlist/lint.rs index 65e5e8472ba..c817d83b33a 100644 --- a/src/lintlist/lint.rs +++ b/src/lintlist/lint.rs @@ -9,19 +9,19 @@ pub struct Lint { } #[derive(PartialOrd, PartialEq, Ord, Eq)] -pub enum LintLevel { +pub enum Level { Allow, Warn, Deny, } -pub const LINT_LEVELS: [(&str, LintLevel); 8] = [ - ("correctness", LintLevel::Deny), - ("style", LintLevel::Warn), - ("complexity", LintLevel::Warn), - ("perf", LintLevel::Warn), - ("restriction", LintLevel::Allow), - ("pedantic", LintLevel::Allow), - ("nursery", LintLevel::Allow), - ("cargo", LintLevel::Allow), +pub const LINT_LEVELS: [(&str, Level); 8] = [ + ("correctness", Level::Deny), + ("style", Level::Warn), + ("complexity", Level::Warn), + ("perf", Level::Warn), + ("restriction", Level::Allow), + ("pedantic", Level::Allow), + ("nursery", Level::Allow), + ("cargo", Level::Allow), ]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2fc0853a4de..3317ccb5ed0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1,8 +1,8 @@ -//! This file is managed by util/dev update_lints. Do not edit. +//! This file is managed by `util/dev update_lints`. Do not edit. pub mod lint; +pub use lint::Level; pub use lint::Lint; -pub use lint::LintLevel; pub use lint::LINT_LEVELS; pub const ALL_LINTS: [Lint; 304] = [ -- cgit 1.4.1-3-g733a5 From 2719c1e6a3bd9a5bf76c510cf30c6d103e24ade2 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Wed, 12 Jun 2019 12:29:23 -0700 Subject: minor fix --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 468951cd4b0..e6b04bf0cfd 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -179,7 +179,7 @@ Available lint options: print_lints(&lints); let max_group_name_len = std::cmp::max( - "all".len(), + "clippy::all".len(), lint_groups .iter() .map(|group| group.len()) -- cgit 1.4.1-3-g733a5 From 0e480ca4bc45fa5b104874a1e57d74ac2a527362 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Fri, 14 Jun 2019 10:36:43 +0200 Subject: Use replace_region_in_file for creating the lint list --- clippy_dev/src/main.rs | 33 +++++++++++++++++---------------- src/lintlist/mod.rs | 25 +++++++++++++++++-------- 2 files changed, 34 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index fedbb661763..302db24c74e 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -94,25 +94,26 @@ fn update_lints(update_mode: &UpdateMode) { let mut sorted_usable_lints = usable_lints.clone(); sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); - std::fs::write( + let mut file_change = replace_region_in_file( "../src/lintlist/mod.rs", - &format!( - "\ -//! This file is managed by `util/dev update_lints`. Do not edit. - -pub mod lint; -pub use lint::Level; -pub use lint::Lint; -pub use lint::LINT_LEVELS; - -pub const ALL_LINTS: [Lint; {}] = {:#?};\n", - sorted_usable_lints.len(), - sorted_usable_lints - ), + "begin lint list", + "end lint list", + false, + update_mode == &UpdateMode::Change, + || { + format!( + "pub const ALL_LINTS: [Lint; {}] = {:#?};", + sorted_usable_lints.len(), + sorted_usable_lints + ) + .lines() + .map(ToString::to_string) + .collect::<Vec<_>>() + }, ) - .expect("can write to file"); + .changed; - let mut file_change = replace_region_in_file( + file_change |= replace_region_in_file( "../README.md", r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#, "", diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 3317ccb5ed0..f28bbf31539 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -5,7 +5,8 @@ pub use lint::Level; pub use lint::Lint; pub use lint::LINT_LEVELS; -pub const ALL_LINTS: [Lint; 304] = [ +// begin lint list, do not remove this comment, it’s used in `update_lints` +pub const ALL_LINTS: [Lint; 305] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -251,13 +252,6 @@ pub const ALL_LINTS: [Lint; 304] = [ deprecation: None, module: "collapsible_if", }, - Lint { - name: "const_static_lifetime", - group: "style", - desc: "Using explicit `\'static` lifetime for constants when elision rules would allow omitting them.", - deprecation: None, - module: "const_static_lifetime", - }, Lint { name: "copy_iterator", group: "pedantic", @@ -762,6 +756,13 @@ pub const ALL_LINTS: [Lint; 304] = [ deprecation: None, module: "arithmetic", }, + Lint { + name: "integer_division", + group: "pedantic", + desc: "integer division may cause loss of precision", + deprecation: None, + module: "integer_division", + }, Lint { name: "into_iter_on_array", group: "correctness", @@ -1525,6 +1526,13 @@ pub const ALL_LINTS: [Lint; 304] = [ deprecation: None, module: "redundant_pattern_matching", }, + Lint { + name: "redundant_static_lifetimes", + group: "style", + desc: "Using explicit `\'static` lifetime for constants or statics when elision rules would allow omitting them.", + deprecation: None, + module: "redundant_static_lifetimes", + }, Lint { name: "ref_in_deref", group: "complexity", @@ -2135,3 +2143,4 @@ pub const ALL_LINTS: [Lint; 304] = [ module: "unicode", }, ]; +// end lint list, do not remove this comment, it’s used in `update_lints` -- cgit 1.4.1-3-g733a5 From f88a387c3fe32119e440ae1e8540067b38626efa Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Sat, 15 Jun 2019 00:11:53 -0700 Subject: Downgrade integer_division to restriction --- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/lib.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index 12dcfa6f661..84268fd6963 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// } /// ``` pub INTEGER_DIVISION, - pedantic, + restriction, "integer division may cause loss of precision" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cfd6070356d..b56413fc2c4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -591,6 +591,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { implicit_return::IMPLICIT_RETURN, indexing_slicing::INDEXING_SLICING, inherent_impl::MULTIPLE_INHERENT_IMPL, + integer_division::INTEGER_DIVISION, literal_representation::DECIMAL_LITERAL_REPRESENTATION, matches::WILDCARD_ENUM_MATCH_ARM, mem_forget::MEM_FORGET, @@ -626,7 +627,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { functions::TOO_MANY_LINES, if_not_else::IF_NOT_ELSE, infinite_iter::MAYBE_INFINITE_ITER, - integer_division::INTEGER_DIVISION, items_after_statements::ITEMS_AFTER_STATEMENTS, literal_representation::LARGE_DIGIT_GROUPS, loops::EXPLICIT_INTO_ITER_LOOP, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f28bbf31539..663b6a5e709 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -758,7 +758,7 @@ pub const ALL_LINTS: [Lint; 305] = [ }, Lint { name: "integer_division", - group: "pedantic", + group: "restriction", desc: "integer division may cause loss of precision", deprecation: None, module: "integer_division", -- cgit 1.4.1-3-g733a5 From 60a80849ce20bbfc3bbef741a2be8cdc7225b96d Mon Sep 17 00:00:00 2001 From: Joe Frikker <jfrikker@gmail.com> Date: Tue, 18 Jun 2019 23:22:51 -0400 Subject: Adding try_err lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 ++ clippy_lints/src/try_err.rs | 120 ++++++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/try_err.rs | 65 ++++++++++++++++++++++++ tests/ui/try_err.stderr | 32 ++++++++++++ 7 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/try_err.rs create mode 100644 tests/ui/try_err.rs create mode 100644 tests/ui/try_err.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3710342d841..461adb729f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1134,6 +1134,7 @@ Released 2018-09-13 [`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null [`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref +[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented diff --git a/README.md b/README.md index 51f618da4b7..c1a25aa1300 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 305 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 306 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b56413fc2c4..d239f14339f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -263,6 +263,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod transmuting_null; pub mod trivially_copy_pass_by_ref; +pub mod try_err; pub mod types; pub mod unicode; pub mod unsafe_removed_from_name; @@ -546,6 +547,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_early_lint_pass(box literal_representation::DecimalLiteralRepresentation::new( conf.literal_representation_threshold )); + reg.register_late_lint_pass(box try_err::TryErr); reg.register_late_lint_pass(box use_self::UseSelf); reg.register_late_lint_pass(box bytecount::ByteCount); reg.register_late_lint_pass(box infinite_iter::InfiniteIter); @@ -861,6 +863,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { transmute::WRONG_TRANSMUTE, transmuting_null::TRANSMUTING_NULL, trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, + try_err::TRY_ERR, types::ABSURD_EXTREME_COMPARISONS, types::BORROWED_BOX, types::BOX_VEC, @@ -963,6 +966,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { returns::NEEDLESS_RETURN, returns::UNUSED_UNIT, strings::STRING_LIT_AS_BYTES, + try_err::TRY_ERR, types::FN_TO_NUMERIC_CAST, types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, types::IMPLICIT_HASHER, diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs new file mode 100644 index 00000000000..ec0b96174da --- /dev/null +++ b/clippy_lints/src/try_err.rs @@ -0,0 +1,120 @@ +use crate::utils::{match_qpath, paths, snippet, span_lint_and_then}; +use if_chain::if_chain; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty::Ty; +use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// **What it does:** Checks for usages of `Err(x)?`. + /// + /// **Why is this bad?** The `?` operator is designed to allow calls that + /// can fail to be easily chained. For example, `foo()?.bar()` or + /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will + /// always return), it is more clear to write `return Err(x)`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// // Bad + /// fn foo(fail: bool) -> Result<i32, String> { + /// if fail { + /// Err("failed")?; + /// } + /// Ok(0) + /// } + /// + /// // Good + /// fn foo(fail: bool) -> Result<i32, String> { + /// if fail { + /// return Err("failed".into()); + /// } + /// Ok(0) + /// } + /// ``` + pub TRY_ERR, + style, + "return errors explicitly rather than hiding them behind a `?`" +} + +declare_lint_pass!(TryErr => [TRY_ERR]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TryErr { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + // Looks for a structure like this: + // match ::std::ops::Try::into_result(Err(5)) { + // ::std::result::Result::Err(err) => + // #[allow(unreachable_code)] + // return ::std::ops::Try::from_error(::std::convert::From::from(err)), + // ::std::result::Result::Ok(val) => + // #[allow(unreachable_code)] + // val, + // }; + if_chain! { + if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.node; + if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.node; + if let ExprKind::Path(ref match_fun_path) = match_fun.node; + if match_qpath(match_fun_path, &["std", "ops", "Try", "into_result"]); + if let Some(ref try_arg) = try_args.get(0); + if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.node; + if let Some(ref err_arg) = err_args.get(0); + if let ExprKind::Path(ref err_fun_path) = err_fun.node; + if match_qpath(err_fun_path, &paths::RESULT_ERR); + if let Some(return_type) = find_err_return_type(cx, &expr.node); + + then { + let err_type = cx.tables.expr_ty(err_arg); + let suggestion = if err_type == return_type { + format!("return Err({})", snippet(cx, err_arg.span, "_")) + } else { + format!("return Err({}.into())", snippet(cx, err_arg.span, "_")) + }; + + span_lint_and_then( + cx, + TRY_ERR, + expr.span, + &format!("confusing error return, consider using `{}`", suggestion), + |db| { + db.span_suggestion( + expr.span, + "try this", + suggestion, + Applicability::MaybeIncorrect + ); + }, + ); + } + } + } +} + +// In order to determine whether to suggest `.into()` or not, we need to find the error type the +// function returns. To do that, we look for the From::from call (see tree above), and capture +// its output type. +fn find_err_return_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx ExprKind) -> Option<Ty<'tcx>> { + if let ExprKind::Match(_, ref arms, MatchSource::TryDesugar) = expr { + arms.iter().filter_map(|ty| find_err_return_type_arm(cx, ty)).nth(0) + } else { + None + } +} + +// Check for From::from in one of the match arms. +fn find_err_return_type_arm<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arm: &'tcx Arm) -> Option<Ty<'tcx>> { + if_chain! { + if let ExprKind::Ret(Some(ref err_ret)) = arm.body.node; + if let ExprKind::Call(ref from_error_path, ref from_error_args) = err_ret.node; + if let ExprKind::Path(ref from_error_fn) = from_error_path.node; + if match_qpath(from_error_fn, &["std", "ops", "Try", "from_error"]); + if let Some(from_error_arg) = from_error_args.get(0); + then { + Some(cx.tables.expr_ty(from_error_arg)) + } else { + None + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 663b6a5e709..e8abb198e78 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 305] = [ +pub const ALL_LINTS: [Lint; 306] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1820,6 +1820,13 @@ pub const ALL_LINTS: [Lint; 305] = [ deprecation: None, module: "trivially_copy_pass_by_ref", }, + Lint { + name: "try_err", + group: "style", + desc: "TODO", + deprecation: None, + module: "try_err", + }, Lint { name: "type_complexity", group: "complexity", diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs new file mode 100644 index 00000000000..d8decbbac66 --- /dev/null +++ b/tests/ui/try_err.rs @@ -0,0 +1,65 @@ +#![deny(clippy::try_err)] + +// Tests that a simple case works +// Should flag `Err(err)?` +pub fn basic_test() -> Result<i32, i32> { + let err: i32 = 1; + Err(err)?; + Ok(0) +} + +// Tests that `.into()` is added when appropriate +pub fn into_test() -> Result<i32, i32> { + let err: u8 = 1; + Err(err)?; + Ok(0) +} + +// Tests that tries in general don't trigger the error +pub fn negative_test() -> Result<i32, i32> { + Ok(nested_error()? + 1) +} + + +// Tests that `.into()` isn't added when the error type +// matches the surrounding closure's return type, even +// when it doesn't match the surrounding function's. +pub fn closure_matches_test() -> Result<i32, i32> { + let res: Result<i32, i8> = Some(1).into_iter() + .map(|i| { + let err: i8 = 1; + Err(err)?; + Ok(i) + }) + .next() + .unwrap(); + + Ok(res?) +} + +// Tests that `.into()` isn't added when the error type +// doesn't match the surrounding closure's return type. +pub fn closure_into_test() -> Result<i32, i32> { + let res: Result<i32, i16> = Some(1).into_iter() + .map(|i| { + let err: i8 = 1; + Err(err)?; + Ok(i) + }) + .next() + .unwrap(); + + Ok(res?) +} + +fn nested_error() -> Result<i32, i32> { + Ok(1) +} + +fn main() { + basic_test().unwrap(); + into_test().unwrap(); + negative_test().unwrap(); + closure_matches_test().unwrap(); + closure_into_test().unwrap(); +} diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr new file mode 100644 index 00000000000..4e6f273052f --- /dev/null +++ b/tests/ui/try_err.stderr @@ -0,0 +1,32 @@ +error: confusing error return, consider using `return Err(err)` + --> $DIR/try_err.rs:7:5 + | +LL | Err(err)?; + | ^^^^^^^^^ help: try this: `return Err(err)` + | +note: lint level defined here + --> $DIR/try_err.rs:1:9 + | +LL | #![deny(clippy::try_err)] + | ^^^^^^^^^^^^^^^ + +error: confusing error return, consider using `return Err(err.into())` + --> $DIR/try_err.rs:14:5 + | +LL | Err(err)?; + | ^^^^^^^^^ help: try this: `return Err(err.into())` + +error: confusing error return, consider using `return Err(err)` + --> $DIR/try_err.rs:31:13 + | +LL | Err(err)?; + | ^^^^^^^^^ help: try this: `return Err(err)` + +error: confusing error return, consider using `return Err(err.into())` + --> $DIR/try_err.rs:46:13 + | +LL | Err(err)?; + | ^^^^^^^^^ help: try this: `return Err(err.into())` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 1e6c6976dd12406d2b57de17f1f667527d7977c6 Mon Sep 17 00:00:00 2001 From: Joe Frikker <jfrikker@gmail.com> Date: Sat, 22 Jun 2019 16:34:07 -0400 Subject: PR comments --- clippy_lints/src/try_err.rs | 31 +++++++++++++------------------ clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 2 +- tests/ui/try_err.stderr | 8 ++++---- 4 files changed, 19 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index ec0b96174da..eec13545956 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_qpath, paths, snippet, span_lint_and_then}; +use crate::utils::{match_qpath, paths, snippet, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -17,17 +17,17 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// - /// ```rust,ignore - /// // Bad + /// ```rust /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// Err("failed")?; /// } /// Ok(0) /// } + /// ``` + /// Could be written: /// - /// // Good + /// ```rust /// fn foo(fail: bool) -> Result<i32, String> { /// if fail { /// return Err("failed".into()); @@ -57,7 +57,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TryErr { if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.node; if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.node; if let ExprKind::Path(ref match_fun_path) = match_fun.node; - if match_qpath(match_fun_path, &["std", "ops", "Try", "into_result"]); + if match_qpath(match_fun_path, &paths::TRY_INTO_RESULT); if let Some(ref try_arg) = try_args.get(0); if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.node; if let Some(ref err_arg) = err_args.get(0); @@ -73,19 +73,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TryErr { format!("return Err({}.into())", snippet(cx, err_arg.span, "_")) }; - span_lint_and_then( + span_lint_and_sugg( cx, TRY_ERR, expr.span, - &format!("confusing error return, consider using `{}`", suggestion), - |db| { - db.span_suggestion( - expr.span, - "try this", - suggestion, - Applicability::MaybeIncorrect - ); - }, + "returning an `Err(_)` with the `?` operator", + "try this", + suggestion, + Applicability::MaybeIncorrect ); } } @@ -97,7 +92,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TryErr { // its output type. fn find_err_return_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx ExprKind) -> Option<Ty<'tcx>> { if let ExprKind::Match(_, ref arms, MatchSource::TryDesugar) = expr { - arms.iter().filter_map(|ty| find_err_return_type_arm(cx, ty)).nth(0) + arms.iter().find_map(|ty| find_err_return_type_arm(cx, ty)) } else { None } @@ -109,7 +104,7 @@ fn find_err_return_type_arm<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arm: &'tcx Arm if let ExprKind::Ret(Some(ref err_ret)) = arm.body.node; if let ExprKind::Call(ref from_error_path, ref from_error_args) = err_ret.node; if let ExprKind::Path(ref from_error_fn) = from_error_path.node; - if match_qpath(from_error_fn, &["std", "ops", "Try", "from_error"]); + if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR); if let Some(from_error_arg) = from_error_args.get(0); then { Some(cx.tables.expr_ty(from_error_arg)) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 1960618ebfa..e08ff3e9705 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -107,6 +107,7 @@ pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned" pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; +pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"]; pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"]; pub const UNINIT: [&str; 4] = ["core", "intrinsics", "", "uninit"]; pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e8abb198e78..8c49a3b1838 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1823,7 +1823,7 @@ pub const ALL_LINTS: [Lint; 306] = [ Lint { name: "try_err", group: "style", - desc: "TODO", + desc: "return errors explicitly rather than hiding them behind a `?`", deprecation: None, module: "try_err", }, diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 4e6f273052f..b2fb35ffb51 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -1,4 +1,4 @@ -error: confusing error return, consider using `return Err(err)` +error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:7:5 | LL | Err(err)?; @@ -10,19 +10,19 @@ note: lint level defined here LL | #![deny(clippy::try_err)] | ^^^^^^^^^^^^^^^ -error: confusing error return, consider using `return Err(err.into())` +error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:14:5 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` -error: confusing error return, consider using `return Err(err)` +error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:31:13 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` -error: confusing error return, consider using `return Err(err.into())` +error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:46:13 | LL | Err(err)?; -- cgit 1.4.1-3-g733a5 From c7da4c26fbff41c07fe03927847f3fe233d8b5ad Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <stucki.jeremy@gmail.com> Date: Mon, 24 Jun 2019 15:08:26 +0200 Subject: Implement flat_map lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 1 + clippy_lints/src/methods/mod.rs | 46 +++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 +++++++ 4 files changed, 55 insertions(+) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 461adb729f9..b907b7f0e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -947,6 +947,7 @@ Released 2018-09-13 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map +[`flat_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d2c9e6b987..5548bb0ab62 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -637,6 +637,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::FILTER_MAP, methods::FILTER_MAP_NEXT, methods::FIND_MAP, + methods::FLAT_MAP, methods::MAP_FLATTEN, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f689a2d4ef0..1578976ed85 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -312,6 +312,26 @@ declare_clippy_lint! { "using combination of `filter_map` and `next` which can usually be written as a single method call" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `flat_map(|x| x)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// iter.flat_map(|x| x) + /// ``` + /// Can be written as + /// ```rust + /// iter.flatten() + /// ``` + pub FLAT_MAP, + pedantic, + "call to `flat_map` where `flatten` is sufficient" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.find(_).map(_)`. /// @@ -844,6 +864,7 @@ declare_lint_pass!(Methods => [ FILTER_NEXT, FILTER_MAP, FILTER_MAP_NEXT, + FLAT_MAP, FIND_MAP, MAP_FLATTEN, ITER_NTH, @@ -884,6 +905,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", ..] => lint_flat_map(cx, expr, arg_lists[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]), ["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]), @@ -2092,6 +2114,30 @@ fn lint_filter_map_flat_map<'a, 'tcx>( } } +/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient +fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, flat_map_args: &'tcx [hir::Expr]) { + if_chain! { + if match_trait_method(cx, expr, &paths::ITERATOR); + + if flat_map_args.len() == 2; + if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_args[1].node; + let body = cx.tcx.hir().body(body_id); + + if body.arguments.len() == 1; + if let hir::PatKind::Binding(_, _, binding_ident, _) = body.arguments[0].pat.node; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.node; + + if path.segments.len() == 1; + if path.segments[0].ident.as_str() == binding_ident.as_str(); + + then { + let msg = "called `flat_map(|x| x)` on an `Iterator`. \ + This can be simplified by calling `flatten().`"; + span_lint(cx, FLAT_MAP, expr.span, msg); + } + } +} + /// lint searching an Iterator followed by `is_some()` fn lint_search_is_some<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8c49a3b1838..a7727258b53 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -553,6 +553,13 @@ pub const ALL_LINTS: [Lint; 306] = [ deprecation: None, module: "methods", }, + Lint { + name: "flat_map", + group: "pedantic", + desc: "call to `flat_map` where `flatten` is sufficient", + deprecation: None, + module: "methods", + }, Lint { name: "float_arithmetic", group: "restriction", -- cgit 1.4.1-3-g733a5 From c100c70822aa960aa9ee0abff002ce313403e902 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Fri, 12 Jul 2019 14:13:15 +0200 Subject: Build sys_root in driver with PathBuf instead of String --- src/driver.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index e6b04bf0cfd..545c43f9a45 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -12,7 +12,7 @@ extern crate rustc_plugin; use rustc_interface::interface; use rustc_tools_util::*; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{exit, Command}; mod lintlist; @@ -270,12 +270,19 @@ pub fn main() { let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); let have_sys_root_arg = sys_root_arg.is_some(); let sys_root = sys_root_arg - .map(std::string::ToString::to_string) - .or_else(|| std::env::var("SYSROOT").ok()) + .map(PathBuf::from) + .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from)) .or_else(|| { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain))) + home.and_then(|home| { + toolchain.map(|toolchain| { + let mut path = PathBuf::from(home); + path.push("toolchains"); + path.push(toolchain); + path + }) + }) }) .or_else(|| { Command::new("rustc") @@ -284,9 +291,10 @@ pub fn main() { .output() .ok() .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) + .map(|s| PathBuf::from(s.trim())) }) - .or_else(|| option_env!("SYSROOT").map(String::from)) + .or_else(|| option_env!("SYSROOT").map(PathBuf::from)) + .map(|pb| pb.to_string_lossy().to_string()) .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. -- cgit 1.4.1-3-g733a5 From b523d35d41c51bff255fd038b0d6acb695e42060 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Mon, 15 Jul 2019 07:35:02 +0200 Subject: Deny warnings in CI --- Cargo.toml | 1 + ci/base-tests.sh | 4 ++-- clippy_lints/src/lib.rs | 1 + src/driver.rs | 1 + src/main.rs | 2 ++ 5 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index f68251adb5e..8c70bb18939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,4 +61,5 @@ rustc-workspace-hack = "1.0.0" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} [features] +deny-warnings = [] debugging = [] diff --git a/ci/base-tests.sh b/ci/base-tests.sh index c5d3eb3c902..71f3d38309a 100755 --- a/ci/base-tests.sh +++ b/ci/base-tests.sh @@ -7,8 +7,8 @@ if [ "$TRAVIS_OS_NAME" == "linux" ]; then remark -f *.md -f doc/*.md > /dev/null fi # build clippy in debug mode and run tests -cargo build --features debugging -cargo test --features debugging +cargo build --features "debugging deny-warnings" +cargo test --features "debugging deny-warnings" # for faster build, share target dir between subcrates export CARGO_TARGET_DIR=`pwd`/target/ (cd clippy_lints && cargo test) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d2c9e6b987..369a736aa64 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -9,6 +9,7 @@ #![recursion_limit = "512"] #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![deny(rustc::internal)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(crate_visibility_modifier)] #![feature(concat_idents)] diff --git a/src/driver.rs b/src/driver.rs index e6b04bf0cfd..cd358ff35cb 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,3 +1,4 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(rustc_private)] // FIXME: switch to something more ergonomic here, once available. diff --git a/src/main.rs b/src/main.rs index e0b2bcc7266..8f9afb95337 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "deny-warnings", deny(warnings))] + use rustc_tools_util::*; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. -- cgit 1.4.1-3-g733a5 From 0513202d25c67ebeb5a02f9fe9dad5dea3296140 Mon Sep 17 00:00:00 2001 From: Darth-Revan <Kivi.Kirchner@web.de> Date: Sat, 6 Jul 2019 20:13:38 +0200 Subject: Implement lint for inherent to_string() method. --- CHANGELOG.md | 2 + README.md | 2 +- clippy_lints/src/inherent_to_string.rs | 148 +++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 6 ++ src/lintlist/mod.rs | 16 +++- tests/ui/inherent_to_string.rs | 84 +++++++++++++++++++ tests/ui/inherent_to_string.stderr | 24 ++++++ 7 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/inherent_to_string.rs create mode 100644 tests/ui/inherent_to_string.rs create mode 100644 tests/ui/inherent_to_string.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 461adb729f9..ff5aebbc892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -973,6 +973,8 @@ Released 2018-09-13 [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter +[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string +[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one diff --git a/README.md b/README.md index 24bda9bbef6..1e649d8982f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 306 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 308 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs new file mode 100644 index 00000000000..57ffdf78d11 --- /dev/null +++ b/clippy_lints/src/inherent_to_string.rs @@ -0,0 +1,148 @@ +use if_chain::if_chain; +use rustc::hir::{ImplItem, ImplItemKind}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; + +use crate::utils::{ + get_trait_def_id, implements_trait, in_macro_or_desugar, match_type, paths, return_ty, span_help_and_lint, + trait_ref_of_method, walk_ptrs_ty, +}; + +declare_clippy_lint! { + /// **What id does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. + /// + /// **Why is this bad?** This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. + /// + /// **Known problems:** None + /// + /// ** Example:** + /// + /// ```rust,ignore + /// // Bad + /// pub struct A; + /// + /// impl A { + /// pub fn to_string(&self) -> String { + /// "I am A".to_string() + /// } + /// } + /// // Good + /// use std::fmt; + /// + /// pub struct A; + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "I am A") + /// } + /// } + /// ``` + pub INHERENT_TO_STRING, + style, + "type implements inherent method 'to_string()', but should instead implement the 'Display' trait" +} + +declare_clippy_lint! { + /// **What id does:** Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait. + /// + /// **Why is this bad?** This method is also implicitly defined if a type implements the 'Display' trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. + /// + /// **Known problems:** The inherent method will shadow the implementation by `Display`. If they behave differently, this may lead to confusing situations for users of the respective type. + /// + /// ** Example:** + /// + /// ```rust,ignore + /// // Bad + /// use std::fmt; + /// + /// pub struct A; + /// + /// impl A { + /// pub fn to_string(&self) -> String { + /// "I am A".to_string() + /// } + /// } + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "I am A, too") + /// } + /// } + /// // Good + /// use std::fmt; + /// + /// pub struct A; + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "I am A") + /// } + /// } + /// ``` + pub INHERENT_TO_STRING_SHADOW_DISPLAY, + correctness, + "type implements inherent method 'to_string()', which gets shadowed by the implementation of the 'Display' trait " +} + +declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_SHADOW_DISPLAY]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InherentToString { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem) { + if in_macro_or_desugar(impl_item.span) { + return; + } + + if_chain! { + // Check if item is a method, called to_string and has a parameter 'self' + if let ImplItemKind::Method(ref signature, _) = impl_item.node; + if impl_item.ident.name.as_str() == "to_string"; + let decl = &signature.decl; + if decl.implicit_self.has_implicit_self(); + + // Check if return type is String + if match_type(cx, return_ty(cx, impl_item.hir_id), &paths::STRING); + + // Filters instances of to_string which are required by a trait + if trait_ref_of_method(cx, impl_item.hir_id).is_none(); + + then { + show_lint(cx, impl_item); + } + } + } +} + +fn show_lint(cx: &LateContext<'_, '_>, item: &ImplItem) { + let display_trait_id = + get_trait_def_id(cx, &["core", "fmt", "Display"]).expect("Failed to get trait ID of 'Display'!"); + + // Get the real type of 'self' + let fn_def_id = cx.tcx.hir().local_def_id(item.hir_id); + let self_type = cx.tcx.fn_sig(fn_def_id).input(0); + let self_type = walk_ptrs_ty(self_type.skip_binder()); + + // Emit either a warning or an error + if implements_trait(cx, self_type, display_trait_id, &[]) { + span_help_and_lint( + cx, + INHERENT_TO_STRING_SHADOW_DISPLAY, + item.span, + &format!( + "type '{}' implements inherent method 'to_string() -> String' which shadows the implementation of 'Display'", + self_type.to_string() + ), + &format!("remove the inherent method from type '{}'", self_type.to_string()) + ); + } else { + span_help_and_lint( + cx, + INHERENT_TO_STRING, + item.span, + &format!( + "implementation of inherent method 'to_string() -> String' for type '{}'", + self_type.to_string() + ), + &format!("implement trait 'Display' for type '{}' instead", self_type.to_string()), + ); + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 369a736aa64..de7a213d7a4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -195,6 +195,7 @@ pub mod indexing_slicing; pub mod infallible_destructuring_match; pub mod infinite_iter; pub mod inherent_impl; +pub mod inherent_to_string; pub mod inline_fn_without_body; pub mod int_plus_one; pub mod integer_division; @@ -585,6 +586,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box path_buf_push_overwrite::PathBufPushOverwrite); reg.register_late_lint_pass(box checked_conversions::CheckedConversions); reg.register_late_lint_pass(box integer_division::IntegerDivision); + reg.register_late_lint_pass(box inherent_to_string::InherentToString); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -725,6 +727,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { indexing_slicing::OUT_OF_BOUNDS_INDEXING, infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, infinite_iter::INFINITE_ITER, + inherent_to_string::INHERENT_TO_STRING, + inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, inline_fn_without_body::INLINE_FN_WITHOUT_BODY, int_plus_one::INT_PLUS_ONE, invalid_ref::INVALID_REF, @@ -913,6 +917,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, + inherent_to_string::INHERENT_TO_STRING, len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_ZERO, let_if_seq::USELESS_LET_IF_SEQ, @@ -1075,6 +1080,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { functions::NOT_UNSAFE_PTR_ARG_DEREF, indexing_slicing::OUT_OF_BOUNDS_INDEXING, infinite_iter::INFINITE_ITER, + inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, inline_fn_without_body::INLINE_FN_WITHOUT_BODY, invalid_ref::INVALID_REF, literal_representation::MISTYPED_LITERAL_SUFFIXES, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8c49a3b1838..59eb92593bd 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 306] = [ +pub const ALL_LINTS: [Lint; 308] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -728,6 +728,20 @@ pub const ALL_LINTS: [Lint; 306] = [ deprecation: None, module: "infinite_iter", }, + Lint { + name: "inherent_to_string", + group: "style", + desc: "type implements inherent method \'to_string()\', but should instead implement the \'Display\' trait", + deprecation: None, + module: "inherent_to_string", + }, + Lint { + name: "inherent_to_string_shadow_display", + group: "correctness", + desc: "type implements inherent method \'to_string()\', which gets shadowed by the implementation of the \'Display\' trait ", + deprecation: None, + module: "inherent_to_string", + }, Lint { name: "inline_always", group: "pedantic", diff --git a/tests/ui/inherent_to_string.rs b/tests/ui/inherent_to_string.rs new file mode 100644 index 00000000000..78f24a3c918 --- /dev/null +++ b/tests/ui/inherent_to_string.rs @@ -0,0 +1,84 @@ +#![warn(clippy::inherent_to_string)] +//#![deny(clippy::inherent_to_string_shadow)] + +use std::fmt; + +trait FalsePositive { + fn to_string(&self) -> String; +} + +struct A; +struct B; +struct C; +struct D; +struct E; + +impl A { + // Should be detected; emit warning + fn to_string(&self) -> String { + "A.to_string()".to_string() + } + + // Should not be detected as it does not match the function signature + fn to_str(&self) -> String { + "A.to_str()".to_string() + } +} + +// Should not be detected as it is a free function +fn to_string() -> String { + "free to_string()".to_string() +} + +impl B { + // Should not be detected, wrong return type + fn to_string(&self) -> i32 { + 42 + } +} + +impl C { + // Should be detected and emit error as C also implements Display + fn to_string(&self) -> String { + "C.to_string()".to_string() + } +} + +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "impl Display for C") + } +} + +impl FalsePositive for D { + // Should not be detected, as it is a trait function + fn to_string(&self) -> String { + "impl FalsePositive for D".to_string() + } +} + +impl E { + // Should not be detected, as it is not bound to an instance + fn to_string() -> String { + "E::to_string()".to_string() + } +} + +fn main() { + let a = A; + a.to_string(); + a.to_str(); + + to_string(); + + let b = B; + b.to_string(); + + let c = C; + C.to_string(); + + let d = D; + d.to_string(); + + E::to_string(); +} diff --git a/tests/ui/inherent_to_string.stderr b/tests/ui/inherent_to_string.stderr new file mode 100644 index 00000000000..85fb06a2265 --- /dev/null +++ b/tests/ui/inherent_to_string.stderr @@ -0,0 +1,24 @@ +error: implementation of inherent method 'to_string() -> String' for type 'A' + --> $DIR/inherent_to_string.rs:18:5 + | +LL | / fn to_string(&self) -> String { +LL | | "A.to_string()".to_string() +LL | | } + | |_____^ + | + = note: `-D clippy::inherent-to-string` implied by `-D warnings` + = help: implement trait 'Display' for type 'A' instead + +error: type 'C' implements inherent method 'to_string() -> String' which shadows the implementation of 'Display' + --> $DIR/inherent_to_string.rs:42:5 + | +LL | / fn to_string(&self) -> String { +LL | | "C.to_string()".to_string() +LL | | } + | |_____^ + | + = note: #[deny(clippy::inherent_to_string_shadow_display)] on by default + = help: remove the inherent method from type 'C' + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From b7145fbb660fa0dfad14b9ba7d47d1459b103e15 Mon Sep 17 00:00:00 2001 From: Darth-Revan <18002263+Darth-Revan@users.noreply.github.com> Date: Tue, 16 Jul 2019 18:29:37 +0200 Subject: Fix "unkown clippy lint" error in UI test. --- src/lintlist/mod.rs | 4 ++-- tests/ui/inherent_to_string.rs | 2 +- tests/ui/inherent_to_string.stderr | 14 +++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 59eb92593bd..2d9e800b6e4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -731,14 +731,14 @@ pub const ALL_LINTS: [Lint; 308] = [ Lint { name: "inherent_to_string", group: "style", - desc: "type implements inherent method \'to_string()\', but should instead implement the \'Display\' trait", + desc: "type implements inherent method `to_string()`, but should instead implement the `Display` trait", deprecation: None, module: "inherent_to_string", }, Lint { name: "inherent_to_string_shadow_display", group: "correctness", - desc: "type implements inherent method \'to_string()\', which gets shadowed by the implementation of the \'Display\' trait ", + desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait ", deprecation: None, module: "inherent_to_string", }, diff --git a/tests/ui/inherent_to_string.rs b/tests/ui/inherent_to_string.rs index 9f81c027f4b..fc21b5cbc3f 100644 --- a/tests/ui/inherent_to_string.rs +++ b/tests/ui/inherent_to_string.rs @@ -1,5 +1,5 @@ #![warn(clippy::inherent_to_string)] -#![deny(clippy::inherent_to_string_shadow)] +#![deny(clippy::inherent_to_string_shadow_display)] use std::fmt; diff --git a/tests/ui/inherent_to_string.stderr b/tests/ui/inherent_to_string.stderr index 4a967f34982..5252a168830 100644 --- a/tests/ui/inherent_to_string.stderr +++ b/tests/ui/inherent_to_string.stderr @@ -17,16 +17,12 @@ LL | | "C.to_string()".to_string() LL | | } | |_____^ | - = note: #[deny(clippy::inherent_to_string_shadow_display)] on by default - = help: remove the inherent method from type `C` - -error: unknown clippy lint: clippy::inherent_to_string_shadow +note: lint level defined here --> $DIR/inherent_to_string.rs:2:9 | -LL | #![deny(clippy::inherent_to_string_shadow)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` +LL | #![deny(clippy::inherent_to_string_shadow_display)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove the inherent method from type `C` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From a865fe607ca277a55f6715cb254d47681f7fdec9 Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Fri, 19 Jul 2019 16:41:10 +0200 Subject: rustup https://github.com/rust-lang/rust/pull/62679/ --- src/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 146e3fe2d08..cec88be7eb1 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -63,7 +63,7 @@ fn test_arg_value() { struct ClippyCallbacks; impl rustc_driver::Callbacks for ClippyCallbacks { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> rustc_driver::Compilation { let sess = compiler.session(); let mut registry = rustc_plugin::registry::Registry::new( sess, @@ -107,7 +107,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { sess.plugin_attributes.borrow_mut().extend(attributes); // Continue execution - true + rustc_driver::Compilation::Continue } } -- cgit 1.4.1-3-g733a5 From 925e8207fa8ff6cc4aea7337b6cb3eeb318123d3 Mon Sep 17 00:00:00 2001 From: xd009642 <danielmckenna93@gmail.com> Date: Sat, 27 Jul 2019 21:58:29 +0100 Subject: Respond to review comments Update README and CHANGELOG using the util scripts, refine the help message and fix the float_cmp error. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 +++-- clippy_lints/src/trait_bounds.rs | 18 +++++++++++------- clippy_lints/src/utils/hir_utils.rs | 30 ++++++++++++------------------ src/lintlist/mod.rs | 9 ++++++++- tests/ui/float_cmp.stderr | 11 ++++++++++- tests/ui/type_repetition_in_bounds.rs | 17 +++++++++++------ 8 files changed, 57 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index ff5aebbc892..089897811a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1138,6 +1138,7 @@ Released 2018-09-13 [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity +[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg diff --git a/README.md b/README.md index 1e649d8982f..38651f72eb3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 308 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 309 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index faffb1a67f1..908bbeb5e19 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -263,9 +263,9 @@ pub mod strings; pub mod suspicious_trait_impl; pub mod swap; pub mod temporary_assignment; +pub mod trait_bounds; pub mod transmute; pub mod transmuting_null; -pub mod trait_bounds; pub mod trivially_copy_pass_by_ref; pub mod try_err; pub mod types; @@ -860,6 +860,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { swap::ALMOST_SWAPPED, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, transmute::TRANSMUTE_BYTES_TO_STR, transmute::TRANSMUTE_INT_TO_BOOL, @@ -870,7 +871,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { transmute::USELESS_TRANSMUTE, transmute::WRONG_TRANSMUTE, transmuting_null::TRANSMUTING_NULL, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, try_err::TRY_ERR, types::ABSURD_EXTREME_COMPARISONS, @@ -1042,6 +1042,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reference::REF_IN_DEREF, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, transmute::TRANSMUTE_BYTES_TO_STR, transmute::TRANSMUTE_INT_TO_BOOL, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index f5ca3793dbc..8a719c0dd04 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,8 +1,8 @@ use crate::utils::{in_macro, snippet, span_help_and_lint, SpanlessHash}; +use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, impl_lint_pass}; use rustc_data_structures::fx::FxHashMap; -use rustc::hir::*; #[derive(Copy, Clone)] pub struct TraitBounds; @@ -10,11 +10,12 @@ pub struct TraitBounds; declare_clippy_lint! { /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds /// - /// **Why is this bad?** Complexity + /// **Why is this bad?** Repeating the type for every bound makes the code + /// less readable than combining the bounds /// /// **Example:** /// ```rust - /// pub fn foo<T>(t: T) where T: Copy, T: Clone + /// pub fn foo<T>(t: T) where T: Copy, T: Clone /// ``` /// /// Could be written as: @@ -34,7 +35,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds { if in_macro(gen.span) { return; } - let hash = | ty | -> u64 { + let hash = |ty| -> u64 { let mut hasher = SpanlessHash::new(cx, cx.tables); hasher.hash_ty(ty); hasher.finish() @@ -44,17 +45,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds { if let WherePredicate::BoundPredicate(ref p) = bound { let h = hash(&p.bounded_ty); if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>()) { - let mut hint_string = format!("consider combining the bounds: `{}: ", snippet(cx, p.bounded_ty.span, "_")); + let mut hint_string = format!( + "consider combining the bounds: `{}:", + snippet(cx, p.bounded_ty.span, "_") + ); for b in v.iter() { if let GenericBound::Trait(ref poly_trait_ref, _) = b { let path = &poly_trait_ref.trait_ref.path; - hint_string.push_str(&format!("{}, ", path)); + hint_string.push_str(&format!(" {} +", path)); } } for b in p.bounds.iter() { if let GenericBound::Trait(ref poly_trait_ref, _) = b { let path = &poly_trait_ref.trait_ref.path; - hint_string.push_str(&format!("{}, ", path)); + hint_string.push_str(&format!(" {} +", path)); } } hint_string.truncate(hint_string.len() - 2); diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 449b8c4397d..db7b10c6bac 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -639,23 +639,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { for ty in ty_list { self.hash_ty(ty); } - }, - TyKind::Path(qpath) => { - match qpath { - QPath::Resolved(ref maybe_ty, ref path) => { - if let Some(ref ty) = maybe_ty { - self.hash_ty(ty); - } - for segment in &path.segments { - segment.ident.name.hash(&mut self.s); - } - }, - QPath::TypeRelative(ref ty, ref segment) => { + TyKind::Path(qpath) => match qpath { + QPath::Resolved(ref maybe_ty, ref path) => { + if let Some(ref ty) = maybe_ty { self.hash_ty(ty); + } + for segment in &path.segments { segment.ident.name.hash(&mut self.s); - }, - } + } + }, + QPath::TypeRelative(ref ty, ref segment) => { + self.hash_ty(ty); + segment.ident.name.hash(&mut self.s); + }, }, TyKind::Def(_, arg_list) => { for arg in arg_list { @@ -670,14 +667,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, TyKind::TraitObject(_, lifetime) => { self.hash_lifetime(lifetime); - }, TyKind::Typeof(anon_const) => { self.hash_expr(&self.cx.tcx.hir().body(anon_const.body).value); }, - TyKind::CVarArgs(lifetime) => { - self.hash_lifetime(lifetime) - }, + TyKind::CVarArgs(lifetime) => self.hash_lifetime(lifetime), TyKind::Err | TyKind::Infer | TyKind::Never => {}, } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2d9e800b6e4..49bce5a6cef 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 308] = [ +pub const ALL_LINTS: [Lint; 309] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1848,6 +1848,13 @@ pub const ALL_LINTS: [Lint; 308] = [ deprecation: None, module: "types", }, + Lint { + name: "type_repetition_in_bounds", + group: "complexity", + desc: "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`", + deprecation: None, + module: "trait_bounds", + }, Lint { name: "unicode_not_nfc", group: "pedantic", diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index 5dc5fbf0f6e..d1ffc0d15c7 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -1,3 +1,12 @@ +error: this type has already been used as a bound predicate + --> $DIR/float_cmp.rs:12:5 + | +LL | T: Copy, + | ^^^^^^^ + | + = note: `-D clippy::type-repetition-in-bounds` implied by `-D warnings` + = help: consider combining the bounds: `T: Add<T, Output = T>, Copy` + error: strict comparison of f32 or f64 --> $DIR/float_cmp.rs:60:5 | @@ -35,5 +44,5 @@ note: std::f32::EPSILON and std::f64::EPSILON are available. LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 3aa0d0da561..8b538be762b 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,14 +1,19 @@ #[deny(clippy::type_repetition_in_bounds)] -pub fn foo<T>(_t: T) where T: Copy, T: Clone { +pub fn foo<T>(_t: T) +where + T: Copy, + T: Clone, +{ unimplemented!(); } -pub fn bar<T, U>(_t: T, _u: U) where T: Copy, U: Clone { +pub fn bar<T, U>(_t: T, _u: U) +where + T: Copy, + U: Clone, +{ unimplemented!(); } - -fn main() { - -} +fn main() {} -- cgit 1.4.1-3-g733a5 From e6a836e2e801a3c0675b3dd24e0de1c810470813 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Tue, 30 Jul 2019 09:50:56 +0200 Subject: Move UNNECESSARY_UNWRAP to complexity and PANICKING_UNWRAP to correctness --- clippy_lints/src/lib.rs | 6 ++++-- clippy_lints/src/unwrap.rs | 4 ++-- src/lintlist/mod.rs | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 908bbeb5e19..1e9e17f599c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -894,6 +894,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_io_amount::UNUSED_IO_AMOUNT, unused_label::UNUSED_LABEL, + unwrap::PANICKING_UNWRAP, + unwrap::UNNECESSARY_UNWRAP, vec::USELESS_VEC, write::PRINTLN_EMPTY_STRING, write::PRINT_LITERAL, @@ -1060,6 +1062,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { types::UNNECESSARY_CAST, types::VEC_BOX, unused_label::UNUSED_LABEL, + unwrap::UNNECESSARY_UNWRAP, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); @@ -1121,6 +1124,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, unused_io_amount::UNUSED_IO_AMOUNT, + unwrap::PANICKING_UNWRAP, ]); reg.register_lint_group("clippy::perf", Some("clippy_perf"), vec![ @@ -1157,8 +1161,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { needless_borrow::NEEDLESS_BORROW, path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, redundant_clone::REDUNDANT_CLONE, - unwrap::PANICKING_UNWRAP, - unwrap::UNNECESSARY_UNWRAP, ]); } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 568087b3667..830e1fc4d25 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// } /// ``` pub UNNECESSARY_UNWRAP, - nursery, + complexity, "checks for calls of unwrap[_err]() that cannot fail" } @@ -52,7 +52,7 @@ declare_clippy_lint! { /// /// This code will always panic. The if condition should probably be inverted. pub PANICKING_UNWRAP, - nursery, + correctness, "checks for calls of unwrap[_err]() that will always fail" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 49bce5a6cef..aa457664020 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1381,7 +1381,7 @@ pub const ALL_LINTS: [Lint; 309] = [ }, Lint { name: "panicking_unwrap", - group: "nursery", + group: "correctness", desc: "checks for calls of unwrap[_err]() that will always fail", deprecation: None, module: "unwrap", @@ -1927,7 +1927,7 @@ pub const ALL_LINTS: [Lint; 309] = [ }, Lint { name: "unnecessary_unwrap", - group: "nursery", + group: "complexity", desc: "checks for calls of unwrap[_err]() that cannot fail", deprecation: None, module: "unwrap", -- cgit 1.4.1-3-g733a5 From 77b21b644f2072768d24dee331494b082ea133d1 Mon Sep 17 00:00:00 2001 From: Vincent Dal Maso <vincent.dalmaso.ext@delair-tech.com> Date: Mon, 17 Jun 2019 17:36:42 +0200 Subject: Move expression check to LateLintPass Changes: - Move from EarlyLintPass - Fix entrypoint check with function path def_id. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 4 +- clippy_lints/src/main_recursion.rs | 55 ++++++++++++---------- src/lintlist/mod.rs | 7 +++ .../ui/crate_level_checks/entrypoint_recursion.rs | 12 +++++ .../crate_level_checks/entrypoint_recursion.stderr | 11 +++++ .../ui/crate_level_checks/no_std_main_recursion.rs | 5 +- .../no_std_main_recursion.stderr | 0 tests/ui/crate_level_checks/std_main_recursion.rs | 1 + .../crate_level_checks/std_main_recursion.stderr | 8 ++-- 10 files changed, 72 insertions(+), 32 deletions(-) create mode 100644 tests/ui/crate_level_checks/entrypoint_recursion.rs create mode 100644 tests/ui/crate_level_checks/entrypoint_recursion.stderr delete mode 100644 tests/ui/crate_level_checks/no_std_main_recursion.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 089897811a5..e4a1a602c43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1000,6 +1000,7 @@ Released 2018-09-13 [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 325195caa3e..258be38e48b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -474,7 +474,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box types::LetUnitValue); reg.register_late_lint_pass(box types::UnitCmp); reg.register_late_lint_pass(box loops::Loops); - reg.register_early_lint_pass(box main_recursion::MainRecursion::new()); + reg.register_late_lint_pass(box main_recursion::MainRecursion::default()); reg.register_late_lint_pass(box lifetimes::Lifetimes); reg.register_late_lint_pass(box entry::HashMapPass); reg.register_late_lint_pass(box ranges::Ranges); @@ -762,6 +762,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { loops::WHILE_IMMUTABLE_CONDITION, loops::WHILE_LET_LOOP, loops::WHILE_LET_ON_ITERATOR, + main_recursion::MAIN_RECURSION, map_clone::MAP_CLONE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, @@ -935,6 +936,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { loops::FOR_KV_MAP, loops::NEEDLESS_RANGE_LOOP, loops::WHILE_LET_ON_ITERATOR, + main_recursion::MAIN_RECURSION, map_clone::MAP_CLONE, matches::MATCH_BOOL, matches::MATCH_OVERLAPPING_ARM, diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 9ef4de21f5a..88f1e685ced 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,53 +1,60 @@ - -use syntax::ast::{Crate, Expr, ExprKind}; -use syntax::symbol::sym; -use rustc::lint::{LintArray, LintPass, EarlyLintPass, EarlyContext}; +use rustc::hir::{Crate, Expr, ExprKind, QPath}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, impl_lint_pass}; +use syntax::symbol::sym; +use crate::utils::{is_entrypoint_fn, snippet, span_help_and_lint}; use if_chain::if_chain; -use crate::utils::span_help_and_lint; declare_clippy_lint! { + /// **What it does:** Checks for recursion using the entrypoint. + /// + /// **Why is this bad?** Apart from special setups (which we could detect following attributes like #![no_std]), + /// recursing into main() seems like an unintuitive antipattern we should be able to detect. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```no_run + /// fn main() { + /// main(); + /// } + /// ``` pub MAIN_RECURSION, - pedantic, - "function named `foo`, which is not a descriptive name" + style, + "recursion using the entrypoint" } +#[derive(Default)] pub struct MainRecursion { - has_no_std_attr: bool + has_no_std_attr: bool, } impl_lint_pass!(MainRecursion => [MAIN_RECURSION]); -impl MainRecursion { - pub fn new() -> MainRecursion { - MainRecursion { - has_no_std_attr: false - } - } -} - -impl EarlyLintPass for MainRecursion { - fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) { +impl LateLintPass<'_, '_> for MainRecursion { + fn check_crate(&mut self, _: &LateContext<'_, '_>, krate: &Crate) { self.has_no_std_attr = krate.attrs.iter().any(|attr| attr.path == sym::no_std); } - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + fn check_expr_post(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) { if self.has_no_std_attr { return; } if_chain! { if let ExprKind::Call(func, _) = &expr.node; - if let ExprKind::Path(_, path) = &func.node; - if *path == sym::main; + if let ExprKind::Path(path) = &func.node; + if let QPath::Resolved(_, path) = &path; + if let Some(def_id) = path.res.opt_def_id(); + if is_entrypoint_fn(cx, def_id); then { span_help_and_lint( cx, MAIN_RECURSION, - expr.span, - "You are recursing into main()", - "Consider using another function for this recursion" + func.span, + &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), + "consider using another function for this recursion" ) } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index aa457664020..802ba60b9f1 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -917,6 +917,13 @@ pub const ALL_LINTS: [Lint; 309] = [ deprecation: None, module: "booleans", }, + Lint { + name: "main_recursion", + group: "style", + desc: "recursion using the entrypoint", + deprecation: None, + module: "main_recursion", + }, Lint { name: "manual_memcpy", group: "perf", diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs new file mode 100644 index 00000000000..995787c5336 --- /dev/null +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -0,0 +1,12 @@ +// ignore-macos +// ignore-windows + +#![feature(main)] + +#[warn(clippy::main_recursion)] +#[allow(unconditional_recursion)] +#[main] +fn a() { + println!("Hello, World!"); + a(); +} diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr new file mode 100644 index 00000000000..f52fc949f6c --- /dev/null +++ b/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -0,0 +1,11 @@ +error: recursing into entrypoint `a` + --> $DIR/entrypoint_recursion.rs:11:5 + | +LL | a(); + | ^ + | + = note: `-D clippy::main-recursion` implied by `-D warnings` + = help: consider using another function for this recursion + +error: aborting due to previous error + diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index 857af96a044..4d19f38e2d0 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ #![feature(lang_items, link_args, start, libc)] -#![link_args="-nostartfiles"] +#![link_args = "-nostartfiles"] #![no_std] use core::panic::PanicInfo; @@ -8,7 +8,6 @@ use core::sync::atomic::{AtomicUsize, Ordering}; static N: AtomicUsize = AtomicUsize::new(0); #[warn(clippy::main_recursion)] -#[allow(unconditional_recursion)] #[start] fn main(argc: isize, argv: *const *const u8) -> isize { let x = N.load(Ordering::Relaxed); @@ -28,4 +27,4 @@ fn panic(_info: &PanicInfo) -> ! { } #[lang = "eh_personality"] -extern fn eh_personality() {} +extern "C" fn eh_personality() {} diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.stderr b/tests/ui/crate_level_checks/no_std_main_recursion.stderr deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/ui/crate_level_checks/std_main_recursion.rs b/tests/ui/crate_level_checks/std_main_recursion.rs index e7689ffb72d..89ff6609934 100644 --- a/tests/ui/crate_level_checks/std_main_recursion.rs +++ b/tests/ui/crate_level_checks/std_main_recursion.rs @@ -1,5 +1,6 @@ #[warn(clippy::main_recursion)] #[allow(unconditional_recursion)] fn main() { + println!("Hello, World!"); main(); } diff --git a/tests/ui/crate_level_checks/std_main_recursion.stderr b/tests/ui/crate_level_checks/std_main_recursion.stderr index 7979010eadf..0a260f9d230 100644 --- a/tests/ui/crate_level_checks/std_main_recursion.stderr +++ b/tests/ui/crate_level_checks/std_main_recursion.stderr @@ -1,11 +1,11 @@ -error: You are recursing into main() - --> $DIR/std_main_recursion.rs:4:5 +error: recursing into entrypoint `main` + --> $DIR/std_main_recursion.rs:5:5 | LL | main(); - | ^^^^^^ + | ^^^^ | = note: `-D clippy::main-recursion` implied by `-D warnings` - = help: Consider using another function for this recursion + = help: consider using another function for this recursion error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From a922f800aff150b1b2b8093ff54df40736b82332 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Mon, 5 Aug 2019 13:24:31 +0200 Subject: Run update_lints and fmt --- README.md | 2 +- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 38651f72eb3..ff64fc93788 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 309 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 310 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 802ba60b9f1..93712e8eb68 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 309] = [ +pub const ALL_LINTS: [Lint; 310] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", -- cgit 1.4.1-3-g733a5 From 40fea7a9e0d35141ed7cfbee9a820c01c0ad0c6c Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Sun, 11 Aug 2019 11:02:25 +0200 Subject: update_lints --- CHANGELOG.md | 1 - README.md | 2 +- src/lintlist/mod.rs | 9 +-------- 3 files changed, 2 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a1a602c43..db838a3e2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -982,7 +982,6 @@ Released 2018-09-13 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref -[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements diff --git a/README.md b/README.md index 389fe316ade..8bcfd8a8430 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 310 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 309 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 93712e8eb68..b41ed4a5910 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 310] = [ +pub const ALL_LINTS: [Lint; 309] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -791,13 +791,6 @@ pub const ALL_LINTS: [Lint; 310] = [ deprecation: None, module: "methods", }, - Lint { - name: "invalid_ref", - group: "correctness", - desc: "creation of invalid reference", - deprecation: None, - module: "invalid_ref", - }, Lint { name: "invalid_regex", group: "correctness", -- cgit 1.4.1-3-g733a5 From f0ce04f81432047bdd9b3a96a57ba06264f18471 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <jeremy@myelin.ch> Date: Sun, 11 Aug 2019 19:51:43 +0200 Subject: Handle calls with 'std::convert::identity' --- clippy_lints/src/methods/mod.rs | 18 ++++++++++++++++++ clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 2 +- tests/ui/unnecessary_flat_map.rs | 5 +++++ tests/ui/unnecessary_flat_map.stderr | 10 ++++++++-- 5 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e51e432749c..58b33524589 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2186,6 +2186,24 @@ fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, fl span_lint(cx, FLAT_MAP, expr.span, msg); } } + + if_chain! { + if match_trait_method(cx, expr, &paths::ITERATOR); + + if flat_map_args.len() == 2; + + let expr = &flat_map_args[1]; + + if let hir::ExprKind::Path(ref qpath) = expr.node; + + if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); + + then { + let msg = "called `flat_map(std::convert::identity)` on an `Iterator`. \ + This can be simplified by calling `flatten().`"; + span_lint(cx, FLAT_MAP, expr.span, msg); + } + } } /// lint searching an Iterator followed by `is_some()` diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 62b22afff95..be811da0217 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -95,6 +95,7 @@ pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; +pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; pub const STRING: [&str; 3] = ["alloc", "string", "String"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 23cad950a95..08179ec34e8 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 309] = [ +pub const ALL_LINTS: [Lint; 310] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", diff --git a/tests/ui/unnecessary_flat_map.rs b/tests/ui/unnecessary_flat_map.rs index d0072eca9d2..b61569d1b93 100644 --- a/tests/ui/unnecessary_flat_map.rs +++ b/tests/ui/unnecessary_flat_map.rs @@ -1,6 +1,11 @@ #![warn(clippy::flat_map)] +use std::convert; + fn main() { let iterator = [[0, 1], [2, 3], [4, 5]].iter(); iterator.flat_map(|x| x); + + let iterator = [[0, 1], [2, 3], [4, 5]].iter(); + iterator.flat_map(convert::identity); } diff --git a/tests/ui/unnecessary_flat_map.stderr b/tests/ui/unnecessary_flat_map.stderr index 9ebef07f1b7..c98b403d29c 100644 --- a/tests/ui/unnecessary_flat_map.stderr +++ b/tests/ui/unnecessary_flat_map.stderr @@ -1,10 +1,16 @@ error: called `flat_map(|x| x)` on an `Iterator`. This can be simplified by calling `flatten().` - --> $DIR/unnecessary_flat_map.rs:5:5 + --> $DIR/unnecessary_flat_map.rs:7:5 | LL | iterator.flat_map(|x| x); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::flat-map` implied by `-D warnings` -error: aborting due to previous error +error: called `flat_map(std::convert::identity)` on an `Iterator`. This can be simplified by calling `flatten().` + --> $DIR/unnecessary_flat_map.rs:10:23 + | +LL | iterator.flat_map(convert::identity); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From b651f19eb87db789f8fd24a7791add446d869630 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <jeremy@myelin.ch> Date: Sun, 11 Aug 2019 20:34:25 +0200 Subject: Rename 'flat_map' → 'flat_map_identity' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/mod.rs | 16 ++++++++++------ src/lintlist/mod.rs | 2 +- tests/ui/unnecessary_flat_map.rs | 2 +- tests/ui/unnecessary_flat_map.stderr | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 89570267a94..87dbe891ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -947,7 +947,7 @@ Released 2018-09-13 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map -[`flat_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4c9126045f9..4cc750ceb2f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -643,7 +643,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::FILTER_MAP, methods::FILTER_MAP_NEXT, methods::FIND_MAP, - methods::FLAT_MAP, + methods::FLAT_MAP_IDENTITY, methods::MAP_FLATTEN, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 58b33524589..0ab7785501a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -357,7 +357,7 @@ declare_clippy_lint! { /// ```rust /// iter.flatten() /// ``` - pub FLAT_MAP, + pub FLAT_MAP_IDENTITY, pedantic, "call to `flat_map` where `flatten` is sufficient" } @@ -912,7 +912,7 @@ declare_lint_pass!(Methods => [ FILTER_NEXT, FILTER_MAP, FILTER_MAP_NEXT, - FLAT_MAP, + FLAT_MAP_IDENTITY, FIND_MAP, MAP_FLATTEN, ITER_NTH, @@ -953,7 +953,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), - ["flat_map", ..] => lint_flat_map(cx, expr, arg_lists[0]), + ["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]), ["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]), @@ -2165,7 +2165,11 @@ fn lint_filter_map_flat_map<'a, 'tcx>( } /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient -fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, flat_map_args: &'tcx [hir::Expr]) { +fn lint_flat_map_identity<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr, + flat_map_args: &'tcx [hir::Expr], +) { if_chain! { if match_trait_method(cx, expr, &paths::ITERATOR); @@ -2183,7 +2187,7 @@ fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, fl then { let msg = "called `flat_map(|x| x)` on an `Iterator`. \ This can be simplified by calling `flatten().`"; - span_lint(cx, FLAT_MAP, expr.span, msg); + span_lint(cx, FLAT_MAP_IDENTITY, expr.span, msg); } } @@ -2201,7 +2205,7 @@ fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, fl then { let msg = "called `flat_map(std::convert::identity)` on an `Iterator`. \ This can be simplified by calling `flatten().`"; - span_lint(cx, FLAT_MAP, expr.span, msg); + span_lint(cx, FLAT_MAP_IDENTITY, expr.span, msg); } } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 08179ec34e8..cfe8dea8837 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -554,7 +554,7 @@ pub const ALL_LINTS: [Lint; 310] = [ module: "methods", }, Lint { - name: "flat_map", + name: "flat_map_identity", group: "pedantic", desc: "call to `flat_map` where `flatten` is sufficient", deprecation: None, diff --git a/tests/ui/unnecessary_flat_map.rs b/tests/ui/unnecessary_flat_map.rs index b61569d1b93..955e791dd2b 100644 --- a/tests/ui/unnecessary_flat_map.rs +++ b/tests/ui/unnecessary_flat_map.rs @@ -1,4 +1,4 @@ -#![warn(clippy::flat_map)] +#![warn(clippy::flat_map_identity)] use std::convert; diff --git a/tests/ui/unnecessary_flat_map.stderr b/tests/ui/unnecessary_flat_map.stderr index c98b403d29c..4872e37f324 100644 --- a/tests/ui/unnecessary_flat_map.stderr +++ b/tests/ui/unnecessary_flat_map.stderr @@ -4,7 +4,7 @@ error: called `flat_map(|x| x)` on an `Iterator`. This can be simplified by call LL | iterator.flat_map(|x| x); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::flat-map` implied by `-D warnings` + = note: `-D clippy::flat-map-identity` implied by `-D warnings` error: called `flat_map(std::convert::identity)` on an `Iterator`. This can be simplified by calling `flatten().` --> $DIR/unnecessary_flat_map.rs:10:23 -- cgit 1.4.1-3-g733a5 From 4275d7b6acc9757de008e61c2dd3d55a9ca113e4 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <jeremy@myelin.ch> Date: Mon, 12 Aug 2019 21:47:12 +0200 Subject: Run 'update_lints' --- clippy_lints/src/lib.rs | 3 ++- src/lintlist/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4cc750ceb2f..38fa6c9b5bc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -643,7 +643,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::FILTER_MAP, methods::FILTER_MAP_NEXT, methods::FIND_MAP, - methods::FLAT_MAP_IDENTITY, methods::MAP_FLATTEN, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, @@ -778,6 +777,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::CLONE_ON_COPY, methods::EXPECT_FUN_CALL, methods::FILTER_NEXT, + methods::FLAT_MAP_IDENTITY, methods::INTO_ITER_ON_ARRAY, methods::INTO_ITER_ON_REF, methods::ITER_CLONED_COLLECT, @@ -1022,6 +1022,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::CHARS_NEXT_CMP, methods::CLONE_ON_COPY, methods::FILTER_NEXT, + methods::FLAT_MAP_IDENTITY, methods::SEARCH_IS_SOME, methods::UNNECESSARY_FILTER_MAP, methods::USELESS_ASREF, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index cfe8dea8837..63d1be8fe0d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -555,7 +555,7 @@ pub const ALL_LINTS: [Lint; 310] = [ }, Lint { name: "flat_map_identity", - group: "pedantic", + group: "complexity", desc: "call to `flat_map` where `flatten` is sufficient", deprecation: None, module: "methods", -- cgit 1.4.1-3-g733a5 From 42f03539caf6320a9618916e5328bb13aa442f30 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Wed, 7 Aug 2019 07:37:13 +0200 Subject: Deprecate unused_collect lint I found this because we only had two test cases in total for this lint. It turns out the functionality is fully covered by rustc these days. [Playground Examples](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eb8ee6db389c77180c9fb152d3c608f4) changelog: Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` cc #2846 --- README.md | 2 +- clippy_lints/src/deprecated_lints.rs | 8 ++++++ clippy_lints/src/lib.rs | 6 +++-- clippy_lints/src/loops.rs | 38 -------------------------- src/lintlist/mod.rs | 9 +------ tests/ui/deprecated.stderr | 8 +++++- tests/ui/deprecated_old.rs | 1 - tests/ui/deprecated_old.stderr | 8 +----- tests/ui/for_loop.rs | 1 - tests/ui/for_loop.stderr | 52 +++++++++++++++--------------------- tests/ui/infinite_iter.stderr | 10 +------ 11 files changed, 45 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 389fe316ade..8bcfd8a8430 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 310 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 309 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 4a6011042f4..97ae9c78088 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -122,3 +122,11 @@ declare_deprecated_lint! { pub INVALID_REF, "superseded by rustc lint `invalid_value`" } + +/// **What it does:** Nothing. This lint has been deprecated. +/// +/// **Deprecation reason:** This lint has been superseded by #[must_use] in rustc. +declare_deprecated_lint! { + pub UNUSED_COLLECT, + "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 70c00b02a2e..c8dbf77704c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -435,6 +435,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { "clippy::invalid_ref", "superseded by rustc lint `invalid_value`", ); + store.register_removed( + "clippy::unused_collect", + "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` reg.register_late_lint_pass(box serde_api::SerdeAPI); @@ -761,7 +765,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { loops::NEEDLESS_RANGE_LOOP, loops::NEVER_LOOP, loops::REVERSE_RANGE_LOOP, - loops::UNUSED_COLLECT, loops::WHILE_IMMUTABLE_CONDITION, loops::WHILE_LET_LOOP, loops::WHILE_LET_ON_ITERATOR, @@ -1142,7 +1145,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { large_enum_variant::LARGE_ENUM_VARIANT, loops::MANUAL_MEMCPY, loops::NEEDLESS_COLLECT, - loops::UNUSED_COLLECT, methods::EXPECT_FUN_CALL, methods::ITER_NTH, methods::OR_FUN_CALL, diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 1f9120a5383..7b36fa7e284 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -242,24 +242,6 @@ declare_clippy_lint! { "`loop { if let { ... } else break }`, which can be written as a `while let` loop" } -declare_clippy_lint! { - /// **What it does:** Checks for using `collect()` on an iterator without using - /// the result. - /// - /// **Why is this bad?** It is more idiomatic to use a `for` loop over the - /// iterator instead. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```ignore - /// vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>(); - /// ``` - pub UNUSED_COLLECT, - perf, - "`collect()`ing an iterator without using the result; this is usually better written as a for loop" -} - declare_clippy_lint! { /// **What it does:** Checks for functions collecting an iterator when collect /// is not needed. @@ -467,7 +449,6 @@ declare_lint_pass!(Loops => [ FOR_LOOP_OVER_RESULT, FOR_LOOP_OVER_OPTION, WHILE_LET_LOOP, - UNUSED_COLLECT, NEEDLESS_COLLECT, REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP, @@ -602,25 +583,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Loops { check_needless_collect(expr, cx); } - - fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { - if let StmtKind::Semi(ref expr) = stmt.node { - if let ExprKind::MethodCall(ref method, _, ref args) = expr.node { - if args.len() == 1 - && method.ident.name == sym!(collect) - && match_trait_method(cx, expr, &paths::ITERATOR) - { - span_lint( - cx, - UNUSED_COLLECT, - expr.span, - "you are collect()ing an iterator and throwing away the result. \ - Consider using an explicit for loop to exhaust the iterator", - ); - } - } - } - } } enum NeverLoopResult { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 63d1be8fe0d..c02cdcdbd45 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 310] = [ +pub const ALL_LINTS: [Lint; 309] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1967,13 +1967,6 @@ pub const ALL_LINTS: [Lint; 310] = [ deprecation: None, module: "misc_early", }, - Lint { - name: "unused_collect", - group: "perf", - desc: "`collect()`ing an iterator without using the result; this is usually better written as a for loop", - deprecation: None, - module: "loops", - }, Lint { name: "unused_io_amount", group: "correctness", diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index fa2cee03060..00ed4c5e51d 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -30,6 +30,12 @@ error: lint `clippy::misaligned_transmute` has been removed: `this lint has been LL | #[warn(clippy::misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint` + --> $DIR/deprecated.rs:6:8 + | +LL | #[warn(clippy::unused_collect)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value`` --> $DIR/deprecated.rs:7:8 | @@ -42,5 +48,5 @@ error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/deprecated_old.rs b/tests/ui/deprecated_old.rs index cd6a3a5bf5a..2e5c5b7ead1 100644 --- a/tests/ui/deprecated_old.rs +++ b/tests/ui/deprecated_old.rs @@ -3,6 +3,5 @@ #[warn(unstable_as_slice)] #[warn(unstable_as_mut_slice)] #[warn(misaligned_transmute)] -#[warn(unused_collect)] fn main() {} diff --git a/tests/ui/deprecated_old.stderr b/tests/ui/deprecated_old.stderr index 8c879fa97c7..ff3e9e8fcf3 100644 --- a/tests/ui/deprecated_old.stderr +++ b/tests/ui/deprecated_old.stderr @@ -30,17 +30,11 @@ error: lint `misaligned_transmute` has been removed: `this lint has been split i LL | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint name `unused_collect` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore - --> $DIR/deprecated_old.rs:6:8 - | -LL | #[warn(unused_collect)] - | ^^^^^^^^^^^^^^ help: change it to: `clippy::unused_collect` - error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated_old.rs:1:8 | LL | #[warn(str_to_string)] | ^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index f13f826b1cc..14f21f1b703 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -24,7 +24,6 @@ impl Unrelated { clippy::reverse_range_loop, clippy::for_kv_map )] -#[warn(clippy::unused_collect)] #[allow( clippy::linkedlist, clippy::shadow_unrelated, diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index 14082e8790b..257a05c02e0 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -1,5 +1,5 @@ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:40:14 + --> $DIR/for_loop.rs:39:14 | LL | for i in 10..0 { | ^^^^^ @@ -11,7 +11,7 @@ LL | for i in (0..10).rev() { | ^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:44:14 + --> $DIR/for_loop.rs:43:14 | LL | for i in 10..=0 { | ^^^^^^ @@ -21,7 +21,7 @@ LL | for i in (0...10).rev() { | ^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:48:14 + --> $DIR/for_loop.rs:47:14 | LL | for i in MAX_LEN..0 { | ^^^^^^^^^^ @@ -31,13 +31,13 @@ LL | for i in (0..MAX_LEN).rev() { | ^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:52:14 + --> $DIR/for_loop.rs:51:14 | LL | for i in 5..5 { | ^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:77:14 + --> $DIR/for_loop.rs:76:14 | LL | for i in 10..5 + 4 { | ^^^^^^^^^ @@ -47,7 +47,7 @@ LL | for i in (5 + 4..10).rev() { | ^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:81:14 + --> $DIR/for_loop.rs:80:14 | LL | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ @@ -57,13 +57,13 @@ LL | for i in ((3 - 1)..(5 + 2)).rev() { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop.rs:85:14 + --> $DIR/for_loop.rs:84:14 | LL | for i in (5 + 2)..(8 - 1) { | ^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:107:15 + --> $DIR/for_loop.rs:106:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -71,13 +71,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:109:15 + --> $DIR/for_loop.rs:108:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods` - --> $DIR/for_loop.rs:112:15 + --> $DIR/for_loop.rs:111:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -85,80 +85,72 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:115:15 + --> $DIR/for_loop.rs:114:15 | LL | for _v in array.into_iter() {} | ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&array` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:120:15 + --> $DIR/for_loop.rs:119:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:124:15 + --> $DIR/for_loop.rs:123:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:129:15 + --> $DIR/for_loop.rs:128:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:132:15 + --> $DIR/for_loop.rs:131:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:135:15 + --> $DIR/for_loop.rs:134:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:138:15 + --> $DIR/for_loop.rs:137:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:141:15 + --> $DIR/for_loop.rs:140:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:144:15 + --> $DIR/for_loop.rs:143:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop.rs:147:15 + --> $DIR/for_loop.rs:146:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop.rs:149:15 + --> $DIR/for_loop.rs:148:15 | LL | for _v in vec.iter().next() {} | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::iter-next-loop` implied by `-D warnings` -error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/for_loop.rs:156:5 - | -LL | vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unused-collect` implied by `-D warnings` - -error: aborting due to 22 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index ec30a54d381..61b40b3b340 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,11 +1,3 @@ -error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/infinite_iter.rs:10:5 - | -LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unused-collect` implied by `-D warnings` - error: infinite iteration detected --> $DIR/infinite_iter.rs:10:5 | @@ -113,5 +105,5 @@ LL | let _: HashSet<i32> = (0..).collect(); // Infinite iter | = note: `#[deny(clippy::infinite_iter)]` on by default -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors -- cgit 1.4.1-3-g733a5 From f4f31a4ff40a6763bb9adf7413773f3a6e701dd9 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <stucki.jeremy@gmail.com> Date: Thu, 15 Aug 2019 22:56:16 +0200 Subject: Implement lint 'suspicious_map' --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 1 + clippy_lints/src/methods/mod.rs | 28 ++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 ++++++++- 5 files changed, 39 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9013985ea..7e5dfa112cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1152,6 +1152,7 @@ Released 2018-09-13 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting +[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr diff --git a/README.md b/README.md index 8bcfd8a8430..389fe316ade 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 309 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 310 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8dbf77704c..2108b65dbd8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -657,6 +657,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, methods::RESULT_MAP_UNWRAP_OR_ELSE, + methods::SUSPICIOUS_MAP, misc::USED_UNDERSCORE_BINDING, misc_early::UNSEPARATED_LITERAL_SUFFIX, mut_mut::MUT_MUT, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0020dbd233d..fc2d2341533 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -889,6 +889,23 @@ declare_clippy_lint! { "using `.into_iter()` on a reference" } +declare_clippy_lint! { + /// **What it does:** Checks for calls to `map` followed by a `count`. + /// + /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// let _ = (0..3).map(|x| x + 2).count(); + /// ``` + pub SUSPICIOUS_MAP, + pedantic, + "suspicious usage of map" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -927,6 +944,7 @@ declare_lint_pass!(Methods => [ UNNECESSARY_FILTER_MAP, INTO_ITER_ON_ARRAY, INTO_ITER_ON_REF, + SUSPICIOUS_MAP, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { @@ -972,6 +990,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]), ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), + ["count", "map"] => lint_suspicious_map(cx, expr), _ => {}, } @@ -2519,6 +2538,15 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_ } } +fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr) { + span_lint( + cx, + SUSPICIOUS_MAP, + expr.span, + "Make sure you did not confuse `map` with `filter`.", + ); +} + /// Given a `Result<T, E>` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> { if let ty::Adt(_, substs) = ty.sty { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c02cdcdbd45..2d4520fb228 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 309] = [ +pub const ALL_LINTS: [Lint; 310] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1736,6 +1736,13 @@ pub const ALL_LINTS: [Lint; 309] = [ deprecation: None, module: "formatting", }, + Lint { + name: "suspicious_map", + group: "pedantic", + desc: "suspicious usage of map", + deprecation: None, + module: "methods", + }, Lint { name: "suspicious_op_assign_impl", group: "correctness", -- cgit 1.4.1-3-g733a5 From a68abc03a2a43455b56b8383001ab8282ee766ad Mon Sep 17 00:00:00 2001 From: "KRAAI, MATTHEW [VISUS]" <mkraai@its.jnj.com> Date: Fri, 16 Aug 2019 05:41:35 -0700 Subject: Remove "a" from single_match_else description --- clippy_lints/src/matches.rs | 4 ++-- src/lintlist/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 8a6f6970e1b..52265ae55bf 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for matches with a two arms where an `if let else` will + /// **What it does:** Checks for matches with two arms where an `if let else` will /// usually suffice. /// /// **Why is this bad?** Just readability – `if let` nests less than a `match`. @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` pub SINGLE_MATCH_ELSE, pedantic, - "a match statement with a two arms where the second arm's pattern is a placeholder instead of a specific match pattern" + "a match statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern" } declare_clippy_lint! { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c02cdcdbd45..0df8370936c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1676,7 +1676,7 @@ pub const ALL_LINTS: [Lint; 309] = [ Lint { name: "single_match_else", group: "pedantic", - desc: "a match statement with a two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", + desc: "a match statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", deprecation: None, module: "matches", }, -- cgit 1.4.1-3-g733a5 From 9c39c02b758c96d94ea1ba648ef77efff2631b86 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki <jeremy@myelin.ch> Date: Sun, 18 Aug 2019 16:49:11 +0200 Subject: Change lint type to 'complexity' --- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/methods/mod.rs | 10 ++++++---- src/lintlist/mod.rs | 2 +- tests/ui/suspicious_map.stderr | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 308c3e918e8..705ec2e9fd8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -657,7 +657,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, methods::RESULT_MAP_UNWRAP_OR_ELSE, - methods::SUSPICIOUS_MAP, misc::USED_UNDERSCORE_BINDING, misc_early::UNSEPARATED_LITERAL_SUFFIX, mut_mut::MUT_MUT, @@ -801,6 +800,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::SHOULD_IMPLEMENT_TRAIT, methods::SINGLE_CHAR_PATTERN, methods::STRING_EXTEND_CHARS, + methods::SUSPICIOUS_MAP, methods::TEMPORARY_CSTRING_AS_PTR, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, @@ -1034,6 +1034,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::FILTER_NEXT, methods::FLAT_MAP_IDENTITY, methods::SEARCH_IS_SOME, + methods::SUSPICIOUS_MAP, methods::UNNECESSARY_FILTER_MAP, methods::USELESS_ASREF, misc::SHORT_CIRCUIT_STATEMENT, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc2d2341533..c8e3ca14ab1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -18,7 +18,6 @@ use syntax::ast; use syntax::source_map::Span; use syntax::symbol::LocalInternedString; -use crate::utils::paths; use crate::utils::sugg; use crate::utils::usage::mutated_variables; use crate::utils::{ @@ -28,6 +27,7 @@ use crate::utils::{ snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; +use crate::utils::{paths, span_help_and_lint}; declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s. @@ -893,6 +893,7 @@ declare_clippy_lint! { /// **What it does:** Checks for calls to `map` followed by a `count`. /// /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`. + /// If the `map` call is intentional, this should be rewritten. /// /// **Known problems:** None /// @@ -902,7 +903,7 @@ declare_clippy_lint! { /// let _ = (0..3).map(|x| x + 2).count(); /// ``` pub SUSPICIOUS_MAP, - pedantic, + complexity, "suspicious usage of map" } @@ -2539,11 +2540,12 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_ } fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr) { - span_lint( + span_help_and_lint( cx, SUSPICIOUS_MAP, expr.span, - "Make sure you did not confuse `map` with `filter`.", + "this call to `map()` won't have an effect on the call to `count()`", + "make sure you did not confuse `map` with `filter`", ); } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 36a45f705e7..ff7db0a3da7 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1738,7 +1738,7 @@ pub const ALL_LINTS: [Lint; 310] = [ }, Lint { name: "suspicious_map", - group: "pedantic", + group: "complexity", desc: "suspicious usage of map", deprecation: None, module: "methods", diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr index 434ea089fed..e6588f4691a 100644 --- a/tests/ui/suspicious_map.stderr +++ b/tests/ui/suspicious_map.stderr @@ -1,10 +1,11 @@ -error: Make sure you did not confuse `map` with `filter`. +error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:4:13 | LL | let _ = (0..3).map(|x| x + 2).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-map` implied by `-D warnings` + = help: make sure you did not confuse `map` with `filter` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 76598adafb2c3032a87544b260584fb526a6f2a5 Mon Sep 17 00:00:00 2001 From: xd009642 <danielmckenna93@gmail.com> Date: Sun, 18 Aug 2019 16:59:31 +0100 Subject: Run update_lints --- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3054f11c176..8f5dc88e6de 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -666,6 +666,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { replace_consts::REPLACE_CONSTS, shadow::SHADOW_UNRELATED, strings::STRING_ADD_ASSIGN, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, types::CAST_POSSIBLE_TRUNCATION, types::CAST_POSSIBLE_WRAP, types::CAST_PRECISION_LOSS, @@ -870,7 +871,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { swap::ALMOST_SWAPPED, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, transmute::TRANSMUTE_BYTES_TO_STR, transmute::TRANSMUTE_INT_TO_BOOL, @@ -1056,7 +1056,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reference::REF_IN_DEREF, swap::MANUAL_SWAP, temporary_assignment::TEMPORARY_ASSIGNMENT, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, transmute::TRANSMUTE_BYTES_TO_STR, transmute::TRANSMUTE_INT_TO_BOOL, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0df8370936c..7d36825df0a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1857,7 +1857,7 @@ pub const ALL_LINTS: [Lint; 309] = [ }, Lint { name: "type_repetition_in_bounds", - group: "complexity", + group: "pedantic", desc: "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`", deprecation: None, module: "trait_bounds", -- cgit 1.4.1-3-g733a5 From 7065239da55420e26adb7cb647fc7eb4e9c8798e Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Thu, 15 Aug 2019 10:53:11 +0700 Subject: Add option_and_then_some lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_dev/src/lib.rs | 6 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 129 +++++++++++++++++++++++++++++++++-- src/lintlist/mod.rs | 9 ++- tests/ui/option_and_then_some.fixed | 21 ++++++ tests/ui/option_and_then_some.rs | 21 ++++++ tests/ui/option_and_then_some.stderr | 20 ++++++ 9 files changed, 201 insertions(+), 10 deletions(-) create mode 100644 tests/ui/option_and_then_some.fixed create mode 100644 tests/ui/option_and_then_some.rs create mode 100644 tests/ui/option_and_then_some.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e5dfa112cf..59dfde0b6f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1088,6 +1088,7 @@ Released 2018-09-13 [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref +[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or diff --git a/README.md b/README.md index 389fe316ade..e5da763607b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 310 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 311 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index db407565b19..b53a5579971 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -123,13 +123,13 @@ pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> { lints .iter() .filter_map(|l| { - l.clone().deprecation.and_then(|depr_text| { - Some(vec![ + l.clone().deprecation.map(|depr_text| { + vec![ " store.register_removed(".to_string(), format!(" \"clippy::{}\",", l.name), format!(" \"{}\",", depr_text), " );".to_string(), - ]) + ] }) }) .flatten() diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e9a251d4bd..4d568a8a8b0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -795,6 +795,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::ITER_SKIP_NEXT, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, + methods::OPTION_AND_THEN_SOME, methods::OPTION_MAP_OR_NONE, methods::OR_FUN_CALL, methods::SEARCH_IS_SOME, @@ -1033,6 +1034,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::CLONE_ON_COPY, methods::FILTER_NEXT, methods::FLAT_MAP_IDENTITY, + methods::OPTION_AND_THEN_SOME, methods::SEARCH_IS_SOME, methods::SUSPICIOUS_MAP, methods::UNNECESSARY_FILTER_MAP, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c8e3ca14ab1..8d062bd897c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -21,11 +21,11 @@ use syntax::symbol::LocalInternedString; use crate::utils::sugg; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, - is_ctor_function, is_expn_of, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, - match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, - snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg, - span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, in_macro_or_desugar, + is_copy, is_ctor_function, is_expn_of, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, + single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; use crate::utils::{paths, span_help_and_lint}; @@ -264,6 +264,32 @@ declare_clippy_lint! { "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`. + /// + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.map(|x| y)`. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// let x = Some("foo"); + /// let _ = x.and_then(|s| Some(s.len())); + /// ``` + /// + /// The correct use would be: + /// + /// ```rust + /// let x = Some("foo"); + /// let _ = x.map(|s| s.len()); + /// ``` + pub OPTION_AND_THEN_SOME, + complexity, + "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.filter(_).next()`. /// @@ -918,6 +944,7 @@ declare_lint_pass!(Methods => [ OPTION_MAP_UNWRAP_OR_ELSE, RESULT_MAP_UNWRAP_OR_ELSE, OPTION_MAP_OR_NONE, + OPTION_AND_THEN_SOME, OR_FUN_CALL, EXPECT_FUN_CALL, CHARS_NEXT_CMP, @@ -967,6 +994,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0]), ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]), ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), + ["and_then", ..] => lint_option_and_then_some(cx, expr, arg_lists[0]), ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -2072,6 +2100,97 @@ fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, } } +/// Lint use of `_.and_then(|x| Some(y))` for `Option`s +fn lint_option_and_then_some(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { + const LINT_MSG: &str = "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"; + const NO_OP_MSG: &str = "using `Option.and_then(Some)`, which is a no-op"; + + // Searches an return expressions in `y` in `_.and_then(|x| Some(y))`, which we don't lint + struct RetCallFinder { + found: bool, + } + + impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + if self.found { + return; + } + if let hir::ExprKind::Ret(..) = &expr.node { + self.found = true; + } else { + intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::None + } + } + + let ty = cx.tables.expr_ty(&args[0]); + if !match_type(cx, ty, &paths::OPTION) { + return; + } + + match args[1].node { + hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => { + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); + if_chain! { + if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.node; + if let hir::ExprKind::Path(ref qpath) = some_expr.node; + if match_qpath(qpath, &paths::OPTION_SOME); + if some_args.len() == 1; + then { + let inner_expr = &some_args[0]; + + let mut finder = RetCallFinder { found: false }; + finder.visit_expr(inner_expr); + if finder.found { + return; + } + + let some_inner_snip = if in_macro_or_desugar(inner_expr.span) { + snippet_with_macro_callsite(cx, inner_expr.span, "_") + } else { + snippet(cx, inner_expr.span, "_") + }; + + let closure_args_snip = snippet(cx, closure_args_span, ".."); + let option_snip = snippet(cx, args[0].span, ".."); + let note = format!("{}.map({} {})", option_snip, closure_args_snip, some_inner_snip); + span_lint_and_sugg( + cx, + OPTION_AND_THEN_SOME, + expr.span, + LINT_MSG, + "try this", + note, + Applicability::MachineApplicable, + ); + } + } + }, + // `_.and_then(Some)` case, which is no-op. + hir::ExprKind::Path(ref qpath) => { + if match_qpath(qpath, &paths::OPTION_SOME) { + let option_snip = snippet(cx, args[0].span, ".."); + let note = format!("{}", option_snip); + span_lint_and_sugg( + cx, + OPTION_AND_THEN_SOME, + expr.span, + NO_OP_MSG, + "use the expression directly", + note, + Applicability::MachineApplicable, + ); + } + }, + _ => {}, + } +} + /// lint use of `filter().next()` for `Iterators` fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) { // lint if caller of `.filter().next()` is an Iterator diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 485352f5cc4..9abe4558bb9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 310] = [ +pub const ALL_LINTS: [Lint; 311] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1316,6 +1316,13 @@ pub const ALL_LINTS: [Lint; 310] = [ deprecation: None, module: "eq_op", }, + Lint { + name: "option_and_then_some", + group: "complexity", + desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`", + deprecation: None, + module: "methods", + }, Lint { name: "option_map_or_none", group: "style", diff --git a/tests/ui/option_and_then_some.fixed b/tests/ui/option_and_then_some.fixed new file mode 100644 index 00000000000..852f48879a3 --- /dev/null +++ b/tests/ui/option_and_then_some.fixed @@ -0,0 +1,21 @@ +// run-rustfix +#![deny(clippy::option_and_then_some)] + +// need a main anyway, use it get rid of unused warnings too +pub fn main() { + let x = Some(5); + // the easiest cases + let _ = x; + let _ = x.map(|o| o + 1); + // and an easy counter-example + let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); + + // Different type + let x: Result<u32, &str> = Ok(1); + let _ = x.and_then(Ok); +} + +pub fn foo() -> Option<String> { + let x = Some(String::from("hello")); + Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?))) +} diff --git a/tests/ui/option_and_then_some.rs b/tests/ui/option_and_then_some.rs new file mode 100644 index 00000000000..aebc66374a5 --- /dev/null +++ b/tests/ui/option_and_then_some.rs @@ -0,0 +1,21 @@ +// run-rustfix +#![deny(clippy::option_and_then_some)] + +// need a main anyway, use it get rid of unused warnings too +pub fn main() { + let x = Some(5); + // the easiest cases + let _ = x.and_then(Some); + let _ = x.and_then(|o| Some(o + 1)); + // and an easy counter-example + let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); + + // Different type + let x: Result<u32, &str> = Ok(1); + let _ = x.and_then(Ok); +} + +pub fn foo() -> Option<String> { + let x = Some(String::from("hello")); + Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?))) +} diff --git a/tests/ui/option_and_then_some.stderr b/tests/ui/option_and_then_some.stderr new file mode 100644 index 00000000000..a3b0a26149e --- /dev/null +++ b/tests/ui/option_and_then_some.stderr @@ -0,0 +1,20 @@ +error: using `Option.and_then(Some)`, which is a no-op + --> $DIR/option_and_then_some.rs:8:13 + | +LL | let _ = x.and_then(Some); + | ^^^^^^^^^^^^^^^^ help: use the expression directly: `x` + | +note: lint level defined here + --> $DIR/option_and_then_some.rs:2:9 + | +LL | #![deny(clippy::option_and_then_some)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` + --> $DIR/option_and_then_some.rs:9:13 + | +LL | let _ = x.and_then(|o| Some(o + 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 08d8ffc6a970a4e0886b36b332cdc4f6622e81f1 Mon Sep 17 00:00:00 2001 From: Simon Sapin <simon.sapin@exyr.org> Date: Mon, 19 Aug 2019 17:51:39 +0200 Subject: Import rustc_plugin from its new location Depends on https://github.com/rust-lang/rust/pull/62727 --- CONTRIBUTING.md | 10 +++++----- clippy_lints/src/lib.rs | 8 ++++---- src/driver.rs | 6 ++---- src/lib.rs | 4 +--- 4 files changed, 12 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8786413c3a1..2a85197068f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,7 +90,7 @@ Clippy is a [rustc compiler plugin][compiler_plugin]. The main entry point is at pub mod else_if_without_else; // ... -pub fn register_plugins(reg: &mut rustc_plugin::Registry) { +pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry) { // ... reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse); // ... @@ -103,7 +103,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { } ``` -The [`rustc_plugin::PluginRegistry`][plugin_registry] provides two methods to register lints: [register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass]. +The [`plugin::PluginRegistry`][plugin_registry] provides two methods to register lints: [register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass]. Both take an object that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/dev update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time. @@ -193,9 +193,9 @@ or the [MIT](http://opensource.org/licenses/MIT) license. [lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/lib.rs [else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/else_if_without_else.rs [compiler_plugin]: https://doc.rust-lang.org/unstable-book/language-features/plugin.html#lint-plugins -[plugin_registry]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin/registry/struct.Registry.html -[reg_early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin/registry/struct.Registry.html#method.register_early_lint_pass -[reg_late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin/registry/struct.Registry.html#method.register_late_lint_pass +[plugin_registry]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html +[reg_early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html#method.register_early_lint_pass +[reg_late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_plugin_impl/registry/struct.Registry.html#method.register_late_lint_pass [early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html [late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.LateLintPass.html [toolstate_commit_history]: https://github.com/rust-lang-nursery/rust-toolstate/commits/master diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4d568a8a8b0..0ae93c6147a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -23,12 +23,12 @@ extern crate rustc; #[allow(unused_extern_crates)] extern crate rustc_data_structures; #[allow(unused_extern_crates)] +extern crate rustc_driver; +#[allow(unused_extern_crates)] extern crate rustc_errors; #[allow(unused_extern_crates)] extern crate rustc_mir; #[allow(unused_extern_crates)] -extern crate rustc_plugin; -#[allow(unused_extern_crates)] extern crate rustc_target; #[allow(unused_extern_crates)] extern crate rustc_typeck; @@ -320,7 +320,7 @@ pub fn register_pre_expansion_lints( } #[doc(hidden)] -pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { +pub fn read_conf(reg: &rustc_driver::plugin::Registry<'_>) -> Conf { match utils::conf::file_from_args(reg.args()) { Ok(file_name) => { // if the user specified a file, it must exist, otherwise default to `clippy.toml` but @@ -382,7 +382,7 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf { /// Used in `./src/driver.rs`. #[allow(clippy::too_many_lines)] #[rustfmt::skip] -pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { +pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Conf) { let mut store = reg.sess.lint_store.borrow_mut(); register_removed_non_tool_lints(&mut store); diff --git a/src/driver.rs b/src/driver.rs index cec88be7eb1..92f83f1a29e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -7,8 +7,6 @@ extern crate rustc_driver; #[allow(unused_extern_crates)] extern crate rustc_interface; -#[allow(unused_extern_crates)] -extern crate rustc_plugin; use rustc_interface::interface; use rustc_tools_util::*; @@ -65,7 +63,7 @@ struct ClippyCallbacks; impl rustc_driver::Callbacks for ClippyCallbacks { fn after_parsing(&mut self, compiler: &interface::Compiler) -> rustc_driver::Compilation { let sess = compiler.session(); - let mut registry = rustc_plugin::registry::Registry::new( + let mut registry = rustc_driver::plugin::registry::Registry::new( sess, compiler .parse() @@ -81,7 +79,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_lints::read_conf(®istry); clippy_lints::register_plugins(&mut registry, &conf); - let rustc_plugin::registry::Registry { + let rustc_driver::plugin::registry::Registry { early_lint_passes, late_lint_passes, lint_groups, diff --git a/src/lib.rs b/src/lib.rs index 86174a6b316..76e1c711656 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,9 +7,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] extern crate rustc_driver; -#[allow(unused_extern_crates)] -extern crate rustc_plugin; -use self::rustc_plugin::Registry; +use self::rustc_driver::plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry<'_>) { -- cgit 1.4.1-3-g733a5 From ab335eacb4ac87c30907fc536c509c70c66c8d8f Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Fri, 23 Aug 2019 09:49:49 +0000 Subject: Run update_lints for Unicode lint --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9abe4558bb9..b7a6e486f0b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1879,7 +1879,7 @@ pub const ALL_LINTS: [Lint; 311] = [ Lint { name: "unicode_not_nfc", group: "pedantic", - desc: "using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", + desc: "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", deprecation: None, module: "unicode", }, -- cgit 1.4.1-3-g733a5 From b01f2d11263ae67ddea62dc0ee989d44db8873bb Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Sat, 31 Aug 2019 20:25:28 +0200 Subject: lint against `MaybeUninit::uninit().assume_init()` --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/methods/mod.rs | 65 +++++++++++++++++++++++++++++++++++++++++ clippy_lints/src/utils/paths.rs | 2 ++ src/lintlist/mod.rs | 9 +++++- tests/ui/uninit.rs | 23 +++++++++++++++ tests/ui/uninit.stderr | 16 ++++++++++ 8 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 tests/ui/uninit.rs create mode 100644 tests/ui/uninit.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 46c2be3010d..5a550e8d84f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1176,6 +1176,7 @@ Released 2018-09-13 [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints diff --git a/README.md b/README.md index e5da763607b..bd97910f597 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 311 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 312 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0ae93c6147a..4383b8b733a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -804,6 +804,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, methods::TEMPORARY_CSTRING_AS_PTR, + methods::UNINIT_ASSUMED_INIT, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, methods::USELESS_ASREF, @@ -1116,6 +1117,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::CLONE_DOUBLE_REF, methods::INTO_ITER_ON_ARRAY, methods::TEMPORARY_CSTRING_AS_PTR, + methods::UNINIT_ASSUMED_INIT, minmax::MIN_MAX, misc::CMP_NAN, misc::FLOAT_CMP, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 110d161471f..ea208953a40 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -951,6 +951,38 @@ declare_clippy_lint! { "suspicious usage of map" } +declare_clippy_lint! { + /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`. + /// + /// **Why is this bad?** For most types, this is undefined behavior. + /// + /// **Known problems:** For now, we accept empty tuples and tuples / arrays + /// of `MaybeUninit`. There may be other types that allow uninitialized + /// data, but those are not yet rigorously defined. + /// + /// **Example:** + /// + /// ```rust + /// // Beware the UB + /// use std::mem::MaybeUninit; + /// + /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; + /// ``` + /// + /// Note that the following is OK: + /// + /// ```rust + /// use std::mem::MaybeUninit; + /// + /// let _: [MaybeUninit<bool>; 5] = unsafe { + /// MaybeUninit::uninit().assume_init() + /// }; + /// ``` + pub UNINIT_ASSUMED_INIT, + correctness, + "`MaybeUninit::uninit().assume_init()`" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -991,6 +1023,7 @@ declare_lint_pass!(Methods => [ INTO_ITER_ON_ARRAY, INTO_ITER_ON_REF, SUSPICIOUS_MAP, + UNINIT_ASSUMED_INIT, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { @@ -1038,6 +1071,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]), ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), ["count", "map"] => lint_suspicious_map(cx, expr), + ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), _ => {}, } @@ -2662,6 +2696,37 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_ } } +/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter) +fn lint_maybe_uninit(cx: &LateContext<'_, '_>, expr: &hir::Expr, outer: &hir::Expr) { + if_chain! { + if let hir::ExprKind::Call(ref callee, ref args) = expr.node; + if args.is_empty(); + if let hir::ExprKind::Path(ref path) = callee.node; + if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); + if !is_maybe_uninit_ty_valid(cx, cx.tables.expr_ty_adjusted(outer)); + then { + span_lint( + cx, + UNINIT_ASSUMED_INIT, + outer.span, + "this call for this type may be undefined behavior" + ); + } + } +} + +fn is_maybe_uninit_ty_valid(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool { + match ty.sty { + ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component), + ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), + ty::Adt(ref adt, _) => { + // needs to be a MaybeUninit + match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT) + }, + _ => false, + } +} + fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr) { span_help_and_lint( cx, diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 55e1387fe99..9b88a0d3089 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -49,6 +49,8 @@ pub const LINT: [&str; 3] = ["rustc", "lint", "Lint"]; pub const LINT_PASS: [&str; 3] = ["rustc", "lint", "LintPass"]; pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"]; pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; +pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; +pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b7a6e486f0b..8d236323825 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 311] = [ +pub const ALL_LINTS: [Lint; 312] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1890,6 +1890,13 @@ pub const ALL_LINTS: [Lint; 311] = [ deprecation: None, module: "panic_unimplemented", }, + Lint { + name: "uninit_assumed_init", + group: "correctness", + desc: "`MaybeUninit::uninit().assume_init()`", + deprecation: None, + module: "methods", + }, Lint { name: "unit_arg", group: "complexity", diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs new file mode 100644 index 00000000000..a4424c490e7 --- /dev/null +++ b/tests/ui/uninit.rs @@ -0,0 +1,23 @@ +#![feature(stmt_expr_attributes)] + +use std::mem::MaybeUninit; + +#[allow(clippy::let_unit_value)] +fn main() { + let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; + + // edge case: For now we lint on empty arrays + let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; + + // edge case: For now we accept unit tuples + let _: () = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because `MaybeUninit` allows uninitialized data. + let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because all constitutent types are uninit-compatible. + let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because all constitutent types are uninit-compatible. + let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; +} diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr new file mode 100644 index 00000000000..f4c45354aef --- /dev/null +++ b/tests/ui/uninit.stderr @@ -0,0 +1,16 @@ +error: this call for this type may be undefined behavior + --> $DIR/uninit.rs:7:29 + | +LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::uninit_assumed_init)]` on by default + +error: this call for this type may be undefined behavior + --> $DIR/uninit.rs:10:31 + | +LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 4960f79476def4c9a1cbde94d349d4c9b12bd585 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada <sinkuu@sinkuu.xyz> Date: Wed, 4 Sep 2019 16:08:48 +0900 Subject: Add manual_saturating_arithmetic lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + .../src/methods/checked_arith_unwrap_or.rs | 173 +++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 32 ++++ src/lintlist/mod.rs | 9 +- tests/ui/manual_saturating_arithmetic.fixed | 45 ++++++ tests/ui/manual_saturating_arithmetic.rs | 55 +++++++ tests/ui/manual_saturating_arithmetic.stderr | 163 +++++++++++++++++++ 9 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/checked_arith_unwrap_or.rs create mode 100644 tests/ui/manual_saturating_arithmetic.fixed create mode 100644 tests/ui/manual_saturating_arithmetic.rs create mode 100644 tests/ui/manual_saturating_arithmetic.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a550e8d84f..dbdf3df4ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1034,6 +1034,7 @@ Released 2018-09-13 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone diff --git a/README.md b/README.md index bd97910f597..dd315fd397b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 312 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 313 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4383b8b733a..a9294da59b6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -793,6 +793,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::ITER_CLONED_COLLECT, methods::ITER_NTH, methods::ITER_SKIP_NEXT, + methods::MANUAL_SATURATING_ARITHMETIC, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, methods::OPTION_AND_THEN_SOME, @@ -958,6 +959,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::INTO_ITER_ON_REF, methods::ITER_CLONED_COLLECT, methods::ITER_SKIP_NEXT, + methods::MANUAL_SATURATING_ARITHMETIC, methods::NEW_RET_NO_SELF, methods::OK_EXPECT, methods::OPTION_MAP_OR_NONE, diff --git a/clippy_lints/src/methods/checked_arith_unwrap_or.rs b/clippy_lints/src/methods/checked_arith_unwrap_or.rs new file mode 100644 index 00000000000..6bfd402f7b1 --- /dev/null +++ b/clippy_lints/src/methods/checked_arith_unwrap_or.rs @@ -0,0 +1,173 @@ +use crate::utils::{match_qpath, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc::hir; +use rustc::lint::LateContext; +use rustc_errors::Applicability; +use rustc_target::abi::LayoutOf; +use syntax::ast; + +pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[&[hir::Expr]], arith: &str) { + let unwrap_arg = &args[0][1]; + let arith_lhs = &args[1][0]; + let arith_rhs = &args[1][1]; + + let ty = cx.tables.expr_ty(arith_lhs); + if !ty.is_integral() { + return; + } + + let mm = if let Some(mm) = is_min_or_max(cx, unwrap_arg) { + mm + } else { + return; + }; + + if ty.is_signed() { + use self::{MinMax::*, Sign::*}; + + let sign = if let Some(sign) = lit_sign(arith_rhs) { + sign + } else { + return; + }; + + match (arith, sign, mm) { + ("add", Pos, Max) | ("add", Neg, Min) | ("sub", Neg, Max) | ("sub", Pos, Min) => (), + // "mul" is omitted because lhs can be negative. + _ => return, + } + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + super::MANUAL_SATURATING_ARITHMETIC, + expr.span, + "manual saturating arithmetic", + &format!("try using `saturating_{}`", arith), + format!( + "{}.saturating_{}({})", + snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), + arith, + snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), + ), + applicability, + ); + } else { + match (mm, arith) { + (MinMax::Max, "add") | (MinMax::Max, "mul") | (MinMax::Min, "sub") => (), + _ => return, + } + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + super::MANUAL_SATURATING_ARITHMETIC, + expr.span, + "manual saturating arithmetic", + &format!("try using `saturating_{}`", arith), + format!( + "{}.saturating_{}({})", + snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), + arith, + snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability), + ), + applicability, + ); + } +} + +#[derive(PartialEq, Eq)] +enum MinMax { + Min, + Max, +} + +fn is_min_or_max<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr) -> Option<MinMax> { + // `T::max_value()` `T::min_value()` inherent methods + if_chain! { + if let hir::ExprKind::Call(func, args) = &expr.node; + if args.is_empty(); + if let hir::ExprKind::Path(path) = &func.node; + if let hir::QPath::TypeRelative(_, segment) = path; + then { + match &*segment.ident.as_str() { + "max_value" => return Some(MinMax::Max), + "min_value" => return Some(MinMax::Min), + _ => {} + } + } + } + + let ty = cx.tables.expr_ty(expr); + let ty_str = ty.to_string(); + + // `std::T::MAX` `std::T::MIN` constants + if let hir::ExprKind::Path(path) = &expr.node { + if match_qpath(path, &["core", &ty_str, "MAX"][..]) { + return Some(MinMax::Max); + } + + if match_qpath(path, &["core", &ty_str, "MIN"][..]) { + return Some(MinMax::Min); + } + } + + // Literals + let bits = cx.layout_of(ty).unwrap().size.bits(); + let (minval, maxval): (u128, u128) = if ty.is_signed() { + let minval = 1 << (bits - 1); + let mut maxval = !(1 << (bits - 1)); + if bits != 128 { + maxval &= (1 << bits) - 1; + } + (minval, maxval) + } else { + (0, if bits == 128 { !0 } else { (1 << bits) - 1 }) + }; + + let check_lit = |expr: &hir::Expr, check_min: bool| { + if let hir::ExprKind::Lit(lit) = &expr.node { + if let ast::LitKind::Int(value, _) = lit.node { + if value == maxval { + return Some(MinMax::Max); + } + + if check_min && value == minval { + return Some(MinMax::Min); + } + } + } + + None + }; + + if let r @ Some(_) = check_lit(expr, !ty.is_signed()) { + return r; + } + + if ty.is_signed() { + if let hir::ExprKind::Unary(hir::UnNeg, val) = &expr.node { + return check_lit(val, true); + } + } + + None +} + +#[derive(PartialEq, Eq)] +enum Sign { + Pos, + Neg, +} + +fn lit_sign(expr: &hir::Expr) -> Option<Sign> { + if let hir::ExprKind::Unary(hir::UnNeg, inner) = &expr.node { + if let hir::ExprKind::Lit(..) = &inner.node { + return Some(Sign::Neg); + } + } else if let hir::ExprKind::Lit(..) = &expr.node { + return Some(Sign::Pos); + } + + None +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ea208953a40..4c1f13daa24 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,4 @@ +mod checked_arith_unwrap_or; mod option_map_unwrap_or; mod unnecessary_filter_map; @@ -983,6 +984,31 @@ declare_clippy_lint! { "`MaybeUninit::uninit().assume_init()`" } +declare_clippy_lint! { + /// **What it does:** Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`. + /// + /// **Why is this bad?** These can be written simply with `saturating_add/sub` methods. + /// + /// **Example:** + /// + /// ```rust + /// let x: u32 = 100; + /// + /// let add = x.checked_add(y).unwrap_or(u32::max_value()); + /// let sub = x.checked_sub(y).unwrap_or(u32::min_value()); + /// ``` + /// + /// can be written using dedicated methods for saturating addition/subtraction as: + /// + /// ```rust + /// let add = x.saturating_add(y); + /// let sub = x.saturating_sub(y); + /// ``` + pub MANUAL_SATURATING_ARITHMETIC, + style, + "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -1024,6 +1050,7 @@ declare_lint_pass!(Methods => [ INTO_ITER_ON_REF, SUSPICIOUS_MAP, UNINIT_ASSUMED_INIT, + MANUAL_SATURATING_ARITHMETIC, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { @@ -1072,6 +1099,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), + ["unwrap_or", arith @ "checked_add"] + | ["unwrap_or", arith @ "checked_sub"] + | ["unwrap_or", arith @ "checked_mul"] => { + checked_arith_unwrap_or::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) + }, _ => {}, } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8d236323825..be09ac321d2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 312] = [ +pub const ALL_LINTS: [Lint; 313] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -931,6 +931,13 @@ pub const ALL_LINTS: [Lint; 312] = [ deprecation: None, module: "loops", }, + Lint { + name: "manual_saturating_arithmetic", + group: "style", + desc: "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`", + deprecation: None, + module: "methods", + }, Lint { name: "manual_swap", group: "complexity", diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed new file mode 100644 index 00000000000..c4f53c446c9 --- /dev/null +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -0,0 +1,45 @@ +// run-rustfix + +#![allow(unused_imports)] + +use std::{i128, i32, u128, u32}; + +fn main() { + let _ = 1u32.saturating_add(1); + let _ = 1u32.saturating_add(1); + let _ = 1u8.saturating_add(1); + let _ = 1u128.saturating_add(1); + let _ = 1u32.checked_add(1).unwrap_or(1234); // ok + let _ = 1u8.checked_add(1).unwrap_or(0); // ok + let _ = 1u32.saturating_mul(1); + + let _ = 1u32.saturating_sub(1); + let _ = 1u32.saturating_sub(1); + let _ = 1u8.saturating_sub(1); + let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok + let _ = 1u8.checked_sub(1).unwrap_or(255); // ok + + let _ = 1i32.saturating_add(1); + let _ = 1i32.saturating_add(1); + let _ = 1i8.saturating_add(1); + let _ = 1i128.saturating_add(1); + let _ = 1i32.saturating_add(-1); + let _ = 1i32.saturating_add(-1); + let _ = 1i8.saturating_add(-1); + let _ = 1i128.saturating_add(-1); + let _ = 1i32.checked_add(1).unwrap_or(1234); // ok + let _ = 1i8.checked_add(1).unwrap_or(-128); // ok + let _ = 1i8.checked_add(-1).unwrap_or(127); // ok + + let _ = 1i32.saturating_sub(1); + let _ = 1i32.saturating_sub(1); + let _ = 1i8.saturating_sub(1); + let _ = 1i128.saturating_sub(1); + let _ = 1i32.saturating_sub(-1); + let _ = 1i32.saturating_sub(-1); + let _ = 1i8.saturating_sub(-1); + let _ = 1i128.saturating_sub(-1); + let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok + let _ = 1i8.checked_sub(1).unwrap_or(127); // ok + let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok +} diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs new file mode 100644 index 00000000000..cd83cf6e65e --- /dev/null +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -0,0 +1,55 @@ +// run-rustfix + +#![allow(unused_imports)] + +use std::{i128, i32, u128, u32}; + +fn main() { + let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); + let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); + let _ = 1u8.checked_add(1).unwrap_or(255); + let _ = 1u128 + .checked_add(1) + .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); + let _ = 1u32.checked_add(1).unwrap_or(1234); // ok + let _ = 1u8.checked_add(1).unwrap_or(0); // ok + let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); + + let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); + let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); + let _ = 1u8.checked_sub(1).unwrap_or(0); + let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok + let _ = 1u8.checked_sub(1).unwrap_or(255); // ok + + let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); + let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); + let _ = 1i8.checked_add(1).unwrap_or(127); + let _ = 1i128 + .checked_add(1) + .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); + let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); + let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); + let _ = 1i8.checked_add(-1).unwrap_or(-128); + let _ = 1i128 + .checked_add(-1) + .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); + let _ = 1i32.checked_add(1).unwrap_or(1234); // ok + let _ = 1i8.checked_add(1).unwrap_or(-128); // ok + let _ = 1i8.checked_add(-1).unwrap_or(127); // ok + + let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); + let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); + let _ = 1i8.checked_sub(1).unwrap_or(-128); + let _ = 1i128 + .checked_sub(1) + .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); + let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); + let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); + let _ = 1i8.checked_sub(-1).unwrap_or(127); + let _ = 1i128 + .checked_sub(-1) + .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); + let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok + let _ = 1i8.checked_sub(1).unwrap_or(127); // ok + let _ = 1i8.checked_sub(-1).unwrap_or(-128); // ok +} diff --git a/tests/ui/manual_saturating_arithmetic.stderr b/tests/ui/manual_saturating_arithmetic.stderr new file mode 100644 index 00000000000..d985f2e754b --- /dev/null +++ b/tests/ui/manual_saturating_arithmetic.stderr @@ -0,0 +1,163 @@ +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:8:13 + | +LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + | + = note: `-D clippy::manual-saturating-arithmetic` implied by `-D warnings` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:9:13 + | +LL | let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u32.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:10:13 + | +LL | let _ = 1u8.checked_add(1).unwrap_or(255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1u8.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:11:13 + | +LL | let _ = 1u128 + | _____________^ +LL | | .checked_add(1) +LL | | .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); + | |_______________________________________________________________________^ help: try using `saturating_add`: `1u128.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:16:13 + | +LL | let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_mul`: `1u32.saturating_mul(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:18:13 + | +LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:19:13 + | +LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u32.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:20:13 + | +LL | let _ = 1u8.checked_sub(1).unwrap_or(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1u8.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:24:13 + | +LL | let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:25:13 + | +LL | let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:26:13 + | +LL | let _ = 1i8.checked_add(1).unwrap_or(127); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:27:13 + | +LL | let _ = 1i128 + | _____________^ +LL | | .checked_add(1) +LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); + | |_______________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:30:13 + | +LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:31:13 + | +LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i32.saturating_add(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:32:13 + | +LL | let _ = 1i8.checked_add(-1).unwrap_or(-128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_add`: `1i8.saturating_add(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:33:13 + | +LL | let _ = 1i128 + | _____________^ +LL | | .checked_add(-1) +LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); + | |________________________________________________________________________^ help: try using `saturating_add`: `1i128.saturating_add(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:40:13 + | +LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:41:13 + | +LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:42:13 + | +LL | let _ = 1i8.checked_sub(1).unwrap_or(-128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:43:13 + | +LL | let _ = 1i128 + | _____________^ +LL | | .checked_sub(1) +LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); + | |________________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:46:13 + | +LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:47:13 + | +LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i32.saturating_sub(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:48:13 + | +LL | let _ = 1i8.checked_sub(-1).unwrap_or(127); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `saturating_sub`: `1i8.saturating_sub(-1)` + +error: manual saturating arithmetic + --> $DIR/manual_saturating_arithmetic.rs:49:13 + | +LL | let _ = 1i128 + | _____________^ +LL | | .checked_sub(-1) +LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); + | |_______________________________________________________________________^ help: try using `saturating_sub`: `1i128.saturating_sub(-1)` + +error: aborting due to 24 previous errors + -- cgit 1.4.1-3-g733a5 From 14d1d040b435d089d6240dc50a789eccdf857afb Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Wed, 4 Sep 2019 15:33:14 +0200 Subject: Run update_lints --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b7a6e486f0b..d9be47f649b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -171,7 +171,7 @@ pub const ALL_LINTS: [Lint; 311] = [ Lint { name: "char_lit_as_u8", group: "complexity", - desc: "casting a character literal to u8", + desc: "casting a character literal to u8 truncates", deprecation: None, module: "types", }, -- cgit 1.4.1-3-g733a5 From e236740f28745cfc24895426197c02fbcedd7c0b Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Tue, 3 Sep 2019 04:49:14 +0900 Subject: Fix `redundant_pattern` false positive --- clippy_lints/src/lib.rs | 4 ++-- clippy_lints/src/misc.rs | 39 --------------------------------------- clippy_lints/src/misc_early.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/lintlist/mod.rs | 2 +- tests/ui/patterns.rs | 6 ++++++ tests/ui/patterns.stderr | 2 +- 6 files changed, 48 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a9294da59b6..9d0a91c5318 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -815,7 +815,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc::CMP_OWNED, misc::FLOAT_CMP, misc::MODULO_ONE, - misc::REDUNDANT_PATTERN, misc::SHORT_CIRCUIT_STATEMENT, misc::TOPLEVEL_REF_ARG, misc::ZERO_PTR, @@ -824,6 +823,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_CLOSURE_CALL, + misc_early::REDUNDANT_PATTERN, misc_early::UNNEEDED_FIELD_PATTERN, misc_early::ZERO_PREFIXED_LITERAL, mut_reference::UNNECESSARY_MUT_PASSED, @@ -967,13 +967,13 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::STRING_EXTEND_CHARS, methods::UNNECESSARY_FOLD, methods::WRONG_SELF_CONVENTION, - misc::REDUNDANT_PATTERN, misc::TOPLEVEL_REF_ARG, misc::ZERO_PTR, misc_early::BUILTIN_TYPE_SHADOW, misc_early::DOUBLE_NEG, misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::MIXED_CASE_HEX_LITERALS, + misc_early::REDUNDANT_PATTERN, misc_early::UNNEEDED_FIELD_PATTERN, mut_reference::UNNECESSARY_MUT_PASSED, neg_multiply::NEG_MULTIPLY, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index c6bcb845c7a..a761f80b793 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -136,28 +136,6 @@ declare_clippy_lint! { "taking a number modulo 1, which always returns 0" } -declare_clippy_lint! { - /// **What it does:** Checks for patterns in the form `name @ _`. - /// - /// **Why is this bad?** It's almost always more readable to just use direct - /// bindings. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// # let v = Some("abc"); - /// - /// match v { - /// Some(x) => (), - /// y @ _ => (), // easier written as `y`, - /// } - /// ``` - pub REDUNDANT_PATTERN, - style, - "using `name @ _` in a pattern" -} - declare_clippy_lint! { /// **What it does:** Checks for the use of bindings with a single leading /// underscore. @@ -247,7 +225,6 @@ declare_lint_pass!(MiscLints => [ FLOAT_CMP, CMP_OWNED, MODULO_ONE, - REDUNDANT_PATTERN, USED_UNDERSCORE_BINDING, SHORT_CIRCUIT_STATEMENT, ZERO_PTR, @@ -459,22 +436,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints { ); } } - - fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { - if let PatKind::Binding(.., ident, Some(ref right)) = pat.node { - if let PatKind::Wild = right.node { - span_lint( - cx, - REDUNDANT_PATTERN, - pat.span, - &format!( - "the `{} @ _` pattern can be written as just `{}`", - ident.name, ident.name - ), - ); - } - } - } } fn check_nan(cx: &LateContext<'_, '_>, path: &Path, expr: &Expr) { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index b90307af8ff..f4a1a1e297f 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -173,6 +173,28 @@ declare_clippy_lint! { "shadowing a builtin type" } +declare_clippy_lint! { + /// **What it does:** Checks for patterns in the form `name @ _`. + /// + /// **Why is this bad?** It's almost always more readable to just use direct + /// bindings. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # let v = Some("abc"); + /// + /// match v { + /// Some(x) => (), + /// y @ _ => (), // easier written as `y`, + /// } + /// ``` + pub REDUNDANT_PATTERN, + style, + "using `name @ _` in a pattern" +} + declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, @@ -181,7 +203,8 @@ declare_lint_pass!(MiscEarlyLints => [ MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, - BUILTIN_TYPE_SHADOW + BUILTIN_TYPE_SHADOW, + REDUNDANT_PATTERN ]); // Used to find `return` statements or equivalents e.g., `?` @@ -286,6 +309,20 @@ impl EarlyLintPass for MiscEarlyLints { } } } + + if let PatKind::Ident(_, ident, Some(ref right)) = pat.node { + if let PatKind::Wild = right.node { + span_lint( + cx, + REDUNDANT_PATTERN, + pat.span, + &format!( + "the `{} @ _` pattern can be written as just `{}`", + ident.name, ident.name, + ), + ); + } + } } fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1435e9968dd..223e6aa9acd 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1552,7 +1552,7 @@ pub const ALL_LINTS: [Lint; 313] = [ group: "style", desc: "using `name @ _` in a pattern", deprecation: None, - module: "misc", + module: "misc_early", }, Lint { name: "redundant_pattern_matching", diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 576e6c9ab92..f76be38a2fc 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,8 +1,10 @@ #![allow(unused)] #![warn(clippy::all)] +#![feature(slice_patterns)] fn main() { let v = Some(true); + let s = [0, 1, 2, 3, 4]; match v { Some(x) => (), y @ _ => (), @@ -11,4 +13,8 @@ fn main() { Some(x) => (), y @ None => (), // no error } + match s { + [x, inside @ .., y] => (), // no error + [..] => (), + } } diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index 39dc034a014..31dfe1cd11c 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,5 +1,5 @@ error: the `y @ _` pattern can be written as just `y` - --> $DIR/patterns.rs:8:9 + --> $DIR/patterns.rs:10:9 | LL | y @ _ => (), | ^^^^^ -- cgit 1.4.1-3-g733a5 From 4a3bc6b5923217a53441b7745b9f5542ed4245e8 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Thu, 12 Sep 2019 08:25:05 +0200 Subject: Add `unneeded-wildcard-pattern` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/misc_early.rs | 93 ++++++++++++++++++++++++++++++- src/lintlist/mod.rs | 9 ++- tests/ui/unneeded_wildcard_pattern.fixed | 41 ++++++++++++++ tests/ui/unneeded_wildcard_pattern.rs | 41 ++++++++++++++ tests/ui/unneeded_wildcard_pattern.stderr | 68 ++++++++++++++++++++++ 8 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 tests/ui/unneeded_wildcard_pattern.fixed create mode 100644 tests/ui/unneeded_wildcard_pattern.rs create mode 100644 tests/ui/unneeded_wildcard_pattern.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index dbdf3df4ddc..eb710654caf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1188,6 +1188,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern +[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization diff --git a/README.md b/README.md index dd315fd397b..4541af9c844 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 313 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 314 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d0a91c5318..de4d262bddc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -825,6 +825,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc_early::REDUNDANT_CLOSURE_CALL, misc_early::REDUNDANT_PATTERN, misc_early::UNNEEDED_FIELD_PATTERN, + misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::ZERO_PREFIXED_LITERAL, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, @@ -1044,6 +1045,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::USELESS_ASREF, misc::SHORT_CIRCUIT_STATEMENT, misc_early::REDUNDANT_CLOSURE_CALL, + misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::ZERO_PREFIXED_LITERAL, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index a9907ed132d..2e1be755d09 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -195,6 +195,40 @@ declare_clippy_lint! { "using `name @ _` in a pattern" } +declare_clippy_lint! { + /// **What it does:** Checks for tuple patterns with a wildcard + /// pattern (`_`) is next to a rest pattern (`..`) pattern. + /// + /// **Why is this bad?** The wildcard pattern is unneeded as the rest pattern + /// can match that element as well. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # struct TupleStruct(u32, u32, u32); + /// # let t = TupleStruct(1, 2, 3); + /// + /// match t { + /// TupleStruct(0, .., _) => (), + /// _ => (), + /// } + /// ``` + /// can be written as + /// ```rust + /// # struct TupleStruct(u32, u32, u32); + /// # let t = TupleStruct(1, 2, 3); + /// + /// match t { + /// TupleStruct(0, ..) => (), + /// _ => (), + /// } + /// ``` + pub UNNEEDED_WILDCARD_PATTERN, + complexity, + "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`) pattern" +} + declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, @@ -204,7 +238,8 @@ declare_lint_pass!(MiscEarlyLints => [ UNSEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW, - REDUNDANT_PATTERN + REDUNDANT_PATTERN, + UNNEEDED_WILDCARD_PATTERN, ]); // Used to find `return` statements or equivalents e.g., `?` @@ -326,6 +361,62 @@ impl EarlyLintPass for MiscEarlyLints { ); } } + + if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.node { + fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) { + span_lint_and_sugg( + cx, + UNNEEDED_WILDCARD_PATTERN, + span, + if only_one { + "this pattern is unneeded as the `..` pattern can match that element" + } else { + "these patterns are unneeded as the `..` pattern can match those elements" + }, + if only_one { "remove it" } else { "remove them" }, + "".to_string(), + Applicability::MachineApplicable, + ); + } + + fn is_rest<P: std::ops::Deref<Target = Pat>>(pat: &P) -> bool { + if let PatKind::Rest = pat.node { + true + } else { + false + } + } + + fn is_wild<P: std::ops::Deref<Target = Pat>>(pat: &&P) -> bool { + if let PatKind::Wild = pat.node { + true + } else { + false + } + } + + if let Some(rest_index) = patterns.iter().position(is_rest) { + if let Some((left_index, left_pat)) = patterns[..rest_index] + .iter() + .rev() + .take_while(is_wild) + .enumerate() + .last() + { + span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0); + } + + if let Some((right_index, right_pat)) = + patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last() + { + span_lint( + cx, + patterns[rest_index].span.shrink_to_hi().to(right_pat.span), + right_index == 0, + ); + } + } + } } fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 223e6aa9acd..589ae6b3d35 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 313] = [ +pub const ALL_LINTS: [Lint; 314] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1974,6 +1974,13 @@ pub const ALL_LINTS: [Lint; 313] = [ deprecation: None, module: "misc_early", }, + Lint { + name: "unneeded_wildcard_pattern", + group: "complexity", + desc: "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`) pattern", + deprecation: None, + module: "misc_early", + }, Lint { name: "unreadable_literal", group: "style", diff --git a/tests/ui/unneeded_wildcard_pattern.fixed b/tests/ui/unneeded_wildcard_pattern.fixed new file mode 100644 index 00000000000..d0b62fa6f43 --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.fixed @@ -0,0 +1,41 @@ +// run-rustfix +#![feature(stmt_expr_attributes)] +#![deny(clippy::unneeded_wildcard_pattern)] + +fn main() { + let t = (0, 1, 2, 3); + + if let (0, ..) = t {}; + if let (0, ..) = t {}; + if let (0, ..) = t {}; + if let (0, ..) = t {}; + if let (_, 0, ..) = t {}; + if let (.., 0, _) = t {}; + if let (0, _, _, _) = t {}; + if let (0, ..) = t {}; + if let (.., 0) = t {}; + + #[rustfmt::skip] + { + if let (0, ..,) = t {}; + } + + struct S(usize, usize, usize, usize); + + let s = S(0, 1, 2, 3); + + if let S(0, ..) = s {}; + if let S(0, ..) = s {}; + if let S(0, ..) = s {}; + if let S(0, ..) = s {}; + if let S(_, 0, ..) = s {}; + if let S(.., 0, _) = s {}; + if let S(0, _, _, _) = s {}; + if let S(0, ..) = s {}; + if let S(.., 0) = s {}; + + #[rustfmt::skip] + { + if let S(0, ..,) = s {}; + } +} diff --git a/tests/ui/unneeded_wildcard_pattern.rs b/tests/ui/unneeded_wildcard_pattern.rs new file mode 100644 index 00000000000..bad158907ba --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.rs @@ -0,0 +1,41 @@ +// run-rustfix +#![feature(stmt_expr_attributes)] +#![deny(clippy::unneeded_wildcard_pattern)] + +fn main() { + let t = (0, 1, 2, 3); + + if let (0, .., _) = t {}; + if let (0, _, ..) = t {}; + if let (0, _, _, ..) = t {}; + if let (0, .., _, _) = t {}; + if let (_, 0, ..) = t {}; + if let (.., 0, _) = t {}; + if let (0, _, _, _) = t {}; + if let (0, ..) = t {}; + if let (.., 0) = t {}; + + #[rustfmt::skip] + { + if let (0, .., _, _,) = t {}; + } + + struct S(usize, usize, usize, usize); + + let s = S(0, 1, 2, 3); + + if let S(0, .., _) = s {}; + if let S(0, _, ..) = s {}; + if let S(0, _, _, ..) = s {}; + if let S(0, .., _, _) = s {}; + if let S(_, 0, ..) = s {}; + if let S(.., 0, _) = s {}; + if let S(0, _, _, _) = s {}; + if let S(0, ..) = s {}; + if let S(.., 0) = s {}; + + #[rustfmt::skip] + { + if let S(0, .., _, _,) = s {}; + } +} diff --git a/tests/ui/unneeded_wildcard_pattern.stderr b/tests/ui/unneeded_wildcard_pattern.stderr new file mode 100644 index 00000000000..8cc2516959a --- /dev/null +++ b/tests/ui/unneeded_wildcard_pattern.stderr @@ -0,0 +1,68 @@ +error: this pattern is unneeded as the `..` pattern can match that element + --> $DIR/unneeded_wildcard_pattern.rs:8:18 + | +LL | if let (0, .., _) = t {}; + | ^^^ help: remove it + | +note: lint level defined here + --> $DIR/unneeded_wildcard_pattern.rs:3:9 + | +LL | #![deny(clippy::unneeded_wildcard_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this pattern is unneeded as the `..` pattern can match that element + --> $DIR/unneeded_wildcard_pattern.rs:9:16 + | +LL | if let (0, _, ..) = t {}; + | ^^^ help: remove it + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:10:16 + | +LL | if let (0, _, _, ..) = t {}; + | ^^^^^^ help: remove them + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:11:18 + | +LL | if let (0, .., _, _) = t {}; + | ^^^^^^ help: remove them + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:20:22 + | +LL | if let (0, .., _, _,) = t {}; + | ^^^^^^ help: remove them + +error: this pattern is unneeded as the `..` pattern can match that element + --> $DIR/unneeded_wildcard_pattern.rs:27:19 + | +LL | if let S(0, .., _) = s {}; + | ^^^ help: remove it + +error: this pattern is unneeded as the `..` pattern can match that element + --> $DIR/unneeded_wildcard_pattern.rs:28:17 + | +LL | if let S(0, _, ..) = s {}; + | ^^^ help: remove it + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:29:17 + | +LL | if let S(0, _, _, ..) = s {}; + | ^^^^^^ help: remove them + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:30:19 + | +LL | if let S(0, .., _, _) = s {}; + | ^^^^^^ help: remove them + +error: these patterns are unneeded as the `..` pattern can match those elements + --> $DIR/unneeded_wildcard_pattern.rs:39:23 + | +LL | if let S(0, .., _, _,) = s {}; + | ^^^^^^ help: remove them + +error: aborting due to 10 previous errors + -- cgit 1.4.1-3-g733a5 From 6f1f41371789e938e0f1fe1e3dfc879835351989 Mon Sep 17 00:00:00 2001 From: Jason Olson <jolson88@outlook.com> Date: Thu, 12 Sep 2019 17:30:58 -0700 Subject: Changes cast-lossless to a pedantic lint Fixes #4528 --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/types.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/types.fixed | 1 + tests/ui/types.rs | 1 + tests/ui/types.stderr | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d0a91c5318..719b414c56f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -667,6 +667,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con shadow::SHADOW_UNRELATED, strings::STRING_ADD_ASSIGN, trait_bounds::TYPE_REPETITION_IN_BOUNDS, + types::CAST_LOSSLESS, types::CAST_POSSIBLE_TRUNCATION, types::CAST_POSSIBLE_WRAP, types::CAST_PRECISION_LOSS, @@ -890,7 +891,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con types::ABSURD_EXTREME_COMPARISONS, types::BORROWED_BOX, types::BOX_VEC, - types::CAST_LOSSLESS, types::CAST_PTR_ALIGNMENT, types::CAST_REF_TO_MUT, types::CHAR_LIT_AS_U8, @@ -1072,7 +1072,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, types::BORROWED_BOX, - types::CAST_LOSSLESS, types::CHAR_LIT_AS_U8, types::OPTION_OPTION, types::TYPE_COMPLEXITY, diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 2e4128ccca6..a1d54ff3f0e 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -765,7 +765,7 @@ declare_clippy_lint! { /// } /// ``` pub CAST_LOSSLESS, - complexity, + pedantic, "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 223e6aa9acd..d0be8c1d341 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -121,7 +121,7 @@ pub const ALL_LINTS: [Lint; 313] = [ }, Lint { name: "cast_lossless", - group: "complexity", + group: "pedantic", desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", deprecation: None, module: "types", diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed index a71a9ec8124..b1622e45f3b 100644 --- a/tests/ui/types.fixed +++ b/tests/ui/types.fixed @@ -1,6 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] +#![warn(clippy::all, clippy::pedantic)] // should not warn on lossy casting in constant types // because not supported yet diff --git a/tests/ui/types.rs b/tests/ui/types.rs index 6f48080cedd..30463f9e2a1 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,6 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] +#![warn(clippy::all, clippy::pedantic)] // should not warn on lossy casting in constant types // because not supported yet diff --git a/tests/ui/types.stderr b/tests/ui/types.stderr index 3b4f57a7a43..daba766856d 100644 --- a/tests/ui/types.stderr +++ b/tests/ui/types.stderr @@ -1,5 +1,5 @@ error: casting i32 to i64 may become silently lossy if you later change the type - --> $DIR/types.rs:13:22 + --> $DIR/types.rs:14:22 | LL | let c_i64: i64 = c as i64; | ^^^^^^^^ help: try: `i64::from(c)` -- cgit 1.4.1-3-g733a5 From cc68d8135b9fa7c3c9432fa154d5d1896408231c Mon Sep 17 00:00:00 2001 From: Jason Olson <jolson88@outlook.com> Date: Sun, 15 Sep 2019 11:07:44 -0700 Subject: Changes to catch_fatal_errors in rustc driver A [recent PR](https://github.com/rust-lang/rust/pull/60584/files#diff-707a0eda6b2f1a0537abc3d23133748cL1151) changed the function name from `report_ices_to_stderr_if_any` to `catch_fatal_errors`. This PR changes to using the new function name. --- src/driver.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 92f83f1a29e..359d2f8530c 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -247,8 +247,9 @@ You can use tool lints to allow or deny lints from your code, eg.: pub fn main() { rustc_driver::init_rustc_env_logger(); + rustc_driver::install_ice_hook(); exit( - rustc_driver::report_ices_to_stderr_if_any(move || { + rustc_driver::catch_fatal_errors(move || { use std::env; if std::env::args().any(|a| a == "--version" || a == "-V") { -- cgit 1.4.1-3-g733a5 From 70a7dab773b5d97fd46541a46bdb6de7abf77b2f Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Wed, 11 Sep 2019 18:39:02 +0200 Subject: New lint: Require `# Safety` section in pub unsafe fn docs --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/doc.rs | 111 +++++++++++++++++++++++++++++++++------------ clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 +++- tests/ui/doc_unsafe.rs | 25 ++++++++++ tests/ui/doc_unsafe.stderr | 12 +++++ 8 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 tests/ui/doc_unsafe.rs create mode 100644 tests/ui/doc_unsafe.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index dbdf3df4ddc..c39b2e69df9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1056,6 +1056,7 @@ Released 2018-09-13 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items [`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception diff --git a/README.md b/README.md index dd315fd397b..4541af9c844 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 313 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 314 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 48133cc5b02..423e13e9dd5 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -27,7 +27,7 @@ semver = "0.9.0" serde = { version = "1.0", features = ["derive"] } toml = "0.5.3" unicode-normalization = "0.1" -pulldown-cmark = "0.5.3" +pulldown-cmark = "0.6.0" url = { version = "2.1.0", features = ["serde"] } # cargo requires serde feat in its url dep # see https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864 if_chain = "1.0.0" diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 4950212a4b5..86d83bf9602 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -34,6 +34,40 @@ declare_clippy_lint! { "presence of `_`, `::` or camel-case outside backticks in documentation" } +declare_clippy_lint! { + /// **What it does:** Checks for the doc comments of publicly visible + /// unsafe functions and warns if there is no `# Safety` section. + /// + /// **Why is this bad?** Unsafe functions should document their safety + /// preconditions, so that users can be sure they are using them safely. + /// + /// **Known problems:** None. + /// + /// **Examples**: + /// ```rust + ///# type Universe = (); + /// /// This function should really be documented + /// pub unsafe fn start_apocalypse(u: &mut Universe) { + /// unimplemented!(); + /// } + /// ``` + /// + /// At least write a line about safety: + /// + /// ```rust + ///# type Universe = (); + /// /// # Safety + /// /// + /// /// This function should not be called before the horsemen are ready. + /// pub unsafe fn start_apocalypse(u: &mut Universe) { + /// unimplemented!(); + /// } + /// ``` + pub MISSING_SAFETY_DOC, + style, + "`pub unsafe fn` without `# Safety` docs" +} + #[allow(clippy::module_name_repetitions)] #[derive(Clone)] pub struct DocMarkdown { @@ -46,7 +80,7 @@ impl DocMarkdown { } } -impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN]); +impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC]); impl EarlyLintPass for DocMarkdown { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { @@ -54,7 +88,20 @@ impl EarlyLintPass for DocMarkdown { } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - check_attrs(cx, &self.valid_idents, &item.attrs); + if check_attrs(cx, &self.valid_idents, &item.attrs) { + return; + } + // no safety header + if let ast::ItemKind::Fn(_, ref header, ..) = item.node { + if item.vis.node.is_pub() && header.unsafety == ast::Unsafety::Unsafe { + span_lint( + cx, + MISSING_SAFETY_DOC, + item.span, + "unsafe function's docs miss `# Safety` section", + ); + } + } } } @@ -115,7 +162,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<( panic!("not a doc-comment: {}", comment); } -pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) { +pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) -> bool { let mut doc = String::new(); let mut spans = vec![]; @@ -129,7 +176,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, } } else if attr.check_name(sym!(doc)) { // ignore mix of sugared and non-sugared doc - return; + return true; // don't trigger the safety check } } @@ -140,26 +187,28 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, current += offset_copy; } - if !doc.is_empty() { - let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); - // Iterate over all `Events` and combine consecutive events into one - let events = parser.coalesce(|previous, current| { - use pulldown_cmark::Event::*; - - let previous_range = previous.1; - let current_range = current.1; - - match (previous.0, current.0) { - (Text(previous), Text(current)) => { - let mut previous = previous.to_string(); - previous.push_str(¤t); - Ok((Text(previous.into()), previous_range)) - }, - (previous, current) => Err(((previous, previous_range), (current, current_range))), - } - }); - check_doc(cx, valid_idents, events, &spans); + if doc.is_empty() { + return false; } + + let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); + // Iterate over all `Events` and combine consecutive events into one + let events = parser.coalesce(|previous, current| { + use pulldown_cmark::Event::*; + + let previous_range = previous.1; + let current_range = current.1; + + match (previous.0, current.0) { + (Text(previous), Text(current)) => { + let mut previous = previous.to_string(); + previous.push_str(¤t); + Ok((Text(previous.into()), previous_range)) + }, + (previous, current) => Err(((previous, previous_range), (current, current_range))), + } + }); + check_doc(cx, valid_idents, events, &spans) } fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>( @@ -167,12 +216,15 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize valid_idents: &FxHashSet<String>, events: Events, spans: &[(usize, Span)], -) { +) -> bool { + // true if a safety header was found use pulldown_cmark::Event::*; use pulldown_cmark::Tag::*; + let mut safety_header = false; let mut in_code = false; let mut in_link = None; + let mut in_heading = false; for (event, range) in events { match event { @@ -180,9 +232,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize End(CodeBlock(_)) => in_code = false, Start(Link(_, url, _)) => in_link = Some(url), End(Link(..)) => in_link = None, - Start(_tag) | End(_tag) => (), // We don't care about other tags - Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it - SoftBreak | HardBreak | TaskListMarker(_) | Code(_) => (), + Start(Heading(_)) => in_heading = true, + End(Heading(_)) => in_heading = false, + Start(_tag) | End(_tag) => (), // We don't care about other tags + Html(_html) => (), // HTML is weird, just ignore it + SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (), FootnoteReference(text) | Text(text) => { if Some(&text) == in_link.as_ref() { // Probably a link of the form `<http://example.com>` @@ -190,7 +244,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize // text "http://example.com" by pulldown-cmark continue; } - + safety_header |= in_heading && text.trim() == "Safety"; if !in_code { let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) { Ok(o) => o, @@ -207,6 +261,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize }, } } + safety_header } fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9d0a91c5318..2892c6c417d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -708,6 +708,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con copies::IFS_SAME_COND, copies::IF_SAME_THEN_ELSE, derive::DERIVE_HASH_XOR_EQ, + doc::MISSING_SAFETY_DOC, double_comparison::DOUBLE_COMPARISONS, double_parens::DOUBLE_PARENS, drop_bounds::DROP_BOUNDS, @@ -929,6 +930,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, + doc::MISSING_SAFETY_DOC, enum_variants::ENUM_VARIANT_NAMES, enum_variants::MODULE_INCEPTION, eq_op::OP_REF, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 223e6aa9acd..f45c240014f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 313] = [ +pub const ALL_LINTS: [Lint; 314] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1078,6 +1078,13 @@ pub const ALL_LINTS: [Lint; 313] = [ deprecation: None, module: "missing_inline", }, + Lint { + name: "missing_safety_doc", + group: "style", + desc: "`pub unsafe fn` without `# Safety` docs", + deprecation: None, + module: "doc", + }, Lint { name: "mistyped_literal_suffixes", group: "correctness", diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs new file mode 100644 index 00000000000..7b26e86b40b --- /dev/null +++ b/tests/ui/doc_unsafe.rs @@ -0,0 +1,25 @@ +/// This is not sufficiently documented +pub unsafe fn destroy_the_planet() { + unimplemented!(); +} + +/// This one is +/// +/// # Safety +/// +/// This function shouldn't be called unless the horsemen are ready +pub unsafe fn apocalypse(universe: &mut ()) { + unimplemented!(); +} + +/// This is a private function, so docs aren't necessary +unsafe fn you_dont_see_me() { + unimplemented!(); +} + +fn main() { + you_dont_see_me(); + destroy_the_planet(); + let mut universe = (); + apocalypse(&mut universe); +} diff --git a/tests/ui/doc_unsafe.stderr b/tests/ui/doc_unsafe.stderr new file mode 100644 index 00000000000..d6d1cd2d4fa --- /dev/null +++ b/tests/ui/doc_unsafe.stderr @@ -0,0 +1,12 @@ +error: unsafe function's docs miss `# Safety` section + --> $DIR/doc_unsafe.rs:2:1 + | +LL | / pub unsafe fn destroy_the_planet() { +LL | | unimplemented!(); +LL | | } + | |_^ + | + = note: `-D clippy::missing-safety-doc` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 8d884c8a1a5f7ed48fb86a2faf8af16707e6d114 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Fri, 13 Sep 2019 18:39:14 +0200 Subject: new lint: mem-replace-with-uninit --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/mem_replace.rs | 126 ++++++++++++++++++++++++++++++---------- clippy_lints/src/utils/paths.rs | 2 + src/lintlist/mod.rs | 9 ++- tests/ui/repl_uninit.rs | 35 +++++++++++ tests/ui/repl_uninit.stderr | 27 +++++++++ 8 files changed, 171 insertions(+), 33 deletions(-) create mode 100644 tests/ui/repl_uninit.rs create mode 100644 tests/ui/repl_uninit.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index c39b2e69df9..6c9d2020a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1050,6 +1050,7 @@ Released 2018-09-13 [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit [`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op diff --git a/README.md b/README.md index 4541af9c844..a8e6efc4ba4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 314 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 315 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 24b8b14f717..79cbb916a5d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -783,6 +783,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con matches::SINGLE_MATCH, mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + mem_replace::MEM_REPLACE_WITH_UNINIT, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, methods::CLONE_DOUBLE_REF, @@ -1117,6 +1118,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con loops::REVERSE_RANGE_LOOP, loops::WHILE_IMMUTABLE_CONDITION, mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, + mem_replace::MEM_REPLACE_WITH_UNINIT, methods::CLONE_DOUBLE_REF, methods::INTO_ITER_ON_ARRAY, methods::TEMPORARY_CSTRING_AS_PTR, diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 7e83e836b85..3e1155806b9 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,4 +1,6 @@ -use crate::utils::{match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{ + match_def_path, match_qpath, paths, snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, +}; use if_chain::if_chain; use rustc::hir::{Expr, ExprKind, MutMutable, QPath}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -32,7 +34,40 @@ declare_clippy_lint! { "replacing an `Option` with `None` instead of `take()`" } -declare_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE]); +declare_clippy_lint! { + /// **What it does:** Checks for `mem::replace(&mut _, mem::uninitialized())` + /// and `mem::replace(&mut _, mem::zeroed())`. + /// + /// **Why is this bad?** This will lead to undefined behavior even if the + /// value is overwritten later, because the uninitialized value may be + /// observed in the case of a panic. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ``` + /// use std::mem; + ///# fn may_panic(v: Vec<i32>) -> Vec<i32> { v } + /// + /// #[allow(deprecated, invalid_value)] + /// fn myfunc (v: &mut Vec<i32>) { + /// let taken_v = unsafe { mem::replace(v, mem::uninitialized()) }; + /// let new_v = may_panic(taken_v); // undefined behavior on panic + /// mem::forget(mem::replace(v, new_v)); + /// } + /// ``` + /// + /// The [take_mut](https://docs.rs/take_mut) crate offers a sound solution, + /// at the cost of either lazily creating a replacement value or aborting + /// on panic, to ensure that the uninitialized value cannot be observed. + pub MEM_REPLACE_WITH_UNINIT, + correctness, + "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`" +} + +declare_lint_pass!(MemReplace => + [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { @@ -45,37 +80,66 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { if match_def_path(cx, def_id, &paths::MEM_REPLACE); // Check that second argument is `Option::None` - if let ExprKind::Path(ref replacement_qpath) = func_args[1].node; - if match_qpath(replacement_qpath, &paths::OPTION_NONE); - then { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match func_args[0].node { - ExprKind::AddrOf(MutMutable, ref replaced) => { - if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.node { - replaced_path - } else { - return - } - }, - ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path, - _ => return, - }; + if let ExprKind::Path(ref replacement_qpath) = func_args[1].node { + if match_qpath(replacement_qpath, &paths::OPTION_NONE) { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr.span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)), - applicability, - ); + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // replacee's path. + let replaced_path = match func_args[0].node { + ExprKind::AddrOf(MutMutable, ref replaced) => { + if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.node { + replaced_path + } else { + return + } + }, + ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path, + _ => return, + }; + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr.span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)), + applicability, + ); + } + } + if let ExprKind::Call(ref repl_func, ref repl_args) = func_args[1].node { + if_chain! { + if repl_args.is_empty(); + if let ExprKind::Path(ref repl_func_qpath) = repl_func.node; + if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + then { + if match_def_path(cx, repl_def_id, &paths::MEM_UNINITIALIZED) { + span_help_and_lint( + cx, + MEM_REPLACE_WITH_UNINIT, + expr.span, + "replacing with `mem::uninitialized()`", + "consider using the `take_mut` crate instead", + ); + } else if match_def_path(cx, repl_def_id, &paths::MEM_ZEROED) && + !cx.tables.expr_ty(&func_args[1]).is_primitive() { + span_help_and_lint( + cx, + MEM_REPLACE_WITH_UNINIT, + expr.span, + "replacing with `mem::zeroed()`", + "consider using a default value or the `take_mut` crate instead", + ); + } + } + } + } } } } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 9b88a0d3089..cda3d2024d2 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -52,6 +52,8 @@ pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; +pub const MEM_UNINITIALIZED: [&str; 3] = ["core", "mem", "uninitialized"]; +pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"]; pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f430e46ae67..49b7731865c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 314] = [ +pub const ALL_LINTS: [Lint; 315] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1043,6 +1043,13 @@ pub const ALL_LINTS: [Lint; 314] = [ deprecation: None, module: "mem_replace", }, + Lint { + name: "mem_replace_with_uninit", + group: "correctness", + desc: "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`", + deprecation: None, + module: "mem_replace", + }, Lint { name: "min_max", group: "correctness", diff --git a/tests/ui/repl_uninit.rs b/tests/ui/repl_uninit.rs new file mode 100644 index 00000000000..346972b7bb4 --- /dev/null +++ b/tests/ui/repl_uninit.rs @@ -0,0 +1,35 @@ +#![allow(deprecated, invalid_value)] +#![warn(clippy::all)] + +use std::mem; + +fn might_panic<X>(x: X) -> X { + // in practice this would be a possibly-panicky operation + x +} + +fn main() { + let mut v = vec![0i32; 4]; + // the following is UB if `might_panic` panics + unsafe { + let taken_v = mem::replace(&mut v, mem::uninitialized()); + let new_v = might_panic(taken_v); + std::mem::forget(mem::replace(&mut v, new_v)); + } + + unsafe { + let taken_v = mem::replace(&mut v, mem::zeroed()); + let new_v = might_panic(taken_v); + std::mem::forget(mem::replace(&mut v, new_v)); + } + + // this is silly but OK, because usize is a primitive type + let mut u: usize = 42; + let uref = &mut u; + let taken_u = unsafe { mem::replace(uref, mem::zeroed()) }; + *uref = taken_u + 1; + + // this is still not OK, because uninit + let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; + *uref = taken_u + 1; +} diff --git a/tests/ui/repl_uninit.stderr b/tests/ui/repl_uninit.stderr new file mode 100644 index 00000000000..c1f55d7601e --- /dev/null +++ b/tests/ui/repl_uninit.stderr @@ -0,0 +1,27 @@ +error: replacing with `mem::uninitialized()` + --> $DIR/repl_uninit.rs:15:23 + | +LL | let taken_v = mem::replace(&mut v, mem::uninitialized()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings` + = help: consider using the `take_mut` crate instead + +error: replacing with `mem::zeroed()` + --> $DIR/repl_uninit.rs:21:23 + | +LL | let taken_v = mem::replace(&mut v, mem::zeroed()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a default value or the `take_mut` crate instead + +error: replacing with `mem::uninitialized()` + --> $DIR/repl_uninit.rs:33:28 + | +LL | let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using the `take_mut` crate instead + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 52408f5b7d0392b008d647c5414e45dad4c4f5fd Mon Sep 17 00:00:00 2001 From: James Wang <jameswang9909@hotmail.com> Date: Tue, 24 Sep 2019 16:55:05 -0500 Subject: Add a new lint for comparison chains --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/comparison_chain.rs | 107 +++++++++++++++++++++++++++++++ clippy_lints/src/copies.rs | 56 ++++------------ clippy_lints/src/lib.rs | 4 ++ clippy_lints/src/needless_bool.rs | 13 +--- clippy_lints/src/non_expressive_names.rs | 103 +++++++++++++++-------------- clippy_lints/src/utils/mod.rs | 44 +++++++++++++ src/lintlist/mod.rs | 9 ++- tests/ui/comparison_chain.rs | 79 +++++++++++++++++++++++ tests/ui/comparison_chain.stderr | 57 ++++++++++++++++ tests/ui/crashes/if_same_then_else.rs | 1 + tests/ui/ifs_same_cond.rs | 2 +- 13 files changed, 369 insertions(+), 109 deletions(-) create mode 100644 clippy_lints/src/comparison_chain.rs create mode 100644 tests/ui/comparison_chain.rs create mode 100644 tests/ui/comparison_chain.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e2b441518d..ca0eb65ca3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -962,6 +962,7 @@ Released 2018-09-13 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro diff --git a/README.md b/README.md index 915396b901c..f944e716e9a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 316 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 317 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs new file mode 100644 index 00000000000..bac6ba55d58 --- /dev/null +++ b/clippy_lints/src/comparison_chain.rs @@ -0,0 +1,107 @@ +use crate::utils::{if_sequence, parent_node_is_if_expr, span_help_and_lint, SpanlessEq}; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks comparison chains written with `if` that can be + /// rewritten with `match` and `cmp`. + /// + /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get + /// repetitive + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// # fn a() {} + /// # fn b() {} + /// # fn c() {} + /// fn f(x: u8, y: u8) { + /// if x > y { + /// a() + /// } else if x < y { + /// b() + /// } else { + /// c() + /// } + /// } + /// ``` + /// + /// Could be written: + /// + /// ```rust,ignore + /// use std::cmp::Ordering; + /// # fn a() {} + /// # fn b() {} + /// # fn c() {} + /// fn f(x: u8, y: u8) { + /// match x.cmp(y) { + /// Ordering::Greater => a(), + /// Ordering::Less => b(), + /// Ordering::Equal => c() + /// } + /// } + /// ``` + pub COMPARISON_CHAIN, + style, + "`if`s that can be rewritten with `match` and `cmp`" +} + +declare_lint_pass!(ComparisonChain => [COMPARISON_CHAIN]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ComparisonChain { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if expr.span.from_expansion() { + return; + } + + // We only care about the top-most `if` in the chain + if parent_node_is_if_expr(expr, cx) { + return; + } + + // Check that there exists at least one explicit else condition + let (conds, _) = if_sequence(expr); + if conds.len() < 2 { + return; + } + + for cond in conds.windows(2) { + if let ( + &ExprKind::Binary(ref kind1, ref lhs1, ref rhs1), + &ExprKind::Binary(ref kind2, ref lhs2, ref rhs2), + ) = (&cond[0].node, &cond[1].node) + { + if !kind_is_cmp(kind1.node) || !kind_is_cmp(kind2.node) { + return; + } + + // Check that both sets of operands are equal + let mut spanless_eq = SpanlessEq::new(cx); + if (!spanless_eq.eq_expr(lhs1, lhs2) || !spanless_eq.eq_expr(rhs1, rhs2)) + && (!spanless_eq.eq_expr(lhs1, rhs2) || !spanless_eq.eq_expr(rhs1, lhs2)) + { + return; + } + } else { + // We only care about comparison chains + return; + } + } + span_help_and_lint( + cx, + COMPARISON_CHAIN, + expr.span, + "`if` chain can be rewritten with `match`", + "Consider rewriting the `if` chain to use `cmp` and `match`.", + ) + } +} + +fn kind_is_cmp(kind: BinOpKind) -> bool { + match kind { + BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq => true, + _ => false, + } +} diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index b01ce7eeb77..38654c753bf 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,11 +1,11 @@ -use crate::utils::{get_parent_expr, higher, same_tys, snippet, span_lint_and_then, span_note_and_lint}; +use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_then, span_note_and_lint}; use crate::utils::{SpanlessEq, SpanlessHash}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::ty::Ty; use rustc::{declare_lint_pass, declare_tool_lint}; use rustc_data_structures::fx::FxHashMap; -use smallvec::SmallVec; +use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use syntax::symbol::Symbol; @@ -241,39 +241,6 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) { } } -/// Returns the list of condition expressions and the list of blocks in a -/// sequence of `if/else`. -/// E.g., this returns `([a, b], [c, d, e])` for the expression -/// `if a { c } else if b { d } else { e }`. -fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) { - let mut conds = SmallVec::new(); - let mut blocks: SmallVec<[&Block; 1]> = SmallVec::new(); - - while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) { - conds.push(&**cond); - if let ExprKind::Block(ref block, _) = then_expr.node { - blocks.push(block); - } else { - panic!("ExprKind::If node is not an ExprKind::Block"); - } - - if let Some(ref else_expr) = *else_expr { - expr = else_expr; - } else { - break; - } - } - - // final `else {..}` - if !blocks.is_empty() { - if let ExprKind::Block(ref block, _) = expr.node { - blocks.push(&**block); - } - } - - (conds, blocks) -} - /// Returns the list of bindings in a pattern. fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<Symbol, Ty<'tcx>> { fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<Symbol, Ty<'tcx>>) { @@ -338,16 +305,15 @@ fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a where Eq: Fn(&T, &T) -> bool, { - if exprs.len() < 2 { - None - } else if exprs.len() == 2 { - if eq(&exprs[0], &exprs[1]) { - Some((&exprs[0], &exprs[1])) - } else { - None - } - } else { - None + match exprs.len().cmp(&2) { + Ordering::Greater | Ordering::Less => None, + Ordering::Equal => { + if eq(&exprs[0], &exprs[1]) { + Some((&exprs[0], &exprs[1])) + } else { + None + } + }, } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2caa065b937..ed47b6a1857 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -159,6 +159,7 @@ pub mod cargo_common_metadata; pub mod checked_conversions; pub mod cognitive_complexity; pub mod collapsible_if; +pub mod comparison_chain; pub mod copies; pub mod copy_iterator; pub mod dbg_macro; @@ -600,6 +601,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con reg.register_late_lint_pass(box integer_division::IntegerDivision); reg.register_late_lint_pass(box inherent_to_string::InherentToString); reg.register_late_lint_pass(box trait_bounds::TraitBounds); + reg.register_late_lint_pass(box comparison_chain::ComparisonChain); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -706,6 +708,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con bytecount::NAIVE_BYTECOUNT, cognitive_complexity::COGNITIVE_COMPLEXITY, collapsible_if::COLLAPSIBLE_IF, + comparison_chain::COMPARISON_CHAIN, copies::IFS_SAME_COND, copies::IF_SAME_THEN_ELSE, derive::DERIVE_HASH_XOR_EQ, @@ -932,6 +935,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, collapsible_if::COLLAPSIBLE_IF, + comparison_chain::COMPARISON_CHAIN, doc::MISSING_SAFETY_DOC, enum_variants::ENUM_VARIANT_NAMES, enum_variants::MODULE_INCEPTION, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index b761457f64c..d19939be6c0 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,7 +3,7 @@ //! This lint is **warn** by default use crate::utils::sugg::Sugg; -use crate::utils::{higher, span_lint, span_lint_and_sugg}; +use crate::utils::{higher, parent_node_is_if_expr, span_lint, span_lint_and_sugg}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -118,17 +118,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { } } -fn parent_node_is_if_expr<'a, 'b>(expr: &Expr, cx: &LateContext<'a, 'b>) -> bool { - let parent_id = cx.tcx.hir().get_parent_node(expr.hir_id); - let parent_node = cx.tcx.hir().get(parent_id); - - match parent_node { - rustc::hir::Node::Expr(e) => higher::if_block(&e).is_some(), - rustc::hir::Node::Arm(e) => higher::if_block(&e.body).is_some(), - _ => false, - } -} - declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 88bf52b1e8d..ff06eaca465 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,6 +1,7 @@ use crate::utils::{span_lint, span_lint_and_then}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_tool_lint, impl_lint_pass}; +use std::cmp::Ordering; use syntax::ast::*; use syntax::attr; use syntax::source_map::Span; @@ -206,63 +207,67 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { continue; } let mut split_at = None; - if existing_name.len > count { - if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { - continue; - } - } else if existing_name.len < count { - if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { - continue; - } - } else { - let mut interned_chars = interned_name.chars(); - let mut existing_chars = existing_name.interned.chars(); - let first_i = interned_chars.next().expect("we know we have at least one char"); - let first_e = existing_chars.next().expect("we know we have at least one char"); - let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); + match existing_name.len.cmp(&count) { + Ordering::Greater => { + if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { + continue; + } + }, + Ordering::Less => { + if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { + continue; + } + }, + Ordering::Equal => { + let mut interned_chars = interned_name.chars(); + let mut existing_chars = existing_name.interned.chars(); + let first_i = interned_chars.next().expect("we know we have at least one char"); + let first_e = existing_chars.next().expect("we know we have at least one char"); + let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); - if eq_or_numeric((first_i, first_e)) { - let last_i = interned_chars.next_back().expect("we know we have at least two chars"); - let last_e = existing_chars.next_back().expect("we know we have at least two chars"); - if eq_or_numeric((last_i, last_e)) { - if interned_chars - .zip(existing_chars) - .filter(|&ie| !eq_or_numeric(ie)) - .count() - != 1 - { - continue; + if eq_or_numeric((first_i, first_e)) { + let last_i = interned_chars.next_back().expect("we know we have at least two chars"); + let last_e = existing_chars.next_back().expect("we know we have at least two chars"); + if eq_or_numeric((last_i, last_e)) { + if interned_chars + .zip(existing_chars) + .filter(|&ie| !eq_or_numeric(ie)) + .count() + != 1 + { + continue; + } + } else { + let second_last_i = interned_chars + .next_back() + .expect("we know we have at least three chars"); + let second_last_e = existing_chars + .next_back() + .expect("we know we have at least three chars"); + if !eq_or_numeric((second_last_i, second_last_e)) + || second_last_i == '_' + || !interned_chars.zip(existing_chars).all(eq_or_numeric) + { + // allowed similarity foo_x, foo_y + // or too many chars differ (foo_x, boo_y) or (foox, booy) + continue; + } + split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); } } else { - let second_last_i = interned_chars - .next_back() - .expect("we know we have at least three chars"); - let second_last_e = existing_chars - .next_back() - .expect("we know we have at least three chars"); - if !eq_or_numeric((second_last_i, second_last_e)) - || second_last_i == '_' + let second_i = interned_chars.next().expect("we know we have at least two chars"); + let second_e = existing_chars.next().expect("we know we have at least two chars"); + if !eq_or_numeric((second_i, second_e)) + || second_i == '_' || !interned_chars.zip(existing_chars).all(eq_or_numeric) { - // allowed similarity foo_x, foo_y - // or too many chars differ (foo_x, boo_y) or (foox, booy) + // allowed similarity x_foo, y_foo + // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) continue; } - split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); + split_at = interned_name.chars().next().map(char::len_utf8); } - } else { - let second_i = interned_chars.next().expect("we know we have at least two chars"); - let second_e = existing_chars.next().expect("we know we have at least two chars"); - if !eq_or_numeric((second_i, second_e)) - || second_i == '_' - || !interned_chars.zip(existing_chars).all(eq_or_numeric) - { - // allowed similarity x_foo, y_foo - // or too many chars differ (x_foo, y_boo) or (xfoo, yboo) - continue; - } - split_at = interned_name.chars().next().map(char::len_utf8); - } + }, } span_lint_and_then( self.0.cx, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 9165f8d74d7..49d9de35e18 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1168,3 +1168,47 @@ pub fn match_def_path<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, did: DefId, syms: &[ let path = cx.get_def_path(did); path.len() == syms.len() && path.into_iter().zip(syms.iter()).all(|(a, &b)| a.as_str() == b) } + +/// Returns the list of condition expressions and the list of blocks in a +/// sequence of `if/else`. +/// E.g., this returns `([a, b], [c, d, e])` for the expression +/// `if a { c } else if b { d } else { e }`. +pub fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) { + let mut conds = SmallVec::new(); + let mut blocks: SmallVec<[&Block; 1]> = SmallVec::new(); + + while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) { + conds.push(&**cond); + if let ExprKind::Block(ref block, _) = then_expr.node { + blocks.push(block); + } else { + panic!("ExprKind::If node is not an ExprKind::Block"); + } + + if let Some(ref else_expr) = *else_expr { + expr = else_expr; + } else { + break; + } + } + + // final `else {..}` + if !blocks.is_empty() { + if let ExprKind::Block(ref block, _) = expr.node { + blocks.push(&**block); + } + } + + (conds, blocks) +} + +pub fn parent_node_is_if_expr<'a, 'b>(expr: &Expr, cx: &LateContext<'a, 'b>) -> bool { + let parent_id = cx.tcx.hir().get_parent_node(expr.hir_id); + let parent_node = cx.tcx.hir().get(parent_id); + + match parent_node { + rustc::hir::Node::Expr(e) => higher::if_block(&e).is_some(), + rustc::hir::Node::Arm(e) => higher::if_block(&e.body).is_some(), + _ => false, + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e6bcbfadf4f..1b838b17f7f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 316] = [ +pub const ALL_LINTS: [Lint; 317] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -252,6 +252,13 @@ pub const ALL_LINTS: [Lint; 316] = [ deprecation: None, module: "collapsible_if", }, + Lint { + name: "comparison_chain", + group: "style", + desc: "`if`s that can be rewritten with `match` and `cmp`", + deprecation: None, + module: "comparison_chain", + }, Lint { name: "copy_iterator", group: "pedantic", diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs new file mode 100644 index 00000000000..b697413b6e0 --- /dev/null +++ b/tests/ui/comparison_chain.rs @@ -0,0 +1,79 @@ +#![allow(dead_code)] +#![warn(clippy::comparison_chain)] + +fn a() {} +fn b() {} +fn c() {} + +fn f(x: u8, y: u8, z: u8) { + // Ignored: Only one branch + if x > y { + a() + } + + if x > y { + a() + } else if x < y { + b() + } + + // Ignored: Only one explicit conditional + if x > y { + a() + } else { + b() + } + + if x > y { + a() + } else if x < y { + b() + } else { + c() + } + + if x > y { + a() + } else if y > x { + b() + } else { + c() + } + + if x > 1 { + a() + } else if x < 1 { + b() + } else if x == 1 { + c() + } + + // Ignored: Binop args are not equivalent + if x > 1 { + a() + } else if y > 1 { + b() + } else { + c() + } + + // Ignored: Binop args are not equivalent + if x > y { + a() + } else if x > z { + b() + } else if y > z { + c() + } + + // Ignored: Not binary comparisons + if true { + a() + } else if false { + b() + } else { + c() + } +} + +fn main() {} diff --git a/tests/ui/comparison_chain.stderr b/tests/ui/comparison_chain.stderr new file mode 100644 index 00000000000..575181dd719 --- /dev/null +++ b/tests/ui/comparison_chain.stderr @@ -0,0 +1,57 @@ +error: `if` chain can be rewritten with `match` + --> $DIR/comparison_chain.rs:14:5 + | +LL | / if x > y { +LL | | a() +LL | | } else if x < y { +LL | | b() +LL | | } + | |_____^ + | + = note: `-D clippy::comparison-chain` implied by `-D warnings` + = help: Consider rewriting the `if` chain to use `cmp` and `match`. + +error: `if` chain can be rewritten with `match` + --> $DIR/comparison_chain.rs:27:5 + | +LL | / if x > y { +LL | | a() +LL | | } else if x < y { +LL | | b() +LL | | } else { +LL | | c() +LL | | } + | |_____^ + | + = help: Consider rewriting the `if` chain to use `cmp` and `match`. + +error: `if` chain can be rewritten with `match` + --> $DIR/comparison_chain.rs:35:5 + | +LL | / if x > y { +LL | | a() +LL | | } else if y > x { +LL | | b() +LL | | } else { +LL | | c() +LL | | } + | |_____^ + | + = help: Consider rewriting the `if` chain to use `cmp` and `match`. + +error: `if` chain can be rewritten with `match` + --> $DIR/comparison_chain.rs:43:5 + | +LL | / if x > 1 { +LL | | a() +LL | | } else if x < 1 { +LL | | b() +LL | | } else if x == 1 { +LL | | c() +LL | | } + | |_____^ + | + = help: Consider rewriting the `if` chain to use `cmp` and `match`. + +error: aborting due to 4 previous errors + diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs index b2a4d541f59..4ef992b05e7 100644 --- a/tests/ui/crashes/if_same_then_else.rs +++ b/tests/ui/crashes/if_same_then_else.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] /// Test for https://github.com/rust-lang/rust-clippy/issues/2426 diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index b67e730b937..80e9839ff40 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -1,5 +1,5 @@ #![warn(clippy::ifs_same_cond)] -#![allow(clippy::if_same_then_else)] // all empty blocks +#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks fn ifs_same_cond() { let a = 0; -- cgit 1.4.1-3-g733a5 From 23a9c021201df810f40d0ad1fe3815dda5da8462 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Tue, 1 Oct 2019 00:10:24 +0200 Subject: New lint: needless_doc_main --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/doc.rs | 53 +++++++++++++++++++++++++++++++++++++++---------- clippy_lints/src/lib.rs | 2 ++ src/lintlist/mod.rs | 9 ++++++++- 5 files changed, 55 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index ca0eb65ca3d..c4e04586530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1105,6 +1105,7 @@ Released 2018-09-13 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop diff --git a/README.md b/README.md index f944e716e9a..2f7032af87d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 317 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 318 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 59cb282a995..bd959427403 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -68,6 +68,34 @@ declare_clippy_lint! { "`pub unsafe fn` without `# Safety` docs" } +declare_clippy_lint! { + /// **What it does:** Checks for `fn main() { .. }` in doctests + /// + /// **Why is this bad?** The test can be shorter (and likely more readable) + /// if the `fn main()` is left implicit. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// ``````rust + /// /// An example of a doctest with a `main()` function + /// /// + /// /// # Examples + /// /// + /// /// ``` + /// /// fn main() { + /// /// // this needs not be in an `fn` + /// /// } + /// /// ``` + /// fn needless_main() { + /// unimplemented!(); + /// } + /// `````` + pub NEEDLESS_DOCTEST_MAIN, + style, + "presence of `fn main() {` in code examples" +} + #[allow(clippy::module_name_repetitions)] #[derive(Clone)] pub struct DocMarkdown { @@ -80,7 +108,7 @@ impl DocMarkdown { } } -impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC]); +impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, NEEDLESS_DOCTEST_MAIN]); impl EarlyLintPass for DocMarkdown { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { @@ -245,17 +273,16 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize continue; } safety_header |= in_heading && text.trim() == "Safety"; - if !in_code { - let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) { - Ok(o) => o, - Err(e) => e - 1, - }; - - let (begin, span) = spans[index]; - + let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) { + Ok(o) => o, + Err(e) => e - 1, + }; + let (begin, span) = spans[index]; + if in_code { + check_code(cx, &text, span); + } else { // Adjust for the beginning of the current `Event` let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin)); - check_text(cx, valid_idents, &text, span); } }, @@ -264,6 +291,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize safety_header } +fn check_code(cx: &EarlyContext<'_>, text: &str, span: Span) { + if text.contains("fn main() {") { + span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); + } +} + fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) { for word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ed47b6a1857..10a14f3b906 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -713,6 +713,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con copies::IF_SAME_THEN_ELSE, derive::DERIVE_HASH_XOR_EQ, doc::MISSING_SAFETY_DOC, + doc::NEEDLESS_DOCTEST_MAIN, double_comparison::DOUBLE_COMPARISONS, double_parens::DOUBLE_PARENS, drop_bounds::DROP_BOUNDS, @@ -937,6 +938,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con collapsible_if::COLLAPSIBLE_IF, comparison_chain::COMPARISON_CHAIN, doc::MISSING_SAFETY_DOC, + doc::NEEDLESS_DOCTEST_MAIN, enum_variants::ENUM_VARIANT_NAMES, enum_variants::MODULE_INCEPTION, eq_op::OP_REF, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1b838b17f7f..383be8b1da4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 317] = [ +pub const ALL_LINTS: [Lint; 318] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1225,6 +1225,13 @@ pub const ALL_LINTS: [Lint; 317] = [ deprecation: None, module: "needless_continue", }, + Lint { + name: "needless_doctest_main", + group: "style", + desc: "presence of `fn main() {` in code examples", + deprecation: None, + module: "doc", + }, Lint { name: "needless_lifetimes", group: "complexity", -- cgit 1.4.1-3-g733a5 From 27fa2b7944d79c1fa16445628fef268bdb34f625 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Fri, 27 Sep 2019 19:19:26 +0200 Subject: New lint: unsound_collection_transmute --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/transmute.rs | 530 ++++++++++++++++++++--------------- src/lintlist/mod.rs | 9 +- tests/ui/transmute.rs | 6 - tests/ui/transmute.stderr | 38 +-- tests/ui/transmute_collection.rs | 47 ++++ tests/ui/transmute_collection.stderr | 112 ++++++++ 9 files changed, 490 insertions(+), 257 deletions(-) create mode 100644 tests/ui/transmute_collection.rs create mode 100644 tests/ui/transmute_collection.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index c4e04586530..4fe97097fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1225,6 +1225,7 @@ Released 2018-09-13 [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix +[`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute [`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect diff --git a/README.md b/README.md index 2f7032af87d..9a75d2ced08 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 318 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 319 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 10a14f3b906..1414b4ad87d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -890,6 +890,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con transmute::TRANSMUTE_INT_TO_FLOAT, transmute::TRANSMUTE_PTR_TO_PTR, transmute::TRANSMUTE_PTR_TO_REF, + transmute::UNSOUND_COLLECTION_TRANSMUTE, transmute::USELESS_TRANSMUTE, transmute::WRONG_TRANSMUTE, transmuting_null::TRANSMUTING_NULL, @@ -1145,6 +1146,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, swap::ALMOST_SWAPPED, + transmute::UNSOUND_COLLECTION_TRANSMUTE, transmute::WRONG_TRANSMUTE, transmuting_null::TRANSMUTING_NULL, types::ABSURD_EXTREME_COMPARISONS, diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 1f029491df4..1339555f9ce 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -216,6 +216,33 @@ declare_clippy_lint! { "transmutes from a pointer to a pointer / a reference to a reference" } +declare_clippy_lint! { + /// **What it does:** Checks for transmutes between collections whose + /// types have different ABI, size or alignment. + /// + /// **Why is this bad?** This is undefined behavior. + /// + /// **Known problems:** Currently, we cannot know whether a type is a + /// collection, so we just lint the ones that come with `std`. + /// + /// **Example:** + /// ```rust + /// // different size, therefore likely out-of-bounds memory access + /// // You absolutely do not want this in your code! + /// unsafe { + /// std::mem::transmute::<_, Vec<u32>>(vec![2_u16]) + /// }; + /// ``` + /// + /// You must always iterate, map and collect the values: + /// + /// ```rust + /// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>(); + /// ``` + pub UNSOUND_COLLECTION_TRANSMUTE, + correctness, + "transmute between collections of layout-incompatible types" +} declare_lint_pass!(Transmute => [ CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, @@ -226,262 +253,292 @@ declare_lint_pass!(Transmute => [ TRANSMUTE_BYTES_TO_STR, TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_FLOAT, + UNSOUND_COLLECTION_TRANSMUTE, ]); +// used to check for UNSOUND_COLLECTION_TRANSMUTE +static COLLECTIONS: &[&[&str]] = &[ + &paths::VEC, + &paths::VEC_DEQUE, + &paths::BINARY_HEAP, + &paths::BTREESET, + &paths::BTREEMAP, + &paths::HASHSET, + &paths::HASHMAP, +]; impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { #[allow(clippy::similar_names, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if let ExprKind::Call(ref path_expr, ref args) = e.kind { - if let ExprKind::Path(ref qpath) = path_expr.kind { - if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() { - if match_def_path(cx, def_id, &paths::TRANSMUTE) { - let from_ty = cx.tables.expr_ty(&args[0]); - let to_ty = cx.tables.expr_ty(e); + if_chain! { + if let ExprKind::Call(ref path_expr, ref args) = e.kind; + if let ExprKind::Path(ref qpath) = path_expr.kind; + if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::TRANSMUTE); + then { + let from_ty = cx.tables.expr_ty(&args[0]); + let to_ty = cx.tables.expr_ty(e); - match (&from_ty.kind, &to_ty.kind) { - _ if from_ty == to_ty => span_lint( - cx, - USELESS_TRANSMUTE, - e.span, - &format!("transmute from a type (`{}`) to itself", from_ty), - ), - (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(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 rty_and_mut = ty::TypeAndMut { - ty: rty, - mutbl: rty_mutbl, - }; + match (&from_ty.kind, &to_ty.kind) { + _ if from_ty == to_ty => span_lint( + cx, + USELESS_TRANSMUTE, + e.span, + &format!("transmute from a type (`{}`) to itself", from_ty), + ), + (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(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 rty_and_mut = ty::TypeAndMut { + ty: rty, + mutbl: rty_mutbl, + }; - let sugg = if ptr_ty == rty_and_mut { - arg.as_ty(to_ty) - } else { - arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) - }; + let sugg = if ptr_ty == rty_and_mut { + arg.as_ty(to_ty) + } else { + arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) + }; - db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); - } - }, - ), - (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => 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(), - Applicability::Unspecified, - ); - } - }, - ), - (&ty::Float(_), &ty::Ref(..)) - | (&ty::Float(_), &ty::RawPtr(_)) - | (&ty::Char, &ty::Ref(..)) - | (&ty::Char, &ty::RawPtr(_)) => span_lint( - cx, - WRONG_TRANSMUTE, - e.span, - &format!("transmute from a `{}` to a pointer", from_ty), - ), - (&ty::RawPtr(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 - ), - ), - (_, &ty::RawPtr(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 - ), - ), - (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => 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 mutbl == Mutability::MutMutable { - ("&mut *", "*mut") - } else { - ("&*", "*const") - }; + db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); + } + }, + ), + (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => 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(), + Applicability::Unspecified, + ); + } + }, + ), + (&ty::Float(_), &ty::Ref(..)) + | (&ty::Float(_), &ty::RawPtr(_)) + | (&ty::Char, &ty::Ref(..)) + | (&ty::Char, &ty::RawPtr(_)) => span_lint( + cx, + WRONG_TRANSMUTE, + e.span, + &format!("transmute from a `{}` to a pointer", from_ty), + ), + (&ty::RawPtr(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 + ), + ), + (_, &ty::RawPtr(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 + ), + ), + (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => 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 mutbl == Mutability::MutMutable { + ("&mut *", "*mut") + } else { + ("&*", "*const") + }; - let arg = if from_pty.ty == to_ref_ty { - arg - } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty))) - }; + let arg = if from_pty.ty == to_ref_ty { + arg + } else { + arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty))) + }; - db.span_suggestion( - e.span, - "try", - sugg::make_unop(deref, arg).to_string(), - Applicability::Unspecified, - ); - }, - ), - (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => { - span_lint_and_then( - cx, - TRANSMUTE_INT_TO_CHAR, + db.span_suggestion( + e.span, + "try", + sugg::make_unop(deref, arg).to_string(), + Applicability::Unspecified, + ); + }, + ), + (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => { + span_lint_and_then( + cx, + TRANSMUTE_INT_TO_CHAR, + e.span, + &format!("transmute from a `{}` to a `char`", from_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let arg = if let ty::Int(_) = from_ty.kind { + arg.as_ty(ast::UintTy::U32) + } else { + arg + }; + db.span_suggestion( e.span, - &format!("transmute from a `{}` to a `char`", from_ty), - |db| { - let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let arg = if let ty::Int(_) = from_ty.kind { - arg.as_ty(ast::UintTy::U32) - } else { - arg - }; - db.span_suggestion( - e.span, - "consider using", - format!("std::char::from_u32({}).unwrap()", arg.to_string()), - Applicability::Unspecified, - ); - }, - ) + "consider using", + format!("std::char::from_u32({}).unwrap()", arg.to_string()), + Applicability::Unspecified, + ); }, - (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => { - if_chain! { - if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind); - if let ty::Uint(ast::UintTy::U8) = slice_ty.kind; - if from_mutbl == to_mutbl; - then { - let postfix = if from_mutbl == Mutability::MutMutable { - "_mut" - } else { - "" - }; + ) + }, + (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => { + if_chain! { + if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind); + if let ty::Uint(ast::UintTy::U8) = slice_ty.kind; + if from_mutbl == to_mutbl; + then { + let postfix = if from_mutbl == Mutability::MutMutable { + "_mut" + } else { + "" + }; - span_lint_and_then( - cx, - TRANSMUTE_BYTES_TO_STR, - e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), - |db| { - db.span_suggestion( - e.span, - "consider using", - format!( - "std::str::from_utf8{}({}).unwrap()", - postfix, - snippet(cx, args[0].span, ".."), - ), - Applicability::Unspecified, - ); - } - ) - } else { - if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { - span_lint_and_then( - cx, - TRANSMUTE_PTR_TO_PTR, - e.span, - "transmute from a reference to a reference", - |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { - let ty_from_and_mut = ty::TypeAndMut { - ty: ty_from, - mutbl: from_mutbl - }; - let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl }; - let sugg_paren = arg - .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) - .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); - let sugg = if to_mutbl == Mutability::MutMutable { - sugg_paren.mut_addr_deref() - } else { - sugg_paren.addr_deref() - }; - db.span_suggestion( - e.span, - "try", - sugg.to_string(), - Applicability::Unspecified, - ); - }, - ) - } - } - } - }, - (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then( - cx, - TRANSMUTE_PTR_TO_PTR, - e.span, - "transmute from a pointer to a pointer", - |db| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { - let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty)); - db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); - } - }, - ), - (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => { span_lint_and_then( cx, - TRANSMUTE_INT_TO_BOOL, + TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{}` to a `bool`", from_ty), + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), |db| { - let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let zero = sugg::Sugg::NonParen(Cow::from("0")); db.span_suggestion( e.span, "consider using", - sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(), + format!( + "std::str::from_utf8{}({}).unwrap()", + postfix, + snippet(cx, args[0].span, ".."), + ), Applicability::Unspecified, ); - }, + } ) + } else { + if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { + span_lint_and_then( + cx, + TRANSMUTE_PTR_TO_PTR, + e.span, + "transmute from a reference to a reference", + |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { + let ty_from_and_mut = ty::TypeAndMut { + ty: ty_from, + mutbl: from_mutbl + }; + let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl }; + let sugg_paren = arg + .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) + .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); + let sugg = if to_mutbl == Mutability::MutMutable { + sugg_paren.mut_addr_deref() + } else { + sugg_paren.addr_deref() + }; + db.span_suggestion( + e.span, + "try", + sugg.to_string(), + Applicability::Unspecified, + ); + }, + ) + } + } + } + }, + (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then( + cx, + TRANSMUTE_PTR_TO_PTR, + e.span, + "transmute from a pointer to a pointer", + |db| { + if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { + let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty)); + db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); + } + }, + ), + (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => { + span_lint_and_then( + cx, + TRANSMUTE_INT_TO_BOOL, + e.span, + &format!("transmute from a `{}` to a `bool`", from_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let zero = sugg::Sugg::NonParen(Cow::from("0")); + db.span_suggestion( + e.span, + "consider using", + sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(), + Applicability::Unspecified, + ); }, - (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then( + ) + }, + (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then( + cx, + TRANSMUTE_INT_TO_FLOAT, + e.span, + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let arg = if let ty::Int(int_ty) = from_ty.kind { + arg.as_ty(format!( + "u{}", + int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()) + )) + } else { + arg + }; + db.span_suggestion( + e.span, + "consider using", + format!("{}::from_bits({})", to_ty, arg.to_string()), + Applicability::Unspecified, + ); + }, + ), + (&ty::Adt(ref from_adt, ref from_substs), &ty::Adt(ref to_adt, ref to_substs)) => { + if from_adt.did != to_adt.did || + !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) { + return; + } + if from_substs.types().zip(to_substs.types()) + .any(|(from_ty, to_ty)| is_layout_incompatible(cx, from_ty, to_ty)) { + span_lint( cx, - TRANSMUTE_INT_TO_FLOAT, + UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), - |db| { - let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let arg = if let ty::Int(int_ty) = from_ty.kind { - arg.as_ty(format!( - "u{}", - int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()) - )) - } else { - arg - }; - db.span_suggestion( - e.span, - "consider using", - format!("{}::from_bits({})", to_ty, arg.to_string()), - Applicability::Unspecified, - ); - }, - ), - _ => return, - }; - } + &format!( + "transmute from `{}` to `{}` with mismatched layout is unsound", + from_ty, + to_ty + ) + ); + } + }, + _ => return, } } } @@ -510,3 +567,16 @@ fn get_type_snippet(cx: &LateContext<'_, '_>, path: &QPath, to_ref_ty: Ty<'_>) - to_ref_ty.to_string() } + +// check if the component types of the transmuted collection and the result have different ABI, +// size or alignment +fn is_layout_incompatible<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { + let from_ty_layout = cx.tcx.layout_of(ty::ParamEnv::empty().and(from)); + let to_ty_layout = cx.tcx.layout_of(ty::ParamEnv::empty().and(to)); + if let (Ok(from_layout), Ok(to_layout)) = (from_ty_layout, to_ty_layout) { + from_layout.size != to_layout.size || from_layout.align != to_layout.align || from_layout.abi != to_layout.abi + } else { + // no idea about layout, so don't lint + false + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 383be8b1da4..002709ac0d4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 318] = [ +pub const ALL_LINTS: [Lint; 319] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2030,6 +2030,13 @@ pub const ALL_LINTS: [Lint; 318] = [ deprecation: None, module: "misc_early", }, + Lint { + name: "unsound_collection_transmute", + group: "correctness", + desc: "transmute between collections of layout-incompatible types", + deprecation: None, + module: "transmute", + }, Lint { name: "unused_io_amount", group: "correctness", diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 6ec7697c0d6..4f0c2f5a895 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -80,12 +80,6 @@ fn useless() { let _: Vec<i32> = my_transmute(my_vec()); - let _: Vec<u32> = core::intrinsics::transmute(my_vec()); - let _: Vec<u32> = core::mem::transmute(my_vec()); - let _: Vec<u32> = std::intrinsics::transmute(my_vec()); - let _: Vec<u32> = std::mem::transmute(my_vec()); - let _: Vec<u32> = my_transmute(my_vec()); - let _: *const usize = std::mem::transmute(5_isize); let _ = 5_isize as *const usize; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index ceee86d224d..f73d72f20bb 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -117,19 +117,19 @@ LL | let _: Vec<i32> = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> $DIR/transmute.rs:89:31 + --> $DIR/transmute.rs:83:31 | LL | let _: *const usize = std::mem::transmute(5_isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` error: transmute from an integer to a pointer - --> $DIR/transmute.rs:93:31 + --> $DIR/transmute.rs:87:31 | LL | let _: *const usize = std::mem::transmute(1 + 1usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:108:24 + --> $DIR/transmute.rs:102:24 | LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,25 +137,25 @@ LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); = note: `-D clippy::crosspointer-transmute` implied by `-D warnings` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> $DIR/transmute.rs:110:24 + --> $DIR/transmute.rs:104:24 | LL | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> $DIR/transmute.rs:112:31 + --> $DIR/transmute.rs:106:31 | LL | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> $DIR/transmute.rs:114:29 + --> $DIR/transmute.rs:108:29 | LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u32` to a `char` - --> $DIR/transmute.rs:120:28 + --> $DIR/transmute.rs:114:28 | LL | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` @@ -163,13 +163,13 @@ LL | let _: char = unsafe { std::mem::transmute(0_u32) }; = note: `-D clippy::transmute-int-to-char` implied by `-D warnings` error: transmute from a `i32` to a `char` - --> $DIR/transmute.rs:121:28 + --> $DIR/transmute.rs:115:28 | LL | let _: char = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` error: transmute from a `u8` to a `bool` - --> $DIR/transmute.rs:126:28 + --> $DIR/transmute.rs:120:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -177,7 +177,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings` error: transmute from a `u32` to a `f32` - --> $DIR/transmute.rs:131:27 + --> $DIR/transmute.rs:125:27 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -185,13 +185,13 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = note: `-D clippy::transmute-int-to-float` implied by `-D warnings` error: transmute from a `i32` to a `f32` - --> $DIR/transmute.rs:132:27 + --> $DIR/transmute.rs:126:27 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:136:28 + --> $DIR/transmute.rs:130:28 | LL | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` @@ -199,13 +199,13 @@ LL | let _: &str = unsafe { std::mem::transmute(b) }; = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:137:32 + --> $DIR/transmute.rs:131:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:169:29 + --> $DIR/transmute.rs:163:29 | LL | let _: *const f32 = std::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32` @@ -213,31 +213,31 @@ LL | let _: *const f32 = std::mem::transmute(ptr); = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:170:27 + --> $DIR/transmute.rs:164:27 | LL | let _: *mut f32 = std::mem::transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32` error: transmute from a reference to a reference - --> $DIR/transmute.rs:172:23 + --> $DIR/transmute.rs:166:23 | LL | let _: &f32 = std::mem::transmute(&1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:173:23 + --> $DIR/transmute.rs:167:23 | LL | let _: &f64 = std::mem::transmute(&1f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:176:27 + --> $DIR/transmute.rs:170:27 | LL | let _: &mut f32 = std::mem::transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:177:37 + --> $DIR/transmute.rs:171:37 | LL | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` diff --git a/tests/ui/transmute_collection.rs b/tests/ui/transmute_collection.rs new file mode 100644 index 00000000000..cd5a7127791 --- /dev/null +++ b/tests/ui/transmute_collection.rs @@ -0,0 +1,47 @@ +#![warn(clippy::unsound_collection_transmute)] + +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; +use std::mem::transmute; + +fn main() { + unsafe { + // wrong size + let _ = transmute::<_, Vec<u32>>(vec![0u8]); + // wrong layout + let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); + + // wrong size + let _ = transmute::<_, VecDeque<u32>>(VecDeque::<u8>::new()); + // wrong layout + let _ = transmute::<_, VecDeque<u32>>(VecDeque::<[u8; 4]>::new()); + + // wrong size + let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<u8>::new()); + // wrong layout + let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<[u8; 4]>::new()); + + // wrong size + let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<u8>::new()); + // wrong layout + let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<[u8; 4]>::new()); + + // wrong size + let _ = transmute::<_, HashSet<u32>>(HashSet::<u8>::new()); + // wrong layout + let _ = transmute::<_, HashSet<u32>>(HashSet::<[u8; 4]>::new()); + + // wrong size + let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, u8>::new()); + let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u32, u32>::new()); + // wrong layout + let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, [u8; 4]>::new()); + let _ = transmute::<_, BTreeMap<u32, u32>>(BTreeMap::<[u8; 4], u32>::new()); + + // wrong size + let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, u8>::new()); + let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u32, u32>::new()); + // wrong layout + let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, [u8; 4]>::new()); + let _ = transmute::<_, HashMap<u32, u32>>(HashMap::<[u8; 4], u32>::new()); + } +} diff --git a/tests/ui/transmute_collection.stderr b/tests/ui/transmute_collection.stderr new file mode 100644 index 00000000000..ebc05c402ab --- /dev/null +++ b/tests/ui/transmute_collection.stderr @@ -0,0 +1,112 @@ +error: transmute from `std::vec::Vec<u8>` to `std::vec::Vec<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:9:17 + | +LL | let _ = transmute::<_, Vec<u32>>(vec![0u8]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unsound-collection-transmute` implied by `-D warnings` + +error: transmute from `std::vec::Vec<u32>` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:11:17 + | +LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::VecDeque<u8>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:14:17 + | +LL | let _ = transmute::<_, VecDeque<u32>>(VecDeque::<u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:16:17 + | +LL | let _ = transmute::<_, VecDeque<u32>>(VecDeque::<[u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BinaryHeap<u8>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:19:17 + | +LL | let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BinaryHeap<[u8; 4]>` to `std::collections::BinaryHeap<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:21:17 + | +LL | let _ = transmute::<_, BinaryHeap<u32>>(BinaryHeap::<[u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeSet<u8>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:24:17 + | +LL | let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeSet<[u8; 4]>` to `std::collections::BTreeSet<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:26:17 + | +LL | let _ = transmute::<_, BTreeSet<u32>>(BTreeSet::<[u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashSet<u8>` to `std::collections::HashSet<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:29:17 + | +LL | let _ = transmute::<_, HashSet<u32>>(HashSet::<u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections::HashSet<u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:31:17 + | +LL | let _ = transmute::<_, HashSet<u32>>(HashSet::<[u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeMap<u8, u8>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:34:17 + | +LL | let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeMap<u32, u32>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:35:17 + | +LL | let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u32, u32>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeMap<u8, [u8; 4]>` to `std::collections::BTreeMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:37:17 + | +LL | let _ = transmute::<_, BTreeMap<u8, u32>>(BTreeMap::<u8, [u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap<u32, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:38:17 + | +LL | let _ = transmute::<_, BTreeMap<u32, u32>>(BTreeMap::<[u8; 4], u32>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashMap<u8, u8>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:41:17 + | +LL | let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, u8>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashMap<u32, u32>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:42:17 + | +LL | let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u32, u32>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashMap<u8, [u8; 4]>` to `std::collections::HashMap<u8, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:44:17 + | +LL | let _ = transmute::<_, HashMap<u8, u32>>(HashMap::<u8, [u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collections::HashMap<u32, u32>` with mismatched layout is unsound + --> $DIR/transmute_collection.rs:45:17 + | +LL | let _ = transmute::<_, HashMap<u32, u32>>(HashMap::<[u8; 4], u32>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors + -- cgit 1.4.1-3-g733a5 From 301ef6bb2a3883da9b1340b243f3a934ec3c6fb8 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada <sinkuu@sinkuu.xyz> Date: Tue, 17 Sep 2019 00:50:15 +0900 Subject: Fix false-positive of redundant_clone and move to clippy::perf --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/redundant_clone.rs | 372 +++++++++++++++++++++++++++++------- src/lintlist/mod.rs | 2 +- tests/ui/redundant_clone.rs | 70 +++++++ tests/ui/redundant_clone.stderr | 42 +++- 5 files changed, 413 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 10a14f3b906..3e31779426a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -864,6 +864,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con ranges::RANGE_MINUS_ONE, ranges::RANGE_PLUS_ONE, ranges::RANGE_ZIP_WITH_LEN, + redundant_clone::REDUNDANT_CLONE, redundant_field_names::REDUNDANT_FIELD_NAMES, redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, @@ -1169,6 +1170,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::SINGLE_CHAR_PATTERN, misc::CMP_OWNED, mutex_atomic::MUTEX_ATOMIC, + redundant_clone::REDUNDANT_CLONE, slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, types::BOX_VEC, @@ -1188,7 +1190,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con mutex_atomic::MUTEX_INTEGER, needless_borrow::NEEDLESS_BORROW, path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, - redundant_clone::REDUNDANT_CLONE, ]); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 09a55d26424..ad8ed568656 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -9,12 +9,19 @@ use rustc::hir::{def_id, Body, FnDecl, HirId}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::mir::{ self, traversal, - visit::{MutatingUseContext, PlaceContext, Visitor}, - TerminatorKind, + visit::{MutatingUseContext, PlaceContext, Visitor as _}, }; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, fold::TypeVisitor, Ty}; use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_data_structures::{ + bit_set::{BitSet, HybridBitSet}, + fx::FxHashMap, + transitive_relation::TransitiveRelation, +}; use rustc_errors::Applicability; +use rustc_mir::dataflow::{ + do_dataflow, BitDenotation, BottomValue, DataflowResults, DataflowResultsCursor, DebugFormatted, GenKillSet, +}; use std::convert::TryFrom; use syntax::source_map::{BytePos, Span}; @@ -36,17 +43,7 @@ declare_clippy_lint! { /// /// **Known problems:** /// - /// * Suggestions made by this lint could require NLL to be enabled. - /// * False-positive if there is a borrow preventing the value from moving out. - /// - /// ```rust - /// # fn foo(x: String) {} - /// let x = String::new(); - /// - /// let y = &x; - /// - /// foo(x.clone()); // This lint suggests to remove this `clone()` - /// ``` + /// False-negatives: analysis performed by this lint is conservative and limited. /// /// **Example:** /// ```rust @@ -68,7 +65,7 @@ declare_clippy_lint! { /// Path::new("/a/b").join("c").to_path_buf(); /// ``` pub REDUNDANT_CLONE, - nursery, + perf, "`clone()` of an owned value that is going to be dropped immediately" } @@ -88,6 +85,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); let mir = cx.tcx.optimized_mir(def_id); + let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len()); + let maybe_storage_live_result = do_dataflow( + cx.tcx, + mir, + def_id, + &[], + &dead_unwinds, + MaybeStorageLive::new(mir), + |bd, p| DebugFormatted::new(&bd.body.local_decls[p]), + ); + let mut possible_borrower = { + let mut vis = PossibleBorrowerVisitor::new(cx, mir); + vis.visit_body(mir); + vis.into_map(cx, maybe_storage_live_result) + }; + for (bb, bbdata) in mir.basic_blocks().iter_enumerated() { let terminator = bbdata.terminator(); @@ -117,15 +130,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { // _1 in MIR `{ _2 = &_1; clone(move _2); }` or `{ _2 = _1; to_path_buf(_2); } (from_deref) // In case of `from_deref`, `arg` is already a reference since it is `deref`ed in the previous // block. - let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to( - cx, - mir, - arg, - from_borrow, - bbdata.statements.iter() - )); - - if from_borrow && cannot_move_out { + let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(cx, mir, arg, from_borrow, bb)); + + let loc = mir::Location { + block: bb, + statement_index: bbdata.statements.len(), + }; + + if from_borrow + && (cannot_move_out || possible_borrower.only_borrowers(&[arg][..], cloned, loc) != Some(true)) + { continue; } @@ -151,14 +165,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { } }; - let (local, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to( - cx, - mir, - pred_arg, - true, - mir[ps[0]].statements.iter() - )); - if cannot_move_out { + let (local, cannot_move_out) = + unwrap_or_continue!(find_stmt_assigns_to(cx, mir, pred_arg, true, ps[0])); + let loc = mir::Location { + block: bb, + statement_index: mir.basic_blocks()[bb].statements.len(), + }; + if cannot_move_out || possible_borrower.only_borrowers(&[arg, cloned][..], local, loc) != Some(true) { continue; } local @@ -224,7 +237,7 @@ fn is_call_with_ref_arg<'tcx>( kind: &'tcx mir::TerminatorKind<'tcx>, ) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, Option<&'tcx mir::Place<'tcx>>)> { if_chain! { - if let TerminatorKind::Call { func, args, destination, .. } = kind; + if let mir::TerminatorKind::Call { func, args, destination, .. } = kind; if args.len() == 1; if let mir::Operand::Move(mir::Place { base: mir::PlaceBase::Local(local), .. }) = &args[0]; if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).kind; @@ -241,42 +254,35 @@ fn is_call_with_ref_arg<'tcx>( type CannotMoveOut = bool; /// Finds the first `to = (&)from`, and returns -/// ``Some((from, [`true` if `from` cannot be moved out]))``. -fn find_stmt_assigns_to<'a, 'tcx: 'a>( +/// ``Some((from, whether `from` cannot be moved out))``. +fn find_stmt_assigns_to<'tcx>( cx: &LateContext<'_, 'tcx>, mir: &mir::Body<'tcx>, - to: mir::Local, + to_local: mir::Local, by_ref: bool, - stmts: impl DoubleEndedIterator<Item = &'a mir::Statement<'tcx>>, + bb: mir::BasicBlock, ) -> Option<(mir::Local, CannotMoveOut)> { - stmts - .rev() - .find_map(|stmt| { - if let mir::StatementKind::Assign(box ( - mir::Place { - base: mir::PlaceBase::Local(local), - .. - }, - v, - )) = &stmt.kind - { - if *local == to { - return Some(v); - } - } + let rvalue = mir.basic_blocks()[bb].statements.iter().rev().find_map(|stmt| { + if let mir::StatementKind::Assign(box ( + mir::Place { + base: mir::PlaceBase::Local(local), + .. + }, + v, + )) = &stmt.kind + { + return if *local == to_local { Some(v) } else { None }; + } - None - }) - .and_then(|v| { - if by_ref { - if let mir::Rvalue::Ref(_, _, ref place) = v { - return base_local_and_movability(cx, mir, place); - } - } else if let mir::Rvalue::Use(mir::Operand::Copy(ref place)) = v { - return base_local_and_movability(cx, mir, place); - } - None - }) + None + })?; + + match (by_ref, &*rvalue) { + (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => { + base_local_and_movability(cx, mir, place) + }, + _ => None, + } } /// Extracts and returns the undermost base `Local` of given `place`. Returns `place` itself @@ -288,8 +294,6 @@ fn base_local_and_movability<'tcx>( mir: &mir::Body<'tcx>, place: &mir::Place<'tcx>, ) -> Option<(mir::Local, CannotMoveOut)> { - use rustc::mir::Place; - use rustc::mir::PlaceBase; use rustc::mir::PlaceRef; // Dereference. You cannot move things out from a borrowed value. @@ -301,13 +305,15 @@ fn base_local_and_movability<'tcx>( base: place_base, mut projection, } = place.as_ref(); - if let PlaceBase::Local(local) = place_base { + if let mir::PlaceBase::Local(local) = place_base { while let [base @ .., elem] = projection { projection = base; - deref = matches!(elem, mir::ProjectionElem::Deref); - field = !field - && matches!(elem, mir::ProjectionElem::Field(..)) - && has_drop(cx, Place::ty_from(place_base, projection, &mir.local_decls, cx.tcx).ty); + deref |= matches!(elem, mir::ProjectionElem::Deref); + field |= matches!(elem, mir::ProjectionElem::Field(..)) + && has_drop( + cx, + mir::Place::ty_from(place_base, projection, &mir.local_decls, cx.tcx).ty, + ); } Some((*local, deref || field)) @@ -353,3 +359,227 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor { } } } + +#[derive(Copy, Clone)] +struct MaybeStorageLive<'a, 'tcx> { + body: &'a mir::Body<'tcx>, +} + +impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> { + fn new(body: &'a mir::Body<'tcx>) -> Self { + MaybeStorageLive { body } + } +} + +impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { + type Idx = mir::Local; + fn name() -> &'static str { + "maybe_storage_live" + } + fn bits_per_block(&self) -> usize { + self.body.local_decls.len() + } + + fn start_block_effect(&self, on_entry: &mut BitSet<mir::Local>) { + for arg in self.body.args_iter() { + on_entry.insert(arg); + } + } + + fn statement_effect(&self, trans: &mut GenKillSet<mir::Local>, loc: mir::Location) { + let stmt = &self.body[loc.block].statements[loc.statement_index]; + + match stmt.kind { + mir::StatementKind::StorageLive(l) => trans.gen(l), + mir::StatementKind::StorageDead(l) => trans.kill(l), + _ => (), + } + } + + fn terminator_effect(&self, _trans: &mut GenKillSet<mir::Local>, _loc: mir::Location) {} + + fn propagate_call_return( + &self, + _in_out: &mut BitSet<mir::Local>, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place<'tcx>, + ) { + // Nothing to do when a call returns successfully + } +} + +impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> { + /// bottom = dead + const BOTTOM_VALUE: bool = false; +} + +struct PossibleBorrowerVisitor<'a, 'tcx> { + possible_borrower: TransitiveRelation<mir::Local>, + body: &'a mir::Body<'tcx>, + cx: &'a LateContext<'a, 'tcx>, +} + +impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'a, 'tcx>, body: &'a mir::Body<'tcx>) -> Self { + Self { + possible_borrower: TransitiveRelation::default(), + cx, + body, + } + } + + fn into_map( + self, + cx: &LateContext<'a, 'tcx>, + maybe_live: DataflowResults<'tcx, MaybeStorageLive<'a, 'tcx>>, + ) -> PossibleBorrower<'a, 'tcx> { + let mut map = FxHashMap::default(); + for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) { + if is_copy(cx, self.body.local_decls[row].ty) { + continue; + } + + let borrowers = self.possible_borrower.reachable_from(&row); + if !borrowers.is_empty() { + let mut bs = HybridBitSet::new_empty(self.body.local_decls.len()); + for &c in borrowers { + if c != mir::Local::from_usize(0) { + bs.insert(c); + } + } + + if !bs.is_empty() { + map.insert(row, bs); + } + } + } + + let bs = BitSet::new_empty(self.body.local_decls.len()); + PossibleBorrower { + map, + maybe_live: DataflowResultsCursor::new(maybe_live, self.body), + bitset: (bs.clone(), bs), + } + } +} + +impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { + fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) { + if let mir::PlaceBase::Local(lhs) = place.base { + match rvalue { + mir::Rvalue::Ref(_, _, borrowed) => { + if let mir::PlaceBase::Local(borrowed_local) = borrowed.base { + self.possible_borrower.add(borrowed_local, lhs); + } + }, + other => { + if !ContainsRegion.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) { + return; + } + rvalue_locals(other, |rhs| { + if lhs != rhs { + self.possible_borrower.add(rhs, lhs); + } + }); + }, + } + } + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) { + if let mir::TerminatorKind::Call { + args, + destination: + Some(( + mir::Place { + base: mir::PlaceBase::Local(dest), + .. + }, + _, + )), + .. + } = &terminator.kind + { + // If the call returns something with some lifetime, + // let's conservatively assume the returned value contains lifetime of all the arguments. + let mut cr = ContainsRegion; + if !cr.visit_ty(&self.body.local_decls[*dest].ty) { + return; + } + + for op in args { + match op { + mir::Operand::Copy(p) | mir::Operand::Move(p) => { + if let mir::PlaceBase::Local(arg) = p.base { + self.possible_borrower.add(arg, *dest); + } + }, + _ => (), + } + } + } + } +} + +struct ContainsRegion; + +impl TypeVisitor<'_> for ContainsRegion { + fn visit_region(&mut self, _: ty::Region<'_>) -> bool { + true + } +} + +fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { + use rustc::mir::Rvalue::*; + + let mut visit_op = |op: &mir::Operand<'_>| match op { + mir::Operand::Copy(p) | mir::Operand::Move(p) => { + if let mir::PlaceBase::Local(l) = p.base { + visit(l) + } + }, + _ => (), + }; + + match rvalue { + Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op), + Aggregate(_, ops) => ops.iter().for_each(visit_op), + BinaryOp(_, lhs, rhs) | CheckedBinaryOp(_, lhs, rhs) => { + visit_op(lhs); + visit_op(rhs); + }, + _ => (), + } +} + +struct PossibleBorrower<'a, 'tcx> { + map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>, + maybe_live: + DataflowResultsCursor<'a, 'tcx, MaybeStorageLive<'a, 'tcx>, DataflowResults<'tcx, MaybeStorageLive<'a, 'tcx>>>, + bitset: (BitSet<mir::Local>, BitSet<mir::Local>), +} + +impl PossibleBorrower<'_, '_> { + fn only_borrowers<'a>( + &mut self, + borrowers: impl IntoIterator<Item = &'a mir::Local>, + borrowed: mir::Local, + at: mir::Location, + ) -> Option<bool> { + self.maybe_live.seek(at); + + self.bitset.0.clear(); + let maybe_live = &mut self.maybe_live; + for b in self.map.get(&borrowed)?.iter().filter(move |b| maybe_live.contains(*b)) { + self.bitset.0.insert(b); + } + + self.bitset.1.clear(); + for b in borrowers { + self.bitset.1.insert(*b); + } + + Some(self.bitset.0 == self.bitset.1) + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 383be8b1da4..d56ccdfd089 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1542,7 +1542,7 @@ pub const ALL_LINTS: [Lint; 318] = [ }, Lint { name: "redundant_clone", - group: "nursery", + group: "perf", desc: "`clone()` of an owned value that is going to be dropped immediately", deprecation: None, module: "redundant_clone", diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 6e9ad71e55b..4e38a5c924c 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -32,6 +32,18 @@ fn main() { let tup_ref = &(String::from("foo"),); let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed + + { + let x = String::new(); + let y = &x; + + let _ = x.clone(); // ok; `x` is borrowed by `y` + + let _ = y.len(); + } + + let x = (String::new(),); + let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x` } #[derive(Clone)] @@ -56,3 +68,61 @@ fn cannot_move_from_type_with_drop() -> String { let s = TypeWithDrop { x: String::new() }; s.x.clone() // removing this `clone()` summons E0509 } + +fn borrower_propagation() { + let s = String::new(); + let t = String::new(); + + { + fn b() -> bool { + unimplemented!() + } + let u = if b() { &s } else { &t }; + + // ok; `s` and `t` are possibly borrowed + let _ = s.clone(); + let _ = t.clone(); + } + + { + let u = || s.len(); + let v = [&t; 32]; + let _ = s.clone(); // ok + let _ = t.clone(); // ok + } + + { + let u = { + let u = Some(&s); + let _ = s.clone(); // ok + u + }; + let _ = s.clone(); // ok + } + + { + use std::convert::identity as id; + let u = id(id(&s)); + let _ = s.clone(); // ok, `u` borrows `s` + } + + let _ = s.clone(); + let _ = t.clone(); + + #[derive(Clone)] + struct Foo { + x: usize, + } + + { + let f = Foo { x: 123 }; + let _x = Some(f.x); + let _f = f.clone(); + } + + { + let f = Foo { x: 123 }; + let _x = &f.x; + let _f = f.clone(); // ok + } +} diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index c8f6cacab2b..d1bc7e44fda 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -108,16 +108,52 @@ LL | let _ = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:41:22 + --> $DIR/redundant_clone.rs:53:22 | LL | (a.clone(), a.clone()) | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:41:21 + --> $DIR/redundant_clone.rs:53:21 | LL | (a.clone(), a.clone()) | ^ -error: aborting due to 10 previous errors +error: redundant clone + --> $DIR/redundant_clone.rs:109:14 + | +LL | let _ = s.clone(); + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:109:13 + | +LL | let _ = s.clone(); + | ^ + +error: redundant clone + --> $DIR/redundant_clone.rs:110:14 + | +LL | let _ = t.clone(); + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:110:13 + | +LL | let _ = t.clone(); + | ^ + +error: redundant clone + --> $DIR/redundant_clone.rs:120:19 + | +LL | let _f = f.clone(); + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:120:18 + | +LL | let _f = f.clone(); + | ^ + +error: aborting due to 13 previous errors -- cgit 1.4.1-3-g733a5 From 327c91f8c707c1265c4a5b350f736cda4334b764 Mon Sep 17 00:00:00 2001 From: Ethan Lam <elmemphis2000@gmail.com> Date: Sat, 28 Sep 2019 13:40:10 -0500 Subject: Addresses Issue #4001 Fixed typo Fixes lint name and uses appropriate linting suggestion changed lint help message Added autofixable test Added Autofixable Test Removed Broken Autofixable File updated lints Generated Autofixable/Nonfixable Test Cases Changed Suggestion Applicability Updated Lint Count --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 ++ clippy_lints/src/mul_add.rs | 106 ++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/mul_add.rs | 16 ++++++ tests/ui/mul_add.stderr | 34 +++++++++++++ tests/ui/mul_add_fixable.fixed | 24 +++++++++ tests/ui/mul_add_fixable.rs | 24 +++++++++ tests/ui/mul_add_fixable.stderr | 40 +++++++++++++++ 10 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/mul_add.rs create mode 100644 tests/ui/mul_add.rs create mode 100644 tests/ui/mul_add.stderr create mode 100644 tests/ui/mul_add_fixable.fixed create mode 100644 tests/ui/mul_add_fixable.rs create mode 100644 tests/ui/mul_add_fixable.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe97097fda..7415c5fa226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1063,6 +1063,7 @@ Released 2018-09-13 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_mul_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_mul_add [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names diff --git a/README.md b/README.md index 9a75d2ced08..aff8a36eca7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 319 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 320 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4300ed41833..452e4e9787d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -224,6 +224,7 @@ pub mod misc_early; pub mod missing_const_for_fn; pub mod missing_doc; pub mod missing_inline; +pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_mut; pub mod mut_reference; @@ -604,6 +605,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con reg.register_late_lint_pass(box inherent_to_string::InherentToString); reg.register_late_lint_pass(box trait_bounds::TraitBounds); reg.register_late_lint_pass(box comparison_chain::ComparisonChain); + reg.register_late_lint_pass(box mul_add::MulAddCheck); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -836,6 +838,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc_early::UNNEEDED_FIELD_PATTERN, misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::ZERO_PREFIXED_LITERAL, + mul_add::MANUAL_MUL_ADD, mut_reference::UNNECESSARY_MUT_PASSED, mutex_atomic::MUTEX_ATOMIC, needless_bool::BOOL_COMPARISON, @@ -1173,6 +1176,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::OR_FUN_CALL, methods::SINGLE_CHAR_PATTERN, misc::CMP_OWNED, + mul_add::MANUAL_MUL_ADD, mutex_atomic::MUTEX_ATOMIC, redundant_clone::REDUNDANT_CLONE, slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, diff --git a/clippy_lints/src/mul_add.rs b/clippy_lints/src/mul_add.rs new file mode 100644 index 00000000000..02e403eee18 --- /dev/null +++ b/clippy_lints/src/mul_add.rs @@ -0,0 +1,106 @@ +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_errors::Applicability; + +use crate::utils::*; + +declare_clippy_lint! { + /// **What it does:** Checks for expressions of the form `a * b + c` + /// or `c + a * b` where `a`, `b`, `c` are floats and suggests using + /// `a.mul_add(b, c)` instead. + /// + /// **Why is this bad?** Calculating `a * b + c` may lead to slight + /// numerical inaccuracies as `a * b` is rounded before being added to + /// `c`. Depending on the target architecture, `mul_add()` may be more + /// performant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # let a = 0_f32; + /// # let b = 0_f32; + /// # let c = 0_f32; + /// let foo = (a * b) + c; + /// ``` + /// + /// can be written as + /// + /// ```rust + /// # let a = 0_f32; + /// # let b = 0_f32; + /// # let c = 0_f32; + /// let foo = a.mul_add(b, c); + /// ``` + pub MANUAL_MUL_ADD, + perf, + "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`" +} + +declare_lint_pass!(MulAddCheck => [MANUAL_MUL_ADD]); + +fn is_float<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr) -> bool { + cx.tables.expr_ty(expr).is_floating_point() +} + +// Checks whether expression is multiplication of two floats +fn is_float_mult_expr<'a, 'tcx, 'b>(cx: &LateContext<'a, 'tcx>, expr: &'b Expr) -> Option<(&'b Expr, &'b Expr)> { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { + if let BinOpKind::Mul = op.node { + if is_float(cx, &lhs) && is_float(cx, &rhs) { + return Some((&lhs, &rhs)); + } + } + } + + None +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MulAddCheck { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { + if let BinOpKind::Add = op.node { + //Converts mult_lhs * mult_rhs + rhs to mult_lhs.mult_add(mult_rhs, rhs) + if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, lhs) { + if is_float(cx, rhs) { + span_lint_and_sugg( + cx, + MANUAL_MUL_ADD, + expr.span, + "consider using mul_add() for better numerical precision", + "try", + format!( + "{}.mul_add({}, {})", + snippet(cx, mult_lhs.span, "_"), + snippet(cx, mult_rhs.span, "_"), + snippet(cx, rhs.span, "_"), + ), + Applicability::MaybeIncorrect, + ); + } + } + //Converts lhs + mult_lhs * mult_rhs to mult_lhs.mult_add(mult_rhs, lhs) + if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, rhs) { + if is_float(cx, lhs) { + span_lint_and_sugg( + cx, + MANUAL_MUL_ADD, + expr.span, + "consider using mul_add() for better numerical precision", + "try", + format!( + "{}.mul_add({}, {})", + snippet(cx, mult_lhs.span, "_"), + snippet(cx, mult_rhs.span, "_"), + snippet(cx, lhs.span, "_"), + ), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2a38c2968d2..8793d98f29f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 319] = [ +pub const ALL_LINTS: [Lint; 320] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -938,6 +938,13 @@ pub const ALL_LINTS: [Lint; 319] = [ deprecation: None, module: "loops", }, + Lint { + name: "manual_mul_add", + group: "perf", + desc: "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`", + deprecation: None, + module: "mul_add", + }, Lint { name: "manual_saturating_arithmetic", group: "style", diff --git a/tests/ui/mul_add.rs b/tests/ui/mul_add.rs new file mode 100644 index 00000000000..1322e002c64 --- /dev/null +++ b/tests/ui/mul_add.rs @@ -0,0 +1,16 @@ +#![warn(clippy::manual_mul_add)] +#![allow(unused_variables)] + +fn mul_add_test() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + + // Examples of not auto-fixable expressions + let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); + let test2 = 1234.567 * 45.67834 + 0.0004; +} + +fn main() { + mul_add_test(); +} diff --git a/tests/ui/mul_add.stderr b/tests/ui/mul_add.stderr new file mode 100644 index 00000000000..92c3b9e03c1 --- /dev/null +++ b/tests/ui/mul_add.stderr @@ -0,0 +1,34 @@ +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add.rs:10:17 + | +LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(a * b + c).mul_add((c + a * b), (c + (a * b) + c))` + | + = note: `-D clippy::manual-mul-add` implied by `-D warnings` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add.rs:10:17 + | +LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); + | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add.rs:10:31 + | +LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); + | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add.rs:10:46 + | +LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); + | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add.rs:11:17 + | +LL | let test2 = 1234.567 * 45.67834 + 0.0004; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567.mul_add(45.67834, 0.0004)` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/mul_add_fixable.fixed b/tests/ui/mul_add_fixable.fixed new file mode 100644 index 00000000000..4af7c7e3e1a --- /dev/null +++ b/tests/ui/mul_add_fixable.fixed @@ -0,0 +1,24 @@ +// run-rustfix + +#![warn(clippy::manual_mul_add)] +#![allow(unused_variables)] + +fn mul_add_test() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + + // Auto-fixable examples + let test1 = a.mul_add(b, c); + let test2 = a.mul_add(b, c); + + let test3 = a.mul_add(b, c); + let test4 = a.mul_add(b, c); + + let test5 = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; + let test6 = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); +} + +fn main() { + mul_add_test(); +} diff --git a/tests/ui/mul_add_fixable.rs b/tests/ui/mul_add_fixable.rs new file mode 100644 index 00000000000..8b42f6f184a --- /dev/null +++ b/tests/ui/mul_add_fixable.rs @@ -0,0 +1,24 @@ +// run-rustfix + +#![warn(clippy::manual_mul_add)] +#![allow(unused_variables)] + +fn mul_add_test() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + + // Auto-fixable examples + let test1 = a * b + c; + let test2 = c + a * b; + + let test3 = (a * b) + c; + let test4 = c + (a * b); + + let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; +} + +fn main() { + mul_add_test(); +} diff --git a/tests/ui/mul_add_fixable.stderr b/tests/ui/mul_add_fixable.stderr new file mode 100644 index 00000000000..123ab2ff100 --- /dev/null +++ b/tests/ui/mul_add_fixable.stderr @@ -0,0 +1,40 @@ +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:12:17 + | +LL | let test1 = a * b + c; + | ^^^^^^^^^ help: try: `a.mul_add(b, c)` + | + = note: `-D clippy::manual-mul-add` implied by `-D warnings` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:13:17 + | +LL | let test2 = c + a * b; + | ^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:15:17 + | +LL | let test3 = (a * b) + c; + | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:16:17 + | +LL | let test4 = c + (a * b); + | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:18:17 + | +LL | let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` + +error: consider using mul_add() for better numerical precision + --> $DIR/mul_add_fixable.rs:19:17 + | +LL | let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From 5143fe1a789ae5bec7aeaa36e19720b7be640a21 Mon Sep 17 00:00:00 2001 From: Nikos Filippakis <nikolaos.filippakis@cern.ch> Date: Thu, 3 Oct 2019 17:45:58 +0200 Subject: New lint: suspicious_unary_op_formatting Lints when, on the RHS of a BinOp, there is a UnOp without a space before the operator but with a space after (e.g. foo >- 1). Signed-off-by: Nikos Filippakis <nikolaos.filippakis@cern.ch> --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/formatting.rs | 65 +++++++++++++++++++++++++- clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 +++- tests/ui/suspicious_unary_op_formatting.rs | 23 +++++++++ tests/ui/suspicious_unary_op_formatting.stderr | 35 ++++++++++++++ 7 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 tests/ui/suspicious_unary_op_formatting.rs create mode 100644 tests/ui/suspicious_unary_op_formatting.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7415c5fa226..86088231109 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1191,6 +1191,7 @@ Released 2018-09-13 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl +[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments diff --git a/README.md b/README.md index aff8a36eca7..3ccf5fcc250 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 320 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 321 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 52ebaa4af7d..821e79e8c77 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,4 @@ -use crate::utils::{differing_macro_contexts, snippet_opt, span_note_and_lint}; +use crate::utils::{differing_macro_contexts, snippet_opt, span_help_and_lint, span_note_and_lint}; use if_chain::if_chain; use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -22,6 +22,28 @@ declare_clippy_lint! { "suspicious formatting of `*=`, `-=` or `!=`" } +declare_clippy_lint! { + /// **What it does:** Checks the formatting of a unary operator on the right hand side + /// of a binary operator. It lints if there is no space between the binary and unary operators, + /// but there is a space between the unary and its operand. + /// + /// **Why is this bad?** This is either a typo in the binary operator or confusing. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// if foo <- 30 { // this should be `foo < -30` but looks like a different operator + /// } + /// + /// if foo &&! bar { // this should be `foo && !bar` but looks like a different operator + /// } + /// ``` + pub SUSPICIOUS_UNARY_OP_FORMATTING, + style, + "suspicious formatting of unary `-` or `!` on the RHS of a BinOp" +} + declare_clippy_lint! { /// **What it does:** Checks for formatting of `else`. It lints if the `else` /// is followed immediately by a newline or the `else` seems to be missing. @@ -80,6 +102,7 @@ declare_clippy_lint! { declare_lint_pass!(Formatting => [ SUSPICIOUS_ASSIGNMENT_FORMATTING, + SUSPICIOUS_UNARY_OP_FORMATTING, SUSPICIOUS_ELSE_FORMATTING, POSSIBLE_MISSING_COMMA ]); @@ -99,6 +122,7 @@ impl EarlyLintPass for Formatting { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { check_assign(cx, expr); + check_unop(cx, expr); check_else(cx, expr); check_array(cx, expr); } @@ -133,6 +157,45 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { } } +/// Implementation of the `SUSPICIOUS_UNARY_OP_FORMATTING` lint. +fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { + if_chain! { + if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind; + if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion(); + // span between BinOp LHS and RHS + let binop_span = lhs.span.between(rhs.span); + // if RHS is a UnOp + if let ExprKind::Unary(op, ref un_rhs) = rhs.kind; + // from UnOp operator to UnOp operand + let unop_operand_span = rhs.span.until(un_rhs.span); + if let Some(binop_snippet) = snippet_opt(cx, binop_span); + if let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span); + let binop_str = BinOpKind::to_string(&binop.node); + // no space after BinOp operator and space after UnOp operator + if binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' '); + then { + let unop_str = UnOp::to_string(op); + let eqop_span = lhs.span.between(un_rhs.span); + span_help_and_lint( + cx, + SUSPICIOUS_UNARY_OP_FORMATTING, + eqop_span, + &format!( + "by not having a space between `{binop}` and `{unop}` it looks like \ + `{binop}{unop}` is a single operator", + binop = binop_str, + unop = unop_str + ), + &format!( + "put a space between `{binop}` and `{unop}` and remove the space after `{unop}`", + binop = binop_str, + unop = unop_str + ), + ); + } + } +} + /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`. fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 452e4e9787d..ec12e06b1aa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -743,6 +743,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con formatting::POSSIBLE_MISSING_COMMA, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, + formatting::SUSPICIOUS_UNARY_OP_FORMATTING, functions::NOT_UNSAFE_PTR_ARG_DEREF, functions::TOO_MANY_ARGUMENTS, get_last_with_len::GET_LAST_WITH_LEN, @@ -953,6 +954,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con excessive_precision::EXCESSIVE_PRECISION, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, + formatting::SUSPICIOUS_UNARY_OP_FORMATTING, infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, inherent_to_string::INHERENT_TO_STRING, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8793d98f29f..28f212fb2b2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 320] = [ +pub const ALL_LINTS: [Lint; 321] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1799,6 +1799,13 @@ pub const ALL_LINTS: [Lint; 320] = [ deprecation: None, module: "suspicious_trait_impl", }, + Lint { + name: "suspicious_unary_op_formatting", + group: "style", + desc: "suspicious formatting of unary `-` or `!` on the RHS of a BinOp", + deprecation: None, + module: "formatting", + }, Lint { name: "temporary_assignment", group: "complexity", diff --git a/tests/ui/suspicious_unary_op_formatting.rs b/tests/ui/suspicious_unary_op_formatting.rs new file mode 100644 index 00000000000..9564e373c24 --- /dev/null +++ b/tests/ui/suspicious_unary_op_formatting.rs @@ -0,0 +1,23 @@ +#![warn(clippy::suspicious_unary_op_formatting)] + +#[rustfmt::skip] +fn main() { + // weird binary operator formatting: + let a = 42; + + if a >- 30 {} + if a >=- 30 {} + + let b = true; + let c = false; + + if b &&! c {} + + if a >- 30 {} + + // those are ok: + if a >-30 {} + if a < -30 {} + if b && !c {} + if a > - 30 {} +} diff --git a/tests/ui/suspicious_unary_op_formatting.stderr b/tests/ui/suspicious_unary_op_formatting.stderr new file mode 100644 index 00000000000..581527dcff8 --- /dev/null +++ b/tests/ui/suspicious_unary_op_formatting.stderr @@ -0,0 +1,35 @@ +error: by not having a space between `>` and `-` it looks like `>-` is a single operator + --> $DIR/suspicious_unary_op_formatting.rs:8:9 + | +LL | if a >- 30 {} + | ^^^^ + | + = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` + = help: put a space between `>` and `-` and remove the space after `-` + +error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator + --> $DIR/suspicious_unary_op_formatting.rs:9:9 + | +LL | if a >=- 30 {} + | ^^^^^ + | + = help: put a space between `>=` and `-` and remove the space after `-` + +error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator + --> $DIR/suspicious_unary_op_formatting.rs:14:9 + | +LL | if b &&! c {} + | ^^^^^ + | + = help: put a space between `&&` and `!` and remove the space after `!` + +error: by not having a space between `>` and `-` it looks like `>-` is a single operator + --> $DIR/suspicious_unary_op_formatting.rs:16:9 + | +LL | if a >- 30 {} + | ^^^^^^ + | + = help: put a space between `>` and `-` and remove the space after `-` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From cc622608db7318b1c0fe3ccd541558436c7c6c4c Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Wed, 18 Sep 2019 08:37:41 +0200 Subject: new lints around `#[must_use]` fns `must_use_unit` lints unit-returning functions with a `#[must_use]` attribute, suggesting to remove it. `double_must_use` lints functions with a plain `#[must_use]` attribute, but which return a type which is already `#[must_use]`, so the attribute has no benefit. `must_use_candidate` is a pedantic lint that lints functions and methods that return some non-unit type that is not already `#[must_use]` and suggests to add the annotation. --- CHANGELOG.md | 3 + README.md | 2 +- clippy_dev/src/lib.rs | 7 + clippy_dev/src/stderr_length_check.rs | 1 + clippy_lints/src/approx_const.rs | 1 + clippy_lints/src/assign_ops.rs | 1 + clippy_lints/src/bit_mask.rs | 2 + clippy_lints/src/checked_conversions.rs | 1 + clippy_lints/src/cognitive_complexity.rs | 1 + clippy_lints/src/doc.rs | 1 + clippy_lints/src/enum_variants.rs | 4 + clippy_lints/src/excessive_precision.rs | 5 + clippy_lints/src/formatting.rs | 1 + clippy_lints/src/functions.rs | 412 +++++++++++++++++++++++++-- clippy_lints/src/infinite_iter.rs | 3 + clippy_lints/src/large_enum_variant.rs | 1 + clippy_lints/src/lib.rs | 7 +- clippy_lints/src/lifetimes.rs | 1 + clippy_lints/src/literal_representation.rs | 9 + clippy_lints/src/loops.rs | 4 + clippy_lints/src/map_unit_fn.rs | 1 + clippy_lints/src/methods/mod.rs | 2 + clippy_lints/src/misc_early.rs | 1 + clippy_lints/src/missing_const_for_fn.rs | 1 + clippy_lints/src/missing_doc.rs | 2 + clippy_lints/src/needless_continue.rs | 3 + clippy_lints/src/non_copy_const.rs | 1 + clippy_lints/src/non_expressive_names.rs | 3 + clippy_lints/src/precedence.rs | 2 + clippy_lints/src/ptr_offset_with_cast.rs | 1 + clippy_lints/src/regex.rs | 1 + clippy_lints/src/returns.rs | 1 + clippy_lints/src/types.rs | 5 + clippy_lints/src/unsafe_removed_from_name.rs | 1 + clippy_lints/src/utils/attrs.rs | 1 + clippy_lints/src/utils/author.rs | 3 + clippy_lints/src/utils/camel_case.rs | 2 + clippy_lints/src/utils/conf.rs | 2 + clippy_lints/src/utils/higher.rs | 1 + clippy_lints/src/utils/internal_lints.rs | 1 + clippy_lints/src/utils/mod.rs | 4 + clippy_lints/src/utils/sugg.rs | 1 + rustc_tools_util/src/lib.rs | 3 + src/lintlist/mod.rs | 23 +- tests/compile-test.rs | 4 + tests/ui/auxiliary/macro_rules.rs | 11 +- tests/ui/double_must_use.rs | 27 ++ tests/ui/double_must_use.stderr | 27 ++ tests/ui/functions.stderr | 8 +- tests/ui/methods.rs | 11 +- tests/ui/methods.stderr | 48 ++-- tests/ui/must_use_candidates.fixed | 88 ++++++ tests/ui/must_use_candidates.rs | 88 ++++++ tests/ui/must_use_candidates.stderr | 40 +++ tests/ui/must_use_unit.fixed | 26 ++ tests/ui/must_use_unit.rs | 26 ++ tests/ui/must_use_unit.stderr | 28 ++ tests/ui/shadow.rs | 1 + tests/ui/shadow.stderr | 46 +-- 59 files changed, 924 insertions(+), 88 deletions(-) create mode 100644 tests/ui/double_must_use.rs create mode 100644 tests/ui/double_must_use.stderr create mode 100644 tests/ui/must_use_candidates.fixed create mode 100644 tests/ui/must_use_candidates.rs create mode 100644 tests/ui/must_use_candidates.stderr create mode 100644 tests/ui/must_use_unit.fixed create mode 100644 tests/ui/must_use_unit.rs create mode 100644 tests/ui/must_use_unit.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 86088231109..dd67bc3cdc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -976,6 +976,7 @@ Released 2018-09-13 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens [`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds @@ -1095,6 +1096,8 @@ Released 2018-09-13 [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl +[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate +[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit [`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref [`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut [`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound diff --git a/README.md b/README.md index 0011fb9cd30..a84ab0e8c25 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 321 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 324 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 7df7109c75f..84b2814a7ce 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -42,6 +42,7 @@ pub struct Lint { } impl Lint { + #[must_use] pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self { Self { name: name.to_lowercase(), @@ -58,6 +59,7 @@ impl Lint { } /// Returns the lints in a `HashMap`, grouped by the different lint groups + #[must_use] pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> { lints .iter() @@ -65,12 +67,14 @@ impl Lint { .into_group_map() } + #[must_use] pub fn is_internal(&self) -> bool { self.group.starts_with("internal") } } /// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`. +#[must_use] pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> { lints .into_iter() @@ -86,6 +90,7 @@ pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> { } /// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`. +#[must_use] pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> { lints .into_iter() @@ -103,6 +108,7 @@ pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> { } /// Generates the list of lint links at the bottom of the README +#[must_use] pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> { let mut lint_list_sorted: Vec<Lint> = lints; lint_list_sorted.sort_by_key(|l| l.name.clone()); @@ -119,6 +125,7 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> { } /// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`. +#[must_use] pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> { lints .iter() diff --git a/clippy_dev/src/stderr_length_check.rs b/clippy_dev/src/stderr_length_check.rs index 3049c45ddc8..2d7d119f3ff 100644 --- a/clippy_dev/src/stderr_length_check.rs +++ b/clippy_dev/src/stderr_length_check.rs @@ -42,6 +42,7 @@ fn stderr_files() -> impl Iterator<Item = walkdir::DirEntry> { .filter(|f| f.path().extension() == Some(OsStr::new("stderr"))) } +#[must_use] fn count_linenumbers(filepath: &str) -> usize { if let Ok(mut file) = File::open(filepath) { let mut content = String::new(); diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 7578b5fffe1..04530542ef8 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -93,6 +93,7 @@ fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, mod /// Returns `false` if the number of significant figures in `value` are /// less than `min_digits`; otherwise, returns true if `value` is equal /// to `constant`, rounded to the number of digits present in `value`. +#[must_use] fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool { if value.len() <= min_digits { false diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index a16c4575e70..3d12bb347aa 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -229,6 +229,7 @@ fn lint_misrefactored_assign_op( ); } +#[must_use] fn is_commutative(op: hir::BinOpKind) -> bool { use rustc::hir::BinOpKind::*; match op { diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index e27b5269ef4..6d68c319f4c 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -100,6 +100,7 @@ pub struct BitMask { } impl BitMask { + #[must_use] pub fn new(verbose_bit_mask_threshold: u64) -> Self { Self { verbose_bit_mask_threshold, @@ -150,6 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask { } } +#[must_use] fn invert_cmp(cmp: BinOpKind) -> BinOpKind { match cmp { BinOpKind::Eq => BinOpKind::Eq, diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index d1d725678b7..dfd497f909b 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -160,6 +160,7 @@ impl<'a> Conversion<'a> { impl ConversionType { /// Creates a conversion type if the type is allowed & conversion is valid + #[must_use] fn try_new(from: &str, to: &str) -> Option<Self> { if UINTS.contains(&from) { Some(Self::FromUnsigned) diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index d869427467c..370421190cb 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -29,6 +29,7 @@ pub struct CognitiveComplexity { } impl CognitiveComplexity { + #[must_use] pub fn new(limit: u64) -> Self { Self { limit: LimitStack::new(limit), diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 0f95efe59f1..726a044f9ed 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -191,6 +191,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown { /// need to keep track of /// the spans but this function is inspired from the later. #[allow(clippy::cast_possible_truncation)] +#[must_use] pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) { // one-line comments lose their prefix const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index e64eed38340..b64e97fba5c 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -107,6 +107,7 @@ pub struct EnumVariantNames { } impl EnumVariantNames { + #[must_use] pub fn new(threshold: u64) -> Self { Self { modules: Vec::new(), @@ -123,6 +124,7 @@ impl_lint_pass!(EnumVariantNames => [ ]); /// Returns the number of chars that match from the start +#[must_use] fn partial_match(pre: &str, name: &str) -> usize { let mut name_iter = name.chars(); let _ = name_iter.next_back(); // make sure the name is never fully matched @@ -130,6 +132,7 @@ fn partial_match(pre: &str, name: &str) -> usize { } /// Returns the number of chars that match from the end +#[must_use] fn partial_rmatch(post: &str, name: &str) -> usize { let mut name_iter = name.chars(); let _ = name_iter.next(); // make sure the name is never fully matched @@ -211,6 +214,7 @@ fn check_variant( ); } +#[must_use] fn to_camel_case(item_name: &str) -> String { let mut s = String::new(); let mut up = true; diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index ae9681134ff..763770c74ef 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -62,6 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { impl ExcessivePrecision { // None if nothing to lint, Some(suggestion) if lint necessary + #[must_use] fn check(self, sym: Symbol, fty: FloatTy) -> Option<String> { let max = max_digits(fty); let sym_str = sym.as_str(); @@ -97,6 +98,7 @@ impl ExcessivePrecision { /// Should we exclude the float because it has a `.0` or `.` suffix /// Ex `1_000_000_000.0` /// Ex `1_000_000_000.` +#[must_use] fn dot_zero_exclusion(s: &str) -> bool { s.split('.').nth(1).map_or(false, |after_dec| { let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E'); @@ -109,6 +111,7 @@ fn dot_zero_exclusion(s: &str) -> bool { }) } +#[must_use] fn max_digits(fty: FloatTy) -> u32 { match fty { FloatTy::F32 => f32::DIGITS, @@ -117,6 +120,7 @@ fn max_digits(fty: FloatTy) -> u32 { } /// Counts the digits excluding leading zeros +#[must_use] fn count_digits(s: &str) -> usize { // Note that s does not contain the f32/64 suffix, and underscores have been stripped s.chars() @@ -138,6 +142,7 @@ enum FloatFormat { Normal, } impl FloatFormat { + #[must_use] fn new(s: &str) -> Self { s.chars() .find_map(|x| match x { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 821e79e8c77..62606257498 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -235,6 +235,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { } } +#[must_use] fn has_unary_equivalent(bin_op: BinOpKind) -> bool { // &, *, - bin_op == BinOpKind::And || bin_op == BinOpKind::Mul || bin_op == BinOpKind::Sub diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 7b6c8c7cea6..6052f936109 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,16 +1,17 @@ -use std::convert::TryFrom; - -use crate::utils::{iter_input_pats, qpath_res, snippet, snippet_opt, span_lint, type_is_unsafe_function}; +use crate::utils::{ + iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt, span_help_and_lint, span_lint, + span_lint_and_then, type_is_unsafe_function, +}; use matches::matches; -use rustc::hir; -use rustc::hir::def::Res; -use rustc::hir::intravisit; +use rustc::hir::{self, def::Res, def_id::DefId, intravisit}; use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass}; -use rustc::ty; +use rustc::ty::{self, Ty}; use rustc::{declare_tool_lint, impl_lint_pass}; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_target::spec::abi::Abi; -use syntax::source_map::{BytePos, Span}; +use syntax::ast::Attribute; +use syntax::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for functions with too many parameters. @@ -84,6 +85,80 @@ declare_clippy_lint! { "public functions dereferencing raw pointer arguments but not marked `unsafe`" } +declare_clippy_lint! { + /// **What it does:** Checks for a [`#[must_use]`] attribute on + /// unit-returning functions and methods. + /// + /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// + /// **Why is this bad?** Unit values are useless. The attribute is likely + /// a remnant of a refactoring that removed the return type. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// ```rust + /// #[must_use] + /// fn useless() { } + /// ``` + pub MUST_USE_UNIT, + style, + "`#[must_use]` attribute on a unit-returning function / method" +} + +declare_clippy_lint! { + /// **What it does:** Checks for a [`#[must_use]`] attribute without + /// further information on functions and methods that return a type already + /// marked as `#[must_use]`. + /// + /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// + /// **Why is this bad?** The attribute isn't needed. Not using the result + /// will already be reported. Alternatively, one can add some text to the + /// attribute to improve the lint message. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// ```rust + /// #[must_use] + /// fn double_must_use() -> Result<(), ()> { + /// unimplemented!(); + /// } + /// ``` + pub DOUBLE_MUST_USE, + style, + "`#[must_use]` attribute on a `#[must_use]`-returning function / method" +} + +declare_clippy_lint! { + /// **What it does:** Checks for public functions that have no + /// [`#[must_use]`] attribute, but return something not already marked + /// must-use, have no mutable arg and mutate no statics. + /// + /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// + /// **Why is this bad?** Not bad at all, this lint just shows places where + /// you could add the attribute. + /// + /// **Known problems:** The lint only checks the arguments for mutable + /// types without looking if they are actually changed. On the other hand, + /// it also ignores a broad range of potentially interesting side effects, + /// because we cannot decide whether the programmer intends the function to + /// be called for the side effect or the result. Expect many false + /// positives. At least we don't lint if the result type is unit or already + /// `#[must_use]`. + /// + /// **Examples:** + /// ```rust + /// // this could be annotated with `#[must_use]`. + /// fn id<T>(t: T) -> T { t } + /// ``` + pub MUST_USE_CANDIDATE, + pedantic, + "function or method that could take a `#[must_use]` attribute" +} + #[derive(Copy, Clone)] pub struct Functions { threshold: u64, @@ -96,7 +171,14 @@ impl Functions { } } -impl_lint_pass!(Functions => [TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF]); +impl_lint_pass!(Functions => [ + TOO_MANY_ARGUMENTS, + TOO_MANY_LINES, + NOT_UNSAFE_PTR_ARG_DEREF, + MUST_USE_UNIT, + DOUBLE_MUST_USE, + MUST_USE_CANDIDATE, +]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { fn check_fn( @@ -134,7 +216,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { _, ) | hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => { - self.check_arg_number(cx, decl, span) + self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi())) }, _ => {}, } @@ -144,42 +226,88 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { self.check_line_number(cx, span, body); } + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + let attr = must_use_attr(&item.attrs); + if let hir::ItemKind::Fn(ref decl, ref _header, ref _generics, ref body_id) = item.kind { + if let Some(attr) = attr { + let fn_header_span = item.span.with_hi(decl.output.span().hi()); + check_needless_must_use(cx, decl, item.hir_id, item.span, fn_header_span, attr); + return; + } + if cx.access_levels.is_exported(item.hir_id) { + check_must_use_candidate( + cx, + decl, + cx.tcx.hir().body(*body_id), + item.span, + item.hir_id, + item.span.with_hi(decl.output.span().hi()), + "this function could have a `#[must_use]` attribute", + ); + } + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) { + if let hir::ImplItemKind::Method(ref sig, ref body_id) = item.kind { + let attr = must_use_attr(&item.attrs); + if let Some(attr) = attr { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); + } else if cx.access_levels.is_exported(item.hir_id) { + check_must_use_candidate( + cx, + &sig.decl, + cx.tcx.hir().body(*body_id), + item.span, + item.hir_id, + item.span.with_hi(sig.decl.output.span().hi()), + "this method could have a `#[must_use]` attribute", + ); + } + } + } + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { if let hir::TraitItemKind::Method(ref sig, ref eid) = item.kind { // don't lint extern functions decls, it's not their fault if sig.header.abi == Abi::Rust { - self.check_arg_number(cx, &sig.decl, item.span); + self.check_arg_number(cx, &sig.decl, item.span.with_hi(sig.decl.output.span().hi())); } + let attr = must_use_attr(&item.attrs); + if let Some(attr) = attr { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); + } if let hir::TraitMethod::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id); + + if attr.is_none() && cx.access_levels.is_exported(item.hir_id) { + check_must_use_candidate( + cx, + &sig.decl, + body, + item.span, + item.hir_id, + item.span.with_hi(sig.decl.output.span().hi()), + "this method could have a `#[must_use]` attribute", + ); + } } } } } impl<'a, 'tcx> Functions { - fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) { - // Remove the function body from the span. We can't use `SourceMap::def_span` because the - // argument list might span multiple lines. - let span = if let Some(snippet) = snippet_opt(cx, span) { - let snippet = snippet.split('{').nth(0).unwrap_or("").trim_end(); - if snippet.is_empty() { - span - } else { - span.with_hi(BytePos(span.lo().0 + u32::try_from(snippet.len()).unwrap())) - } - } else { - span - }; - + fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, fn_span: Span) { let args = decl.inputs.len() as u64; if args > self.threshold { span_lint( cx, TOO_MANY_ARGUMENTS, - span, + fn_span, &format!("this function has too many arguments ({}/{})", args, self.threshold), ); } @@ -268,6 +396,164 @@ impl<'a, 'tcx> Functions { } } +fn check_needless_must_use( + cx: &LateContext<'_, '_>, + decl: &hir::FnDecl, + item_id: hir::HirId, + item_span: Span, + fn_header_span: Span, + attr: &Attribute, +) { + if in_external_macro(cx.sess(), item_span) { + return; + } + if returns_unit(decl) { + span_lint_and_then( + cx, + MUST_USE_UNIT, + fn_header_span, + "this unit-returning function has a `#[must_use]` attribute", + |db| { + db.span_suggestion( + attr.span, + "remove the attribute", + "".into(), + Applicability::MachineApplicable, + ); + }, + ); + } else if !attr.is_value_str() && is_must_use_ty(cx, return_ty(cx, item_id)) { + span_help_and_lint( + cx, + DOUBLE_MUST_USE, + fn_header_span, + "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`", + "either add some descriptive text or remove the attribute", + ); + } +} + +fn check_must_use_candidate<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Body, + item_span: Span, + item_id: hir::HirId, + fn_span: Span, + msg: &str, +) { + if has_mutable_arg(cx, body) + || mutates_static(cx, body) + || in_external_macro(cx.sess(), item_span) + || returns_unit(decl) + || is_must_use_ty(cx, return_ty(cx, item_id)) + { + return; + } + span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |db| { + if let Some(snippet) = snippet_opt(cx, fn_span) { + db.span_suggestion( + fn_span, + "add the attribute", + format!("#[must_use] {}", snippet), + Applicability::MachineApplicable, + ); + } + }); +} + +fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { + attrs + .iter() + .find(|attr| attr.ident().map_or(false, |ident| "must_use" == &ident.as_str())) +} + +fn returns_unit(decl: &hir::FnDecl) -> bool { + match decl.output { + hir::FunctionRetTy::DefaultReturn(_) => true, + hir::FunctionRetTy::Return(ref ty) => match ty.kind { + hir::TyKind::Tup(ref tys) => tys.is_empty(), + hir::TyKind::Never => true, + _ => false, + }, + } +} + +fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { + use ty::TyKind::*; + match ty.kind { + Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), + Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), + Slice(ref ty) | Array(ref ty, _) | RawPtr(ty::TypeAndMut { ref ty, .. }) | Ref(_, ref ty, _) => { + // for the Array case we don't need to care for the len == 0 case + // because we don't want to lint functions returning empty arrays + is_must_use_ty(cx, *ty) + }, + Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), + Opaque(ref def_id, _) => { + for (predicate, _) in &cx.tcx.predicates_of(*def_id).predicates { + if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate { + if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + Dynamic(binder, _) => { + for predicate in binder.skip_binder().iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { + return true; + } + } + } + false + }, + _ => false, + } +} + +fn has_mutable_arg(cx: &LateContext<'_, '_>, body: &hir::Body) -> bool { + let mut tys = FxHashSet::default(); + body.params.iter().any(|param| is_mutable_pat(cx, ¶m.pat, &mut tys)) +} + +fn is_mutable_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, tys: &mut FxHashSet<DefId>) -> bool { + if let hir::PatKind::Wild = pat.kind { + return false; // ignore `_` patterns + } + let def_id = pat.hir_id.owner_def_id(); + if cx.tcx.has_typeck_tables(def_id) { + is_mutable_ty(cx, &cx.tcx.typeck_tables_of(def_id).pat_ty(pat), pat.span, tys) + } else { + false + } +} + +static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]]; + +fn is_mutable_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet<DefId>) -> bool { + use ty::TyKind::*; + match ty.kind { + // primitive types are never mutable + Bool | Char | Int(_) | Uint(_) | Float(_) | Str => false, + Adt(ref adt, ref substs) => { + tys.insert(adt.did) && !ty.is_freeze(cx.tcx, cx.param_env, span) + || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path)) + && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)) + }, + Tuple(ref substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)), + Array(ty, _) | Slice(ty) => is_mutable_ty(cx, ty, span, tys), + RawPtr(ty::TypeAndMut { ty, mutbl }) | Ref(_, ty, mutbl) => { + mutbl == hir::Mutability::MutMutable || is_mutable_ty(cx, ty, span, tys) + }, + // calling something constitutes a side effect, so return true on all callables + // also never calls need not be used, so return true for them, too + _ => true, + } +} + fn raw_ptr_arg(arg: &hir::Param, ty: &hir::Ty) -> Option<hir::HirId> { if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) { Some(id) @@ -282,7 +568,7 @@ struct DerefVisitor<'a, 'tcx> { tables: &'a ty::TypeckTables<'tcx>, } -impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { +impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.kind { hir::ExprKind::Call(ref f, ref args) => { @@ -308,8 +594,9 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { _ => (), } - hir::intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr); } + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { intravisit::NestedVisitorMap::None } @@ -331,3 +618,72 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { } } } + +struct StaticMutVisitor<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + mutates_static: bool, +} + +impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + use hir::ExprKind::*; + + if self.mutates_static { + return; + } + match expr.kind { + Call(_, ref args) | MethodCall(_, _, ref args) => { + let mut tys = FxHashSet::default(); + for arg in args { + let def_id = arg.hir_id.owner_def_id(); + if self.cx.tcx.has_typeck_tables(def_id) + && is_mutable_ty( + self.cx, + self.cx.tcx.typeck_tables_of(def_id).expr_ty(arg), + arg.span, + &mut tys, + ) + && is_mutated_static(self.cx, arg) + { + self.mutates_static = true; + return; + } + tys.clear(); + } + }, + Assign(ref target, _) | AssignOp(_, ref target, _) | AddrOf(hir::Mutability::MutMutable, ref target) => { + self.mutates_static |= is_mutated_static(self.cx, target) + }, + _ => {}, + } + } + + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::None + } +} + +fn is_mutated_static(cx: &LateContext<'_, '_>, e: &hir::Expr) -> bool { + use hir::ExprKind::*; + + match e.kind { + Path(ref qpath) => { + if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) { + false + } else { + true + } + }, + Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), + _ => false, + } +} + +fn mutates_static<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, body: &'tcx hir::Body) -> bool { + let mut v = StaticMutVisitor { + cx, + mutates_static: false, + }; + intravisit::walk_expr(&mut v, &body.value); + v.mutates_static +} diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index adda6ae0c11..e6af8e8c7fc 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -67,6 +67,7 @@ enum Finiteness { use self::Finiteness::{Finite, Infinite, MaybeInfinite}; impl Finiteness { + #[must_use] fn and(self, b: Self) -> Self { match (self, b) { (Finite, _) | (_, Finite) => Finite, @@ -75,6 +76,7 @@ impl Finiteness { } } + #[must_use] fn or(self, b: Self) -> Self { match (self, b) { (Infinite, _) | (_, Infinite) => Infinite, @@ -85,6 +87,7 @@ impl Finiteness { } impl From<bool> for Finiteness { + #[must_use] fn from(b: bool) -> Self { if b { Infinite diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index d5c1318f677..d612a4326fe 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -35,6 +35,7 @@ pub struct LargeEnumVariant { } impl LargeEnumVariant { + #[must_use] pub fn new(maximum_size_difference_allowed: u64) -> Self { Self { maximum_size_difference_allowed, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ec12e06b1aa..5d428221e69 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -6,7 +6,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(stmt_expr_attributes)] -#![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)] #![recursion_limit = "512"] #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![deny(rustc::internal)] @@ -648,6 +648,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con enum_variants::MODULE_NAME_REPETITIONS, enum_variants::PUB_ENUM_VARIANT_NAMES, eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + functions::MUST_USE_CANDIDATE, functions::TOO_MANY_LINES, if_not_else::IF_NOT_ELSE, infinite_iter::MAYBE_INFINITE_ITER, @@ -744,6 +745,8 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + functions::DOUBLE_MUST_USE, + functions::MUST_USE_UNIT, functions::NOT_UNSAFE_PTR_ARG_DEREF, functions::TOO_MANY_ARGUMENTS, get_last_with_len::GET_LAST_WITH_LEN, @@ -955,6 +958,8 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + functions::DOUBLE_MUST_USE, + functions::MUST_USE_UNIT, infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, inherent_to_string::INHERENT_TO_STRING, len_zero::LEN_WITHOUT_IS_EMPTY, diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 88d393c84ee..be1e65fc17c 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -270,6 +270,7 @@ fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bo } /// Number of unique lifetimes in the given vector. +#[must_use] fn unique_lifetimes(lts: &[RefLt]) -> usize { lts.iter().collect::<FxHashSet<_>>().len() } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 5cdbfe1099c..4b2bb69fa79 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -113,6 +113,7 @@ pub(super) enum Radix { impl Radix { /// Returns a reasonable digit group size for this radix. + #[must_use] crate fn suggest_grouping(&self) -> usize { match *self { Self::Binary | Self::Hexadecimal => 4, @@ -136,6 +137,7 @@ pub(super) struct DigitInfo<'a> { } impl<'a> DigitInfo<'a> { + #[must_use] crate fn new(lit: &'a str, float: bool) -> Self { // Determine delimiter for radix prefix, if present, and radix. let radix = if lit.starts_with("0x") { @@ -422,6 +424,7 @@ impl LiteralDigitGrouping { /// Given the sizes of the digit groups of both integral and fractional /// parts, and the length /// of both parts, determine if the digits have been grouped consistently. + #[must_use] fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usize, frac_size: usize) -> bool { match (int_group_size, frac_group_size) { // No groups on either side of decimal point - trivially consistent. @@ -499,6 +502,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } impl DecimalLiteralRepresentation { + #[must_use] pub fn new(threshold: u64) -> Self { Self { threshold } } @@ -573,22 +577,27 @@ impl DecimalLiteralRepresentation { } } +#[must_use] fn is_mistyped_suffix(suffix: &str) -> bool { ["_8", "_16", "_32", "_64"].contains(&suffix) } +#[must_use] fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool { ((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1) } +#[must_use] fn is_mistyped_float_suffix(suffix: &str) -> bool { ["_32", "_64"].contains(&suffix) } +#[must_use] fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool { (len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1) } +#[must_use] fn has_possible_float_suffix(lit: &str) -> bool { lit.ends_with("_32") || lit.ends_with("_64") } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index ea496a0294a..22821e02fe2 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -610,6 +610,7 @@ enum NeverLoopResult { Otherwise, } +#[must_use] fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { match *arg { NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise, @@ -618,6 +619,7 @@ fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { } // Combine two results for parts that are called in order. +#[must_use] fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult { match first { NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first, @@ -626,6 +628,7 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu } // Combine two results where both parts are called but not necessarily in order. +#[must_use] fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult { match (left, right) { (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => { @@ -637,6 +640,7 @@ fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResul } // Combine two results where only one of the part may have been executed. +#[must_use] fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult { match (b1, b2) { (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak, diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 70f324a5081..8b2bcce471c 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -195,6 +195,7 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String { } } +#[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { format!( "called `map(f)` on an {0} value where `f` is a unit {1}", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 198f97e1f56..848e3bcb881 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2898,6 +2898,7 @@ impl SelfKind { } } + #[must_use] fn description(self) -> &'static str { match self { Self::Value => "self by value", @@ -2909,6 +2910,7 @@ impl SelfKind { } impl Convention { + #[must_use] fn check(&self, other: &str) -> bool { match *self { Self::Eq(this) => this == other, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 43a5e5c1b4b..c06eec95028 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -253,6 +253,7 @@ struct ReturnVisitor { } impl ReturnVisitor { + #[must_use] fn new() -> Self { Self { found_return: false } } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 2f20aa9c683..d97e3ed8806 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -128,6 +128,7 @@ fn method_accepts_dropable(cx: &LateContext<'_, '_>, param_tys: &HirVec<hir::Ty> } // We don't have to lint on something that's already `const` +#[must_use] fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index f09a864240b..949bd4bce27 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -37,12 +37,14 @@ pub struct MissingDoc { } impl ::std::default::Default for MissingDoc { + #[must_use] fn default() -> Self { Self::new() } } impl MissingDoc { + #[must_use] pub fn new() -> Self { Self { doc_hidden_stack: vec![false], diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index bd9d1583493..8fa30f6827c 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -405,6 +405,7 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) { /// /// NOTE: when there is no closing brace in `s`, `s` is _not_ preserved, i.e., /// an empty string will be returned in that case. +#[must_use] pub fn erode_from_back(s: &str) -> String { let mut ret = String::from(s); while ret.pop().map_or(false, |c| c != '}') {} @@ -435,6 +436,7 @@ pub fn erode_from_back(s: &str) -> String { /// inside_a_block(); /// } /// ``` +#[must_use] pub fn erode_from_front(s: &str) -> String { s.chars() .skip_while(|c| c.is_whitespace()) @@ -447,6 +449,7 @@ pub fn erode_from_front(s: &str) -> String { /// tries to get the contents of the block. If there is no closing brace /// present, /// an empty string is returned. +#[must_use] pub fn erode_block(s: &str) -> String { erode_from_back(&erode_from_front(s)) } diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 33f1dde9872..9cddd812b52 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -92,6 +92,7 @@ enum Source { } impl Source { + #[must_use] fn lint(&self) -> (&'static Lint, &'static str, Span) { match self { Self::Item { item } | Self::Assoc { item, .. } => ( diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 25e8efe3cad..08a78b784ba 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -148,6 +148,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { } } +#[must_use] fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { for &allow in WHITELIST { if whitelisted(interned_name, allow) { @@ -157,6 +158,7 @@ fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> { None } +#[must_use] fn whitelisted(interned_name: &str, list: &[&str]) -> bool { list.iter() .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name)) @@ -383,6 +385,7 @@ fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attri } /// Precondition: `a_name.chars().count() < b_name.chars().count()`. +#[must_use] fn levenstein_not_1(a_name: &str, b_name: &str) -> bool { debug_assert!(a_name.chars().count() < b_name.chars().count()); let mut a_chars = a_name.chars(); diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index b00062cd55a..a2d054c1de4 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -121,6 +121,7 @@ fn is_arith_expr(expr: &Expr) -> bool { } } +#[must_use] fn is_bit_op(op: BinOpKind) -> bool { use syntax::ast::BinOpKind::*; match op { @@ -129,6 +130,7 @@ fn is_bit_op(op: BinOpKind) -> bool { } } +#[must_use] fn is_arith_op(op: BinOpKind) -> bool { use syntax::ast::BinOpKind::*; match op { diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index d2e48e1d798..5c509158128 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -131,6 +131,7 @@ enum Method { } impl Method { + #[must_use] fn suggestion(self) -> &'static str { match self { Self::Offset => "add", diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 22c4b107f00..54220f1107b 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -129,6 +129,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex { } #[allow(clippy::cast_possible_truncation)] // truncation very unlikely here +#[must_use] fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span { let offset = u32::from(offset); let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 47fdc226e99..a5323501207 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -318,6 +318,7 @@ fn attr_is_cfg(attr: &ast::Attribute) -> bool { } // get the def site +#[must_use] fn get_def(span: Span) -> Option<Span> { if span.from_expansion() { Some(span.ctxt().outer_expn_data().def_site) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 7230c0c08f2..be8165d51f5 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1372,6 +1372,7 @@ pub struct TypeComplexity { } impl TypeComplexity { + #[must_use] pub fn new(threshold: u64) -> Self { Self { threshold } } @@ -1780,6 +1781,7 @@ enum FullInt { impl FullInt { #[allow(clippy::cast_sign_loss)] + #[must_use] fn cmp_s_u(s: i128, u: u128) -> Ordering { if s < 0 { Ordering::Less @@ -1792,12 +1794,14 @@ impl FullInt { } impl PartialEq for FullInt { + #[must_use] fn eq(&self, other: &Self) -> bool { self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal } } impl PartialOrd for FullInt { + #[must_use] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(match (self, other) { (&Self::S(s), &Self::S(o)) => s.cmp(&o), @@ -1808,6 +1812,7 @@ impl PartialOrd for FullInt { } } impl Ord for FullInt { + #[must_use] fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other) .expect("partial_cmp for FullInt can never return None") diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 29c8015edcf..528a1915be8 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -72,6 +72,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, } } +#[must_use] fn contains_unsafe(name: &LocalInternedString) -> bool { name.contains("Unsafe") || name.contains("unsafe") } diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index bec8d53714e..11340f69aa2 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -34,6 +34,7 @@ impl Drop for LimitStack { } impl LimitStack { + #[must_use] pub fn new(limit: u64) -> Self { Self { stack: vec![limit] } } diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index f36570904c0..a424c09ef40 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -146,6 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Author { } impl PrintVisitor { + #[must_use] fn new(s: &'static str) -> Self { Self { ids: FxHashMap::default(), @@ -683,6 +684,7 @@ fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool { get_attr(sess, attrs, "author").count() > 0 } +#[must_use] fn desugaring_name(des: hir::MatchSource) -> String { match des { hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(), @@ -702,6 +704,7 @@ fn desugaring_name(des: hir::MatchSource) -> String { } } +#[must_use] fn loop_desugaring_name(des: hir::LoopSource) -> &'static str { match des { hir::LoopSource::ForLoop => "LoopSource::ForLoop", diff --git a/clippy_lints/src/utils/camel_case.rs b/clippy_lints/src/utils/camel_case.rs index 5b124dd96bf..4192a26d3c8 100644 --- a/clippy_lints/src/utils/camel_case.rs +++ b/clippy_lints/src/utils/camel_case.rs @@ -1,4 +1,5 @@ /// Returns the index of the character after the first camel-case component of `s`. +#[must_use] pub fn until(s: &str) -> usize { let mut iter = s.char_indices(); if let Some((_, first)) = iter.next() { @@ -32,6 +33,7 @@ pub fn until(s: &str) -> usize { } /// Returns index of the last camel-case component of `s`. +#[must_use] pub fn from(s: &str) -> usize { let mut iter = s.char_indices().rev(); if let Some((_, first)) = iter.next() { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 4595819f557..734b689ab1a 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -90,6 +90,7 @@ macro_rules! define_Conf { } } + #[must_use] fn $rust_name() -> define_Conf!(TY $($ty)+) { define_Conf!(DEFAULT $($ty)+, $default) } @@ -153,6 +154,7 @@ define_Conf! { } impl Default for Conf { + #[must_use] fn default() -> Self { toml::from_str("").expect("we never error on empty config files") } diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index de974eb3d27..63e9a27c545 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -10,6 +10,7 @@ use rustc::{hir, ty}; use syntax::ast; /// Converts a hir binary operator to the corresponding `ast` type. +#[must_use] pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind { match op { hir::BinOpKind::Eq => ast::BinOpKind::Eq, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 1ec89cb93f1..96b00eb154a 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -239,6 +239,7 @@ pub struct CompilerLintFunctions { } impl CompilerLintFunctions { + #[must_use] pub fn new() -> Self { let mut map = FxHashMap::default(); map.insert("span_lint", "utils::span_lint"); diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 88553bf1d76..a5e2f3dc4b4 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -52,6 +52,7 @@ use crate::reexport::*; /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). +#[must_use] pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { rhs.ctxt() != lhs.ctxt() } @@ -98,6 +99,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { } /// Returns `true` if this `span` was expanded by any macro. +#[must_use] pub fn in_macro(span: Span) -> bool { if span.from_expansion() { if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind { @@ -721,6 +723,7 @@ pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool { /// Returns the pre-expansion span if is this comes from an expansion of the /// macro `name`. /// See also `is_direct_expn_of`. +#[must_use] pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { loop { if span.from_expansion() { @@ -748,6 +751,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only /// `bar!` by /// `is_direct_expn_of`. +#[must_use] pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { if span.from_expansion() { let data = span.ctxt().outer_expn_data(); diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 3c31067f7f8..0675c603341 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -417,6 +417,7 @@ enum Associativity { /// Chained `as` and explicit `:` type coercion never need inner parenthesis so /// they are considered /// associative. +#[must_use] fn associativity(op: &AssocOp) -> Associativity { use syntax::util::parser::AssocOp::*; diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 92b710614ec..36b58a398dc 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -79,6 +79,7 @@ impl std::fmt::Debug for VersionInfo { } } +#[must_use] pub fn get_commit_hash() -> Option<String> { std::process::Command::new("git") .args(&["rev-parse", "--short", "HEAD"]) @@ -87,6 +88,7 @@ pub fn get_commit_hash() -> Option<String> { .and_then(|r| String::from_utf8(r.stdout).ok()) } +#[must_use] pub fn get_commit_date() -> Option<String> { std::process::Command::new("git") .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) @@ -95,6 +97,7 @@ pub fn get_commit_date() -> Option<String> { .and_then(|r| String::from_utf8(r.stdout).ok()) } +#[must_use] pub fn get_channel() -> Option<String> { match env::var("CFG_RELEASE_CHANNEL") { Ok(channel) => Some(channel), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 28f212fb2b2..66ee41402ea 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 321] = [ +pub const ALL_LINTS: [Lint; 324] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -350,6 +350,13 @@ pub const ALL_LINTS: [Lint; 321] = [ deprecation: None, module: "double_comparison", }, + Lint { + name: "double_must_use", + group: "style", + desc: "`#[must_use]` attribute on a `#[must_use]`-returning function / method", + deprecation: None, + module: "functions", + }, Lint { name: "double_neg", group: "style", @@ -1155,6 +1162,20 @@ pub const ALL_LINTS: [Lint; 321] = [ deprecation: None, module: "inherent_impl", }, + Lint { + name: "must_use_candidate", + group: "pedantic", + desc: "function or method that could take a `#[must_use]` attribute", + deprecation: None, + module: "functions", + }, + Lint { + name: "must_use_unit", + group: "style", + desc: "`#[must_use]` attribute on a unit-returning function / method", + deprecation: None, + module: "functions", + }, Lint { name: "mut_from_ref", group: "correctness", diff --git a/tests/compile-test.rs b/tests/compile-test.rs index e65a4a9a40a..b5cd2860e81 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -9,6 +9,7 @@ use std::fs; use std::io; use std::path::{Path, PathBuf}; +#[must_use] fn clippy_driver_path() -> PathBuf { if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { PathBuf::from(path) @@ -17,6 +18,7 @@ fn clippy_driver_path() -> PathBuf { } } +#[must_use] fn host_libs() -> PathBuf { if let Some(path) = option_env!("HOST_LIBS") { PathBuf::from(path) @@ -25,10 +27,12 @@ fn host_libs() -> PathBuf { } } +#[must_use] fn rustc_test_suite() -> Option<PathBuf> { option_env!("RUSTC_TEST_SUITE").map(PathBuf::from) } +#[must_use] fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 486e419bee5..b717afd0b27 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -1,9 +1,18 @@ #![allow(dead_code)] -/// Used to test that certain lints don't trigger in imported external macros +//! Used to test that certain lints don't trigger in imported external macros + #[macro_export] macro_rules! foofoo { () => { loop {} }; } + +#[macro_export] +macro_rules! must_use_unit { + () => { + #[must_use] + fn foo() {} + }; +} diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs new file mode 100644 index 00000000000..a48e675e4ea --- /dev/null +++ b/tests/ui/double_must_use.rs @@ -0,0 +1,27 @@ +#![warn(clippy::double_must_use)] + +#[must_use] +pub fn must_use_result() -> Result<(), ()> { + unimplemented!(); +} + +#[must_use] +pub fn must_use_tuple() -> (Result<(), ()>, u8) { + unimplemented!(); +} + +#[must_use] +pub fn must_use_array() -> [Result<(), ()>; 1] { + unimplemented!(); +} + +#[must_use = "With note"] +pub fn must_use_with_note() -> Result<(), ()> { + unimplemented!(); +} + +fn main() { + must_use_result(); + must_use_tuple(); + must_use_with_note(); +} diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr new file mode 100644 index 00000000000..bc37785294f --- /dev/null +++ b/tests/ui/double_must_use.stderr @@ -0,0 +1,27 @@ +error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` + --> $DIR/double_must_use.rs:4:1 + | +LL | pub fn must_use_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::double-must-use` implied by `-D warnings` + = help: either add some descriptive text or remove the attribute + +error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` + --> $DIR/double_must_use.rs:9:1 + | +LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive text or remove the attribute + +error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` + --> $DIR/double_must_use.rs:14:1 + | +LL | pub fn must_use_array() -> [Result<(), ()>; 1] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive text or remove the attribute + +error: aborting due to 3 previous errors + diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index 10d72fb96b1..0a86568b18d 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -2,7 +2,7 @@ error: this function has too many arguments (8/7) --> $DIR/functions.rs:8:1 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-arguments` implied by `-D warnings` @@ -16,19 +16,19 @@ LL | | three: &str, ... | LL | | eight: () LL | | ) { - | |_^ + | |__^ error: this function has too many arguments (8/7) --> $DIR/functions.rs:45:5 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) --> $DIR/functions.rs:54:5 | LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function dereferences a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:63:34 diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 8f53b8cecbd..e5a6cba9a25 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -4,16 +4,17 @@ #![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)] #![allow( clippy::blacklisted_name, - unused, - clippy::print_stdout, + clippy::default_trait_access, + clippy::missing_docs_in_private_items, clippy::non_ascii_literal, clippy::new_without_default, - clippy::missing_docs_in_private_items, clippy::needless_pass_by_value, - clippy::default_trait_access, + clippy::print_stdout, + clippy::must_use_candidate, clippy::use_self, clippy::useless_format, - clippy::wrong_self_convention + clippy::wrong_self_convention, + unused )] #[macro_use] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index b30371fa541..28da35bff3e 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:36:5 + --> $DIR/methods.rs:37:5 | LL | / pub fn add(self, other: T) -> T { LL | | self @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: methods called `new` usually return `Self` - --> $DIR/methods.rs:152:5 + --> $DIR/methods.rs:153:5 | LL | / fn new() -> i32 { LL | | 0 @@ -19,7 +19,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:174:13 + --> $DIR/methods.rs:175:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -31,7 +31,7 @@ LL | | .unwrap_or(0); = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:178:13 + --> $DIR/methods.rs:179:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -41,7 +41,7 @@ LL | | ).unwrap_or(0); | |____________________________^ error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:182:13 + --> $DIR/methods.rs:183:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -51,7 +51,7 @@ LL | | }); | |__________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:187:13 + --> $DIR/methods.rs:188:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:189:13 + --> $DIR/methods.rs:190:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -69,7 +69,7 @@ LL | | ).unwrap_or(None); | |_____________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:193:13 + --> $DIR/methods.rs:194:13 | LL | let _ = opt | _____________^ @@ -80,7 +80,7 @@ LL | | .unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:204:13 + --> $DIR/methods.rs:205:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); = note: replace `map(|p| format!("{}.", p)).unwrap_or(id)` with `map_or(id, |p| format!("{}.", p))` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:208:13 + --> $DIR/methods.rs:209:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -100,7 +100,7 @@ LL | | .unwrap_or_else(|| 0); = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:212:13 + --> $DIR/methods.rs:213:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -110,7 +110,7 @@ LL | | ).unwrap_or_else(|| 0); | |____________________________________^ error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:216:13 + --> $DIR/methods.rs:217:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -120,7 +120,7 @@ LL | | ); | |_________________^ error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:246:13 + --> $DIR/methods.rs:247:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:249:13 + --> $DIR/methods.rs:250:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -139,7 +139,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:266:22 + --> $DIR/methods.rs:267:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -147,25 +147,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:267:20 + --> $DIR/methods.rs:268:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:268:20 + --> $DIR/methods.rs:269:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:269:22 + --> $DIR/methods.rs:270:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:272:13 + --> $DIR/methods.rs:273:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -175,13 +175,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:278:22 + --> $DIR/methods.rs:279:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:281:13 + --> $DIR/methods.rs:282:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -191,13 +191,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:287:22 + --> $DIR/methods.rs:288:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:290:13 + --> $DIR/methods.rs:291:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -207,7 +207,7 @@ LL | | ).is_some(); | |______________________________^ error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message - --> $DIR/methods.rs:305:13 + --> $DIR/methods.rs:306:13 | LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed new file mode 100644 index 00000000000..dded5321af8 --- /dev/null +++ b/tests/ui/must_use_candidates.fixed @@ -0,0 +1,88 @@ +// run-rustfix +#![feature(never_type)] +#![allow(unused_mut)] +#![warn(clippy::must_use_candidate)] +use std::rc::Rc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +pub struct MyAtomic(AtomicBool); +pub struct MyPure; + +#[must_use] pub fn pure(i: u8) -> u8 { + i +} + +impl MyPure { + #[must_use] pub fn inherent_pure(&self) -> u8 { + 0 + } +} + +pub trait MyPureTrait { + fn trait_pure(&self, i: u32) -> u32 { + self.trait_impl_pure(i) + 1 + } + + fn trait_impl_pure(&self, i: u32) -> u32; +} + +impl MyPureTrait for MyPure { + #[must_use] fn trait_impl_pure(&self, i: u32) -> u32 { + i + } +} + +pub fn without_result() { + // OK +} + +pub fn impure_primitive(i: &mut u8) -> u8 { + *i +} + +pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool { + f(0) +} + +#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + true +} + +pub fn quoth_the_raven(_more: !) -> u32 { + unimplemented!(); +} + +pub fn atomics(b: &AtomicBool) -> bool { + b.load(Ordering::SeqCst) +} + +#[must_use] pub fn rcd(_x: Rc<u32>) -> bool { + true +} + +pub fn rcmut(_x: Rc<&mut u32>) -> bool { + true +} + +#[must_use] pub fn arcd(_x: Arc<u32>) -> bool { + false +} + +pub fn inner_types(_m: &MyAtomic) -> bool { + true +} + +static mut COUNTER: usize = 0; + +/// # Safety +/// +/// Don't ever call this from multiple threads +pub unsafe fn mutates_static() -> usize { + COUNTER += 1; + COUNTER +} + +fn main() { + assert_eq!(1, pure(1)); +} diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs new file mode 100644 index 00000000000..29c0752994a --- /dev/null +++ b/tests/ui/must_use_candidates.rs @@ -0,0 +1,88 @@ +// run-rustfix +#![feature(never_type)] +#![allow(unused_mut)] +#![warn(clippy::must_use_candidate)] +use std::rc::Rc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +pub struct MyAtomic(AtomicBool); +pub struct MyPure; + +pub fn pure(i: u8) -> u8 { + i +} + +impl MyPure { + pub fn inherent_pure(&self) -> u8 { + 0 + } +} + +pub trait MyPureTrait { + fn trait_pure(&self, i: u32) -> u32 { + self.trait_impl_pure(i) + 1 + } + + fn trait_impl_pure(&self, i: u32) -> u32; +} + +impl MyPureTrait for MyPure { + fn trait_impl_pure(&self, i: u32) -> u32 { + i + } +} + +pub fn without_result() { + // OK +} + +pub fn impure_primitive(i: &mut u8) -> u8 { + *i +} + +pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool { + f(0) +} + +pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + true +} + +pub fn quoth_the_raven(_more: !) -> u32 { + unimplemented!(); +} + +pub fn atomics(b: &AtomicBool) -> bool { + b.load(Ordering::SeqCst) +} + +pub fn rcd(_x: Rc<u32>) -> bool { + true +} + +pub fn rcmut(_x: Rc<&mut u32>) -> bool { + true +} + +pub fn arcd(_x: Arc<u32>) -> bool { + false +} + +pub fn inner_types(_m: &MyAtomic) -> bool { + true +} + +static mut COUNTER: usize = 0; + +/// # Safety +/// +/// Don't ever call this from multiple threads +pub unsafe fn mutates_static() -> usize { + COUNTER += 1; + COUNTER +} + +fn main() { + assert_eq!(1, pure(1)); +} diff --git a/tests/ui/must_use_candidates.stderr b/tests/ui/must_use_candidates.stderr new file mode 100644 index 00000000000..f3a44210237 --- /dev/null +++ b/tests/ui/must_use_candidates.stderr @@ -0,0 +1,40 @@ +error: this function could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:12:1 + | +LL | pub fn pure(i: u8) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` + | + = note: `-D clippy::must-use-candidate` implied by `-D warnings` + +error: this method could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:17:5 + | +LL | pub fn inherent_pure(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` + +error: this method could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:31:5 + | +LL | fn trait_impl_pure(&self, i: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] fn trait_impl_pure(&self, i: u32) -> u32` + +error: this function could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:48:1 + | +LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` + +error: this function could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:60:1 + | +LL | pub fn rcd(_x: Rc<u32>) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool` + +error: this function could have a `#[must_use]` attribute + --> $DIR/must_use_candidates.rs:68:1 + | +LL | pub fn arcd(_x: Arc<u32>) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed new file mode 100644 index 00000000000..6c9aa434ac0 --- /dev/null +++ b/tests/ui/must_use_unit.fixed @@ -0,0 +1,26 @@ +//run-rustfix +// aux-build:macro_rules.rs + +#![warn(clippy::must_use_unit)] +#![allow(clippy::unused_unit)] + +#[macro_use] +extern crate macro_rules; + + +pub fn must_use_default() {} + + +pub fn must_use_unit() -> () {} + + +pub fn must_use_with_note() {} + +fn main() { + must_use_default(); + must_use_unit(); + must_use_with_note(); + + // We should not lint in external macros + must_use_unit!(); +} diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs new file mode 100644 index 00000000000..8a395dc284d --- /dev/null +++ b/tests/ui/must_use_unit.rs @@ -0,0 +1,26 @@ +//run-rustfix +// aux-build:macro_rules.rs + +#![warn(clippy::must_use_unit)] +#![allow(clippy::unused_unit)] + +#[macro_use] +extern crate macro_rules; + +#[must_use] +pub fn must_use_default() {} + +#[must_use] +pub fn must_use_unit() -> () {} + +#[must_use = "With note"] +pub fn must_use_with_note() {} + +fn main() { + must_use_default(); + must_use_unit(); + must_use_with_note(); + + // We should not lint in external macros + must_use_unit!(); +} diff --git a/tests/ui/must_use_unit.stderr b/tests/ui/must_use_unit.stderr new file mode 100644 index 00000000000..15e0906b66b --- /dev/null +++ b/tests/ui/must_use_unit.stderr @@ -0,0 +1,28 @@ +error: this unit-returning function has a `#[must_use]` attribute + --> $DIR/must_use_unit.rs:11:1 + | +LL | #[must_use] + | ----------- help: remove the attribute +LL | pub fn must_use_default() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::must-use-unit` implied by `-D warnings` + +error: this unit-returning function has a `#[must_use]` attribute + --> $DIR/must_use_unit.rs:14:1 + | +LL | #[must_use] + | ----------- help: remove the attribute +LL | pub fn must_use_unit() -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this unit-returning function has a `#[must_use]` attribute + --> $DIR/must_use_unit.rs:17:1 + | +LL | #[must_use = "With note"] + | ------------------------- help: remove the attribute +LL | pub fn must_use_with_note() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 7a5da67e026..bd91ae4e934 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -16,6 +16,7 @@ fn id<T>(x: T) -> T { x } +#[must_use] fn first(x: (isize, isize)) -> isize { x.0 } diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 184e781ae43..7fa58cf7649 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,135 +1,135 @@ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:25:5 + --> $DIR/shadow.rs:26:5 | LL | let x = &mut x; | ^^^^^^^^^^^^^^^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:24:13 + --> $DIR/shadow.rs:25:13 | LL | let mut x = 1; | ^ error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:26:5 + --> $DIR/shadow.rs:27:5 | LL | let x = { x }; | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:25:9 + --> $DIR/shadow.rs:26:9 | LL | let x = &mut x; | ^ error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:27:5 + --> $DIR/shadow.rs:28:5 | LL | let x = (&*x); | ^^^^^^^^^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:26:9 + --> $DIR/shadow.rs:27:9 | LL | let x = { x }; | ^ error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:28:9 + --> $DIR/shadow.rs:29:9 | LL | let x = { *x + 1 }; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:28:13 + --> $DIR/shadow.rs:29:13 | LL | let x = { *x + 1 }; | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:27:9 + --> $DIR/shadow.rs:28:9 | LL | let x = (&*x); | ^ error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:30:9 | LL | let x = id(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:29:13 + --> $DIR/shadow.rs:30:13 | LL | let x = id(x); | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:28:9 + --> $DIR/shadow.rs:29:9 | LL | let x = { *x + 1 }; | ^ error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:31:9 | LL | let x = (1, x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:30:13 + --> $DIR/shadow.rs:31:13 | LL | let x = (1, x); | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:30:9 | LL | let x = id(x); | ^ error: `x` is shadowed by `first(x)` which reuses the original value - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:32:9 | LL | let x = first(x); | ^ | note: initialization happens here - --> $DIR/shadow.rs:31:13 + --> $DIR/shadow.rs:32:13 | LL | let x = first(x); | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:31:9 | LL | let x = (1, x); | ^ error: `x` is shadowed by `y` - --> $DIR/shadow.rs:33:9 + --> $DIR/shadow.rs:34:9 | LL | let x = y; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: initialization happens here - --> $DIR/shadow.rs:33:13 + --> $DIR/shadow.rs:34:13 | LL | let x = y; | ^ note: previous binding is here - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:32:9 | LL | let x = first(x); | ^ error: `x` shadows a previous declaration - --> $DIR/shadow.rs:35:5 + --> $DIR/shadow.rs:36:5 | LL | let x; | ^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:33:9 + --> $DIR/shadow.rs:34:9 | LL | let x = y; | ^ -- cgit 1.4.1-3-g733a5 From 664522baddd813e9a8a989479289be43fe0da5cd Mon Sep 17 00:00:00 2001 From: James Wang <jameswang9909@hotmail.com> Date: Thu, 3 Oct 2019 14:09:32 -0500 Subject: Add a new lint for unused self --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/double_comparison.rs | 4 +- clippy_lints/src/enum_glob_use.rs | 18 ++-- clippy_lints/src/excessive_precision.rs | 4 +- clippy_lints/src/functions.rs | 5 +- clippy_lints/src/int_plus_one.rs | 43 +++++----- clippy_lints/src/lib.rs | 4 + clippy_lints/src/literal_representation.rs | 4 +- clippy_lints/src/misc_early.rs | 4 +- clippy_lints/src/returns.rs | 14 +--- clippy_lints/src/slow_vector_initialization.rs | 4 +- clippy_lints/src/unused_self.rs | 104 +++++++++++++++++++++++ clippy_lints/src/utils/hir_utils.rs | 4 +- src/lintlist/mod.rs | 9 +- tests/ui/booleans.rs | 1 + tests/ui/booleans.stderr | 60 ++++++------- tests/ui/complex_types.rs | 2 +- tests/ui/def_id_nocore.rs | 1 + tests/ui/def_id_nocore.stderr | 2 +- tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 24 +++--- tests/ui/expect_fun_call.fixed | 1 + tests/ui/expect_fun_call.rs | 1 + tests/ui/expect_fun_call.stderr | 22 ++--- tests/ui/extra_unused_lifetimes.rs | 3 +- tests/ui/extra_unused_lifetimes.stderr | 8 +- tests/ui/functions.stderr | 26 +++--- tests/ui/inherent_to_string.rs | 2 +- tests/ui/iter_nth.rs | 1 + tests/ui/iter_nth.stderr | 14 ++-- tests/ui/len_without_is_empty.rs | 2 +- tests/ui/len_zero.fixed | 2 +- tests/ui/len_zero.rs | 2 +- tests/ui/map_unit_fn.rs | 2 +- tests/ui/missing_const_for_fn/cant_be_const.rs | 1 + tests/ui/missing_const_for_fn/could_be_const.rs | 2 +- tests/ui/mut_from_ref.rs | 2 +- tests/ui/mut_reference.rs | 2 +- tests/ui/needless_lifetimes.rs | 7 +- tests/ui/needless_lifetimes.stderr | 34 ++++---- tests/ui/option_map_unit_fn_fixable.fixed | 2 +- tests/ui/option_map_unit_fn_fixable.rs | 2 +- tests/ui/range.rs | 2 + tests/ui/range.stderr | 12 +-- tests/ui/result_map_unit_fn_fixable.fixed | 2 +- tests/ui/result_map_unit_fn_fixable.rs | 2 +- tests/ui/string_extend.fixed | 1 + tests/ui/string_extend.rs | 1 + tests/ui/string_extend.stderr | 6 +- tests/ui/trivially_copy_pass_by_ref.rs | 3 +- tests/ui/trivially_copy_pass_by_ref.stderr | 30 +++---- tests/ui/unit_arg.fixed | 2 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unused_self.rs | 107 ++++++++++++++++++++++++ tests/ui/unused_self.stderr | 75 +++++++++++++++++ tests/ui/unused_self.stdout | 0 tests/ui/unused_unit.fixed | 2 +- tests/ui/unused_unit.rs | 2 +- tests/ui/wrong_self_convention.rs | 2 +- 62 files changed, 509 insertions(+), 202 deletions(-) create mode 100644 clippy_lints/src/unused_self.rs create mode 100644 tests/ui/unused_self.rs create mode 100644 tests/ui/unused_self.stderr create mode 100644 tests/ui/unused_self.stdout (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index dd67bc3cdc1..9dd04af611f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1236,6 +1236,7 @@ Released 2018-09-13 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self diff --git a/README.md b/README.md index a84ab0e8c25..986d920ac96 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 324 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 325 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 48d2fd341f8..a1e4be260b4 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -39,7 +39,7 @@ declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]); impl<'a, 'tcx> DoubleComparisons { #[allow(clippy::similar_names)] - fn check_binop(self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) { + fn check_binop(cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) { let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) { (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => { (lb.node, llhs, lrhs, rb.node, rlhs, rrhs) @@ -89,7 +89,7 @@ impl<'a, 'tcx> DoubleComparisons { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DoubleComparisons { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.kind { - self.check_binop(cx, kind.node, lhs, rhs, expr.span); + Self::check_binop(cx, kind.node, lhs, rhs, expr.span); } } } diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs index bb71bb54472..64f340dffa1 100644 --- a/clippy_lints/src/enum_glob_use.rs +++ b/clippy_lints/src/enum_glob_use.rs @@ -32,20 +32,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { let map = cx.tcx.hir(); // only check top level `use` statements for item in &m.item_ids { - self.lint_item(cx, map.expect_item(item.id)); + lint_item(cx, map.expect_item(item.id)); } } } -impl EnumGlobUse { - fn lint_item(self, cx: &LateContext<'_, '_>, item: &Item) { - if item.vis.node.is_pub() { - return; // re-exports are fine - } - if let ItemKind::Use(ref path, UseKind::Glob) = item.kind { - if let Res::Def(DefKind::Enum, _) = path.res { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } +fn lint_item(cx: &LateContext<'_, '_>, item: &Item) { + if item.vis.node.is_pub() { + return; // re-exports are fine + } + if let ItemKind::Use(ref path, UseKind::Glob) = item.kind { + if let Res::Def(DefKind::Enum, _) = path.res { + span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); } } } diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index 763770c74ef..fcc247974c5 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { if let ty::Float(fty) = ty.kind; if let hir::ExprKind::Lit(ref lit) = expr.kind; if let LitKind::Float(sym, _) | LitKind::FloatUnsuffixed(sym) = lit.node; - if let Some(sugg) = self.check(sym, fty); + if let Some(sugg) = Self::check(sym, fty); then { span_lint_and_sugg( cx, @@ -63,7 +63,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { impl ExcessivePrecision { // None if nothing to lint, Some(suggestion) if lint necessary #[must_use] - fn check(self, sym: Symbol, fty: FloatTy) -> Option<String> { + fn check(sym: Symbol, fty: FloatTy) -> Option<String> { let max = max_digits(fty); let sym_str = sym.as_str(); if dot_zero_exclusion(&sym_str) { diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 6052f936109..5b2619aa9ba 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } } - self.check_raw_ptr(cx, unsafety, decl, body, hir_id); + Self::check_raw_ptr(cx, unsafety, decl, body, hir_id); self.check_line_number(cx, span, body); } @@ -282,7 +282,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { } if let hir::TraitMethod::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); - self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id); + Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id); if attr.is_none() && cx.access_levels.is_exported(item.hir_id) { check_must_use_candidate( @@ -368,7 +368,6 @@ impl<'a, 'tcx> Functions { } fn check_raw_ptr( - self, cx: &LateContext<'a, 'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl, diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 4d588f253e8..93e09315f86 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -53,25 +53,25 @@ enum Side { impl IntPlusOne { #[allow(clippy::cast_sign_loss)] - fn check_lit(self, lit: &Lit, target_value: i128) -> bool { + fn check_lit(lit: &Lit, target_value: i128) -> bool { if let LitKind::Int(value, ..) = lit.kind { return value == (target_value as u128); } false } - fn check_binop(self, cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> { + fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> { match (binop, &lhs.kind, &rhs.kind) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) { // `-1 + x` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => { - self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => { + Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) }, // `x - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) }, _ => None, } @@ -82,11 +82,11 @@ impl IntPlusOne { { match (&rhslhs.kind, &rhsrhs.kind) { // `y + 1` and `1 + y` - (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) + (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) }, - (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) + (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) }, _ => None, } @@ -97,11 +97,11 @@ impl IntPlusOne { { match (&lhslhs.kind, &lhsrhs.kind) { // `1 + x` and `x + 1` - (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) + (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS) }, - (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) + (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS) }, _ => None, } @@ -110,12 +110,12 @@ impl IntPlusOne { (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { // `-1 + y` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => { - self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => { + Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS) }, // `y - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => { - self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => { + Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS) }, _ => None, } @@ -125,7 +125,6 @@ impl IntPlusOne { } fn generate_recommendation( - self, cx: &EarlyContext<'_>, binop: BinOpKind, node: &Expr, @@ -149,7 +148,7 @@ impl IntPlusOne { None } - fn emit_warning(self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { + fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { span_lint_and_then( cx, INT_PLUS_ONE, @@ -170,8 +169,8 @@ impl IntPlusOne { impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind { - if let Some(ref rec) = self.check_binop(cx, kind.node, lhs, rhs) { - self.emit_warning(cx, item, rec.clone()); + if let Some(ref rec) = Self::check_binop(cx, kind.node, lhs, rhs) { + Self::emit_warning(cx, item, rec.clone()); } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5d428221e69..09db4f6ca90 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -277,6 +277,7 @@ pub mod unicode; pub mod unsafe_removed_from_name; pub mod unused_io_amount; pub mod unused_label; +pub mod unused_self; pub mod unwrap; pub mod use_self; pub mod vec; @@ -606,6 +607,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con reg.register_late_lint_pass(box trait_bounds::TraitBounds); reg.register_late_lint_pass(box comparison_chain::ComparisonChain); reg.register_late_lint_pass(box mul_add::MulAddCheck); + reg.register_late_lint_pass(box unused_self::UnusedSelf); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -926,6 +928,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_io_amount::UNUSED_IO_AMOUNT, unused_label::UNUSED_LABEL, + unused_self::UNUSED_SELF, unwrap::PANICKING_UNWRAP, unwrap::UNNECESSARY_UNWRAP, vec::USELESS_VEC, @@ -1104,6 +1107,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con types::UNNECESSARY_CAST, types::VEC_BOX, unused_label::UNUSED_LABEL, + unused_self::UNUSED_SELF, unwrap::UNNECESSARY_UNWRAP, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 4b2bb69fa79..badd2237073 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -350,13 +350,13 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + Self::check_lit(cx, lit) } } } impl LiteralDigitGrouping { - fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { + fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) { let in_macro = in_macro(lit.span); match lit.kind { LitKind::Int(..) => { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index c06eec95028..2f43daf4caf 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -437,7 +437,7 @@ impl EarlyLintPass for MiscEarlyLints { ); } }, - ExprKind::Lit(ref lit) => self.check_lit(cx, lit), + ExprKind::Lit(ref lit) => Self::check_lit(cx, lit), _ => (), } } @@ -469,7 +469,7 @@ impl EarlyLintPass for MiscEarlyLints { } impl MiscEarlyLints { - fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { + fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) { // We test if first character in snippet is a number, because the snippet could be an expansion // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`. // Note that this check also covers special case that `line!()` is eagerly expanded by compiler. diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index a5323501207..5ed95a674b7 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -117,7 +117,7 @@ impl Return { ast::ExprKind::Ret(ref inner) => { // allow `#[cfg(a)] return a; #[cfg(b)] return b;` if !expr.attrs.iter().any(attr_is_cfg) { - self.emit_return_lint( + Self::emit_return_lint( cx, span.expect("`else return` is not possible"), inner.as_ref().map(|i| i.span), @@ -146,13 +146,7 @@ impl Return { } } - fn emit_return_lint( - &mut self, - cx: &EarlyContext<'_>, - ret_span: Span, - inner_span: Option<Span>, - replacement: RetReplacement, - ) { + fn emit_return_lint(cx: &EarlyContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) { match inner_span { Some(inner_span) => { if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() { @@ -191,7 +185,7 @@ impl Return { } // Check for "let x = EXPR; x" - fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { + fn check_let_return(cx: &EarlyContext<'_>, block: &ast::Block) { let mut it = block.stmts.iter(); // we need both a let-binding stmt and an expr @@ -275,7 +269,7 @@ impl EarlyLintPass for Return { } fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - self.check_let_return(cx, block); + Self::check_let_return(cx, block); if_chain! { if let Some(ref stmt) = block.stmts.last(); if let ast::StmtKind::Expr(ref expr) = stmt.kind; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 3b9985a4245..41d8980e746 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that take is applied to `repeat(0)` if let Some(ref repeat_expr) = take_args.get(0); - if self.is_repeat_zero(repeat_expr); + if Self::is_repeat_zero(repeat_expr); // Check that len expression is equals to `with_capacity` expression if let Some(ref len_arg) = take_args.get(1); @@ -259,7 +259,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } /// Returns `true` if given expression is `repeat(0)` - fn is_repeat_zero(&self, expr: &Expr) -> bool { + fn is_repeat_zero(expr: &Expr) -> bool { if_chain! { if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.kind; if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind; diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs new file mode 100644 index 00000000000..42644b88acc --- /dev/null +++ b/clippy_lints/src/unused_self.rs @@ -0,0 +1,104 @@ +use if_chain::if_chain; +use rustc::hir::def::Res; +use rustc::hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; +use rustc::hir::{AssocItemKind, HirId, ImplItemKind, ImplItemRef, Item, ItemKind, Path}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; + +use crate::utils::span_help_and_lint; + +declare_clippy_lint! { + /// **What it does:** Checks methods that contain a `self` argument but don't use it + /// + /// **Why is this bad?** It may be clearer to define the method as a static function instead + /// of an instance method if it doesn't require `self`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// struct A; + /// impl A { + /// fn method(&self) {} + /// } + /// ``` + /// + /// Could be written: + /// + /// ```rust,ignore + /// struct A; + /// impl A { + /// fn method() {} + /// } + /// ``` + pub UNUSED_SELF, + complexity, + "methods that contain a `self` argument but don't use it" +} + +declare_lint_pass!(UnusedSelf => [UNUSED_SELF]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedSelf { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &Item) { + if item.span.from_expansion() { + return; + } + if let ItemKind::Impl(_, _, _, _, None, _, ref impl_item_refs) = item.kind { + for impl_item_ref in impl_item_refs { + if_chain! { + if let ImplItemRef { + kind: AssocItemKind::Method { has_self: true }, + .. + } = impl_item_ref; + let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id); + if let ImplItemKind::Method(_, body_id) = &impl_item.kind; + then { + // println!("Visiting method: {:?}", impl_item); + let body = cx.tcx.hir().body(*body_id); + let self_param = &body.params[0]; + let self_hir_id = self_param.pat.hir_id; + let visitor = &mut UnusedSelfVisitor { + cx, + uses_self: false, + self_hir_id: &self_hir_id, + }; + visitor.visit_body(body); + if !visitor.uses_self { + // println!("LINTING SPAN: {:?}", &self_param.span); + span_help_and_lint( + cx, + UNUSED_SELF, + self_param.span, + "unused `self` argument", + "consider refactoring to a static method or function", + ) + } + } + } + } + }; + } +} + +struct UnusedSelfVisitor<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + uses_self: bool, + self_hir_id: &'a HirId, +} + +impl<'a, 'tcx> Visitor<'tcx> for UnusedSelfVisitor<'a, 'tcx> { + fn visit_path(&mut self, path: &'tcx Path, _id: HirId) { + if self.uses_self { + // This function already uses `self` + return; + } + if let Res::Local(hir_id) = &path.res { + self.uses_self = self.self_hir_id == hir_id + } + walk_path(self, path); + } + + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.cx.tcx.hir()) + } +} diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 9bfd1b38ffa..0e8fcf8fd0f 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -169,13 +169,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { fn eq_generic_arg(&mut self, left: &GenericArg, right: &GenericArg) -> bool { match (left, right) { - (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => self.eq_lifetime(l_lt, r_lt), + (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt), (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty), _ => false, } } - fn eq_lifetime(&mut self, left: &Lifetime, right: &Lifetime) -> bool { + fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool { left.name == right.name } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 66ee41402ea..f52d3d8650a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 324] = [ +pub const ALL_LINTS: [Lint; 325] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2086,6 +2086,13 @@ pub const ALL_LINTS: [Lint; 324] = [ deprecation: None, module: "unused_label", }, + Lint { + name: "unused_self", + group: "complexity", + desc: "methods that contain a `self` argument but don\'t use it", + deprecation: None, + module: "unused_self", + }, Lint { name: "unused_unit", group: "style", diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index ece20fb1eab..a2d9860b6a4 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,4 +1,5 @@ #![warn(clippy::nonminimal_bool, clippy::logic_bug)] +#![allow(clippy::unused_self)] #[allow(unused, clippy::many_single_char_names)] fn main() { diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index ab0b54e26d7..f77d7cb7415 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -1,18 +1,18 @@ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:10:13 + --> $DIR/booleans.rs:11:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | = note: `-D clippy::logic-bug` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:10:18 + --> $DIR/booleans.rs:11:18 | LL | let _ = a && b || a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:12:13 + --> $DIR/booleans.rs:13:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -20,55 +20,55 @@ LL | let _ = !true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/booleans.rs:13:13 + --> $DIR/booleans.rs:14:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/booleans.rs:14:13 + --> $DIR/booleans.rs:15:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:15:13 + --> $DIR/booleans.rs:16:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:15:22 + --> $DIR/booleans.rs:16:22 | LL | let _ = false && a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:16:13 + --> $DIR/booleans.rs:17:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/booleans.rs:21:13 + --> $DIR/booleans.rs:22:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `!b || a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:31:13 + --> $DIR/booleans.rs:32:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:31:13 + --> $DIR/booleans.rs:32:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:32:13 + --> $DIR/booleans.rs:33:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:33:13 + --> $DIR/booleans.rs:34:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,31 +92,31 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:34:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:34:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:35:13 + --> $DIR/booleans.rs:36:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:35:13 + --> $DIR/booleans.rs:36:13 | LL | let _ = a > b && a <= b; | ^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:37:13 + --> $DIR/booleans.rs:38:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,73 +128,73 @@ LL | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:45:13 + --> $DIR/booleans.rs:46:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:47:13 + --> $DIR/booleans.rs:48:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:49:13 + --> $DIR/booleans.rs:50:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:51:13 + --> $DIR/booleans.rs:52:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:53:13 + --> $DIR/booleans.rs:54:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:54:26 + --> $DIR/booleans.rs:55:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:55:25 + --> $DIR/booleans.rs:56:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:56:23 + --> $DIR/booleans.rs:57:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:128:8 + --> $DIR/booleans.rs:129:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:129:8 + --> $DIR/booleans.rs:130:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:132:8 + --> $DIR/booleans.rs:133:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:133:8 + --> $DIR/booleans.rs:134:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index be61fb6b9be..343c12af6b4 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)] +#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::unused_self)] #![feature(associated_type_defaults)] type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 2a948d60b10..d02518b47f0 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -22,6 +22,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { pub struct A; +#[allow(clippy::unused_self)] impl A { pub fn as_ref(self) -> &'static str { "A" diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index ed87a50547d..82946263921 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/def_id_nocore.rs:26:19 + --> $DIR/def_id_nocore.rs:27:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 746afa47503..5b42738a6dd 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,6 +1,6 @@ #![feature(never_type)] #![warn(clippy::diverging_sub_expression)] -#![allow(clippy::match_same_arms, clippy::logic_bug)] +#![allow(clippy::match_same_arms, clippy::logic_bug, clippy::unused_self)] #[allow(clippy::empty_loop)] fn diverge() -> ! { diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index 5d62a6d9b01..e3b286e1445 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -7,7 +7,8 @@ clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref + clippy::trivially_copy_pass_by_ref, + clippy::unused_self )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index a9c4b209960..e3742259f9b 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -7,7 +7,8 @@ clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref + clippy::trivially_copy_pass_by_ref, + clippy::unused_self )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index d19d21eec0d..1742239e87a 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure found - --> $DIR/eta.rs:21:27 + --> $DIR/eta.rs:22:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` @@ -7,13 +7,13 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:22:10 + --> $DIR/eta.rs:23:10 | LL | meta(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/eta.rs:25:21 + --> $DIR/eta.rs:26:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` @@ -21,13 +21,13 @@ LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:32:27 + --> $DIR/eta.rs:33:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` error: redundant closure found - --> $DIR/eta.rs:75:51 + --> $DIR/eta.rs:76:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: remove closure as shown: `TestStruct::foo` @@ -35,43 +35,43 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:77:51 + --> $DIR/eta.rs:78:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `TestTrait::trait_foo` error: redundant closure found - --> $DIR/eta.rs:80:42 + --> $DIR/eta.rs:81:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: remove closure as shown: `std::vec::Vec::clear` error: redundant closure found - --> $DIR/eta.rs:85:29 + --> $DIR/eta.rs:86:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string` error: redundant closure found - --> $DIR/eta.rs:87:27 + --> $DIR/eta.rs:88:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_uppercase` error: redundant closure found - --> $DIR/eta.rs:90:65 + --> $DIR/eta.rs:91:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase` error: redundant closure found - --> $DIR/eta.rs:173:27 + --> $DIR/eta.rs:174:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `foo_ptr` error: redundant closure found - --> $DIR/eta.rs:178:27 + --> $DIR/eta.rs:179:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `closure` diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index e111ee3dfed..59b9a19d706 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![allow(clippy::unused_self)] #![warn(clippy::expect_fun_call)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 891ec883120..06d12fb5f49 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,5 +1,6 @@ // run-rustfix +#![allow(clippy::unused_self)] #![warn(clippy::expect_fun_call)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index bb16fabd973..033698c7862 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:28:26 + --> $DIR/expect_fun_call.rs:29:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,61 +7,61 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:31:26 + --> $DIR/expect_fun_call.rs:32:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:41:25 + --> $DIR/expect_fun_call.rs:42:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:44:25 + --> $DIR/expect_fun_call.rs:45:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:56:17 + --> $DIR/expect_fun_call.rs:57:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:77:21 + --> $DIR/expect_fun_call.rs:78:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:78:21 + --> $DIR/expect_fun_call.rs:79:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:79:21 + --> $DIR/expect_fun_call.rs:80:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:81:21 + --> $DIR/expect_fun_call.rs:82:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:82:21 + --> $DIR/expect_fun_call.rs:83:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:86:16 + --> $DIR/expect_fun_call.rs:87:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index ba95fd63bf9..09fb810d1ce 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -3,7 +3,8 @@ dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value, - clippy::trivially_copy_pass_by_ref + clippy::trivially_copy_pass_by_ref, + clippy::unused_self )] #![warn(clippy::extra_unused_lifetimes)] diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index ebdb8e74952..173f79c97dc 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:14:14 + --> $DIR/extra_unused_lifetimes.rs:15:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,19 +7,19 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:16:25 + --> $DIR/extra_unused_lifetimes.rs:17:25 | LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:41:10 + --> $DIR/extra_unused_lifetimes.rs:42:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:67:22 + --> $DIR/extra_unused_lifetimes.rs:68:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index 0a86568b18d..c4d48974a3b 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -1,5 +1,5 @@ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:8:1 + --> $DIR/functions.rs:7:1 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f = note: `-D clippy::too-many-arguments` implied by `-D warnings` error: this function has too many arguments (8/7) - --> $DIR/functions.rs:11:1 + --> $DIR/functions.rs:10:1 | LL | / fn bad_multiline( LL | | one: u32, @@ -19,19 +19,19 @@ LL | | ) { | |__^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:45:5 + --> $DIR/functions.rs:44:5 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:54:5 + --> $DIR/functions.rs:53:5 | LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:63:34 + --> $DIR/functions.rs:62:34 | LL | println!("{}", unsafe { *p }); | ^ @@ -39,49 +39,49 @@ LL | println!("{}", unsafe { *p }); = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:64:35 + --> $DIR/functions.rs:63:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:65:33 + --> $DIR/functions.rs:64:33 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:76:30 + --> $DIR/functions.rs:75:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:77:31 + --> $DIR/functions.rs:76:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:78:29 + --> $DIR/functions.rs:77:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:87:34 + --> $DIR/functions.rs:86:34 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:88:35 + --> $DIR/functions.rs:87:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:89:33 + --> $DIR/functions.rs:88:33 | LL | unsafe { std::ptr::read(p) }; | ^ diff --git a/tests/ui/inherent_to_string.rs b/tests/ui/inherent_to_string.rs index e6cf337d1bb..6e9feeeb02a 100644 --- a/tests/ui/inherent_to_string.rs +++ b/tests/ui/inherent_to_string.rs @@ -1,6 +1,6 @@ #![warn(clippy::inherent_to_string)] #![deny(clippy::inherent_to_string_shadow_display)] -#![allow(clippy::many_single_char_names)] +#![allow(clippy::many_single_char_names, clippy::unused_self)] use std::fmt; diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index 9c21dd82ee4..fdc5342fcfd 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -1,5 +1,6 @@ // aux-build:option_helpers.rs +#![allow(clippy::unused_self)] #![warn(clippy::iter_nth)] #[macro_use] diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index 70412f78404..d1ae093e9e4 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -1,5 +1,5 @@ error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:33:23 + --> $DIR/iter_nth.rs:34:23 | LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | let bad_vec = some_vec.iter().nth(3); = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:34:26 + --> $DIR/iter_nth.rs:35:26 | LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:35:31 + --> $DIR/iter_nth.rs:36:31 | LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:36:29 + --> $DIR/iter_nth.rs:37:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:41:23 + --> $DIR/iter_nth.rs:42:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:44:26 + --> $DIR/iter_nth.rs:45:26 | LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:47:29 + --> $DIR/iter_nth.rs:48:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 3ef29dd6388..91f60871151 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -1,5 +1,5 @@ #![warn(clippy::len_without_is_empty)] -#![allow(dead_code, unused)] +#![allow(dead_code, unused, clippy::unused_self)] pub struct PubOne; diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 624e5ef8fcf..6ea4639769d 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty)] +#![allow(dead_code, unused, clippy::len_without_is_empty, clippy::unused_self)] pub struct One; struct Wither; diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 7fba971cfd8..bfda052d709 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty)] +#![allow(dead_code, unused, clippy::len_without_is_empty, clippy::unused_self)] pub struct One; struct Wither; diff --git a/tests/ui/map_unit_fn.rs b/tests/ui/map_unit_fn.rs index 9a74da4e3b8..a7ffe8a0c2d 100644 --- a/tests/ui/map_unit_fn.rs +++ b/tests/ui/map_unit_fn.rs @@ -1,4 +1,4 @@ -#![allow(unused)] +#![allow(unused, clippy::unused_self)] struct Mappable {} impl Mappable { diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index f367279906f..36125620ad2 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -2,6 +2,7 @@ //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. +#![allow(clippy::unused_self)] #![warn(clippy::missing_const_for_fn)] #![feature(start)] diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 9109d255ca7..24044bfbaff 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,5 @@ #![warn(clippy::missing_const_for_fn)] -#![allow(clippy::let_and_return)] +#![allow(clippy::let_and_return, clippy::unused_self)] use std::mem::transmute; diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 8f9ed7ed637..bef86daf506 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::trivially_copy_pass_by_ref)] +#![allow(unused, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] #![warn(clippy::mut_from_ref)] struct Foo; diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index c4379e0ea1c..f25b7765945 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::trivially_copy_pass_by_ref)] +#![allow(unused_variables, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] fn takes_an_immutable_reference(a: &i32) {} fn takes_a_mutable_reference(a: &mut i32) {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index f3fdd48633f..b39a7949eef 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,10 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] +#![allow( + dead_code, + clippy::needless_pass_by_value, + clippy::trivially_copy_pass_by_ref, + clippy::unused_self +)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index ad55fc5f750..69ce6edfd46 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:4:1 + --> $DIR/needless_lifetimes.rs:9:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:6:1 + --> $DIR/needless_lifetimes.rs:11:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:16:1 + --> $DIR/needless_lifetimes.rs:21:1 | LL | / fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { LL | | x @@ -21,7 +21,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:45:1 + --> $DIR/needless_lifetimes.rs:50:1 | LL | / fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { LL | | Ok(x) @@ -29,7 +29,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:55:1 | LL | / fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> LL | | where @@ -40,13 +40,13 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:62:1 + --> $DIR/needless_lifetimes.rs:67:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:86:1 + --> $DIR/needless_lifetimes.rs:91:1 | LL | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> LL | | where @@ -57,7 +57,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:120:5 + --> $DIR/needless_lifetimes.rs:125:5 | LL | / fn self_and_out<'s>(&'s self) -> &'s u8 { LL | | &self.x @@ -65,13 +65,13 @@ LL | | } | |_____^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:129:5 + --> $DIR/needless_lifetimes.rs:134:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:148:1 + --> $DIR/needless_lifetimes.rs:153:1 | LL | / fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { LL | | unimplemented!() @@ -79,7 +79,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:178:1 + --> $DIR/needless_lifetimes.rs:183:1 | LL | / fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { LL | | unimplemented!() @@ -87,7 +87,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:184:1 + --> $DIR/needless_lifetimes.rs:189:1 | LL | / fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { LL | | unimplemented!() @@ -95,7 +95,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:203:1 + --> $DIR/needless_lifetimes.rs:208:1 | LL | / fn named_input_elided_output<'a>(_arg: &'a str) -> &str { LL | | unimplemented!() @@ -103,7 +103,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:211:1 + --> $DIR/needless_lifetimes.rs:216:1 | LL | / fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { LL | | unimplemented!() @@ -111,7 +111,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:247:1 + --> $DIR/needless_lifetimes.rs:252:1 | LL | / fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { LL | | unimplemented!() @@ -119,13 +119,13 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:254:9 + --> $DIR/needless_lifetimes.rs:259:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:258:9 + --> $DIR/needless_lifetimes.rs:263:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index ad153e4fc19..3ee9e32cf43 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::option_map_unit_fn)] -#![allow(unused)] +#![allow(unused, clippy::unused_self)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index 6926498341a..4e1ac8553b5 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::option_map_unit_fn)] -#![allow(unused)] +#![allow(unused, clippy::unused_self)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/range.rs b/tests/ui/range.rs index d0c5cc93bd9..dec0e3067c3 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,4 +1,6 @@ struct NotARange; + +#[allow(clippy::unused_self)] impl NotARange { fn step_by(&self, _: u32) {} } diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index 387d1f674cb..0c11592a941 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -1,5 +1,5 @@ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:8:13 + --> $DIR/range.rs:10:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | let _ = (0..1).step_by(0); = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:12:13 + --> $DIR/range.rs:14:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:13:13 + --> $DIR/range.rs:15:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:16:13 + --> $DIR/range.rs:18:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: It is more idiomatic to use v1.iter().enumerate() - --> $DIR/range.rs:24:14 + --> $DIR/range.rs:26:14 | LL | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _x = v1.iter().zip(0..v1.len()); = note: `-D clippy::range-zip-with-len` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:28:13 + --> $DIR/range.rs:30:13 | LL | let _ = v1.iter().step_by(2 / 3); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index 64d39516be7..1a5724d04e6 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -2,7 +2,7 @@ #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] -#![allow(unused)] +#![allow(unused, clippy::unused_self)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index bf4aba8a7cc..4a901fd4d14 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -2,7 +2,7 @@ #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] -#![allow(unused)] +#![allow(unused, clippy::unused_self)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index 1883a9f8325..3e0581ad8c1 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -3,6 +3,7 @@ #[derive(Copy, Clone)] struct HasChars; +#[allow(clippy::unused_self)] impl HasChars { fn chars(self) -> std::str::Chars<'static> { "HasChars".chars() diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 07d0baa1be6..2994a86b05a 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -3,6 +3,7 @@ #[derive(Copy, Clone)] struct HasChars; +#[allow(clippy::unused_self)] impl HasChars { fn chars(self) -> std::str::Chars<'static> { "HasChars".chars() diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index 6af8c9e1662..669405735b3 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -1,5 +1,5 @@ error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:18:5 + --> $DIR/string_extend.rs:19:5 | LL | s.extend(abc.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` @@ -7,13 +7,13 @@ LL | s.extend(abc.chars()); = note: `-D clippy::string-extend-chars` implied by `-D warnings` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:21:5 + --> $DIR/string_extend.rs:22:5 | LL | s.extend("abc".chars()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:24:5 + --> $DIR/string_extend.rs:25:5 | LL | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index bd23aa99ceb..b0349ec0250 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -4,7 +4,8 @@ #![allow( clippy::many_single_char_names, clippy::blacklisted_name, - clippy::redundant_field_names + clippy::redundant_field_names, + clippy::unused_self )] #[derive(Copy, Clone)] diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 1addc3d7195..03ca7f496fa 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:11 + --> $DIR/trivially_copy_pass_by_ref.rs:51:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -7,85 +7,85 @@ LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:20 + --> $DIR/trivially_copy_pass_by_ref.rs:51:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:29 + --> $DIR/trivially_copy_pass_by_ref.rs:51:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:12 + --> $DIR/trivially_copy_pass_by_ref.rs:58:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:22 + --> $DIR/trivially_copy_pass_by_ref.rs:58:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:31 + --> $DIR/trivially_copy_pass_by_ref.rs:58:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:40 + --> $DIR/trivially_copy_pass_by_ref.rs:58:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:16 + --> $DIR/trivially_copy_pass_by_ref.rs:60:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:25 + --> $DIR/trivially_copy_pass_by_ref.rs:60:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:34 + --> $DIR/trivially_copy_pass_by_ref.rs:60:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:16 + --> $DIR/trivially_copy_pass_by_ref.rs:72:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:25 + --> $DIR/trivially_copy_pass_by_ref.rs:72:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:34 + --> $DIR/trivially_copy_pass_by_ref.rs:72:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:75:34 + --> $DIR/trivially_copy_pass_by_ref.rs:76:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:79:37 + --> $DIR/trivially_copy_pass_by_ref.rs:80:37 | LL | fn trait_method2(&self, _color: &Color); | ^^^^^^ help: consider passing by value instead: `Color` diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed index cf146c91f6d..08a60202988 100644 --- a/tests/ui/unit_arg.fixed +++ b/tests/ui/unit_arg.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, clippy::unused_self, unused_must_use)] use std::fmt::Debug; diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index c15b0a50045..14e3531ed79 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, clippy::unused_self, unused_must_use)] use std::fmt::Debug; diff --git a/tests/ui/unused_self.rs b/tests/ui/unused_self.rs new file mode 100644 index 00000000000..33a7ccad4a1 --- /dev/null +++ b/tests/ui/unused_self.rs @@ -0,0 +1,107 @@ +#![warn(clippy::unused_self)] +#![allow(clippy::boxed_local)] + +mod unused_self { + use std::pin::Pin; + use std::sync::{Arc, Mutex}; + + struct A {} + + impl A { + fn unused_self_move(self) {} + fn unused_self_ref(&self) {} + fn unused_self_mut_ref(&mut self) {} + fn unused_self_pin_ref(self: Pin<&Self>) {} + fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} + fn unused_self_pin_nested(self: Pin<Arc<Self>>) {} + fn unused_self_box(self: Box<Self>) {} + fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { + x + y + } + fn unused_self_class_method(&self) { + Self::static_method(); + } + + fn static_method() {} + } +} + +mod used_self { + use std::pin::Pin; + + struct A { + x: u8, + } + + impl A { + fn used_self_move(self) -> u8 { + self.x + } + fn used_self_ref(&self) -> u8 { + self.x + } + fn used_self_mut_ref(&mut self) { + self.x += 1 + } + fn used_self_pin_ref(self: Pin<&Self>) -> u8 { + self.x + } + fn used_self_box(self: Box<Self>) -> u8 { + self.x + } + fn used_self_with_other_unused_args(&self, x: u8, y: u8) -> u8 { + self.x + } + fn used_in_nested_closure(&self) -> u8 { + let mut a = || -> u8 { self.x }; + a() + } + + #[allow(clippy::collapsible_if)] + fn used_self_method_nested_conditions(&self, a: bool, b: bool, c: bool, d: bool) { + if a { + if b { + if c { + if d { + self.used_self_ref(); + } + } + } + } + } + + fn foo(&self) -> u32 { + let mut sum = 0u32; + for i in 0..self.x { + sum += i as u32; + } + sum + } + + fn bar(&mut self, x: u8) -> u32 { + let mut y = 0u32; + for i in 0..x { + y += self.foo() + } + y + } + } +} + +mod not_applicable { + use std::fmt; + + struct A {} + + impl fmt::Debug for A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "A") + } + } + + impl A { + fn method(x: u8, y: u8) {} + } +} + +fn main() {} diff --git a/tests/ui/unused_self.stderr b/tests/ui/unused_self.stderr new file mode 100644 index 00000000000..497adddb8bc --- /dev/null +++ b/tests/ui/unused_self.stderr @@ -0,0 +1,75 @@ +error: unused `self` argument + --> $DIR/unused_self.rs:11:29 + | +LL | fn unused_self_move(self) {} + | ^^^^ + | + = note: `-D clippy::unused-self` implied by `-D warnings` + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:12:28 + | +LL | fn unused_self_ref(&self) {} + | ^^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:13:32 + | +LL | fn unused_self_mut_ref(&mut self) {} + | ^^^^^^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:14:32 + | +LL | fn unused_self_pin_ref(self: Pin<&Self>) {} + | ^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:15:36 + | +LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} + | ^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:16:35 + | +LL | fn unused_self_pin_nested(self: Pin<Arc<Self>>) {} + | ^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:17:28 + | +LL | fn unused_self_box(self: Box<Self>) {} + | ^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:18:40 + | +LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { + | ^^^^^ + | + = help: consider refactoring to a static method or function + +error: unused `self` argument + --> $DIR/unused_self.rs:21:37 + | +LL | fn unused_self_class_method(&self) { + | ^^^^^ + | + = help: consider refactoring to a static method or function + +error: aborting due to 9 previous errors + diff --git a/tests/ui/unused_self.stdout b/tests/ui/unused_self.stdout new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 3f63624720f..20a63122d00 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -10,7 +10,7 @@ #![rustfmt::skip] #![deny(clippy::unused_unit)] -#![allow(dead_code)] +#![allow(dead_code, clippy::unused_self)] struct Unitter; impl Unitter { diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index 8fc072ebd69..cc2f6587446 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -10,7 +10,7 @@ #![rustfmt::skip] #![deny(clippy::unused_unit)] -#![allow(dead_code)] +#![allow(dead_code, clippy::unused_self)] struct Unitter; impl Unitter { diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 7567fa7158c..018fe80df37 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,6 +1,6 @@ #![warn(clippy::wrong_self_convention)] #![warn(clippy::wrong_pub_self_convention)] -#![allow(dead_code, clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] fn main() {} -- cgit 1.4.1-3-g733a5 From e23a424b318891062397d61f70e6eab06f3092c0 Mon Sep 17 00:00:00 2001 From: James Wang <jameswang9909@hotmail.com> Date: Fri, 4 Oct 2019 12:18:52 -0500 Subject: Change lint to be pedantic --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/unused_self.rs | 4 +- src/lintlist/mod.rs | 2 +- tests/ui/booleans.rs | 1 - tests/ui/booleans.stderr | 60 ++++++++++++------------- tests/ui/complex_types.rs | 2 +- tests/ui/def_id_nocore.rs | 1 - tests/ui/def_id_nocore.stderr | 2 +- tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/eta.fixed | 3 +- tests/ui/eta.rs | 3 +- tests/ui/eta.stderr | 24 +++++----- tests/ui/expect_fun_call.fixed | 1 - tests/ui/expect_fun_call.rs | 1 - tests/ui/expect_fun_call.stderr | 22 ++++----- tests/ui/extra_unused_lifetimes.rs | 3 +- tests/ui/extra_unused_lifetimes.stderr | 8 ++-- tests/ui/functions.stderr | 26 +++++------ tests/ui/inherent_to_string.rs | 2 +- tests/ui/iter_nth.rs | 1 - tests/ui/iter_nth.stderr | 14 +++--- tests/ui/len_without_is_empty.rs | 2 +- tests/ui/len_zero.fixed | 2 +- tests/ui/len_zero.rs | 2 +- tests/ui/map_unit_fn.rs | 2 +- tests/ui/methods.rs | 1 + tests/ui/methods.stderr | 48 ++++++++++---------- tests/ui/missing_const_for_fn/cant_be_const.rs | 1 - tests/ui/missing_const_for_fn/could_be_const.rs | 2 +- tests/ui/mut_from_ref.rs | 2 +- tests/ui/mut_reference.rs | 2 +- tests/ui/needless_lifetimes.rs | 7 +-- tests/ui/needless_lifetimes.stderr | 34 +++++++------- tests/ui/option_map_unit_fn_fixable.fixed | 2 +- tests/ui/option_map_unit_fn_fixable.rs | 2 +- tests/ui/range.rs | 2 - tests/ui/range.stderr | 12 ++--- tests/ui/result_map_unit_fn_fixable.fixed | 2 +- tests/ui/result_map_unit_fn_fixable.rs | 2 +- tests/ui/string_extend.fixed | 1 - tests/ui/string_extend.rs | 1 - tests/ui/string_extend.stderr | 6 +-- tests/ui/trivially_copy_pass_by_ref.rs | 3 +- tests/ui/trivially_copy_pass_by_ref.stderr | 30 ++++++------- tests/ui/unit_arg.fixed | 2 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unused_self.rs | 4 ++ tests/ui/unused_self.stdout | 0 tests/ui/unused_unit.fixed | 2 +- tests/ui/unused_unit.rs | 2 +- tests/ui/wrong_self_convention.rs | 2 +- 51 files changed, 176 insertions(+), 191 deletions(-) delete mode 100644 tests/ui/unused_self.stdout (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 09db4f6ca90..e8962c6e207 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -685,6 +685,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con types::LINKEDLIST, unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, + unused_self::UNUSED_SELF, use_self::USE_SELF, ]); @@ -928,7 +929,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_io_amount::UNUSED_IO_AMOUNT, unused_label::UNUSED_LABEL, - unused_self::UNUSED_SELF, unwrap::PANICKING_UNWRAP, unwrap::UNNECESSARY_UNWRAP, vec::USELESS_VEC, @@ -1107,7 +1107,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con types::UNNECESSARY_CAST, types::VEC_BOX, unused_label::UNUSED_LABEL, - unused_self::UNUSED_SELF, unwrap::UNNECESSARY_UNWRAP, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 5615dd37cd2..fee902604b2 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// } /// ``` pub UNUSED_SELF, - complexity, + pedantic, "methods that contain a `self` argument but don't use it" } @@ -56,7 +56,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedSelf { let body = cx.tcx.hir().body(*body_id); let self_param = &body.params[0]; let self_hir_id = self_param.pat.hir_id; - let visitor = &mut UnusedSelfVisitor { + let mut visitor = UnusedSelfVisitor { cx, uses_self: false, self_hir_id: &self_hir_id, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f52d3d8650a..d9ae1f70d42 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2088,7 +2088,7 @@ pub const ALL_LINTS: [Lint; 325] = [ }, Lint { name: "unused_self", - group: "complexity", + group: "pedantic", desc: "methods that contain a `self` argument but don\'t use it", deprecation: None, module: "unused_self", diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index a2d9860b6a4..ece20fb1eab 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,5 +1,4 @@ #![warn(clippy::nonminimal_bool, clippy::logic_bug)] -#![allow(clippy::unused_self)] #[allow(unused, clippy::many_single_char_names)] fn main() { diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index f77d7cb7415..ab0b54e26d7 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -1,18 +1,18 @@ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:11:13 + --> $DIR/booleans.rs:10:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | = note: `-D clippy::logic-bug` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:11:18 + --> $DIR/booleans.rs:10:18 | LL | let _ = a && b || a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:13:13 + --> $DIR/booleans.rs:12:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -20,55 +20,55 @@ LL | let _ = !true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/booleans.rs:14:13 + --> $DIR/booleans.rs:13:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/booleans.rs:15:13 + --> $DIR/booleans.rs:14:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:16:13 + --> $DIR/booleans.rs:15:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:16:22 + --> $DIR/booleans.rs:15:22 | LL | let _ = false && a; | ^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:17:13 + --> $DIR/booleans.rs:16:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/booleans.rs:22:13 + --> $DIR/booleans.rs:21:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `!b || a` error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:32:13 + --> $DIR/booleans.rs:31:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:32:13 + --> $DIR/booleans.rs:31:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:33:13 + --> $DIR/booleans.rs:32:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:34:13 + --> $DIR/booleans.rs:33:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,31 +92,31 @@ LL | let _ = !(c != 5 || a != b); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:35:13 + --> $DIR/booleans.rs:34:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:35:13 + --> $DIR/booleans.rs:34:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/booleans.rs:36:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/booleans.rs:36:13 + --> $DIR/booleans.rs:35:13 | LL | let _ = a > b && a <= b; | ^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:38:13 + --> $DIR/booleans.rs:37:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,73 +128,73 @@ LL | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ error: this boolean expression can be simplified - --> $DIR/booleans.rs:46:13 + --> $DIR/booleans.rs:45:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:48:13 + --> $DIR/booleans.rs:47:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:50:13 + --> $DIR/booleans.rs:49:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:52:13 + --> $DIR/booleans.rs:51:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:54:13 + --> $DIR/booleans.rs:53:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `c || a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:55:26 + --> $DIR/booleans.rs:54:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:56:25 + --> $DIR/booleans.rs:55:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:57:23 + --> $DIR/booleans.rs:56:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:129:8 + --> $DIR/booleans.rs:128:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:130:8 + --> $DIR/booleans.rs:129:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:133:8 + --> $DIR/booleans.rs:132:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> $DIR/booleans.rs:134:8 + --> $DIR/booleans.rs:133:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index 343c12af6b4..be61fb6b9be 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::unused_self)] +#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)] #![feature(associated_type_defaults)] type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index d02518b47f0..2a948d60b10 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -22,7 +22,6 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { pub struct A; -#[allow(clippy::unused_self)] impl A { pub fn as_ref(self) -> &'static str { "A" diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 82946263921..ed87a50547d 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name - --> $DIR/def_id_nocore.rs:27:19 + --> $DIR/def_id_nocore.rs:26:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 5b42738a6dd..746afa47503 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,6 +1,6 @@ #![feature(never_type)] #![warn(clippy::diverging_sub_expression)] -#![allow(clippy::match_same_arms, clippy::logic_bug, clippy::unused_self)] +#![allow(clippy::match_same_arms, clippy::logic_bug)] #[allow(clippy::empty_loop)] fn diverge() -> ! { diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index e3b286e1445..5d62a6d9b01 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -7,8 +7,7 @@ clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref, - clippy::unused_self + clippy::trivially_copy_pass_by_ref )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index e3742259f9b..a9c4b209960 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -7,8 +7,7 @@ clippy::many_single_char_names, clippy::needless_pass_by_value, clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref, - clippy::unused_self + clippy::trivially_copy_pass_by_ref )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 1742239e87a..d19d21eec0d 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure found - --> $DIR/eta.rs:22:27 + --> $DIR/eta.rs:21:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` @@ -7,13 +7,13 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:23:10 + --> $DIR/eta.rs:22:10 | LL | meta(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/eta.rs:26:21 + --> $DIR/eta.rs:25:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` @@ -21,13 +21,13 @@ LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:33:27 + --> $DIR/eta.rs:32:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` error: redundant closure found - --> $DIR/eta.rs:76:51 + --> $DIR/eta.rs:75:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: remove closure as shown: `TestStruct::foo` @@ -35,43 +35,43 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:78:51 + --> $DIR/eta.rs:77:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `TestTrait::trait_foo` error: redundant closure found - --> $DIR/eta.rs:81:42 + --> $DIR/eta.rs:80:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: remove closure as shown: `std::vec::Vec::clear` error: redundant closure found - --> $DIR/eta.rs:86:29 + --> $DIR/eta.rs:85:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string` error: redundant closure found - --> $DIR/eta.rs:88:27 + --> $DIR/eta.rs:87:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_uppercase` error: redundant closure found - --> $DIR/eta.rs:91:65 + --> $DIR/eta.rs:90:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase` error: redundant closure found - --> $DIR/eta.rs:174:27 + --> $DIR/eta.rs:173:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `foo_ptr` error: redundant closure found - --> $DIR/eta.rs:179:27 + --> $DIR/eta.rs:178:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `closure` diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 59b9a19d706..e111ee3dfed 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,6 +1,5 @@ // run-rustfix -#![allow(clippy::unused_self)] #![warn(clippy::expect_fun_call)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 06d12fb5f49..891ec883120 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,6 +1,5 @@ // run-rustfix -#![allow(clippy::unused_self)] #![warn(clippy::expect_fun_call)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index 033698c7862..bb16fabd973 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:29:26 + --> $DIR/expect_fun_call.rs:28:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,61 +7,61 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:32:26 + --> $DIR/expect_fun_call.rs:31:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:42:25 + --> $DIR/expect_fun_call.rs:41:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:45:25 + --> $DIR/expect_fun_call.rs:44:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:57:17 + --> $DIR/expect_fun_call.rs:56:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:78:21 + --> $DIR/expect_fun_call.rs:77:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:79:21 + --> $DIR/expect_fun_call.rs:78:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:80:21 + --> $DIR/expect_fun_call.rs:79:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:82:21 + --> $DIR/expect_fun_call.rs:81:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:83:21 + --> $DIR/expect_fun_call.rs:82:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:87:16 + --> $DIR/expect_fun_call.rs:86:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index 09fb810d1ce..ba95fd63bf9 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -3,8 +3,7 @@ dead_code, clippy::needless_lifetimes, clippy::needless_pass_by_value, - clippy::trivially_copy_pass_by_ref, - clippy::unused_self + clippy::trivially_copy_pass_by_ref )] #![warn(clippy::extra_unused_lifetimes)] diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index 173f79c97dc..ebdb8e74952 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:15:14 + --> $DIR/extra_unused_lifetimes.rs:14:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,19 +7,19 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:17:25 + --> $DIR/extra_unused_lifetimes.rs:16:25 | LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:42:10 + --> $DIR/extra_unused_lifetimes.rs:41:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:68:22 + --> $DIR/extra_unused_lifetimes.rs:67:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index c4d48974a3b..0a86568b18d 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -1,5 +1,5 @@ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:7:1 + --> $DIR/functions.rs:8:1 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f = note: `-D clippy::too-many-arguments` implied by `-D warnings` error: this function has too many arguments (8/7) - --> $DIR/functions.rs:10:1 + --> $DIR/functions.rs:11:1 | LL | / fn bad_multiline( LL | | one: u32, @@ -19,19 +19,19 @@ LL | | ) { | |__^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:44:5 + --> $DIR/functions.rs:45:5 | LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many arguments (8/7) - --> $DIR/functions.rs:53:5 + --> $DIR/functions.rs:54:5 | LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:62:34 + --> $DIR/functions.rs:63:34 | LL | println!("{}", unsafe { *p }); | ^ @@ -39,49 +39,49 @@ LL | println!("{}", unsafe { *p }); = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:63:35 + --> $DIR/functions.rs:64:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:64:33 + --> $DIR/functions.rs:65:33 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:75:30 + --> $DIR/functions.rs:76:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:76:31 + --> $DIR/functions.rs:77:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:77:29 + --> $DIR/functions.rs:78:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:86:34 + --> $DIR/functions.rs:87:34 | LL | println!("{}", unsafe { *p }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:87:35 + --> $DIR/functions.rs:88:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function dereferences a raw pointer but is not marked `unsafe` - --> $DIR/functions.rs:88:33 + --> $DIR/functions.rs:89:33 | LL | unsafe { std::ptr::read(p) }; | ^ diff --git a/tests/ui/inherent_to_string.rs b/tests/ui/inherent_to_string.rs index 6e9feeeb02a..e6cf337d1bb 100644 --- a/tests/ui/inherent_to_string.rs +++ b/tests/ui/inherent_to_string.rs @@ -1,6 +1,6 @@ #![warn(clippy::inherent_to_string)] #![deny(clippy::inherent_to_string_shadow_display)] -#![allow(clippy::many_single_char_names, clippy::unused_self)] +#![allow(clippy::many_single_char_names)] use std::fmt; diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index fdc5342fcfd..9c21dd82ee4 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -1,6 +1,5 @@ // aux-build:option_helpers.rs -#![allow(clippy::unused_self)] #![warn(clippy::iter_nth)] #[macro_use] diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index d1ae093e9e4..70412f78404 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -1,5 +1,5 @@ error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:34:23 + --> $DIR/iter_nth.rs:33:23 | LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | let bad_vec = some_vec.iter().nth(3); = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:35:26 + --> $DIR/iter_nth.rs:34:26 | LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:36:31 + --> $DIR/iter_nth.rs:35:31 | LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable - --> $DIR/iter_nth.rs:37:29 + --> $DIR/iter_nth.rs:36:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:42:23 + --> $DIR/iter_nth.rs:41:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:45:26 + --> $DIR/iter_nth.rs:44:26 | LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable - --> $DIR/iter_nth.rs:48:29 + --> $DIR/iter_nth.rs:47:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index 91f60871151..3ef29dd6388 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -1,5 +1,5 @@ #![warn(clippy::len_without_is_empty)] -#![allow(dead_code, unused, clippy::unused_self)] +#![allow(dead_code, unused)] pub struct PubOne; diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 6ea4639769d..624e5ef8fcf 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty, clippy::unused_self)] +#![allow(dead_code, unused, clippy::len_without_is_empty)] pub struct One; struct Wither; diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index bfda052d709..7fba971cfd8 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty, clippy::unused_self)] +#![allow(dead_code, unused, clippy::len_without_is_empty)] pub struct One; struct Wither; diff --git a/tests/ui/map_unit_fn.rs b/tests/ui/map_unit_fn.rs index a7ffe8a0c2d..9a74da4e3b8 100644 --- a/tests/ui/map_unit_fn.rs +++ b/tests/ui/map_unit_fn.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::unused_self)] +#![allow(unused)] struct Mappable {} impl Mappable { diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index e5a6cba9a25..54a58e0c86a 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -14,6 +14,7 @@ clippy::use_self, clippy::useless_format, clippy::wrong_self_convention, + clippy::unused_self, unused )] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 28da35bff3e..c3dc08be00b 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name - --> $DIR/methods.rs:37:5 + --> $DIR/methods.rs:38:5 | LL | / pub fn add(self, other: T) -> T { LL | | self @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::should-implement-trait` implied by `-D warnings` error: methods called `new` usually return `Self` - --> $DIR/methods.rs:153:5 + --> $DIR/methods.rs:154:5 | LL | / fn new() -> i32 { LL | | 0 @@ -19,7 +19,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:175:13 + --> $DIR/methods.rs:176:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -31,7 +31,7 @@ LL | | .unwrap_or(0); = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:179:13 + --> $DIR/methods.rs:180:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -41,7 +41,7 @@ LL | | ).unwrap_or(0); | |____________________________^ error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:183:13 + --> $DIR/methods.rs:184:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -51,7 +51,7 @@ LL | | }); | |__________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:188:13 + --> $DIR/methods.rs:189:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:190:13 + --> $DIR/methods.rs:191:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -69,7 +69,7 @@ LL | | ).unwrap_or(None); | |_____________________^ error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/methods.rs:194:13 + --> $DIR/methods.rs:195:13 | LL | let _ = opt | _____________^ @@ -80,7 +80,7 @@ LL | | .unwrap_or(None); = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))` error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/methods.rs:205:13 + --> $DIR/methods.rs:206:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); = note: replace `map(|p| format!("{}.", p)).unwrap_or(id)` with `map_or(id, |p| format!("{}.", p))` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:209:13 + --> $DIR/methods.rs:210:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -100,7 +100,7 @@ LL | | .unwrap_or_else(|| 0); = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:213:13 + --> $DIR/methods.rs:214:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -110,7 +110,7 @@ LL | | ).unwrap_or_else(|| 0); | |____________________________________^ error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/methods.rs:217:13 + --> $DIR/methods.rs:218:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -120,7 +120,7 @@ LL | | ); | |_________________^ error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:247:13 + --> $DIR/methods.rs:248:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next(); = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:250:13 + --> $DIR/methods.rs:251:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ @@ -139,7 +139,7 @@ LL | | ).next(); | |___________________________^ error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:267:22 + --> $DIR/methods.rs:268:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -147,25 +147,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:268:20 + --> $DIR/methods.rs:269:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:269:20 + --> $DIR/methods.rs:270:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:270:22 + --> $DIR/methods.rs:271:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:273:13 + --> $DIR/methods.rs:274:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -175,13 +175,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:279:22 + --> $DIR/methods.rs:280:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:282:13 + --> $DIR/methods.rs:283:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -191,13 +191,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:288:22 + --> $DIR/methods.rs:289:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:291:13 + --> $DIR/methods.rs:292:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -207,7 +207,7 @@ LL | | ).is_some(); | |______________________________^ error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message - --> $DIR/methods.rs:306:13 + --> $DIR/methods.rs:307:13 | LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 36125620ad2..f367279906f 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -2,7 +2,6 @@ //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. -#![allow(clippy::unused_self)] #![warn(clippy::missing_const_for_fn)] #![feature(start)] diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 24044bfbaff..9109d255ca7 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,5 @@ #![warn(clippy::missing_const_for_fn)] -#![allow(clippy::let_and_return, clippy::unused_self)] +#![allow(clippy::let_and_return)] use std::mem::transmute; diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index bef86daf506..8f9ed7ed637 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] +#![allow(unused, clippy::trivially_copy_pass_by_ref)] #![warn(clippy::mut_from_ref)] struct Foo; diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index f25b7765945..c4379e0ea1c 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] +#![allow(unused_variables, clippy::trivially_copy_pass_by_ref)] fn takes_an_immutable_reference(a: &i32) {} fn takes_a_mutable_reference(a: &mut i32) {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index b39a7949eef..f3fdd48633f 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,10 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow( - dead_code, - clippy::needless_pass_by_value, - clippy::trivially_copy_pass_by_ref, - clippy::unused_self -)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 69ce6edfd46..ad55fc5f750 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:9:1 + --> $DIR/needless_lifetimes.rs:4:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:11:1 + --> $DIR/needless_lifetimes.rs:6:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:21:1 + --> $DIR/needless_lifetimes.rs:16:1 | LL | / fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { LL | | x @@ -21,7 +21,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:45:1 | LL | / fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { LL | | Ok(x) @@ -29,7 +29,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:55:1 + --> $DIR/needless_lifetimes.rs:50:1 | LL | / fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> LL | | where @@ -40,13 +40,13 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:67:1 + --> $DIR/needless_lifetimes.rs:62:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:91:1 + --> $DIR/needless_lifetimes.rs:86:1 | LL | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> LL | | where @@ -57,7 +57,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:125:5 + --> $DIR/needless_lifetimes.rs:120:5 | LL | / fn self_and_out<'s>(&'s self) -> &'s u8 { LL | | &self.x @@ -65,13 +65,13 @@ LL | | } | |_____^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:134:5 + --> $DIR/needless_lifetimes.rs:129:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:153:1 + --> $DIR/needless_lifetimes.rs:148:1 | LL | / fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { LL | | unimplemented!() @@ -79,7 +79,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:183:1 + --> $DIR/needless_lifetimes.rs:178:1 | LL | / fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { LL | | unimplemented!() @@ -87,7 +87,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:189:1 + --> $DIR/needless_lifetimes.rs:184:1 | LL | / fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { LL | | unimplemented!() @@ -95,7 +95,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:208:1 + --> $DIR/needless_lifetimes.rs:203:1 | LL | / fn named_input_elided_output<'a>(_arg: &'a str) -> &str { LL | | unimplemented!() @@ -103,7 +103,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:216:1 + --> $DIR/needless_lifetimes.rs:211:1 | LL | / fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { LL | | unimplemented!() @@ -111,7 +111,7 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:252:1 + --> $DIR/needless_lifetimes.rs:247:1 | LL | / fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { LL | | unimplemented!() @@ -119,13 +119,13 @@ LL | | } | |_^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:259:9 + --> $DIR/needless_lifetimes.rs:254:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:263:9 + --> $DIR/needless_lifetimes.rs:258:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 3ee9e32cf43..ad153e4fc19 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::option_map_unit_fn)] -#![allow(unused, clippy::unused_self)] +#![allow(unused)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index 4e1ac8553b5..6926498341a 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::option_map_unit_fn)] -#![allow(unused, clippy::unused_self)] +#![allow(unused)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/range.rs b/tests/ui/range.rs index dec0e3067c3..d0c5cc93bd9 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,6 +1,4 @@ struct NotARange; - -#[allow(clippy::unused_self)] impl NotARange { fn step_by(&self, _: u32) {} } diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index 0c11592a941..387d1f674cb 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -1,5 +1,5 @@ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:10:13 + --> $DIR/range.rs:8:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ @@ -7,25 +7,25 @@ LL | let _ = (0..1).step_by(0); = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:14:13 + --> $DIR/range.rs:12:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:15:13 + --> $DIR/range.rs:13:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:18:13 + --> $DIR/range.rs:16:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: It is more idiomatic to use v1.iter().enumerate() - --> $DIR/range.rs:26:14 + --> $DIR/range.rs:24:14 | LL | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _x = v1.iter().zip(0..v1.len()); = note: `-D clippy::range-zip-with-len` implied by `-D warnings` error: Iterator::step_by(0) will panic at runtime - --> $DIR/range.rs:30:13 + --> $DIR/range.rs:28:13 | LL | let _ = v1.iter().step_by(2 / 3); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index 1a5724d04e6..64d39516be7 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -2,7 +2,7 @@ #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] -#![allow(unused, clippy::unused_self)] +#![allow(unused)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index 4a901fd4d14..bf4aba8a7cc 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -2,7 +2,7 @@ #![feature(never_type)] #![warn(clippy::result_map_unit_fn)] -#![allow(unused, clippy::unused_self)] +#![allow(unused)] fn do_nothing<T>(_: T) {} diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index 3e0581ad8c1..1883a9f8325 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -3,7 +3,6 @@ #[derive(Copy, Clone)] struct HasChars; -#[allow(clippy::unused_self)] impl HasChars { fn chars(self) -> std::str::Chars<'static> { "HasChars".chars() diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 2994a86b05a..07d0baa1be6 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -3,7 +3,6 @@ #[derive(Copy, Clone)] struct HasChars; -#[allow(clippy::unused_self)] impl HasChars { fn chars(self) -> std::str::Chars<'static> { "HasChars".chars() diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index 669405735b3..6af8c9e1662 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -1,5 +1,5 @@ error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:19:5 + --> $DIR/string_extend.rs:18:5 | LL | s.extend(abc.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` @@ -7,13 +7,13 @@ LL | s.extend(abc.chars()); = note: `-D clippy::string-extend-chars` implied by `-D warnings` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:22:5 + --> $DIR/string_extend.rs:21:5 | LL | s.extend("abc".chars()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` error: calling `.extend(_.chars())` - --> $DIR/string_extend.rs:25:5 + --> $DIR/string_extend.rs:24:5 | LL | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index b0349ec0250..bd23aa99ceb 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -4,8 +4,7 @@ #![allow( clippy::many_single_char_names, clippy::blacklisted_name, - clippy::redundant_field_names, - clippy::unused_self + clippy::redundant_field_names )] #[derive(Copy, Clone)] diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 03ca7f496fa..1addc3d7195 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:11 + --> $DIR/trivially_copy_pass_by_ref.rs:50:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -7,85 +7,85 @@ LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:20 + --> $DIR/trivially_copy_pass_by_ref.rs:50:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:29 + --> $DIR/trivially_copy_pass_by_ref.rs:50:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:12 + --> $DIR/trivially_copy_pass_by_ref.rs:57:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:22 + --> $DIR/trivially_copy_pass_by_ref.rs:57:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:31 + --> $DIR/trivially_copy_pass_by_ref.rs:57:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:40 + --> $DIR/trivially_copy_pass_by_ref.rs:57:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:16 + --> $DIR/trivially_copy_pass_by_ref.rs:59:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:25 + --> $DIR/trivially_copy_pass_by_ref.rs:59:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:34 + --> $DIR/trivially_copy_pass_by_ref.rs:59:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:72:16 + --> $DIR/trivially_copy_pass_by_ref.rs:71:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:72:25 + --> $DIR/trivially_copy_pass_by_ref.rs:71:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:72:34 + --> $DIR/trivially_copy_pass_by_ref.rs:71:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:76:34 + --> $DIR/trivially_copy_pass_by_ref.rs:75:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:80:37 + --> $DIR/trivially_copy_pass_by_ref.rs:79:37 | LL | fn trait_method2(&self, _color: &Color); | ^^^^^^ help: consider passing by value instead: `Color` diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed index 08a60202988..cf146c91f6d 100644 --- a/tests/ui/unit_arg.fixed +++ b/tests/ui/unit_arg.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, clippy::unused_self, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use)] use std::fmt::Debug; diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 14e3531ed79..c15b0a50045 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, clippy::unused_self, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use)] use std::fmt::Debug; diff --git a/tests/ui/unused_self.rs b/tests/ui/unused_self.rs index 33a7ccad4a1..9119c43c082 100644 --- a/tests/ui/unused_self.rs +++ b/tests/ui/unused_self.rs @@ -102,6 +102,10 @@ mod not_applicable { impl A { fn method(x: u8, y: u8) {} } + + trait B { + fn method(&self) {} + } } fn main() {} diff --git a/tests/ui/unused_self.stdout b/tests/ui/unused_self.stdout deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 20a63122d00..3f63624720f 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -10,7 +10,7 @@ #![rustfmt::skip] #![deny(clippy::unused_unit)] -#![allow(dead_code, clippy::unused_self)] +#![allow(dead_code)] struct Unitter; impl Unitter { diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index cc2f6587446..8fc072ebd69 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -10,7 +10,7 @@ #![rustfmt::skip] #![deny(clippy::unused_unit)] -#![allow(dead_code, clippy::unused_self)] +#![allow(dead_code)] struct Unitter; impl Unitter { diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 018fe80df37..7567fa7158c 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,6 +1,6 @@ #![warn(clippy::wrong_self_convention)] #![warn(clippy::wrong_pub_self_convention)] -#![allow(dead_code, clippy::trivially_copy_pass_by_ref, clippy::unused_self)] +#![allow(dead_code, clippy::trivially_copy_pass_by_ref)] fn main() {} -- cgit 1.4.1-3-g733a5 From 76b44f34b9ecd531b761b9fb10edc90671734d0e Mon Sep 17 00:00:00 2001 From: HMPerson1 <hmperson1@gmail.com> Date: Wed, 16 Oct 2019 15:54:20 -0400 Subject: Add `inefficient_to_string` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/inefficient_to_string.rs | 55 +++++++++++++++++++++++ clippy_lints/src/methods/mod.rs | 28 ++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/inefficient_to_string.rs | 31 +++++++++++++ tests/ui/inefficient_to_string.stderr | 55 +++++++++++++++++++++++ 8 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/methods/inefficient_to_string.rs create mode 100644 tests/ui/inefficient_to_string.rs create mode 100644 tests/ui/inefficient_to_string.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dd04af611f..42ab00001d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1033,6 +1033,7 @@ Released 2018-09-13 [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask +[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string diff --git a/README.md b/README.md index 986d920ac96..5023538c5ed 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 325 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 326 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e8962c6e207..bae904a445e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -806,6 +806,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con methods::EXPECT_FUN_CALL, methods::FILTER_NEXT, methods::FLAT_MAP_IDENTITY, + methods::INEFFICIENT_TO_STRING, methods::INTO_ITER_ON_ARRAY, methods::INTO_ITER_ON_REF, methods::ITER_CLONED_COLLECT, @@ -1182,6 +1183,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con loops::MANUAL_MEMCPY, loops::NEEDLESS_COLLECT, methods::EXPECT_FUN_CALL, + methods::INEFFICIENT_TO_STRING, methods::ITER_NTH, methods::OR_FUN_CALL, methods::SINGLE_CHAR_PATTERN, diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs new file mode 100644 index 00000000000..35c634cc52d --- /dev/null +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -0,0 +1,55 @@ +use super::INEFFICIENT_TO_STRING; +use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty_depth}; +use if_chain::if_chain; +use rustc::hir; +use rustc::lint::LateContext; +use rustc::ty::{self, Ty}; +use rustc_errors::Applicability; + +/// Checks for the `INEFFICIENT_TO_STRING` lint +pub fn lint<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'tcx>) { + if_chain! { + if let Some(to_string_meth_did) = cx.tables.type_dependent_def_id(expr.hir_id); + if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); + if let Some(substs) = cx.tables.node_substs_opt(expr.hir_id); + let self_ty = substs.type_at(0); + let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); + if deref_count >= 1; + if specializes_tostring(cx, deref_self_ty); + then { + span_lint_and_then( + cx, + INEFFICIENT_TO_STRING, + expr.span, + &format!("calling `to_string` on `{}`", arg_ty), + |db| { + db.help(&format!( + "`{}` implements `ToString` through the blanket impl, but `{}` specializes `ToString` directly", + self_ty, deref_self_ty + )); + let mut applicability = Applicability::MachineApplicable; + let arg_snippet = snippet_with_applicability(cx, arg.span, "..", &mut applicability); + db.span_suggestion( + expr.span, + "try dereferencing the receiver", + format!("({}{}).to_string()", "*".repeat(deref_count), arg_snippet), + applicability, + ); + }, + ); + } + } +} + +/// Returns whether `ty` specializes `ToString`. +/// Currently, these are `str`, `String`, and `Cow<'_, str>`. +fn specializes_tostring(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool { + match ty.kind { + ty::Str => true, + ty::Adt(adt, substs) => { + match_def_path(cx, adt.did, &paths::STRING) + || (match_def_path(cx, adt.did, &paths::COW) && substs.type_at(1).is_str()) + }, + _ => false, + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 848e3bcb881..efa283b823d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,4 @@ +mod inefficient_to_string; mod manual_saturating_arithmetic; mod option_map_unwrap_or; mod unnecessary_filter_map; @@ -589,6 +590,29 @@ declare_clippy_lint! { "using `clone` on `&&T`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `.to_string()` on an `&&T` where + /// `T` implements `ToString` directly (like `&&str` or `&&String`). + /// + /// **Why is this bad?** This bypasses the specialized implementation of + /// `ToString` and instead goes through the more expensive string formatting + /// facilities. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// // Generic implementation for `T: Display` is used (slow) + /// ["foo", "bar"].iter().map(|s| s.to_string()); + /// + /// // OK, the specialized impl is used + /// ["foo", "bar"].iter().map(|&s| s.to_string()); + /// ``` + pub INEFFICIENT_TO_STRING, + perf, + "using `to_string` on `&&T` where `T: ToString`" +} + declare_clippy_lint! { /// **What it does:** Checks for `new` not returning `Self`. /// @@ -1029,6 +1053,7 @@ declare_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, + INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, SEARCH_IS_SOME, @@ -1122,6 +1147,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { lint_clone_on_copy(cx, expr, &args[0], self_ty); lint_clone_on_ref_ptr(cx, expr, &args[0]); } + if args.len() == 1 && method_call.ident.name == sym!(to_string) { + inefficient_to_string::lint(cx, expr, &args[0], self_ty); + } match self_ty.kind { ty::Ref(_, ty, _) if ty.kind == ty::Str => { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index d9ae1f70d42..1575f0e3027 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 325] = [ +pub const ALL_LINTS: [Lint; 326] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -735,6 +735,13 @@ pub const ALL_LINTS: [Lint; 325] = [ deprecation: None, module: "bit_mask", }, + Lint { + name: "inefficient_to_string", + group: "perf", + desc: "using `to_string` on `&&T` where `T: ToString`", + deprecation: None, + module: "methods", + }, Lint { name: "infallible_destructuring_match", group: "style", diff --git a/tests/ui/inefficient_to_string.rs b/tests/ui/inefficient_to_string.rs new file mode 100644 index 00000000000..a9f8f244c19 --- /dev/null +++ b/tests/ui/inefficient_to_string.rs @@ -0,0 +1,31 @@ +#![deny(clippy::inefficient_to_string)] + +use std::borrow::Cow; +use std::string::ToString; + +fn main() { + let rstr: &str = "hello"; + let rrstr: &&str = &rstr; + let rrrstr: &&&str = &rrstr; + let _: String = rstr.to_string(); + let _: String = rrstr.to_string(); + let _: String = rrrstr.to_string(); + + let string: String = String::from("hello"); + let rstring: &String = &string; + let rrstring: &&String = &rstring; + let rrrstring: &&&String = &rrstring; + let _: String = string.to_string(); + let _: String = rstring.to_string(); + let _: String = rrstring.to_string(); + let _: String = rrrstring.to_string(); + + let cow: Cow<'_, str> = Cow::Borrowed("hello"); + let rcow: &Cow<'_, str> = &cow; + let rrcow: &&Cow<'_, str> = &rcow; + let rrrcow: &&&Cow<'_, str> = &rrcow; + let _: String = cow.to_string(); + let _: String = rcow.to_string(); + let _: String = rrcow.to_string(); + let _: String = rrrcow.to_string(); +} diff --git a/tests/ui/inefficient_to_string.stderr b/tests/ui/inefficient_to_string.stderr new file mode 100644 index 00000000000..70e3c1e82c7 --- /dev/null +++ b/tests/ui/inefficient_to_string.stderr @@ -0,0 +1,55 @@ +error: calling `to_string` on `&&str` + --> $DIR/inefficient_to_string.rs:11:21 + | +LL | let _: String = rrstr.to_string(); + | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()` + | +note: lint level defined here + --> $DIR/inefficient_to_string.rs:1:9 + | +LL | #![deny(clippy::inefficient_to_string)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: `&str` implements `ToString` through the blanket impl, but `str` specializes `ToString` directly + +error: calling `to_string` on `&&&str` + --> $DIR/inefficient_to_string.rs:12:21 + | +LL | let _: String = rrrstr.to_string(); + | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstr).to_string()` + | + = help: `&&str` implements `ToString` through the blanket impl, but `str` specializes `ToString` directly + +error: calling `to_string` on `&&std::string::String` + --> $DIR/inefficient_to_string.rs:20:21 + | +LL | let _: String = rrstring.to_string(); + | ^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstring).to_string()` + | + = help: `&std::string::String` implements `ToString` through the blanket impl, but `std::string::String` specializes `ToString` directly + +error: calling `to_string` on `&&&std::string::String` + --> $DIR/inefficient_to_string.rs:21:21 + | +LL | let _: String = rrrstring.to_string(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstring).to_string()` + | + = help: `&&std::string::String` implements `ToString` through the blanket impl, but `std::string::String` specializes `ToString` directly + +error: calling `to_string` on `&&std::borrow::Cow<'_, str>` + --> $DIR/inefficient_to_string.rs:29:21 + | +LL | let _: String = rrcow.to_string(); + | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()` + | + = help: `&std::borrow::Cow<'_, str>` implements `ToString` through the blanket impl, but `std::borrow::Cow<'_, str>` specializes `ToString` directly + +error: calling `to_string` on `&&&std::borrow::Cow<'_, str>` + --> $DIR/inefficient_to_string.rs:30:21 + | +LL | let _: String = rrrcow.to_string(); + | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()` + | + = help: `&&std::borrow::Cow<'_, str>` implements `ToString` through the blanket impl, but `std::borrow::Cow<'_, str>` specializes `ToString` directly + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From 98dc3aabeaf4102669d46912fb9def5f125a05ca Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" <heinz@licenser.net> Date: Sat, 12 Oct 2019 13:26:14 +0200 Subject: Add todo and tests --- CHANGELOG.md | 3 +++ README.md | 2 +- clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/panic_unimplemented.rs | 23 +++++++++++++++++++++-- src/lintlist/mod.rs | 23 ++++++++++++++++++++++- tests/ui/panic.rs | 12 ++++++++++++ tests/ui/panic.stderr | 10 ++++++++++ tests/ui/panic_unimplemented.rs | 9 ++++++++- tests/ui/panic_unimplemented.stderr | 10 +++++++++- 9 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 tests/ui/panic.rs create mode 100644 tests/ui/panic.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ab00001d9..5ce2eb4d5de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1138,6 +1138,7 @@ Released 2018-09-13 [`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional +[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl @@ -1198,6 +1199,7 @@ Released 2018-09-13 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg @@ -1227,6 +1229,7 @@ Released 2018-09-13 [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern +[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization diff --git a/README.md b/README.md index 5023538c5ed..7913a3eefda 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 326 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 329 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ccc5b74de30..9fca5a4b97a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -631,7 +631,10 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc::FLOAT_CMP_CONST, missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + panic_unimplemented::PANIC, + panic_unimplemented::TODO, panic_unimplemented::UNIMPLEMENTED, + panic_unimplemented::UNREACHABLE, shadow::SHADOW_REUSE, shadow::SHADOW_SAME, strings::STRING_ADD, diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index bbb037ad8eb..6981ecff0d0 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -57,6 +57,22 @@ declare_clippy_lint! { "`unimplemented!` should not be present in production code" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `todo!`. + /// + /// **Why is this bad?** This macro should not be present in production code + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```no_run + /// todo!(); + /// ``` + pub TODO, + restriction, + "`todo!` should not be present in production code" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `unreachable!`. /// @@ -73,7 +89,7 @@ declare_clippy_lint! { "`unreachable!` should not be present in production code" } -declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE]); +declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { @@ -87,6 +103,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PanicUnimplemented { let span = get_outer_span(expr); span_lint(cx, UNIMPLEMENTED, span, "`unimplemented` should not be present in production code"); + } else if is_expn_of(expr.span, "todo").is_some() { + let span = get_outer_span(expr); + span_lint(cx, TODO, span, + "`todo` should not be present in production code"); } else if is_expn_of(expr.span, "unreachable").is_some() { let span = get_outer_span(expr); span_lint(cx, UNREACHABLE, span, @@ -95,7 +115,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PanicUnimplemented { let span = get_outer_span(expr); span_lint(cx, PANIC, span, "`panic` should not be present in production code"); - //} else { match_panic(params, expr, cx); } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1575f0e3027..24e01f32780 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 326] = [ +pub const ALL_LINTS: [Lint; 329] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1456,6 +1456,13 @@ pub const ALL_LINTS: [Lint; 326] = [ deprecation: None, module: "overflow_check_conditional", }, + Lint { + name: "panic", + group: "restriction", + desc: "missing parameters in `panic!` calls", + deprecation: None, + module: "panic_unimplemented", + }, Lint { name: "panic_params", group: "style", @@ -1848,6 +1855,13 @@ pub const ALL_LINTS: [Lint; 326] = [ deprecation: None, module: "methods", }, + Lint { + name: "todo", + group: "restriction", + desc: "`todo!` should not be present in production code", + deprecation: None, + module: "panic_unimplemented", + }, Lint { name: "too_many_arguments", group: "complexity", @@ -2051,6 +2065,13 @@ pub const ALL_LINTS: [Lint; 326] = [ deprecation: None, module: "misc_early", }, + Lint { + name: "unreachable", + group: "restriction", + desc: "`unreachable!` should not be present in production code", + deprecation: None, + module: "panic_unimplemented", + }, Lint { name: "unreadable_literal", group: "style", diff --git a/tests/ui/panic.rs b/tests/ui/panic.rs new file mode 100644 index 00000000000..dee3104774c --- /dev/null +++ b/tests/ui/panic.rs @@ -0,0 +1,12 @@ +#![warn(clippy::panic)] +#![allow(clippy::assertions_on_constants)] + +fn panic() { + let a = 2; + panic!(); + let b = a + 2; +} + +fn main() { + panic(); +} diff --git a/tests/ui/panic.stderr b/tests/ui/panic.stderr new file mode 100644 index 00000000000..cfef1a16e49 --- /dev/null +++ b/tests/ui/panic.stderr @@ -0,0 +1,10 @@ +error: `panic` should not be present in production code + --> $DIR/panic.rs:6:5 + | +LL | panic!(); + | ^^^^^^^^^ + | + = note: `-D clippy::panic` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/panic_unimplemented.rs b/tests/ui/panic_unimplemented.rs index fed82f13515..f3dae3bbde6 100644 --- a/tests/ui/panic_unimplemented.rs +++ b/tests/ui/panic_unimplemented.rs @@ -1,4 +1,4 @@ -#![warn(clippy::panic_params, clippy::unimplemented, clippy::unreachable)] +#![warn(clippy::panic_params, clippy::unimplemented, clippy::unreachable, clippy::todo)] #![allow(clippy::assertions_on_constants)] fn missing() { if true { @@ -62,6 +62,12 @@ fn unreachable() { let b = a + 2; } +fn todo() { + let a = 2; + todo!(); + let b = a + 2; +} + fn main() { missing(); ok_single(); @@ -72,4 +78,5 @@ fn main() { ok_escaped(); unimplemented(); unreachable(); + todo(); } diff --git a/tests/ui/panic_unimplemented.stderr b/tests/ui/panic_unimplemented.stderr index 5f19b35fe6c..6d847e8df3e 100644 --- a/tests/ui/panic_unimplemented.stderr +++ b/tests/ui/panic_unimplemented.stderr @@ -40,5 +40,13 @@ LL | unreachable!(); | = note: `-D clippy::unreachable` implied by `-D warnings` -error: aborting due to 6 previous errors +error: `todo` should not be present in production code + --> $DIR/panic_unimplemented.rs:67:5 + | +LL | todo!(); + | ^^^^^^^^ + | + = note: `-D clippy::todo` implied by `-D warnings` + +error: aborting due to 7 previous errors -- cgit 1.4.1-3-g733a5 From 7f454d8d06279663a330cfc4c9248056c402acd1 Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" <heinz@licenser.net> Date: Wed, 16 Oct 2019 19:43:26 +0200 Subject: Split out tests --- CHANGELOG.md | 2 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 6 ++- clippy_lints/src/panic_unimplemented.rs | 2 +- src/lintlist/mod.rs | 18 +++++++- tests/ui/expect.rs | 16 +++++++ tests/ui/expect.stderr | 18 ++++++++ tests/ui/methods.rs | 14 ++---- tests/ui/methods.stderr | 10 +--- tests/ui/panic.rs | 61 +++++++++++++++++++++--- tests/ui/panic.stderr | 30 +++++++++--- tests/ui/panic_unimplemented.rs | 82 --------------------------------- tests/ui/panic_unimplemented.stderr | 52 --------------------- tests/ui/panicking_macros.rs | 33 +++++++++++++ tests/ui/panicking_macros.stderr | 34 ++++++++++++++ tests/ui/unwrap.rs | 16 +++++++ tests/ui/unwrap.stderr | 18 ++++++++ 18 files changed, 245 insertions(+), 171 deletions(-) create mode 100644 tests/ui/expect.rs create mode 100644 tests/ui/expect.stderr delete mode 100644 tests/ui/panic_unimplemented.rs delete mode 100644 tests/ui/panic_unimplemented.stderr create mode 100644 tests/ui/panicking_macros.rs create mode 100644 tests/ui/panicking_macros.stderr create mode 100644 tests/ui/unwrap.rs create mode 100644 tests/ui/unwrap.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ce2eb4d5de..ef21695cbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1129,6 +1129,7 @@ Released 2018-09-13 [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some +[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or @@ -1168,6 +1169,7 @@ Released 2018-09-13 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts +[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used diff --git a/README.md b/README.md index 7913a3eefda..41b8b4199ec 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 329 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 331 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9fca5a4b97a..bff1952cce7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -625,7 +625,9 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con mem_forget::MEM_FORGET, methods::CLONE_ON_REF_PTR, methods::GET_UNWRAP, + methods::OPTION_EXPECT_USED, methods::OPTION_UNWRAP_USED, + methods::RESULT_EXPECT_USED, methods::RESULT_UNWRAP_USED, methods::WRONG_PUB_SELF_CONVENTION, misc::FLOAT_CMP_CONST, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ac8a1dbdac3..74538164f8e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -111,9 +111,10 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ```ignore /// let opt = Some(1); /// opt?; + /// # Some::<()>(()) /// ``` pub OPTION_EXPECT_USED, restriction, @@ -139,9 +140,10 @@ declare_clippy_lint! { /// /// Better: /// - /// ```rust + /// ``` /// let res: Result<usize, ()> = Ok(1); /// res?; + /// # Ok::<(), ()>(()) /// ``` pub RESULT_EXPECT_USED, restriction, diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 94efb5acc00..87ef5f9034c 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { /// ``` pub PANIC, restriction, - "missing parameters in `panic!` calls" + "usage of the `panic!` macro" } declare_clippy_lint! { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 24e01f32780..f44ef226847 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 329] = [ +pub const ALL_LINTS: [Lint; 331] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1393,6 +1393,13 @@ pub const ALL_LINTS: [Lint; 329] = [ deprecation: None, module: "methods", }, + Lint { + name: "option_expect_used", + group: "restriction", + desc: "using `Option.expect()`, which might be better handled", + deprecation: None, + module: "methods", + }, Lint { name: "option_map_or_none", group: "style", @@ -1459,7 +1466,7 @@ pub const ALL_LINTS: [Lint; 329] = [ Lint { name: "panic", group: "restriction", - desc: "missing parameters in `panic!` calls", + desc: "usage of the `panic!` macro", deprecation: None, module: "panic_unimplemented", }, @@ -1659,6 +1666,13 @@ pub const ALL_LINTS: [Lint; 329] = [ deprecation: None, module: "replace_consts", }, + Lint { + name: "result_expect_used", + group: "restriction", + desc: "using `Result.expect()`, which might be better handled", + deprecation: None, + module: "methods", + }, Lint { name: "result_map_unit_fn", group: "complexity", diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs new file mode 100644 index 00000000000..0bd4252c49a --- /dev/null +++ b/tests/ui/expect.rs @@ -0,0 +1,16 @@ +#![warn(clippy::option_expect_used, clippy::result_expect_used)] + +fn expect_option() { + let opt = Some(0); + let _ = opt.expect(""); +} + +fn expect_result() { + let res: Result<u8, ()> = Ok(0); + let _ = res.expect(""); +} + +fn main() { + expect_option(); + expect_result(); +} diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr new file mode 100644 index 00000000000..4f954f611a6 --- /dev/null +++ b/tests/ui/expect.stderr @@ -0,0 +1,18 @@ +error: used expect() on an Option value. If this value is an None it will panic + --> $DIR/expect.rs:5:13 + | +LL | let _ = opt.expect(""); + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::option-expect-used` implied by `-D warnings` + +error: used expect() on a Result value. If this value is an Err it will panic + --> $DIR/expect.rs:10:13 + | +LL | let _ = res.expect(""); + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::result-expect-used` implied by `-D warnings` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index ca8358754ee..847a0f0f339 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,13 +1,7 @@ // aux-build:option_helpers.rs // compile-flags: --edition 2018 -#![warn( - clippy::all, - clippy::pedantic, - clippy::option_unwrap_used, - clippy::option_expect_used, - clippy::result_expect_used -)] +#![warn(clippy::all, clippy::pedantic)] #![allow( clippy::blacklisted_name, clippy::default_trait_access, @@ -307,8 +301,8 @@ fn search_is_some() { let _ = foo.rposition().is_some(); } -#[allow(clippy::similar_names)] fn main() { - let opt = Some(0); - let _ = opt.unwrap(); + option_methods(); + filter_next(); + search_is_some(); } diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index c3dc08be00b..af7bd4a6a9d 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -206,13 +206,5 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message - --> $DIR/methods.rs:307:13 - | -LL | let _ = opt.unwrap(); - | ^^^^^^^^^^^^ - | - = note: `-D clippy::option-unwrap-used` implied by `-D warnings` - -error: aborting due to 24 previous errors +error: aborting due to 23 previous errors diff --git a/tests/ui/panic.rs b/tests/ui/panic.rs index dee3104774c..6e004aa9a92 100644 --- a/tests/ui/panic.rs +++ b/tests/ui/panic.rs @@ -1,12 +1,61 @@ -#![warn(clippy::panic)] +#![warn(clippy::panic_params)] #![allow(clippy::assertions_on_constants)] +fn missing() { + if true { + panic!("{}"); + } else if false { + panic!("{:?}"); + } else { + assert!(true, "here be missing values: {}"); + } -fn panic() { - let a = 2; - panic!(); - let b = a + 2; + panic!("{{{this}}}"); +} + +fn ok_single() { + panic!("foo bar"); +} + +fn ok_inner() { + // Test for #768 + assert!("foo bar".contains(&format!("foo {}", "bar"))); +} + +fn ok_multiple() { + panic!("{}", "This is {ok}"); +} + +fn ok_bracket() { + match 42 { + 1337 => panic!("{so is this"), + 666 => panic!("so is this}"), + _ => panic!("}so is that{"), + } +} + +const ONE: u32 = 1; + +fn ok_nomsg() { + assert!({ 1 == ONE }); + assert!(if 1 == ONE { ONE == 1 } else { false }); +} + +fn ok_escaped() { + panic!("{{ why should this not be ok? }}"); + panic!(" or {{ that ?"); + panic!(" or }} this ?"); + panic!(" {or {{ that ?"); + panic!(" }or }} this ?"); + panic!("{{ test }"); + panic!("{case }}"); } fn main() { - panic(); + missing(); + ok_single(); + ok_multiple(); + ok_bracket(); + ok_inner(); + ok_nomsg(); + ok_escaped(); } diff --git a/tests/ui/panic.stderr b/tests/ui/panic.stderr index cfef1a16e49..1f8ff8ccf55 100644 --- a/tests/ui/panic.stderr +++ b/tests/ui/panic.stderr @@ -1,10 +1,28 @@ -error: `panic` should not be present in production code - --> $DIR/panic.rs:6:5 +error: you probably are missing some parameter in your format string + --> $DIR/panic.rs:5:16 | -LL | panic!(); - | ^^^^^^^^^ +LL | panic!("{}"); + | ^^^^ | - = note: `-D clippy::panic` implied by `-D warnings` + = note: `-D clippy::panic-params` implied by `-D warnings` -error: aborting due to previous error +error: you probably are missing some parameter in your format string + --> $DIR/panic.rs:7:16 + | +LL | panic!("{:?}"); + | ^^^^^^ + +error: you probably are missing some parameter in your format string + --> $DIR/panic.rs:9:23 + | +LL | assert!(true, "here be missing values: {}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: you probably are missing some parameter in your format string + --> $DIR/panic.rs:12:12 + | +LL | panic!("{{{this}}}"); + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/panic_unimplemented.rs b/tests/ui/panic_unimplemented.rs deleted file mode 100644 index f3dae3bbde6..00000000000 --- a/tests/ui/panic_unimplemented.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![warn(clippy::panic_params, clippy::unimplemented, clippy::unreachable, clippy::todo)] -#![allow(clippy::assertions_on_constants)] -fn missing() { - if true { - panic!("{}"); - } else if false { - panic!("{:?}"); - } else { - assert!(true, "here be missing values: {}"); - } - - panic!("{{{this}}}"); -} - -fn ok_single() { - panic!("foo bar"); -} - -fn ok_inner() { - // Test for #768 - assert!("foo bar".contains(&format!("foo {}", "bar"))); -} - -fn ok_multiple() { - panic!("{}", "This is {ok}"); -} - -fn ok_bracket() { - match 42 { - 1337 => panic!("{so is this"), - 666 => panic!("so is this}"), - _ => panic!("}so is that{"), - } -} - -const ONE: u32 = 1; - -fn ok_nomsg() { - assert!({ 1 == ONE }); - assert!(if 1 == ONE { ONE == 1 } else { false }); -} - -fn ok_escaped() { - panic!("{{ why should this not be ok? }}"); - panic!(" or {{ that ?"); - panic!(" or }} this ?"); - panic!(" {or {{ that ?"); - panic!(" }or }} this ?"); - panic!("{{ test }"); - panic!("{case }}"); -} - -fn unimplemented() { - let a = 2; - unimplemented!(); - let b = a + 2; -} - -fn unreachable() { - let a = 2; - unreachable!(); - let b = a + 2; -} - -fn todo() { - let a = 2; - todo!(); - let b = a + 2; -} - -fn main() { - missing(); - ok_single(); - ok_multiple(); - ok_bracket(); - ok_inner(); - ok_nomsg(); - ok_escaped(); - unimplemented(); - unreachable(); - todo(); -} diff --git a/tests/ui/panic_unimplemented.stderr b/tests/ui/panic_unimplemented.stderr deleted file mode 100644 index 6d847e8df3e..00000000000 --- a/tests/ui/panic_unimplemented.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:5:16 - | -LL | panic!("{}"); - | ^^^^ - | - = note: `-D clippy::panic-params` implied by `-D warnings` - -error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:7:16 - | -LL | panic!("{:?}"); - | ^^^^^^ - -error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:9:23 - | -LL | assert!(true, "here be missing values: {}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you probably are missing some parameter in your format string - --> $DIR/panic_unimplemented.rs:12:12 - | -LL | panic!("{{{this}}}"); - | ^^^^^^^^^^^^ - -error: `unimplemented` should not be present in production code - --> $DIR/panic_unimplemented.rs:55:5 - | -LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unimplemented` implied by `-D warnings` - -error: `unreachable` should not be present in production code - --> $DIR/panic_unimplemented.rs:61:5 - | -LL | unreachable!(); - | ^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unreachable` implied by `-D warnings` - -error: `todo` should not be present in production code - --> $DIR/panic_unimplemented.rs:67:5 - | -LL | todo!(); - | ^^^^^^^^ - | - = note: `-D clippy::todo` implied by `-D warnings` - -error: aborting due to 7 previous errors - diff --git a/tests/ui/panicking_macros.rs b/tests/ui/panicking_macros.rs new file mode 100644 index 00000000000..dabb695368d --- /dev/null +++ b/tests/ui/panicking_macros.rs @@ -0,0 +1,33 @@ +#![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)] +#![allow(clippy::assertions_on_constants)] + +fn panic() { + let a = 2; + panic!(); + let b = a + 2; +} + +fn todo() { + let a = 2; + todo!(); + let b = a + 2; +} + +fn unimplemented() { + let a = 2; + unimplemented!(); + let b = a + 2; +} + +fn unreachable() { + let a = 2; + unreachable!(); + let b = a + 2; +} + +fn main() { + panic(); + todo(); + unimplemented(); + unreachable(); +} diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr new file mode 100644 index 00000000000..72319bc7e45 --- /dev/null +++ b/tests/ui/panicking_macros.stderr @@ -0,0 +1,34 @@ +error: `panic` should not be present in production code + --> $DIR/panicking_macros.rs:6:5 + | +LL | panic!(); + | ^^^^^^^^^ + | + = note: `-D clippy::panic` implied by `-D warnings` + +error: `todo` should not be present in production code + --> $DIR/panicking_macros.rs:12:5 + | +LL | todo!(); + | ^^^^^^^^ + | + = note: `-D clippy::todo` implied by `-D warnings` + +error: `unimplemented` should not be present in production code + --> $DIR/panicking_macros.rs:18:5 + | +LL | unimplemented!(); + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unimplemented` implied by `-D warnings` + +error: `unreachable` should not be present in production code + --> $DIR/panicking_macros.rs:24:5 + | +LL | unreachable!(); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unreachable` implied by `-D warnings` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs new file mode 100644 index 00000000000..fcd1fcd14d4 --- /dev/null +++ b/tests/ui/unwrap.rs @@ -0,0 +1,16 @@ +#![warn(clippy::option_unwrap_used, clippy::result_unwrap_used)] + +fn unwrap_option() { + let opt = Some(0); + let _ = opt.unwrap(); +} + +fn unwrap_result() { + let res: Result<u8, ()> = Ok(0); + let _ = res.unwrap(); +} + +fn main() { + unwrap_option(); + unwrap_result(); +} diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr new file mode 100644 index 00000000000..cde3ceffd9d --- /dev/null +++ b/tests/ui/unwrap.stderr @@ -0,0 +1,18 @@ +error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message + --> $DIR/unwrap.rs:5:13 + | +LL | let _ = opt.unwrap(); + | ^^^^^^^^^^^^ + | + = note: `-D clippy::option-unwrap-used` implied by `-D warnings` + +error: used unwrap() on a Result value. If you don't want to handle the Err case gracefully, consider using expect() to provide a better panic message + --> $DIR/unwrap.rs:10:13 + | +LL | let _ = res.unwrap(); + | ^^^^^^^^^^^^ + | + = note: `-D clippy::result-unwrap-used` implied by `-D warnings` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 5572476a36f85959ec820d0886548a747ce0570a Mon Sep 17 00:00:00 2001 From: Marcel Hellwig <git@cookiesoft.de> Date: Wed, 16 Oct 2019 13:25:42 +0200 Subject: Add lint for debug_assert_with_mut_call This lint will complain when you put a mutable function/method call inside a `debug_assert` macro, because it will not be executed in release mode, therefore it will change the execution flow, which is not wanted. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 + clippy_lints/src/mutable_debug_assertion.rs | 155 +++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +- tests/ui/debug_assert_with_mut_call.rs | 124 ++++++++++++++++++++ tests/ui/debug_assert_with_mut_call.stderr | 172 ++++++++++++++++++++++++++++ 7 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/mutable_debug_assertion.rs create mode 100644 tests/ui/debug_assert_with_mut_call.rs create mode 100644 tests/ui/debug_assert_with_mut_call.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index ef21695cbab..7b32914854f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -966,6 +966,7 @@ Released 2018-09-13 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro +[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access diff --git a/README.md b/README.md index 41b8b4199ec..87ef441eadd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 331 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 332 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bff1952cce7..8f0b3c21682 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -230,6 +230,7 @@ pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_mut; pub mod mut_reference; +pub mod mutable_debug_assertion; pub mod mutex_atomic; pub mod needless_bool; pub mod needless_borrow; @@ -610,6 +611,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con reg.register_late_lint_pass(box comparison_chain::ComparisonChain); reg.register_late_lint_pass(box mul_add::MulAddCheck); reg.register_late_lint_pass(box unused_self::UnusedSelf); + reg.register_late_lint_pass(box mutable_debug_assertion::DebugAssertWithMutCall); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -855,6 +857,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc_early::ZERO_PREFIXED_LITERAL, mul_add::MANUAL_MUL_ADD, mut_reference::UNNECESSARY_MUT_PASSED, + mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, mutex_atomic::MUTEX_ATOMIC, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, @@ -1160,6 +1163,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con misc::CMP_NAN, misc::FLOAT_CMP, misc::MODULO_ONE, + mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, open_options::NONSENSICAL_OPEN_OPTIONS, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs new file mode 100644 index 00000000000..1184db0587b --- /dev/null +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -0,0 +1,155 @@ +use crate::utils::{is_direct_expn_of, span_lint}; +use if_chain::if_chain; +use matches::matches; +use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc::hir::{Expr, ExprKind, Mutability, StmtKind, UnOp}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint, ty}; +use syntax_pos::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for function/method calls with a mutable + /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros. + /// + /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the + /// compiler. + /// Therefore mutating something in a `debug_assert!` macro results in different behaviour + /// between a release and debug build. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust,ignore + /// debug_assert_eq!(vec![3].pop(), Some(3)); + /// // or + /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() } + /// debug_assert!(take_a_mut_parameter(&mut 5)); + /// ``` + pub DEBUG_ASSERT_WITH_MUT_CALL, + correctness, + "mutable arguments in `debug_assert{,_ne,_eq}!`" +} + +declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]); + +const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"]; + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { + for dmn in &DEBUG_MACRO_NAMES { + if is_direct_expn_of(e.span, dmn).is_some() { + if let Some(span) = extract_call(cx, e) { + span_lint( + cx, + DEBUG_ASSERT_WITH_MUT_CALL, + span, + &format!("do not call a function with mutable arguments inside of `{}!`", dmn), + ); + } + } + } + } +} + +//HACK(hellow554): remove this when #4694 is implemented +#[allow(clippy::cognitive_complexity)] +fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Span> { + if_chain! { + if let ExprKind::Block(ref block, _) = e.kind; + if block.stmts.len() == 1; + if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind; + then { + if_chain! { + if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind; + if let ExprKind::DropTemps(ref droptmp) = ifclause.kind; + if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind; + then { + // debug_assert + let mut visitor = MutArgVisitor::new(cx); + visitor.visit_expr(condition); + return visitor.expr_span(); + } else { + // debug_assert_{eq,ne} + if_chain! { + if let ExprKind::Block(ref matchblock, _) = matchexpr.kind; + if let Some(ref matchheader) = matchblock.expr; + if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind; + if let ExprKind::Tup(ref conditions) = headerexpr.kind; + if conditions.len() == 2; + then { + if let ExprKind::AddrOf(_, ref lhs) = conditions[0].kind { + let mut visitor = MutArgVisitor::new(cx); + visitor.visit_expr(lhs); + if let Some(span) = visitor.expr_span() { + return Some(span); + } + } + if let ExprKind::AddrOf(_, ref rhs) = conditions[1].kind { + let mut visitor = MutArgVisitor::new(cx); + visitor.visit_expr(rhs); + if let Some(span) = visitor.expr_span() { + return Some(span); + } + } + } + } + } + } + } + } + + None +} + +struct MutArgVisitor<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + expr_span: Option<Span>, + found: bool, +} + +impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'a, 'tcx>) -> Self { + Self { + cx, + expr_span: None, + found: false, + } + } + + fn expr_span(&self) -> Option<Span> { + if self.found { + self.expr_span + } else { + None + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr) { + match expr.kind { + ExprKind::AddrOf(Mutability::MutMutable, _) => { + self.found = true; + return; + }, + ExprKind::Path(_) => { + if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) { + if adj + .iter() + .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::MutMutable))) + { + self.found = true; + return; + } + } + }, + _ if !self.found => self.expr_span = Some(expr.span), + _ => return, + } + walk_expr(self, expr) + } + + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir()) + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f44ef226847..48ca368f5a9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 331] = [ +pub const ALL_LINTS: [Lint; 332] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -280,6 +280,13 @@ pub const ALL_LINTS: [Lint; 331] = [ deprecation: None, module: "dbg_macro", }, + Lint { + name: "debug_assert_with_mut_call", + group: "correctness", + desc: "mutable arguments in `debug_assert{,_ne,_eq}!`", + deprecation: None, + module: "mutable_debug_assertion", + }, Lint { name: "decimal_literal_representation", group: "restriction", diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs new file mode 100644 index 00000000000..a588547b943 --- /dev/null +++ b/tests/ui/debug_assert_with_mut_call.rs @@ -0,0 +1,124 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] +#![allow(clippy::trivially_copy_pass_by_ref, clippy::cognitive_complexity, clippy::redundant_closure_call)] + +struct S; + +impl S { + fn bool_self_ref(&self) -> bool { false } + fn bool_self_mut(&mut self) -> bool { false } + fn bool_self_ref_arg_ref(&self, _: &u32) -> bool { false } + fn bool_self_ref_arg_mut(&self, _: &mut u32) -> bool { false } + fn bool_self_mut_arg_ref(&mut self, _: &u32) -> bool { false } + fn bool_self_mut_arg_mut(&mut self, _: &mut u32) -> bool { false } + + fn u32_self_ref(&self) -> u32 { 0 } + fn u32_self_mut(&mut self) -> u32 { 0 } + fn u32_self_ref_arg_ref(&self, _: &u32) -> u32 { 0 } + fn u32_self_ref_arg_mut(&self, _: &mut u32) -> u32 { 0 } + fn u32_self_mut_arg_ref(&mut self, _: &u32) -> u32 { 0 } + fn u32_self_mut_arg_mut(&mut self, _: &mut u32) -> u32 { 0 } +} + +fn bool_ref(_: &u32) -> bool { false } +fn bool_mut(_: &mut u32) -> bool { false } +fn u32_ref(_: &u32) -> u32 { 0 } +fn u32_mut(_: &mut u32) -> u32 { 0 } + +fn func_non_mutable() { + debug_assert!(bool_ref(&3)); + debug_assert!(!bool_ref(&3)); + + debug_assert_eq!(0, u32_ref(&3)); + debug_assert_eq!(u32_ref(&3), 0); + + debug_assert_ne!(1, u32_ref(&3)); + debug_assert_ne!(u32_ref(&3), 1); +} + +fn func_mutable() { + debug_assert!(bool_mut(&mut 3)); + debug_assert!(!bool_mut(&mut 3)); + + debug_assert_eq!(0, u32_mut(&mut 3)); + debug_assert_eq!(u32_mut(&mut 3), 0); + + debug_assert_ne!(1, u32_mut(&mut 3)); + debug_assert_ne!(u32_mut(&mut 3), 1); +} + +fn method_non_mutable() { + debug_assert!(S.bool_self_ref()); + debug_assert!(S.bool_self_ref_arg_ref(&3)); + + debug_assert_eq!(S.u32_self_ref(), 0); + debug_assert_eq!(S.u32_self_ref_arg_ref(&3), 0); + + debug_assert_ne!(S.u32_self_ref(), 1); + debug_assert_ne!(S.u32_self_ref_arg_ref(&3), 1); +} + +fn method_mutable() { + debug_assert!(S.bool_self_mut()); + debug_assert!(!S.bool_self_mut()); + debug_assert!(S.bool_self_ref_arg_mut(&mut 3)); + debug_assert!(S.bool_self_mut_arg_ref(&3)); + debug_assert!(S.bool_self_mut_arg_mut(&mut 3)); + + debug_assert_eq!(S.u32_self_mut(), 0); + debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0); + debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0); + debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0); + + debug_assert_ne!(S.u32_self_mut(), 1); + debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1); + debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1); + debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1); +} + +fn misc() { + // with variable + let mut v: Vec<u32> = vec![1, 2, 3, 4]; + debug_assert_eq!(v.get(0), Some(&1)); + debug_assert_ne!(v[0], 2); + debug_assert_eq!(v.pop(), Some(1)); + debug_assert_ne!(Some(3), v.pop()); + + let a = &mut 3; + debug_assert!(bool_mut(a)); + + // nested + debug_assert!(!(bool_ref(&u32_mut(&mut 3)))); + + // chained + debug_assert_eq!(v.pop().unwrap(), 3); + + // format args + debug_assert!(bool_ref(&3), "w/o format"); + debug_assert!(bool_mut(&mut 3), "w/o format"); + debug_assert!(bool_ref(&3), "{} format", "w/"); + debug_assert!(bool_mut(&mut 3), "{} format", "w/"); + + // sub block + let mut x = 42_u32; + debug_assert!({ + bool_mut(&mut x); + x > 10 + }); + + // closures + debug_assert!((|| { + let mut x = 42; + bool_mut(&mut x); + x > 10 + })()); +} + +fn main() { + func_non_mutable(); + func_mutable(); + method_non_mutable(); + method_mutable(); + + misc(); +} diff --git a/tests/ui/debug_assert_with_mut_call.stderr b/tests/ui/debug_assert_with_mut_call.stderr new file mode 100644 index 00000000000..48c7f4ea85e --- /dev/null +++ b/tests/ui/debug_assert_with_mut_call.stderr @@ -0,0 +1,172 @@ +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:40:19 + | +LL | debug_assert!(bool_mut(&mut 3)); + | ^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::debug_assert_with_mut_call)]` on by default + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:41:20 + | +LL | debug_assert!(!bool_mut(&mut 3)); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:43:25 + | +LL | debug_assert_eq!(0, u32_mut(&mut 3)); + | ^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:44:22 + | +LL | debug_assert_eq!(u32_mut(&mut 3), 0); + | ^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:46:25 + | +LL | debug_assert_ne!(1, u32_mut(&mut 3)); + | ^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:47:22 + | +LL | debug_assert_ne!(u32_mut(&mut 3), 1); + | ^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:62:19 + | +LL | debug_assert!(S.bool_self_mut()); + | ^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:63:20 + | +LL | debug_assert!(!S.bool_self_mut()); + | ^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:64:19 + | +LL | debug_assert!(S.bool_self_ref_arg_mut(&mut 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:65:19 + | +LL | debug_assert!(S.bool_self_mut_arg_ref(&3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:66:19 + | +LL | debug_assert!(S.bool_self_mut_arg_mut(&mut 3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:68:22 + | +LL | debug_assert_eq!(S.u32_self_mut(), 0); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:69:22 + | +LL | debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:70:22 + | +LL | debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:71:22 + | +LL | debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:73:22 + | +LL | debug_assert_ne!(S.u32_self_mut(), 1); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:74:22 + | +LL | debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:75:22 + | +LL | debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:76:22 + | +LL | debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:84:22 + | +LL | debug_assert_eq!(v.pop(), Some(1)); + | ^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_ne!` + --> $DIR/debug_assert_with_mut_call.rs:85:31 + | +LL | debug_assert_ne!(Some(3), v.pop()); + | ^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:88:19 + | +LL | debug_assert!(bool_mut(a)); + | ^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:91:31 + | +LL | debug_assert!(!(bool_ref(&u32_mut(&mut 3)))); + | ^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert_eq!` + --> $DIR/debug_assert_with_mut_call.rs:94:22 + | +LL | debug_assert_eq!(v.pop().unwrap(), 3); + | ^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:98:19 + | +LL | debug_assert!(bool_mut(&mut 3), "w/o format"); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:100:19 + | +LL | debug_assert!(bool_mut(&mut 3), "{} format", "w/"); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:105:9 + | +LL | bool_mut(&mut x); + | ^^^^^^^^^^^^^^^^ + +error: do not call a function with mutable arguments inside of `debug_assert!` + --> $DIR/debug_assert_with_mut_call.rs:112:9 + | +LL | bool_mut(&mut x); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors + -- cgit 1.4.1-3-g733a5 From 7e77f3c29f9221ccd785aa99ffd8b6180d4c063d Mon Sep 17 00:00:00 2001 From: Mark Rousskov <mark.simulacrum@gmail.com> Date: Thu, 10 Oct 2019 21:46:22 -0400 Subject: Update clippy for latest rustc changes Specifically, this revises the clippy integration to utilize a new callback to register its lints, as the prior editing of lint store in Session is no longer possible. --- clippy_lints/src/lib.rs | 1917 ++++++++++++++---------- clippy_lints/src/trivially_copy_pass_by_ref.rs | 3 +- src/driver.rs | 57 +- src/lib.rs | 26 +- 4 files changed, 1149 insertions(+), 854 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8f0b3c21682..3512972c55e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -41,6 +41,9 @@ extern crate syntax_expand; #[allow(unused_extern_crates)] extern crate syntax_pos; +use rustc::lint::{self, LintId}; +use rustc::session::Session; +use rustc_data_structures::fx::FxHashSet; use toml; /// Macro used to declare a Clippy lint. @@ -303,33 +306,20 @@ mod reexport { /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints( - session: &rustc::session::Session, - store: &mut rustc::lint::LintStore, - conf: &Conf, -) { - store.register_pre_expansion_pass(Some(session), true, false, box write::Write); - store.register_pre_expansion_pass( - Some(session), - true, - false, - box redundant_field_names::RedundantFieldNames, - ); - store.register_pre_expansion_pass( - Some(session), - true, - false, - box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold: conf.single_char_binding_names_threshold, - }, - ); - store.register_pre_expansion_pass(Some(session), true, false, box attrs::DeprecatedCfgAttribute); - store.register_pre_expansion_pass(Some(session), true, false, box dbg_macro::DbgMacro); +pub fn register_pre_expansion_lints(store: &mut rustc::lint::LintStore, conf: &Conf) { + store.register_pre_expansion_pass(|| box write::Write); + store.register_pre_expansion_pass(|| box redundant_field_names::RedundantFieldNames); + let p = conf.single_char_binding_names_threshold; + store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold: p, + }); + store.register_pre_expansion_pass(|| box attrs::DeprecatedCfgAttribute); + store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); } #[doc(hidden)] -pub fn read_conf(reg: &rustc_driver::plugin::Registry<'_>) -> Conf { - match utils::conf::file_from_args(reg.args()) { +pub fn read_conf(args: &[syntax::ast::NestedMetaItem], sess: &Session) -> Conf { + match utils::conf::file_from_args(args) { Ok(file_name) => { // if the user specified a file, it must exist, otherwise default to `clippy.toml` but // do not require the file to exist @@ -339,18 +329,16 @@ pub fn read_conf(reg: &rustc_driver::plugin::Registry<'_>) -> Conf { match utils::conf::lookup_conf_file() { Ok(path) => path, Err(error) => { - reg.sess - .struct_err(&format!("error finding Clippy's configuration file: {}", error)) + sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)) .emit(); None - }, + } } }; let file_name = file_name.map(|file_name| { if file_name.is_relative() { - reg.sess - .local_crate_source_file + sess.local_crate_source_file .as_ref() .and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf)) .unwrap_or_default() @@ -364,24 +352,22 @@ pub fn read_conf(reg: &rustc_driver::plugin::Registry<'_>) -> Conf { // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - reg.sess - .struct_err(&format!( - "error reading Clippy's configuration file `{}`: {}", - file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), - error - )) - .emit(); + sess.struct_err(&format!( + "error reading Clippy's configuration file `{}`: {}", + file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), + error + )) + .emit(); } conf - }, + } Err((err, span)) => { - reg.sess - .struct_span_err(span, err) + sess.struct_span_err(span, err) .span_note(span, "Clippy will use default configuration") .emit(); toml::from_str("").expect("we never error on empty config files") - }, + } } } @@ -390,9 +376,8 @@ pub fn read_conf(reg: &rustc_driver::plugin::Registry<'_>) -> Conf { /// Used in `./src/driver.rs`. #[allow(clippy::too_many_lines)] #[rustfmt::skip] -pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Conf) { - let mut store = reg.sess.lint_store.borrow_mut(); - register_removed_non_tool_lints(&mut store); +pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf) { + register_removed_non_tool_lints(store); // begin deprecated lints, do not remove this comment, it’s used in `update_lints` store.register_removed( @@ -449,778 +434,1120 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` - reg.register_late_lint_pass(box serde_api::SerdeAPI); - reg.register_early_lint_pass(box utils::internal_lints::ClippyLintsInternal); - reg.register_late_lint_pass(box utils::internal_lints::CompilerLintFunctions::new()); - reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default()); - reg.register_late_lint_pass(box utils::internal_lints::OuterExpnDataPass); - reg.register_late_lint_pass(box utils::inspector::DeepCodeInspector); - reg.register_late_lint_pass(box utils::author::Author); - reg.register_late_lint_pass(box types::Types); - reg.register_late_lint_pass(box booleans::NonminimalBool); - reg.register_late_lint_pass(box eq_op::EqOp); - reg.register_early_lint_pass(box enum_variants::EnumVariantNames::new(conf.enum_variant_name_threshold)); - reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); - reg.register_late_lint_pass(box enum_clike::UnportableVariant); - reg.register_late_lint_pass(box excessive_precision::ExcessivePrecision); - reg.register_late_lint_pass(box bit_mask::BitMask::new(conf.verbose_bit_mask_threshold)); - reg.register_late_lint_pass(box ptr::Ptr); - reg.register_late_lint_pass(box needless_bool::NeedlessBool); - reg.register_late_lint_pass(box needless_bool::BoolComparison); - reg.register_late_lint_pass(box approx_const::ApproxConstant); - reg.register_late_lint_pass(box misc::MiscLints); - reg.register_early_lint_pass(box precedence::Precedence); - reg.register_early_lint_pass(box needless_continue::NeedlessContinue); - reg.register_late_lint_pass(box eta_reduction::EtaReduction); - reg.register_late_lint_pass(box identity_op::IdentityOp); - reg.register_late_lint_pass(box erasing_op::ErasingOp); - reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements); - reg.register_late_lint_pass(box mut_mut::MutMut); - reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed); - reg.register_late_lint_pass(box len_zero::LenZero); - reg.register_late_lint_pass(box attrs::Attributes); - reg.register_early_lint_pass(box collapsible_if::CollapsibleIf); - reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition); - reg.register_late_lint_pass(box unicode::Unicode); - reg.register_late_lint_pass(box strings::StringAdd); - reg.register_early_lint_pass(box returns::Return); - reg.register_late_lint_pass(box implicit_return::ImplicitReturn); - reg.register_late_lint_pass(box methods::Methods); - reg.register_late_lint_pass(box map_clone::MapClone); - reg.register_late_lint_pass(box shadow::Shadow); - reg.register_late_lint_pass(box types::LetUnitValue); - reg.register_late_lint_pass(box types::UnitCmp); - reg.register_late_lint_pass(box loops::Loops); - reg.register_late_lint_pass(box main_recursion::MainRecursion::default()); - reg.register_late_lint_pass(box lifetimes::Lifetimes); - reg.register_late_lint_pass(box entry::HashMapPass); - reg.register_late_lint_pass(box ranges::Ranges); - reg.register_late_lint_pass(box types::Casts); - reg.register_late_lint_pass(box types::TypeComplexity::new(conf.type_complexity_threshold)); - reg.register_late_lint_pass(box matches::Matches); - reg.register_late_lint_pass(box minmax::MinMaxPass); - reg.register_late_lint_pass(box open_options::OpenOptions); - reg.register_late_lint_pass(box zero_div_zero::ZeroDiv); - reg.register_late_lint_pass(box mutex_atomic::Mutex); - reg.register_late_lint_pass(box needless_update::NeedlessUpdate); - reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow::default()); - reg.register_late_lint_pass(box needless_borrowed_ref::NeedlessBorrowedRef); - reg.register_late_lint_pass(box no_effect::NoEffect); - reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignment); - reg.register_late_lint_pass(box transmute::Transmute); - reg.register_late_lint_pass( - box cognitive_complexity::CognitiveComplexity::new(conf.cognitive_complexity_threshold) + // begin register lints, do not remove this comment, it’s used in `update_lints` + store.register_lints(&[ + &approx_const::APPROX_CONSTANT, + &arithmetic::FLOAT_ARITHMETIC, + &arithmetic::INTEGER_ARITHMETIC, + &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, + &assign_ops::ASSIGN_OP_PATTERN, + &assign_ops::MISREFACTORED_ASSIGN_OP, + &attrs::DEPRECATED_CFG_ATTR, + &attrs::DEPRECATED_SEMVER, + &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, + &attrs::INLINE_ALWAYS, + &attrs::UNKNOWN_CLIPPY_LINTS, + &attrs::USELESS_ATTRIBUTE, + &bit_mask::BAD_BIT_MASK, + &bit_mask::INEFFECTIVE_BIT_MASK, + &bit_mask::VERBOSE_BIT_MASK, + &blacklisted_name::BLACKLISTED_NAME, + &block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, + &block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, + &booleans::LOGIC_BUG, + &booleans::NONMINIMAL_BOOL, + &bytecount::NAIVE_BYTECOUNT, + &cargo_common_metadata::CARGO_COMMON_METADATA, + &checked_conversions::CHECKED_CONVERSIONS, + &cognitive_complexity::COGNITIVE_COMPLEXITY, + &collapsible_if::COLLAPSIBLE_IF, + &comparison_chain::COMPARISON_CHAIN, + &copies::IFS_SAME_COND, + &copies::IF_SAME_THEN_ELSE, + &copies::MATCH_SAME_ARMS, + ©_iterator::COPY_ITERATOR, + &dbg_macro::DBG_MACRO, + &default_trait_access::DEFAULT_TRAIT_ACCESS, + &derive::DERIVE_HASH_XOR_EQ, + &derive::EXPL_IMPL_CLONE_ON_COPY, + &doc::DOC_MARKDOWN, + &doc::MISSING_SAFETY_DOC, + &doc::NEEDLESS_DOCTEST_MAIN, + &double_comparison::DOUBLE_COMPARISONS, + &double_parens::DOUBLE_PARENS, + &drop_bounds::DROP_BOUNDS, + &drop_forget_ref::DROP_COPY, + &drop_forget_ref::DROP_REF, + &drop_forget_ref::FORGET_COPY, + &drop_forget_ref::FORGET_REF, + &duration_subsec::DURATION_SUBSEC, + &else_if_without_else::ELSE_IF_WITHOUT_ELSE, + &empty_enum::EMPTY_ENUM, + &entry::MAP_ENTRY, + &enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, + &enum_glob_use::ENUM_GLOB_USE, + &enum_variants::ENUM_VARIANT_NAMES, + &enum_variants::MODULE_INCEPTION, + &enum_variants::MODULE_NAME_REPETITIONS, + &enum_variants::PUB_ENUM_VARIANT_NAMES, + &eq_op::EQ_OP, + &eq_op::OP_REF, + &erasing_op::ERASING_OP, + &escape::BOXED_LOCAL, + &eta_reduction::REDUNDANT_CLOSURE, + &eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + &eval_order_dependence::DIVERGING_SUB_EXPRESSION, + &eval_order_dependence::EVAL_ORDER_DEPENDENCE, + &excessive_precision::EXCESSIVE_PRECISION, + &explicit_write::EXPLICIT_WRITE, + &fallible_impl_from::FALLIBLE_IMPL_FROM, + &format::USELESS_FORMAT, + &formatting::POSSIBLE_MISSING_COMMA, + &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + &formatting::SUSPICIOUS_ELSE_FORMATTING, + &formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + &functions::DOUBLE_MUST_USE, + &functions::MUST_USE_CANDIDATE, + &functions::MUST_USE_UNIT, + &functions::NOT_UNSAFE_PTR_ARG_DEREF, + &functions::TOO_MANY_ARGUMENTS, + &functions::TOO_MANY_LINES, + &get_last_with_len::GET_LAST_WITH_LEN, + &identity_conversion::IDENTITY_CONVERSION, + &identity_op::IDENTITY_OP, + &if_not_else::IF_NOT_ELSE, + &implicit_return::IMPLICIT_RETURN, + &indexing_slicing::INDEXING_SLICING, + &indexing_slicing::OUT_OF_BOUNDS_INDEXING, + &infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, + &infinite_iter::INFINITE_ITER, + &infinite_iter::MAYBE_INFINITE_ITER, + &inherent_impl::MULTIPLE_INHERENT_IMPL, + &inherent_to_string::INHERENT_TO_STRING, + &inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, + &inline_fn_without_body::INLINE_FN_WITHOUT_BODY, + &int_plus_one::INT_PLUS_ONE, + &integer_division::INTEGER_DIVISION, + &items_after_statements::ITEMS_AFTER_STATEMENTS, + &large_enum_variant::LARGE_ENUM_VARIANT, + &len_zero::LEN_WITHOUT_IS_EMPTY, + &len_zero::LEN_ZERO, + &let_if_seq::USELESS_LET_IF_SEQ, + &lifetimes::EXTRA_UNUSED_LIFETIMES, + &lifetimes::NEEDLESS_LIFETIMES, + &literal_representation::DECIMAL_LITERAL_REPRESENTATION, + &literal_representation::INCONSISTENT_DIGIT_GROUPING, + &literal_representation::LARGE_DIGIT_GROUPS, + &literal_representation::MISTYPED_LITERAL_SUFFIXES, + &literal_representation::UNREADABLE_LITERAL, + &loops::EMPTY_LOOP, + &loops::EXPLICIT_COUNTER_LOOP, + &loops::EXPLICIT_INTO_ITER_LOOP, + &loops::EXPLICIT_ITER_LOOP, + &loops::FOR_KV_MAP, + &loops::FOR_LOOP_OVER_OPTION, + &loops::FOR_LOOP_OVER_RESULT, + &loops::ITER_NEXT_LOOP, + &loops::MANUAL_MEMCPY, + &loops::MUT_RANGE_BOUND, + &loops::NEEDLESS_COLLECT, + &loops::NEEDLESS_RANGE_LOOP, + &loops::NEVER_LOOP, + &loops::REVERSE_RANGE_LOOP, + &loops::WHILE_IMMUTABLE_CONDITION, + &loops::WHILE_LET_LOOP, + &loops::WHILE_LET_ON_ITERATOR, + &main_recursion::MAIN_RECURSION, + &map_clone::MAP_CLONE, + &map_unit_fn::OPTION_MAP_UNIT_FN, + &map_unit_fn::RESULT_MAP_UNIT_FN, + &matches::MATCH_AS_REF, + &matches::MATCH_BOOL, + &matches::MATCH_OVERLAPPING_ARM, + &matches::MATCH_REF_PATS, + &matches::MATCH_WILD_ERR_ARM, + &matches::SINGLE_MATCH, + &matches::SINGLE_MATCH_ELSE, + &matches::WILDCARD_ENUM_MATCH_ARM, + &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, + &mem_forget::MEM_FORGET, + &mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + &mem_replace::MEM_REPLACE_WITH_UNINIT, + &methods::CHARS_LAST_CMP, + &methods::CHARS_NEXT_CMP, + &methods::CLONE_DOUBLE_REF, + &methods::CLONE_ON_COPY, + &methods::CLONE_ON_REF_PTR, + &methods::EXPECT_FUN_CALL, + &methods::FILTER_MAP, + &methods::FILTER_MAP_NEXT, + &methods::FILTER_NEXT, + &methods::FIND_MAP, + &methods::FLAT_MAP_IDENTITY, + &methods::GET_UNWRAP, + &methods::INEFFICIENT_TO_STRING, + &methods::INTO_ITER_ON_ARRAY, + &methods::INTO_ITER_ON_REF, + &methods::ITER_CLONED_COLLECT, + &methods::ITER_NTH, + &methods::ITER_SKIP_NEXT, + &methods::MANUAL_SATURATING_ARITHMETIC, + &methods::MAP_FLATTEN, + &methods::NEW_RET_NO_SELF, + &methods::OK_EXPECT, + &methods::OPTION_AND_THEN_SOME, + &methods::OPTION_EXPECT_USED, + &methods::OPTION_MAP_OR_NONE, + &methods::OPTION_MAP_UNWRAP_OR, + &methods::OPTION_MAP_UNWRAP_OR_ELSE, + &methods::OPTION_UNWRAP_USED, + &methods::OR_FUN_CALL, + &methods::RESULT_EXPECT_USED, + &methods::RESULT_MAP_UNWRAP_OR_ELSE, + &methods::RESULT_UNWRAP_USED, + &methods::SEARCH_IS_SOME, + &methods::SHOULD_IMPLEMENT_TRAIT, + &methods::SINGLE_CHAR_PATTERN, + &methods::STRING_EXTEND_CHARS, + &methods::SUSPICIOUS_MAP, + &methods::TEMPORARY_CSTRING_AS_PTR, + &methods::UNINIT_ASSUMED_INIT, + &methods::UNNECESSARY_FILTER_MAP, + &methods::UNNECESSARY_FOLD, + &methods::USELESS_ASREF, + &methods::WRONG_PUB_SELF_CONVENTION, + &methods::WRONG_SELF_CONVENTION, + &minmax::MIN_MAX, + &misc::CMP_NAN, + &misc::CMP_OWNED, + &misc::FLOAT_CMP, + &misc::FLOAT_CMP_CONST, + &misc::MODULO_ONE, + &misc::SHORT_CIRCUIT_STATEMENT, + &misc::TOPLEVEL_REF_ARG, + &misc::USED_UNDERSCORE_BINDING, + &misc::ZERO_PTR, + &misc_early::BUILTIN_TYPE_SHADOW, + &misc_early::DOUBLE_NEG, + &misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + &misc_early::MIXED_CASE_HEX_LITERALS, + &misc_early::REDUNDANT_CLOSURE_CALL, + &misc_early::REDUNDANT_PATTERN, + &misc_early::UNNEEDED_FIELD_PATTERN, + &misc_early::UNNEEDED_WILDCARD_PATTERN, + &misc_early::UNSEPARATED_LITERAL_SUFFIX, + &misc_early::ZERO_PREFIXED_LITERAL, + &missing_const_for_fn::MISSING_CONST_FOR_FN, + &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, + &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + &mul_add::MANUAL_MUL_ADD, + &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, + &mut_mut::MUT_MUT, + &mut_reference::UNNECESSARY_MUT_PASSED, + &mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, + &mutex_atomic::MUTEX_ATOMIC, + &mutex_atomic::MUTEX_INTEGER, + &needless_bool::BOOL_COMPARISON, + &needless_bool::NEEDLESS_BOOL, + &needless_borrow::NEEDLESS_BORROW, + &needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, + &needless_continue::NEEDLESS_CONTINUE, + &needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, + &needless_update::NEEDLESS_UPDATE, + &neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, + &neg_multiply::NEG_MULTIPLY, + &new_without_default::NEW_WITHOUT_DEFAULT, + &no_effect::NO_EFFECT, + &no_effect::UNNECESSARY_OPERATION, + &non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + &non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, + &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, + &non_expressive_names::MANY_SINGLE_CHAR_NAMES, + &non_expressive_names::SIMILAR_NAMES, + &ok_if_let::IF_LET_SOME_RESULT, + &open_options::NONSENSICAL_OPEN_OPTIONS, + &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + &panic_unimplemented::PANIC, + &panic_unimplemented::PANIC_PARAMS, + &panic_unimplemented::TODO, + &panic_unimplemented::UNIMPLEMENTED, + &panic_unimplemented::UNREACHABLE, + &partialeq_ne_impl::PARTIALEQ_NE_IMPL, + &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + &precedence::PRECEDENCE, + &ptr::CMP_NULL, + &ptr::MUT_FROM_REF, + &ptr::PTR_ARG, + &ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, + &question_mark::QUESTION_MARK, + &ranges::ITERATOR_STEP_BY_ZERO, + &ranges::RANGE_MINUS_ONE, + &ranges::RANGE_PLUS_ONE, + &ranges::RANGE_ZIP_WITH_LEN, + &redundant_clone::REDUNDANT_CLONE, + &redundant_field_names::REDUNDANT_FIELD_NAMES, + &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, + &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, + &reference::DEREF_ADDROF, + &reference::REF_IN_DEREF, + ®ex::INVALID_REGEX, + ®ex::REGEX_MACRO, + ®ex::TRIVIAL_REGEX, + &replace_consts::REPLACE_CONSTS, + &returns::LET_AND_RETURN, + &returns::NEEDLESS_RETURN, + &returns::UNUSED_UNIT, + &serde_api::SERDE_API_MISUSE, + &shadow::SHADOW_REUSE, + &shadow::SHADOW_SAME, + &shadow::SHADOW_UNRELATED, + &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, + &strings::STRING_ADD, + &strings::STRING_ADD_ASSIGN, + &strings::STRING_LIT_AS_BYTES, + &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, + &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, + &swap::ALMOST_SWAPPED, + &swap::MANUAL_SWAP, + &temporary_assignment::TEMPORARY_ASSIGNMENT, + &trait_bounds::TYPE_REPETITION_IN_BOUNDS, + &transmute::CROSSPOINTER_TRANSMUTE, + &transmute::TRANSMUTE_BYTES_TO_STR, + &transmute::TRANSMUTE_INT_TO_BOOL, + &transmute::TRANSMUTE_INT_TO_CHAR, + &transmute::TRANSMUTE_INT_TO_FLOAT, + &transmute::TRANSMUTE_PTR_TO_PTR, + &transmute::TRANSMUTE_PTR_TO_REF, + &transmute::UNSOUND_COLLECTION_TRANSMUTE, + &transmute::USELESS_TRANSMUTE, + &transmute::WRONG_TRANSMUTE, + &transmuting_null::TRANSMUTING_NULL, + &trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, + &try_err::TRY_ERR, + &types::ABSURD_EXTREME_COMPARISONS, + &types::BORROWED_BOX, + &types::BOX_VEC, + &types::CAST_LOSSLESS, + &types::CAST_POSSIBLE_TRUNCATION, + &types::CAST_POSSIBLE_WRAP, + &types::CAST_PRECISION_LOSS, + &types::CAST_PTR_ALIGNMENT, + &types::CAST_REF_TO_MUT, + &types::CAST_SIGN_LOSS, + &types::CHAR_LIT_AS_U8, + &types::FN_TO_NUMERIC_CAST, + &types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + &types::IMPLICIT_HASHER, + &types::INVALID_UPCAST_COMPARISONS, + &types::LET_UNIT_VALUE, + &types::LINKEDLIST, + &types::OPTION_OPTION, + &types::TYPE_COMPLEXITY, + &types::UNIT_ARG, + &types::UNIT_CMP, + &types::UNNECESSARY_CAST, + &types::VEC_BOX, + &unicode::NON_ASCII_LITERAL, + &unicode::UNICODE_NOT_NFC, + &unicode::ZERO_WIDTH_SPACE, + &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + &unused_io_amount::UNUSED_IO_AMOUNT, + &unused_label::UNUSED_LABEL, + &unused_self::UNUSED_SELF, + &unwrap::PANICKING_UNWRAP, + &unwrap::UNNECESSARY_UNWRAP, + &use_self::USE_SELF, + &vec::USELESS_VEC, + &wildcard_dependencies::WILDCARD_DEPENDENCIES, + &write::PRINTLN_EMPTY_STRING, + &write::PRINT_LITERAL, + &write::PRINT_STDOUT, + &write::PRINT_WITH_NEWLINE, + &write::USE_DEBUG, + &write::WRITELN_EMPTY_STRING, + &write::WRITE_LITERAL, + &write::WRITE_WITH_NEWLINE, + &zero_div_zero::ZERO_DIVIDED_BY_ZERO, + ]); + // end register lints, do not remove this comment, it’s used in `update_lints` + + store.register_late_pass(|| box serde_api::SerdeAPI); + store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); + store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); + store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); + store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + store.register_late_pass(|| box utils::author::Author); + store.register_late_pass(|| box types::Types); + store.register_late_pass(|| box booleans::NonminimalBool); + store.register_late_pass(|| box eq_op::EqOp); + store.register_late_pass(|| box enum_glob_use::EnumGlobUse); + store.register_late_pass(|| box enum_clike::UnportableVariant); + store.register_late_pass(|| box excessive_precision::ExcessivePrecision); + let p = conf.verbose_bit_mask_threshold; + store.register_late_pass(move || box bit_mask::BitMask::new(p)); + store.register_late_pass(|| box ptr::Ptr); + store.register_late_pass(|| box needless_bool::NeedlessBool); + store.register_late_pass(|| box needless_bool::BoolComparison); + store.register_late_pass(|| box approx_const::ApproxConstant); + store.register_late_pass(|| box misc::MiscLints); + store.register_late_pass(|| box eta_reduction::EtaReduction); + store.register_late_pass(|| box identity_op::IdentityOp); + store.register_late_pass(|| box erasing_op::ErasingOp); + store.register_late_pass(|| box mut_mut::MutMut); + store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed); + store.register_late_pass(|| box len_zero::LenZero); + store.register_late_pass(|| box attrs::Attributes); + store.register_late_pass(|| box block_in_if_condition::BlockInIfCondition); + store.register_late_pass(|| box unicode::Unicode); + store.register_late_pass(|| box strings::StringAdd); + store.register_late_pass(|| box implicit_return::ImplicitReturn); + store.register_late_pass(|| box methods::Methods); + store.register_late_pass(|| box map_clone::MapClone); + store.register_late_pass(|| box shadow::Shadow); + store.register_late_pass(|| box types::LetUnitValue); + store.register_late_pass(|| box types::UnitCmp); + store.register_late_pass(|| box loops::Loops); + store.register_late_pass(|| box main_recursion::MainRecursion::default()); + store.register_late_pass(|| box lifetimes::Lifetimes); + store.register_late_pass(|| box entry::HashMapPass); + store.register_late_pass(|| box ranges::Ranges); + store.register_late_pass(|| box types::Casts); + let p = conf.type_complexity_threshold; + store.register_late_pass(move || box types::TypeComplexity::new(p)); + store.register_late_pass(|| box matches::Matches); + store.register_late_pass(|| box minmax::MinMaxPass); + store.register_late_pass(|| box open_options::OpenOptions); + store.register_late_pass(|| box zero_div_zero::ZeroDiv); + store.register_late_pass(|| box mutex_atomic::Mutex); + store.register_late_pass(|| box needless_update::NeedlessUpdate); + store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default()); + store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef); + store.register_late_pass(|| box no_effect::NoEffect); + store.register_late_pass(|| box temporary_assignment::TemporaryAssignment); + store.register_late_pass(|| box transmute::Transmute); + let p = conf.cognitive_complexity_threshold; + store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(p)); + let a = conf.too_large_for_stack; + store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack: a}); + store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented); + store.register_late_pass(|| box strings::StringLitAsBytes); + store.register_late_pass(|| box derive::Derive); + store.register_late_pass(|| box types::CharLitAsU8); + store.register_late_pass(|| box vec::UselessVec); + store.register_late_pass(|| box drop_bounds::DropBounds); + store.register_late_pass(|| box get_last_with_len::GetLastWithLen); + store.register_late_pass(|| box drop_forget_ref::DropForgetRef); + store.register_late_pass(|| box empty_enum::EmptyEnum); + store.register_late_pass(|| box types::AbsurdExtremeComparisons); + store.register_late_pass(|| box types::InvalidUpcastComparisons); + store.register_late_pass(|| box regex::Regex::default()); + store.register_late_pass(|| box copies::CopyAndPaste); + store.register_late_pass(|| box copy_iterator::CopyIterator); + store.register_late_pass(|| box format::UselessFormat); + store.register_late_pass(|| box swap::Swap); + store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional); + store.register_late_pass(|| box unused_label::UnusedLabel); + store.register_late_pass(|| box new_without_default::NewWithoutDefault::default()); + let p = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(p.clone())); + let a1 = conf.too_many_arguments_threshold; + let a2 = conf.too_many_lines_threshold; + store.register_late_pass(move || box functions::Functions::new(a1, a2)); + let p = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || box doc::DocMarkdown::new(p.clone())); + store.register_late_pass(|| box neg_multiply::NegMultiply); + store.register_late_pass(|| box mem_discriminant::MemDiscriminant); + store.register_late_pass(|| box mem_forget::MemForget); + store.register_late_pass(|| box mem_replace::MemReplace); + store.register_late_pass(|| box arithmetic::Arithmetic::default()); + store.register_late_pass(|| box assign_ops::AssignOps); + store.register_late_pass(|| box let_if_seq::LetIfSeq); + store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); + store.register_late_pass(|| box missing_doc::MissingDoc::new()); + store.register_late_pass(|| box missing_inline::MissingInline); + store.register_late_pass(|| box ok_if_let::OkIfLet); + store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching); + store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); + store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); + let p = conf.enum_variant_size_threshold; + store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(p)); + store.register_late_pass(|| box explicit_write::ExplicitWrite); + store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue); + let p = trivially_copy_pass_by_ref::TriviallyCopyPassByRef::new( + conf.trivial_copy_size_limit, + &sess.target, ); - reg.register_late_lint_pass(box escape::BoxedLocal{too_large_for_stack: conf.too_large_for_stack}); - reg.register_early_lint_pass(box misc_early::MiscEarlyLints); - reg.register_late_lint_pass(box panic_unimplemented::PanicUnimplemented); - reg.register_late_lint_pass(box strings::StringLitAsBytes); - reg.register_late_lint_pass(box derive::Derive); - reg.register_late_lint_pass(box types::CharLitAsU8); - reg.register_late_lint_pass(box vec::UselessVec); - reg.register_late_lint_pass(box drop_bounds::DropBounds); - reg.register_late_lint_pass(box get_last_with_len::GetLastWithLen); - reg.register_late_lint_pass(box drop_forget_ref::DropForgetRef); - reg.register_late_lint_pass(box empty_enum::EmptyEnum); - reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); - reg.register_late_lint_pass(box types::InvalidUpcastComparisons); - reg.register_late_lint_pass(box regex::Regex::default()); - reg.register_late_lint_pass(box copies::CopyAndPaste); - reg.register_late_lint_pass(box copy_iterator::CopyIterator); - reg.register_late_lint_pass(box format::UselessFormat); - reg.register_early_lint_pass(box formatting::Formatting); - reg.register_late_lint_pass(box swap::Swap); - reg.register_early_lint_pass(box if_not_else::IfNotElse); - reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse); - reg.register_early_lint_pass(box int_plus_one::IntPlusOne); - reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); - reg.register_late_lint_pass(box unused_label::UnusedLabel); - reg.register_late_lint_pass(box new_without_default::NewWithoutDefault::default()); - reg.register_late_lint_pass(box blacklisted_name::BlacklistedName::new( - conf.blacklisted_names.iter().cloned().collect() - )); - reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold, conf.too_many_lines_threshold)); - reg.register_late_lint_pass(box doc::DocMarkdown::new(conf.doc_valid_idents.iter().cloned().collect())); - reg.register_late_lint_pass(box neg_multiply::NegMultiply); - reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval); - reg.register_late_lint_pass(box mem_discriminant::MemDiscriminant); - reg.register_late_lint_pass(box mem_forget::MemForget); - reg.register_late_lint_pass(box mem_replace::MemReplace); - reg.register_late_lint_pass(box arithmetic::Arithmetic::default()); - reg.register_late_lint_pass(box assign_ops::AssignOps); - reg.register_late_lint_pass(box let_if_seq::LetIfSeq); - reg.register_late_lint_pass(box eval_order_dependence::EvalOrderDependence); - reg.register_late_lint_pass(box missing_doc::MissingDoc::new()); - reg.register_late_lint_pass(box missing_inline::MissingInline); - reg.register_late_lint_pass(box ok_if_let::OkIfLet); - reg.register_late_lint_pass(box redundant_pattern_matching::RedundantPatternMatching); - reg.register_late_lint_pass(box partialeq_ne_impl::PartialEqNeImpl); - reg.register_early_lint_pass(box reference::DerefAddrOf); - reg.register_early_lint_pass(box reference::RefInDeref); - reg.register_early_lint_pass(box double_parens::DoubleParens); - reg.register_late_lint_pass(box unused_io_amount::UnusedIoAmount); - reg.register_late_lint_pass(box large_enum_variant::LargeEnumVariant::new(conf.enum_variant_size_threshold)); - reg.register_late_lint_pass(box explicit_write::ExplicitWrite); - reg.register_late_lint_pass(box needless_pass_by_value::NeedlessPassByValue); - reg.register_late_lint_pass(box trivially_copy_pass_by_ref::TriviallyCopyPassByRef::new( - conf.trivial_copy_size_limit, - ®.sess.target, - )); - reg.register_early_lint_pass(box literal_representation::LiteralDigitGrouping); - reg.register_early_lint_pass(box literal_representation::DecimalLiteralRepresentation::new( - conf.literal_representation_threshold - )); - reg.register_late_lint_pass(box try_err::TryErr); - reg.register_late_lint_pass(box use_self::UseSelf); - reg.register_late_lint_pass(box bytecount::ByteCount); - reg.register_late_lint_pass(box infinite_iter::InfiniteIter); - reg.register_late_lint_pass(box inline_fn_without_body::InlineFnWithoutBody); - reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default()); - reg.register_late_lint_pass(box types::ImplicitHasher); - reg.register_early_lint_pass(box redundant_static_lifetimes::RedundantStaticLifetimes); - reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom); - reg.register_late_lint_pass(box replace_consts::ReplaceConsts); - reg.register_late_lint_pass(box types::UnitArg); - reg.register_late_lint_pass(box double_comparison::DoubleComparisons); - reg.register_late_lint_pass(box question_mark::QuestionMark); - reg.register_late_lint_pass(box suspicious_trait_impl::SuspiciousImpl); - reg.register_early_lint_pass(box cargo_common_metadata::CargoCommonMetadata); - reg.register_early_lint_pass(box multiple_crate_versions::MultipleCrateVersions); - reg.register_early_lint_pass(box wildcard_dependencies::WildcardDependencies); - reg.register_late_lint_pass(box map_unit_fn::MapUnit); - reg.register_late_lint_pass(box infallible_destructuring_match::InfallibleDestructingMatch); - reg.register_late_lint_pass(box inherent_impl::MultipleInherentImpl::default()); - reg.register_late_lint_pass(box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); - reg.register_late_lint_pass(box unwrap::Unwrap); - reg.register_late_lint_pass(box duration_subsec::DurationSubsec); - reg.register_late_lint_pass(box default_trait_access::DefaultTraitAccess); - reg.register_late_lint_pass(box indexing_slicing::IndexingSlicing); - reg.register_late_lint_pass(box non_copy_const::NonCopyConst); - reg.register_late_lint_pass(box ptr_offset_with_cast::PtrOffsetWithCast); - reg.register_late_lint_pass(box redundant_clone::RedundantClone); - reg.register_late_lint_pass(box slow_vector_initialization::SlowVectorInit); - reg.register_late_lint_pass(box types::RefToMut); - reg.register_late_lint_pass(box assertions_on_constants::AssertionsOnConstants); - reg.register_late_lint_pass(box missing_const_for_fn::MissingConstForFn); - reg.register_late_lint_pass(box transmuting_null::TransmutingNull); - reg.register_late_lint_pass(box path_buf_push_overwrite::PathBufPushOverwrite); - reg.register_late_lint_pass(box checked_conversions::CheckedConversions); - reg.register_late_lint_pass(box integer_division::IntegerDivision); - reg.register_late_lint_pass(box inherent_to_string::InherentToString); - reg.register_late_lint_pass(box trait_bounds::TraitBounds); - reg.register_late_lint_pass(box comparison_chain::ComparisonChain); - reg.register_late_lint_pass(box mul_add::MulAddCheck); - reg.register_late_lint_pass(box unused_self::UnusedSelf); - reg.register_late_lint_pass(box mutable_debug_assertion::DebugAssertWithMutCall); + store.register_late_pass(move || box p); + store.register_late_pass(|| box try_err::TryErr); + store.register_late_pass(|| box use_self::UseSelf); + store.register_late_pass(|| box bytecount::ByteCount); + store.register_late_pass(|| box infinite_iter::InfiniteIter); + store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); + store.register_late_pass(|| box identity_conversion::IdentityConversion::default()); + store.register_late_pass(|| box types::ImplicitHasher); + store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); + store.register_late_pass(|| box replace_consts::ReplaceConsts); + store.register_late_pass(|| box types::UnitArg); + store.register_late_pass(|| box double_comparison::DoubleComparisons); + store.register_late_pass(|| box question_mark::QuestionMark); + store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); + store.register_late_pass(|| box map_unit_fn::MapUnit); + store.register_late_pass(|| box infallible_destructuring_match::InfallibleDestructingMatch); + store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default()); + store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); + store.register_late_pass(|| box unwrap::Unwrap); + store.register_late_pass(|| box duration_subsec::DurationSubsec); + store.register_late_pass(|| box default_trait_access::DefaultTraitAccess); + store.register_late_pass(|| box indexing_slicing::IndexingSlicing); + store.register_late_pass(|| box non_copy_const::NonCopyConst); + store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); + store.register_late_pass(|| box redundant_clone::RedundantClone); + store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); + store.register_late_pass(|| box types::RefToMut); + store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); + store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); + store.register_late_pass(|| box transmuting_null::TransmutingNull); + store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite); + store.register_late_pass(|| box checked_conversions::CheckedConversions); + store.register_late_pass(|| box integer_division::IntegerDivision); + store.register_late_pass(|| box inherent_to_string::InherentToString); + store.register_late_pass(|| box trait_bounds::TraitBounds); + store.register_late_pass(|| box comparison_chain::ComparisonChain); + store.register_late_pass(|| box mul_add::MulAddCheck); + + store.register_early_pass(|| box reference::DerefAddrOf); + store.register_early_pass(|| box reference::RefInDeref); + store.register_early_pass(|| box double_parens::DoubleParens); + store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval); + store.register_early_pass(|| box if_not_else::IfNotElse); + store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse); + store.register_early_pass(|| box int_plus_one::IntPlusOne); + store.register_early_pass(|| box formatting::Formatting); + store.register_early_pass(|| box misc_early::MiscEarlyLints); + store.register_early_pass(|| box returns::Return); + store.register_early_pass(|| box collapsible_if::CollapsibleIf); + store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); + store.register_early_pass(|| box precedence::Precedence); + store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); + store.register_early_pass(|| box cargo_common_metadata::CargoCommonMetadata); + store.register_early_pass(|| box multiple_crate_versions::MultipleCrateVersions); + store.register_early_pass(|| box wildcard_dependencies::WildcardDependencies); + store.register_early_pass(|| box literal_representation::LiteralDigitGrouping); + let p = conf.literal_representation_threshold; + store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(p)); + store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); + let p = conf.enum_variant_name_threshold; + store.register_early_pass(move || box enum_variants::EnumVariantNames::new(p)); - reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ - arithmetic::FLOAT_ARITHMETIC, - arithmetic::INTEGER_ARITHMETIC, - dbg_macro::DBG_MACRO, - else_if_without_else::ELSE_IF_WITHOUT_ELSE, - implicit_return::IMPLICIT_RETURN, - indexing_slicing::INDEXING_SLICING, - inherent_impl::MULTIPLE_INHERENT_IMPL, - integer_division::INTEGER_DIVISION, - literal_representation::DECIMAL_LITERAL_REPRESENTATION, - matches::WILDCARD_ENUM_MATCH_ARM, - mem_forget::MEM_FORGET, - methods::CLONE_ON_REF_PTR, - methods::GET_UNWRAP, - methods::OPTION_EXPECT_USED, - methods::OPTION_UNWRAP_USED, - methods::RESULT_EXPECT_USED, - methods::RESULT_UNWRAP_USED, - methods::WRONG_PUB_SELF_CONVENTION, - misc::FLOAT_CMP_CONST, - missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, - missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, - panic_unimplemented::PANIC, - panic_unimplemented::TODO, - panic_unimplemented::UNIMPLEMENTED, - panic_unimplemented::UNREACHABLE, - shadow::SHADOW_REUSE, - shadow::SHADOW_SAME, - strings::STRING_ADD, - write::PRINT_STDOUT, - write::USE_DEBUG, + store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ + LintId::of(&arithmetic::FLOAT_ARITHMETIC), + LintId::of(&arithmetic::INTEGER_ARITHMETIC), + LintId::of(&dbg_macro::DBG_MACRO), + LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), + LintId::of(&implicit_return::IMPLICIT_RETURN), + LintId::of(&indexing_slicing::INDEXING_SLICING), + LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), + LintId::of(&integer_division::INTEGER_DIVISION), + LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), + LintId::of(&mem_forget::MEM_FORGET), + LintId::of(&methods::CLONE_ON_REF_PTR), + LintId::of(&methods::GET_UNWRAP), + LintId::of(&methods::OPTION_EXPECT_USED), + LintId::of(&methods::OPTION_UNWRAP_USED), + LintId::of(&methods::RESULT_EXPECT_USED), + LintId::of(&methods::RESULT_UNWRAP_USED), + LintId::of(&methods::WRONG_PUB_SELF_CONVENTION), + LintId::of(&misc::FLOAT_CMP_CONST), + LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), + LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(&panic_unimplemented::PANIC), + LintId::of(&panic_unimplemented::TODO), + LintId::of(&panic_unimplemented::UNIMPLEMENTED), + LintId::of(&panic_unimplemented::UNREACHABLE), + LintId::of(&shadow::SHADOW_REUSE), + LintId::of(&shadow::SHADOW_SAME), + LintId::of(&strings::STRING_ADD), + LintId::of(&write::PRINT_STDOUT), + LintId::of(&write::USE_DEBUG), ]); - reg.register_lint_group("clippy::pedantic", Some("clippy_pedantic"), vec![ - attrs::INLINE_ALWAYS, - checked_conversions::CHECKED_CONVERSIONS, - copies::MATCH_SAME_ARMS, - copy_iterator::COPY_ITERATOR, - default_trait_access::DEFAULT_TRAIT_ACCESS, - derive::EXPL_IMPL_CLONE_ON_COPY, - doc::DOC_MARKDOWN, - empty_enum::EMPTY_ENUM, - enum_glob_use::ENUM_GLOB_USE, - enum_variants::MODULE_NAME_REPETITIONS, - enum_variants::PUB_ENUM_VARIANT_NAMES, - eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, - functions::MUST_USE_CANDIDATE, - functions::TOO_MANY_LINES, - if_not_else::IF_NOT_ELSE, - infinite_iter::MAYBE_INFINITE_ITER, - items_after_statements::ITEMS_AFTER_STATEMENTS, - literal_representation::LARGE_DIGIT_GROUPS, - loops::EXPLICIT_INTO_ITER_LOOP, - loops::EXPLICIT_ITER_LOOP, - matches::SINGLE_MATCH_ELSE, - methods::FILTER_MAP, - methods::FILTER_MAP_NEXT, - methods::FIND_MAP, - methods::MAP_FLATTEN, - methods::OPTION_MAP_UNWRAP_OR, - methods::OPTION_MAP_UNWRAP_OR_ELSE, - methods::RESULT_MAP_UNWRAP_OR_ELSE, - misc::USED_UNDERSCORE_BINDING, - misc_early::UNSEPARATED_LITERAL_SUFFIX, - mut_mut::MUT_MUT, - needless_continue::NEEDLESS_CONTINUE, - needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, - non_expressive_names::SIMILAR_NAMES, - replace_consts::REPLACE_CONSTS, - shadow::SHADOW_UNRELATED, - strings::STRING_ADD_ASSIGN, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, - types::CAST_LOSSLESS, - types::CAST_POSSIBLE_TRUNCATION, - types::CAST_POSSIBLE_WRAP, - types::CAST_PRECISION_LOSS, - types::CAST_SIGN_LOSS, - types::INVALID_UPCAST_COMPARISONS, - types::LINKEDLIST, - unicode::NON_ASCII_LITERAL, - unicode::UNICODE_NOT_NFC, - unused_self::UNUSED_SELF, - use_self::USE_SELF, + store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ + LintId::of(&attrs::INLINE_ALWAYS), + LintId::of(&checked_conversions::CHECKED_CONVERSIONS), + LintId::of(&copies::MATCH_SAME_ARMS), + LintId::of(©_iterator::COPY_ITERATOR), + LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), + LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), + LintId::of(&doc::DOC_MARKDOWN), + LintId::of(&empty_enum::EMPTY_ENUM), + LintId::of(&enum_glob_use::ENUM_GLOB_USE), + LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), + LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES), + LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), + LintId::of(&functions::MUST_USE_CANDIDATE), + LintId::of(&functions::TOO_MANY_LINES), + LintId::of(&if_not_else::IF_NOT_ELSE), + LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), + LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), + LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), + LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), + LintId::of(&loops::EXPLICIT_ITER_LOOP), + LintId::of(&matches::SINGLE_MATCH_ELSE), + LintId::of(&methods::FILTER_MAP), + LintId::of(&methods::FILTER_MAP_NEXT), + LintId::of(&methods::FIND_MAP), + LintId::of(&methods::MAP_FLATTEN), + LintId::of(&methods::OPTION_MAP_UNWRAP_OR), + LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE), + LintId::of(&methods::RESULT_MAP_UNWRAP_OR_ELSE), + LintId::of(&misc::USED_UNDERSCORE_BINDING), + LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX), + LintId::of(&mut_mut::MUT_MUT), + LintId::of(&needless_continue::NEEDLESS_CONTINUE), + LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), + LintId::of(&non_expressive_names::SIMILAR_NAMES), + LintId::of(&replace_consts::REPLACE_CONSTS), + LintId::of(&shadow::SHADOW_UNRELATED), + LintId::of(&strings::STRING_ADD_ASSIGN), + LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS), + LintId::of(&types::CAST_LOSSLESS), + LintId::of(&types::CAST_POSSIBLE_TRUNCATION), + LintId::of(&types::CAST_POSSIBLE_WRAP), + LintId::of(&types::CAST_PRECISION_LOSS), + LintId::of(&types::CAST_SIGN_LOSS), + LintId::of(&types::INVALID_UPCAST_COMPARISONS), + LintId::of(&types::LINKEDLIST), + LintId::of(&unicode::NON_ASCII_LITERAL), + LintId::of(&unicode::UNICODE_NOT_NFC), + LintId::of(&unused_self::UNUSED_SELF), + LintId::of(&use_self::USE_SELF), ]); - reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![ - utils::internal_lints::CLIPPY_LINTS_INTERNAL, - utils::internal_lints::COMPILER_LINT_FUNCTIONS, - utils::internal_lints::LINT_WITHOUT_LINT_PASS, - utils::internal_lints::OUTER_EXPN_EXPN_DATA, + store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ + LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), + LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), + LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), + LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), ]); - reg.register_lint_group("clippy::all", Some("clippy"), vec![ - approx_const::APPROX_CONSTANT, - assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assign_ops::ASSIGN_OP_PATTERN, - assign_ops::MISREFACTORED_ASSIGN_OP, - attrs::DEPRECATED_CFG_ATTR, - attrs::DEPRECATED_SEMVER, - attrs::UNKNOWN_CLIPPY_LINTS, - attrs::USELESS_ATTRIBUTE, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - bit_mask::VERBOSE_BIT_MASK, - blacklisted_name::BLACKLISTED_NAME, - block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, - block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, - booleans::LOGIC_BUG, - booleans::NONMINIMAL_BOOL, - bytecount::NAIVE_BYTECOUNT, - cognitive_complexity::COGNITIVE_COMPLEXITY, - collapsible_if::COLLAPSIBLE_IF, - comparison_chain::COMPARISON_CHAIN, - copies::IFS_SAME_COND, - copies::IF_SAME_THEN_ELSE, - derive::DERIVE_HASH_XOR_EQ, - doc::MISSING_SAFETY_DOC, - doc::NEEDLESS_DOCTEST_MAIN, - double_comparison::DOUBLE_COMPARISONS, - double_parens::DOUBLE_PARENS, - drop_bounds::DROP_BOUNDS, - drop_forget_ref::DROP_COPY, - drop_forget_ref::DROP_REF, - drop_forget_ref::FORGET_COPY, - drop_forget_ref::FORGET_REF, - duration_subsec::DURATION_SUBSEC, - entry::MAP_ENTRY, - enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - enum_variants::ENUM_VARIANT_NAMES, - enum_variants::MODULE_INCEPTION, - eq_op::EQ_OP, - eq_op::OP_REF, - erasing_op::ERASING_OP, - escape::BOXED_LOCAL, - eta_reduction::REDUNDANT_CLOSURE, - eval_order_dependence::DIVERGING_SUB_EXPRESSION, - eval_order_dependence::EVAL_ORDER_DEPENDENCE, - excessive_precision::EXCESSIVE_PRECISION, - explicit_write::EXPLICIT_WRITE, - format::USELESS_FORMAT, - formatting::POSSIBLE_MISSING_COMMA, - formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - formatting::SUSPICIOUS_ELSE_FORMATTING, - formatting::SUSPICIOUS_UNARY_OP_FORMATTING, - functions::DOUBLE_MUST_USE, - functions::MUST_USE_UNIT, - functions::NOT_UNSAFE_PTR_ARG_DEREF, - functions::TOO_MANY_ARGUMENTS, - get_last_with_len::GET_LAST_WITH_LEN, - identity_conversion::IDENTITY_CONVERSION, - identity_op::IDENTITY_OP, - indexing_slicing::OUT_OF_BOUNDS_INDEXING, - infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, - infinite_iter::INFINITE_ITER, - inherent_to_string::INHERENT_TO_STRING, - inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, - inline_fn_without_body::INLINE_FN_WITHOUT_BODY, - int_plus_one::INT_PLUS_ONE, - large_enum_variant::LARGE_ENUM_VARIANT, - len_zero::LEN_WITHOUT_IS_EMPTY, - len_zero::LEN_ZERO, - let_if_seq::USELESS_LET_IF_SEQ, - lifetimes::EXTRA_UNUSED_LIFETIMES, - lifetimes::NEEDLESS_LIFETIMES, - literal_representation::INCONSISTENT_DIGIT_GROUPING, - literal_representation::MISTYPED_LITERAL_SUFFIXES, - literal_representation::UNREADABLE_LITERAL, - loops::EMPTY_LOOP, - loops::EXPLICIT_COUNTER_LOOP, - loops::FOR_KV_MAP, - loops::FOR_LOOP_OVER_OPTION, - loops::FOR_LOOP_OVER_RESULT, - loops::ITER_NEXT_LOOP, - loops::MANUAL_MEMCPY, - loops::MUT_RANGE_BOUND, - loops::NEEDLESS_COLLECT, - loops::NEEDLESS_RANGE_LOOP, - loops::NEVER_LOOP, - loops::REVERSE_RANGE_LOOP, - loops::WHILE_IMMUTABLE_CONDITION, - loops::WHILE_LET_LOOP, - loops::WHILE_LET_ON_ITERATOR, - main_recursion::MAIN_RECURSION, - map_clone::MAP_CLONE, - map_unit_fn::OPTION_MAP_UNIT_FN, - map_unit_fn::RESULT_MAP_UNIT_FN, - matches::MATCH_AS_REF, - matches::MATCH_BOOL, - matches::MATCH_OVERLAPPING_ARM, - matches::MATCH_REF_PATS, - matches::MATCH_WILD_ERR_ARM, - matches::SINGLE_MATCH, - mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, - mem_replace::MEM_REPLACE_OPTION_WITH_NONE, - mem_replace::MEM_REPLACE_WITH_UNINIT, - methods::CHARS_LAST_CMP, - methods::CHARS_NEXT_CMP, - methods::CLONE_DOUBLE_REF, - methods::CLONE_ON_COPY, - methods::EXPECT_FUN_CALL, - methods::FILTER_NEXT, - methods::FLAT_MAP_IDENTITY, - methods::INEFFICIENT_TO_STRING, - methods::INTO_ITER_ON_ARRAY, - methods::INTO_ITER_ON_REF, - methods::ITER_CLONED_COLLECT, - methods::ITER_NTH, - methods::ITER_SKIP_NEXT, - methods::MANUAL_SATURATING_ARITHMETIC, - methods::NEW_RET_NO_SELF, - methods::OK_EXPECT, - methods::OPTION_AND_THEN_SOME, - methods::OPTION_MAP_OR_NONE, - methods::OR_FUN_CALL, - methods::SEARCH_IS_SOME, - methods::SHOULD_IMPLEMENT_TRAIT, - methods::SINGLE_CHAR_PATTERN, - methods::STRING_EXTEND_CHARS, - methods::SUSPICIOUS_MAP, - methods::TEMPORARY_CSTRING_AS_PTR, - methods::UNINIT_ASSUMED_INIT, - methods::UNNECESSARY_FILTER_MAP, - methods::UNNECESSARY_FOLD, - methods::USELESS_ASREF, - methods::WRONG_SELF_CONVENTION, - minmax::MIN_MAX, - misc::CMP_NAN, - misc::CMP_OWNED, - misc::FLOAT_CMP, - misc::MODULO_ONE, - misc::SHORT_CIRCUIT_STATEMENT, - misc::TOPLEVEL_REF_ARG, - misc::ZERO_PTR, - misc_early::BUILTIN_TYPE_SHADOW, - misc_early::DOUBLE_NEG, - misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - misc_early::MIXED_CASE_HEX_LITERALS, - misc_early::REDUNDANT_CLOSURE_CALL, - misc_early::REDUNDANT_PATTERN, - misc_early::UNNEEDED_FIELD_PATTERN, - misc_early::UNNEEDED_WILDCARD_PATTERN, - misc_early::ZERO_PREFIXED_LITERAL, - mul_add::MANUAL_MUL_ADD, - mut_reference::UNNECESSARY_MUT_PASSED, - mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, - mutex_atomic::MUTEX_ATOMIC, - needless_bool::BOOL_COMPARISON, - needless_bool::NEEDLESS_BOOL, - needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, - needless_update::NEEDLESS_UPDATE, - neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, - neg_multiply::NEG_MULTIPLY, - new_without_default::NEW_WITHOUT_DEFAULT, - no_effect::NO_EFFECT, - no_effect::UNNECESSARY_OPERATION, - non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, - non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, - non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, - non_expressive_names::MANY_SINGLE_CHAR_NAMES, - ok_if_let::IF_LET_SOME_RESULT, - open_options::NONSENSICAL_OPEN_OPTIONS, - overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - panic_unimplemented::PANIC_PARAMS, - partialeq_ne_impl::PARTIALEQ_NE_IMPL, - precedence::PRECEDENCE, - ptr::CMP_NULL, - ptr::MUT_FROM_REF, - ptr::PTR_ARG, - ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, - question_mark::QUESTION_MARK, - ranges::ITERATOR_STEP_BY_ZERO, - ranges::RANGE_MINUS_ONE, - ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, - redundant_clone::REDUNDANT_CLONE, - redundant_field_names::REDUNDANT_FIELD_NAMES, - redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, - redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, - reference::DEREF_ADDROF, - reference::REF_IN_DEREF, - regex::INVALID_REGEX, - regex::REGEX_MACRO, - regex::TRIVIAL_REGEX, - returns::LET_AND_RETURN, - returns::NEEDLESS_RETURN, - returns::UNUSED_UNIT, - serde_api::SERDE_API_MISUSE, - slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - strings::STRING_LIT_AS_BYTES, - suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, - suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, - swap::ALMOST_SWAPPED, - swap::MANUAL_SWAP, - temporary_assignment::TEMPORARY_ASSIGNMENT, - transmute::CROSSPOINTER_TRANSMUTE, - transmute::TRANSMUTE_BYTES_TO_STR, - transmute::TRANSMUTE_INT_TO_BOOL, - transmute::TRANSMUTE_INT_TO_CHAR, - transmute::TRANSMUTE_INT_TO_FLOAT, - transmute::TRANSMUTE_PTR_TO_PTR, - transmute::TRANSMUTE_PTR_TO_REF, - transmute::UNSOUND_COLLECTION_TRANSMUTE, - transmute::USELESS_TRANSMUTE, - transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, - trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, - try_err::TRY_ERR, - types::ABSURD_EXTREME_COMPARISONS, - types::BORROWED_BOX, - types::BOX_VEC, - types::CAST_PTR_ALIGNMENT, - types::CAST_REF_TO_MUT, - types::CHAR_LIT_AS_U8, - types::FN_TO_NUMERIC_CAST, - types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - types::IMPLICIT_HASHER, - types::LET_UNIT_VALUE, - types::OPTION_OPTION, - types::TYPE_COMPLEXITY, - types::UNIT_ARG, - types::UNIT_CMP, - types::UNNECESSARY_CAST, - types::VEC_BOX, - unicode::ZERO_WIDTH_SPACE, - unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - unused_io_amount::UNUSED_IO_AMOUNT, - unused_label::UNUSED_LABEL, - unwrap::PANICKING_UNWRAP, - unwrap::UNNECESSARY_UNWRAP, - vec::USELESS_VEC, - write::PRINTLN_EMPTY_STRING, - write::PRINT_LITERAL, - write::PRINT_WITH_NEWLINE, - write::WRITELN_EMPTY_STRING, - write::WRITE_LITERAL, - write::WRITE_WITH_NEWLINE, - zero_div_zero::ZERO_DIVIDED_BY_ZERO, + store.register_group(true, "clippy::all", Some("clippy"), vec![ + LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(&assign_ops::ASSIGN_OP_PATTERN), + LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&attrs::DEPRECATED_CFG_ATTR), + LintId::of(&attrs::DEPRECATED_SEMVER), + LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), + LintId::of(&attrs::USELESS_ATTRIBUTE), + LintId::of(&bit_mask::BAD_BIT_MASK), + LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(&bit_mask::VERBOSE_BIT_MASK), + LintId::of(&blacklisted_name::BLACKLISTED_NAME), + LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR), + LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT), + LintId::of(&booleans::LOGIC_BUG), + LintId::of(&booleans::NONMINIMAL_BOOL), + LintId::of(&bytecount::NAIVE_BYTECOUNT), + LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&comparison_chain::COMPARISON_CHAIN), + LintId::of(&copies::IFS_SAME_COND), + LintId::of(&copies::IF_SAME_THEN_ELSE), + LintId::of(&derive::DERIVE_HASH_XOR_EQ), + LintId::of(&doc::MISSING_SAFETY_DOC), + LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(&double_comparison::DOUBLE_COMPARISONS), + LintId::of(&double_parens::DOUBLE_PARENS), + LintId::of(&drop_bounds::DROP_BOUNDS), + LintId::of(&drop_forget_ref::DROP_COPY), + LintId::of(&drop_forget_ref::DROP_REF), + LintId::of(&drop_forget_ref::FORGET_COPY), + LintId::of(&drop_forget_ref::FORGET_REF), + LintId::of(&duration_subsec::DURATION_SUBSEC), + LintId::of(&entry::MAP_ENTRY), + LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(&enum_variants::ENUM_VARIANT_NAMES), + LintId::of(&enum_variants::MODULE_INCEPTION), + LintId::of(&eq_op::EQ_OP), + LintId::of(&eq_op::OP_REF), + LintId::of(&erasing_op::ERASING_OP), + LintId::of(&escape::BOXED_LOCAL), + LintId::of(&eta_reduction::REDUNDANT_CLOSURE), + LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(&excessive_precision::EXCESSIVE_PRECISION), + LintId::of(&explicit_write::EXPLICIT_WRITE), + LintId::of(&format::USELESS_FORMAT), + LintId::of(&formatting::POSSIBLE_MISSING_COMMA), + LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(&functions::DOUBLE_MUST_USE), + LintId::of(&functions::MUST_USE_UNIT), + LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(&functions::TOO_MANY_ARGUMENTS), + LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(&identity_conversion::IDENTITY_CONVERSION), + LintId::of(&identity_op::IDENTITY_OP), + LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(&infinite_iter::INFINITE_ITER), + LintId::of(&inherent_to_string::INHERENT_TO_STRING), + LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(&int_plus_one::INT_PLUS_ONE), + LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(&len_zero::LEN_ZERO), + LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(&lifetimes::NEEDLESS_LIFETIMES), + LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(&literal_representation::UNREADABLE_LITERAL), + LintId::of(&loops::EMPTY_LOOP), + LintId::of(&loops::EXPLICIT_COUNTER_LOOP), + LintId::of(&loops::FOR_KV_MAP), + LintId::of(&loops::FOR_LOOP_OVER_OPTION), + LintId::of(&loops::FOR_LOOP_OVER_RESULT), + LintId::of(&loops::ITER_NEXT_LOOP), + LintId::of(&loops::MANUAL_MEMCPY), + LintId::of(&loops::MUT_RANGE_BOUND), + LintId::of(&loops::NEEDLESS_COLLECT), + LintId::of(&loops::NEEDLESS_RANGE_LOOP), + LintId::of(&loops::NEVER_LOOP), + LintId::of(&loops::REVERSE_RANGE_LOOP), + LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(&loops::WHILE_LET_LOOP), + LintId::of(&loops::WHILE_LET_ON_ITERATOR), + LintId::of(&main_recursion::MAIN_RECURSION), + LintId::of(&map_clone::MAP_CLONE), + LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(&matches::MATCH_AS_REF), + LintId::of(&matches::MATCH_BOOL), + LintId::of(&matches::MATCH_OVERLAPPING_ARM), + LintId::of(&matches::MATCH_REF_PATS), + LintId::of(&matches::MATCH_WILD_ERR_ARM), + LintId::of(&matches::SINGLE_MATCH), + LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(&methods::CHARS_LAST_CMP), + LintId::of(&methods::CHARS_NEXT_CMP), + LintId::of(&methods::CLONE_DOUBLE_REF), + LintId::of(&methods::CLONE_ON_COPY), + LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::FILTER_NEXT), + LintId::of(&methods::FLAT_MAP_IDENTITY), + LintId::of(&methods::INEFFICIENT_TO_STRING), + LintId::of(&methods::INTO_ITER_ON_ARRAY), + LintId::of(&methods::INTO_ITER_ON_REF), + LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NTH), + LintId::of(&methods::ITER_SKIP_NEXT), + LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::NEW_RET_NO_SELF), + LintId::of(&methods::OK_EXPECT), + LintId::of(&methods::OPTION_AND_THEN_SOME), + LintId::of(&methods::OPTION_MAP_OR_NONE), + LintId::of(&methods::OR_FUN_CALL), + LintId::of(&methods::SEARCH_IS_SOME), + LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::SINGLE_CHAR_PATTERN), + LintId::of(&methods::STRING_EXTEND_CHARS), + LintId::of(&methods::SUSPICIOUS_MAP), + LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR), + LintId::of(&methods::UNINIT_ASSUMED_INIT), + LintId::of(&methods::UNNECESSARY_FILTER_MAP), + LintId::of(&methods::UNNECESSARY_FOLD), + LintId::of(&methods::USELESS_ASREF), + LintId::of(&methods::WRONG_SELF_CONVENTION), + LintId::of(&minmax::MIN_MAX), + LintId::of(&misc::CMP_NAN), + LintId::of(&misc::CMP_OWNED), + LintId::of(&misc::FLOAT_CMP), + LintId::of(&misc::MODULO_ONE), + LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(&misc::TOPLEVEL_REF_ARG), + LintId::of(&misc::ZERO_PTR), + LintId::of(&misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(&misc_early::DOUBLE_NEG), + LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL), + LintId::of(&misc_early::REDUNDANT_PATTERN), + LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(&mul_add::MANUAL_MUL_ADD), + LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), + LintId::of(&mutex_atomic::MUTEX_ATOMIC), + LintId::of(&needless_bool::BOOL_COMPARISON), + LintId::of(&needless_bool::NEEDLESS_BOOL), + LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(&needless_update::NEEDLESS_UPDATE), + LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(&neg_multiply::NEG_MULTIPLY), + LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(&no_effect::NO_EFFECT), + LintId::of(&no_effect::UNNECESSARY_OPERATION), + LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(&panic_unimplemented::PANIC_PARAMS), + LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(&precedence::PRECEDENCE), + LintId::of(&ptr::CMP_NULL), + LintId::of(&ptr::MUT_FROM_REF), + LintId::of(&ptr::PTR_ARG), + LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(&question_mark::QUESTION_MARK), + LintId::of(&ranges::ITERATOR_STEP_BY_ZERO), + LintId::of(&ranges::RANGE_MINUS_ONE), + LintId::of(&ranges::RANGE_PLUS_ONE), + LintId::of(&ranges::RANGE_ZIP_WITH_LEN), + LintId::of(&redundant_clone::REDUNDANT_CLONE), + LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), + LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(&reference::DEREF_ADDROF), + LintId::of(&reference::REF_IN_DEREF), + LintId::of(®ex::INVALID_REGEX), + LintId::of(®ex::REGEX_MACRO), + LintId::of(®ex::TRIVIAL_REGEX), + LintId::of(&returns::LET_AND_RETURN), + LintId::of(&returns::NEEDLESS_RETURN), + LintId::of(&returns::UNUSED_UNIT), + LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(&strings::STRING_LIT_AS_BYTES), + LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(&swap::ALMOST_SWAPPED), + LintId::of(&swap::MANUAL_SWAP), + LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(&transmute::USELESS_TRANSMUTE), + LintId::of(&transmute::WRONG_TRANSMUTE), + LintId::of(&transmuting_null::TRANSMUTING_NULL), + LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), + LintId::of(&try_err::TRY_ERR), + LintId::of(&types::ABSURD_EXTREME_COMPARISONS), + LintId::of(&types::BORROWED_BOX), + LintId::of(&types::BOX_VEC), + LintId::of(&types::CAST_PTR_ALIGNMENT), + LintId::of(&types::CAST_REF_TO_MUT), + LintId::of(&types::CHAR_LIT_AS_U8), + LintId::of(&types::FN_TO_NUMERIC_CAST), + LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(&types::IMPLICIT_HASHER), + LintId::of(&types::LET_UNIT_VALUE), + LintId::of(&types::OPTION_OPTION), + LintId::of(&types::TYPE_COMPLEXITY), + LintId::of(&types::UNIT_ARG), + LintId::of(&types::UNIT_CMP), + LintId::of(&types::UNNECESSARY_CAST), + LintId::of(&types::VEC_BOX), + LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(&unused_label::UNUSED_LABEL), + LintId::of(&unwrap::PANICKING_UNWRAP), + LintId::of(&unwrap::UNNECESSARY_UNWRAP), + LintId::of(&vec::USELESS_VEC), + LintId::of(&write::PRINTLN_EMPTY_STRING), + LintId::of(&write::PRINT_LITERAL), + LintId::of(&write::PRINT_WITH_NEWLINE), + LintId::of(&write::WRITELN_EMPTY_STRING), + LintId::of(&write::WRITE_LITERAL), + LintId::of(&write::WRITE_WITH_NEWLINE), + LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); - reg.register_lint_group("clippy::style", Some("clippy_style"), vec![ - assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assign_ops::ASSIGN_OP_PATTERN, - attrs::UNKNOWN_CLIPPY_LINTS, - bit_mask::VERBOSE_BIT_MASK, - blacklisted_name::BLACKLISTED_NAME, - block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, - block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, - collapsible_if::COLLAPSIBLE_IF, - comparison_chain::COMPARISON_CHAIN, - doc::MISSING_SAFETY_DOC, - doc::NEEDLESS_DOCTEST_MAIN, - enum_variants::ENUM_VARIANT_NAMES, - enum_variants::MODULE_INCEPTION, - eq_op::OP_REF, - eta_reduction::REDUNDANT_CLOSURE, - excessive_precision::EXCESSIVE_PRECISION, - formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - formatting::SUSPICIOUS_ELSE_FORMATTING, - formatting::SUSPICIOUS_UNARY_OP_FORMATTING, - functions::DOUBLE_MUST_USE, - functions::MUST_USE_UNIT, - infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, - inherent_to_string::INHERENT_TO_STRING, - len_zero::LEN_WITHOUT_IS_EMPTY, - len_zero::LEN_ZERO, - let_if_seq::USELESS_LET_IF_SEQ, - literal_representation::INCONSISTENT_DIGIT_GROUPING, - literal_representation::UNREADABLE_LITERAL, - loops::EMPTY_LOOP, - loops::FOR_KV_MAP, - loops::NEEDLESS_RANGE_LOOP, - loops::WHILE_LET_ON_ITERATOR, - main_recursion::MAIN_RECURSION, - map_clone::MAP_CLONE, - matches::MATCH_BOOL, - matches::MATCH_OVERLAPPING_ARM, - matches::MATCH_REF_PATS, - matches::MATCH_WILD_ERR_ARM, - matches::SINGLE_MATCH, - mem_replace::MEM_REPLACE_OPTION_WITH_NONE, - methods::CHARS_LAST_CMP, - methods::INTO_ITER_ON_REF, - methods::ITER_CLONED_COLLECT, - methods::ITER_SKIP_NEXT, - methods::MANUAL_SATURATING_ARITHMETIC, - methods::NEW_RET_NO_SELF, - methods::OK_EXPECT, - methods::OPTION_MAP_OR_NONE, - methods::SHOULD_IMPLEMENT_TRAIT, - methods::STRING_EXTEND_CHARS, - methods::UNNECESSARY_FOLD, - methods::WRONG_SELF_CONVENTION, - misc::TOPLEVEL_REF_ARG, - misc::ZERO_PTR, - misc_early::BUILTIN_TYPE_SHADOW, - misc_early::DOUBLE_NEG, - misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - misc_early::MIXED_CASE_HEX_LITERALS, - misc_early::REDUNDANT_PATTERN, - misc_early::UNNEEDED_FIELD_PATTERN, - mut_reference::UNNECESSARY_MUT_PASSED, - neg_multiply::NEG_MULTIPLY, - new_without_default::NEW_WITHOUT_DEFAULT, - non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, - non_expressive_names::MANY_SINGLE_CHAR_NAMES, - ok_if_let::IF_LET_SOME_RESULT, - panic_unimplemented::PANIC_PARAMS, - ptr::CMP_NULL, - ptr::PTR_ARG, - question_mark::QUESTION_MARK, - redundant_field_names::REDUNDANT_FIELD_NAMES, - redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, - redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, - regex::REGEX_MACRO, - regex::TRIVIAL_REGEX, - returns::LET_AND_RETURN, - returns::NEEDLESS_RETURN, - returns::UNUSED_UNIT, - strings::STRING_LIT_AS_BYTES, - try_err::TRY_ERR, - types::FN_TO_NUMERIC_CAST, - types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - types::IMPLICIT_HASHER, - types::LET_UNIT_VALUE, - unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - write::PRINTLN_EMPTY_STRING, - write::PRINT_LITERAL, - write::PRINT_WITH_NEWLINE, - write::WRITELN_EMPTY_STRING, - write::WRITE_LITERAL, - write::WRITE_WITH_NEWLINE, + store.register_group(true, "clippy::style", Some("clippy_style"), vec![ + LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(&assign_ops::ASSIGN_OP_PATTERN), + LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), + LintId::of(&bit_mask::VERBOSE_BIT_MASK), + LintId::of(&blacklisted_name::BLACKLISTED_NAME), + LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR), + LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT), + LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&comparison_chain::COMPARISON_CHAIN), + LintId::of(&doc::MISSING_SAFETY_DOC), + LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(&enum_variants::ENUM_VARIANT_NAMES), + LintId::of(&enum_variants::MODULE_INCEPTION), + LintId::of(&eq_op::OP_REF), + LintId::of(&eta_reduction::REDUNDANT_CLOSURE), + LintId::of(&excessive_precision::EXCESSIVE_PRECISION), + LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(&functions::DOUBLE_MUST_USE), + LintId::of(&functions::MUST_USE_UNIT), + LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(&inherent_to_string::INHERENT_TO_STRING), + LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(&len_zero::LEN_ZERO), + LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(&literal_representation::UNREADABLE_LITERAL), + LintId::of(&loops::EMPTY_LOOP), + LintId::of(&loops::FOR_KV_MAP), + LintId::of(&loops::NEEDLESS_RANGE_LOOP), + LintId::of(&loops::WHILE_LET_ON_ITERATOR), + LintId::of(&main_recursion::MAIN_RECURSION), + LintId::of(&map_clone::MAP_CLONE), + LintId::of(&matches::MATCH_BOOL), + LintId::of(&matches::MATCH_OVERLAPPING_ARM), + LintId::of(&matches::MATCH_REF_PATS), + LintId::of(&matches::MATCH_WILD_ERR_ARM), + LintId::of(&matches::SINGLE_MATCH), + LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(&methods::CHARS_LAST_CMP), + LintId::of(&methods::INTO_ITER_ON_REF), + LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_SKIP_NEXT), + LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::NEW_RET_NO_SELF), + LintId::of(&methods::OK_EXPECT), + LintId::of(&methods::OPTION_MAP_OR_NONE), + LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::STRING_EXTEND_CHARS), + LintId::of(&methods::UNNECESSARY_FOLD), + LintId::of(&methods::WRONG_SELF_CONVENTION), + LintId::of(&misc::TOPLEVEL_REF_ARG), + LintId::of(&misc::ZERO_PTR), + LintId::of(&misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(&misc_early::DOUBLE_NEG), + LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(&misc_early::REDUNDANT_PATTERN), + LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(&neg_multiply::NEG_MULTIPLY), + LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&panic_unimplemented::PANIC_PARAMS), + LintId::of(&ptr::CMP_NULL), + LintId::of(&ptr::PTR_ARG), + LintId::of(&question_mark::QUESTION_MARK), + LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), + LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(®ex::REGEX_MACRO), + LintId::of(®ex::TRIVIAL_REGEX), + LintId::of(&returns::LET_AND_RETURN), + LintId::of(&returns::NEEDLESS_RETURN), + LintId::of(&returns::UNUSED_UNIT), + LintId::of(&strings::STRING_LIT_AS_BYTES), + LintId::of(&try_err::TRY_ERR), + LintId::of(&types::FN_TO_NUMERIC_CAST), + LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(&types::IMPLICIT_HASHER), + LintId::of(&types::LET_UNIT_VALUE), + LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(&write::PRINTLN_EMPTY_STRING), + LintId::of(&write::PRINT_LITERAL), + LintId::of(&write::PRINT_WITH_NEWLINE), + LintId::of(&write::WRITELN_EMPTY_STRING), + LintId::of(&write::WRITE_LITERAL), + LintId::of(&write::WRITE_WITH_NEWLINE), ]); - reg.register_lint_group("clippy::complexity", Some("clippy_complexity"), vec![ - assign_ops::MISREFACTORED_ASSIGN_OP, - attrs::DEPRECATED_CFG_ATTR, - booleans::NONMINIMAL_BOOL, - cognitive_complexity::COGNITIVE_COMPLEXITY, - double_comparison::DOUBLE_COMPARISONS, - double_parens::DOUBLE_PARENS, - duration_subsec::DURATION_SUBSEC, - eval_order_dependence::DIVERGING_SUB_EXPRESSION, - eval_order_dependence::EVAL_ORDER_DEPENDENCE, - explicit_write::EXPLICIT_WRITE, - format::USELESS_FORMAT, - functions::TOO_MANY_ARGUMENTS, - get_last_with_len::GET_LAST_WITH_LEN, - identity_conversion::IDENTITY_CONVERSION, - identity_op::IDENTITY_OP, - int_plus_one::INT_PLUS_ONE, - lifetimes::EXTRA_UNUSED_LIFETIMES, - lifetimes::NEEDLESS_LIFETIMES, - loops::EXPLICIT_COUNTER_LOOP, - loops::MUT_RANGE_BOUND, - loops::WHILE_LET_LOOP, - map_unit_fn::OPTION_MAP_UNIT_FN, - map_unit_fn::RESULT_MAP_UNIT_FN, - matches::MATCH_AS_REF, - methods::CHARS_NEXT_CMP, - methods::CLONE_ON_COPY, - methods::FILTER_NEXT, - methods::FLAT_MAP_IDENTITY, - methods::OPTION_AND_THEN_SOME, - methods::SEARCH_IS_SOME, - methods::SUSPICIOUS_MAP, - methods::UNNECESSARY_FILTER_MAP, - methods::USELESS_ASREF, - misc::SHORT_CIRCUIT_STATEMENT, - misc_early::REDUNDANT_CLOSURE_CALL, - misc_early::UNNEEDED_WILDCARD_PATTERN, - misc_early::ZERO_PREFIXED_LITERAL, - needless_bool::BOOL_COMPARISON, - needless_bool::NEEDLESS_BOOL, - needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, - needless_update::NEEDLESS_UPDATE, - neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, - no_effect::NO_EFFECT, - no_effect::UNNECESSARY_OPERATION, - overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - partialeq_ne_impl::PARTIALEQ_NE_IMPL, - precedence::PRECEDENCE, - ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, - ranges::RANGE_MINUS_ONE, - ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, - reference::DEREF_ADDROF, - reference::REF_IN_DEREF, - swap::MANUAL_SWAP, - temporary_assignment::TEMPORARY_ASSIGNMENT, - transmute::CROSSPOINTER_TRANSMUTE, - transmute::TRANSMUTE_BYTES_TO_STR, - transmute::TRANSMUTE_INT_TO_BOOL, - transmute::TRANSMUTE_INT_TO_CHAR, - transmute::TRANSMUTE_INT_TO_FLOAT, - transmute::TRANSMUTE_PTR_TO_PTR, - transmute::TRANSMUTE_PTR_TO_REF, - transmute::USELESS_TRANSMUTE, - types::BORROWED_BOX, - types::CHAR_LIT_AS_U8, - types::OPTION_OPTION, - types::TYPE_COMPLEXITY, - types::UNIT_ARG, - types::UNNECESSARY_CAST, - types::VEC_BOX, - unused_label::UNUSED_LABEL, - unwrap::UNNECESSARY_UNWRAP, - zero_div_zero::ZERO_DIVIDED_BY_ZERO, + store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ + LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&attrs::DEPRECATED_CFG_ATTR), + LintId::of(&booleans::NONMINIMAL_BOOL), + LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(&double_comparison::DOUBLE_COMPARISONS), + LintId::of(&double_parens::DOUBLE_PARENS), + LintId::of(&duration_subsec::DURATION_SUBSEC), + LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(&explicit_write::EXPLICIT_WRITE), + LintId::of(&format::USELESS_FORMAT), + LintId::of(&functions::TOO_MANY_ARGUMENTS), + LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(&identity_conversion::IDENTITY_CONVERSION), + LintId::of(&identity_op::IDENTITY_OP), + LintId::of(&int_plus_one::INT_PLUS_ONE), + LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(&lifetimes::NEEDLESS_LIFETIMES), + LintId::of(&loops::EXPLICIT_COUNTER_LOOP), + LintId::of(&loops::MUT_RANGE_BOUND), + LintId::of(&loops::WHILE_LET_LOOP), + LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(&matches::MATCH_AS_REF), + LintId::of(&methods::CHARS_NEXT_CMP), + LintId::of(&methods::CLONE_ON_COPY), + LintId::of(&methods::FILTER_NEXT), + LintId::of(&methods::FLAT_MAP_IDENTITY), + LintId::of(&methods::OPTION_AND_THEN_SOME), + LintId::of(&methods::SEARCH_IS_SOME), + LintId::of(&methods::SUSPICIOUS_MAP), + LintId::of(&methods::UNNECESSARY_FILTER_MAP), + LintId::of(&methods::USELESS_ASREF), + LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL), + LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(&needless_bool::BOOL_COMPARISON), + LintId::of(&needless_bool::NEEDLESS_BOOL), + LintId::of(&needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(&needless_update::NEEDLESS_UPDATE), + LintId::of(&neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(&no_effect::NO_EFFECT), + LintId::of(&no_effect::UNNECESSARY_OPERATION), + LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(&precedence::PRECEDENCE), + LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(&ranges::RANGE_MINUS_ONE), + LintId::of(&ranges::RANGE_PLUS_ONE), + LintId::of(&ranges::RANGE_ZIP_WITH_LEN), + LintId::of(&reference::DEREF_ADDROF), + LintId::of(&reference::REF_IN_DEREF), + LintId::of(&swap::MANUAL_SWAP), + LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(&transmute::USELESS_TRANSMUTE), + LintId::of(&types::BORROWED_BOX), + LintId::of(&types::CHAR_LIT_AS_U8), + LintId::of(&types::OPTION_OPTION), + LintId::of(&types::TYPE_COMPLEXITY), + LintId::of(&types::UNIT_ARG), + LintId::of(&types::UNNECESSARY_CAST), + LintId::of(&types::VEC_BOX), + LintId::of(&unused_label::UNUSED_LABEL), + LintId::of(&unwrap::UNNECESSARY_UNWRAP), + LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); - reg.register_lint_group("clippy::correctness", Some("clippy_correctness"), vec![ - approx_const::APPROX_CONSTANT, - attrs::DEPRECATED_SEMVER, - attrs::USELESS_ATTRIBUTE, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - booleans::LOGIC_BUG, - copies::IFS_SAME_COND, - copies::IF_SAME_THEN_ELSE, - derive::DERIVE_HASH_XOR_EQ, - drop_bounds::DROP_BOUNDS, - drop_forget_ref::DROP_COPY, - drop_forget_ref::DROP_REF, - drop_forget_ref::FORGET_COPY, - drop_forget_ref::FORGET_REF, - enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - eq_op::EQ_OP, - erasing_op::ERASING_OP, - formatting::POSSIBLE_MISSING_COMMA, - functions::NOT_UNSAFE_PTR_ARG_DEREF, - indexing_slicing::OUT_OF_BOUNDS_INDEXING, - infinite_iter::INFINITE_ITER, - inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, - inline_fn_without_body::INLINE_FN_WITHOUT_BODY, - literal_representation::MISTYPED_LITERAL_SUFFIXES, - loops::FOR_LOOP_OVER_OPTION, - loops::FOR_LOOP_OVER_RESULT, - loops::ITER_NEXT_LOOP, - loops::NEVER_LOOP, - loops::REVERSE_RANGE_LOOP, - loops::WHILE_IMMUTABLE_CONDITION, - mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, - mem_replace::MEM_REPLACE_WITH_UNINIT, - methods::CLONE_DOUBLE_REF, - methods::INTO_ITER_ON_ARRAY, - methods::TEMPORARY_CSTRING_AS_PTR, - methods::UNINIT_ASSUMED_INIT, - minmax::MIN_MAX, - misc::CMP_NAN, - misc::FLOAT_CMP, - misc::MODULO_ONE, - mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, - non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, - non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, - open_options::NONSENSICAL_OPEN_OPTIONS, - ptr::MUT_FROM_REF, - ranges::ITERATOR_STEP_BY_ZERO, - regex::INVALID_REGEX, - serde_api::SERDE_API_MISUSE, - suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, - suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, - swap::ALMOST_SWAPPED, - transmute::UNSOUND_COLLECTION_TRANSMUTE, - transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, - types::ABSURD_EXTREME_COMPARISONS, - types::CAST_PTR_ALIGNMENT, - types::CAST_REF_TO_MUT, - types::UNIT_CMP, - unicode::ZERO_WIDTH_SPACE, - unused_io_amount::UNUSED_IO_AMOUNT, - unwrap::PANICKING_UNWRAP, + store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ + LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&attrs::DEPRECATED_SEMVER), + LintId::of(&attrs::USELESS_ATTRIBUTE), + LintId::of(&bit_mask::BAD_BIT_MASK), + LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(&booleans::LOGIC_BUG), + LintId::of(&copies::IFS_SAME_COND), + LintId::of(&copies::IF_SAME_THEN_ELSE), + LintId::of(&derive::DERIVE_HASH_XOR_EQ), + LintId::of(&drop_bounds::DROP_BOUNDS), + LintId::of(&drop_forget_ref::DROP_COPY), + LintId::of(&drop_forget_ref::DROP_REF), + LintId::of(&drop_forget_ref::FORGET_COPY), + LintId::of(&drop_forget_ref::FORGET_REF), + LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(&eq_op::EQ_OP), + LintId::of(&erasing_op::ERASING_OP), + LintId::of(&formatting::POSSIBLE_MISSING_COMMA), + LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(&infinite_iter::INFINITE_ITER), + LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(&loops::FOR_LOOP_OVER_OPTION), + LintId::of(&loops::FOR_LOOP_OVER_RESULT), + LintId::of(&loops::ITER_NEXT_LOOP), + LintId::of(&loops::NEVER_LOOP), + LintId::of(&loops::REVERSE_RANGE_LOOP), + LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(&methods::CLONE_DOUBLE_REF), + LintId::of(&methods::INTO_ITER_ON_ARRAY), + LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR), + LintId::of(&methods::UNINIT_ASSUMED_INIT), + LintId::of(&minmax::MIN_MAX), + LintId::of(&misc::CMP_NAN), + LintId::of(&misc::FLOAT_CMP), + LintId::of(&misc::MODULO_ONE), + LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), + LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(&ptr::MUT_FROM_REF), + LintId::of(&ranges::ITERATOR_STEP_BY_ZERO), + LintId::of(®ex::INVALID_REGEX), + LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(&swap::ALMOST_SWAPPED), + LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(&transmute::WRONG_TRANSMUTE), + LintId::of(&transmuting_null::TRANSMUTING_NULL), + LintId::of(&types::ABSURD_EXTREME_COMPARISONS), + LintId::of(&types::CAST_PTR_ALIGNMENT), + LintId::of(&types::CAST_REF_TO_MUT), + LintId::of(&types::UNIT_CMP), + LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(&unwrap::PANICKING_UNWRAP), ]); - reg.register_lint_group("clippy::perf", Some("clippy_perf"), vec![ - bytecount::NAIVE_BYTECOUNT, - entry::MAP_ENTRY, - escape::BOXED_LOCAL, - large_enum_variant::LARGE_ENUM_VARIANT, - loops::MANUAL_MEMCPY, - loops::NEEDLESS_COLLECT, - methods::EXPECT_FUN_CALL, - methods::INEFFICIENT_TO_STRING, - methods::ITER_NTH, - methods::OR_FUN_CALL, - methods::SINGLE_CHAR_PATTERN, - misc::CMP_OWNED, - mul_add::MANUAL_MUL_ADD, - mutex_atomic::MUTEX_ATOMIC, - redundant_clone::REDUNDANT_CLONE, - slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF, - types::BOX_VEC, - vec::USELESS_VEC, + store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ + LintId::of(&bytecount::NAIVE_BYTECOUNT), + LintId::of(&entry::MAP_ENTRY), + LintId::of(&escape::BOXED_LOCAL), + LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(&loops::MANUAL_MEMCPY), + LintId::of(&loops::NEEDLESS_COLLECT), + LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::INEFFICIENT_TO_STRING), + LintId::of(&methods::ITER_NTH), + LintId::of(&methods::OR_FUN_CALL), + LintId::of(&methods::SINGLE_CHAR_PATTERN), + LintId::of(&misc::CMP_OWNED), + LintId::of(&mul_add::MANUAL_MUL_ADD), + LintId::of(&mutex_atomic::MUTEX_ATOMIC), + LintId::of(&redundant_clone::REDUNDANT_CLONE), + LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), + LintId::of(&types::BOX_VEC), + LintId::of(&vec::USELESS_VEC), ]); - reg.register_lint_group("clippy::cargo", Some("clippy_cargo"), vec![ - cargo_common_metadata::CARGO_COMMON_METADATA, - multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, - wildcard_dependencies::WILDCARD_DEPENDENCIES, + store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ + LintId::of(&cargo_common_metadata::CARGO_COMMON_METADATA), + LintId::of(&multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), + LintId::of(&wildcard_dependencies::WILDCARD_DEPENDENCIES), ]); - reg.register_lint_group("clippy::nursery", Some("clippy_nursery"), vec![ - attrs::EMPTY_LINE_AFTER_OUTER_ATTR, - fallible_impl_from::FALLIBLE_IMPL_FROM, - missing_const_for_fn::MISSING_CONST_FOR_FN, - mutex_atomic::MUTEX_INTEGER, - needless_borrow::NEEDLESS_BORROW, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ + LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), + LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), + LintId::of(&mutex_atomic::MUTEX_INTEGER), + LintId::of(&needless_borrow::NEEDLESS_BORROW), + LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), ]); } diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index bdc679c902a..a5617f781a6 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -54,6 +54,7 @@ declare_clippy_lint! { "functions taking small copyable arguments by reference" } +#[derive(Copy, Clone)] pub struct TriviallyCopyPassByRef { limit: u64, } @@ -159,7 +160,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { return; } } - }, + } FnKind::Method(..) => (), _ => return, } diff --git a/src/driver.rs b/src/driver.rs index 359d2f8530c..d2f81066dde 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -61,51 +61,20 @@ fn test_arg_value() { struct ClippyCallbacks; impl rustc_driver::Callbacks for ClippyCallbacks { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> rustc_driver::Compilation { - let sess = compiler.session(); - let mut registry = rustc_driver::plugin::registry::Registry::new( - sess, - compiler - .parse() - .expect( - "at this compilation stage \ - the crate must be parsed", - ) - .peek() - .span, - ); - registry.args_hidden = Some(Vec::new()); - - let conf = clippy_lints::read_conf(®istry); - clippy_lints::register_plugins(&mut registry, &conf); - - let rustc_driver::plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, false, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, false, false, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); - } - clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf); - clippy_lints::register_renamed(&mut ls); - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); + fn config(&mut self, config: &mut interface::Config) { + let previous = config.register_lints.take(); + config.register_lints = Some(Box::new(move |sess, mut lint_store| { + // technically we're ~guaranteed that this is none but might as well call anything that + // is there already. Certainly it can't hurt. + if let Some(previous) = &previous { + (previous)(sess, lint_store); + } - // Continue execution - rustc_driver::Compilation::Continue + let conf = clippy_lints::read_conf(&[], &sess); + clippy_lints::register_plugins(&mut lint_store, &sess, &conf); + clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf); + clippy_lints::register_renamed(&mut lint_store); + })); } } diff --git a/src/lib.rs b/src/lib.rs index 76e1c711656..6b398f6b9aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,22 +11,20 @@ use self::rustc_driver::plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry<'_>) { - reg.sess.lint_store.with_read_lock(|lint_store| { - for (lint, _, _) in lint_store.get_lint_groups() { - reg.sess - .struct_warn( - "the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature", - ) - .emit(); - if lint == "clippy" { - // cargo clippy run on a crate that also uses the plugin - return; - } + for (lint, _, _) in reg.lint_store.get_lint_groups() { + reg.sess + .struct_warn( + "the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature", + ) + .emit(); + if lint == "clippy" { + // cargo clippy run on a crate that also uses the plugin + return; } - }); + } - let conf = clippy_lints::read_conf(reg); - clippy_lints::register_plugins(reg, &conf); + let conf = clippy_lints::read_conf(reg.args(), ®.sess); + clippy_lints::register_plugins(&mut reg.lint_store, ®.sess, &conf); } // only exists to let the dogfood integration test works. -- cgit 1.4.1-3-g733a5 From a127e14631769f20a1d0a51e658986b15305da00 Mon Sep 17 00:00:00 2001 From: msizanoen <qtmlabs@protonmail.com> Date: Tue, 22 Oct 2019 12:56:26 +0700 Subject: Remove clippy plugin --- Cargo.toml | 5 ----- src/lib.rs | 35 ----------------------------------- 2 files changed, 40 deletions(-) delete mode 100644 src/lib.rs (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index 1f5e2bb4035..300e40d4e35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,11 +22,6 @@ publish = false travis-ci = { repository = "rust-lang/rust-clippy" } appveyor = { repository = "rust-lang/rust-clippy" } -[lib] -name = "clippy" -plugin = true -test = false - [[bin]] name = "cargo-clippy" test = false diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 6b398f6b9aa..00000000000 --- a/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -// error-pattern:cargo-clippy -#![feature(plugin_registrar)] -#![feature(rustc_private)] -#![warn(rust_2018_idioms)] - -// FIXME: switch to something more ergonomic here, once available. -// (Currently there is no way to opt into sysroot crates without `extern crate`.) -#[allow(unused_extern_crates)] -extern crate rustc_driver; -use self::rustc_driver::plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry<'_>) { - for (lint, _, _) in reg.lint_store.get_lint_groups() { - reg.sess - .struct_warn( - "the clippy plugin is being deprecated, please use cargo clippy or rls with the clippy feature", - ) - .emit(); - if lint == "clippy" { - // cargo clippy run on a crate that also uses the plugin - return; - } - } - - let conf = clippy_lints::read_conf(reg.args(), ®.sess); - clippy_lints::register_plugins(&mut reg.lint_store, ®.sess, &conf); -} - -// only exists to let the dogfood integration test works. -// Don't run clippy as an executable directly -#[allow(dead_code)] -fn main() { - panic!("Please use the cargo-clippy executable"); -} -- cgit 1.4.1-3-g733a5 From 1e1d45a0055eb7c67972e698d7dcd86378ce9ebe Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Sat, 26 Oct 2019 19:56:36 +0200 Subject: Move manual_mul_add into nursery --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/mul_add.rs | 6 ++++-- src/lintlist/mod.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 005b734c16f..71745190324 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1183,7 +1183,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_ATOMIC), @@ -1527,7 +1526,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::OR_FUN_CALL), LintId::of(&methods::SINGLE_CHAR_PATTERN), LintId::of(&misc::CMP_OWNED), - LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutex_atomic::MUTEX_ATOMIC), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), @@ -1546,6 +1544,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), + LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), diff --git a/clippy_lints/src/mul_add.rs b/clippy_lints/src/mul_add.rs index 02e403eee18..5263bfbd357 100644 --- a/clippy_lints/src/mul_add.rs +++ b/clippy_lints/src/mul_add.rs @@ -15,7 +15,9 @@ declare_clippy_lint! { /// `c`. Depending on the target architecture, `mul_add()` may be more /// performant. /// - /// **Known problems:** None. + /// **Known problems:** This lint can emit semantic incorrect suggestions. + /// For example, for `a * b * c + d` the suggestion `a * b.mul_add(c, d)` + /// is emitted, which is equivalent to `a * (b * c + d)`. (#4735) /// /// **Example:** /// @@ -35,7 +37,7 @@ declare_clippy_lint! { /// let foo = a.mul_add(b, c); /// ``` pub MANUAL_MUL_ADD, - perf, + nursery, "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 48ca368f5a9..a053cf8bef0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -961,7 +961,7 @@ pub const ALL_LINTS: [Lint; 332] = [ }, Lint { name: "manual_mul_add", - group: "perf", + group: "nursery", desc: "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`", deprecation: None, module: "mul_add", -- cgit 1.4.1-3-g733a5 From 08fd397c2c8db452692dc71ce7b4d3c47417ff09 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Thu, 7 Nov 2019 13:44:57 +0100 Subject: Deprecate `into_iter_on_array` lint This lint was uplifted/reimplemented by rustc. Rustup to rust-lang/rust#66017 --- README.md | 2 +- clippy_lints/src/deprecated_lints.rs | 9 +++++ clippy_lints/src/lib.rs | 7 ++-- clippy_lints/src/methods/mod.rs | 45 ++-------------------- src/lintlist/mod.rs | 9 +---- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +++- tests/ui/for_loop_fixable.fixed | 5 +-- tests/ui/for_loop_fixable.rs | 5 +-- tests/ui/for_loop_fixable.stderr | 26 +++++-------- tests/ui/for_loop_unfixable.rs | 2 +- tests/ui/into_iter_on_ref.fixed | 3 -- tests/ui/into_iter_on_ref.rs | 3 -- tests/ui/into_iter_on_ref.stderr | 72 ++++++++++++++---------------------- 14 files changed, 67 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 87ef441eadd..41b8b4199ec 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 332 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 331 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 97ae9c78088..2ac5dca8c2e 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -130,3 +130,12 @@ declare_deprecated_lint! { pub UNUSED_COLLECT, "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** This lint has been uplifted to rustc and is now called + /// `array_into_iter`. + pub INTO_ITER_ON_ARRAY, + "this lint has been uplifted to rustc and is now called `array_into_iter`" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 817575092cc..1bd117dae94 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -430,6 +430,10 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf "clippy::unused_collect", "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", ); + store.register_removed( + "clippy::into_iter_on_array", + "this lint has been uplifted to rustc and is now called `array_into_iter`", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -584,7 +588,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &methods::FLAT_MAP_IDENTITY, &methods::GET_UNWRAP, &methods::INEFFICIENT_TO_STRING, - &methods::INTO_ITER_ON_ARRAY, &methods::INTO_ITER_ON_REF, &methods::ITER_CLONED_COLLECT, &methods::ITER_NTH, @@ -1142,7 +1145,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INEFFICIENT_TO_STRING), - LintId::of(&methods::INTO_ITER_ON_ARRAY), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NTH), @@ -1481,7 +1483,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::CLONE_DOUBLE_REF), - LintId::of(&methods::INTO_ITER_ON_ARRAY), LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR), LintId::of(&methods::UNINIT_ASSUMED_INIT), LintId::of(&minmax::MIN_MAX), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index db94d9dcdaf..c71324ea472 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -968,34 +968,6 @@ declare_clippy_lint! { "using `filter_map` when a more succinct alternative exists" } -declare_clippy_lint! { - /// **What it does:** Checks for `into_iter` calls on types which should be replaced by `iter` or - /// `iter_mut`. - /// - /// **Why is this bad?** Arrays and `PathBuf` do not yet have an `into_iter` method which move out - /// their content into an iterator. Auto-referencing resolves the `into_iter` call to its reference - /// instead, like `<&[T; N] as IntoIterator>::into_iter`, which just iterates over item references - /// like calling `iter` would. Furthermore, when the standard library actually - /// [implements the `into_iter` method](https://github.com/rust-lang/rust/issues/25725) which moves - /// the content out of the array, the original use of `into_iter` got inferred with the wrong type - /// and the code will be broken. - /// - /// **Known problems:** None - /// - /// **Example:** - /// - /// ```rust - /// let _ = [1, 2, 3].into_iter().map(|x| *x).collect::<Vec<u32>>(); - /// ``` - /// Could be written as: - /// ```rust - /// let _ = [1, 2, 3].iter().map(|x| *x).collect::<Vec<u32>>(); - /// ``` - pub INTO_ITER_ON_ARRAY, - correctness, - "using `.into_iter()` on an array" -} - declare_clippy_lint! { /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter` /// or `iter_mut`. @@ -1133,7 +1105,6 @@ declare_lint_pass!(Methods => [ USELESS_ASREF, UNNECESSARY_FOLD, UNNECESSARY_FILTER_MAP, - INTO_ITER_ON_ARRAY, INTO_ITER_ON_REF, SUSPICIOUS_MAP, UNINIT_ASSUMED_INIT, @@ -2786,16 +2757,8 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_re } } -fn ty_has_iter_method( - cx: &LateContext<'_, '_>, - self_ref_ty: Ty<'_>, -) -> Option<(&'static Lint, &'static str, &'static str)> { +fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: Ty<'_>) -> Option<(&'static str, &'static str)> { has_iter_method(cx, self_ref_ty).map(|ty_name| { - let lint = if ty_name == "array" || ty_name == "PathBuf" { - INTO_ITER_ON_ARRAY - } else { - INTO_ITER_ON_REF - }; let mutbl = match self_ref_ty.kind { ty::Ref(_, _, mutbl) => mutbl, _ => unreachable!(), @@ -2804,7 +2767,7 @@ fn ty_has_iter_method( hir::MutImmutable => "iter", hir::MutMutable => "iter_mut", }; - (lint, ty_name, method_name) + (ty_name, method_name) }) } @@ -2812,10 +2775,10 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_ if !match_trait_method(cx, expr, &paths::INTO_ITERATOR) { return; } - if let Some((lint, kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { + if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) { span_lint_and_sugg( cx, - lint, + INTO_ITER_ON_REF, method_span, &format!( "this .into_iter() call is equivalent to .{}() and will not move the {}", diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a053cf8bef0..35cbeae3988 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 332] = [ +pub const ALL_LINTS: [Lint; 331] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -812,13 +812,6 @@ pub const ALL_LINTS: [Lint; 332] = [ deprecation: None, module: "integer_division", }, - Lint { - name: "into_iter_on_array", - group: "correctness", - desc: "using `.into_iter()` on an array", - deprecation: None, - module: "methods", - }, Lint { name: "into_iter_on_ref", group: "style", diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index a928d044b7a..91d43758ab0 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -5,5 +5,6 @@ #[warn(clippy::misaligned_transmute)] #[warn(clippy::unused_collect)] #[warn(clippy::invalid_ref)] +#[warn(clippy::into_iter_on_array)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 00ed4c5e51d..d353b26e537 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -42,11 +42,17 @@ error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `i LL | #[warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter`` + --> $DIR/deprecated.rs:8:8 + | +LL | #[warn(clippy::into_iter_on_array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index 3075638ef94..ec5ff1aeeef 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -31,7 +31,7 @@ impl Unrelated { clippy::cognitive_complexity, clippy::similar_names )] -#[allow(clippy::many_single_char_names, unused_variables, clippy::into_iter_on_array)] +#[allow(clippy::many_single_char_names, unused_variables)] fn main() { const MAX_LEN: usize = 42; let mut vec = vec![1, 2, 3, 4]; @@ -102,9 +102,6 @@ fn main() { let out_vec = vec![1, 2, 3]; for _v in out_vec {} - let array = [1, 2, 3]; - for _v in &array {} - for _v in &vec {} // these are fine for _v in &mut vec {} // these are fine diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 2201596fd6a..2f42ea3ca41 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -31,7 +31,7 @@ impl Unrelated { clippy::cognitive_complexity, clippy::similar_names )] -#[allow(clippy::many_single_char_names, unused_variables, clippy::into_iter_on_array)] +#[allow(clippy::many_single_char_names, unused_variables)] fn main() { const MAX_LEN: usize = 42; let mut vec = vec![1, 2, 3, 4]; @@ -102,9 +102,6 @@ fn main() { let out_vec = vec![1, 2, 3]; for _v in out_vec.into_iter() {} - let array = [1, 2, 3]; - for _v in array.into_iter() {} - for _v in &vec {} // these are fine for _v in &mut vec {} // these are fine diff --git a/tests/ui/for_loop_fixable.stderr b/tests/ui/for_loop_fixable.stderr index 7454f40f3e2..485ba1ee7b3 100644 --- a/tests/ui/for_loop_fixable.stderr +++ b/tests/ui/for_loop_fixable.stderr @@ -77,64 +77,58 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:106:15 - | -LL | for _v in array.into_iter() {} - | ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&array` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:111:15 + --> $DIR/for_loop_fixable.rs:108:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:115:15 + --> $DIR/for_loop_fixable.rs:112:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:120:15 + --> $DIR/for_loop_fixable.rs:117:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:123:15 + --> $DIR/for_loop_fixable.rs:120:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:126:15 + --> $DIR/for_loop_fixable.rs:123:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:129:15 + --> $DIR/for_loop_fixable.rs:126:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:132:15 + --> $DIR/for_loop_fixable.rs:129:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:135:15 + --> $DIR/for_loop_fixable.rs:132:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:138:15 + --> $DIR/for_loop_fixable.rs:135:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` -error: aborting due to 18 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/for_loop_unfixable.rs b/tests/ui/for_loop_unfixable.rs index 5d94647e0db..20a93a22282 100644 --- a/tests/ui/for_loop_unfixable.rs +++ b/tests/ui/for_loop_unfixable.rs @@ -17,7 +17,7 @@ unused, dead_code )] -#[allow(clippy::many_single_char_names, unused_variables, clippy::into_iter_on_array)] +#[allow(clippy::many_single_char_names, unused_variables)] fn main() { for i in 5..5 { println!("{}", i); diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index f5342be631b..c30d23de3f8 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -1,7 +1,6 @@ // run-rustfix #![allow(clippy::useless_vec)] #![warn(clippy::into_iter_on_ref)] -#![deny(clippy::into_iter_on_array)] struct X; use std::collections::*; @@ -10,9 +9,7 @@ fn main() { for _ in &[1, 2, 3] {} for _ in vec![X, X] {} for _ in &vec![X, X] {} - for _ in [1, 2, 3].iter() {} //~ ERROR equivalent to .iter() - let _ = [1, 2, 3].iter(); //~ ERROR equivalent to .iter() let _ = vec![1, 2, 3].into_iter(); let _ = (&vec![1, 2, 3]).iter(); //~ WARN equivalent to .iter() let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ WARN equivalent to .iter() diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 5ec64dcf733..94bc1689619 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -1,7 +1,6 @@ // run-rustfix #![allow(clippy::useless_vec)] #![warn(clippy::into_iter_on_ref)] -#![deny(clippy::into_iter_on_array)] struct X; use std::collections::*; @@ -10,9 +9,7 @@ fn main() { for _ in &[1, 2, 3] {} for _ in vec![X, X] {} for _ in &vec![X, X] {} - for _ in [1, 2, 3].into_iter() {} //~ ERROR equivalent to .iter() - let _ = [1, 2, 3].into_iter(); //~ ERROR equivalent to .iter() let _ = vec![1, 2, 3].into_iter(); let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 931e4880f93..a5be50f6405 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,23 +1,5 @@ -error: this .into_iter() call is equivalent to .iter() and will not move the array - --> $DIR/into_iter_on_ref.rs:13:24 - | -LL | for _ in [1, 2, 3].into_iter() {} //~ ERROR equivalent to .iter() - | ^^^^^^^^^ help: call directly: `iter` - | -note: lint level defined here - --> $DIR/into_iter_on_ref.rs:4:9 - | -LL | #![deny(clippy::into_iter_on_array)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this .into_iter() call is equivalent to .iter() and will not move the array - --> $DIR/into_iter_on_ref.rs:15:23 - | -LL | let _ = [1, 2, 3].into_iter(); //~ ERROR equivalent to .iter() - | ^^^^^^^^^ help: call directly: `iter` - error: this .into_iter() call is equivalent to .iter() and will not move the Vec - --> $DIR/into_iter_on_ref.rs:17:30 + --> $DIR/into_iter_on_ref.rs:14:30 | LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` @@ -25,154 +7,154 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() = note: `-D clippy::into-iter-on-ref` implied by `-D warnings` error: this .into_iter() call is equivalent to .iter() and will not move the slice - --> $DIR/into_iter_on_ref.rs:18:46 + --> $DIR/into_iter_on_ref.rs:15:46 | LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the slice - --> $DIR/into_iter_on_ref.rs:19:41 + --> $DIR/into_iter_on_ref.rs:16:41 | LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the slice - --> $DIR/into_iter_on_ref.rs:20:44 + --> $DIR/into_iter_on_ref.rs:17:44 | LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the array - --> $DIR/into_iter_on_ref.rs:22:32 + --> $DIR/into_iter_on_ref.rs:19:32 | LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the array - --> $DIR/into_iter_on_ref.rs:23:36 + --> $DIR/into_iter_on_ref.rs:20:36 | LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the array - --> $DIR/into_iter_on_ref.rs:24:40 + --> $DIR/into_iter_on_ref.rs:21:40 | LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the Option - --> $DIR/into_iter_on_ref.rs:26:24 + --> $DIR/into_iter_on_ref.rs:23:24 | LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the Option - --> $DIR/into_iter_on_ref.rs:27:28 + --> $DIR/into_iter_on_ref.rs:24:28 | LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the Result - --> $DIR/into_iter_on_ref.rs:28:32 + --> $DIR/into_iter_on_ref.rs:25:32 | LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the Result - --> $DIR/into_iter_on_ref.rs:29:37 + --> $DIR/into_iter_on_ref.rs:26:37 | LL | let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the Vec - --> $DIR/into_iter_on_ref.rs:30:34 + --> $DIR/into_iter_on_ref.rs:27:34 | LL | let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the Vec - --> $DIR/into_iter_on_ref.rs:31:38 + --> $DIR/into_iter_on_ref.rs:28:38 | LL | let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the BTreeMap - --> $DIR/into_iter_on_ref.rs:32:44 + --> $DIR/into_iter_on_ref.rs:29:44 | LL | let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the BTreeMap - --> $DIR/into_iter_on_ref.rs:33:48 + --> $DIR/into_iter_on_ref.rs:30:48 | LL | let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the VecDeque - --> $DIR/into_iter_on_ref.rs:34:39 + --> $DIR/into_iter_on_ref.rs:31:39 | LL | let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the VecDeque - --> $DIR/into_iter_on_ref.rs:35:43 + --> $DIR/into_iter_on_ref.rs:32:43 | LL | let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the LinkedList - --> $DIR/into_iter_on_ref.rs:36:41 + --> $DIR/into_iter_on_ref.rs:33:41 | LL | let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the LinkedList - --> $DIR/into_iter_on_ref.rs:37:45 + --> $DIR/into_iter_on_ref.rs:34:45 | LL | let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the HashMap - --> $DIR/into_iter_on_ref.rs:38:43 + --> $DIR/into_iter_on_ref.rs:35:43 | LL | let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter_mut() and will not move the HashMap - --> $DIR/into_iter_on_ref.rs:39:47 + --> $DIR/into_iter_on_ref.rs:36:47 | LL | let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut() | ^^^^^^^^^ help: call directly: `iter_mut` error: this .into_iter() call is equivalent to .iter() and will not move the BTreeSet - --> $DIR/into_iter_on_ref.rs:41:39 + --> $DIR/into_iter_on_ref.rs:38:39 | LL | let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the BinaryHeap - --> $DIR/into_iter_on_ref.rs:42:41 + --> $DIR/into_iter_on_ref.rs:39:41 | LL | let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the HashSet - --> $DIR/into_iter_on_ref.rs:43:38 + --> $DIR/into_iter_on_ref.rs:40:38 | LL | let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the Path - --> $DIR/into_iter_on_ref.rs:44:43 + --> $DIR/into_iter_on_ref.rs:41:43 | LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` error: this .into_iter() call is equivalent to .iter() and will not move the PathBuf - --> $DIR/into_iter_on_ref.rs:45:47 + --> $DIR/into_iter_on_ref.rs:42:47 | LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 28 previous errors +error: aborting due to 26 previous errors -- cgit 1.4.1-3-g733a5 From 60c2fdd0b96829df97329e29fdb92c958a3c5d4f Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" <heinz@licenser.net> Date: Fri, 18 Oct 2019 21:10:35 +0200 Subject: Update lints --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 1 + src/lintlist/mod.rs | 7 +++++++ 3 files changed, 9 insertions(+) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b32914854f..84a3bd491cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -996,6 +996,7 @@ Released 2018-09-13 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision +[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call [`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy [`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 99bbaf32c29..d267a3d47e3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -949,6 +949,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), + LintId::of(&exit::EXIT), LintId::of(&implicit_return::IMPLICIT_RETURN), LintId::of(&indexing_slicing::INDEXING_SLICING), LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 35cbeae3988..7ce73b6c090 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -490,6 +490,13 @@ pub const ALL_LINTS: [Lint; 331] = [ deprecation: None, module: "excessive_precision", }, + Lint { + name: "exit", + group: "restriction", + desc: "`std::process::exit` is called, terminating the program", + deprecation: None, + module: "exit", + }, Lint { name: "expect_fun_call", group: "perf", -- cgit 1.4.1-3-g733a5 From eae6a62db7582cc0c243a798268a258436c27407 Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" <heinz@licenser.net> Date: Thu, 24 Oct 2019 21:17:21 +0200 Subject: Simplify dentry point detection --- README.md | 2 +- clippy_lints/src/exit.rs | 28 ++++++---------------------- clippy_lints/src/lib.rs | 1 + src/lintlist/mod.rs | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 41b8b4199ec..922dbcd1138 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 331 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 23952efbc8d..7220833b9f2 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -33,31 +33,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Exit { if match_def_path(cx, def_id, &paths::EXIT); then { let mut parent = cx.tcx.hir().get_parent_item(e.hir_id); - // We have to traverse the parents upwards until we find a function - // otherwise a exit in a let or if in main would still trigger this - loop{ - match cx.tcx.hir().find(parent) { - Some(Node::Item(Item{ident, kind: ItemKind::Fn(..), ..})) => { - // If we found a function we check it's name if it is - // `main` we emit a lint. - let def_id = cx.tcx.hir().local_def_id(parent); - if !is_entrypoint_fn(cx, def_id) { - span_lint(cx, EXIT, e.span, "usage of `process::exit`"); - } - // We found any kind of function and can end our loop - break; - } - // If we found anything but a funciton we continue with the - // loop and go one parent up - Some(_) => { - parent = cx.tcx.hir().get_parent_item(parent); - }, - // If we found nothing we break. - None => break, + if let Some(Node::Item(Item{ident, kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent) { + // If the next item up is a function we check if it is an entry point + // and only then emit a linter warning + let def_id = cx.tcx.hir().local_def_id(parent); + if !is_entrypoint_fn(cx, def_id) { + span_lint(cx, EXIT, e.span, "usage of `process::exit`"); } } } - } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d267a3d47e3..84e074fc292 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -502,6 +502,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &eval_order_dependence::DIVERGING_SUB_EXPRESSION, &eval_order_dependence::EVAL_ORDER_DEPENDENCE, &excessive_precision::EXCESSIVE_PRECISION, + &exit::EXIT, &explicit_write::EXPLICIT_WRITE, &fallible_impl_from::FALLIBLE_IMPL_FROM, &format::USELESS_FORMAT, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 7ce73b6c090..cda2a4faba1 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 331] = [ +pub const ALL_LINTS: [Lint; 333] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", -- cgit 1.4.1-3-g733a5 From 2f1370d64cb62c521ec04999f30ed856b644dccc Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" <heinz@licenser.net> Date: Thu, 7 Nov 2019 17:13:26 +0100 Subject: Update lints --- README.md | 2 +- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 922dbcd1138..87ef441eadd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 332 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index cda2a4faba1..5c92d69a499 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 333] = [ +pub const ALL_LINTS: [Lint; 332] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", -- cgit 1.4.1-3-g733a5 From 5817a4fa0606f10797bd79d641b39d47a40d67e6 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Sun, 10 Nov 2019 15:12:05 +0200 Subject: Add `to_digit_is_some` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/to_digit_is_some.rs | 92 ++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/to_digit_is_some.fixed | 11 +++++ tests/ui/to_digit_is_some.rs | 11 +++++ tests/ui/to_digit_is_some.stderr | 16 +++++++ 8 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/to_digit_is_some.rs create mode 100644 tests/ui/to_digit_is_some.fixed create mode 100644 tests/ui/to_digit_is_some.rs create mode 100644 tests/ui/to_digit_is_some.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 84a3bd491cb..30d3108e0be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1203,6 +1203,7 @@ Released 2018-09-13 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines diff --git a/README.md b/README.md index 87ef441eadd..922dbcd1138 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 332 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dae1c429b7d..c108290e478 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -272,6 +272,7 @@ pub mod strings; pub mod suspicious_trait_impl; pub mod swap; pub mod temporary_assignment; +pub mod to_digit_is_some; pub mod trait_bounds; pub mod transmute; pub mod transmuting_null; @@ -713,6 +714,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &swap::ALMOST_SWAPPED, &swap::MANUAL_SWAP, &temporary_assignment::TEMPORARY_ASSIGNMENT, + &to_digit_is_some::TO_DIGIT_IS_SOME, &trait_bounds::TYPE_REPETITION_IN_BOUNDS, &transmute::CROSSPOINTER_TRANSMUTE, &transmute::TRANSMUTE_BYTES_TO_STR, @@ -944,6 +946,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box unused_self::UnusedSelf); store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); store.register_late_pass(|| box exit::Exit); + store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1238,6 +1241,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&swap::ALMOST_SWAPPED), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), @@ -1363,6 +1367,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&strings::STRING_LIT_AS_BYTES), + LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&try_err::TRY_ERR), LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs new file mode 100644 index 00000000000..de7fc0236ba --- /dev/null +++ b/clippy_lints/src/to_digit_is_some.rs @@ -0,0 +1,92 @@ +use crate::utils::{match_def_path, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc::hir; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty; +use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// **What it does:** Checks for `.to_digit().is_some()` on `char`s. + /// + /// **Why is this bad?** This is a convoluted way of checking if a `char` is a digit. It's + /// more straight forward use the dedicated `is_digit` method. + /// + /// **Example:** + /// ```rust + /// # let x: char = 'x' + /// let is_digit = x.to_digit().is_some(); + /// ``` + /// can be written as: + /// ``` + /// # let x: char = 'x' + /// let is_digit = x.is_digit(); + /// ``` + pub TO_DIGIT_IS_SOME, + style, + "`char.is_digit()` is clearer" +} + +declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ToDigitIsSome { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { + if_chain! { + if let hir::ExprKind::MethodCall(is_some_path, _, is_some_args) = &expr.kind; + if is_some_path.ident.name.as_str() == "is_some"; + if let [to_digit_expr] = &**is_some_args; + then { + let match_result = match &to_digit_expr.kind { + hir::ExprKind::MethodCall(to_digits_path, _, to_digit_args) => { + if_chain! { + if let [char_arg, radix_arg] = &**to_digit_args; + if to_digits_path.ident.name.as_str() == "to_digit"; + let char_arg_ty = cx.tables.expr_ty_adjusted(char_arg); + if char_arg_ty.kind == ty::Char; + then { + Some((true, char_arg, radix_arg)) + } else { + None + } + } + } + hir::ExprKind::Call(to_digits_call, to_digit_args) => { + if_chain! { + if let [char_arg, radix_arg] = &**to_digit_args; + if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind; + if let to_digits_call_res = cx.tables.qpath_res(to_digits_path, to_digits_call.hir_id); + if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id(); + if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "<impl char>", "to_digit"]); + then { + Some((false, char_arg, radix_arg)) + } else { + None + } + } + } + _ => None + }; + + if let Some((is_method_call, char_arg, radix_arg)) = match_result { + let mut applicability = Applicability::MachineApplicable; + let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability); + let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability); + + span_lint_and_sugg( + cx, + TO_DIGIT_IS_SOME, + expr.span, + "use of `.to_digit(..).is_some()`", + "try this", + if is_method_call { + format!("{}.is_digit({})", char_arg_snip, radix_snip) + } else { + format!("char::is_digit({}, {})", char_arg_snip, radix_snip) + }, + applicability, + ); + } + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5c92d69a499..0b301b6be96 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 332] = [ +pub const ALL_LINTS: [Lint; 333] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1876,6 +1876,13 @@ pub const ALL_LINTS: [Lint; 332] = [ deprecation: None, module: "methods", }, + Lint { + name: "to_digit_is_some", + group: "style", + desc: "`char.is_digit()` is clearer", + deprecation: None, + module: "to_digit_is_some", + }, Lint { name: "todo", group: "restriction", diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed new file mode 100644 index 00000000000..19184df0bec --- /dev/null +++ b/tests/ui/to_digit_is_some.fixed @@ -0,0 +1,11 @@ +//run-rustfix + +#![warn(clippy::to_digit_is_some)] + +fn main() { + let c = 'x'; + let d = &c; + + let _ = d.is_digit(10); + let _ = char::is_digit(c, 10); +} diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs new file mode 100644 index 00000000000..45a6728ebf5 --- /dev/null +++ b/tests/ui/to_digit_is_some.rs @@ -0,0 +1,11 @@ +//run-rustfix + +#![warn(clippy::to_digit_is_some)] + +fn main() { + let c = 'x'; + let d = &c; + + let _ = d.to_digit(10).is_some(); + let _ = char::to_digit(c, 10).is_some(); +} diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr new file mode 100644 index 00000000000..177d3ccd3e2 --- /dev/null +++ b/tests/ui/to_digit_is_some.stderr @@ -0,0 +1,16 @@ +error: use of `.to_digit(..).is_some()` + --> $DIR/to_digit_is_some.rs:9:13 + | +LL | let _ = d.to_digit(10).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(10)` + | + = note: `-D clippy::to-digit-is-some` implied by `-D warnings` + +error: use of `.to_digit(..).is_some()` + --> $DIR/to_digit_is_some.rs:10:13 + | +LL | let _ = char::to_digit(c, 10).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 10)` + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 227dc44aee7f9dd8ac85fce15943dad5c43422ea Mon Sep 17 00:00:00 2001 From: Mikhail Babenko <misha-babenko@yandex.ru> Date: Wed, 13 Nov 2019 04:27:43 +0300 Subject: display help on empty command line arguments --- src/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index d2f81066dde..9995c3fb1ce 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -268,14 +268,14 @@ pub fn main() { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let wrapper_mode = Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()); + let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); if wrapper_mode { // we still want to be able to invoke it normally though orig_args.remove(1); } - if !wrapper_mode && std::env::args().any(|a| a == "--help" || a == "-h") { + if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { display_help(); exit(0); } -- cgit 1.4.1-3-g733a5 From 7fddac040469a26fa2fb1d1f1f2dea604d739f49 Mon Sep 17 00:00:00 2001 From: Areredify <misha-babenko@yandex.ru> Date: Tue, 12 Nov 2019 22:22:53 +0000 Subject: Add new lint: large stack array added documentation minor style fix change as to ::from add ignore to doc include threshold in lint message/make suggestion more apparent/use Scalar api instead of matching style fix shange snippet_opt to snippet --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/large_stack_arrays.rs | 67 ++++++++++++++++++++++ clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/utils/conf.rs | 2 + src/lintlist/mod.rs | 9 ++- .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/large_stack_arrays.rs | 30 ++++++++++ tests/ui/large_stack_arrays.stderr | 35 +++++++++++ 9 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/large_stack_arrays.rs create mode 100644 tests/ui/large_stack_arrays.rs create mode 100644 tests/ui/large_stack_arrays.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d3108e0be..94858c8fa17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1059,6 +1059,7 @@ Released 2018-09-13 [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups [`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return diff --git a/README.md b/README.md index 922dbcd1138..c5106e074cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs new file mode 100644 index 00000000000..acc90214ff8 --- /dev/null +++ b/clippy_lints/src/large_stack_arrays.rs @@ -0,0 +1,67 @@ +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::mir::interpret::ConstValue; +use rustc::ty; +use rustc::{declare_tool_lint, impl_lint_pass}; + +use if_chain::if_chain; + +use crate::rustc_target::abi::LayoutOf; +use crate::utils::{snippet, span_help_and_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for local arrays that may be too large. + /// + /// **Why is this bad?** Large local arrays may cause stack overflow. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// let a = [0u32; 1_000_000]; + /// ``` + pub LARGE_STACK_ARRAYS, + pedantic, + "allocating large arrays on stack may cause stack overflow" +} + +pub struct LargeStackArrays { + maximum_allowed_size: u64, +} + +impl LargeStackArrays { + #[must_use] + pub fn new(maximum_allowed_size: u64) -> Self { + Self { maximum_allowed_size } + } +} + +impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) { + if_chain! { + if let ExprKind::Repeat(_, _) = expr.kind; + if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind; + if let ConstValue::Scalar(element_count) = cst.val; + if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); + if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); + if self.maximum_allowed_size < element_count * element_size; + then { + span_help_and_lint( + cx, + LARGE_STACK_ARRAYS, + expr.span, + &format!( + "allocating a local array larger than {} bytes", + self.maximum_allowed_size + ), + &format!( + "consider allocating on the heap with vec!{}.into_boxed_slice()", + snippet(cx, expr.span, "[...]") + ), + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 00028ec1965..e417097b3b0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -211,6 +211,7 @@ pub mod int_plus_one; pub mod integer_division; pub mod items_after_statements; pub mod large_enum_variant; +pub mod large_stack_arrays; pub mod len_zero; pub mod let_if_seq; pub mod lifetimes; @@ -537,6 +538,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &integer_division::INTEGER_DIVISION, &items_after_statements::ITEMS_AFTER_STATEMENTS, &large_enum_variant::LARGE_ENUM_VARIANT, + &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, @@ -949,6 +951,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); store.register_late_pass(|| box exit::Exit); store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); + let array_size_threshold = conf.array_size_threshold; + store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1002,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&if_not_else::IF_NOT_ELSE), LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), + LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 734b689ab1a..a3407d1e990 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -151,6 +151,8 @@ define_Conf! { (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>), /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have (too_many_lines_threshold, "too_many_lines_threshold", 100 => u64), + /// Lint: LARGE_STACK_ARRAYS. The maximum allowed size for arrays on the stack + (array_size_threshold, "array_size_threshold", 512_000 => u64), } impl Default for Conf { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0b301b6be96..83bab9c865d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 333] = [ +pub const ALL_LINTS: [Lint; 334] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -903,6 +903,13 @@ pub const ALL_LINTS: [Lint; 333] = [ deprecation: None, module: "large_enum_variant", }, + Lint { + name: "large_stack_arrays", + group: "pedantic", + desc: "allocating large arrays on stack may cause stack overflow", + deprecation: None, + module: "large_stack_arrays", + }, Lint { name: "len_without_is_empty", group: "style", diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index c9446cda77c..cbb4126a866 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/large_stack_arrays.rs b/tests/ui/large_stack_arrays.rs new file mode 100644 index 00000000000..d9161bfcf15 --- /dev/null +++ b/tests/ui/large_stack_arrays.rs @@ -0,0 +1,30 @@ +#![warn(clippy::large_stack_arrays)] +#![allow(clippy::large_enum_variant)] + +#[derive(Clone, Copy)] +struct S { + pub data: [u64; 32], +} + +#[derive(Clone, Copy)] +enum E { + S(S), + T(u32), +} + +fn main() { + let bad = ( + [0u32; 20_000_000], + [S { data: [0; 32] }; 5000], + [Some(""); 20_000_000], + [E::T(0); 5000], + ); + + let good = ( + [0u32; 1000], + [S { data: [0; 32] }; 1000], + [Some(""); 1000], + [E::T(0); 1000], + [(); 20_000_000], + ); +} diff --git a/tests/ui/large_stack_arrays.stderr b/tests/ui/large_stack_arrays.stderr new file mode 100644 index 00000000000..98d8262372d --- /dev/null +++ b/tests/ui/large_stack_arrays.stderr @@ -0,0 +1,35 @@ +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:17:9 + | +LL | [0u32; 20_000_000], + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::large-stack-arrays` implied by `-D warnings` + = help: consider allocating on the heap with vec![0u32; 20_000_000].into_boxed_slice() + +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:18:9 + | +LL | [S { data: [0; 32] }; 5000], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with vec![S { data: [0; 32] }; 5000].into_boxed_slice() + +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:19:9 + | +LL | [Some(""); 20_000_000], + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with vec![Some(""); 20_000_000].into_boxed_slice() + +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:20:9 + | +LL | [E::T(0); 5000], + | ^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with vec![E::T(0); 5000].into_boxed_slice() + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 73806b72a90c205b43a58545462ce154e0c398d8 Mon Sep 17 00:00:00 2001 From: Florian Rohm <florian.rohm@tngtech.com> Date: Fri, 15 Nov 2019 16:20:21 +0100 Subject: register new lint "tabs in doc comments" and update readme --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 +++++ src/lintlist/mod.rs | 9 ++++++++- 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d3108e0be..f5bb9014989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1201,6 +1201,7 @@ Released 2018-09-13 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some diff --git a/README.md b/README.md index 922dbcd1138..c5106e074cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c22693aee3b..28fca44281a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -275,6 +275,7 @@ pub mod slow_vector_initialization; pub mod strings; pub mod suspicious_trait_impl; pub mod swap; +pub mod tabs_in_doc_comments; pub mod temporary_assignment; pub mod to_digit_is_some; pub mod trait_bounds; @@ -717,6 +718,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, &swap::ALMOST_SWAPPED, &swap::MANUAL_SWAP, + &tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, &temporary_assignment::TEMPORARY_ASSIGNMENT, &to_digit_is_some::TO_DIGIT_IS_SOME, &trait_bounds::TYPE_REPETITION_IN_BOUNDS, @@ -947,6 +949,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); let enum_variant_name_threshold = conf.enum_variant_name_threshold; store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); + store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); store.register_late_pass(|| box unused_self::UnusedSelf); store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); store.register_late_pass(|| box exit::Exit); @@ -1244,6 +1247,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), LintId::of(&swap::MANUAL_SWAP), + LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), @@ -1371,6 +1375,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&strings::STRING_LIT_AS_BYTES), + LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&try_err::TRY_ERR), LintId::of(&types::FN_TO_NUMERIC_CAST), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0b301b6be96..c82b239ee21 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 333] = [ +pub const ALL_LINTS: [Lint; 334] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1862,6 +1862,13 @@ pub const ALL_LINTS: [Lint; 333] = [ deprecation: None, module: "formatting", }, + Lint { + name: "tabs_in_doc_comments", + group: "style", + desc: "using tabs in doc comments is not recommended", + deprecation: None, + module: "tabs_in_doc_comments", + }, Lint { name: "temporary_assignment", group: "complexity", -- cgit 1.4.1-3-g733a5 From c21b1985767f0a4cea6f7b504210300f0390f5d8 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Thu, 14 Nov 2019 20:18:24 +0100 Subject: New lint: zst_offset --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/mod.rs | 33 +++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 ++++++++- tests/ui/zero_offset.rs | 12 ++++++++++++ tests/ui/zero_offset.stderr | 9 +++++++++ 7 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 tests/ui/zero_offset.rs create mode 100644 tests/ui/zero_offset.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d3108e0be..39ca3be0446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1273,4 +1273,5 @@ Released 2018-09-13 [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset <!-- end autogenerated links to lint list --> diff --git a/README.md b/README.md index 922dbcd1138..c5106e074cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c22693aee3b..a2dcbb6a95c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -625,6 +625,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &methods::USELESS_ASREF, &methods::WRONG_PUB_SELF_CONVENTION, &methods::WRONG_SELF_CONVENTION, + &methods::ZST_OFFSET, &minmax::MIN_MAX, &misc::CMP_NAN, &misc::CMP_OWNED, @@ -1177,6 +1178,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::UNNECESSARY_FOLD), LintId::of(&methods::USELESS_ASREF), LintId::of(&methods::WRONG_SELF_CONVENTION), + LintId::of(&methods::ZST_OFFSET), LintId::of(&minmax::MIN_MAX), LintId::of(&misc::CMP_NAN), LintId::of(&misc::CMP_OWNED), @@ -1498,6 +1500,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR), LintId::of(&methods::UNINIT_ASSUMED_INIT), + LintId::of(&methods::ZST_OFFSET), LintId::of(&minmax::MIN_MAX), LintId::of(&misc::CMP_NAN), LintId::of(&misc::FLOAT_CMP), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9fcffc77005..f20abeff065 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1065,6 +1065,23 @@ declare_clippy_lint! { "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`" } +declare_clippy_lint! { + /// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to + /// zero-sized types + /// + /// **Why is this bad?** This is a no-op, and likely unintended + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```ignore + /// unsafe { (&() as *const ()).offest(1) }; + /// ``` + pub ZST_OFFSET, + correctness, + "Check for offset calculations on raw pointers to zero-sized types" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -1109,6 +1126,7 @@ declare_lint_pass!(Methods => [ SUSPICIOUS_MAP, UNINIT_ASSUMED_INIT, MANUAL_SATURATING_ARITHMETIC, + ZST_OFFSET, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { @@ -1167,6 +1185,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { | ["unwrap_or", arith @ "checked_mul"] => { manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) }, + ["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => { + check_pointer_offset(cx, expr, arg_lists[0]) + }, _ => {}, } @@ -3063,3 +3084,15 @@ fn contains_return(expr: &hir::Expr) -> bool { visitor.visit_expr(expr); visitor.found } + +fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { + if_chain! { + if args.len() == 2; + if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables.expr_ty(&args[0]).kind; + if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); + if layout.is_zst(); + then { + span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0b301b6be96..8d046aa2b22 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 333] = [ +pub const ALL_LINTS: [Lint; 334] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2338,5 +2338,12 @@ pub const ALL_LINTS: [Lint; 333] = [ deprecation: None, module: "unicode", }, + Lint { + name: "zst_offset", + group: "correctness", + desc: "Check for offset calculations on raw pointers to zero-sized types", + deprecation: None, + module: "methods", + }, ]; // end lint list, do not remove this comment, it’s used in `update_lints` diff --git a/tests/ui/zero_offset.rs b/tests/ui/zero_offset.rs new file mode 100644 index 00000000000..2de904376ad --- /dev/null +++ b/tests/ui/zero_offset.rs @@ -0,0 +1,12 @@ +fn main() { + unsafe { + let x = &() as *const (); + x.offset(0); + x.wrapping_add(0); + x.sub(0); + x.wrapping_sub(0); + + let y = &1 as *const u8; + y.offset(0); + } +} diff --git a/tests/ui/zero_offset.stderr b/tests/ui/zero_offset.stderr new file mode 100644 index 00000000000..cfcd7de2b3d --- /dev/null +++ b/tests/ui/zero_offset.stderr @@ -0,0 +1,9 @@ +error[E0606]: casting `&i32` as `*const u8` is invalid + --> $DIR/zero_offset.rs:9:17 + | +LL | let y = &1 as *const u8; + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0606`. -- cgit 1.4.1-3-g733a5 From bbb8cd4fbbed4b82b7d1b61206bf6c70fd75e665 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov <popzxc@yandex.ru> Date: Thu, 14 Nov 2019 08:06:34 +0300 Subject: Implement if_same_cond_fn lint Run ./util/dev Revert changelog entry Rename lint to same_functions_in_if_condition and add a doc example Add testcases with different arg in fn invocation --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/copies.rs | 78 ++++++++++++++++++++++++- clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 ++- tests/ui/same_functions_in_if_condition.rs | 80 ++++++++++++++++++++++++++ tests/ui/same_functions_in_if_condition.stderr | 75 ++++++++++++++++++++++++ 7 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 tests/ui/same_functions_in_if_condition.rs create mode 100644 tests/ui/same_functions_in_if_condition.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d3108e0be..a10706c3fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1030,6 +1030,7 @@ Released 2018-09-13 [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond +[`ifs_same_cond_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond_fn [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping diff --git a/README.md b/README.md index 922dbcd1138..c5106e074cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f514068fb10..9cbff066f46 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -40,6 +40,53 @@ declare_clippy_lint! { "consecutive `ifs` with the same condition" } +declare_clippy_lint! { + /// **What it does:** Checks for consecutive `if`s with the same function call. + /// + /// **Why is this bad?** This is probably a copy & paste error. + /// Despite the fact that function can have side effects and `if` works as + /// intended, such an approach is implicit and can be considered a "code smell". + /// + /// **Known problems:** Hopefully none. + /// + /// **Example:** + /// ```ignore + /// if foo() == bar { + /// … + /// } else if foo() == bar { + /// … + /// } + /// ``` + /// + /// This probably should be: + /// ```ignore + /// if foo() == bar { + /// … + /// } else if foo() == baz { + /// … + /// } + /// ``` + /// + /// or if the original code was not a typo and called function mutates a state, + /// consider move the mutation out of the `if` condition to avoid similarity to + /// a copy & paste error: + /// + /// ```ignore + /// let first = foo(); + /// if first == bar { + /// … + /// } else { + /// let second = foo(); + /// if second == bar { + /// … + /// } + /// } + /// ``` + pub SAME_FUNCTIONS_IN_IF_CONDITION, + pedantic, + "consecutive `ifs` with the same function call" +} + declare_clippy_lint! { /// **What it does:** Checks for `if/else` with the same body as the *then* part /// and the *else* part. @@ -102,7 +149,7 @@ declare_clippy_lint! { "`match` with identical arm bodies" } -declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]); +declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { @@ -119,6 +166,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { let (conds, blocks) = if_sequence(expr); lint_same_then_else(cx, &blocks); lint_same_cond(cx, &conds); + lint_same_fns_in_if_cond(cx, &conds); lint_match_arms(cx, expr); } } @@ -163,6 +211,34 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) { } } +/// Implementation of `SAME_FUNCTIONS_IN_IF_CONDITION`. +fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) { + let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 { + let mut h = SpanlessHash::new(cx, cx.tables); + h.hash_expr(expr); + h.finish() + }; + + let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { + // Do not spawn warning if `IFS_SAME_COND` already produced it. + if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) { + return false; + } + SpanlessEq::new(cx).eq_expr(lhs, rhs) + }; + + for (i, j) in search_same(conds, hash, eq) { + span_note_and_lint( + cx, + SAME_FUNCTIONS_IN_IF_CONDITION, + j.span, + "this `if` has the same function call as a previous if", + i.span, + "same as this", + ); + } +} + /// Implementation of `MATCH_SAME_ARMS`. fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) { fn same_bindings<'tcx>( diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c22693aee3b..07feb25e735 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -471,6 +471,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &collapsible_if::COLLAPSIBLE_IF, &comparison_chain::COMPARISON_CHAIN, &copies::IFS_SAME_COND, + &copies::SAME_FUNCTIONS_IN_IF_CONDITION, &copies::IF_SAME_THEN_ELSE, &copies::MATCH_SAME_ARMS, ©_iterator::COPY_ITERATOR, @@ -989,6 +990,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), + LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(&copies::MATCH_SAME_ARMS), LintId::of(©_iterator::COPY_ITERATOR), LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0b301b6be96..b033da45ecb 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 333] = [ +pub const ALL_LINTS: [Lint; 334] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -714,6 +714,13 @@ pub const ALL_LINTS: [Lint; 333] = [ deprecation: None, module: "copies", }, + Lint { + name: "ifs_same_cond_fn", + group: "pedantic", + desc: "consecutive `ifs` with the same function call", + deprecation: None, + module: "copies", + }, Lint { name: "implicit_hasher", group: "style", diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs new file mode 100644 index 00000000000..686867cf5c6 --- /dev/null +++ b/tests/ui/same_functions_in_if_condition.rs @@ -0,0 +1,80 @@ +#![warn(clippy::same_functions_in_if_condition)] +#![allow(clippy::ifs_same_cond)] // This warning is different from `ifs_same_cond`. +#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks + +fn function() -> bool { + true +} + +fn fn_arg(_arg: u8) -> bool { + true +} + +struct Struct; + +impl Struct { + fn method(&self) -> bool { + true + } + fn method_arg(&self, _arg: u8) -> bool { + true + } +} + +fn ifs_same_cond_fn() { + let a = 0; + let obj = Struct; + + if function() { + } else if function() { + //~ ERROR ifs same condition + } + + if fn_arg(a) { + } else if fn_arg(a) { + //~ ERROR ifs same condition + } + + if obj.method() { + } else if obj.method() { + //~ ERROR ifs same condition + } + + if obj.method_arg(a) { + } else if obj.method_arg(a) { + //~ ERROR ifs same condition + } + + let mut v = vec![1]; + if v.pop() == None { + //~ ERROR ifs same condition + } else if v.pop() == None { + } + + if v.len() == 42 { + //~ ERROR ifs same condition + } else if v.len() == 42 { + } + + if v.len() == 1 { + // ok, different conditions + } else if v.len() == 2 { + } + + if fn_arg(0) { + // ok, different arguments. + } else if fn_arg(1) { + } + + if obj.method_arg(0) { + // ok, different arguments. + } else if obj.method_arg(1) { + } + + if a == 1 { + // ok, warning is on `ifs_same_cond` behalf. + } else if a == 1 { + } +} + +fn main() {} diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr new file mode 100644 index 00000000000..214f1a9e7c8 --- /dev/null +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -0,0 +1,75 @@ +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:29:15 + | +LL | } else if function() { + | ^^^^^^^^^^ + | + = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` +note: same as this + --> $DIR/same_functions_in_if_condition.rs:28:8 + | +LL | if function() { + | ^^^^^^^^^^ + +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:34:15 + | +LL | } else if fn_arg(a) { + | ^^^^^^^^^ + | +note: same as this + --> $DIR/same_functions_in_if_condition.rs:33:8 + | +LL | if fn_arg(a) { + | ^^^^^^^^^ + +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:39:15 + | +LL | } else if obj.method() { + | ^^^^^^^^^^^^ + | +note: same as this + --> $DIR/same_functions_in_if_condition.rs:38:8 + | +LL | if obj.method() { + | ^^^^^^^^^^^^ + +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:44:15 + | +LL | } else if obj.method_arg(a) { + | ^^^^^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/same_functions_in_if_condition.rs:43:8 + | +LL | if obj.method_arg(a) { + | ^^^^^^^^^^^^^^^^^ + +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:51:15 + | +LL | } else if v.pop() == None { + | ^^^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/same_functions_in_if_condition.rs:49:8 + | +LL | if v.pop() == None { + | ^^^^^^^^^^^^^^^ + +error: this `if` has the same function call as a previous if + --> $DIR/same_functions_in_if_condition.rs:56:15 + | +LL | } else if v.len() == 42 { + | ^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/same_functions_in_if_condition.rs:54:8 + | +LL | if v.len() == 42 { + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + -- cgit 1.4.1-3-g733a5 From e3a74ed2b5185fbcf55ef815f3b7367d19289a5f Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Fri, 22 Nov 2019 14:24:38 +0100 Subject: Set mir_opt_level=0 This introduces some FNs. But a building Clippy is more important for now --- src/driver.rs | 2 ++ tests/ui/indexing_slicing.stderr | 22 +------------- tests/ui/missing_const_for_fn/cant_be_const.rs | 3 ++ tests/ui/redundant_clone.fixed | 9 ++++-- tests/ui/redundant_clone.rs | 5 +++ tests/ui/redundant_clone.stderr | 42 ++++++-------------------- 6 files changed, 27 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 9995c3fb1ce..bd19127b3ce 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -75,6 +75,8 @@ impl rustc_driver::Callbacks for ClippyCallbacks { clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf); clippy_lints::register_renamed(&mut lint_store); })); + + config.opts.debugging_opts.mir_opt_level = 0; } } diff --git a/tests/ui/indexing_slicing.stderr b/tests/ui/indexing_slicing.stderr index b2840f7b5cc..0744676d139 100644 --- a/tests/ui/indexing_slicing.stderr +++ b/tests/ui/indexing_slicing.stderr @@ -1,23 +1,3 @@ -error: index out of bounds: the len is 4 but the index is 4 - --> $DIR/indexing_slicing.rs:18:5 - | -LL | x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^ - | - = note: `#[deny(const_err)]` on by default - -error: index out of bounds: the len is 4 but the index is 8 - --> $DIR/indexing_slicing.rs:19:5 - | -LL | x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^^^^^^ - -error: index out of bounds: the len is 4 but the index is 15 - --> $DIR/indexing_slicing.rs:54:5 - | -LL | x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays. - | ^^^^ - error: indexing may panic. --> $DIR/indexing_slicing.rs:13:5 | @@ -209,5 +189,5 @@ LL | v[M]; | = help: Consider using `.get(n)` or `.get_mut(n)` instead -error: aborting due to 27 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 43258be7a97..f367279906f 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -32,8 +32,11 @@ fn random_caller() -> u32 { static Y: u32 = 0; +// We should not suggest to make this function `const` because const functions are not allowed to +// refer to a static variable fn get_y() -> u32 { Y + //~^ ERROR E0013 } // Don't lint entrypoint functions diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index c2c2b2e2dec..e5e706e8483 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -18,11 +18,11 @@ fn main() { let _s = Path::new("/a/b/").join("c"); - let _s = Path::new("/a/b/").join("c"); + let _s = Path::new("/a/b/").join("c").to_path_buf(); let _s = OsString::new(); - let _s = OsString::new(); + let _s = OsString::new().to_os_string(); // Check that lint level works #[allow(clippy::redundant_clone)] @@ -47,6 +47,7 @@ fn main() { let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x` with_branch(Alpha, true); + cannot_double_move(Alpha); cannot_move_from_type_with_drop(); borrower_propagation(); } @@ -61,6 +62,10 @@ fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) { } } +fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) { + (a.clone(), a) +} + struct TypeWithDrop { x: String, } diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 07bd8465841..9ea2de9a3da 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -47,6 +47,7 @@ fn main() { let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x` with_branch(Alpha, true); + cannot_double_move(Alpha); cannot_move_from_type_with_drop(); borrower_propagation(); } @@ -61,6 +62,10 @@ fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) { } } +fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) { + (a.clone(), a) +} + struct TypeWithDrop { x: String, } diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index f52d50dbf6b..62f4ce7645e 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -59,18 +59,6 @@ note: this value is dropped without further use LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: redundant clone - --> $DIR/redundant_clone.rs:21:42 - | -LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); - | ^^^^^^^^^^^^^^ help: remove this - | -note: this value is dropped without further use - --> $DIR/redundant_clone.rs:21:14 - | -LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: redundant clone --> $DIR/redundant_clone.rs:23:29 | @@ -83,18 +71,6 @@ note: this value is dropped without further use LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ -error: redundant clone - --> $DIR/redundant_clone.rs:25:29 - | -LL | let _s = OsString::new().to_os_string(); - | ^^^^^^^^^^^^^^^ help: remove this - | -note: this value is dropped without further use - --> $DIR/redundant_clone.rs:25:14 - | -LL | let _s = OsString::new().to_os_string(); - | ^^^^^^^^^^^^^^^ - error: redundant clone --> $DIR/redundant_clone.rs:32:19 | @@ -108,52 +84,52 @@ LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:58:22 + --> $DIR/redundant_clone.rs:59:22 | LL | (a.clone(), a.clone()) | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:58:21 + --> $DIR/redundant_clone.rs:59:21 | LL | (a.clone(), a.clone()) | ^ error: redundant clone - --> $DIR/redundant_clone.rs:114:15 + --> $DIR/redundant_clone.rs:119:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:114:14 + --> $DIR/redundant_clone.rs:119:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:115:15 + --> $DIR/redundant_clone.rs:120:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:115:14 + --> $DIR/redundant_clone.rs:120:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:125:19 + --> $DIR/redundant_clone.rs:130:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:125:18 + --> $DIR/redundant_clone.rs:130:18 | LL | let _f = f.clone(); | ^ -error: aborting due to 13 previous errors +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 7bae5bd828e98af9d245b77118c075a7f1a036b9 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Sat, 23 Nov 2019 01:26:19 +0100 Subject: Add comment for mir_opt_level=0 --- src/driver.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index bd19127b3ce..2a4448cc0ec 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -76,6 +76,10 @@ impl rustc_driver::Callbacks for ClippyCallbacks { clippy_lints::register_renamed(&mut lint_store); })); + // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be + // run on the unoptimized MIR. On the other hand this results in some false negatives. If + // MIR passes can be enabled / disabled separately, we should figure out, what passes to + // use for Clippy. config.opts.debugging_opts.mir_opt_level = 0; } } -- cgit 1.4.1-3-g733a5 From 9b4faf97f37f03ec1fd3e01f13945b05e413464c Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Sat, 23 Nov 2019 17:57:28 +0100 Subject: Run update_lints --- CHANGELOG.md | 2 +- README.md | 2 +- clippy_lints/src/lib.rs | 4 ++-- src/lintlist/mod.rs | 16 ++++++++-------- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 72773df604c..f21174c0bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1030,7 +1030,6 @@ Released 2018-09-13 [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond -[`ifs_same_cond_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond_fn [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping @@ -1178,6 +1177,7 @@ Released 2018-09-13 [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used [`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff --git a/README.md b/README.md index c5106e074cb..d467e05257b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 337 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index de55f3d2bb8..c8954aef2ba 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -472,9 +472,9 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &collapsible_if::COLLAPSIBLE_IF, &comparison_chain::COMPARISON_CHAIN, &copies::IFS_SAME_COND, - &copies::SAME_FUNCTIONS_IN_IF_CONDITION, &copies::IF_SAME_THEN_ELSE, &copies::MATCH_SAME_ARMS, + &copies::SAME_FUNCTIONS_IN_IF_CONDITION, ©_iterator::COPY_ITERATOR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, @@ -997,8 +997,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), - LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(&copies::MATCH_SAME_ARMS), + LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(©_iterator::COPY_ITERATOR), LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2958e77fd5e..9b258ffb610 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 334] = [ +pub const ALL_LINTS: [Lint; 337] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -714,13 +714,6 @@ pub const ALL_LINTS: [Lint; 334] = [ deprecation: None, module: "copies", }, - Lint { - name: "ifs_same_cond_fn", - group: "pedantic", - desc: "consecutive `ifs` with the same function call", - deprecation: None, - module: "copies", - }, Lint { name: "implicit_hasher", group: "style", @@ -1722,6 +1715,13 @@ pub const ALL_LINTS: [Lint; 334] = [ deprecation: None, module: "loops", }, + Lint { + name: "same_functions_in_if_condition", + group: "pedantic", + desc: "consecutive `ifs` with the same function call", + deprecation: None, + module: "copies", + }, Lint { name: "search_is_some", group: "complexity", -- cgit 1.4.1-3-g733a5 From 9ec8888b91322284859ef7414760bb837bcad393 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko <misha-babenko@yandex.ru> Date: Fri, 15 Nov 2019 22:27:07 +0300 Subject: implemented `as_conversions` lint actuall add files add better example and change pedantic to restriction --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/as_conversions.rs | 56 ++++++++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 +++ src/lintlist/mod.rs | 9 +++++- tests/ui/as_conversions.rs | 7 +++++ tests/ui/as_conversions.stderr | 27 ++++++++++++++++++ tests/ui/types.fixed | 2 +- tests/ui/types.rs | 2 +- 9 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/as_conversions.rs create mode 100644 tests/ui/as_conversions.rs create mode 100644 tests/ui/as_conversions.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f21174c0bce..4e747524e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -929,6 +929,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops diff --git a/README.md b/README.md index d467e05257b..e8818412e90 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 337 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 338 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs new file mode 100644 index 00000000000..ee6357359d1 --- /dev/null +++ b/clippy_lints/src/as_conversions.rs @@ -0,0 +1,56 @@ +use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; +use syntax::ast::*; + +use crate::utils::span_help_and_lint; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `as` conversions. + /// + /// **Why is this bad?** `as` conversions will perform many kinds of + /// conversions, including silently lossy conversions and dangerous coercions. + /// There are cases when it makes sense to use `as`, so the lint is + /// Allow by default. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// let a: u32; + /// ... + /// f(a as u16); + /// ``` + /// + /// Usually better represents the semantics you expect: + /// ```rust,ignore + /// f(a.try_into()?); + /// ``` + /// or + /// ```rust,ignore + /// f(a.try_into().expect("Unexpected u16 overflow in f")); + /// ``` + /// + pub AS_CONVERSIONS, + restriction, + "using a potentially dangerous silent `as` conversion" +} + +declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); + +impl EarlyLintPass for AsConversions { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if let ExprKind::Cast(_, _) = expr.kind { + span_help_and_lint( + cx, + AS_CONVERSIONS, + expr.span, + "using a potentially dangerous silent `as` conversion", + "consider using a safe wrapper for this conversion", + ); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8954aef2ba..32518405855 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -155,6 +155,7 @@ mod utils; // begin lints modules, do not remove this comment, it’s used in `update_lints` pub mod approx_const; pub mod arithmetic; +pub mod as_conversions; pub mod assertions_on_constants; pub mod assign_ops; pub mod attrs; @@ -448,6 +449,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &approx_const::APPROX_CONSTANT, &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, + &as_conversions::AS_CONVERSIONS, &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, @@ -959,10 +961,12 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_early_pass(|| box as_conversions::AsConversions); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), + LintId::of(&as_conversions::AS_CONVERSIONS), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9b258ffb610..6b7a93f5819 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 337] = [ +pub const ALL_LINTS: [Lint; 338] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -28,6 +28,13 @@ pub const ALL_LINTS: [Lint; 337] = [ deprecation: None, module: "approx_const", }, + Lint { + name: "as_conversions", + group: "restriction", + desc: "using a potentially dangerous silent `as` conversion", + deprecation: None, + module: "as_conversions", + }, Lint { name: "assertions_on_constants", group: "style", diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs new file mode 100644 index 00000000000..e01ba0c64df --- /dev/null +++ b/tests/ui/as_conversions.rs @@ -0,0 +1,7 @@ +#[warn(clippy::as_conversions)] + +fn main() { + let i = 0u32 as u64; + + let j = &i as *const u64 as *mut u64; +} diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr new file mode 100644 index 00000000000..312d3a7460e --- /dev/null +++ b/tests/ui/as_conversions.stderr @@ -0,0 +1,27 @@ +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:4:13 + | +LL | let i = 0u32 as u64; + | ^^^^^^^^^^^ + | + = note: `-D clippy::as-conversions` implied by `-D warnings` + = help: consider using a safe wrapper for this conversion + +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:6:13 + | +LL | let j = &i as *const u64 as *mut u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using a safe wrapper for this conversion + +error: using a potentially dangerous silent `as` conversion + --> $DIR/as_conversions.rs:6:13 + | +LL | let j = &i as *const u64 as *mut u64; + | ^^^^^^^^^^^^^^^^ + | + = help: consider using a safe wrapper for this conversion + +error: aborting due to 3 previous errors + diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed index b1622e45f3b..417da42edf1 100644 --- a/tests/ui/types.fixed +++ b/tests/ui/types.fixed @@ -1,7 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] -#![warn(clippy::all, clippy::pedantic)] +#![warn(clippy::cast_lossless)] // should not warn on lossy casting in constant types // because not supported yet diff --git a/tests/ui/types.rs b/tests/ui/types.rs index 30463f9e2a1..b16e9e538b1 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,7 +1,7 @@ // run-rustfix #![allow(dead_code, unused_variables)] -#![warn(clippy::all, clippy::pedantic)] +#![warn(clippy::cast_lossless)] // should not warn on lossy casting in constant types // because not supported yet -- cgit 1.4.1-3-g733a5 From d0e0ffa99f45ef07855c41ec0be30ca5496d8ba3 Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Tue, 26 Nov 2019 14:14:28 +0000 Subject: make use of Result::map_or --- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/lib.rs | 1 + clippy_lints/src/methods/mod.rs | 12 +++++------- src/driver.rs | 3 ++- src/lintlist/mod.rs | 2 +- tests/ui/result_map_unwrap_or_else.stderr | 12 ++++++------ 6 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index bb6e0e5c51c..58fe4d99c78 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -152,7 +152,7 @@ impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { fn is_large_box(&self, ty: Ty<'tcx>) -> bool { // Large types need to be boxed to avoid stack overflows. if ty.is_box() { - self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack + self.cx.layout_of(ty.boxed_ty()).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack } else { false } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c8954aef2ba..96e9c850cdb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -12,6 +12,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(crate_visibility_modifier)] #![feature(concat_idents)] +#![feature(result_map_or)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5448eecb90e..d2067cace94 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -291,7 +291,7 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `result.ok().map_or_else(_, _)`. + /// `result.map_or_else(_, _)`. /// /// **Known problems:** None. /// @@ -303,7 +303,7 @@ declare_clippy_lint! { /// ``` pub RESULT_MAP_UNWRAP_OR_ELSE, pedantic, - "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`" + "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.map_or_else(g, f)`" } declare_clippy_lint! { @@ -2217,7 +2217,7 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( `map_or_else(g, f)` instead" } else { "called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \ - `ok().map_or_else(g, f)` instead" + `.map_or_else(g, f)` instead" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); @@ -2238,10 +2238,8 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( msg, expr.span, &format!( - "replace `map({0}).unwrap_or_else({1})` with `{2}map_or_else({1}, {0})`", - map_snippet, - unwrap_snippet, - if is_result { "ok()." } else { "" } + "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", + map_snippet, unwrap_snippet, ), ); } else if same_span && multiline { diff --git a/src/driver.rs b/src/driver.rs index 2a4448cc0ec..2579fb4ad4d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] +#![feature(result_map_or)] #![feature(rustc_private)] // FIXME: switch to something more ergonomic here, once available. @@ -319,7 +320,7 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") + let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true") || arg_value(&orig_args, "--emit", |val| val.split(',').any(|e| e == "metadata")).is_some(); if clippy_enabled { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9b258ffb610..715d505abf3 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1697,7 +1697,7 @@ pub const ALL_LINTS: [Lint; 337] = [ Lint { name: "result_map_unwrap_or_else", group: "pedantic", - desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`", + desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.map_or_else(g, f)`", deprecation: None, module: "methods", }, diff --git a/tests/ui/result_map_unwrap_or_else.stderr b/tests/ui/result_map_unwrap_or_else.stderr index 7674b91c128..2b014e9ebb1 100644 --- a/tests/ui/result_map_unwrap_or_else.stderr +++ b/tests/ui/result_map_unwrap_or_else.stderr @@ -1,27 +1,27 @@ -error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead +error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `.map_or_else(g, f)` instead --> $DIR/result_map_unwrap_or_else.rs:15:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::result-map-unwrap-or-else` implied by `-D warnings` - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` -error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead +error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `.map_or_else(g, f)` instead --> $DIR/result_map_unwrap_or_else.rs:17:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` -error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead +error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `.map_or_else(g, f)` instead --> $DIR/result_map_unwrap_or_else.rs:18:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)` + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From a61fd43a79e43af1f7d0d282f9ef5dfdc6dcdda0 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Sat, 23 Nov 2019 02:08:36 +0100 Subject: Don't error on clippy.toml of dependencies --- src/driver.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 2579fb4ad4d..0b14e1d5a5a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -318,10 +318,9 @@ pub fn main() { }; // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built + // crate is linted but not built let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true") - || arg_value(&orig_args, "--emit", |val| val.split(',').any(|e| e == "metadata")).is_some(); + || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none(); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); -- cgit 1.4.1-3-g733a5 From 70a2a294530464dd142c5e9a0a7142dc23969cad Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Fri, 29 Nov 2019 07:51:49 +0100 Subject: Move use_self to nursery Closes #4859 We have a lot of false positives in this lint, so I think it makes sense to move this to the nursery until they are resolved. changelog: Move `use_self` lint to nursery, due to many false positives --- clippy_lints/src/use_self.rs | 2 +- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 5a048e1ce43..23d0ab09020 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// } /// ``` pub USE_SELF, - pedantic, + nursery, "Unnecessary structure name repetition whereas `Self` is applicable" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e5d8f2d0c1a..5b08571c258 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2193,7 +2193,7 @@ pub const ALL_LINTS: [Lint; 338] = [ }, Lint { name: "use_self", - group: "pedantic", + group: "nursery", desc: "Unnecessary structure name repetition whereas `Self` is applicable", deprecation: None, module: "use_self", -- cgit 1.4.1-3-g733a5 From 676f14baa0eb0291e946e6c134f832277c5236b8 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Fri, 27 Sep 2019 07:09:12 +0200 Subject: Add custom ICE message that points to Clippy repo This utilizes https://github.com/rust-lang/rust/pull/60584 by setting our own `panic_hook` and pointing to our own issue tracker instead of the rustc issue tracker. This also adds a new internal lint to test the ICE message. **Potential downsides** * This essentially copies rustc's `report_ice` function as `report_clippy_ice`. I think that's how it's meant to be implemented, but maybe @jonas-schievink could have a look as well =) The downside of more-or-less copying this function is that we have to maintain it as well now. The original function can be found [here][original]. * `driver` now depends directly on `rustc` and `rustc_errors` Closes #2734 [original]: https://github.com/rust-lang/rust/blob/59367b074f1523353dddefa678ffe3cac9fd4e50/src/librustc_driver/lib.rs#L1185 --- Cargo.toml | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/utils/internal_lints.rs | 39 ++++++++++++++++++++ src/driver.rs | 63 +++++++++++++++++++++++++++++++- tests/ui/custom_ice_message.rs | 5 +++ tests/ui/custom_ice_message.stderr | 11 ++++++ 6 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/ui/custom_ice_message.rs create mode 100644 tests/ui/custom_ice_message.stderr (limited to 'src') diff --git a/Cargo.toml b/Cargo.toml index dabc4a62e6d..6b757ac0a2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ semver = "0.9" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} git2 = { version = "0.10", optional = true } tempfile = { version = "3.1.0", optional = true } +lazy_static = "1.0" [dev-dependencies] cargo_metadata = "0.9.0" diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 07fe9f47465..c1113daadd8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -963,6 +963,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); store.register_early_pass(|| box as_conversions::AsConversions); + store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1057,6 +1058,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&utils::internal_lints::COMPILER_LINT_FUNCTIONS), LintId::of(&utils::internal_lints::LINT_WITHOUT_LINT_PASS), LintId::of(&utils::internal_lints::OUTER_EXPN_EXPN_DATA), + LintId::of(&utils::internal_lints::PRODUCE_ICE), ]); store.register_group(true, "clippy::all", Some("clippy"), vec![ diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 5bf10558221..cb75720f120 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -11,9 +11,11 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintAr use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; +use syntax::ast; use syntax::ast::{Crate as AstCrate, ItemKind, Name}; use syntax::source_map::Span; use syntax_pos::symbol::SymbolStr; +use syntax::visit::FnKind; declare_clippy_lint! { /// **What it does:** Checks for various things we like to keep tidy in clippy. @@ -99,6 +101,24 @@ declare_clippy_lint! { "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`" } +declare_clippy_lint! { + /// **What it does:** Not an actual lint. This lint is only meant for testing our customized internal compiler + /// error message by calling `panic`. + /// + /// **Why is this bad?** ICE in large quantities can damage your teeth + /// + /// **Known problems:** None + /// + /// **Example:** + /// Bad: + /// ```rust,ignore + /// 🍦🍦🍦🍦🍦 + /// ``` + pub PRODUCE_ICE, + internal, + "this message should not appear anywhere as we ICE before and don't emit the lint" +} + declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { @@ -302,3 +322,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OuterExpnDataPass { } } } + +declare_lint_pass!(ProduceIce => [PRODUCE_ICE]); + +impl EarlyLintPass for ProduceIce { + fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &ast::FnDecl, _: Span, _: ast::NodeId) { + if is_trigger_fn(fn_kind) { + panic!("Testing the ICE message"); + } + } +} + +fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool { + match fn_kind { + FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => { + ident.name.as_str() == "should_trigger_an_ice_in_clippy" + }, + FnKind::Closure(..) => false, + } +} diff --git a/src/driver.rs b/src/driver.rs index 0b14e1d5a5a..76aaae3747b 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -5,13 +5,21 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] +extern crate rustc; +#[allow(unused_extern_crates)] extern crate rustc_driver; #[allow(unused_extern_crates)] +extern crate rustc_errors; +#[allow(unused_extern_crates)] extern crate rustc_interface; +use rustc::ty::TyCtxt; use rustc_interface::interface; use rustc_tools_util::*; +use lazy_static::lazy_static; +use std::borrow::Cow; +use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; @@ -221,9 +229,62 @@ You can use tool lints to allow or deny lints from your code, eg.: ); } +const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; + +lazy_static! { + static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); + hook + }; +} + +fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { + // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace + (*ICE_HOOK)(info); + + // Separate the output with an empty line + eprintln!(); + + let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( + rustc_errors::ColorConfig::Auto, + None, + false, + false, + None, + false, + )); + let handler = rustc_errors::Handler::with_emitter(true, None, emitter); + + // a .span_bug or .bug call has already printed what + // it wants to print. + if !info.payload().is::<rustc_errors::ExplicitBug>() { + let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic"); + handler.emit_diagnostic(&d); + handler.abort_if_errors_and_should_abort(); + } + + let xs: Vec<Cow<'static, str>> = vec![ + "the compiler unexpectedly panicked. this is a bug.".into(), + format!("we would appreciate a bug report: {}", bug_report_url).into(), + format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown_version")).into(), + ]; + + for note in &xs { + handler.note_without_error(¬e); + } + + // If backtraces are enabled, also print the query stack + let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + + if backtrace { + TyCtxt::try_print_query_stack(); + } +} + pub fn main() { rustc_driver::init_rustc_env_logger(); - rustc_driver::install_ice_hook(); + lazy_static::initialize(&ICE_HOOK); exit( rustc_driver::catch_fatal_errors(move || { use std::env; diff --git a/tests/ui/custom_ice_message.rs b/tests/ui/custom_ice_message.rs new file mode 100644 index 00000000000..8ad5ebba7f3 --- /dev/null +++ b/tests/ui/custom_ice_message.rs @@ -0,0 +1,5 @@ +#![deny(clippy::internal)] + +fn should_trigger_an_ice_in_clippy() {} + +fn main() {} diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui/custom_ice_message.stderr new file mode 100644 index 00000000000..85c9f42a2de --- /dev/null +++ b/tests/ui/custom_ice_message.stderr @@ -0,0 +1,11 @@ +thread 'rustc' panicked at 'Testing the ICE message', clippy_lints/src/utils/internal_lints.rs:333:13 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + +error: internal compiler error: unexpected panic + +note: the compiler unexpectedly panicked. this is a bug. + +note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new + +note: rustc unknown_version + -- cgit 1.4.1-3-g733a5 From fc57c84abeee862fea08d823077f56ebab809ea7 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Fri, 27 Sep 2019 07:25:16 +0200 Subject: Use Clippy version in ICE message --- src/driver.rs | 4 +++- tests/ui/custom_ice_message.stderr | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 76aaae3747b..50c821c182d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -264,10 +264,12 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { handler.abort_if_errors_and_should_abort(); } + let version_info = rustc_tools_util::get_version_info!(); + let xs: Vec<Cow<'static, str>> = vec![ "the compiler unexpectedly panicked. this is a bug.".into(), format!("we would appreciate a bug report: {}", bug_report_url).into(), - format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown_version")).into(), + format!("Clippy version: {}", version_info).into(), ]; for note in &xs { diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui/custom_ice_message.stderr index 85c9f42a2de..cacc41bb5df 100644 --- a/tests/ui/custom_ice_message.stderr +++ b/tests/ui/custom_ice_message.stderr @@ -7,5 +7,5 @@ note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new -note: rustc unknown_version +note: Clippy version: clippy 0.0.212 (68ff8b19 2019-09-26) -- cgit 1.4.1-3-g733a5 From 36c6a18217f27491c57b1b078c24f881cde92c57 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Tue, 8 Oct 2019 21:23:57 +0200 Subject: Update custom ICE function with latest rustc --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 50c821c182d..ffa9b663ec4 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -280,7 +280,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); if backtrace { - TyCtxt::try_print_query_stack(); + TyCtxt::try_print_query_stack(&handler); } } -- cgit 1.4.1-3-g733a5 From 44eec0884d198020e72f2f28b522bcfa16a1830a Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Wed, 9 Oct 2019 20:51:45 +0200 Subject: Feed the dog --- src/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index ffa9b663ec4..fda304afcbe 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -277,7 +277,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } // If backtraces are enabled, also print the query stack - let backtrace = std::env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); if backtrace { TyCtxt::try_print_query_stack(&handler); -- cgit 1.4.1-3-g733a5 From f5d0a452ba0b50b796cbbcc49cc6e25f2b29a256 Mon Sep 17 00:00:00 2001 From: RobbieClarken <robbie.clarken@gmail.com> Date: Fri, 6 Dec 2019 10:30:23 +1030 Subject: Add lint for pub fns returning a `Result` without documenting errors The Rust Book recommends that functions that return a `Result` type have a doc comment with an `# Errors` section describing the kind of errors that can be returned (https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commonly-used-sections). This change adds a lint to enforce this. The lint is allow by default; it can be enabled with `#![warn(clippy::missing_errors_doc)]`. Closes #4854. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/doc.rs | 137 ++++++++++++++++++++++++++++++--------------- clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 ++- tests/ui/doc_errors.rs | 64 +++++++++++++++++++++ tests/ui/doc_errors.stderr | 34 +++++++++++ 7 files changed, 202 insertions(+), 47 deletions(-) create mode 100644 tests/ui/doc_errors.rs create mode 100644 tests/ui/doc_errors.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e747524e9e..a9448a57f7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1092,6 +1092,7 @@ Released 2018-09-13 [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc [`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes diff --git a/README.md b/README.md index e8818412e90..97a7c97b49a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 338 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 339 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 0fcc9763d37..8f8d8ad96bb 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,4 +1,4 @@ -use crate::utils::span_lint; +use crate::utils::{match_type, paths, return_ty, span_lint}; use itertools::Itertools; use pulldown_cmark; use rustc::hir; @@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_session::declare_tool_lint; use std::ops::Range; use syntax::ast::{AttrKind, Attribute}; -use syntax::source_map::{BytePos, Span}; +use syntax::source_map::{BytePos, MultiSpan, Span}; use syntax_pos::Pos; use url::Url; @@ -45,7 +45,7 @@ declare_clippy_lint! { /// /// **Known problems:** None. /// - /// **Examples**: + /// **Examples:** /// ```rust ///# type Universe = (); /// /// This function should really be documented @@ -70,6 +70,35 @@ declare_clippy_lint! { "`pub unsafe fn` without `# Safety` docs" } +declare_clippy_lint! { + /// **What it does:** Checks the doc comments of publicly visible functions that + /// return a `Result` type and warns if there is no `# Errors` section. + /// + /// **Why is this bad?** Documenting the type of errors that can be returned from a + /// function can help callers write code to handle the errors appropriately. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// + /// Since the following function returns a `Result` it has an `# Errors` section in + /// its doc comment: + /// + /// ```rust + ///# use std::io; + /// /// # Errors + /// /// + /// /// Will return `Err` if `filename` does not exist or the user does not have + /// /// permission to read it. + /// pub fn read(filename: String) -> io::Result<String> { + /// unimplemented!(); + /// } + /// ``` + pub MISSING_ERRORS_DOC, + pedantic, + "`pub fn` returns `Result` without `# Errors` in doc comment" +} + declare_clippy_lint! { /// **What it does:** Checks for `fn main() { .. }` in doctests /// @@ -114,7 +143,7 @@ impl DocMarkdown { } } -impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, NEEDLESS_DOCTEST_MAIN]); +impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, NEEDLESS_DOCTEST_MAIN]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown { fn check_crate(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx hir::Crate) { @@ -122,20 +151,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown { } fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { - if check_attrs(cx, &self.valid_idents, &item.attrs) { - return; - } - // no safety header + let headers = check_attrs(cx, &self.valid_idents, &item.attrs); match item.kind { hir::ItemKind::Fn(ref sig, ..) => { - if cx.access_levels.is_exported(item.hir_id) && sig.header.unsafety == hir::Unsafety::Unsafe { - span_lint( - cx, - MISSING_SAFETY_DOC, - item.span, - "unsafe function's docs miss `# Safety` section", - ); - } + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers); }, hir::ItemKind::Impl(_, _, _, _, ref trait_ref, ..) => { self.in_trait_impl = trait_ref.is_some(); @@ -151,40 +170,51 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown { } fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { - if check_attrs(cx, &self.valid_idents, &item.attrs) { - return; - } - // no safety header + let headers = check_attrs(cx, &self.valid_idents, &item.attrs); if let hir::TraitItemKind::Method(ref sig, ..) = item.kind { - if cx.access_levels.is_exported(item.hir_id) && sig.header.unsafety == hir::Unsafety::Unsafe { - span_lint( - cx, - MISSING_SAFETY_DOC, - item.span, - "unsafe function's docs miss `# Safety` section", - ); - } + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers); } } fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) { - if check_attrs(cx, &self.valid_idents, &item.attrs) || self.in_trait_impl { + let headers = check_attrs(cx, &self.valid_idents, &item.attrs); + if self.in_trait_impl { return; } - // no safety header if let hir::ImplItemKind::Method(ref sig, ..) = item.kind { - if cx.access_levels.is_exported(item.hir_id) && sig.header.unsafety == hir::Unsafety::Unsafe { - span_lint( - cx, - MISSING_SAFETY_DOC, - item.span, - "unsafe function's docs miss `# Safety` section", - ); - } + lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers); } } } +fn lint_for_missing_headers<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + hir_id: hir::HirId, + span: impl Into<MultiSpan> + Copy, + sig: &hir::FnSig, + headers: DocHeaders, +) { + if !cx.access_levels.is_exported(hir_id) { + return; // Private functions do not require doc comments + } + if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe { + span_lint( + cx, + MISSING_SAFETY_DOC, + span, + "unsafe function's docs miss `# Safety` section", + ); + } + if !headers.errors && match_type(cx, return_ty(cx, hir_id), &paths::RESULT) { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); + } +} + /// Cleanup documentation decoration (`///` and such). /// /// We can't use `syntax::attr::AttributeMethods::with_desugared_doc` or @@ -243,7 +273,13 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<( panic!("not a doc-comment: {}", comment); } -pub fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> bool { +#[derive(Copy, Clone)] +struct DocHeaders { + safety: bool, + errors: bool, +} + +fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders { let mut doc = String::new(); let mut spans = vec![]; @@ -255,7 +291,11 @@ pub fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String doc.push_str(&comment); } else if attr.check_name(sym!(doc)) { // ignore mix of sugared and non-sugared doc - return true; // don't trigger the safety check + // don't trigger the safety or errors check + return DocHeaders { + safety: true, + errors: true, + }; } } @@ -267,7 +307,10 @@ pub fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String } if doc.is_empty() { - return false; + return DocHeaders { + safety: false, + errors: false, + }; } let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); @@ -295,12 +338,15 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize valid_idents: &FxHashSet<String>, events: Events, spans: &[(usize, Span)], -) -> bool { +) -> DocHeaders { // true if a safety header was found use pulldown_cmark::Event::*; use pulldown_cmark::Tag::*; - let mut safety_header = false; + let mut headers = DocHeaders { + safety: false, + errors: false, + }; let mut in_code = false; let mut in_link = None; let mut in_heading = false; @@ -323,7 +369,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize // text "http://example.com" by pulldown-cmark continue; } - safety_header |= in_heading && text.trim() == "Safety"; + headers.safety |= in_heading && text.trim() == "Safety"; + headers.errors |= in_heading && text.trim() == "Errors"; let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) { Ok(o) => o, Err(e) => e - 1, @@ -340,7 +387,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize }, } } - safety_header + headers } fn check_code(cx: &LateContext<'_, '_>, text: &str, span: Span) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 432a38a11a5..d14f946c8eb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -488,6 +488,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &derive::DERIVE_HASH_XOR_EQ, &derive::EXPL_IMPL_CLONE_ON_COPY, &doc::DOC_MARKDOWN, + &doc::MISSING_ERRORS_DOC, &doc::MISSING_SAFETY_DOC, &doc::NEEDLESS_DOCTEST_MAIN, &double_comparison::DOUBLE_COMPARISONS, @@ -1013,6 +1014,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), LintId::of(&doc::DOC_MARKDOWN), + LintId::of(&doc::MISSING_ERRORS_DOC), LintId::of(&empty_enum::EMPTY_ENUM), LintId::of(&enum_glob_use::ENUM_GLOB_USE), LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5b08571c258..1f1c24b2c30 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 338] = [ +pub const ALL_LINTS: [Lint; 339] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1127,6 +1127,13 @@ pub const ALL_LINTS: [Lint; 338] = [ deprecation: None, module: "missing_doc", }, + Lint { + name: "missing_errors_doc", + group: "pedantic", + desc: "`pub fn` returns `Result` without `# Errors` in doc comment", + deprecation: None, + module: "doc", + }, Lint { name: "missing_inline_in_public_items", group: "restriction", diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs new file mode 100644 index 00000000000..408cf573896 --- /dev/null +++ b/tests/ui/doc_errors.rs @@ -0,0 +1,64 @@ +#![warn(clippy::missing_errors_doc)] + +use std::io; + +pub fn pub_fn_missing_errors_header() -> Result<(), ()> { + unimplemented!(); +} + +/// This is not sufficiently documented. +pub fn pub_fn_returning_io_result() -> io::Result<()> { + unimplemented!(); +} + +/// # Errors +/// A description of the errors goes here. +pub fn pub_fn_with_errors_header() -> Result<(), ()> { + unimplemented!(); +} + +/// This function doesn't require the documentation because it is private +fn priv_fn_missing_errors_header() -> Result<(), ()> { + unimplemented!(); +} + +pub struct Struct1; + +impl Struct1 { + /// This is not sufficiently documented. + pub fn pub_method_missing_errors_header() -> Result<(), ()> { + unimplemented!(); + } + + /// # Errors + /// A description of the errors goes here. + pub fn pub_method_with_errors_header() -> Result<(), ()> { + unimplemented!(); + } + + /// This function doesn't require the documentation because it is private. + fn priv_method_missing_errors_header() -> Result<(), ()> { + unimplemented!(); + } +} + +pub trait Trait1 { + /// This is not sufficiently documented. + fn trait_method_missing_errors_header() -> Result<(), ()>; + + /// # Errors + /// A description of the errors goes here. + fn trait_method_with_errors_header() -> Result<(), ()>; +} + +impl Trait1 for Struct1 { + fn trait_method_missing_errors_header() -> Result<(), ()> { + unimplemented!(); + } + + fn trait_method_with_errors_header() -> Result<(), ()> { + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui/doc_errors.stderr b/tests/ui/doc_errors.stderr new file mode 100644 index 00000000000..f1d321cf909 --- /dev/null +++ b/tests/ui/doc_errors.stderr @@ -0,0 +1,34 @@ +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_errors.rs:5:1 + | +LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { +LL | | unimplemented!(); +LL | | } + | |_^ + | + = note: `-D clippy::missing-errors-doc` implied by `-D warnings` + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_errors.rs:10:1 + | +LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { +LL | | unimplemented!(); +LL | | } + | |_^ + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_errors.rs:29:5 + | +LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { +LL | | unimplemented!(); +LL | | } + | |_____^ + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_errors.rs:47:5 + | +LL | fn trait_method_missing_errors_header() -> Result<(), ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From c77fc06d5218d1e5d757fa82eab130e688924f50 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 7 Dec 2019 16:33:49 -0800 Subject: Add lint to detect transmutes from float to integer Add lint that detects transmutation from a float to an integer and suggests usage of `{f32, f64}.to_bits()` instead. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/transmute.rs | 67 +++++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++++- tests/ui/transmute.rs | 10 +++++++ tests/ui/transmute.stderr | 56 ++++++++++++++++++++++++++++++------ 7 files changed, 136 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index a9448a57f7f..962f9067a4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1214,6 +1214,7 @@ Released 2018-09-13 [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str +[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float diff --git a/README.md b/README.md index 97a7c97b49a..6133fa4c3a5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 339 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d14f946c8eb..736ff30c81a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -735,6 +735,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &trait_bounds::TYPE_REPETITION_IN_BOUNDS, &transmute::CROSSPOINTER_TRANSMUTE, &transmute::TRANSMUTE_BYTES_TO_STR, + &transmute::TRANSMUTE_FLOAT_TO_INT, &transmute::TRANSMUTE_INT_TO_BOOL, &transmute::TRANSMUTE_INT_TO_CHAR, &transmute::TRANSMUTE_INT_TO_FLOAT, @@ -1586,6 +1587,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 12de3023dad..3c63ef765fe 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -190,6 +190,28 @@ declare_clippy_lint! { "transmutes from an integer to a float" } +declare_clippy_lint! { + /// **What it does:** Checks for transmutes from a float to an integer. + /// + /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive + /// and safe. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// unsafe { + /// let _: u32 = std::mem::transmute(1f32); + /// } + /// + /// // should be: + /// let _: u32 = 1f32.to_bits(); + /// ``` + pub TRANSMUTE_FLOAT_TO_INT, + nursery, + "transmutes from a float to an integer" +} + declare_clippy_lint! { /// **What it does:** Checks for transmutes from a pointer to a pointer, or /// from a reference to a reference. @@ -254,6 +276,7 @@ declare_lint_pass!(Transmute => [ TRANSMUTE_BYTES_TO_STR, TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_FLOAT, + TRANSMUTE_FLOAT_TO_INT, UNSOUND_COLLECTION_TRANSMUTE, ]); @@ -520,6 +543,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), + (&ty::Float(float_ty), &ty::Int(_)) | (&ty::Float(float_ty), &ty::Uint(_)) => span_lint_and_then( + cx, + TRANSMUTE_FLOAT_TO_INT, + e.span, + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + |db| { + let mut expr = &args[0]; + let mut arg = sugg::Sugg::hir(cx, expr, ".."); + + if let ExprKind::Unary(UnOp::UnNeg, inner_expr) = &expr.kind { + expr = &inner_expr; + } + + if_chain! { + // if the expression is a float literal and it is unsuffixed then + // add a suffix so the suggestion is valid and unambiguous + let op = format!("{}{}", arg, float_ty.name_str()).into(); + if let ExprKind::Lit(lit) = &expr.kind; + if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node; + then { + match arg { + sugg::Sugg::MaybeParen(_) => arg = sugg::Sugg::MaybeParen(op), + _ => arg = sugg::Sugg::NonParen(op) + } + } + } + + arg = sugg::Sugg::NonParen(format!("{}.to_bits()", arg.maybe_par()).into()); + + // cast the result of `to_bits` if `to_ty` is signed + arg = if let ty::Int(int_ty) = to_ty.kind { + arg.as_ty(int_ty.name_str().to_string()) + } else { + arg + }; + + db.span_suggestion( + e.span, + "consider using", + arg.to_string(), + Applicability::Unspecified, + ); + }, + ), (&ty::Adt(ref from_adt, ref from_substs), &ty::Adt(ref to_adt, ref to_substs)) => { if from_adt.did != to_adt.did || !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1f1c24b2c30..f4ebf6cbd91 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 339] = [ +pub const ALL_LINTS: [Lint; 340] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1953,6 +1953,13 @@ pub const ALL_LINTS: [Lint; 339] = [ deprecation: None, module: "transmute", }, + Lint { + name: "transmute_float_to_int", + group: "nursery", + desc: "transmutes from a float to an integer", + deprecation: None, + module: "transmute", + }, Lint { name: "transmute_int_to_bool", group: "complexity", diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 4f0c2f5a895..75d16f66a87 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -126,6 +126,16 @@ fn int_to_float() { let _: f32 = unsafe { std::mem::transmute(0_i32) }; } +#[warn(clippy::transmute_float_to_int)] +fn float_to_int() { + let _: u32 = unsafe { std::mem::transmute(1f32) }; + let _: i32 = unsafe { std::mem::transmute(1f32) }; + let _: u64 = unsafe { std::mem::transmute(1f64) }; + let _: i64 = unsafe { std::mem::transmute(1f64) }; + let _: u64 = unsafe { std::mem::transmute(1.0) }; + let _: u64 = unsafe { std::mem::transmute(-1.0) }; +} + fn bytes_to_str(b: &[u8], mb: &mut [u8]) { let _: &str = unsafe { std::mem::transmute(b) }; let _: &mut str = unsafe { std::mem::transmute(mb) }; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index f73d72f20bb..241e850a208 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -190,8 +190,46 @@ error: transmute from a `i32` to a `f32` LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` +error: transmute from a `f32` to a `u32` + --> $DIR/transmute.rs:131:27 + | +LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` + | + = note: `-D clippy::transmute-float-to-int` implied by `-D warnings` + +error: transmute from a `f32` to a `i32` + --> $DIR/transmute.rs:132:27 + | +LL | let _: i32 = unsafe { std::mem::transmute(1f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` + +error: transmute from a `f64` to a `u64` + --> $DIR/transmute.rs:133:27 + | +LL | let _: u64 = unsafe { std::mem::transmute(1f64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` + +error: transmute from a `f64` to a `i64` + --> $DIR/transmute.rs:134:27 + | +LL | let _: i64 = unsafe { std::mem::transmute(1f64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64` + +error: transmute from a `f64` to a `u64` + --> $DIR/transmute.rs:135:27 + | +LL | let _: u64 = unsafe { std::mem::transmute(1.0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()` + +error: transmute from a `f64` to a `u64` + --> $DIR/transmute.rs:136:27 + | +LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` + error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:130:28 + --> $DIR/transmute.rs:140:28 | LL | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` @@ -199,13 +237,13 @@ LL | let _: &str = unsafe { std::mem::transmute(b) }; = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:131:32 + --> $DIR/transmute.rs:141:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:163:29 + --> $DIR/transmute.rs:173:29 | LL | let _: *const f32 = std::mem::transmute(ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32` @@ -213,34 +251,34 @@ LL | let _: *const f32 = std::mem::transmute(ptr); = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings` error: transmute from a pointer to a pointer - --> $DIR/transmute.rs:164:27 + --> $DIR/transmute.rs:174:27 | LL | let _: *mut f32 = std::mem::transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32` error: transmute from a reference to a reference - --> $DIR/transmute.rs:166:23 + --> $DIR/transmute.rs:176:23 | LL | let _: &f32 = std::mem::transmute(&1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:167:23 + --> $DIR/transmute.rs:177:23 | LL | let _: &f64 = std::mem::transmute(&1f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:170:27 + --> $DIR/transmute.rs:180:27 | LL | let _: &mut f32 = std::mem::transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> $DIR/transmute.rs:171:37 + --> $DIR/transmute.rs:181:37 | LL | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` -error: aborting due to 38 previous errors +error: aborting due to 44 previous errors -- cgit 1.4.1-3-g733a5 From 728a2418cb34e577c2013dcc14d31c6b2d3d5432 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Mon, 16 Dec 2019 22:29:05 -0800 Subject: Fix clippy build failure Clippy build fails because the feature `result_map_or` has been stabilized in v1.41.0 but we still have an explicit feature attribute for it. --- clippy_lints/src/lib.rs | 1 - src/driver.rs | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 736ff30c81a..bae4eebf850 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -12,7 +12,6 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(crate_visibility_modifier)] #![feature(concat_idents)] -#![feature(result_map_or)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/src/driver.rs b/src/driver.rs index fda304afcbe..4cdff783788 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,5 +1,4 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] -#![feature(result_map_or)] #![feature(rustc_private)] // FIXME: switch to something more ergonomic here, once available. -- cgit 1.4.1-3-g733a5 From ecbfa386d4070708c512ddcc15ef7fec24da0b57 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Wed, 18 Dec 2019 19:19:26 +0200 Subject: Fix `iterator_step_by_zero` definition --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f4ebf6cbd91..201a80d81b3 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -887,7 +887,7 @@ pub const ALL_LINTS: [Lint; 340] = [ group: "correctness", desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", deprecation: None, - module: "ranges", + module: "methods", }, Lint { name: "just_underscores_and_digits", -- cgit 1.4.1-3-g733a5 From 3a81e60a29c53d6638319dafd5123fcbe59bb0b2 Mon Sep 17 00:00:00 2001 From: Michael Wright <mikerite@lavabit.com> Date: Fri, 20 Dec 2019 08:22:43 +0200 Subject: Update lints for `iterator_step_by_zero` changes --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 201a80d81b3..c91be11f4f4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -885,7 +885,7 @@ pub const ALL_LINTS: [Lint; 340] = [ Lint { name: "iterator_step_by_zero", group: "correctness", - desc: "using `Iterator::step_by(0)`, which produces an infinite iterator", + desc: "using `Iterator::step_by(0)`, which will panic at runtime", deprecation: None, module: "methods", }, -- cgit 1.4.1-3-g733a5 From 710c749bb12bc84018e04b63424b8d8d3d80a9c4 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Sat, 21 Dec 2019 16:20:30 +0100 Subject: Deprecate unused_label lint This lint was uplifted/turned into warn-by-default in rustc --- README.md | 2 +- clippy_lints/src/deprecated_lints.rs | 9 ++++ clippy_lints/src/lib.rs | 9 ++-- clippy_lints/src/unused_label.rs | 83 ------------------------------------ src/lintlist/mod.rs | 9 +--- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +++- tests/ui/empty_loop.rs | 1 - tests/ui/empty_loop.stderr | 6 +-- tests/ui/unused_labels.rs | 35 --------------- tests/ui/unused_labels.stderr | 30 ------------- 11 files changed, 26 insertions(+), 167 deletions(-) delete mode 100644 clippy_lints/src/unused_label.rs delete mode 100644 tests/ui/unused_labels.rs delete mode 100644 tests/ui/unused_labels.stderr (limited to 'src') diff --git a/README.md b/README.md index 6133fa4c3a5..97a7c97b49a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 339 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index f399b4a78c6..93c19bf9550 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -138,3 +138,12 @@ declare_deprecated_lint! { pub INTO_ITER_ON_ARRAY, "this lint has been uplifted to rustc and is now called `array_into_iter`" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** This lint has been uplifted to rustc and is now called + /// `unused_labels`. + pub UNUSED_LABEL, + "this lint has been uplifted to rustc and is now called `unused_labels`" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7fb499ebf85..d4e86cbfe57 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -292,7 +292,6 @@ pub mod types; pub mod unicode; pub mod unsafe_removed_from_name; pub mod unused_io_amount; -pub mod unused_label; pub mod unused_self; pub mod unwrap; pub mod use_self; @@ -446,6 +445,10 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf "clippy::into_iter_on_array", "this lint has been uplifted to rustc and is now called `array_into_iter`", ); + store.register_removed( + "clippy::unused_label", + "this lint has been uplifted to rustc and is now called `unused_labels`", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -774,7 +777,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &unicode::ZERO_WIDTH_SPACE, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, - &unused_label::UNUSED_LABEL, &unused_self::UNUSED_SELF, &unwrap::PANICKING_UNWRAP, &unwrap::UNNECESSARY_UNWRAP, @@ -868,7 +870,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box format::UselessFormat); store.register_late_pass(|| box swap::Swap); store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional); - store.register_late_pass(|| box unused_label::UnusedLabel); store.register_late_pass(|| box new_without_default::NewWithoutDefault::default()); let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>(); store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone())); @@ -1302,7 +1303,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&unicode::ZERO_WIDTH_SPACE), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(&unused_label::UNUSED_LABEL), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&vec::USELESS_VEC), @@ -1482,7 +1482,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&types::UNIT_ARG), LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), - LintId::of(&unused_label::UNUSED_LABEL), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs deleted file mode 100644 index 60acbc1469f..00000000000 --- a/clippy_lints/src/unused_label.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::utils::span_lint; -use rustc::declare_lint_pass; -use rustc::hir; -use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc_data_structures::fx::FxHashMap; -use rustc_session::declare_tool_lint; -use syntax::source_map::Span; -use syntax::symbol::Symbol; - -declare_clippy_lint! { - /// **What it does:** Checks for unused labels. - /// - /// **Why is this bad?** Maybe the label should be used in which case there is - /// an error in the code or it should be removed. - /// - /// **Known problems:** Hopefully none. - /// - /// **Example:** - /// ```rust,ignore - /// fn unused_label() { - /// 'label: for i in 1..2 { - /// if i > 4 { continue } - /// } - /// ``` - pub UNUSED_LABEL, - complexity, - "unused labels" -} - -struct UnusedLabelVisitor<'a, 'tcx> { - labels: FxHashMap<Symbol, Span>, - cx: &'a LateContext<'a, 'tcx>, -} - -declare_lint_pass!(UnusedLabel => [UNUSED_LABEL]); - -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::Body, - span: Span, - fn_id: hir::HirId, - ) { - if span.from_expansion() { - return; - } - - let mut v = UnusedLabelVisitor { - cx, - labels: FxHashMap::default(), - }; - walk_fn(&mut v, kind, decl, body.id(), span, fn_id); - - for (label, span) in v.labels { - span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - match expr.kind { - hir::ExprKind::Break(destination, _) | hir::ExprKind::Continue(destination) => { - if let Some(label) = destination.label { - self.labels.remove(&label.ident.name); - } - }, - hir::ExprKind::Loop(_, Some(label), _) => { - self.labels.insert(label.ident.name, expr.span); - }, - _ => (), - } - - walk_expr(self, expr); - } - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.cx.tcx.hir()) - } -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c91be11f4f4..f3012fba2da 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 340] = [ +pub const ALL_LINTS: [Lint; 339] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2177,13 +2177,6 @@ pub const ALL_LINTS: [Lint; 340] = [ deprecation: None, module: "unused_io_amount", }, - Lint { - name: "unused_label", - group: "complexity", - desc: "unused labels", - deprecation: None, - module: "unused_label", - }, Lint { name: "unused_self", group: "pedantic", diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 91d43758ab0..188a641aa1a 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -6,5 +6,6 @@ #[warn(clippy::unused_collect)] #[warn(clippy::invalid_ref)] #[warn(clippy::into_iter_on_array)] +#[warn(clippy::unused_label)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index d353b26e537..a4efe3d15a9 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -48,11 +48,17 @@ error: lint `clippy::into_iter_on_array` has been removed: `this lint has been u LL | #[warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels`` + --> $DIR/deprecated.rs:9:8 + | +LL | #[warn(clippy::unused_label)] + | ^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index fb9f2cb9cf4..8fd7697eb3b 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,7 +1,6 @@ // aux-build:macro_rules.rs #![warn(clippy::empty_loop)] -#![allow(clippy::unused_label)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr index 41b79900425..e44c58ea770 100644 --- a/tests/ui/empty_loop.stderr +++ b/tests/ui/empty_loop.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body. - --> $DIR/empty_loop.rs:10:5 + --> $DIR/empty_loop.rs:9:5 | LL | loop {} | ^^^^^^^ @@ -7,13 +7,13 @@ LL | loop {} = note: `-D clippy::empty-loop` implied by `-D warnings` error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body. - --> $DIR/empty_loop.rs:12:9 + --> $DIR/empty_loop.rs:11:9 | LL | loop {} | ^^^^^^^ error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body. - --> $DIR/empty_loop.rs:16:9 + --> $DIR/empty_loop.rs:15:9 | LL | 'inner: loop {} | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs deleted file mode 100644 index ae963ad6969..00000000000 --- a/tests/ui/unused_labels.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![allow(dead_code, clippy::items_after_statements, clippy::never_loop)] -#![warn(clippy::unused_label)] - -fn unused_label() { - 'label: for i in 1..2 { - if i > 4 { - continue; - } - } -} - -fn foo() { - 'same_label_in_two_fns: loop { - break 'same_label_in_two_fns; - } -} - -fn bla() { - 'a: loop { - break; - } - fn blub() {} -} - -fn main() { - 'a: for _ in 0..10 { - while let Some(42) = None { - continue 'a; - } - } - - 'same_label_in_two_fns: loop { - let _ = 1; - } -} diff --git a/tests/ui/unused_labels.stderr b/tests/ui/unused_labels.stderr deleted file mode 100644 index d2ca0f1b57f..00000000000 --- a/tests/ui/unused_labels.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: unused label `'label` - --> $DIR/unused_labels.rs:5:5 - | -LL | / 'label: for i in 1..2 { -LL | | if i > 4 { -LL | | continue; -LL | | } -LL | | } - | |_____^ - | - = note: `-D clippy::unused-label` implied by `-D warnings` - -error: unused label `'a` - --> $DIR/unused_labels.rs:19:5 - | -LL | / 'a: loop { -LL | | break; -LL | | } - | |_____^ - -error: unused label `'same_label_in_two_fns` - --> $DIR/unused_labels.rs:32:5 - | -LL | / 'same_label_in_two_fns: loop { -LL | | let _ = 1; -LL | | } - | |_____^ - -error: aborting due to 3 previous errors - -- cgit 1.4.1-3-g733a5 From a310cb2d0b708a46fda5c4b6f91a3221c25842c6 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko <misha-babenko@yandex.ru> Date: Sat, 16 Nov 2019 17:55:00 +0300 Subject: implemented `let_underscore` lint actually add files update lints change to pedantic --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/functions.rs | 6 +-- clippy_lints/src/let_underscore.rs | 62 ++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 ++ clippy_lints/src/utils/mod.rs | 24 ++++++++- src/lintlist/mod.rs | 9 +++- tests/ui/let_underscore.rs | 84 ++++++++++++++++++++++++++++++++ tests/ui/let_underscore.stderr | 99 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 285 insertions(+), 6 deletions(-) create mode 100644 clippy_lints/src/let_underscore.rs create mode 100644 tests/ui/let_underscore.rs create mode 100644 tests/ui/let_underscore.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 962f9067a4e..e485c2c979e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1064,6 +1064,7 @@ Released 2018-09-13 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug diff --git a/README.md b/README.md index 280b25d7c53..46fbc9dc9a4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 339 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index ae4f36dd34a..de14f2327db 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,7 +1,7 @@ use crate::utils::{ - attrs::is_proc_macro, iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt, - span_help_and_lint, span_lint, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, - must_use_attr, is_must_use_ty, + attrs::is_proc_macro, is_must_use_ty, iter_input_pats, match_def_path, must_use_attr, qpath_res, return_ty, + snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then, trait_ref_of_method, + type_is_unsafe_function, }; use matches::matches; use rustc::hir::{self, def::Res, def_id::DefId, intravisit}; diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs new file mode 100644 index 00000000000..2b59b7c6b4a --- /dev/null +++ b/clippy_lints/src/let_underscore.rs @@ -0,0 +1,62 @@ +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc_session::declare_tool_lint; + +use crate::utils::{is_must_use_func_call, is_must_use_ty, span_help_and_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for `let _ = <expr>` + /// where expr is #[must_use] + /// + /// **Why is this bad?** It's better to explicitly + /// handle the value of a #[must_use] expr + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// fn f() -> Result<u32, u32> { + /// Ok(0) + /// } + /// + /// let _ = f(); + /// // is_ok() is marked #[must_use] + /// let _ = f().is_ok(); + /// ``` + pub LET_UNDERSCORE_MUST_USE, + restriction, + "non-binding let on a #[must_use] expression" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { + fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &Stmt) { + if_chain! { + if let StmtKind::Local(ref local) = stmt.kind; + if let PatKind::Wild = local.pat.kind; + if let Some(ref init) = local.init; + then { + if is_must_use_ty(cx, cx.tables.expr_ty(init)) { + span_help_and_lint( + cx, + LET_UNDERSCORE_MUST_USE, + stmt.span, + "non-binding let on an expression with #[must_use] type", + "consider explicitly using expression value" + ) + } else if is_must_use_func_call(cx, init) { + span_help_and_lint( + cx, + LET_UNDERSCORE_MUST_USE, + stmt.span, + "non-binding let on a result of a #[must_use] function", + "consider explicitly using function result" + ) + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d4e86cbfe57..2e5ce50bf34 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -220,6 +220,7 @@ pub mod large_enum_variant; pub mod large_stack_arrays; pub mod len_zero; pub mod let_if_seq; +pub mod let_underscore; pub mod lifetimes; pub mod literal_representation; pub mod loops; @@ -555,6 +556,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, + &let_underscore::LET_UNDERSCORE_MUST_USE, &lifetimes::EXTRA_UNUSED_LIFETIMES, &lifetimes::NEEDLESS_LIFETIMES, &literal_representation::DECIMAL_LITERAL_REPRESENTATION, @@ -970,6 +972,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); + store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -982,6 +985,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&indexing_slicing::INDEXING_SLICING), LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), LintId::of(&integer_division::INTEGER_DIVISION), + LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index b1edb4b448f..43d458f4206 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -41,7 +41,7 @@ use rustc::ty::{ }; use rustc_errors::Applicability; use smallvec::SmallVec; -use syntax::ast::{self, LitKind, Attribute}; +use syntax::ast::{self, Attribute, LitKind}; use syntax::attr; use syntax::source_map::{Span, DUMMY_SP}; use syntax::symbol::{kw, Symbol}; @@ -1283,3 +1283,25 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo } } +// check if expr is calling method or function with #[must_use] attribyte +pub fn is_must_use_func_call(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { + let did = match expr.kind { + ExprKind::Call(ref path, _) => if_chain! { + if let ExprKind::Path(ref qpath) = path.kind; + if let def::Res::Def(_, did) = cx.tables.qpath_res(qpath, path.hir_id); + then { + Some(did) + } else { + None + } + }, + ExprKind::MethodCall(_, _, _) => cx.tables.type_dependent_def_id(expr.hir_id), + _ => None, + }; + + if let Some(did) = did { + must_use_attr(&cx.tcx.get_attrs(did)).is_some() + } else { + false + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f3012fba2da..913e941660e 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 339] = [ +pub const ALL_LINTS: [Lint; 340] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -938,6 +938,13 @@ pub const ALL_LINTS: [Lint; 339] = [ deprecation: None, module: "returns", }, + Lint { + name: "let_underscore_must_use", + group: "restriction", + desc: "non-binding let on a #[must_use] expression", + deprecation: None, + module: "let_underscore", + }, Lint { name: "let_unit_value", group: "style", diff --git a/tests/ui/let_underscore.rs b/tests/ui/let_underscore.rs new file mode 100644 index 00000000000..1f0dbcee42a --- /dev/null +++ b/tests/ui/let_underscore.rs @@ -0,0 +1,84 @@ +#![warn(clippy::let_underscore_must_use)] + +#[must_use] +fn f() -> u32 { + 0 +} + +fn g() -> Result<u32, u32> { + Ok(0) +} + +#[must_use] +fn l<T>(x: T) -> T { + x +} + +fn h() -> u32 { + 0 +} + +struct S {} + +impl S { + #[must_use] + pub fn f(&self) -> u32 { + 0 + } + + pub fn g(&self) -> Result<u32, u32> { + Ok(0) + } + + fn k(&self) -> u32 { + 0 + } + + #[must_use] + fn h() -> u32 { + 0 + } + + fn p() -> Result<u32, u32> { + Ok(0) + } +} + +trait Trait { + #[must_use] + fn a() -> u32; +} + +impl Trait for S { + fn a() -> u32 { + 0 + } +} + +fn main() { + let _ = f(); + let _ = g(); + let _ = h(); + let _ = l(0_u32); + + let s = S {}; + + let _ = s.f(); + let _ = s.g(); + let _ = s.k(); + + let _ = S::h(); + let _ = S::p(); + + let _ = S::a(); + + let _ = if true { Ok(()) } else { Err(()) }; + + let a = Result::<(), ()>::Ok(()); + + let _ = a.is_ok(); + + let _ = a.map(|_| ()); + + let _ = a; +} diff --git a/tests/ui/let_underscore.stderr b/tests/ui/let_underscore.stderr new file mode 100644 index 00000000000..da007d3b083 --- /dev/null +++ b/tests/ui/let_underscore.stderr @@ -0,0 +1,99 @@ +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:59:5 + | +LL | let _ = f(); + | ^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` + = help: consider explicitly using function result + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:60:5 + | +LL | let _ = g(); + | ^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:62:5 + | +LL | let _ = l(0_u32); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:66:5 + | +LL | let _ = s.f(); + | ^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:67:5 + | +LL | let _ = s.g(); + | ^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:70:5 + | +LL | let _ = S::h(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:71:5 + | +LL | let _ = S::p(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:73:5 + | +LL | let _ = S::a(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:75:5 + | +LL | let _ = if true { Ok(()) } else { Err(()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a #[must_use] function + --> $DIR/let_underscore.rs:79:5 + | +LL | let _ = a.is_ok(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:81:5 + | +LL | let _ = a.map(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on an expression with #[must_use] type + --> $DIR/let_underscore.rs:83:5 + | +LL | let _ = a; + | ^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: aborting due to 12 previous errors + -- cgit 1.4.1-3-g733a5 From f5b896451ac44fc45bdc78656176f2846f44891a Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Tue, 24 Dec 2019 03:06:52 +0700 Subject: do minor cleanups * ToString and AsRef are in prelude, no need to import them --- clippy_dev/src/lib.rs | 2 +- clippy_lints/src/cargo_common_metadata.rs | 4 +- clippy_lints/src/consts.rs | 2 +- clippy_lints/src/doc.rs | 1 - clippy_lints/src/eta_reduction.rs | 6 +-- clippy_lints/src/lib.rs | 11 ++--- clippy_lints/src/literal_representation.rs | 1 - clippy_lints/src/multiple_crate_versions.rs | 1 - clippy_lints/src/regex.rs | 1 - clippy_lints/src/utils/conf.rs | 2 - clippy_lints/src/utils/sugg.rs | 2 - clippy_lints/src/wildcard_dependencies.rs | 2 - src/driver.rs | 69 ++++++++++++----------------- tests/integration.rs | 1 - tests/ui/inefficient_to_string.fixed | 1 - tests/ui/inefficient_to_string.rs | 1 - tests/ui/inefficient_to_string.stderr | 12 ++--- 17 files changed, 45 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index f73e7b86720..3aae3e53317 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -50,7 +50,7 @@ impl Lint { name: name.to_lowercase(), group: group.to_string(), desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), - deprecation: deprecation.map(std::string::ToString::to_string), + deprecation: deprecation.map(ToString::to_string), module: module.to_string(), } } diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 4fc9c3e60e7..15457e57860 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -8,8 +8,6 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc_session::declare_tool_lint; use syntax::{ast::*, source_map::DUMMY_SP}; -use cargo_metadata; - declare_clippy_lint! { /// **What it does:** Checks to see if all common metadata is defined in /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata @@ -56,7 +54,7 @@ fn is_empty_path(value: &Option<PathBuf>) -> bool { fn is_empty_vec(value: &[String]) -> bool { // This works because empty iterators return true - value.iter().all(std::string::String::is_empty) + value.iter().all(String::is_empty) } declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]); diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index d86766ee0a5..f1e488a7e6d 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -253,7 +253,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { let res = self.tables.qpath_res(qpath, callee.hir_id); if let Some(def_id) = res.opt_def_id(); let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect(); - let def_path: Vec<&str> = def_path.iter().map(|s| &**s).collect(); + let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect(); if let ["core", "num", int_impl, "max_value"] = *def_path; then { let value = match int_impl { diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 327c18e855d..75e6cebb563 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,6 +1,5 @@ use crate::utils::{match_type, paths, return_ty, span_lint}; use itertools::Itertools; -use pulldown_cmark; use rustc::hir; use rustc::impl_lint_pass; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 54fdde67dec..0abe757e359 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -146,11 +146,7 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) { } /// Tries to determine the type for universal function call to be used instead of the closure -fn get_ufcs_type_name( - cx: &LateContext<'_, '_>, - method_def_id: def_id::DefId, - self_arg: &Expr, -) -> std::option::Option<String> { +fn get_ufcs_type_name(cx: &LateContext<'_, '_>, method_def_id: def_id::DefId, self_arg: &Expr) -> Option<String> { let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0]; let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2e5ce50bf34..c3712e13d3f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -47,7 +47,8 @@ extern crate syntax_pos; use rustc::lint::{self, LintId}; use rustc::session::Session; use rustc_data_structures::fx::FxHashSet; -use toml; + +use std::path::Path; /// Macro used to declare a Clippy lint. /// @@ -349,16 +350,16 @@ pub fn read_conf(args: &[syntax::ast::NestedMetaItem], sess: &Session) -> Conf { let file_name = file_name.map(|file_name| { if file_name.is_relative() { sess.local_crate_source_file - .as_ref() - .and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf)) - .unwrap_or_default() + .as_deref() + .and_then(Path::parent) + .unwrap_or_else(|| Path::new("")) .join(file_name) } else { file_name } }); - let (conf, errors) = utils::conf::read(file_name.as_ref().map(std::convert::AsRef::as_ref)); + let (conf, errors) = utils::conf::read(file_name.as_ref().map(AsRef::as_ref)); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 24f40a161be..427243d4c62 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -8,7 +8,6 @@ use rustc::{declare_lint_pass, impl_lint_pass}; use rustc_errors::Applicability; use rustc_session::declare_tool_lint; use syntax::ast::*; -use syntax_pos; declare_clippy_lint! { /// **What it does:** Warns if a long integral or floating-point constant does diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index db22631104d..79caf4f5552 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -6,7 +6,6 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc_session::declare_tool_lint; use syntax::{ast::*, source_map::DUMMY_SP}; -use cargo_metadata; use itertools::Itertools; declare_clippy_lint! { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index e06ebe539e7..c60912ddb2c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,7 +1,6 @@ use crate::consts::{constant, Constant}; use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint}; use if_chain::if_chain; -use regex_syntax; use rustc::hir::*; use rustc::impl_lint_pass; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index a3407d1e990..52223aa7a4b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -8,7 +8,6 @@ use std::io::Read; use std::sync::Mutex; use std::{env, fmt, fs, io, path}; use syntax::{ast, source_map}; -use toml; /// Gets the configuration file from arguments. pub fn file_from_args(args: &[ast::NestedMetaItem]) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> { @@ -77,7 +76,6 @@ macro_rules! define_Conf { } $( mod $rust_name { - use serde; use serde::Deserialize; crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<define_Conf!(TY $($ty)+), D::Error> { diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 228fda9eec0..7050ea4cb2d 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -5,9 +5,7 @@ use crate::utils::{higher, snippet, snippet_opt, snippet_with_macro_callsite}; use matches::matches; use rustc::hir; use rustc::lint::{EarlyContext, LateContext, LintContext}; -use rustc_errors; use rustc_errors::Applicability; -use std; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index bd865bf495c..0a302ce04ca 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -4,9 +4,7 @@ use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc_session::declare_tool_lint; use syntax::{ast::*, source_map::DUMMY_SP}; -use cargo_metadata; use if_chain::if_chain; -use semver; declare_clippy_lint! { /// **What it does:** Checks for wildcard dependencies in the `Cargo.toml`. diff --git a/src/driver.rs b/src/driver.rs index 4cdff783788..4a080c12e44 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,5 +1,6 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(rustc_private)] +#![feature(str_strip)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) @@ -18,6 +19,8 @@ use rustc_tools_util::*; use lazy_static::lazy_static; use std::borrow::Cow; +use std::env; +use std::ops::Deref; use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; @@ -26,22 +29,21 @@ mod lintlist; /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. -fn arg_value<'a>( - args: impl IntoIterator<Item = &'a String>, +fn arg_value<'a, T: Deref<Target = str>>( + args: &'a [T], find_arg: &str, pred: impl Fn(&str) -> bool, ) -> Option<&'a str> { - let mut args = args.into_iter().map(String::as_str); - + let mut args = args.iter().map(Deref::deref); while let Some(arg) = args.next() { - let arg: Vec<_> = arg.splitn(2, '=').collect(); - if arg.get(0) != Some(&find_arg) { + let mut arg = arg.splitn(2, '='); + if arg.next() != Some(find_arg) { continue; } - let value = arg.get(1).cloned().or_else(|| args.next()); - if value.as_ref().map_or(false, |p| pred(p)) { - return value; + match arg.next().or_else(|| args.next()) { + Some(v) if pred(v) => return Some(v), + _ => {}, } } None @@ -49,19 +51,16 @@ fn arg_value<'a>( #[test] fn test_arg_value() { - let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"] - .iter() - .map(std::string::ToString::to_string) - .collect(); - - assert_eq!(arg_value(None, "--foobar", |_| true), None); - assert_eq!(arg_value(&args, "--bar", |_| false), None); - assert_eq!(arg_value(&args, "--bar", |_| true), Some("bar")); - assert_eq!(arg_value(&args, "--bar", |p| p == "bar"), Some("bar")); - assert_eq!(arg_value(&args, "--bar", |p| p == "foo"), None); - assert_eq!(arg_value(&args, "--foobar", |p| p == "foo"), None); - assert_eq!(arg_value(&args, "--foobar", |p| p == "123"), Some("123")); - assert_eq!(arg_value(&args, "--foo", |_| true), None); + let args = &["--bar=bar", "--foobar", "123", "--foo"]; + + assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None); + assert_eq!(arg_value(args, "--bar", |_| false), None); + assert_eq!(arg_value(args, "--bar", |_| true), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar")); + assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None); + assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123")); + assert_eq!(arg_value(args, "--foo", |_| true), None); } #[allow(clippy::too_many_lines)] @@ -276,7 +275,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } // If backtraces are enabled, also print the query stack - let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); if backtrace { TyCtxt::try_print_query_stack(&handler); @@ -288,16 +287,14 @@ pub fn main() { lazy_static::initialize(&ICE_HOOK); exit( rustc_driver::catch_fatal_errors(move || { - use std::env; + let mut orig_args: Vec<String> = env::args().collect(); - if std::env::args().any(|a| a == "--version" || a == "-V") { + if orig_args.iter().any(|a| a == "--version" || a == "-V") { let version_info = rustc_tools_util::get_version_info!(); println!("{}", version_info); exit(0); } - let mut orig_args: Vec<String> = env::args().collect(); - // Get the sysroot, looking from most specific to this invocation to the least: // - command line // - runtime environment @@ -350,7 +347,7 @@ pub fn main() { } let should_describe_lints = || { - let args: Vec<_> = std::env::args().collect(); + let args: Vec<_> = env::args().collect(); args.windows(2).any(|args| { args[1] == "help" && match args[0].as_str() { @@ -368,15 +365,9 @@ pub fn main() { // this conditional check for the --sysroot flag is there so users can call // `clippy_driver` directly // without having to pass --sysroot or anything - let mut args: Vec<String> = if have_sys_root_arg { - orig_args.clone() - } else { - orig_args - .clone() - .into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() + let mut args: Vec<String> = orig_args.clone(); + if !have_sys_root_arg { + args.extend(vec!["--sysroot".into(), sys_root]); }; // this check ensures that dependencies are built but not linted and the final @@ -385,7 +376,7 @@ pub fn main() { || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none(); if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); if let Ok(extra_args) = env::var("CLIPPY_ARGS") { args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { if s.is_empty() { @@ -396,12 +387,10 @@ pub fn main() { })); } } - let mut clippy = ClippyCallbacks; let mut default = rustc_driver::DefaultCallbacks; let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { &mut clippy } else { &mut default }; - let args = args; rustc_driver::run_compiler(&args, callbacks, None, None) }) .and_then(|result| result) diff --git a/tests/integration.rs b/tests/integration.rs index 455965436d6..d14ced8ad4e 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,7 +1,6 @@ #![cfg(feature = "integration")] use git2::Repository; -use tempfile; use std::env; use std::process::Command; diff --git a/tests/ui/inefficient_to_string.fixed b/tests/ui/inefficient_to_string.fixed index 32bc7574a52..c972b9419ef 100644 --- a/tests/ui/inefficient_to_string.fixed +++ b/tests/ui/inefficient_to_string.fixed @@ -2,7 +2,6 @@ #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; -use std::string::ToString; fn main() { let rstr: &str = "hello"; diff --git a/tests/ui/inefficient_to_string.rs b/tests/ui/inefficient_to_string.rs index 2741565e50d..acdc55aa0d6 100644 --- a/tests/ui/inefficient_to_string.rs +++ b/tests/ui/inefficient_to_string.rs @@ -2,7 +2,6 @@ #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; -use std::string::ToString; fn main() { let rstr: &str = "hello"; diff --git a/tests/ui/inefficient_to_string.stderr b/tests/ui/inefficient_to_string.stderr index 20788f6f6cc..08592e7d588 100644 --- a/tests/ui/inefficient_to_string.stderr +++ b/tests/ui/inefficient_to_string.stderr @@ -1,5 +1,5 @@ error: calling `to_string` on `&&str` - --> $DIR/inefficient_to_string.rs:12:21 + --> $DIR/inefficient_to_string.rs:11:21 | LL | let _: String = rrstr.to_string(); | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()` @@ -12,7 +12,7 @@ LL | #![deny(clippy::inefficient_to_string)] = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString` error: calling `to_string` on `&&&str` - --> $DIR/inefficient_to_string.rs:13:21 + --> $DIR/inefficient_to_string.rs:12:21 | LL | let _: String = rrrstr.to_string(); | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstr).to_string()` @@ -20,7 +20,7 @@ LL | let _: String = rrrstr.to_string(); = help: `&&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString` error: calling `to_string` on `&&std::string::String` - --> $DIR/inefficient_to_string.rs:21:21 + --> $DIR/inefficient_to_string.rs:20:21 | LL | let _: String = rrstring.to_string(); | ^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstring).to_string()` @@ -28,7 +28,7 @@ LL | let _: String = rrstring.to_string(); = help: `&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString` error: calling `to_string` on `&&&std::string::String` - --> $DIR/inefficient_to_string.rs:22:21 + --> $DIR/inefficient_to_string.rs:21:21 | LL | let _: String = rrrstring.to_string(); | ^^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstring).to_string()` @@ -36,7 +36,7 @@ LL | let _: String = rrrstring.to_string(); = help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString` error: calling `to_string` on `&&std::borrow::Cow<'_, str>` - --> $DIR/inefficient_to_string.rs:30:21 + --> $DIR/inefficient_to_string.rs:29:21 | LL | let _: String = rrcow.to_string(); | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()` @@ -44,7 +44,7 @@ LL | let _: String = rrcow.to_string(); = help: `&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString` error: calling `to_string` on `&&&std::borrow::Cow<'_, str>` - --> $DIR/inefficient_to_string.rs:31:21 + --> $DIR/inefficient_to_string.rs:30:21 | LL | let _: String = rrrcow.to_string(); | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()` -- cgit 1.4.1-3-g733a5 From 40435acf3d3b6abdc37c00a5d3c7a97c61b8841f Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Fri, 6 Dec 2019 19:45:33 +0100 Subject: new lint: mutable_key_type --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/mut_key.rs | 120 ++++++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/mut_key.rs | 37 ++++++++++++++ tests/ui/mut_key.stderr | 22 ++++++++ 7 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/mut_key.rs create mode 100644 tests/ui/mut_key.rs create mode 100644 tests/ui/mut_key.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index e485c2c979e..09805e91d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1108,6 +1108,7 @@ Released 2018-09-13 [`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref [`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut [`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound +[`mutable_key_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type [`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount diff --git a/README.md b/README.md index 46fbc9dc9a4..be5433029de 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 341 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2e5ce50bf34..218928dfeae 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -240,6 +240,7 @@ pub mod missing_doc; pub mod missing_inline; pub mod mul_add; pub mod multiple_crate_versions; +pub mod mut_key; pub mod mut_mut; pub mod mut_reference; pub mod mutable_debug_assertion; @@ -667,6 +668,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, &mul_add::MANUAL_MUL_ADD, &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, + &mut_key::MUTABLE_KEY_TYPE, &mut_mut::MUT_MUT, &mut_reference::UNNECESSARY_MUT_PASSED, &mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, @@ -939,6 +941,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box trait_bounds::TraitBounds); store.register_late_pass(|| box comparison_chain::ComparisonChain); store.register_late_pass(|| box mul_add::MulAddCheck); + store.register_late_pass(|| box mut_key::MutableKeyType); store.register_early_pass(|| box reference::DerefAddrOf); store.register_early_pass(|| box reference::RefInDeref); store.register_early_pass(|| box double_parens::DoubleParens); @@ -1223,6 +1226,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(&mut_key::MUTABLE_KEY_TYPE), LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_ATOMIC), @@ -1532,6 +1536,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&misc::CMP_NAN), LintId::of(&misc::FLOAT_CMP), LintId::of(&misc::MODULO_ONE), + LintId::of(&mut_key::MUTABLE_KEY_TYPE), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs new file mode 100644 index 00000000000..3a0899032a5 --- /dev/null +++ b/clippy_lints/src/mut_key.rs @@ -0,0 +1,120 @@ +use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty}; +use rustc::declare_lint_pass; +use rustc::hir; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty::{Adt, Dynamic, Opaque, Param, RawPtr, Ref, Ty, TypeAndMut}; +use rustc_session::declare_tool_lint; +use syntax::source_map::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for sets/maps with mutable key types. + /// + /// **Why is this bad?** All of `HashMap`, `HashSet`, `BTreeMap` and + /// `BtreeSet` rely on either the hash or the order of keys be unchanging, + /// so having types with interior mutability is a bad idea. + /// + /// **Known problems:** We don't currently account for `Rc` or `Arc`, so + /// this may yield false positives. + /// + /// **Example:** + /// ```rust + /// use std::cmp::{PartialEq, Eq}; + /// use std::collections::HashSet; + /// use std::hash::{Hash, Hasher}; + /// use std::sync::atomic::AtomicUsize; + ///# #[allow(unused)] + /// + /// struct Bad(AtomicUsize); + /// impl PartialEq for Bad { + /// fn eq(&self, rhs: &Self) -> bool { + /// .. + /// ; unimplemented!(); + /// } + /// } + /// + /// impl Eq for Bad {} + /// + /// impl Hash for Bad { + /// fn hash<H: Hasher>(&self, h: &mut H) { + /// .. + /// ; unimplemented!(); + /// } + /// } + /// + /// fn main() { + /// let _: HashSet<Bad> = HashSet::new(); + /// } + /// ``` + pub MUTABLE_KEY_TYPE, + correctness, + "Check for mutable Map/Set key type" +} + +declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableKeyType { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>) { + if let hir::ItemKind::Fn(ref sig, ..) = item.kind { + check_sig(cx, item.hir_id, &sig.decl); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem<'tcx>) { + if let hir::ImplItemKind::Method(ref sig, ..) = item.kind { + if trait_ref_of_method(cx, item.hir_id).is_none() { + check_sig(cx, item.hir_id, &sig.decl); + } + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem<'tcx>) { + if let hir::TraitItemKind::Method(ref sig, ..) = item.kind { + check_sig(cx, item.hir_id, &sig.decl); + } + } + + fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &hir::Local) { + if let hir::PatKind::Wild = local.pat.kind { + return; + } + check_ty(cx, local.span, cx.tables.pat_ty(&*local.pat)); + } +} + +fn check_sig<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item_hir_id: hir::HirId, decl: &hir::FnDecl) { + let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id); + let fn_sig = cx.tcx.fn_sig(fn_def_id); + for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) { + check_ty(cx, hir_ty.span, ty); + } + check_ty( + cx, + decl.output.span(), + cx.tcx.erase_late_bound_regions(&fn_sig.output()), + ); +} + +// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased +// generics (because the compiler cannot ensure immutability for unknown types). +fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { + let ty = walk_ptrs_ty(ty); + if let Adt(def, substs) = ty.kind { + if [&paths::HASHMAP, &paths::BTREEMAP, &paths::HASHSET, &paths::BTREESET] + .iter() + .any(|path| match_def_path(cx, def.did, &**path)) + { + let key_type = substs.type_at(0); + if is_concrete_type(key_type) && !key_type.is_freeze(cx.tcx, cx.param_env, span) { + span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); + } + } + } +} + +fn is_concrete_type(ty: Ty<'_>) -> bool { + match ty.kind { + RawPtr(TypeAndMut { ty: inner_ty, .. }) | Ref(_, inner_ty, _) => is_concrete_type(inner_ty), + Dynamic(..) | Opaque(..) | Param(..) => false, + _ => true, + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 913e941660e..bdbe06c5f27 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 340] = [ +pub const ALL_LINTS: [Lint; 341] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1239,6 +1239,13 @@ pub const ALL_LINTS: [Lint; 340] = [ deprecation: None, module: "loops", }, + Lint { + name: "mutable_key_type", + group: "correctness", + desc: "Check for mutable Map/Set key type", + deprecation: None, + module: "mut_key", + }, Lint { name: "mutex_atomic", group: "perf", diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs new file mode 100644 index 00000000000..5ec9b05f517 --- /dev/null +++ b/tests/ui/mut_key.rs @@ -0,0 +1,37 @@ +use std::collections::{HashMap, HashSet}; +use std::hash::{Hash, Hasher}; +use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + +struct Key(AtomicUsize); + +impl Clone for Key { + fn clone(&self) -> Self { + Key(AtomicUsize::new(self.0.load(Relaxed))) + } +} + +impl PartialEq for Key { + fn eq(&self, other: &Self) -> bool { + self.0.load(Relaxed) == other.0.load(Relaxed) + } +} + +impl Eq for Key {} + +impl Hash for Key { + fn hash<H: Hasher>(&self, h: &mut H) { + self.0.load(Relaxed).hash(h); + } +} + +fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> { + let _other: HashMap<Key, bool> = HashMap::new(); + m.keys().cloned().collect() +} + +fn this_is_ok(m: &mut HashMap<usize, Key>) {} + +fn main() { + let _ = should_not_take_this_arg(&mut HashMap::new(), 1); + this_is_ok(&mut HashMap::new()); +} diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr new file mode 100644 index 00000000000..ebdbfe99022 --- /dev/null +++ b/tests/ui/mut_key.stderr @@ -0,0 +1,22 @@ +error: mutable key type + --> $DIR/mut_key.rs:27:32 + | +LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::mutable_key_type)]` on by default + +error: mutable key type + --> $DIR/mut_key.rs:27:72 + | +LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> { + | ^^^^^^^^^^^^ + +error: mutable key type + --> $DIR/mut_key.rs:28:5 + | +LL | let _other: HashMap<Key, bool> = HashMap::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From f191e916bdbb98ef91a35b3c82376b3c517654fb Mon Sep 17 00:00:00 2001 From: mgr-inz-rafal <rchabowski@gmail.com> Date: Thu, 26 Dec 2019 13:34:18 +0100 Subject: Add new lint (modulo_arithmetic) --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 + clippy_lints/src/modulo_arithmetic.rs | 149 ++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +- 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/modulo_arithmetic.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f0684ea44cc..50a7f44ad8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1186,6 +1186,7 @@ Released 2018-09-13 [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl diff --git a/README.md b/README.md index be5433029de..01fc20f0f27 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 341 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 342 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c83be8e2c19..8b8f6b27a95 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -239,6 +239,7 @@ pub mod misc_early; pub mod missing_const_for_fn; pub mod missing_doc; pub mod missing_inline; +pub mod modulo_arithmetic; pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_key; @@ -667,6 +668,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &missing_const_for_fn::MISSING_CONST_FOR_FN, &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + &modulo_arithmetic::MODULO_ARITHMETIC, &mul_add::MANUAL_MUL_ADD, &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, &mut_key::MUTABLE_KEY_TYPE, @@ -943,6 +945,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_late_pass(|| box comparison_chain::ComparisonChain); store.register_late_pass(|| box mul_add::MulAddCheck); store.register_late_pass(|| box mut_key::MutableKeyType); + store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); store.register_early_pass(|| box reference::DerefAddrOf); store.register_early_pass(|| box reference::RefInDeref); store.register_early_pass(|| box double_parens::DoubleParens); @@ -1003,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&misc::FLOAT_CMP_CONST), LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), LintId::of(&panic_unimplemented::PANIC), LintId::of(&panic_unimplemented::TODO), LintId::of(&panic_unimplemented::UNIMPLEMENTED), diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs new file mode 100644 index 00000000000..308bb00fe76 --- /dev/null +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -0,0 +1,149 @@ +use crate::consts::{constant, Constant}; +use crate::utils::{sext, span_lint_and_then}; +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty::{self}; +use rustc_session::declare_tool_lint; +use std::fmt::Display; + +declare_clippy_lint! { + /// **What it does:** Checks for modulo arithemtic. + /// + /// **Why is this bad?** The results of modulo (%) operation might differ + /// depending on the language, when negative numbers are involved. + /// If you interop with different languages it might be beneficial + /// to double check all places that use modulo arithmetic. + /// + /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// let x = -17 % 3; + /// ``` + pub MODULO_ARITHMETIC, + restriction, + "any modulo arithmetic statement" +} + +declare_lint_pass!(ModuloArithmetic => [MODULO_ARITHMETIC]); + +struct OperandInfo { + string_representation: Option<String>, + is_negative: bool, + is_integral: bool, +} + +fn analyze_operand(operand: &Expr, cx: &LateContext<'_, '_>, expr: &Expr) -> Option<OperandInfo> { + match constant(cx, cx.tables, operand) { + Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind { + ty::Int(ity) => { + let value = sext(cx.tcx, v, ity); + return Some(OperandInfo { + string_representation: Some(value.to_string()), + is_negative: value < 0, + is_integral: true, + }); + }, + ty::Uint(_) => { + return Some(OperandInfo { + string_representation: None, + is_negative: false, + is_integral: true, + }); + }, + _ => {}, + }, + Some((Constant::F32(f), _)) => { + return Some(floating_point_operand_info(&f)); + }, + Some((Constant::F64(f), _)) => { + return Some(floating_point_operand_info(&f)); + }, + _ => {}, + } + None +} + +fn floating_point_operand_info<T: Display + PartialOrd + From<f32>>(f: &T) -> OperandInfo { + OperandInfo { + string_representation: Some(format!("{:.3}", *f)), + is_negative: *f < 0.0.into(), + is_integral: false, + } +} + +fn might_have_negative_value(t: &ty::TyS<'_>) -> bool { + t.is_signed() || t.is_floating_point() +} + +fn check_const_operands<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx Expr, + lhs_operand: &OperandInfo, + rhs_operand: &OperandInfo, +) { + if lhs_operand.is_negative ^ rhs_operand.is_negative { + span_lint_and_then( + cx, + MODULO_ARITHMETIC, + expr.span, + &format!( + "you are using modulo operator on constants with different signs: `{} % {}`", + lhs_operand.string_representation.as_ref().unwrap(), + rhs_operand.string_representation.as_ref().unwrap() + ), + |db| { + db.note("double check for expected result especially when interoperating with different languages"); + if lhs_operand.is_integral { + db.note("or consider using `rem_euclid` or similar function"); + } + }, + ); + } +} + +fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, operand: &Expr) { + let operand_type = cx.tables.expr_ty(operand); + if might_have_negative_value(operand_type) { + span_lint_and_then( + cx, + MODULO_ARITHMETIC, + expr.span, + "you are using modulo operator on types that might have different signs", + |db| { + db.note("double check for expected result especially when interoperating with different languages"); + if operand_type.is_integral() { + db.note("or consider using `rem_euclid` or similar function"); + } + }, + ); + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ModuloArithmetic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + match &expr.kind { + ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { + if let BinOpKind::Rem = op.node { + let lhs_operand = analyze_operand(lhs, cx, expr); + let rhs_operand = analyze_operand(rhs, cx, expr); + if_chain! { + if let Some(lhs_operand) = lhs_operand; + if let Some(rhs_operand) = rhs_operand; + then { + check_const_operands(cx, expr, &lhs_operand, &rhs_operand); + } + else { + check_non_const_operands(cx, expr, lhs); + } + } + }; + }, + _ => {}, + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index bdbe06c5f27..08cbff40444 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 341] = [ +pub const ALL_LINTS: [Lint; 342] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1183,6 +1183,13 @@ pub const ALL_LINTS: [Lint; 341] = [ deprecation: None, module: "enum_variants", }, + Lint { + name: "modulo_arithmetic", + group: "restriction", + desc: "any modulo arithmetic statement", + deprecation: None, + module: "modulo_arithmetic", + }, Lint { name: "modulo_one", group: "correctness", -- cgit 1.4.1-3-g733a5 From 8db319f9578aa4cc5647a187f92aa00a6f4ad335 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 7 Dec 2019 19:10:06 -0800 Subject: Use `mem::take` instead of `mem::replace` when applicable `std::mem::take` can be used to replace a value of type `T` with `T::default()` instead of `std::mem::replace`. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/mem_replace.rs | 186 ++++++++++++++++++++++++++-------------- src/lintlist/mod.rs | 7 ++ tests/ui/mem_replace.fixed | 21 ++++- tests/ui/mem_replace.rs | 21 ++++- tests/ui/mem_replace.stderr | 20 ++++- 7 files changed, 189 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a7f44ad8e..05d437d3598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1173,6 +1173,7 @@ Released 2018-09-13 [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default [`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit [`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 49101695a58..abcddc88527 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -599,6 +599,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, &mem_forget::MEM_FORGET, &mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + &mem_replace::MEM_REPLACE_WITH_DEFAULT, &mem_replace::MEM_REPLACE_WITH_UNINIT, &methods::CHARS_LAST_CMP, &methods::CHARS_NEXT_CMP, @@ -1594,6 +1595,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutex_atomic::MUTEX_INTEGER), diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index b7b0538cbae..5ad41a53b89 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -3,7 +3,7 @@ use crate::utils::{ }; use if_chain::if_chain; use rustc::declare_lint_pass; -use rustc::hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; +use rustc::hir::{BorrowKind, Expr, ExprKind, HirVec, Mutability, QPath}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc_errors::Applicability; use rustc_session::declare_tool_lint; @@ -67,8 +67,127 @@ declare_clippy_lint! { "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`" } +declare_clippy_lint! { + /// **What it does:** Checks for `std::mem::replace` on a value of type + /// `T` with `T::default()`. + /// + /// **Why is this bad?** `std::mem` module already has the method `take` to + /// take the current value and replace it with the default value of that type. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// let mut text = String::from("foo"); + /// let replaced = std::mem::replace(&mut text, String::default()); + /// ``` + /// Is better expressed with: + /// ```rust + /// let mut text = String::from("foo"); + /// let taken = std::mem::take(&mut text); + /// ``` + pub MEM_REPLACE_WITH_DEFAULT, + nursery, + "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" +} + declare_lint_pass!(MemReplace => - [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT]); + [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); + +fn check_replace_option_with_none(cx: &LateContext<'_, '_>, expr: &'_ Expr, args: &HirVec<Expr>) { + if let ExprKind::Path(ref replacement_qpath) = args[1].kind { + // Check that second argument is `Option::None` + if match_qpath(replacement_qpath, &paths::OPTION_NONE) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // replacee's path. + let replaced_path = match args[0].kind { + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref replaced) => { + if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.kind { + replaced_path + } else { + return; + } + }, + ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path, + _ => return, + }; + + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr.span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) + ), + applicability, + ); + } + } +} + +fn check_replace_with_uninit(cx: &LateContext<'_, '_>, expr: &'_ Expr, args: &HirVec<Expr>) { + if let ExprKind::Call(ref repl_func, ref repl_args) = args[1].kind { + if_chain! { + if repl_args.is_empty(); + if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; + if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + then { + if match_def_path(cx, repl_def_id, &paths::MEM_UNINITIALIZED) { + span_help_and_lint( + cx, + MEM_REPLACE_WITH_UNINIT, + expr.span, + "replacing with `mem::uninitialized()`", + "consider using the `take_mut` crate instead", + ); + } else if match_def_path(cx, repl_def_id, &paths::MEM_ZEROED) && + !cx.tables.expr_ty(&args[1]).is_primitive() { + span_help_and_lint( + cx, + MEM_REPLACE_WITH_UNINIT, + expr.span, + "replacing with `mem::zeroed()`", + "consider using a default value or the `take_mut` crate instead", + ); + } + } + } + } +} + +fn check_replace_with_default(cx: &LateContext<'_, '_>, expr: &'_ Expr, args: &HirVec<Expr>) { + if let ExprKind::Call(ref repl_func, ref repl_args) = args[1].kind { + if_chain! { + if repl_args.is_empty(); + if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; + if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); + if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD); + then { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( + cx, + MEM_REPLACE_WITH_DEFAULT, + expr.span, + "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`", + "consider using", + format!( + "std::mem::take({})", + snippet_with_applicability(cx, args[0].span, "", &mut applicability) + ), + applicability, + ); + } + } + } +} impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { @@ -80,67 +199,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::MEM_REPLACE); - // Check that second argument is `Option::None` then { - if let ExprKind::Path(ref replacement_qpath) = func_args[1].kind { - if match_qpath(replacement_qpath, &paths::OPTION_NONE) { - - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match func_args[0].kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref replaced) => { - if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.kind { - replaced_path - } else { - return - } - }, - ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path, - _ => return, - }; - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr.span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)), - applicability, - ); - } - } - if let ExprKind::Call(ref repl_func, ref repl_args) = func_args[1].kind { - if_chain! { - if repl_args.is_empty(); - if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; - if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - then { - if match_def_path(cx, repl_def_id, &paths::MEM_UNINITIALIZED) { - span_help_and_lint( - cx, - MEM_REPLACE_WITH_UNINIT, - expr.span, - "replacing with `mem::uninitialized()`", - "consider using the `take_mut` crate instead", - ); - } else if match_def_path(cx, repl_def_id, &paths::MEM_ZEROED) && - !cx.tables.expr_ty(&func_args[1]).is_primitive() { - span_help_and_lint( - cx, - MEM_REPLACE_WITH_UNINIT, - expr.span, - "replacing with `mem::zeroed()`", - "consider using a default value or the `take_mut` crate instead", - ); - } - } - } - } + check_replace_option_with_none(cx, expr, &func_args); + check_replace_with_uninit(cx, expr, &func_args); + check_replace_with_default(cx, expr, &func_args); } } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 08cbff40444..4b820250c8d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1099,6 +1099,13 @@ pub const ALL_LINTS: [Lint; 342] = [ deprecation: None, module: "mem_replace", }, + Lint { + name: "mem_replace_with_default", + group: "nursery", + desc: "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`", + deprecation: None, + module: "mem_replace", + }, Lint { name: "mem_replace_with_uninit", group: "correctness", diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 4e47ac95d82..19205dc3822 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -9,13 +9,30 @@ // run-rustfix #![allow(unused_imports)] -#![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] use std::mem; -fn main() { +fn replace_option_with_none() { let mut an_option = Some(1); let _ = an_option.take(); let an_option = &mut Some(1); let _ = an_option.take(); } + +fn replace_with_default() { + let mut s = String::from("foo"); + let _ = std::mem::take(&mut s); + let s = &mut String::from("foo"); + let _ = std::mem::take(s); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); +} diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index 6824ab18e7f..97ac283abc6 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -9,13 +9,30 @@ // run-rustfix #![allow(unused_imports)] -#![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)] +#![warn( + clippy::all, + clippy::style, + clippy::mem_replace_option_with_none, + clippy::mem_replace_with_default +)] use std::mem; -fn main() { +fn replace_option_with_none() { let mut an_option = Some(1); let _ = mem::replace(&mut an_option, None); let an_option = &mut Some(1); let _ = mem::replace(an_option, None); } + +fn replace_with_default() { + let mut s = String::from("foo"); + let _ = std::mem::replace(&mut s, String::default()); + let s = &mut String::from("foo"); + let _ = std::mem::replace(s, String::default()); +} + +fn main() { + replace_option_with_none(); + replace_with_default(); +} diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr index 791c4d71dbf..44495a973c8 100644 --- a/tests/ui/mem_replace.stderr +++ b/tests/ui/mem_replace.stderr @@ -1,5 +1,5 @@ error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:18:13 + --> $DIR/mem_replace.rs:23:13 | LL | let _ = mem::replace(&mut an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` @@ -7,10 +7,24 @@ LL | let _ = mem::replace(&mut an_option, None); = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings` error: replacing an `Option` with `None` - --> $DIR/mem_replace.rs:20:13 + --> $DIR/mem_replace.rs:25:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` -error: aborting due to 2 previous errors +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:30:13 + | +LL | let _ = std::mem::replace(&mut s, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` + | + = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:32:13 + | +LL | let _ = std::mem::replace(s, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` + +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 78b4dfc57cffd96c5f48b0bc0b350066ab1d0ceb Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Wed, 18 Dec 2019 22:15:55 -0800 Subject: Move `mem_replace_with_default` out of nursery --- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/mem_replace.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index abcddc88527..3aace11716e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1183,6 +1183,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), @@ -1370,6 +1371,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), @@ -1595,7 +1597,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutex_atomic::MUTEX_INTEGER), diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index ab0bdb4d02c..3405ccf0631 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -87,7 +87,7 @@ declare_clippy_lint! { /// let taken = std::mem::take(&mut text); /// ``` pub MEM_REPLACE_WITH_DEFAULT, - nursery, + style, "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 4b820250c8d..c396c3ab8a8 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1101,7 +1101,7 @@ pub const ALL_LINTS: [Lint; 342] = [ }, Lint { name: "mem_replace_with_default", - group: "nursery", + group: "style", desc: "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`", deprecation: None, module: "mem_replace", -- cgit 1.4.1-3-g733a5 From 42e4595d3ab7844d840ab4ef3fa8eb80116484f6 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 28 Dec 2019 21:52:08 -0800 Subject: Indicate anonymous lifetimes for types --- README.md | 2 +- clippy_lints/src/mem_replace.rs | 6 +++--- src/lintlist/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 01fc20f0f27..215ad6f5630 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 342 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 343 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 17a088e09a0..5a1e3b73ded 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -96,7 +96,7 @@ declare_clippy_lint! { declare_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); -fn check_replace_option_with_none(cx: &LateContext<'_, '_>, src: &Expr, dest: &Expr, expr_span: Span) { +fn check_replace_option_with_none(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let ExprKind::Path(ref replacement_qpath) = src.kind { // Check that second argument is `Option::None` if match_qpath(replacement_qpath, &paths::OPTION_NONE) { @@ -134,7 +134,7 @@ fn check_replace_option_with_none(cx: &LateContext<'_, '_>, src: &Expr, dest: &E } } -fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr, expr_span: Span) { +fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span: Span) { if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind { if_chain! { if repl_args.is_empty(); @@ -164,7 +164,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr, expr_span: Sp } } -fn check_replace_with_default(cx: &LateContext<'_, '_>, src: &Expr, dest: &Expr, expr_span: Span) { +fn check_replace_with_default(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let ExprKind::Call(ref repl_func, _) = src.kind { if_chain! { if !in_external_macro(cx.tcx.sess, expr_span); diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c396c3ab8a8..cd3336bdb37 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 342] = [ +pub const ALL_LINTS: [Lint; 343] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", -- cgit 1.4.1-3-g733a5 From ab5ff0352e9c6d9a46b5557f68abba9c004e8b93 Mon Sep 17 00:00:00 2001 From: Brad Sherman <bsherman1096@gmail.com> Date: Sat, 28 Dec 2019 15:37:23 -0700 Subject: Add lint for iter.nth(0) - Encourage iter.next() rather than iter.nth(0), which is less readable --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/mod.rs | 59 ++++++++++++++++++++++++++++++++++++++--- src/lintlist/mod.rs | 9 ++++++- tests/ui/iter_nth_zero.fixed | 31 ++++++++++++++++++++++ tests/ui/iter_nth_zero.rs | 31 ++++++++++++++++++++++ tests/ui/iter_nth_zero.stderr | 22 +++++++++++++++ 8 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 tests/ui/iter_nth_zero.fixed create mode 100644 tests/ui/iter_nth_zero.rs create mode 100644 tests/ui/iter_nth_zero.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 05d437d3598..874cb056bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1141,6 +1141,7 @@ Released 2018-09-13 [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits diff --git a/README.md b/README.md index 215ad6f5630..3b4e22c3a39 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 343 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 344 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3aace11716e..4a0976fe800 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -618,6 +618,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, &methods::ITER_NTH, + &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, &methods::MANUAL_SATURATING_ARITHMETIC, &methods::MAP_FLATTEN, @@ -1197,6 +1198,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NTH), + LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(&methods::NEW_RET_NO_SELF), @@ -1375,6 +1377,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(&methods::NEW_RET_NO_SELF), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d0021d12967..27a8b61fdba 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -20,6 +20,7 @@ use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol, SymbolStr}; use syntax::ast; +use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, @@ -756,6 +757,33 @@ declare_clippy_lint! { "using `Iterator::step_by(0)`, which will panic at runtime" } +declare_clippy_lint! { + /// **What it does:** Checks for the use of `iter.nth(0)`. + /// + /// **Why is this bad?** `iter.nth(0)` is unnecessary, and `iter.next()` + /// is more readable. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # use std::collections::HashSet; + /// // Bad + /// # let mut s = HashSet::new(); + /// # s.insert(1); + /// let x = s.iter().nth(0); + /// + /// // Good + /// # let mut s = HashSet::new(); + /// # s.insert(1); + /// let x = s.iter().next(); + /// ``` + pub ITER_NTH_ZERO, + style, + "replace `iter.nth(0)` with `iter.next()`" +} + declare_clippy_lint! { /// **What it does:** Checks for use of `.iter().nth()` (and the related /// `.iter_mut().nth()`) on standard library types with O(1) element access. @@ -1136,6 +1164,7 @@ declare_lint_pass!(Methods => [ MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, ITER_NTH, + ITER_NTH_ZERO, ITER_SKIP_NEXT, GET_UNWRAP, STRING_EXTEND_CHARS, @@ -1191,8 +1220,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["as_ptr", "unwrap"] | ["as_ptr", "expect"] => { lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]) }, - ["nth", "iter"] => lint_iter_nth(cx, expr, arg_lists[1], false), - ["nth", "iter_mut"] => lint_iter_nth(cx, expr, arg_lists[1], true), + ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), + ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), + ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr), ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]), @@ -1983,7 +2013,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, fold_ar fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) { if match_trait_method(cx, expr, &paths::ITERATOR) { - use crate::consts::{constant, Constant}; if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) { span_lint( cx, @@ -1998,9 +2027,10 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args fn lint_iter_nth<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, - iter_args: &'tcx [hir::Expr<'_>], + nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]], is_mut: bool, ) { + let iter_args = nth_and_iter_args[1]; let mut_str = if is_mut { "_mut" } else { "" }; let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() { "slice" @@ -2009,6 +2039,8 @@ fn lint_iter_nth<'a, 'tcx>( } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC_DEQUE) { "VecDeque" } else { + let nth_args = nth_and_iter_args[0]; + lint_iter_nth_zero(cx, expr, &nth_args); return; // caller is not a type that we want to lint }; @@ -2023,6 +2055,25 @@ fn lint_iter_nth<'a, 'tcx>( ); } +fn lint_iter_nth_zero<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) { + if_chain! { + if match_trait_method(cx, expr, &paths::ITERATOR); + if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &nth_args[1]); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NTH_ZERO, + expr.span, + "called `.nth(0)` on a `std::iter::Iterator`", + "try calling", + format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)), + applicability, + ); + } + } +} + fn lint_get_unwrap<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index cd3336bdb37..5bc49f7b600 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 343] = [ +pub const ALL_LINTS: [Lint; 344] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -875,6 +875,13 @@ pub const ALL_LINTS: [Lint; 343] = [ deprecation: None, module: "methods", }, + Lint { + name: "iter_nth_zero", + group: "style", + desc: "replace `iter.nth(0)` with `iter.next()`", + deprecation: None, + module: "methods", + }, Lint { name: "iter_skip_next", group: "style", diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed new file mode 100644 index 00000000000..b54147c94d1 --- /dev/null +++ b/tests/ui/iter_nth_zero.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::iter_nth_zero)] +use std::collections::HashSet; + +struct Foo {} + +impl Foo { + fn nth(&self, index: usize) -> usize { + index + 1 + } +} + +fn main() { + let f = Foo {}; + f.nth(0); // lint does not apply here + + let mut s = HashSet::new(); + s.insert(1); + let _x = s.iter().next(); + + let mut s2 = HashSet::new(); + s2.insert(2); + let mut iter = s2.iter(); + let _y = iter.next(); + + let mut s3 = HashSet::new(); + s3.insert(3); + let mut iter2 = s3.iter(); + let _unwrapped = iter2.next().unwrap(); +} diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs new file mode 100644 index 00000000000..b92c7d18adb --- /dev/null +++ b/tests/ui/iter_nth_zero.rs @@ -0,0 +1,31 @@ +// run-rustfix + +#![warn(clippy::iter_nth_zero)] +use std::collections::HashSet; + +struct Foo {} + +impl Foo { + fn nth(&self, index: usize) -> usize { + index + 1 + } +} + +fn main() { + let f = Foo {}; + f.nth(0); // lint does not apply here + + let mut s = HashSet::new(); + s.insert(1); + let _x = s.iter().nth(0); + + let mut s2 = HashSet::new(); + s2.insert(2); + let mut iter = s2.iter(); + let _y = iter.nth(0); + + let mut s3 = HashSet::new(); + s3.insert(3); + let mut iter2 = s3.iter(); + let _unwrapped = iter2.nth(0).unwrap(); +} diff --git a/tests/ui/iter_nth_zero.stderr b/tests/ui/iter_nth_zero.stderr new file mode 100644 index 00000000000..2b20a4ceb4a --- /dev/null +++ b/tests/ui/iter_nth_zero.stderr @@ -0,0 +1,22 @@ +error: called `.nth(0)` on a `std::iter::Iterator` + --> $DIR/iter_nth_zero.rs:20:14 + | +LL | let _x = s.iter().nth(0); + | ^^^^^^^^^^^^^^^ help: try calling: `s.iter().next()` + | + = note: `-D clippy::iter-nth-zero` implied by `-D warnings` + +error: called `.nth(0)` on a `std::iter::Iterator` + --> $DIR/iter_nth_zero.rs:25:14 + | +LL | let _y = iter.nth(0); + | ^^^^^^^^^^^ help: try calling: `iter.next()` + +error: called `.nth(0)` on a `std::iter::Iterator` + --> $DIR/iter_nth_zero.rs:30:22 + | +LL | let _unwrapped = iter2.nth(0).unwrap(); + | ^^^^^^^^^^^^ help: try calling: `iter2.next()` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 9e6a6069a7918a48340a7e30cb7d6794d2804e46 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Sun, 5 Jan 2020 16:16:27 -0800 Subject: Add lint to detect usage of invalid atomic ordering Detect usage of invalid atomic ordering modes such as `Ordering::{Release, AcqRel}` in atomic loads and `Ordering::{Acquire, AcqRel}` in atomic stores. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/atomic_ordering.rs | 102 ++++++++++ clippy_lints/src/lib.rs | 5 + src/lintlist/mod.rs | 9 +- tests/ui/atomic_ordering.rs | 196 ++++++++++++++++++ tests/ui/atomic_ordering.stderr | 387 ++++++++++++++++++++++++++++++++++++ 7 files changed, 700 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/atomic_ordering.rs create mode 100644 tests/ui/atomic_ordering.rs create mode 100644 tests/ui/atomic_ordering.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 874cb056bc9..f60ac7d5267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1134,6 +1134,7 @@ Released 2018-09-13 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref +[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons diff --git a/README.md b/README.md index 3b4e22c3a39..c46d3e16bb1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 344 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 345 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs new file mode 100644 index 00000000000..3e7cd967f06 --- /dev/null +++ b/clippy_lints/src/atomic_ordering.rs @@ -0,0 +1,102 @@ +use crate::utils::{match_def_path, span_help_and_lint}; +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::def_id::DefId; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty; +use rustc_session::declare_tool_lint; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of invalid atomic + /// ordering in Atomic*::{load, store} calls. + /// + /// **Why is this bad?** Using an invalid atomic ordering + /// will cause a panic at run-time. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// # use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let x = AtomicBool::new(true); + /// + /// let _ = x.load(Ordering::Release); + /// let _ = x.load(Ordering::AcqRel); + /// + /// x.store(false, Ordering::Acquire); + /// x.store(false, Ordering::AcqRel); + /// ``` + pub INVALID_ATOMIC_ORDERING, + correctness, + "lint usage of invalid atomic ordering in atomic load/store calls" +} + +declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]); + +const ATOMIC_TYPES: [&str; 12] = [ + "AtomicBool", + "AtomicI8", + "AtomicI16", + "AtomicI32", + "AtomicI64", + "AtomicIsize", + "AtomicPtr", + "AtomicU8", + "AtomicU16", + "AtomicU32", + "AtomicU64", + "AtomicUsize", +]; + +fn type_is_atomic(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables.expr_ty(expr).kind { + ATOMIC_TYPES + .iter() + .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty])) + } else { + false + } +} + +fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&str]) -> bool { + orderings + .iter() + .any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering])) +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind; + let method = method_path.ident.name.as_str(); + if type_is_atomic(cx, &args[0]); + if method == "load" || method == "store"; + let ordering_arg = if method == "load" { &args[1] } else { &args[2] }; + if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind; + if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id(); + then { + if method == "load" && + match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) { + span_help_and_lint( + cx, + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + "atomic loads cannot have `Release` and `AcqRel` ordering", + "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`" + ); + } else if method == "store" && + match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) { + span_help_and_lint( + cx, + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + "atomic stores cannot have `Acquire` and `AcqRel` ordering", + "consider using ordering modes `Release`, `SeqCst` or `Relaxed`" + ); + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5b68ecf562b..6846730a415 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -165,6 +165,7 @@ pub mod arithmetic; pub mod as_conversions; pub mod assertions_on_constants; pub mod assign_ops; +pub mod atomic_ordering; pub mod attrs; pub mod bit_mask; pub mod blacklisted_name; @@ -466,6 +467,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, + &atomic_ordering::INVALID_ATOMIC_ORDERING, &attrs::DEPRECATED_CFG_ATTR, &attrs::DEPRECATED_SEMVER, &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, @@ -984,6 +986,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); + store.register_late_pass(|| box atomic_ordering::AtomicOrdering); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1089,6 +1092,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_CFG_ATTR), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), @@ -1509,6 +1513,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::USELESS_ATTRIBUTE), LintId::of(&bit_mask::BAD_BIT_MASK), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5bc49f7b600..a69d090ca37 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 344] = [ +pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -833,6 +833,13 @@ pub const ALL_LINTS: [Lint; 344] = [ deprecation: None, module: "methods", }, + Lint { + name: "invalid_atomic_ordering", + group: "correctness", + desc: "lint usage of invalid atomic ordering in atomic load/store calls", + deprecation: None, + module: "atomic_ordering", + }, Lint { name: "invalid_regex", group: "correctness", diff --git a/tests/ui/atomic_ordering.rs b/tests/ui/atomic_ordering.rs new file mode 100644 index 00000000000..2c354b5ef6e --- /dev/null +++ b/tests/ui/atomic_ordering.rs @@ -0,0 +1,196 @@ +#![warn(clippy::invalid_atomic_ordering)] + +use std::sync::atomic::{ + AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32, AtomicU64, + AtomicU8, AtomicUsize, Ordering, +}; + +fn main() { + // `AtomicBool` test cases + let x = AtomicBool::new(true); + + // Allowed load ordering modes + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + + // Disallowed load ordering modes + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + // Allowed store ordering modes + x.store(false, Ordering::Release); + x.store(false, Ordering::SeqCst); + x.store(false, Ordering::Relaxed); + + // Disallowed store ordering modes + x.store(false, Ordering::Acquire); + x.store(false, Ordering::AcqRel); + + // `AtomicI8` test cases + let x = AtomicI8::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicI16` test cases + let x = AtomicI16::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicI32` test cases + let x = AtomicI32::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicI64` test cases + let x = AtomicI64::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicIsize` test cases + let x = AtomicIsize::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicPtr` test cases + let ptr = &mut 5; + let other_ptr = &mut 10; + let x = AtomicPtr::new(ptr); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(other_ptr, Ordering::Release); + x.store(other_ptr, Ordering::SeqCst); + x.store(other_ptr, Ordering::Relaxed); + x.store(other_ptr, Ordering::Acquire); + x.store(other_ptr, Ordering::AcqRel); + + // `AtomicU8` test cases + let x = AtomicU8::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicU16` test cases + let x = AtomicU16::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicU32` test cases + let x = AtomicU32::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicU64` test cases + let x = AtomicU64::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); + + // `AtomicUsize` test cases + let x = AtomicUsize::new(0); + + let _ = x.load(Ordering::Acquire); + let _ = x.load(Ordering::SeqCst); + let _ = x.load(Ordering::Relaxed); + let _ = x.load(Ordering::Release); + let _ = x.load(Ordering::AcqRel); + + x.store(1, Ordering::Release); + x.store(1, Ordering::SeqCst); + x.store(1, Ordering::Relaxed); + x.store(1, Ordering::Acquire); + x.store(1, Ordering::AcqRel); +} diff --git a/tests/ui/atomic_ordering.stderr b/tests/ui/atomic_ordering.stderr new file mode 100644 index 00000000000..7485eef39fe --- /dev/null +++ b/tests/ui/atomic_ordering.stderr @@ -0,0 +1,387 @@ +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:18:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings` + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:19:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:27:20 + | +LL | x.store(false, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:28:20 + | +LL | x.store(false, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:36:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:37:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:42:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:43:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:51:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:52:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:57:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:58:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:66:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:67:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:72:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:73:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:81:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:82:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:87:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:88:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:96:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:97:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:102:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:103:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:113:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:114:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:119:24 + | +LL | x.store(other_ptr, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:120:24 + | +LL | x.store(other_ptr, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:128:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:129:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:134:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:135:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:143:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:144:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:149:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:150:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:158:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:159:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:164:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:165:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:173:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:174:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:179:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:180:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:188:20 + | +LL | let _ = x.load(Ordering::Release); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic loads cannot have `Release` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:189:20 + | +LL | let _ = x.load(Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:194:16 + | +LL | x.store(1, Ordering::Acquire); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: atomic stores cannot have `Acquire` and `AcqRel` ordering + --> $DIR/atomic_ordering.rs:195:16 + | +LL | x.store(1, Ordering::AcqRel); + | ^^^^^^^^^^^^^^^^ + | + = help: consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +error: aborting due to 48 previous errors + -- cgit 1.4.1-3-g733a5 From fe21ef4e8bf299c2bebc2d8ec7454ca13ba24f9f Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Mon, 6 Jan 2020 17:33:28 -0800 Subject: Prevent doc-tests from running and fix lint description --- clippy_lints/src/atomic_ordering.rs | 8 ++++---- src/lintlist/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 3e7cd967f06..fe06c63a553 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -1,10 +1,10 @@ use crate::utils::{match_def_path, span_help_and_lint}; use if_chain::if_chain; use rustc::declare_lint_pass; -use rustc::hir::def_id::DefId; -use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::ty; +use rustc_hir::def_id::DefId; +use rustc_hir::*; use rustc_session::declare_tool_lint; declare_clippy_lint! { @@ -17,7 +17,7 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore + /// ```rust,no_run /// # use std::sync::atomic::{AtomicBool, Ordering}; /// /// let x = AtomicBool::new(true); @@ -30,7 +30,7 @@ declare_clippy_lint! { /// ``` pub INVALID_ATOMIC_ORDERING, correctness, - "lint usage of invalid atomic ordering in atomic load/store calls" + "usage of invalid atomic ordering in atomic load/store calls" } declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]); diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a69d090ca37..e079fead572 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -836,7 +836,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "invalid_atomic_ordering", group: "correctness", - desc: "lint usage of invalid atomic ordering in atomic load/store calls", + desc: "usage of invalid atomic ordering in atomic load/store calls", deprecation: None, module: "atomic_ordering", }, -- cgit 1.4.1-3-g733a5 From cd201f526f797796c738b93241fd0c70df881f9c Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Mon, 6 Jan 2020 16:41:15 +0900 Subject: Update lintlist --- src/lintlist/mod.rs | 64 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e079fead572..af89a473b6a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -87,7 +87,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "borrow_interior_mutable_const", group: "correctness", - desc: "referencing const with interior mutability", + desc: "referencing `const` with interior mutability", deprecation: None, module: "non_copy_const", }, @@ -178,7 +178,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "char_lit_as_u8", group: "complexity", - desc: "casting a character literal to u8 truncates", + desc: "casting a character literal to `u8` truncates", deprecation: None, module: "types", }, @@ -227,7 +227,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "cmp_nan", group: "correctness", - desc: "comparisons to NAN, which will always return false, probably not intended", + desc: "comparisons to `NAN`, which will always return false, probably not intended", deprecation: None, module: "misc", }, @@ -304,14 +304,14 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "declare_interior_mutable_const", group: "correctness", - desc: "declaring const with interior mutability", + desc: "declaring `const` with interior mutability", deprecation: None, module: "non_copy_const", }, Lint { name: "default_trait_access", group: "pedantic", - desc: "checks for literal calls to Default::default()", + desc: "checks for literal calls to `Default::default()`", deprecation: None, module: "default_trait_access", }, @@ -423,7 +423,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "else_if_without_else", group: "restriction", - desc: "if expression with an `else if`, but without a final `else` branch", + desc: "`if` expression with an `else if`, but without a final `else` branch", deprecation: None, module: "else_if_without_else", }, @@ -710,14 +710,14 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "if_same_then_else", group: "correctness", - desc: "if with the same *then* and *else* blocks", + desc: "`if` with the same `then` and `else` blocks", deprecation: None, module: "copies", }, Lint { name: "ifs_same_cond", group: "correctness", - desc: "consecutive `ifs` with the same condition", + desc: "consecutive `if`s with the same condition", deprecation: None, module: "copies", }, @@ -766,7 +766,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "infallible_destructuring_match", group: "style", - desc: "a match statement with a single infallible arm instead of a `let`", + desc: "a `match` statement with a single infallible arm instead of a `let`", deprecation: None, module: "infallible_destructuring_match", }, @@ -787,7 +787,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "inherent_to_string_shadow_display", group: "correctness", - desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait ", + desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait", deprecation: None, module: "inherent_to_string", }, @@ -808,7 +808,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "int_plus_one", group: "complexity", - desc: "instead of using x >= y + 1, use x > y", + desc: "instead of using `x >= y + 1`, use `x > y`", deprecation: None, module: "int_plus_one", }, @@ -955,21 +955,21 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "let_underscore_must_use", group: "restriction", - desc: "non-binding let on a #[must_use] expression", + desc: "non-binding let on a `#[must_use]` expression", deprecation: None, module: "let_underscore", }, Lint { name: "let_unit_value", group: "style", - desc: "creating a let binding to a value of unit type, which usually can\'t be used afterwards", + desc: "creating a `let` binding to a value of unit type, which usually can\'t be used afterwards", deprecation: None, module: "types", }, Lint { name: "linkedlist", group: "pedantic", - desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque", + desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`", deprecation: None, module: "types", }, @@ -1046,28 +1046,28 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "match_as_ref", group: "complexity", - desc: "a match on an Option value instead of using `as_ref()` or `as_mut`", + desc: "a `match` on an Option value instead of using `as_ref()` or `as_mut`", deprecation: None, module: "matches", }, Lint { name: "match_bool", group: "style", - desc: "a match on a boolean expression instead of an `if..else` block", + desc: "a `match` on a boolean expression instead of an `if..else` block", deprecation: None, module: "matches", }, Lint { name: "match_overlapping_arm", group: "style", - desc: "a match with overlapping arms", + desc: "a `match` with overlapping arms", deprecation: None, module: "matches", }, Lint { name: "match_ref_pats", group: "style", - desc: "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", + desc: "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", deprecation: None, module: "matches", }, @@ -1081,7 +1081,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "match_wild_err_arm", group: "style", - desc: "a match with `Err(_)` arm and take drastic actions", + desc: "a `match` with `Err(_)` arm and take drastic actions", deprecation: None, module: "matches", }, @@ -1095,7 +1095,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "mem_discriminant_non_enum", group: "correctness", - desc: "calling mem::descriminant on non-enum type", + desc: "calling `mem::descriminant` on non-enum type", deprecation: None, module: "mem_discriminant", }, @@ -1165,7 +1165,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "missing_inline_in_public_items", group: "restriction", - desc: "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)", + desc: "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)", deprecation: None, module: "missing_inline", }, @@ -1270,7 +1270,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "mutable_key_type", group: "correctness", - desc: "Check for mutable Map/Set key type", + desc: "Check for mutable `Map`/`Set` key type", deprecation: None, module: "mut_key", }, @@ -1382,7 +1382,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "neg_multiply", group: "style", - desc: "multiplying integers with -1", + desc: "multiplying integers with `-1`", deprecation: None, module: "neg_multiply", }, @@ -1480,7 +1480,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "option_map_unit_fn", group: "complexity", - desc: "using `option.map(f)`, where f is a function or closure that returns ()", + desc: "using `option.map(f)`, where `f` is a function or closure that returns `()`", deprecation: None, module: "map_unit_fn", }, @@ -1550,7 +1550,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "panicking_unwrap", group: "correctness", - desc: "checks for calls of unwrap[_err]() that will always fail", + desc: "checks for calls of `unwrap[_err]()` that will always fail", deprecation: None, module: "unwrap", }, @@ -1746,7 +1746,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "result_map_unit_fn", group: "complexity", - desc: "using `result.map(f)`, where f is a function or closure that returns ()", + desc: "using `result.map(f)`, where `f` is a function or closure that returns `()`", deprecation: None, module: "map_unit_fn", }, @@ -1774,7 +1774,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "same_functions_in_if_condition", group: "pedantic", - desc: "consecutive `ifs` with the same function call", + desc: "consecutive `if`s with the same function call", deprecation: None, module: "copies", }, @@ -1844,14 +1844,14 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "single_match", group: "style", - desc: "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", + desc: "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", deprecation: None, module: "matches", }, Lint { name: "single_match_else", group: "pedantic", - desc: "a match statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", + desc: "a `match` statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", deprecation: None, module: "matches", }, @@ -2159,7 +2159,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "unnecessary_unwrap", group: "complexity", - desc: "checks for calls of unwrap[_err]() that cannot fail", + desc: "checks for calls of `unwrap[_err]()` that cannot fail", deprecation: None, module: "unwrap", }, @@ -2390,7 +2390,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "zero_divided_by_zero", group: "complexity", - desc: "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN", + desc: "usage of `0.0 / 0.0` to obtain NaN instead of `std::f32::NAN` or `std::f64::NAN`", deprecation: None, module: "zero_div_zero", }, @@ -2404,7 +2404,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "zero_ptr", group: "style", - desc: "using 0 as *{const, mut} T", + desc: "using `0 as *{const, mut} T`", deprecation: None, module: "misc", }, -- cgit 1.4.1-3-g733a5 From f7a93f029ce721fc2d74d8ba12942d9cdfbb6c14 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Tue, 7 Jan 2020 00:44:52 +0900 Subject: Apply suggestion from code review --- clippy_lints/src/attrs.rs | 4 ++-- clippy_lints/src/missing_const_for_fn.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/cfg_attr_rustfmt.stderr | 4 ++-- tests/ui/missing_const_for_fn/could_be_const.stderr | 16 ++++++++-------- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2939a71a511..c57061c0bfa 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -187,7 +187,7 @@ declare_clippy_lint! { /// ``` pub DEPRECATED_CFG_ATTR, complexity, - "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`" + "usage of `cfg_attr(rustfmt)` instead of tool attributes" } declare_lint_pass!(Attributes => [ @@ -520,7 +520,7 @@ impl EarlyLintPass for DeprecatedCfgAttribute { cx, DEPRECATED_CFG_ATTR, attr.span, - "`cfg_attr` is deprecated for rustfmt and got replaced by `tool_attributes`", + "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", "use", "#[rustfmt::skip]".to_string(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index cdd9e5a90a8..eb2a3220a04 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { cx.tcx.sess.span_err(span, &err); } } else { - span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const_fn`"); + span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); } } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index af89a473b6a..1086f5e48f9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -318,7 +318,7 @@ pub const ALL_LINTS: [Lint; 345] = [ Lint { name: "deprecated_cfg_attr", group: "complexity", - desc: "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`", + desc: "usage of `cfg_attr(rustfmt)` instead of tool attributes", deprecation: None, module: "attrs", }, diff --git a/tests/ui/cfg_attr_rustfmt.stderr b/tests/ui/cfg_attr_rustfmt.stderr index 74f27456d79..c1efd47db90 100644 --- a/tests/ui/cfg_attr_rustfmt.stderr +++ b/tests/ui/cfg_attr_rustfmt.stderr @@ -1,4 +1,4 @@ -error: `cfg_attr` is deprecated for rustfmt and got replaced by `tool_attributes` +error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes --> $DIR/cfg_attr_rustfmt.rs:18:5 | LL | #[cfg_attr(rustfmt, rustfmt::skip)] @@ -6,7 +6,7 @@ LL | #[cfg_attr(rustfmt, rustfmt::skip)] | = note: `-D clippy::deprecated-cfg-attr` implied by `-D warnings` -error: `cfg_attr` is deprecated for rustfmt and got replaced by `tool_attributes` +error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes --> $DIR/cfg_attr_rustfmt.rs:22:1 | LL | #[cfg_attr(rustfmt, rustfmt_skip)] diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index c060a9a983e..7d3dca1800b 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -1,4 +1,4 @@ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:12:5 | LL | / pub fn new() -> Self { @@ -8,7 +8,7 @@ LL | | } | = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:18:1 | LL | / fn one() -> i32 { @@ -16,7 +16,7 @@ LL | | 1 LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:23:1 | LL | / fn two() -> i32 { @@ -25,7 +25,7 @@ LL | | abc LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:30:1 | LL | / fn string() -> String { @@ -33,7 +33,7 @@ LL | | String::new() LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:35:1 | LL | / unsafe fn four() -> i32 { @@ -41,7 +41,7 @@ LL | | 4 LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:40:1 | LL | / fn generic<T>(t: T) -> T { @@ -49,7 +49,7 @@ LL | | t LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:44:1 | LL | / fn sub(x: u32) -> usize { @@ -57,7 +57,7 @@ LL | | unsafe { transmute(&x) } LL | | } | |_^ -error: this could be a `const_fn` +error: this could be a `const fn` --> $DIR/could_be_const.rs:63:9 | LL | / pub fn b(self, a: &A) -> B { -- cgit 1.4.1-3-g733a5 From 96c41988323cd4c3d211e494fd3e143caf11f8cd Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Tue, 24 Dec 2019 16:42:09 +0100 Subject: New lint: pats_with_wild_match_arm - Wildcard use with other pattern in same match arm --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 ++ clippy_lints/src/matches.rs | 43 +++++++++++++++++++++++++++++++- src/lintlist/mod.rs | 7 ++++++ tests/ui/pats_with_wild_match_arm.fixed | 38 ++++++++++++++++++++++++++++ tests/ui/pats_with_wild_match_arm.rs | 38 ++++++++++++++++++++++++++++ tests/ui/pats_with_wild_match_arm.stderr | 28 +++++++++++++++++++++ 7 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pats_with_wild_match_arm.fixed create mode 100644 tests/ui/pats_with_wild_match_arm.rs create mode 100644 tests/ui/pats_with_wild_match_arm.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f60ac7d5267..d4ecdabeb14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1241,6 +1241,7 @@ Released 2018-09-13 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`pats_with_wild_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#pats_with_wild_match_arm [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6846730a415..2d83a5b41d0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -597,6 +597,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_WILD_ERR_ARM, + &matches::PATS_WITH_WILD_MATCH_ARM, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, &matches::WILDCARD_ENUM_MATCH_ARM, @@ -1001,6 +1002,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&integer_division::INTEGER_DIVISION), LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), LintId::of(&methods::CLONE_ON_REF_PTR), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 3200de1cfc1..29d34c37988 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -223,6 +223,26 @@ declare_clippy_lint! { "a wildcard enum match arm using `_`" } +declare_clippy_lint! { + /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm. + /// + /// **Why is this bad?** Wildcard pattern already covers any other pattern as it will match anyway. + /// It makes the code less readable, especially to spot wildcard pattern use in match arm. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// match "foo" { + /// "a" => {}, + /// "bar" | _ => {}, + /// } + /// ``` + pub PATS_WITH_WILD_MATCH_ARM, + restriction, + "a wildcard pattern used with others patterns in same match arm" +} + declare_lint_pass!(Matches => [ SINGLE_MATCH, MATCH_REF_PATS, @@ -231,7 +251,8 @@ declare_lint_pass!(Matches => [ MATCH_OVERLAPPING_ARM, MATCH_WILD_ERR_ARM, MATCH_AS_REF, - WILDCARD_ENUM_MATCH_ARM + WILDCARD_ENUM_MATCH_ARM, + PATS_WITH_WILD_MATCH_ARM ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { @@ -246,6 +267,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { check_wild_err_arm(cx, ex, arms); check_wild_enum_match(cx, ex, arms); check_match_as_ref(cx, ex, arms, expr); + check_pats_wild_match(cx, ex, arms, expr); } if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms, expr); @@ -664,6 +686,25 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], } } +fn check_pats_wild_match(cx: &LateContext<'_, '_>, _ex: &Expr, arms: &[Arm], _expr: &Expr) { + for arm in arms { + if let PatKind::Or(ref fields) = arm.pat.kind { + // look for multiple fields where one at least matches Wild pattern + if fields.len() > 1 && fields.into_iter().any(|pat| is_wild(pat)) { + span_lint_and_sugg( + cx, + PATS_WITH_WILD_MATCH_ARM, + arm.pat.span, + "wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only", + "try this", + "_".to_string(), + Applicability::MachineApplicable, + ) + } + } + } +} + /// Gets all arms that are unbounded `PatRange`s. fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm<'_>]) -> Vec<SpannedRange<Constant>> { arms.iter() diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1086f5e48f9..a6b31876a7a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1568,6 +1568,13 @@ pub const ALL_LINTS: [Lint; 345] = [ deprecation: None, module: "path_buf_push_overwrite", }, + Lint { + name: "pats_with_wild_match_arm", + group: "restriction", + desc: "a wildcard pattern used with others patterns in same match arm", + deprecation: None, + module: "matches", + }, Lint { name: "possible_missing_comma", group: "correctness", diff --git a/tests/ui/pats_with_wild_match_arm.fixed b/tests/ui/pats_with_wild_match_arm.fixed new file mode 100644 index 00000000000..daa34af9436 --- /dev/null +++ b/tests/ui/pats_with_wild_match_arm.fixed @@ -0,0 +1,38 @@ +// run-rustfix + +#![warn(clippy::pats_with_wild_match_arm)] + +fn main() { + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or bar2 or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; +} diff --git a/tests/ui/pats_with_wild_match_arm.rs b/tests/ui/pats_with_wild_match_arm.rs new file mode 100644 index 00000000000..0410cecb5d6 --- /dev/null +++ b/tests/ui/pats_with_wild_match_arm.rs @@ -0,0 +1,38 @@ +// run-rustfix + +#![warn(clippy::pats_with_wild_match_arm)] + +fn main() { + match "foo" { + "a" => { + dbg!("matched a"); + }, + "bar" | _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + "bar" | "bar2" | _ => { + dbg!("matched (bar or bar2 or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ | "bar" | _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ | "bar" => { + dbg!("matched (bar or) wild"); + }, + }; +} diff --git a/tests/ui/pats_with_wild_match_arm.stderr b/tests/ui/pats_with_wild_match_arm.stderr new file mode 100644 index 00000000000..5b5d8d28738 --- /dev/null +++ b/tests/ui/pats_with_wild_match_arm.stderr @@ -0,0 +1,28 @@ +error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only + --> $DIR/pats_with_wild_match_arm.rs:10:9 + | +LL | "bar" | _ => { + | ^^^^^^^^^ help: try this: `_` + | + = note: `-D clippy::pats-with-wild-match-arm` implied by `-D warnings` + +error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only + --> $DIR/pats_with_wild_match_arm.rs:18:9 + | +LL | "bar" | "bar2" | _ => { + | ^^^^^^^^^^^^^^^^^^ help: try this: `_` + +error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only + --> $DIR/pats_with_wild_match_arm.rs:26:9 + | +LL | _ | "bar" | _ => { + | ^^^^^^^^^^^^^ help: try this: `_` + +error: wildcard pattern covers any other pattern as it will match anyway. Consider replacing with wildcard pattern only + --> $DIR/pats_with_wild_match_arm.rs:34:9 + | +LL | _ | "bar" => { + | ^^^^^^^^^ help: try this: `_` + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From d60c6f939862ed0be315499f53a0c2fe63b580d6 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Fri, 27 Dec 2019 05:42:28 +0100 Subject: Move to complexity and adapt test - test wildcard_enum_match_arm has been impacted by this new lint --- clippy_lints/src/lib.rs | 3 ++- src/lintlist/mod.rs | 2 +- tests/ui/wildcard_enum_match_arm.fixed | 8 +++++++- tests/ui/wildcard_enum_match_arm.rs | 8 +++++++- tests/ui/wildcard_enum_match_arm.stderr | 10 +++++----- 5 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2d83a5b41d0..a009bab57c6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1002,7 +1002,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&integer_division::INTEGER_DIVISION), LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), LintId::of(&methods::CLONE_ON_REF_PTR), @@ -1189,6 +1188,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_WILD_ERR_ARM), + LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), @@ -1463,6 +1463,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::MATCH_AS_REF), + LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::FILTER_NEXT), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a6b31876a7a..34bf4749d83 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1570,7 +1570,7 @@ pub const ALL_LINTS: [Lint; 345] = [ }, Lint { name: "pats_with_wild_match_arm", - group: "restriction", + group: "complexity", desc: "a wildcard pattern used with others patterns in same match arm", deprecation: None, module: "matches", diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 1da2833e260..f46320e03cc 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -1,7 +1,13 @@ // run-rustfix #![deny(clippy::wildcard_enum_match_arm)] -#![allow(unreachable_code, unused_variables, dead_code, clippy::single_match)] +#![allow( + unreachable_code, + unused_variables, + dead_code, + clippy::single_match, + clippy::pats_with_wild_match_arm +)] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index c2eb4b30802..508d0e0bb79 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -1,7 +1,13 @@ // run-rustfix #![deny(clippy::wildcard_enum_match_arm)] -#![allow(unreachable_code, unused_variables, dead_code, clippy::single_match)] +#![allow( + unreachable_code, + unused_variables, + dead_code, + clippy::single_match, + clippy::pats_with_wild_match_arm +)] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index 735f610b7e5..e6f0411095c 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -1,5 +1,5 @@ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:31:9 + --> $DIR/wildcard_enum_match_arm.rs:37:9 | LL | _ => eprintln!("Not red"), | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` @@ -11,25 +11,25 @@ LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:35:9 + --> $DIR/wildcard_enum_match_arm.rs:41:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:39:9 + --> $DIR/wildcard_enum_match_arm.rs:45:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:55:9 + --> $DIR/wildcard_enum_match_arm.rs:61:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: match on non-exhaustive enum doesn't explicitly match all known variants - --> $DIR/wildcard_enum_match_arm.rs:72:9 + --> $DIR/wildcard_enum_match_arm.rs:78:9 | LL | _ => {}, | ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _` -- cgit 1.4.1-3-g733a5 From 8ae8b08e323b7dcfad331af18bebbeb68757a904 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Sun, 5 Jan 2020 15:05:16 +0100 Subject: Change lint name to WILDCARD_IN_OR_PATTERNS --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 ++--- clippy_lints/src/matches.rs | 10 ++++----- src/lintlist/mod.rs | 14 ++++++------ tests/ui/pats_with_wild_match_arm.fixed | 38 -------------------------------- tests/ui/pats_with_wild_match_arm.rs | 38 -------------------------------- tests/ui/pats_with_wild_match_arm.stderr | 28 ----------------------- tests/ui/wild_in_or_pats.fixed | 38 ++++++++++++++++++++++++++++++++ tests/ui/wild_in_or_pats.rs | 38 ++++++++++++++++++++++++++++++++ tests/ui/wild_in_or_pats.stderr | 28 +++++++++++++++++++++++ tests/ui/wildcard_enum_match_arm.fixed | 2 +- tests/ui/wildcard_enum_match_arm.rs | 2 +- 12 files changed, 122 insertions(+), 122 deletions(-) delete mode 100644 tests/ui/pats_with_wild_match_arm.fixed delete mode 100644 tests/ui/pats_with_wild_match_arm.rs delete mode 100644 tests/ui/pats_with_wild_match_arm.stderr create mode 100644 tests/ui/wild_in_or_pats.fixed create mode 100644 tests/ui/wild_in_or_pats.rs create mode 100644 tests/ui/wild_in_or_pats.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index d4ecdabeb14..69694da1520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1241,7 +1241,6 @@ Released 2018-09-13 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite -[`pats_with_wild_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#pats_with_wild_match_arm [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal @@ -1362,6 +1361,7 @@ Released 2018-09-13 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator [`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies [`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm +[`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns [`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal [`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline [`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a009bab57c6..518b6ee6141 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -597,10 +597,10 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_WILD_ERR_ARM, - &matches::PATS_WITH_WILD_MATCH_ARM, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, &matches::WILDCARD_ENUM_MATCH_ARM, + &matches::WILDCARD_IN_OR_PATTERNS, &mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, &mem_forget::MEM_FORGET, &mem_replace::MEM_REPLACE_OPTION_WITH_NONE, @@ -1188,8 +1188,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_WILD_ERR_ARM), - LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), LintId::of(&matches::SINGLE_MATCH), + LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), @@ -1463,7 +1463,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::MATCH_AS_REF), - LintId::of(&matches::PATS_WITH_WILD_MATCH_ARM), + LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::FILTER_NEXT), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2347a0619d6..2e25b7236d7 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -238,7 +238,7 @@ declare_clippy_lint! { /// "bar" | _ => {}, /// } /// ``` - pub PATS_WITH_WILD_MATCH_ARM, + pub WILDCARD_IN_OR_PATTERNS, complexity, "a wildcard pattern used with others patterns in same match arm" } @@ -252,7 +252,7 @@ declare_lint_pass!(Matches => [ MATCH_WILD_ERR_ARM, MATCH_AS_REF, WILDCARD_ENUM_MATCH_ARM, - PATS_WITH_WILD_MATCH_ARM + WILDCARD_IN_OR_PATTERNS ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { @@ -267,7 +267,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { check_wild_err_arm(cx, ex, arms); check_wild_enum_match(cx, ex, arms); check_match_as_ref(cx, ex, arms, expr); - check_pats_wild_match(cx, ex, arms); + check_wild_in_or_pats(cx, ex, arms); } if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms, expr); @@ -686,7 +686,7 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], } } -fn check_pats_wild_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { +fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let mut is_non_exhaustive_enum = false; let ty = cx.tables.expr_ty(ex); if ty.is_enum() { @@ -703,7 +703,7 @@ fn check_pats_wild_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ if fields.len() > 1 && fields.iter().any(is_wild) { span_lint_and_then( cx, - PATS_WITH_WILD_MATCH_ARM, + WILDCARD_IN_OR_PATTERNS, arm.pat.span, "wildcard pattern covers any other pattern as it will match anyway.", |db| { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 34bf4749d83..399f3483a59 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1568,13 +1568,6 @@ pub const ALL_LINTS: [Lint; 345] = [ deprecation: None, module: "path_buf_push_overwrite", }, - Lint { - name: "pats_with_wild_match_arm", - group: "complexity", - desc: "a wildcard pattern used with others patterns in same match arm", - deprecation: None, - module: "matches", - }, Lint { name: "possible_missing_comma", group: "correctness", @@ -2352,6 +2345,13 @@ pub const ALL_LINTS: [Lint; 345] = [ deprecation: None, module: "matches", }, + Lint { + name: "wildcard_in_or_patterns", + group: "complexity", + desc: "a wildcard pattern used with others patterns in same match arm", + deprecation: None, + module: "matches", + }, Lint { name: "write_literal", group: "style", diff --git a/tests/ui/pats_with_wild_match_arm.fixed b/tests/ui/pats_with_wild_match_arm.fixed deleted file mode 100644 index daa34af9436..00000000000 --- a/tests/ui/pats_with_wild_match_arm.fixed +++ /dev/null @@ -1,38 +0,0 @@ -// run-rustfix - -#![warn(clippy::pats_with_wild_match_arm)] - -fn main() { - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or bar2 or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; -} diff --git a/tests/ui/pats_with_wild_match_arm.rs b/tests/ui/pats_with_wild_match_arm.rs deleted file mode 100644 index 0410cecb5d6..00000000000 --- a/tests/ui/pats_with_wild_match_arm.rs +++ /dev/null @@ -1,38 +0,0 @@ -// run-rustfix - -#![warn(clippy::pats_with_wild_match_arm)] - -fn main() { - match "foo" { - "a" => { - dbg!("matched a"); - }, - "bar" | _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - "bar" | "bar2" | _ => { - dbg!("matched (bar or bar2 or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ | "bar" | _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ | "bar" => { - dbg!("matched (bar or) wild"); - }, - }; -} diff --git a/tests/ui/pats_with_wild_match_arm.stderr b/tests/ui/pats_with_wild_match_arm.stderr deleted file mode 100644 index 215d0b2e413..00000000000 --- a/tests/ui/pats_with_wild_match_arm.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/pats_with_wild_match_arm.rs:10:9 - | -LL | "bar" | _ => { - | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` - | - = note: `-D clippy::pats-with-wild-match-arm` implied by `-D warnings` - -error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/pats_with_wild_match_arm.rs:18:9 - | -LL | "bar" | "bar2" | _ => { - | ^^^^^^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` - -error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/pats_with_wild_match_arm.rs:26:9 - | -LL | _ | "bar" | _ => { - | ^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` - -error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/pats_with_wild_match_arm.rs:34:9 - | -LL | _ | "bar" => { - | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/wild_in_or_pats.fixed b/tests/ui/wild_in_or_pats.fixed new file mode 100644 index 00000000000..40d4a6e8fac --- /dev/null +++ b/tests/ui/wild_in_or_pats.fixed @@ -0,0 +1,38 @@ +// run-rustfix + +#![warn(clippy::wildcard_in_or_patterns)] + +fn main() { + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or bar2 or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ => { + dbg!("matched (bar or) wild"); + }, + }; +} diff --git a/tests/ui/wild_in_or_pats.rs b/tests/ui/wild_in_or_pats.rs new file mode 100644 index 00000000000..569871db936 --- /dev/null +++ b/tests/ui/wild_in_or_pats.rs @@ -0,0 +1,38 @@ +// run-rustfix + +#![warn(clippy::wildcard_in_or_patterns)] + +fn main() { + match "foo" { + "a" => { + dbg!("matched a"); + }, + "bar" | _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + "bar" | "bar2" | _ => { + dbg!("matched (bar or bar2 or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ | "bar" | _ => { + dbg!("matched (bar or) wild"); + }, + }; + match "foo" { + "a" => { + dbg!("matched a"); + }, + _ | "bar" => { + dbg!("matched (bar or) wild"); + }, + }; +} diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr new file mode 100644 index 00000000000..45ae31db21a --- /dev/null +++ b/tests/ui/wild_in_or_pats.stderr @@ -0,0 +1,28 @@ +error: wildcard pattern covers any other pattern as it will match anyway. + --> $DIR/wild_in_or_pats.rs:10:9 + | +LL | "bar" | _ => { + | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + | + = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` + +error: wildcard pattern covers any other pattern as it will match anyway. + --> $DIR/wild_in_or_pats.rs:18:9 + | +LL | "bar" | "bar2" | _ => { + | ^^^^^^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + +error: wildcard pattern covers any other pattern as it will match anyway. + --> $DIR/wild_in_or_pats.rs:26:9 + | +LL | _ | "bar" | _ => { + | ^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + +error: wildcard pattern covers any other pattern as it will match anyway. + --> $DIR/wild_in_or_pats.rs:34:9 + | +LL | _ | "bar" => { + | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index f46320e03cc..2aa24ea1156 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -6,7 +6,7 @@ unused_variables, dead_code, clippy::single_match, - clippy::pats_with_wild_match_arm + clippy::wildcard_in_or_patterns )] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index 508d0e0bb79..07c93feaf28 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -6,7 +6,7 @@ unused_variables, dead_code, clippy::single_match, - clippy::pats_with_wild_match_arm + clippy::wildcard_in_or_patterns )] use std::io::ErrorKind; -- cgit 1.4.1-3-g733a5 From 0fa0df9efb9f34c8e0612bd0d0844417259873e9 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Tue, 7 Jan 2020 18:13:31 +0100 Subject: Span help without suggestion --- README.md | 2 +- clippy_lints/src/matches.rs | 38 ++++++-------------------------------- src/lintlist/mod.rs | 2 +- tests/ui/wild_in_or_pats.fixed | 38 -------------------------------------- tests/ui/wild_in_or_pats.rs | 2 -- tests/ui/wild_in_or_pats.stderr | 23 +++++++++++++++-------- 6 files changed, 23 insertions(+), 82 deletions(-) delete mode 100644 tests/ui/wild_in_or_pats.fixed (limited to 'src') diff --git a/README.md b/README.md index c46d3e16bb1..4de256e9e72 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 345 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 346 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2e25b7236d7..6b5b4e4c4f0 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -3,7 +3,8 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::{ expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet, - snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, + snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, + walk_ptrs_ty, }; use if_chain::if_chain; use rustc::declare_lint_pass; @@ -267,7 +268,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { check_wild_err_arm(cx, ex, arms); check_wild_enum_match(cx, ex, arms); check_match_as_ref(cx, ex, arms, expr); - check_wild_in_or_pats(cx, ex, arms); + check_wild_in_or_pats(cx, arms); } if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms, expr); @@ -686,44 +687,17 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], } } -fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { - let mut is_non_exhaustive_enum = false; - let ty = cx.tables.expr_ty(ex); - if ty.is_enum() { - if let ty::Adt(def, _) = ty.kind { - if def.is_variant_list_non_exhaustive() { - is_non_exhaustive_enum = true; - } - } - } - +fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) { for arm in arms { if let PatKind::Or(ref fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern if fields.len() > 1 && fields.iter().any(is_wild) { - span_lint_and_then( + span_help_and_lint( cx, WILDCARD_IN_OR_PATTERNS, arm.pat.span, "wildcard pattern covers any other pattern as it will match anyway.", - |db| { - // handle case where a non exhaustive enum is being used - if is_non_exhaustive_enum { - db.span_suggestion( - arm.pat.span, - "consider handling `_` separately.", - "_ => ...".to_string(), - Applicability::MaybeIncorrect, - ); - } else { - db.span_suggestion( - arm.pat.span, - "consider replacing with wildcard pattern only", - "_".to_string(), - Applicability::MachineApplicable, - ); - } - }, + "Consider handling `_` separately.", ); } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 399f3483a59..3cc4efb9b05 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 345] = [ +pub const ALL_LINTS: [Lint; 346] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", diff --git a/tests/ui/wild_in_or_pats.fixed b/tests/ui/wild_in_or_pats.fixed deleted file mode 100644 index 40d4a6e8fac..00000000000 --- a/tests/ui/wild_in_or_pats.fixed +++ /dev/null @@ -1,38 +0,0 @@ -// run-rustfix - -#![warn(clippy::wildcard_in_or_patterns)] - -fn main() { - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or bar2 or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; - match "foo" { - "a" => { - dbg!("matched a"); - }, - _ => { - dbg!("matched (bar or) wild"); - }, - }; -} diff --git a/tests/ui/wild_in_or_pats.rs b/tests/ui/wild_in_or_pats.rs index 569871db936..ad600f12577 100644 --- a/tests/ui/wild_in_or_pats.rs +++ b/tests/ui/wild_in_or_pats.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![warn(clippy::wildcard_in_or_patterns)] fn main() { diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr index 45ae31db21a..33c34cbbd40 100644 --- a/tests/ui/wild_in_or_pats.stderr +++ b/tests/ui/wild_in_or_pats.stderr @@ -1,28 +1,35 @@ error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/wild_in_or_pats.rs:10:9 + --> $DIR/wild_in_or_pats.rs:8:9 | LL | "bar" | _ => { - | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + | ^^^^^^^^^ | = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings` + = help: Consider handling `_` separately. error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/wild_in_or_pats.rs:18:9 + --> $DIR/wild_in_or_pats.rs:16:9 | LL | "bar" | "bar2" | _ => { - | ^^^^^^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + | ^^^^^^^^^^^^^^^^^^ + | + = help: Consider handling `_` separately. error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/wild_in_or_pats.rs:26:9 + --> $DIR/wild_in_or_pats.rs:24:9 | LL | _ | "bar" | _ => { - | ^^^^^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + | ^^^^^^^^^^^^^ + | + = help: Consider handling `_` separately. error: wildcard pattern covers any other pattern as it will match anyway. - --> $DIR/wild_in_or_pats.rs:34:9 + --> $DIR/wild_in_or_pats.rs:32:9 | LL | _ | "bar" => { - | ^^^^^^^^^ help: consider replacing with wildcard pattern only: `_` + | ^^^^^^^^^ + | + = help: Consider handling `_` separately. error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From b793cf09f2dfa9d96e4af9420e041b88d961ef56 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Tue, 7 Jan 2020 15:53:19 -0800 Subject: Move `transmute_float_to_int` lint to `complexity` `transmute_float_to_int` lint was accidentally added to nursery so moving it to the complexity group. --- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/transmute.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6846730a415..0ba1bf6008c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1296,6 +1296,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), @@ -1494,6 +1495,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), LintId::of(&transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), LintId::of(&transmute::TRANSMUTE_INT_TO_BOOL), LintId::of(&transmute::TRANSMUTE_INT_TO_CHAR), LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), @@ -1612,7 +1614,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), - LintId::of(&transmute::TRANSMUTE_FLOAT_TO_INT), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 7e87a285eba..30ea81125c5 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -210,7 +210,7 @@ declare_clippy_lint! { /// let _: u32 = 1f32.to_bits(); /// ``` pub TRANSMUTE_FLOAT_TO_INT, - nursery, + complexity, "transmutes from a float to an integer" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1086f5e48f9..f237809d920 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1997,7 +1997,7 @@ pub const ALL_LINTS: [Lint; 345] = [ }, Lint { name: "transmute_float_to_int", - group: "nursery", + group: "complexity", desc: "transmutes from a float to an integer", deprecation: None, module: "transmute", -- cgit 1.4.1-3-g733a5 From 822de884ff99c80d0e1ecf70273b464994e67a57 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Thu, 9 Jan 2020 16:14:19 +0900 Subject: Rustup to rust-lang/rust#68024 --- src/driver.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 4a080c12e44..27ff7fa9116 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -259,7 +259,6 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { if !info.payload().is::<rustc_errors::ExplicitBug>() { let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic"); handler.emit_diagnostic(&d); - handler.abort_if_errors_and_should_abort(); } let version_info = rustc_tools_util::get_version_info!(); -- cgit 1.4.1-3-g733a5 From e2e40f2570cc66d3b74a2f474e57763cb75f6029 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Thu, 9 Jan 2020 09:49:15 -0800 Subject: Detect usage of invalid atomic ordering in memory fences Detect usage of `core::sync::atomic::{fence, compiler_fence}` with `Ordering::Relaxed` and suggest valid alternatives. --- clippy_lints/src/atomic_ordering.rs | 97 ++++++++++++++++++++++++------------- src/lintlist/mod.rs | 2 +- 2 files changed, 65 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index fe06c63a553..f5b0b625023 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -9,7 +9,7 @@ use rustc_session::declare_tool_lint; declare_clippy_lint! { /// **What it does:** Checks for usage of invalid atomic - /// ordering in Atomic*::{load, store} calls. + /// ordering in atomic loads/stores and memory fences. /// /// **Why is this bad?** Using an invalid atomic ordering /// will cause a panic at run-time. @@ -18,7 +18,7 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,no_run - /// # use std::sync::atomic::{AtomicBool, Ordering}; + /// # use std::sync::atomic::{self, AtomicBool, Ordering}; /// /// let x = AtomicBool::new(true); /// @@ -27,10 +27,13 @@ declare_clippy_lint! { /// /// x.store(false, Ordering::Acquire); /// x.store(false, Ordering::AcqRel); + /// + /// atomic::fence(Ordering::Relaxed); + /// atomic::compiler_fence(Ordering::Relaxed); /// ``` pub INVALID_ATOMIC_ORDERING, correctness, - "usage of invalid atomic ordering in atomic load/store calls" + "usage of invalid atomic ordering in atomic loads/stores and memory fences" } declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]); @@ -66,37 +69,65 @@ fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&s .any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering])) } -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind; - let method = method_path.ident.name.as_str(); - if type_is_atomic(cx, &args[0]); - if method == "load" || method == "store"; - let ordering_arg = if method == "load" { &args[1] } else { &args[2] }; - if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind; - if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id(); - then { - if method == "load" && - match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) { - span_help_and_lint( - cx, - INVALID_ATOMIC_ORDERING, - ordering_arg.span, - "atomic loads cannot have `Release` and `AcqRel` ordering", - "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`" - ); - } else if method == "store" && - match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) { - span_help_and_lint( - cx, - INVALID_ATOMIC_ORDERING, - ordering_arg.span, - "atomic stores cannot have `Acquire` and `AcqRel` ordering", - "consider using ordering modes `Release`, `SeqCst` or `Relaxed`" - ); - } +fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind; + let method = method_path.ident.name.as_str(); + if type_is_atomic(cx, &args[0]); + if method == "load" || method == "store"; + let ordering_arg = if method == "load" { &args[1] } else { &args[2] }; + if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind; + if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id(); + then { + if method == "load" && + match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) { + span_help_and_lint( + cx, + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + "atomic loads cannot have `Release` and `AcqRel` ordering", + "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`" + ); + } else if method == "store" && + match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) { + span_help_and_lint( + cx, + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + "atomic stores cannot have `Acquire` and `AcqRel` ordering", + "consider using ordering modes `Release`, `SeqCst` or `Relaxed`" + ); } } } } + +fn check_memory_fence(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if ["fence", "compiler_fence"] + .iter() + .any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func])); + if let ExprKind::Path(ref ordering_qpath) = &args[0].kind; + if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id(); + if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]); + then { + span_help_and_lint( + cx, + INVALID_ATOMIC_ORDERING, + args[0].span, + "memory fences cannot have `Relaxed` ordering", + "consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`" + ); + } + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AtomicOrdering { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { + check_atomic_load_store(cx, expr); + check_memory_fence(cx, expr); + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f576bb152de..b133a799762 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -836,7 +836,7 @@ pub const ALL_LINTS: [Lint; 346] = [ Lint { name: "invalid_atomic_ordering", group: "correctness", - desc: "usage of invalid atomic ordering in atomic load/store calls", + desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences", deprecation: None, module: "atomic_ordering", }, -- cgit 1.4.1-3-g733a5 From 96334d0d7cc2901acc80a67ba454409dcd452a30 Mon Sep 17 00:00:00 2001 From: xiongmao86 <xiongmao86dev@sina.com> Date: Thu, 2 Jan 2020 13:12:23 +0800 Subject: Declare lint. --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/mod.rs | 35 +++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 +++++++ 4 files changed, 46 insertions(+) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 69694da1520..11d745a4c23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1093,6 +1093,7 @@ Released 2018-09-13 [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from +[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1a112c0d370..85cca4a77fe 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -612,6 +612,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf &methods::CLONE_ON_COPY, &methods::CLONE_ON_REF_PTR, &methods::EXPECT_FUN_CALL, + &methods::FILETYPE_IS_FILE, &methods::FILTER_MAP, &methods::FILTER_MAP_NEXT, &methods::FILTER_NEXT, @@ -1199,6 +1200,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INEFFICIENT_TO_STRING), @@ -1384,6 +1386,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&methods::CHARS_LAST_CMP), + LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NTH_ZERO), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 073177b0f3d..b5f68817c35 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1130,6 +1130,40 @@ declare_clippy_lint! { "Check for offset calculations on raw pointers to zero-sized types" } +declare_clippy_lint! { + /// **What it does:** Checks for `FileType::is_file()`. + /// + /// **Why is this bad?** When people testing a file type with `FileType::is_file` + /// they are testing whether a path is something they can get bytes from. But + /// `is_file` doesn't cover special file types in unix-like systems. and not covering + /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. + /// + /// **Example:** + /// + /// ```rust,ignore + /// let metadata = std::fs::metadata("foo.txt")?; + /// let filetype = metadata.file_type(); + /// + /// if filetype.is_file() { + /// // read file + /// } + /// ``` + /// + /// should be writing as: + /// + /// ```rust,ignore + /// let metadata = std::fs::metadata("foo.txt")?; + /// let filetype = metadata.file_type(); + /// + /// if !filetype.is_dir() { + /// // read file + /// } + /// ``` + pub FILETYPE_IS_FILE, + style, + "`FileType::is_file` is not recommended to test for readable file type." +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -1177,6 +1211,7 @@ declare_lint_pass!(Methods => [ UNINIT_ASSUMED_INIT, MANUAL_SATURATING_ARITHMETIC, ZST_OFFSET, + FILETYPE_IS_FILE, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f576bb152de..5dd82b66b8e 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -560,6 +560,13 @@ pub const ALL_LINTS: [Lint; 346] = [ deprecation: None, module: "fallible_impl_from", }, + Lint { + name: "filetype_is_file", + group: "style", + desc: "`FileType::is_file` is not recommended to test for readable file type.", + deprecation: None, + module: "methods", + }, Lint { name: "filter_map", group: "pedantic", -- cgit 1.4.1-3-g733a5 From 2909bc372fb51fe21be59aca3950eca9ad1514d8 Mon Sep 17 00:00:00 2001 From: xiongmao86 <xiongmao86dev@sina.com> Date: Tue, 7 Jan 2020 16:11:34 +0800 Subject: ./util/dev update_lints. --- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 85cca4a77fe..9ee849ce162 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1006,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), LintId::of(&methods::CLONE_ON_REF_PTR), + LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::GET_UNWRAP), LintId::of(&methods::OPTION_EXPECT_USED), LintId::of(&methods::OPTION_UNWRAP_USED), @@ -1200,7 +1201,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::EXPECT_FUN_CALL), - LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INEFFICIENT_TO_STRING), @@ -1386,7 +1386,6 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&methods::CHARS_LAST_CMP), - LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NTH_ZERO), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5dd82b66b8e..8554de78d85 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -562,8 +562,8 @@ pub const ALL_LINTS: [Lint; 346] = [ }, Lint { name: "filetype_is_file", - group: "style", - desc: "`FileType::is_file` is not recommended to test for readable file type.", + group: "restriction", + desc: "`FileType::is_file` is not recommended to test for readable file type", deprecation: None, module: "methods", }, -- cgit 1.4.1-3-g733a5 From bba468887bb3c20ff8e38a61bb0f2222836cb451 Mon Sep 17 00:00:00 2001 From: xiongmao86 <xiongmao86dev@sina.com> Date: Sat, 11 Jan 2020 11:57:49 +0800 Subject: Pull master, rebase, and update_lints again. --- README.md | 2 +- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 4de256e9e72..7b1d14e9afc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 346 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 347 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8554de78d85..9cad1ac786a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 346] = [ +pub const ALL_LINTS: [Lint; 347] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", -- cgit 1.4.1-3-g733a5 From ff5fb19bbd7f9885c32009957fa7f7e2b42e9e16 Mon Sep 17 00:00:00 2001 From: Andre Bogus <bogusandre@gmail.com> Date: Fri, 17 Jan 2020 10:15:14 +0100 Subject: Downgrade range_plus_one to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/ranges.rs | 6 +++++- src/lintlist/mod.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c1fe51fbf8a..b37e0945d77 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1068,6 +1068,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_continue::NEEDLESS_CONTINUE), LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), LintId::of(&non_expressive_names::SIMILAR_NAMES), + LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&replace_consts::REPLACE_CONSTS), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), @@ -1277,7 +1278,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(&question_mark::QUESTION_MARK), LintId::of(&ranges::RANGE_MINUS_ONE), - LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), @@ -1495,7 +1495,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&precedence::PRECEDENCE), LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(&ranges::RANGE_MINUS_ONE), - LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 19f88e770ae..1be59787721 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -45,6 +45,10 @@ declare_clippy_lint! { /// and ends with a closing one. /// I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. /// + /// Also in many cases, inclusive ranges are still slower to run than + /// exclusive ranges, because they essentially add an extra branch that + /// LLVM may fail to hoist out of the loop. + /// /// **Example:** /// ```rust,ignore /// for x..(y+1) { .. } @@ -54,7 +58,7 @@ declare_clippy_lint! { /// for x..=y { .. } /// ``` pub RANGE_PLUS_ONE, - complexity, + pedantic, "`x..(y+1)` reads better as `x..=y`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9cad1ac786a..eee16fcd312 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1654,7 +1654,7 @@ pub const ALL_LINTS: [Lint; 347] = [ }, Lint { name: "range_plus_one", - group: "complexity", + group: "pedantic", desc: "`x..(y+1)` reads better as `x..=y`", deprecation: None, module: "ranges", -- cgit 1.4.1-3-g733a5 From ae872fe1c74d68d7d1e88079cc77c858268fcdbf Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sat, 11 Jan 2020 03:29:55 +0900 Subject: Rename `ok_if_let` to `if_let_some_result` --- clippy_lints/src/if_let_some_result.rs | 79 ++++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 10 ++--- clippy_lints/src/ok_if_let.rs | 79 ---------------------------------- src/lintlist/mod.rs | 2 +- tests/ui/if_let_some_result.fixed | 34 +++++++++++++++ tests/ui/if_let_some_result.rs | 34 +++++++++++++++ tests/ui/if_let_some_result.stderr | 37 ++++++++++++++++ tests/ui/ok_if_let.fixed | 34 --------------- tests/ui/ok_if_let.rs | 34 --------------- tests/ui/ok_if_let.stderr | 37 ---------------- 10 files changed, 190 insertions(+), 190 deletions(-) create mode 100644 clippy_lints/src/if_let_some_result.rs delete mode 100644 clippy_lints/src/ok_if_let.rs create mode 100644 tests/ui/if_let_some_result.fixed create mode 100644 tests/ui/if_let_some_result.rs create mode 100644 tests/ui/if_let_some_result.stderr delete mode 100644 tests/ui/ok_if_let.fixed delete mode 100644 tests/ui/ok_if_let.rs delete mode 100644 tests/ui/ok_if_let.stderr (limited to 'src') diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs new file mode 100644 index 00000000000..dc129a28e37 --- /dev/null +++ b/clippy_lints/src/if_let_some_result.rs @@ -0,0 +1,79 @@ +use crate::utils::{match_type, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; + +declare_clippy_lint! { + /// **What it does:*** Checks for unnecessary `ok()` in if let. + /// + /// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match + /// on `Ok(pat)` + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```ignore + /// for i in iter { + /// if let Some(value) = i.parse().ok() { + /// vec.push(value) + /// } + /// } + /// ``` + /// Could be written: + /// + /// ```ignore + /// for i in iter { + /// if let Ok(value) = i.parse() { + /// vec.push(value) + /// } + /// } + /// ``` + pub IF_LET_SOME_RESULT, + style, + "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead" +} + +declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { //begin checking variables + if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match + if let MatchSource::IfLetDesugar { contains_else_clause } = source; //test if it is an If Let + if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() + if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation + if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; + + then { + let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); + let mut applicability = Applicability::MachineApplicable; + let trimed_ok_span = op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))); + let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); + let trimmed_ok = snippet_with_applicability(cx, trimed_ok_span, "", &mut applicability); + let mut sugg = format!( + "if let Ok({}) = {} {}", + some_expr_string, + trimmed_ok, + snippet(cx, body[0].span, ".."), + ); + if contains_else_clause { + sugg = format!("{} else {}", sugg, snippet(cx, body[1].span, "..")); + } + if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { + span_lint_and_sugg( + cx, + IF_LET_SOME_RESULT, + expr.span, + "Matching on `Some` with `ok()` is redundant", + &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, + ); + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5fe0d937f2f..8a90e39f2e9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -210,6 +210,7 @@ pub mod functions; pub mod get_last_with_len; pub mod identity_conversion; pub mod identity_op; +pub mod if_let_some_result; pub mod if_not_else; pub mod implicit_return; pub mod indexing_slicing; @@ -263,7 +264,6 @@ pub mod new_without_default; pub mod no_effect; pub mod non_copy_const; pub mod non_expressive_names; -pub mod ok_if_let; pub mod open_options; pub mod overflow_check_conditional; pub mod panic_unimplemented; @@ -703,7 +703,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, &non_expressive_names::MANY_SINGLE_CHAR_NAMES, &non_expressive_names::SIMILAR_NAMES, - &ok_if_let::IF_LET_SOME_RESULT, + &if_let_some_result::IF_LET_SOME_RESULT, &open_options::NONSENSICAL_OPEN_OPTIONS, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_unimplemented::PANIC, @@ -904,7 +904,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); store.register_late_pass(|| box missing_doc::MissingDoc::new()); store.register_late_pass(|| box missing_inline::MissingInline); - store.register_late_pass(|| box ok_if_let::OkIfLet); + store.register_late_pass(|| box if_let_some_result::OkIfLet); store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching); store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); @@ -1265,7 +1265,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(&panic_unimplemented::PANIC_PARAMS), @@ -1413,7 +1413,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::PTR_ARG), diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs deleted file mode 100644 index dc129a28e37..00000000000 --- a/clippy_lints/src/ok_if_let.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::utils::{match_type, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::BytePos; - -declare_clippy_lint! { - /// **What it does:*** Checks for unnecessary `ok()` in if let. - /// - /// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match - /// on `Ok(pat)` - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```ignore - /// for i in iter { - /// if let Some(value) = i.parse().ok() { - /// vec.push(value) - /// } - /// } - /// ``` - /// Could be written: - /// - /// ```ignore - /// for i in iter { - /// if let Ok(value) = i.parse() { - /// vec.push(value) - /// } - /// } - /// ``` - pub IF_LET_SOME_RESULT, - style, - "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead" -} - -declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { contains_else_clause } = source; //test if it is an If Let - if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() - if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation - if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - - then { - let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); - let mut applicability = Applicability::MachineApplicable; - let trimed_ok_span = op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))); - let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); - let trimmed_ok = snippet_with_applicability(cx, trimed_ok_span, "", &mut applicability); - let mut sugg = format!( - "if let Ok({}) = {} {}", - some_expr_string, - trimmed_ok, - snippet(cx, body[0].span, ".."), - ); - if contains_else_clause { - sugg = format!("{} else {}", sugg, snippet(cx, body[1].span, "..")); - } - if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { - span_lint_and_sugg( - cx, - IF_LET_SOME_RESULT, - expr.span, - "Matching on `Some` with `ok()` is redundant", - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), - sugg, - applicability, - ); - } - } - } - } -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index eee16fcd312..c6339daf2eb 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -705,7 +705,7 @@ pub const ALL_LINTS: [Lint; 347] = [ group: "style", desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", deprecation: None, - module: "ok_if_let", + module: "if_let_some_result", }, Lint { name: "if_not_else", diff --git a/tests/ui/if_let_some_result.fixed b/tests/ui/if_let_some_result.fixed new file mode 100644 index 00000000000..439c749f995 --- /dev/null +++ b/tests/ui/if_let_some_result.fixed @@ -0,0 +1,34 @@ +// run-rustfix + +#![warn(clippy::if_let_some_result)] + +fn str_to_int(x: &str) -> i32 { + if let Ok(y) = x.parse() { + y + } else { + 0 + } +} + +fn str_to_int_ok(x: &str) -> i32 { + if let Ok(y) = x.parse() { + y + } else { + 0 + } +} + +fn nested_some_no_else(x: &str) -> i32 { + { + if let Ok(y) = x.parse() { + return y; + }; + 0 + } +} + +fn main() { + let _ = str_to_int("1"); + let _ = str_to_int_ok("2"); + let _ = nested_some_no_else("3"); +} diff --git a/tests/ui/if_let_some_result.rs b/tests/ui/if_let_some_result.rs new file mode 100644 index 00000000000..83f6ce1d330 --- /dev/null +++ b/tests/ui/if_let_some_result.rs @@ -0,0 +1,34 @@ +// run-rustfix + +#![warn(clippy::if_let_some_result)] + +fn str_to_int(x: &str) -> i32 { + if let Some(y) = x.parse().ok() { + y + } else { + 0 + } +} + +fn str_to_int_ok(x: &str) -> i32 { + if let Ok(y) = x.parse() { + y + } else { + 0 + } +} + +fn nested_some_no_else(x: &str) -> i32 { + { + if let Some(y) = x.parse().ok() { + return y; + }; + 0 + } +} + +fn main() { + let _ = str_to_int("1"); + let _ = str_to_int_ok("2"); + let _ = nested_some_no_else("3"); +} diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr new file mode 100644 index 00000000000..6925dfa0bf9 --- /dev/null +++ b/tests/ui/if_let_some_result.stderr @@ -0,0 +1,37 @@ +error: Matching on `Some` with `ok()` is redundant + --> $DIR/if_let_some_result.rs:6:5 + | +LL | / if let Some(y) = x.parse().ok() { +LL | | y +LL | | } else { +LL | | 0 +LL | | } + | |_____^ + | + = note: `-D clippy::if-let-some-result` implied by `-D warnings` +help: Consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x.parse() { +LL | y +LL | } else { +LL | 0 +LL | } + | + +error: Matching on `Some` with `ok()` is redundant + --> $DIR/if_let_some_result.rs:23:9 + | +LL | / if let Some(y) = x.parse().ok() { +LL | | return y; +LL | | }; + | |_________^ + | +help: Consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x.parse() { +LL | return y; +LL | }; + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/ok_if_let.fixed b/tests/ui/ok_if_let.fixed deleted file mode 100644 index 439c749f995..00000000000 --- a/tests/ui/ok_if_let.fixed +++ /dev/null @@ -1,34 +0,0 @@ -// run-rustfix - -#![warn(clippy::if_let_some_result)] - -fn str_to_int(x: &str) -> i32 { - if let Ok(y) = x.parse() { - y - } else { - 0 - } -} - -fn str_to_int_ok(x: &str) -> i32 { - if let Ok(y) = x.parse() { - y - } else { - 0 - } -} - -fn nested_some_no_else(x: &str) -> i32 { - { - if let Ok(y) = x.parse() { - return y; - }; - 0 - } -} - -fn main() { - let _ = str_to_int("1"); - let _ = str_to_int_ok("2"); - let _ = nested_some_no_else("3"); -} diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs deleted file mode 100644 index 83f6ce1d330..00000000000 --- a/tests/ui/ok_if_let.rs +++ /dev/null @@ -1,34 +0,0 @@ -// run-rustfix - -#![warn(clippy::if_let_some_result)] - -fn str_to_int(x: &str) -> i32 { - if let Some(y) = x.parse().ok() { - y - } else { - 0 - } -} - -fn str_to_int_ok(x: &str) -> i32 { - if let Ok(y) = x.parse() { - y - } else { - 0 - } -} - -fn nested_some_no_else(x: &str) -> i32 { - { - if let Some(y) = x.parse().ok() { - return y; - }; - 0 - } -} - -fn main() { - let _ = str_to_int("1"); - let _ = str_to_int_ok("2"); - let _ = nested_some_no_else("3"); -} diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr deleted file mode 100644 index 4aa6057ba47..00000000000 --- a/tests/ui/ok_if_let.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:6:5 - | -LL | / if let Some(y) = x.parse().ok() { -LL | | y -LL | | } else { -LL | | 0 -LL | | } - | |_____^ - | - = note: `-D clippy::if-let-some-result` implied by `-D warnings` -help: Consider matching on `Ok(y)` and removing the call to `ok` instead - | -LL | if let Ok(y) = x.parse() { -LL | y -LL | } else { -LL | 0 -LL | } - | - -error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:23:9 - | -LL | / if let Some(y) = x.parse().ok() { -LL | | return y; -LL | | }; - | |_________^ - | -help: Consider matching on `Ok(y)` and removing the call to `ok` instead - | -LL | if let Ok(y) = x.parse() { -LL | return y; -LL | }; - | - -error: aborting due to 2 previous errors - -- cgit 1.4.1-3-g733a5 From 95c369fa9168d2eee08d1a693dc1c63872fe46c0 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Mon, 20 Jan 2020 10:54:54 +0900 Subject: Add `skip_while_next` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 3 +++ clippy_lints/src/methods/mod.rs | 39 ++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 ++++++++- tests/ui/auxiliary/option_helpers.rs | 4 ++++ tests/ui/skip_while_next.rs | 29 +++++++++++++++++++++++++++ tests/ui/skip_while_next.stderr | 20 ++++++++++++++++++ 8 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 tests/ui/skip_while_next.rs create mode 100644 tests/ui/skip_while_next.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 11d745a4c23..f7e8a4534de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1285,6 +1285,7 @@ Released 2018-09-13 [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add diff --git a/README.md b/README.md index 7b1d14e9afc..d752e5b4cc1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 347 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 348 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 497146772a5..962ff38eb6c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -645,6 +645,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, &methods::SINGLE_CHAR_PATTERN, + &methods::SKIP_WHILE_NEXT, &methods::STRING_EXTEND_CHARS, &methods::SUSPICIOUS_MAP, &methods::TEMPORARY_CSTRING_AS_PTR, @@ -1223,6 +1224,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), LintId::of(&methods::SINGLE_CHAR_PATTERN), + LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::SUSPICIOUS_MAP), LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR), @@ -1475,6 +1477,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::OPTION_AND_THEN_SOME), LintId::of(&methods::SEARCH_IS_SOME), + LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::SUSPICIOUS_MAP), LintId::of(&methods::UNNECESSARY_FILTER_MAP), LintId::of(&methods::USELESS_ASREF), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ed37d3411b5..8dfebb56f30 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -375,6 +375,29 @@ declare_clippy_lint! { "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.skip_while(condition).next()`. + /// + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.find(!condition)`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # let vec = vec![1]; + /// vec.iter().skip_while(|x| **x == 0).next(); + /// ``` + /// Could be written as + /// ```rust + /// # let vec = vec![1]; + /// vec.iter().find(|x| **x != 0); + /// ``` + pub SKIP_WHILE_NEXT, + complexity, + "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// @@ -1192,6 +1215,7 @@ declare_lint_pass!(Methods => [ SEARCH_IS_SOME, TEMPORARY_CSTRING_AS_PTR, FILTER_NEXT, + SKIP_WHILE_NEXT, FILTER_MAP, FILTER_MAP_NEXT, FLAT_MAP_IDENTITY, @@ -1237,6 +1261,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), ["and_then", ..] => lint_option_and_then_some(cx, expr, arg_lists[0]), ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), + ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), @@ -2530,6 +2555,20 @@ fn lint_filter_next<'a, 'tcx>( } } +/// lint use of `skip_while().next()` for `Iterators` +fn lint_skip_while_next<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &'tcx hir::Expr<'_>, + _skip_while_args: &'tcx [hir::Expr<'_>], +) { + // lint if caller of `.skip_while().next()` is an Iterator + if match_trait_method(cx, expr, &paths::ITERATOR) { + let msg = "called `skip_while(p).next()` on an `Iterator`. \ + This is more succinctly expressed by calling `.find(!p)` instead."; + span_lint(cx, SKIP_WHILE_NEXT, expr.span, msg); + } +} + /// lint use of `filter().map()` for `Iterators` fn lint_filter_map<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c6339daf2eb..dcdfd015393 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 347] = [ +pub const ALL_LINTS: [Lint; 348] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1862,6 +1862,13 @@ pub const ALL_LINTS: [Lint; 347] = [ deprecation: None, module: "matches", }, + Lint { + name: "skip_while_next", + group: "complexity", + desc: "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`", + deprecation: None, + module: "methods", + }, Lint { name: "slow_vector_initialization", group: "perf", diff --git a/tests/ui/auxiliary/option_helpers.rs b/tests/ui/auxiliary/option_helpers.rs index 33195211968..ed11c41e21c 100644 --- a/tests/ui/auxiliary/option_helpers.rs +++ b/tests/ui/auxiliary/option_helpers.rs @@ -44,4 +44,8 @@ impl IteratorFalsePositives { pub fn skip(self, _: usize) -> IteratorFalsePositives { self } + + pub fn skip_while(self) -> IteratorFalsePositives { + self + } } diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs new file mode 100644 index 00000000000..a522c0f08b2 --- /dev/null +++ b/tests/ui/skip_while_next.rs @@ -0,0 +1,29 @@ +// aux-build:option_helpers.rs + +#![warn(clippy::skip_while_next)] +#![allow(clippy::blacklisted_name)] + +extern crate option_helpers; +use option_helpers::IteratorFalsePositives; + +#[rustfmt::skip] +fn skip_while_next() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + + // Single-line case. + let _ = v.iter().skip_while(|&x| *x < 0).next(); + + // Multi-line case. + let _ = v.iter().skip_while(|&x| { + *x < 0 + } + ).next(); + + // Check that hat we don't lint if the caller is not an `Iterator`. + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.skip_while().next(); +} + +fn main() { + skip_while_next(); +} diff --git a/tests/ui/skip_while_next.stderr b/tests/ui/skip_while_next.stderr new file mode 100644 index 00000000000..2ce88ac23a5 --- /dev/null +++ b/tests/ui/skip_while_next.stderr @@ -0,0 +1,20 @@ +error: called `skip_while(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(!p)` instead. + --> $DIR/skip_while_next.rs:14:13 + | +LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::skip-while-next` implied by `-D warnings` + +error: called `skip_while(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(!p)` instead. + --> $DIR/skip_while_next.rs:17:13 + | +LL | let _ = v.iter().skip_while(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).next(); + | |___________________________^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 796958c7e2afb765d0354007cb89c1312d8899e9 Mon Sep 17 00:00:00 2001 From: Areredify <misha-babenko@yandex.ru> Date: Mon, 23 Dec 2019 07:48:15 +0300 Subject: add `option_as_ref_deref` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/methods/mod.rs | 103 +++++++++++++++++++++++++++++++++++- clippy_lints/src/utils/paths.rs | 8 +++ src/lintlist/mod.rs | 9 +++- tests/ui/option_as_ref_deref.fixed | 38 +++++++++++++ tests/ui/option_as_ref_deref.rs | 41 ++++++++++++++ tests/ui/option_as_ref_deref.stderr | 92 ++++++++++++++++++++++++++++++++ 9 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 tests/ui/option_as_ref_deref.fixed create mode 100644 tests/ui/option_as_ref_deref.rs create mode 100644 tests/ui/option_as_ref_deref.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e8a4534de..78020c2dac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1227,6 +1227,7 @@ Released 2018-09-13 [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some +[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn diff --git a/README.md b/README.md index d752e5b4cc1..8f65ff94ca8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 348 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 349 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 962ff38eb6c..0c7717c4f19 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -633,6 +633,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::NEW_RET_NO_SELF, &methods::OK_EXPECT, &methods::OPTION_AND_THEN_SOME, + &methods::OPTION_AS_REF_DEREF, &methods::OPTION_EXPECT_USED, &methods::OPTION_MAP_OR_NONE, &methods::OPTION_MAP_UNWRAP_OR, @@ -1219,6 +1220,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AND_THEN_SOME), + LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::OR_FUN_CALL), LintId::of(&methods::SEARCH_IS_SOME), @@ -1476,6 +1478,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::OPTION_AND_THEN_SOME), + LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::SUSPICIOUS_MAP), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6a5d6d64cf4..ae7b1e3485f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1189,6 +1189,27 @@ declare_clippy_lint! { "`FileType::is_file` is not recommended to test for readable file type" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str). + /// + /// **Why is this bad?** Readability, this can be written more concisely as a + /// single method call. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// opt.as_ref().map(String::as_str) + /// ``` + /// Can be written as + /// ```rust,ignore + /// opt.as_deref() + /// ``` + pub OPTION_AS_REF_DEREF, + complexity, + "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -1238,10 +1259,11 @@ declare_lint_pass!(Methods => [ MANUAL_SATURATING_ARITHMETIC, ZST_OFFSET, FILETYPE_IS_FILE, + OPTION_AS_REF_DEREF, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { - #[allow(clippy::cognitive_complexity)] + #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { if in_macro(expr.span) { return; @@ -1303,6 +1325,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), + ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), + ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), _ => {}, } @@ -3062,6 +3086,83 @@ fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) { ); } +/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s +fn lint_option_as_ref_deref<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + expr: &hir::Expr<'_>, + as_ref_args: &[hir::Expr<'_>], + map_args: &[hir::Expr<'_>], + is_mut: bool, +) { + let option_ty = cx.tables.expr_ty(&as_ref_args[0]); + if !match_type(cx, option_ty, &paths::OPTION) { + return; + } + + let deref_aliases: [&[&str]; 9] = [ + &paths::DEREF_TRAIT_METHOD, + &paths::DEREF_MUT_TRAIT_METHOD, + &paths::CSTRING_AS_C_STR, + &paths::OS_STRING_AS_OS_STR, + &paths::PATH_BUF_AS_PATH, + &paths::STRING_AS_STR, + &paths::STRING_AS_MUT_STR, + &paths::VEC_AS_SLICE, + &paths::VEC_AS_MUT_SLICE, + ]; + + let is_deref = match map_args[1].kind { + hir::ExprKind::Path(ref expr_qpath) => deref_aliases.iter().any(|path| match_qpath(expr_qpath, path)), + hir::ExprKind::Closure(_, _, body_id, _, _) => { + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); + if_chain! { + if let hir::ExprKind::MethodCall(_, _, args) = &closure_expr.kind; + if args.len() == 1; + if let hir::ExprKind::Path(qpath) = &args[0].kind; + if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id); + if closure_body.params[0].pat.hir_id == local_id; + let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>(); + if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj; + then { + let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap(); + deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) + } else { + false + } + } + }, + + _ => false, + }; + + if is_deref { + let current_method = if is_mut { + ".as_mut().map(DerefMut::deref_mut)" + } else { + ".as_ref().map(Deref::deref)" + }; + let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" }; + let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint); + let suggestion = format!("try using {} instead", method_hint); + + let msg = format!( + "called `{0}` (or with one of deref aliases) on an Option value. \ + This can be done more directly by calling `{1}` instead", + current_method, hint + ); + span_lint_and_sugg( + cx, + OPTION_AS_REF_DEREF, + expr.span, + &msg, + &suggestion, + hint, + Applicability::MachineApplicable, + ); + } +} + /// Given a `Result<T, E>` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> { match ty.kind { diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 4f8fe02dfd2..7980a02b3ba 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -18,8 +18,10 @@ pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"]; +pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; +pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; @@ -63,10 +65,12 @@ pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"]; pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"]; +pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARTIAL_ORD: [&str; 3] = ["core", "cmp", "PartialOrd"]; pub const PATH: [&str; 3] = ["std", "path", "Path"]; pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; +pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const PTR_NULL: [&str; 2] = ["ptr", "null"]; pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"]; @@ -105,6 +109,8 @@ pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; pub const STRING: [&str; 3] = ["alloc", "string", "String"]; +pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; +pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; @@ -114,6 +120,8 @@ pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"]; pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"]; pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; +pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; +pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 6858c3e15c8..5dbcb4483f2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 348] = [ +pub const ALL_LINTS: [Lint; 349] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1470,6 +1470,13 @@ pub const ALL_LINTS: [Lint; 348] = [ deprecation: None, module: "methods", }, + Lint { + name: "option_as_ref_deref", + group: "complexity", + desc: "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`", + deprecation: None, + module: "methods", + }, Lint { name: "option_expect_used", group: "restriction", diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed new file mode 100644 index 00000000000..973e5b308a2 --- /dev/null +++ b/tests/ui/option_as_ref_deref.fixed @@ -0,0 +1,38 @@ +// run-rustfix + +#![allow(unused_imports, clippy::redundant_clone)] +#![warn(clippy::option_as_ref_deref)] + +use std::ffi::{CString, OsString}; +use std::ops::{Deref, DerefMut}; +use std::path::PathBuf; + +fn main() { + let mut opt = Some(String::from("123")); + + let _ = opt.clone().as_deref().map(str::len); + + #[rustfmt::skip] + let _ = opt.clone().as_deref() + .map(str::len); + + let _ = opt.as_deref_mut(); + + let _ = opt.as_deref(); + let _ = opt.as_deref(); + let _ = opt.as_deref_mut(); + let _ = opt.as_deref_mut(); + let _ = Some(CString::new(vec![]).unwrap()).as_deref(); + let _ = Some(OsString::new()).as_deref(); + let _ = Some(PathBuf::new()).as_deref(); + let _ = Some(Vec::<()>::new()).as_deref(); + let _ = Some(Vec::<()>::new()).as_deref_mut(); + + let _ = opt.as_deref(); + let _ = opt.clone().as_deref_mut().map(|x| x.len()); + + let vc = vec![String::new()]; + let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted + + let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted +} diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs new file mode 100644 index 00000000000..baad85ab908 --- /dev/null +++ b/tests/ui/option_as_ref_deref.rs @@ -0,0 +1,41 @@ +// run-rustfix + +#![allow(unused_imports, clippy::redundant_clone)] +#![warn(clippy::option_as_ref_deref)] + +use std::ffi::{CString, OsString}; +use std::ops::{Deref, DerefMut}; +use std::path::PathBuf; + +fn main() { + let mut opt = Some(String::from("123")); + + let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); + + #[rustfmt::skip] + let _ = opt.clone() + .as_ref().map( + Deref::deref + ) + .map(str::len); + + let _ = opt.as_mut().map(DerefMut::deref_mut); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); + let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); + let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); + let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); + let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); + let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); + + let _ = opt.as_ref().map(|x| x.deref()); + let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); + + let vc = vec![String::new()]; + let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted + + let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted +} diff --git a/tests/ui/option_as_ref_deref.stderr b/tests/ui/option_as_ref_deref.stderr new file mode 100644 index 00000000000..09a0fa058e6 --- /dev/null +++ b/tests/ui/option_as_ref_deref.stderr @@ -0,0 +1,92 @@ +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead + --> $DIR/option_as_ref_deref.rs:13:13 + | +LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()` + | + = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead + --> $DIR/option_as_ref_deref.rs:16:13 + | +LL | let _ = opt.clone() + | _____________^ +LL | | .as_ref().map( +LL | | Deref::deref +LL | | ) + | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` + +error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead + --> $DIR/option_as_ref_deref.rs:22:13 + | +LL | let _ = opt.as_mut().map(DerefMut::deref_mut); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead + --> $DIR/option_as_ref_deref.rs:24:13 + | +LL | let _ = opt.as_ref().map(String::as_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead + --> $DIR/option_as_ref_deref.rs:25:13 + | +LL | let _ = opt.as_ref().map(|x| x.as_str()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + +error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead + --> $DIR/option_as_ref_deref.rs:26:13 + | +LL | let _ = opt.as_mut().map(String::as_mut_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + +error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead + --> $DIR/option_as_ref_deref.rs:27:13 + | +LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead + --> $DIR/option_as_ref_deref.rs:28:13 + | +LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead + --> $DIR/option_as_ref_deref.rs:29:13 + | +LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead + --> $DIR/option_as_ref_deref.rs:30:13 + | +LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead + --> $DIR/option_as_ref_deref.rs:31:13 + | +LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` + +error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead + --> $DIR/option_as_ref_deref.rs:32:13 + | +LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` + +error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead + --> $DIR/option_as_ref_deref.rs:34:13 + | +LL | let _ = opt.as_ref().map(|x| x.deref()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` + +error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead + --> $DIR/option_as_ref_deref.rs:35:13 + | +LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` + +error: aborting due to 14 previous errors + -- cgit 1.4.1-3-g733a5 From 512efbea2321dafd19d30eacb9d8f9d21fcedae2 Mon Sep 17 00:00:00 2001 From: xiongmao86 <xiongmao86dev@sina.com> Date: Thu, 30 Jan 2020 00:21:29 +0800 Subject: Declare lint and implement lint logic. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/single_component_path_imports.rs | 61 +++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/single_component_path_imports.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 78020c2dac6..d5dbbabb3c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1284,6 +1284,7 @@ Released 2018-09-13 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next diff --git a/README.md b/README.md index 8f65ff94ca8..0cb14eda6a8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 349 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 91240362445..7008c6d6839 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -284,6 +284,7 @@ pub mod replace_consts; pub mod returns; pub mod serde_api; pub mod shadow; +pub mod single_component_path_imports; pub mod slow_vector_initialization; pub mod strings; pub mod suspicious_trait_impl; @@ -741,6 +742,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_REUSE, &shadow::SHADOW_SAME, &shadow::SHADOW_UNRELATED, + &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, @@ -993,6 +995,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); + store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1296,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), @@ -1431,6 +1435,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), + LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs new file mode 100644 index 00000000000..eb3261bebe3 --- /dev/null +++ b/clippy_lints/src/single_component_path_imports.rs @@ -0,0 +1,61 @@ +use crate::utils::span_lint_and_sugg; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::edition::Edition; +use syntax::ast::{Item, ItemKind, UseTreeKind}; + +declare_clippy_lint! { + /// **What it does:** Checking for imports with single component use path. + /// + /// **Why is this bad?** Import with single component use path such as `use cratename;` + /// is not necessary, and thus should be removed. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust, ignore + /// use regex; + /// + /// fn main() { + /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); + /// } + /// ``` + /// Better as + /// ```rust, ignore + /// fn main() { + /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); + /// } + /// ``` + pub SINGLE_COMPONENT_PATH_IMPORTS, + style, + "imports with single component path are redundant" +} + +declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]); + +impl EarlyLintPass for SingleComponentPathImports { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if_chain! { + if cx.sess.opts.edition == Edition::Edition2018; + if !item.vis.node.is_pub(); + if let ItemKind::Use(use_tree) = &item.kind; + if let segments = &use_tree.prefix.segments; + if segments.len() == 1; + if let UseTreeKind::Simple(None, _, _) = use_tree.kind; + then { + span_lint_and_sugg( + cx, + SINGLE_COMPONENT_PATH_IMPORTS, + item.span, + "this import is redundant", + "remove it entirely", + String::new(), + Applicability::MachineApplicable + ); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5dbcb4483f2..b762c8d1395 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 349] = [ +pub const ALL_LINTS: [Lint; 350] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1855,6 +1855,13 @@ pub const ALL_LINTS: [Lint; 349] = [ deprecation: None, module: "methods", }, + Lint { + name: "single_component_path_imports", + group: "style", + desc: "imports with single component path are redundant", + deprecation: None, + module: "single_component_path_imports", + }, Lint { name: "single_match", group: "style", -- cgit 1.4.1-3-g733a5 From d1f862171150f91c114eb126c559e90873c8dc00 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko <misha-babenko@yandex.ru> Date: Mon, 27 Jan 2020 17:34:30 +0300 Subject: add lint --- CHANGELOG.md | 1 + clippy_lints/src/let_underscore.rs | 79 +++++++++++++++++++++++++++++--------- clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/utils/paths.rs | 3 ++ src/lintlist/mod.rs | 7 ++++ tests/ui/let_underscore.rs | 7 ++++ tests/ui/let_underscore.stderr | 27 ++++++++++++- 7 files changed, 108 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index d5dbbabb3c5..32427225769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1153,6 +1153,7 @@ Released 2018-09-13 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 2df3cccb83b..4d746596c37 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -4,7 +4,7 @@ use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, span_lint_and_help}; +use crate::utils::{is_must_use_func_call, is_must_use_ty, match_def_path, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = <expr>` @@ -30,7 +30,35 @@ declare_clippy_lint! { "non-binding let on a `#[must_use]` expression" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE]); +declare_clippy_lint! { + /// **What it does:** Checks for `let _ = sync_primitive.lock()` + /// + /// **Why is this bad?** This statement locks the synchronization + /// primitive and immediately drops the lock, which is probably + /// not intended. To extend lock lifetime to the end of the scope, + /// use an underscore-prefixed name instead (i.e. _lock). + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// Bad: + /// ```rust,ignore + /// let _ = mutex.lock(); + /// ``` + /// + /// Good: + /// ```rust,ignore + /// let _lock = mutex.lock(); + /// ``` + pub LET_UNDERSCORE_LOCK, + correctness, + "non-binding let on a synchronization lock" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]); + +const LOCK_METHODS_PATHS: [&[&str]; 3] = [&paths::MUTEX_LOCK, &paths::RWLOCK_READ, &paths::RWLOCK_WRITE]; impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &Stmt<'_>) { @@ -43,22 +71,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { if let PatKind::Wild = local.pat.kind; if let Some(ref init) = local.init; then { - if is_must_use_ty(cx, cx.tables.expr_ty(init)) { - span_lint_and_help( - cx, - LET_UNDERSCORE_MUST_USE, - stmt.span, - "non-binding let on an expression with `#[must_use]` type", - "consider explicitly using expression value" - ) - } else if is_must_use_func_call(cx, init) { - span_lint_and_help( - cx, - LET_UNDERSCORE_MUST_USE, - stmt.span, - "non-binding let on a result of a `#[must_use]` function", - "consider explicitly using function result" - ) + if_chain! { + if let ExprKind::MethodCall(_, _, _) = init.kind; + let method_did = cx.tables.type_dependent_def_id(init.hir_id).unwrap(); + if LOCK_METHODS_PATHS.iter().any(|path| match_def_path(cx, method_did, path)); + then { + span_lint_and_help( + cx, + LET_UNDERSCORE_LOCK, + stmt.span, + "non-binding let on an a synchronization lock", + "consider using an underscore-prefixed named binding" + ) + } else { + if is_must_use_ty(cx, cx.tables.expr_ty(init)) { + span_lint_and_help( + cx, + LET_UNDERSCORE_MUST_USE, + stmt.span, + "non-binding let on an expression with `#[must_use]` type", + "consider explicitly using expression value" + ) + } else if is_must_use_func_call(cx, init) { + span_lint_and_help( + cx, + LET_UNDERSCORE_MUST_USE, + stmt.span, + "non-binding let on a result of a `#[must_use]` function", + "consider explicitly using function result" + ) + } + } } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7008c6d6839..443a9c7e9d9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -566,6 +566,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, + &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, &lifetimes::EXTRA_UNUSED_LIFETIMES, &lifetimes::NEEDLESS_LIFETIMES, @@ -1171,6 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), @@ -1556,6 +1558,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::INFINITE_ITER), LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), LintId::of(&loops::FOR_LOOP_OVER_OPTION), LintId::of(&loops::FOR_LOOP_OVER_RESULT), diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 7980a02b3ba..ff8acb321a4 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -58,6 +58,7 @@ pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; pub const MEM_UNINITIALIZED: [&str; 3] = ["core", "mem", "uninitialized"]; pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"]; pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"]; +pub const MUTEX_LOCK: [&str; 5] = ["std", "sync", "mutex", "Mutex", "lock"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; pub const OPTION: [&str; 3] = ["core", "option", "Option"]; @@ -100,6 +101,8 @@ pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"]; pub const RESULT: [&str; 3] = ["core", "result", "Result"]; pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; +pub const RWLOCK_READ: [&str; 5] = ["std", "sync", "rwlock", "RwLock", "read"]; +pub const RWLOCK_WRITE: [&str; 5] = ["std", "sync", "rwlock", "RwLock", "write"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"]; pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b762c8d1395..1f7d450ab66 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -959,6 +959,13 @@ pub const ALL_LINTS: [Lint; 350] = [ deprecation: None, module: "returns", }, + Lint { + name: "let_underscore_lock", + group: "correctness", + desc: "non-binding let on a synchronization lock", + deprecation: None, + module: "let_underscore", + }, Lint { name: "let_underscore_must_use", group: "restriction", diff --git a/tests/ui/let_underscore.rs b/tests/ui/let_underscore.rs index 7f481542fa7..cfe207251f4 100644 --- a/tests/ui/let_underscore.rs +++ b/tests/ui/let_underscore.rs @@ -88,4 +88,11 @@ fn main() { let _ = a.map(|_| ()); let _ = a; + + let m = std::sync::Mutex::new(()); + let rw = std::sync::RwLock::new(()); + + let _ = m.lock(); + let _ = rw.read(); + let _ = rw.write(); } diff --git a/tests/ui/let_underscore.stderr b/tests/ui/let_underscore.stderr index e7d5f712bec..bcd560fe493 100644 --- a/tests/ui/let_underscore.stderr +++ b/tests/ui/let_underscore.stderr @@ -95,5 +95,30 @@ LL | let _ = a; | = help: consider explicitly using expression value -error: aborting due to 12 previous errors +error: non-binding let on an a synchronization lock + --> $DIR/let_underscore.rs:95:5 + | +LL | let _ = m.lock(); + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_lock)]` on by default + = help: consider using an underscore-prefixed named binding + +error: non-binding let on an a synchronization lock + --> $DIR/let_underscore.rs:96:5 + | +LL | let _ = rw.read(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding + +error: non-binding let on an a synchronization lock + --> $DIR/let_underscore.rs:97:5 + | +LL | let _ = rw.write(); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding + +error: aborting due to 15 previous errors -- cgit 1.4.1-3-g733a5 From 9b88a2b295e51803a74ad8bb852549693815e0c0 Mon Sep 17 00:00:00 2001 From: Mikhail Babenko <misha-babenko@yandex.ru> Date: Tue, 28 Jan 2020 12:28:11 +0300 Subject: decouple 'let_underscore' tests --- README.md | 2 +- clippy_lints/src/let_underscore.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/let_underscore.rs | 98 ------------------------- tests/ui/let_underscore.stderr | 124 -------------------------------- tests/ui/let_underscore_lock.rs | 10 +++ tests/ui/let_underscore_lock.stderr | 27 +++++++ tests/ui/let_underscore_must_use.rs | 91 +++++++++++++++++++++++ tests/ui/let_underscore_must_use.stderr | 99 +++++++++++++++++++++++++ 9 files changed, 230 insertions(+), 225 deletions(-) delete mode 100644 tests/ui/let_underscore.rs delete mode 100644 tests/ui/let_underscore.stderr create mode 100644 tests/ui/let_underscore_lock.rs create mode 100644 tests/ui/let_underscore_lock.stderr create mode 100644 tests/ui/let_underscore_must_use.rs create mode 100644 tests/ui/let_underscore_must_use.stderr (limited to 'src') diff --git a/README.md b/README.md index 0cb14eda6a8..b68eb3ed7fa 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 351 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 4d746596c37..a43674316a1 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore { cx, LET_UNDERSCORE_LOCK, stmt.span, - "non-binding let on an a synchronization lock", + "non-binding let on a synchronization lock", "consider using an underscore-prefixed named binding" ) } else { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1f7d450ab66..0c5b8146b13 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 350] = [ +pub const ALL_LINTS: [Lint; 351] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", diff --git a/tests/ui/let_underscore.rs b/tests/ui/let_underscore.rs deleted file mode 100644 index cfe207251f4..00000000000 --- a/tests/ui/let_underscore.rs +++ /dev/null @@ -1,98 +0,0 @@ -#![warn(clippy::let_underscore_must_use)] - -// Debug implementations can fire this lint, -// so we shouldn't lint external macros -#[derive(Debug)] -struct Foo { - field: i32, -} - -#[must_use] -fn f() -> u32 { - 0 -} - -fn g() -> Result<u32, u32> { - Ok(0) -} - -#[must_use] -fn l<T>(x: T) -> T { - x -} - -fn h() -> u32 { - 0 -} - -struct S {} - -impl S { - #[must_use] - pub fn f(&self) -> u32 { - 0 - } - - pub fn g(&self) -> Result<u32, u32> { - Ok(0) - } - - fn k(&self) -> u32 { - 0 - } - - #[must_use] - fn h() -> u32 { - 0 - } - - fn p() -> Result<u32, u32> { - Ok(0) - } -} - -trait Trait { - #[must_use] - fn a() -> u32; -} - -impl Trait for S { - fn a() -> u32 { - 0 - } -} - -fn main() { - let _ = f(); - let _ = g(); - let _ = h(); - let _ = l(0_u32); - - let s = S {}; - - let _ = s.f(); - let _ = s.g(); - let _ = s.k(); - - let _ = S::h(); - let _ = S::p(); - - let _ = S::a(); - - let _ = if true { Ok(()) } else { Err(()) }; - - let a = Result::<(), ()>::Ok(()); - - let _ = a.is_ok(); - - let _ = a.map(|_| ()); - - let _ = a; - - let m = std::sync::Mutex::new(()); - let rw = std::sync::RwLock::new(()); - - let _ = m.lock(); - let _ = rw.read(); - let _ = rw.write(); -} diff --git a/tests/ui/let_underscore.stderr b/tests/ui/let_underscore.stderr deleted file mode 100644 index bcd560fe493..00000000000 --- a/tests/ui/let_underscore.stderr +++ /dev/null @@ -1,124 +0,0 @@ -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:66:5 - | -LL | let _ = f(); - | ^^^^^^^^^^^^ - | - = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` - = help: consider explicitly using function result - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:67:5 - | -LL | let _ = g(); - | ^^^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:69:5 - | -LL | let _ = l(0_u32); - | ^^^^^^^^^^^^^^^^^ - | - = help: consider explicitly using function result - -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:73:5 - | -LL | let _ = s.f(); - | ^^^^^^^^^^^^^^ - | - = help: consider explicitly using function result - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:74:5 - | -LL | let _ = s.g(); - | ^^^^^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:77:5 - | -LL | let _ = S::h(); - | ^^^^^^^^^^^^^^^ - | - = help: consider explicitly using function result - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:78:5 - | -LL | let _ = S::p(); - | ^^^^^^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:80:5 - | -LL | let _ = S::a(); - | ^^^^^^^^^^^^^^^ - | - = help: consider explicitly using function result - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:82:5 - | -LL | let _ = if true { Ok(()) } else { Err(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore.rs:86:5 - | -LL | let _ = a.is_ok(); - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider explicitly using function result - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:88:5 - | -LL | let _ = a.map(|_| ()); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore.rs:90:5 - | -LL | let _ = a; - | ^^^^^^^^^^ - | - = help: consider explicitly using expression value - -error: non-binding let on an a synchronization lock - --> $DIR/let_underscore.rs:95:5 - | -LL | let _ = m.lock(); - | ^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_lock)]` on by default - = help: consider using an underscore-prefixed named binding - -error: non-binding let on an a synchronization lock - --> $DIR/let_underscore.rs:96:5 - | -LL | let _ = rw.read(); - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding - -error: non-binding let on an a synchronization lock - --> $DIR/let_underscore.rs:97:5 - | -LL | let _ = rw.write(); - | ^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding - -error: aborting due to 15 previous errors - diff --git a/tests/ui/let_underscore_lock.rs b/tests/ui/let_underscore_lock.rs new file mode 100644 index 00000000000..f4a33c36066 --- /dev/null +++ b/tests/ui/let_underscore_lock.rs @@ -0,0 +1,10 @@ +#![warn(clippy::let_underscore_lock)] + +fn main() { + let m = std::sync::Mutex::new(()); + let rw = std::sync::RwLock::new(()); + + let _ = m.lock(); + let _ = rw.read(); + let _ = rw.write(); +} diff --git a/tests/ui/let_underscore_lock.stderr b/tests/ui/let_underscore_lock.stderr new file mode 100644 index 00000000000..bd297f6020c --- /dev/null +++ b/tests/ui/let_underscore_lock.stderr @@ -0,0 +1,27 @@ +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:7:5 + | +LL | let _ = m.lock(); + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-lock` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:8:5 + | +LL | let _ = rw.read(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding + +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:9:5 + | +LL | let _ = rw.write(); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding + +error: aborting due to 3 previous errors + diff --git a/tests/ui/let_underscore_must_use.rs b/tests/ui/let_underscore_must_use.rs new file mode 100644 index 00000000000..7f481542fa7 --- /dev/null +++ b/tests/ui/let_underscore_must_use.rs @@ -0,0 +1,91 @@ +#![warn(clippy::let_underscore_must_use)] + +// Debug implementations can fire this lint, +// so we shouldn't lint external macros +#[derive(Debug)] +struct Foo { + field: i32, +} + +#[must_use] +fn f() -> u32 { + 0 +} + +fn g() -> Result<u32, u32> { + Ok(0) +} + +#[must_use] +fn l<T>(x: T) -> T { + x +} + +fn h() -> u32 { + 0 +} + +struct S {} + +impl S { + #[must_use] + pub fn f(&self) -> u32 { + 0 + } + + pub fn g(&self) -> Result<u32, u32> { + Ok(0) + } + + fn k(&self) -> u32 { + 0 + } + + #[must_use] + fn h() -> u32 { + 0 + } + + fn p() -> Result<u32, u32> { + Ok(0) + } +} + +trait Trait { + #[must_use] + fn a() -> u32; +} + +impl Trait for S { + fn a() -> u32 { + 0 + } +} + +fn main() { + let _ = f(); + let _ = g(); + let _ = h(); + let _ = l(0_u32); + + let s = S {}; + + let _ = s.f(); + let _ = s.g(); + let _ = s.k(); + + let _ = S::h(); + let _ = S::p(); + + let _ = S::a(); + + let _ = if true { Ok(()) } else { Err(()) }; + + let a = Result::<(), ()>::Ok(()); + + let _ = a.is_ok(); + + let _ = a.map(|_| ()); + + let _ = a; +} diff --git a/tests/ui/let_underscore_must_use.stderr b/tests/ui/let_underscore_must_use.stderr new file mode 100644 index 00000000000..447f2419e3b --- /dev/null +++ b/tests/ui/let_underscore_must_use.stderr @@ -0,0 +1,99 @@ +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:66:5 + | +LL | let _ = f(); + | ^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-must-use` implied by `-D warnings` + = help: consider explicitly using function result + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:67:5 + | +LL | let _ = g(); + | ^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:69:5 + | +LL | let _ = l(0_u32); + | ^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:73:5 + | +LL | let _ = s.f(); + | ^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:74:5 + | +LL | let _ = s.g(); + | ^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:77:5 + | +LL | let _ = S::h(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:78:5 + | +LL | let _ = S::p(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:80:5 + | +LL | let _ = S::a(); + | ^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:82:5 + | +LL | let _ = if true { Ok(()) } else { Err(()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on a result of a `#[must_use]` function + --> $DIR/let_underscore_must_use.rs:86:5 + | +LL | let _ = a.is_ok(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using function result + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:88:5 + | +LL | let _ = a.map(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: non-binding let on an expression with `#[must_use]` type + --> $DIR/let_underscore_must_use.rs:90:5 + | +LL | let _ = a; + | ^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: aborting due to 12 previous errors + -- cgit 1.4.1-3-g733a5 From 4d1a11d354c77213a98f76b07933ebb26822d017 Mon Sep 17 00:00:00 2001 From: Philipp Hansch <dev@phansch.net> Date: Thu, 30 Jan 2020 08:33:48 +0100 Subject: Deprecate util/dev in favor of cargo alias If you've been using `./util/dev` before, this now becomes `cargo dev`. The key part of this change is found in `.cargo/config`. This means one less shell script and a bit more cross-platform support for contributors. --- .cargo/config | 1 + .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- CONTRIBUTING.md | 2 +- ci/base-tests.sh | 4 ++-- clippy_dev/src/fmt.rs | 2 +- clippy_dev/src/lib.rs | 17 +++++++++++++---- clippy_dev/src/main.rs | 23 ++++++++++++----------- doc/adding_lints.md | 10 +++++----- src/lintlist/mod.rs | 2 +- tests/fmt.rs | 2 +- util/dev | 2 ++ 11 files changed, 41 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/.cargo/config b/.cargo/config index b4bc4418f1e..2bad3b9c57f 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,6 @@ [alias] uitest = "test --test compile-test" +dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" [build] rustflags = ["-Zunstable-options"] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b2713a8775e..97aa220afea 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,9 +15,9 @@ checked during review or continuous integration. - [ ] Followed [lint naming conventions][lint_naming] - [ ] Added passing UI tests (including committed `.stderr` file) - [ ] `cargo test` passes locally -- [ ] Executed `./util/dev update_lints` +- [ ] Executed `cargo dev update_lints` - [ ] Added lint documentation -- [ ] Run `./util/dev fmt` +- [ ] Run `cargo dev fmt` [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fcf984ccaaf..4a828051185 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,7 +105,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry) { The [`plugin::PluginRegistry`][plugin_registry] provides two methods to register lints: [register_early_lint_pass][reg_early_lint_pass] and [register_late_lint_pass][reg_late_lint_pass]. Both take an object that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in every single lint. -It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `util/dev update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time. +It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev update_lints` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time. ```rust // ./clippy_lints/src/else_if_without_else.rs diff --git a/ci/base-tests.sh b/ci/base-tests.sh index 010c8919752..125a566271d 100755 --- a/ci/base-tests.sh +++ b/ci/base-tests.sh @@ -22,8 +22,8 @@ cargo test --features deny-warnings ) # Perform various checks for lint registration -./util/dev update_lints --check -./util/dev --limit-stderr-length +cargo dev update_lints --check +cargo dev --limit-stderr-length # Check running clippy-driver without cargo ( diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 69cd046a855..0d950d5b9fe 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -88,7 +88,7 @@ pub fn run(check: bool, verbose: bool) { Ok(false) => { eprintln!(); eprintln!("Formatting check failed."); - eprintln!("Run `./util/dev fmt` to update formatting."); + eprintln!("Run `cargo dev fmt` to update formatting."); 1 }, Err(err) => { diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 3aae3e53317..1aa34ce651f 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; use std::ffi::OsStr; use std::fs; use std::io::prelude::*; +use std::path::{Path, PathBuf}; use walkdir::WalkDir; lazy_static! { @@ -205,7 +206,8 @@ fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item = Lint> { fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> { // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. - WalkDir::new("../clippy_lints/src") + let path = clippy_project_dir().join("clippy_lints/src"); + WalkDir::new(path) .into_iter() .filter_map(std::result::Result::ok) .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) @@ -225,7 +227,7 @@ pub struct FileChange { /// See `replace_region_in_text` for documentation of the other options. #[allow(clippy::expect_fun_call)] pub fn replace_region_in_file<F>( - path: &str, + path: &Path, start: &str, end: &str, replace_start: bool, @@ -235,14 +237,15 @@ pub fn replace_region_in_file<F>( where F: Fn() -> Vec<String>, { - let mut f = fs::File::open(path).expect(&format!("File not found: {}", path)); + let path = clippy_project_dir().join(path); + let mut f = fs::File::open(&path).expect(&format!("File not found: {}", path.to_string_lossy())); let mut contents = String::new(); f.read_to_string(&mut contents) .expect("Something went wrong reading the file"); let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); if write_back { - let mut f = fs::File::create(path).expect(&format!("File not found: {}", path)); + let mut f = fs::File::create(&path).expect(&format!("File not found: {}", path.to_string_lossy())); f.write_all(file_change.new_lines.as_bytes()) .expect("Unable to write file"); // Ensure we write the changes with a trailing newline so that @@ -318,6 +321,12 @@ where } } +/// Returns the path to the Clippy project directory +fn clippy_project_dir() -> PathBuf { + let clippy_dev_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + clippy_dev_dir.parent().unwrap().to_path_buf() +} + #[test] fn test_parse_contents() { let result: Vec<Lint> = parse_contents( diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 58b4f87e872..7369db1f078 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -2,6 +2,7 @@ use clap::{App, Arg, SubCommand}; use clippy_dev::*; +use std::path::Path; mod fmt; mod new_lint; @@ -49,12 +50,12 @@ fn main() { .arg( Arg::with_name("check") .long("check") - .help("Checks that util/dev update_lints has been run. Used on CI."), + .help("Checks that `cargo dev update_lints` has been run. Used on CI."), ), ) .subcommand( SubCommand::with_name("new_lint") - .about("Create new lint and run util/dev update_lints") + .about("Create new lint and run `cargo dev update_lints`") .arg( Arg::with_name("pass") .short("p") @@ -170,7 +171,7 @@ fn update_lints(update_mode: &UpdateMode) { sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); let mut file_change = replace_region_in_file( - "../src/lintlist/mod.rs", + Path::new("src/lintlist/mod.rs"), "begin lint list", "end lint list", false, @@ -189,7 +190,7 @@ fn update_lints(update_mode: &UpdateMode) { .changed; file_change |= replace_region_in_file( - "../README.md", + Path::new("README.md"), r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#, "", true, @@ -202,7 +203,7 @@ fn update_lints(update_mode: &UpdateMode) { ).changed; file_change |= replace_region_in_file( - "../CHANGELOG.md", + Path::new("CHANGELOG.md"), "<!-- begin autogenerated links to lint list -->", "<!-- end autogenerated links to lint list -->", false, @@ -212,7 +213,7 @@ fn update_lints(update_mode: &UpdateMode) { .changed; file_change |= replace_region_in_file( - "../clippy_lints/src/lib.rs", + Path::new("clippy_lints/src/lib.rs"), "begin deprecated lints", "end deprecated lints", false, @@ -222,7 +223,7 @@ fn update_lints(update_mode: &UpdateMode) { .changed; file_change |= replace_region_in_file( - "../clippy_lints/src/lib.rs", + Path::new("clippy_lints/src/lib.rs"), "begin register lints", "end register lints", false, @@ -232,7 +233,7 @@ fn update_lints(update_mode: &UpdateMode) { .changed; file_change |= replace_region_in_file( - "../clippy_lints/src/lib.rs", + Path::new("clippy_lints/src/lib.rs"), "begin lints modules", "end lints modules", false, @@ -243,7 +244,7 @@ fn update_lints(update_mode: &UpdateMode) { // Generate lists of lints in the clippy::all lint group file_change |= replace_region_in_file( - "../clippy_lints/src/lib.rs", + Path::new("clippy_lints/src/lib.rs"), r#"store.register_group\(true, "clippy::all""#, r#"\]\);"#, false, @@ -266,7 +267,7 @@ fn update_lints(update_mode: &UpdateMode) { // Generate the list of lints for all other lint groups for (lint_group, lints) in Lint::by_lint_group(&usable_lints) { file_change |= replace_region_in_file( - "../clippy_lints/src/lib.rs", + Path::new("clippy_lints/src/lib.rs"), &format!("store.register_group\\(true, \"clippy::{}\"", lint_group), r#"\]\);"#, false, @@ -279,7 +280,7 @@ fn update_lints(update_mode: &UpdateMode) { if update_mode == &UpdateMode::Check && file_change { println!( "Not all lints defined properly. \ - Please run `util/dev update_lints` to make sure all lints are defined properly." + Please run `cargo dev update_lints` to make sure all lints are defined properly." ); std::process::exit(1); } diff --git a/doc/adding_lints.md b/doc/adding_lints.md index fcd7dd75760..99178c2d75b 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -39,10 +39,10 @@ lint. Fortunately, you can use the clippy dev tools to handle this for you. We are naming our new lint `foo_functions` (lints are generally written in snake case), and we don't need type information so it will have an early pass type (more on this later on). To get started on this lint you can run -`./util/dev new_lint --name=foo_functions --pass=early --category=pedantic` +`cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`, -as well as run `./util/dev update_lints` to register the new lint. Next, we'll +as well as run `cargo dev update_lints` to register the new lint. Next, we'll open up these files and add our lint! ### Testing @@ -386,7 +386,7 @@ It can be installed via `rustup`: rustup component add rustfmt --toolchain=nightly ``` -Use `./util/dev fmt` to format the whole codebase. Make sure that `rustfmt` is +Use `cargo dev fmt` to format the whole codebase. Make sure that `rustfmt` is installed for the nightly toolchain. ### Debugging @@ -404,9 +404,9 @@ Before submitting your PR make sure you followed all of the basic requirements: - [ ] Followed [lint naming conventions][lint_naming] - [ ] Added passing UI tests (including committed `.stderr` file) - [ ] `cargo test` passes locally -- [ ] Executed `./util/dev update_lints` +- [ ] Executed `cargo dev update_lints` - [ ] Added lint documentation -- [ ] Run `./util/dev fmt` +- [ ] Run `cargo dev fmt` ### Cheatsheet diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b762c8d1395..41ca1bf5485 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1,4 +1,4 @@ -//! This file is managed by `util/dev update_lints`. Do not edit. +//! This file is managed by `cargo dev update_lints`. Do not edit. pub mod lint; pub use lint::Level; diff --git a/tests/fmt.rs b/tests/fmt.rs index 962425d955a..2e33c3ed5e5 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -34,6 +34,6 @@ fn fmt() { assert!( output.status.success(), - "Formatting check failed. Run `./util/dev fmt` to update formatting." + "Formatting check failed. Run `cargo dev fmt` to update formatting." ); } diff --git a/util/dev b/util/dev index 8e3ed97f98d..319de217e0d 100755 --- a/util/dev +++ b/util/dev @@ -2,4 +2,6 @@ CARGO_TARGET_DIR=$(pwd)/target/ export CARGO_TARGET_DIR +echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.' + cd clippy_dev && cargo run -- "$@" -- cgit 1.4.1-3-g733a5 From 5ba4aa8ebab79ffff4cb621fa22a07d32ea41b1f Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Fri, 31 Jan 2020 10:42:31 +0100 Subject: Move debug_assertions_with_mut_call to nursery --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/mutable_debug_assertion.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 443a9c7e9d9..04239b797e3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1261,7 +1261,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), LintId::of(&mut_key::MUTABLE_KEY_TYPE), LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_ATOMIC), LintId::of(&needless_bool::BOOL_COMPARISON), LintId::of(&needless_bool::NEEDLESS_BOOL), @@ -1578,7 +1577,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc::FLOAT_CMP), LintId::of(&misc::MODULO_ONE), LintId::of(&mut_key::MUTABLE_KEY_TYPE), - LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), @@ -1632,6 +1630,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), + LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 881f59bbabd..f0c5c95b1d4 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// debug_assert!(take_a_mut_parameter(&mut 5)); /// ``` pub DEBUG_ASSERT_WITH_MUT_CALL, - correctness, + nursery, "mutable arguments in `debug_assert{,_ne,_eq}!`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 3edde70a27f..eaada9961b0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -289,7 +289,7 @@ pub const ALL_LINTS: [Lint; 351] = [ }, Lint { name: "debug_assert_with_mut_call", - group: "correctness", + group: "nursery", desc: "mutable arguments in `debug_assert{,_ne,_eq}!`", deprecation: None, module: "mutable_debug_assertion", -- cgit 1.4.1-3-g733a5 From 6afd7ea147cf34eb2ce505d513664b5f4fadfb58 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Sun, 19 Jan 2020 11:07:13 +0100 Subject: Use span_lint_and_sugg + move infaillible lint - moving infaillible lint to prevent collisions --- CHANGELOG.md | 1 + clippy_lints/src/infallible_destructuring_match.rs | 77 ------------ clippy_lints/src/lib.rs | 14 +-- clippy_lints/src/matches.rs | 130 +++++++++++++++++---- src/lintlist/mod.rs | 9 +- tests/ui/escape_analysis.rs | 2 +- tests/ui/escape_analysis.stderr | 4 +- tests/ui/match_single_binding.fixed | 26 +++++ tests/ui/match_single_binding.rs | 4 +- tests/ui/match_single_binding.stderr | 11 +- 10 files changed, 166 insertions(+), 112 deletions(-) delete mode 100644 clippy_lints/src/infallible_destructuring_match.rs create mode 100644 tests/ui/match_single_binding.fixed (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index eb3b518cd8f..49de9df6469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1217,6 +1217,7 @@ Released 2018-09-13 [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs deleted file mode 100644 index 1d23dd115bc..00000000000 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// **What it does:** Checks for matches being used to destructure a single-variant enum - /// or tuple struct where a `let` will suffice. - /// - /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// enum Wrapper { - /// Data(i32), - /// } - /// - /// let wrapper = Wrapper::Data(42); - /// - /// let data = match wrapper { - /// Wrapper::Data(i) => i, - /// }; - /// ``` - /// - /// The correct use would be: - /// ```rust - /// enum Wrapper { - /// Data(i32), - /// } - /// - /// let wrapper = Wrapper::Data(42); - /// let Wrapper::Data(data) = wrapper; - /// ``` - pub INFALLIBLE_DESTRUCTURING_MATCH, - style, - "a `match` statement with a single infallible arm instead of a `let`" -} - -declare_lint_pass!(InfallibleDestructingMatch => [INFALLIBLE_DESTRUCTURING_MATCH]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InfallibleDestructingMatch { - fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local<'_>) { - if_chain! { - if let Some(ref expr) = local.init; - if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind; - if arms.len() == 1 && arms[0].guard.is_none(); - if let PatKind::TupleStruct(QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; - if args.len() == 1; - if let Some(arg) = get_arg_name(&args[0]); - let body = remove_blocks(&arms[0].body); - if match_var(body, arg); - - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - INFALLIBLE_DESTRUCTURING_MATCH, - local.span, - "you seem to be trying to use `match` to destructure a single infallible pattern. \ - Consider using `let`", - "try this", - format!( - "let {}({}) = {};", - snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), - snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), - snippet_with_applicability(cx, target.span, "..", &mut applicability), - ), - applicability, - ); - } - } - } -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2f4e6a0fd48..45342cc7e00 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -218,7 +218,6 @@ pub mod if_let_some_result; pub mod if_not_else; pub mod implicit_return; pub mod indexing_slicing; -pub mod infallible_destructuring_match; pub mod infinite_iter; pub mod inherent_impl; pub mod inherent_to_string; @@ -555,7 +554,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &implicit_return::IMPLICIT_RETURN, &indexing_slicing::INDEXING_SLICING, &indexing_slicing::OUT_OF_BOUNDS_INDEXING, - &infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH, &infinite_iter::INFINITE_ITER, &infinite_iter::MAYBE_INFINITE_ITER, &inherent_impl::MULTIPLE_INHERENT_IMPL, @@ -600,12 +598,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &map_clone::MAP_CLONE, &map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN, + &matches::INFALLIBLE_DESTRUCTURING_MATCH, &matches::MATCH_AS_REF, &matches::MATCH_BOOL, &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, - &matches::MATCH_WILD_ERR_ARM, &matches::MATCH_SINGLE_BINDING, + &matches::MATCH_WILD_ERR_ARM, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, &matches::WILDCARD_ENUM_MATCH_ARM, @@ -865,7 +864,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); - store.register_late_pass(|| box matches::Matches); + store.register_late_pass(|| box matches::Matches::default()); store.register_late_pass(|| box minmax::MinMaxPass); store.register_late_pass(|| box open_options::OpenOptions); store.register_late_pass(|| box zero_div_zero::ZeroDiv); @@ -942,7 +941,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box question_mark::QuestionMark); store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); store.register_late_pass(|| box map_unit_fn::MapUnit); - store.register_late_pass(|| box infallible_destructuring_match::InfallibleDestructingMatch); store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default()); store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); store.register_late_pass(|| box unwrap::Unwrap); @@ -1167,7 +1165,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&identity_op::IDENTITY_OP), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&infinite_iter::INFINITE_ITER), LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), @@ -1202,12 +1199,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), - LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::MATCH_SINGLE_BINDING), + LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), @@ -1384,7 +1382,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&functions::DOUBLE_MUST_USE), LintId::of(&functions::MUST_USE_UNIT), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), @@ -1397,6 +1394,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::WHILE_LET_ON_ITERATOR), LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&map_clone::MAP_CLONE), + LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index b5cf12b0947..e4335abcea2 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -5,7 +5,7 @@ use crate::utils::usage::is_unused; use crate::utils::{ span_lint_and_help, span_lint_and_note, expr_block, in_macro, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks, - snippet, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, + snippet, snippet_block, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; use rustc::lint::in_external_macro; @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_hir::def::CtorKind; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use std::cmp::Ordering; use std::collections::Bound; @@ -245,12 +245,47 @@ declare_clippy_lint! { "a wildcard pattern used with others patterns in same match arm" } +declare_clippy_lint! { + /// **What it does:** Checks for matches being used to destructure a single-variant enum + /// or tuple struct where a `let` will suffice. + /// + /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// enum Wrapper { + /// Data(i32), + /// } + /// + /// let wrapper = Wrapper::Data(42); + /// + /// let data = match wrapper { + /// Wrapper::Data(i) => i, + /// }; + /// ``` + /// + /// The correct use would be: + /// ```rust + /// enum Wrapper { + /// Data(i32), + /// } + /// + /// let wrapper = Wrapper::Data(42); + /// let Wrapper::Data(data) = wrapper; + /// ``` + pub INFALLIBLE_DESTRUCTURING_MATCH, + style, + "a `match` statement with a single infallible arm instead of a `let`" +} + declare_clippy_lint! { /// **What it does:** Checks for useless match that binds to only one value. /// /// **Why is this bad?** Readability and needless complexity. /// - /// **Known problems:** This situation frequently happen in macros, so can't lint there. + /// **Known problems:** None. /// /// **Example:** /// ```rust @@ -272,7 +307,12 @@ declare_clippy_lint! { "a match with a single binding instead of using `let` statement" } -declare_lint_pass!(Matches => [ +#[derive(Default)] +pub struct Matches { + infallible_destructuring_match_linted: bool, +} + +impl_lint_pass!(Matches => [ SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, @@ -283,6 +323,7 @@ declare_lint_pass!(Matches => [ WILDCARD_ENUM_MATCH_ARM, WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, + INFALLIBLE_DESTRUCTURING_MATCH ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { @@ -298,12 +339,51 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { check_wild_enum_match(cx, ex, arms); check_match_as_ref(cx, ex, arms, expr); check_wild_in_or_pats(cx, arms); - check_match_single_binding(cx, ex, arms, expr); + + if self.infallible_destructuring_match_linted { + self.infallible_destructuring_match_linted = false; + } else { + check_match_single_binding(cx, ex, arms, expr); + } } if let ExprKind::Match(ref ex, ref arms, _) = expr.kind { check_match_ref_pats(cx, ex, arms, expr); } } + + fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local<'_>) { + if_chain! { + if let Some(ref expr) = local.init; + if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind; + if arms.len() == 1 && arms[0].guard.is_none(); + if let PatKind::TupleStruct( + QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; + if args.len() == 1; + if let Some(arg) = get_arg_name(&args[0]); + let body = remove_blocks(&arms[0].body); + if match_var(body, arg); + + then { + let mut applicability = Applicability::MachineApplicable; + self.infallible_destructuring_match_linted = true; + span_lint_and_sugg( + cx, + INFALLIBLE_DESTRUCTURING_MATCH, + local.span, + "you seem to be trying to use `match` to destructure a single infallible pattern. \ + Consider using `let`", + "try this", + format!( + "let {}({}) = {};", + snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), + snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), + snippet_with_applicability(cx, target.span, "..", &mut applicability), + ), + applicability, + ); + } + } + } } #[rustfmt::skip] @@ -746,21 +826,31 @@ fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[A return; } if arms.len() == 1 { - let bind_names = arms[0].pat.span; - let matched_vars = ex.span; - span_lint_and_sugg( - cx, - MATCH_SINGLE_BINDING, - expr.span, - "this match could be written as a `let` statement", - "try this", - format!( - "let {} = {};", - snippet(cx, bind_names, ".."), - snippet(cx, matched_vars, "..") - ), - Applicability::HasPlaceholders, - ); + if is_refutable(cx, arms[0].pat) { + return; + } + match arms[0].pat.kind { + PatKind::Binding(..) | PatKind::Tuple(_, _) => { + let bind_names = arms[0].pat.span; + let matched_vars = ex.span; + let match_body = remove_blocks(&arms[0].body); + span_lint_and_sugg( + cx, + MATCH_SINGLE_BINDING, + expr.span, + "this match could be written as a `let` statement", + "consider using `let` statement", + format!( + "let {} = {};\n{}", + snippet(cx, bind_names, ".."), + snippet(cx, matched_vars, ".."), + snippet_block(cx, match_body.span, "..") + ), + Applicability::MachineApplicable, + ); + }, + _ => (), + } } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index eaada9961b0..b28a0917a91 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -775,7 +775,7 @@ pub const ALL_LINTS: [Lint; 351] = [ group: "style", desc: "a `match` statement with a single infallible arm instead of a `let`", deprecation: None, - module: "infallible_destructuring_match", + module: "matches", }, Lint { name: "infinite_iter", @@ -1092,6 +1092,13 @@ pub const ALL_LINTS: [Lint; 351] = [ deprecation: None, module: "copies", }, + Lint { + name: "match_single_binding", + group: "complexity", + desc: "a match with a single binding instead of using `let` statement", + deprecation: None, + module: "matches", + }, Lint { name: "match_wild_err_arm", group: "style", diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index d435484d3e3..7d4b71d09dc 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -3,7 +3,7 @@ clippy::borrowed_box, clippy::needless_pass_by_value, clippy::unused_unit, - clippy::redundant_clone + clippy::redundant_clone, )] #![warn(clippy::boxed_local)] diff --git a/tests/ui/escape_analysis.stderr b/tests/ui/escape_analysis.stderr index 19342fe1be7..c86a769a3da 100644 --- a/tests/ui/escape_analysis.stderr +++ b/tests/ui/escape_analysis.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:39:13 + --> $DIR/escape_analysis.rs:40:13 | LL | fn warn_arg(x: Box<A>) { | ^ @@ -7,7 +7,7 @@ LL | fn warn_arg(x: Box<A>) { = note: `-D clippy::boxed-local` implied by `-D warnings` error: local variable doesn't need to be boxed here - --> $DIR/escape_analysis.rs:130:12 + --> $DIR/escape_analysis.rs:131:12 | LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {} | ^^^^^^^^^^^ diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed new file mode 100644 index 00000000000..41faa1e1c21 --- /dev/null +++ b/tests/ui/match_single_binding.fixed @@ -0,0 +1,26 @@ +// run-rustfix + +#![warn(clippy::match_single_binding)] +#[allow(clippy::many_single_char_names)] + +fn main() { + let a = 1; + let b = 2; + let c = 3; + // Lint + let (x, y, z) = (a, b, c); +{ + println!("{} {} {}", x, y, z); +} + // Ok + match a { + 2 => println!("2"), + _ => println!("Not 2"), + } + // Ok + let d = Some(5); + match d { + Some(d) => println!("{}", d), + _ => println!("None"), + } +} diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index 816a7e7197c..06b924d0471 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![warn(clippy::match_single_binding)] #[allow(clippy::many_single_char_names)] @@ -19,7 +21,7 @@ fn main() { // Ok let d = Some(5); match d { - Some(d) => println!("5"), + Some(d) => println!("{}", d), _ => println!("None"), } } diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 2fad6aab32c..64216a72ef7 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,14 +1,21 @@ error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:9:5 + --> $DIR/match_single_binding.rs:11:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { LL | | println!("{} {} {}", x, y, z); LL | | }, LL | | } - | |_____^ help: try this: `let (x, y, z) = (a, b, c);` + | |_____^ | = note: `-D clippy::match-single-binding` implied by `-D warnings` +help: consider using `let` statement + | +LL | let (x, y, z) = (a, b, c); +LL | { +LL | println!("{} {} {}", x, y, z); +LL | } + | error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 53094de08efea5f4f4ff2d5e8e7381bf8aede625 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Tue, 4 Feb 2020 08:20:49 +0100 Subject: Merge fixes --- README.md | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/println_empty_string.fixed | 1 + tests/ui/println_empty_string.rs | 1 + tests/ui/println_empty_string.stderr | 4 ++-- 5 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index b68eb3ed7fa..da02591f690 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 351 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 352 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b28a0917a91..7d2aedd667d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 351] = [ +pub const ALL_LINTS: [Lint; 352] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 4e84511d7b0..2b889b62ea9 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![allow(clippy::match_single_binding)] fn main() { println!(); diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 9fdfb03a366..890f5f68476 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -1,4 +1,5 @@ // run-rustfix +#![allow(clippy::match_single_binding)] fn main() { println!(); diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 689624a0fa0..23112b88168 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -1,5 +1,5 @@ error: using `println!("")` - --> $DIR/println_empty_string.rs:5:5 + --> $DIR/println_empty_string.rs:6:5 | LL | println!(""); | ^^^^^^^^^^^^ help: replace it with: `println!()` @@ -7,7 +7,7 @@ LL | println!(""); = note: `-D clippy::println-empty-string` implied by `-D warnings` error: using `println!("")` - --> $DIR/println_empty_string.rs:8:14 + --> $DIR/println_empty_string.rs:9:14 | LL | _ => println!(""), | ^^^^^^^^^^^^ help: replace it with: `println!()` -- cgit 1.4.1-3-g733a5 From 338fb7a3e913fee1567ab01d8fa110603da718e7 Mon Sep 17 00:00:00 2001 From: Areredify <misha-babenko@yandex.ru> Date: Sun, 2 Feb 2020 02:49:52 +0300 Subject: add excessive bools lints --- CHANGELOG.md | 2 + README.md | 2 +- clippy_lints/src/excessive_bools.rs | 174 +++++++++++++++++++++ clippy_lints/src/lib.rs | 8 + clippy_lints/src/utils/conf.rs | 4 + clippy_lints/src/utils/mod.rs | 7 + src/lintlist/mod.rs | 16 +- .../ui-toml/fn_params_excessive_bools/clippy.toml | 1 + tests/ui-toml/fn_params_excessive_bools/test.rs | 6 + .../ui-toml/fn_params_excessive_bools/test.stderr | 11 ++ tests/ui-toml/struct_excessive_bools/clippy.toml | 1 + tests/ui-toml/struct_excessive_bools/test.rs | 9 ++ tests/ui-toml/struct_excessive_bools/test.stderr | 13 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/fn_params_excessive_bools.rs | 44 ++++++ tests/ui/fn_params_excessive_bools.stderr | 53 +++++++ tests/ui/struct_excessive_bools.rs | 44 ++++++ tests/ui/struct_excessive_bools.stderr | 29 ++++ tests/ui/unused_self.rs | 2 +- 19 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 clippy_lints/src/excessive_bools.rs create mode 100644 tests/ui-toml/fn_params_excessive_bools/clippy.toml create mode 100644 tests/ui-toml/fn_params_excessive_bools/test.rs create mode 100644 tests/ui-toml/fn_params_excessive_bools/test.stderr create mode 100644 tests/ui-toml/struct_excessive_bools/clippy.toml create mode 100644 tests/ui-toml/struct_excessive_bools/test.rs create mode 100644 tests/ui-toml/struct_excessive_bools/test.stderr create mode 100644 tests/ui/fn_params_excessive_bools.rs create mode 100644 tests/ui/fn_params_excessive_bools.stderr create mode 100644 tests/ui/struct_excessive_bools.rs create mode 100644 tests/ui/struct_excessive_bools.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 49de9df6469..0953432bfad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1147,6 +1147,7 @@ Released 2018-09-13 [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map @@ -1342,6 +1343,7 @@ Released 2018-09-13 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string +[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting diff --git a/README.md b/README.md index da02591f690..96584dfef5c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 352 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 354 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs new file mode 100644 index 00000000000..a1bfb0a7101 --- /dev/null +++ b/clippy_lints/src/excessive_bools.rs @@ -0,0 +1,174 @@ +use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; +use syntax::ast::{AssocItemKind, Extern, FnSig, Item, ItemKind, Ty, TyKind}; + +use std::convert::TryInto; + +declare_clippy_lint! { + /// **What it does:** Checks for excessive + /// use of bools in structs. + /// + /// **Why is this bad?** Excessive bools in a struct + /// is often a sign that it's used as a state machine, + /// which is much better implemented as an enum. + /// If it's not the case, excessive bools usually benefit + /// from refactoring into two-variant enums for better + /// readability and API. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust + /// struct S { + /// is_pending: bool, + /// is_processing: bool, + /// is_finished: bool, + /// } + /// ``` + /// + /// Good: + /// ```rust + /// enum S { + /// Pending, + /// Processing, + /// Finished, + /// } + /// ``` + pub STRUCT_EXCESSIVE_BOOLS, + pedantic, + "using too many bools in a struct" +} + +declare_clippy_lint! { + /// **What it does:** Checks for excessive use of + /// bools in function definitions. + /// + /// **Why is this bad?** Calls to such functions + /// are confusing and error prone, because it's + /// hard to remember argument order and you have + /// no type system support to back you up. Using + /// two-variant enums instead of bools often makes + /// API easier to use. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust,ignore + /// fn f(is_round: bool, is_hot: bool) { ... } + /// ``` + /// + /// Good: + /// ```rust,ignore + /// enum Shape { + /// Round, + /// Spiky, + /// } + /// + /// enum Temperature { + /// Hot, + /// IceCold, + /// } + /// + /// fn f(shape: Shape, temperature: Temperature) { ... } + /// ``` + pub FN_PARAMS_EXCESSIVE_BOOLS, + pedantic, + "using too many bools in function parameters" +} + +pub struct ExcessiveBools { + max_struct_bools: u64, + max_fn_params_bools: u64, +} + +impl ExcessiveBools { + #[must_use] + pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self { + Self { + max_struct_bools, + max_fn_params_bools, + } + } + + fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) { + match fn_sig.header.ext { + Extern::Implicit | Extern::Explicit(_) => return, + Extern::None => (), + } + + let fn_sig_bools = fn_sig + .decl + .inputs + .iter() + .filter(|param| is_bool_ty(¶m.ty)) + .count() + .try_into() + .unwrap(); + if self.max_fn_params_bools < fn_sig_bools { + span_lint_and_help( + cx, + FN_PARAMS_EXCESSIVE_BOOLS, + span, + &format!("more than {} bools in function parameters", self.max_fn_params_bools), + "consider refactoring bools into two-variant enums", + ); + } + } +} + +impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]); + +fn is_bool_ty(ty: &Ty) -> bool { + if let TyKind::Path(None, path) = &ty.kind { + return match_path_ast(path, &["bool"]); + } + false +} + +impl EarlyLintPass for ExcessiveBools { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if in_macro(item.span) { + return; + } + match &item.kind { + ItemKind::Struct(variant_data, _) => { + if attr_by_name(&item.attrs, "repr").is_some() { + return; + } + + let struct_bools = variant_data + .fields() + .iter() + .filter(|field| is_bool_ty(&field.ty)) + .count() + .try_into() + .unwrap(); + if self.max_struct_bools < struct_bools { + span_lint_and_help( + cx, + STRUCT_EXCESSIVE_BOOLS, + item.span, + &format!("more than {} bools in a struct", self.max_struct_bools), + "consider using a state machine or refactoring bools into two-variant enums", + ); + } + }, + ItemKind::Impl { + of_trait: None, items, .. + } + | ItemKind::Trait(_, _, _, _, items) => { + for item in items { + if let AssocItemKind::Fn(fn_sig, _) = &item.kind { + self.check_fn_sig(cx, fn_sig, item.span); + } + } + }, + ItemKind::Fn(fn_sig, _, _) => self.check_fn_sig(cx, fn_sig, item.span), + _ => (), + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ff72a7f9e98..5084e4e599c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -202,6 +202,7 @@ pub mod erasing_op; pub mod escape; pub mod eta_reduction; pub mod eval_order_dependence; +pub mod excessive_bools; pub mod excessive_precision; pub mod exit; pub mod explicit_write; @@ -528,6 +529,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, &eval_order_dependence::DIVERGING_SUB_EXPRESSION, &eval_order_dependence::EVAL_ORDER_DEPENDENCE, + &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, + &excessive_bools::STRUCT_EXCESSIVE_BOOLS, &excessive_precision::EXCESSIVE_PRECISION, &exit::EXIT, &explicit_write::EXPLICIT_WRITE, @@ -997,6 +1000,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); + let max_fn_params_bools = conf.max_fn_params_bools; + let max_struct_bools = conf.max_struct_bools; + store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1051,6 +1057,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES), LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), + LintId::of(&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), + LintId::of(&excessive_bools::STRUCT_EXCESSIVE_BOOLS), LintId::of(&functions::MUST_USE_CANDIDATE), LintId::of(&functions::TOO_MANY_LINES), LintId::of(&if_not_else::IF_NOT_ELSE), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 241f0657cb1..584cde2678f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -154,6 +154,10 @@ define_Conf! { (array_size_threshold, "array_size_threshold": u64, 512_000), /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096), + /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have + (max_struct_bools, "max_struct_bools": u64, 3), + /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have + (max_fn_params_bools, "max_fn_params_bools": u64, 3), } impl Default for Conf { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 393ae64f81c..4b7e21bc3ba 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1355,6 +1355,13 @@ pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { }) } +/// Check if parent of a hir node is a trait implementation block. +/// For example, `f` in +/// ```rust,ignore +/// impl Trait for S { +/// fn f() {} +/// } +/// ``` pub fn is_trait_impl_item(cx: &LateContext<'_, '_>, hir_id: HirId) -> bool { if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. }) diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 7d2aedd667d..f725ce2563f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 352] = [ +pub const ALL_LINTS: [Lint; 354] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -623,6 +623,13 @@ pub const ALL_LINTS: [Lint; 352] = [ deprecation: None, module: "misc", }, + Lint { + name: "fn_params_excessive_bools", + group: "pedantic", + desc: "using too many bools in function parameters", + deprecation: None, + module: "excessive_bools", + }, Lint { name: "fn_to_numeric_cast", group: "style", @@ -1932,6 +1939,13 @@ pub const ALL_LINTS: [Lint; 352] = [ deprecation: None, module: "strings", }, + Lint { + name: "struct_excessive_bools", + group: "pedantic", + desc: "using too many bools in a struct", + deprecation: None, + module: "excessive_bools", + }, Lint { name: "suspicious_arithmetic_impl", group: "correctness", diff --git a/tests/ui-toml/fn_params_excessive_bools/clippy.toml b/tests/ui-toml/fn_params_excessive_bools/clippy.toml new file mode 100644 index 00000000000..022eec3e0e2 --- /dev/null +++ b/tests/ui-toml/fn_params_excessive_bools/clippy.toml @@ -0,0 +1 @@ +max-fn-params-bools = 1 diff --git a/tests/ui-toml/fn_params_excessive_bools/test.rs b/tests/ui-toml/fn_params_excessive_bools/test.rs new file mode 100644 index 00000000000..42897b389ed --- /dev/null +++ b/tests/ui-toml/fn_params_excessive_bools/test.rs @@ -0,0 +1,6 @@ +#![warn(clippy::fn_params_excessive_bools)] + +fn f(_: bool) {} +fn g(_: bool, _: bool) {} + +fn main() {} diff --git a/tests/ui-toml/fn_params_excessive_bools/test.stderr b/tests/ui-toml/fn_params_excessive_bools/test.stderr new file mode 100644 index 00000000000..d05adc3d36e --- /dev/null +++ b/tests/ui-toml/fn_params_excessive_bools/test.stderr @@ -0,0 +1,11 @@ +error: more than 1 bools in function parameters + --> $DIR/test.rs:4:1 + | +LL | fn g(_: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` + = help: consider refactoring bools into two-variant enums + +error: aborting due to previous error + diff --git a/tests/ui-toml/struct_excessive_bools/clippy.toml b/tests/ui-toml/struct_excessive_bools/clippy.toml new file mode 100644 index 00000000000..3912ab54277 --- /dev/null +++ b/tests/ui-toml/struct_excessive_bools/clippy.toml @@ -0,0 +1 @@ +max-struct-bools = 0 diff --git a/tests/ui-toml/struct_excessive_bools/test.rs b/tests/ui-toml/struct_excessive_bools/test.rs new file mode 100644 index 00000000000..242984680e1 --- /dev/null +++ b/tests/ui-toml/struct_excessive_bools/test.rs @@ -0,0 +1,9 @@ +#![warn(clippy::struct_excessive_bools)] + +struct S { + a: bool, +} + +struct Foo {} + +fn main() {} diff --git a/tests/ui-toml/struct_excessive_bools/test.stderr b/tests/ui-toml/struct_excessive_bools/test.stderr new file mode 100644 index 00000000000..65861d10d0f --- /dev/null +++ b/tests/ui-toml/struct_excessive_bools/test.stderr @@ -0,0 +1,13 @@ +error: more than 0 bools in a struct + --> $DIR/test.rs:3:1 + | +LL | / struct S { +LL | | a: bool, +LL | | } + | |_^ + | + = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` + = help: consider using a state machine or refactoring bools into two-variant enums + +error: aborting due to previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 9eebc0bcf3f..18f5d994ba8 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/fn_params_excessive_bools.rs b/tests/ui/fn_params_excessive_bools.rs new file mode 100644 index 00000000000..7d6fd607e65 --- /dev/null +++ b/tests/ui/fn_params_excessive_bools.rs @@ -0,0 +1,44 @@ +#![warn(clippy::fn_params_excessive_bools)] + +extern "C" { + fn f(_: bool, _: bool, _: bool, _: bool); +} + +macro_rules! foo { + () => { + fn fff(_: bool, _: bool, _: bool, _: bool) {} + }; +} + +foo!(); + +#[no_mangle] +extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {} +fn g(_: bool, _: bool, _: bool, _: bool) {} +fn h(_: bool, _: bool, _: bool) {} +fn e(_: S, _: S, _: Box<S>, _: Vec<u32>) {} +fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {} + +struct S {} +trait Trait { + fn f(_: bool, _: bool, _: bool, _: bool); + fn g(_: bool, _: bool, _: bool, _: Vec<u32>); +} + +impl S { + fn f(&self, _: bool, _: bool, _: bool, _: bool) {} + fn g(&self, _: bool, _: bool, _: bool) {} + #[no_mangle] + extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {} +} + +impl Trait for S { + fn f(_: bool, _: bool, _: bool, _: bool) {} + fn g(_: bool, _: bool, _: bool, _: Vec<u32>) {} +} + +fn main() { + fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) { + fn nn(_: bool, _: bool, _: bool, _: bool) {} + } +} diff --git a/tests/ui/fn_params_excessive_bools.stderr b/tests/ui/fn_params_excessive_bools.stderr new file mode 100644 index 00000000000..4e5dbc261d6 --- /dev/null +++ b/tests/ui/fn_params_excessive_bools.stderr @@ -0,0 +1,53 @@ +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:17:1 + | +LL | fn g(_: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings` + = help: consider refactoring bools into two-variant enums + +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:20:1 + | +LL | fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider refactoring bools into two-variant enums + +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:24:5 + | +LL | fn f(_: bool, _: bool, _: bool, _: bool); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider refactoring bools into two-variant enums + +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:29:5 + | +LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider refactoring bools into two-variant enums + +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:41:5 + | +LL | / fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) { +LL | | fn nn(_: bool, _: bool, _: bool, _: bool) {} +LL | | } + | |_____^ + | + = help: consider refactoring bools into two-variant enums + +error: more than 3 bools in function parameters + --> $DIR/fn_params_excessive_bools.rs:42:9 + | +LL | fn nn(_: bool, _: bool, _: bool, _: bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider refactoring bools into two-variant enums + +error: aborting due to 6 previous errors + diff --git a/tests/ui/struct_excessive_bools.rs b/tests/ui/struct_excessive_bools.rs new file mode 100644 index 00000000000..ce4fe830a0a --- /dev/null +++ b/tests/ui/struct_excessive_bools.rs @@ -0,0 +1,44 @@ +#![warn(clippy::struct_excessive_bools)] + +macro_rules! foo { + () => { + struct MacroFoo { + a: bool, + b: bool, + c: bool, + d: bool, + } + }; +} + +foo!(); + +struct Foo { + a: bool, + b: bool, + c: bool, +} + +struct BadFoo { + a: bool, + b: bool, + c: bool, + d: bool, +} + +#[repr(C)] +struct Bar { + a: bool, + b: bool, + c: bool, + d: bool, +} + +fn main() { + struct FooFoo { + a: bool, + b: bool, + c: bool, + d: bool, + } +} diff --git a/tests/ui/struct_excessive_bools.stderr b/tests/ui/struct_excessive_bools.stderr new file mode 100644 index 00000000000..2941bf2983a --- /dev/null +++ b/tests/ui/struct_excessive_bools.stderr @@ -0,0 +1,29 @@ +error: more than 3 bools in a struct + --> $DIR/struct_excessive_bools.rs:22:1 + | +LL | / struct BadFoo { +LL | | a: bool, +LL | | b: bool, +LL | | c: bool, +LL | | d: bool, +LL | | } + | |_^ + | + = note: `-D clippy::struct-excessive-bools` implied by `-D warnings` + = help: consider using a state machine or refactoring bools into two-variant enums + +error: more than 3 bools in a struct + --> $DIR/struct_excessive_bools.rs:38:5 + | +LL | / struct FooFoo { +LL | | a: bool, +LL | | b: bool, +LL | | c: bool, +LL | | d: bool, +LL | | } + | |_____^ + | + = help: consider using a state machine or refactoring bools into two-variant enums + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unused_self.rs b/tests/ui/unused_self.rs index 711c1cd9d6c..42d432a2c9e 100644 --- a/tests/ui/unused_self.rs +++ b/tests/ui/unused_self.rs @@ -1,5 +1,5 @@ #![warn(clippy::unused_self)] -#![allow(clippy::boxed_local)] +#![allow(clippy::boxed_local, clippy::fn_params_excessive_bools)] mod unused_self { use std::pin::Pin; -- cgit 1.4.1-3-g733a5 From be1bc571c3558cf3920e77d5eb3f017aeeac637c Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 8 Feb 2020 16:44:35 -0800 Subject: Add `option-env-unwrap` lint --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 ++++ clippy_lints/src/option_env_unwrap.rs | 55 +++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++++- tests/ui/option_env_unwrap.rs | 12 ++++++++ tests/ui/option_env_unwrap.stderr | 23 +++++++++++++++ 7 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/option_env_unwrap.rs create mode 100644 tests/ui/option_env_unwrap.rs create mode 100644 tests/ui/option_env_unwrap.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 0953432bfad..3658df88d40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1276,6 +1276,7 @@ Released 2018-09-13 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref +[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn diff --git a/README.md b/README.md index 96584dfef5c..fd7f33f91d5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 354 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 355 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5084e4e599c..f900a99f314 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -267,6 +267,7 @@ pub mod no_effect; pub mod non_copy_const; pub mod non_expressive_names; pub mod open_options; +pub mod option_env_unwrap; pub mod overflow_check_conditional; pub mod panic_unimplemented; pub mod partialeq_ne_impl; @@ -713,6 +714,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::MANY_SINGLE_CHAR_NAMES, &non_expressive_names::SIMILAR_NAMES, &open_options::NONSENSICAL_OPEN_OPTIONS, + &option_env_unwrap::OPTION_ENV_UNWRAP, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_unimplemented::PANIC, &panic_unimplemented::PANIC_PARAMS, @@ -1003,6 +1005,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); + store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1285,6 +1288,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), @@ -1590,6 +1594,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(&ptr::MUT_FROM_REF), LintId::of(®ex::INVALID_REGEX), LintId::of(&serde_api::SERDE_API_MISUSE), diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs new file mode 100644 index 00000000000..e0e8a95acd5 --- /dev/null +++ b/clippy_lints/src/option_env_unwrap.rs @@ -0,0 +1,55 @@ +use crate::utils::{is_direct_expn_of, span_lint_and_help}; +use if_chain::if_chain; +use rustc::lint::in_external_macro; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use syntax::ast::*; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `option_env!(...).unwrap()` and + /// suggests usage of the `env!` macro. + /// + /// **Why is this bad?** Unwrapping the result of `option_env!` will panic + /// at run-time if the environment variable doesn't exist, whereas `env!` + /// catches it at compile-time. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,no_run + /// let _ = option_env!("HOME").unwrap(); + /// ``` + /// + /// Is better expressed as: + /// + /// ```rust,no_run + /// let _ = env!("HOME"); + /// ``` + pub OPTION_ENV_UNWRAP, + correctness, + "using `option_env!(...).unwrap()` to get environment variable" +} + +declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); + +impl EarlyLintPass for OptionEnvUnwrap { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if_chain! { + if !in_external_macro(cx.sess, expr.span); + if let ExprKind::MethodCall(path_segment, args) = &expr.kind; + if path_segment.ident.as_str() == "unwrap"; + if let ExprKind::Call(caller, _) = &args[0].kind; + if is_direct_expn_of(caller.span, "option_env").is_some(); + then { + span_lint_and_help( + cx, + OPTION_ENV_UNWRAP, + expr.span, + "this will panic at run-time if the environment variable doesn't exist", + "consider using the `env!` macro instead" + ); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f725ce2563f..d4f94a9b60a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 354] = [ +pub const ALL_LINTS: [Lint; 355] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1498,6 +1498,13 @@ pub const ALL_LINTS: [Lint; 354] = [ deprecation: None, module: "methods", }, + Lint { + name: "option_env_unwrap", + group: "correctness", + desc: "using `option_env!(...).unwrap()` to get environment variable", + deprecation: None, + module: "option_env_unwrap", + }, Lint { name: "option_expect_used", group: "restriction", diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs new file mode 100644 index 00000000000..2830669ff66 --- /dev/null +++ b/tests/ui/option_env_unwrap.rs @@ -0,0 +1,12 @@ +#![warn(clippy::option_env_unwrap)] + +macro_rules! option_env_unwrap { + ($env: expr) => { + option_env!($env).unwrap() + }; +} + +fn main() { + let _ = option_env!("HOME").unwrap(); + let _ = option_env_unwrap!("HOME"); +} diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr new file mode 100644 index 00000000000..b7d5ecd6321 --- /dev/null +++ b/tests/ui/option_env_unwrap.stderr @@ -0,0 +1,23 @@ +error: this will panic at run-time if the environment variable doesn't exist + --> $DIR/option_env_unwrap.rs:10:13 + | +LL | let _ = option_env!("HOME").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::option-env-unwrap` implied by `-D warnings` + = help: consider using the `env!` macro instead + +error: this will panic at run-time if the environment variable doesn't exist + --> $DIR/option_env_unwrap.rs:5:9 + | +LL | option_env!($env).unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | let _ = option_env_unwrap!("HOME"); + | -------------------------- in this macro invocation + | + = help: consider using the `env!` macro instead + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From bfc4bd4dbefaf3bd80eda2f3e764e03757fc9f46 Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Tue, 11 Feb 2020 22:52:00 +0700 Subject: Impl DefaultCallbacks on our side --- src/driver.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 27ff7fa9116..087c8c67b4a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -63,10 +63,10 @@ fn test_arg_value() { assert_eq!(arg_value(args, "--foo", |_| true), None); } -#[allow(clippy::too_many_lines)] +struct DefaultCallbacks; +impl rustc_driver::Callbacks for DefaultCallbacks {} struct ClippyCallbacks; - impl rustc_driver::Callbacks for ClippyCallbacks { fn config(&mut self, config: &mut interface::Config) { let previous = config.register_lints.take(); @@ -387,7 +387,7 @@ pub fn main() { } } let mut clippy = ClippyCallbacks; - let mut default = rustc_driver::DefaultCallbacks; + let mut default = DefaultCallbacks; let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { &mut clippy } else { &mut default }; rustc_driver::run_compiler(&args, callbacks, None, None) -- cgit 1.4.1-3-g733a5 From f5db351a1d502cb65f8807ec2c84f44756099ef3 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Wed, 22 Jan 2020 14:56:08 +0100 Subject: Get {RUSTUP,MULTIRUST}_{HOME,TOOLCHAIN} from runtime environment Keep the fallback to compile-time environment --- src/driver.rs | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 087c8c67b4a..097b796e785 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -281,6 +281,17 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } } +fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> { + home.and_then(|home| { + toolchain.map(|toolchain| { + let mut path = PathBuf::from(home); + path.push("toolchains"); + path.push(toolchain); + path + }) + }) +} + pub fn main() { rustc_driver::init_rustc_env_logger(); lazy_static::initialize(&ICE_HOOK); @@ -301,22 +312,21 @@ pub fn main() { // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN // - sysroot from rustc in the path // - compile-time environment + // - SYSROOT + // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); let have_sys_root_arg = sys_root_arg.is_some(); let sys_root = sys_root_arg .map(PathBuf::from) .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from)) .or_else(|| { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - home.and_then(|home| { - toolchain.map(|toolchain| { - let mut path = PathBuf::from(home); - path.push("toolchains"); - path.push(toolchain); - path - }) - }) + let home = std::env::var("RUSTUP_HOME") + .or_else(|_| std::env::var("MULTIRUST_HOME")) + .ok(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN") + .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN")) + .ok(); + toolchain_path(home, toolchain) }) .or_else(|| { Command::new("rustc") @@ -328,6 +338,15 @@ pub fn main() { .map(|s| PathBuf::from(s.trim())) }) .or_else(|| option_env!("SYSROOT").map(PathBuf::from)) + .or_else(|| { + let home = option_env!("RUSTUP_HOME") + .or(option_env!("MULTIRUST_HOME")) + .map(ToString::to_string); + let toolchain = option_env!("RUSTUP_TOOLCHAIN") + .or(option_env!("MULTIRUST_TOOLCHAIN")) + .map(ToString::to_string); + toolchain_path(home, toolchain) + }) .map(|pb| pb.to_string_lossy().to_string()) .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); -- cgit 1.4.1-3-g733a5 From 7e0af69f1ce02efc69ca67bd3792969a84949411 Mon Sep 17 00:00:00 2001 From: Lily Chung <lily@commure.com> Date: Wed, 12 Feb 2020 16:50:29 -0800 Subject: Reclassify chars_next_cmp as a style lint. This makes it consistent with chars_last_cmp. --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index d4f94a9b60a..06a1fca4fdd 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -191,7 +191,7 @@ pub const ALL_LINTS: [Lint; 355] = [ }, Lint { name: "chars_next_cmp", - group: "complexity", + group: "style", desc: "using `.chars().next()` to check if a string starts with a char", deprecation: None, module: "methods", -- cgit 1.4.1-3-g733a5 From 45936a6e26ad123bfaa391791edeb2c7f51b296c Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Mon, 17 Feb 2020 00:17:26 -0800 Subject: Uplift `excessive_precision` to the correctness category --- clippy_lints/src/excessive_precision.rs | 10 +++++----- clippy_lints/src/lib.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index 70b44dee661..781d85a00e4 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -22,15 +22,15 @@ declare_clippy_lint! { /// /// ```rust /// // Bad - /// let v: f32 = 0.123_456_789_9; - /// println!("{}", v); // 0.123_456_789 + /// let a: f32 = 0.123_456_789_9; // 0.123_456_789 + /// let b: f32 = 16_777_217.0; // 16_777_216.0 /// /// // Good - /// let v: f64 = 0.123_456_789_9; - /// println!("{}", v); // 0.123_456_789_9 + /// let a: f64 = 0.123_456_789_9; + /// let b: f64 = 16_777_216.0; /// ``` pub EXCESSIVE_PRECISION, - style, + correctness, "excessive precision for float literal" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1cf01d2e02e..8bd0d187061 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1386,7 +1386,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_variants::MODULE_INCEPTION), LintId::of(&eq_op::OP_REF), LintId::of(&eta_reduction::REDUNDANT_CLOSURE), - LintId::of(&excessive_precision::EXCESSIVE_PRECISION), LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), @@ -1567,6 +1566,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(&eq_op::EQ_OP), LintId::of(&erasing_op::ERASING_OP), + LintId::of(&excessive_precision::EXCESSIVE_PRECISION), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 06a1fca4fdd..8c04afce1d2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -492,7 +492,7 @@ pub const ALL_LINTS: [Lint; 355] = [ }, Lint { name: "excessive_precision", - group: "style", + group: "correctness", desc: "excessive precision for float literal", deprecation: None, module: "excessive_precision", -- cgit 1.4.1-3-g733a5 From 78a250773631002303a24455eef7a8e7e7fbe619 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati <nipunn@dropbox.com> Date: Wed, 19 Feb 2020 15:32:59 -0800 Subject: Move unneeded_field_pattern to restriction group Fixes https://github.com/rust-lang/rust-clippy/issues/1741 --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/misc_early.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8bd0d187061..409e2863f9a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1033,6 +1033,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::RESULT_UNWRAP_USED), LintId::of(&methods::WRONG_PUB_SELF_CONVENTION), LintId::of(&misc::FLOAT_CMP_CONST), + LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(&missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(&missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(&modulo_arithmetic::MODULO_ARITHMETIC), @@ -1270,7 +1271,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL), LintId::of(&misc_early::REDUNDANT_PATTERN), - LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), LintId::of(&mut_key::MUTABLE_KEY_TYPE), @@ -1433,7 +1433,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS), LintId::of(&misc_early::REDUNDANT_PATTERN), - LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(&neg_multiply::NEG_MULTIPLY), LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index b28a61eb621..3f17ac3de22 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// let { a: _, b: ref b, c: _ } = .. /// ``` pub UNNEEDED_FIELD_PATTERN, - style, + restriction, "struct fields bound to a wildcard instead of using `..`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8c04afce1d2..6ed67681cb1 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2228,7 +2228,7 @@ pub const ALL_LINTS: [Lint; 355] = [ }, Lint { name: "unneeded_field_pattern", - group: "style", + group: "restriction", desc: "struct fields bound to a wildcard instead of using `..`", deprecation: None, module: "misc_early", -- cgit 1.4.1-3-g733a5 From 219c94d02848c87db16c99ac2c6b30728713f58e Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Thu, 20 Feb 2020 18:32:06 -0800 Subject: Separate out lint to check lossy whole number float literals --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/excessive_precision.rs | 154 --------------------------- clippy_lints/src/float_literal.rs | 183 ++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 12 ++- src/lintlist/mod.rs | 13 ++- tests/ui/excessive_precision.fixed | 22 ---- tests/ui/excessive_precision.rs | 22 ---- tests/ui/excessive_precision.stderr | 68 +----------- tests/ui/lossy_float_literal.fixed | 35 ++++++ tests/ui/lossy_float_literal.rs | 35 ++++++ tests/ui/lossy_float_literal.stderr | 70 ++++++++++++ 12 files changed, 343 insertions(+), 274 deletions(-) delete mode 100644 clippy_lints/src/excessive_precision.rs create mode 100644 clippy_lints/src/float_literal.rs create mode 100644 tests/ui/lossy_float_literal.fixed create mode 100644 tests/ui/lossy_float_literal.rs create mode 100644 tests/ui/lossy_float_literal.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f527a407db..05ebe97d7b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1207,6 +1207,7 @@ Released 2018-09-13 [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_mul_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_mul_add diff --git a/README.md b/README.md index 444d79bcb27..f2ffea7d23c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 355 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 356 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs deleted file mode 100644 index 781d85a00e4..00000000000 --- a/clippy_lints/src/excessive_precision.rs +++ /dev/null @@ -1,154 +0,0 @@ -use crate::utils::span_lint_and_sugg; -use crate::utils::sugg::format_numeric_literal; -use if_chain::if_chain; -use rustc::ty; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use std::{f32, f64, fmt}; -use syntax::ast::*; - -declare_clippy_lint! { - /// **What it does:** Checks for float literals with a precision greater - /// than that supported by the underlying type. - /// - /// **Why is this bad?** Rust will silently lose precision during conversion - /// to a float. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// - /// ```rust - /// // Bad - /// let a: f32 = 0.123_456_789_9; // 0.123_456_789 - /// let b: f32 = 16_777_217.0; // 16_777_216.0 - /// - /// // Good - /// let a: f64 = 0.123_456_789_9; - /// let b: f64 = 16_777_216.0; - /// ``` - pub EXCESSIVE_PRECISION, - correctness, - "excessive precision for float literal" -} - -declare_lint_pass!(ExcessivePrecision => [EXCESSIVE_PRECISION]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - let ty = cx.tables.expr_ty(expr); - if let ty::Float(fty) = ty.kind; - if let hir::ExprKind::Lit(ref lit) = expr.kind; - if let LitKind::Float(sym, lit_float_ty) = lit.node; - then { - let sym_str = sym.as_str(); - let formatter = FloatFormat::new(&sym_str); - // Try to bail out if the float is for sure fine. - // If its within the 2 decimal digits of being out of precision we - // check if the parsed representation is the same as the string - // since we'll need the truncated string anyway. - let digits = count_digits(&sym_str); - let max = max_digits(fty); - let float_str = match fty { - FloatTy::F32 => sym_str.parse::<f32>().map(|f| formatter.format(f)), - FloatTy::F64 => sym_str.parse::<f64>().map(|f| formatter.format(f)), - }.unwrap(); - let type_suffix = match lit_float_ty { - LitFloatType::Suffixed(FloatTy::F32) => Some("f32"), - LitFloatType::Suffixed(FloatTy::F64) => Some("f64"), - _ => None - }; - - if is_whole_number(&sym_str, fty) { - // Normalize the literal by stripping the fractional portion - if sym_str.split('.').next().unwrap() != float_str { - span_lint_and_sugg( - cx, - EXCESSIVE_PRECISION, - expr.span, - "literal cannot be represented as the underlying type without loss of precision", - "consider changing the type or replacing it with", - format_numeric_literal(format!("{}.0", float_str).as_str(), type_suffix, true), - Applicability::MachineApplicable, - ); - } - } else if digits > max as usize && sym_str != float_str { - span_lint_and_sugg( - cx, - EXCESSIVE_PRECISION, - expr.span, - "float has excessive precision", - "consider changing the type or truncating it to", - format_numeric_literal(&float_str, type_suffix, true), - Applicability::MachineApplicable, - ); - } - } - } - } -} - -// Checks whether a float literal is a whole number -#[must_use] -fn is_whole_number(sym_str: &str, fty: FloatTy) -> bool { - match fty { - FloatTy::F32 => sym_str.parse::<f32>().unwrap().fract() == 0.0, - FloatTy::F64 => sym_str.parse::<f64>().unwrap().fract() == 0.0, - } -} - -#[must_use] -fn max_digits(fty: FloatTy) -> u32 { - match fty { - FloatTy::F32 => f32::DIGITS, - FloatTy::F64 => f64::DIGITS, - } -} - -/// Counts the digits excluding leading zeros -#[must_use] -fn count_digits(s: &str) -> usize { - // Note that s does not contain the f32/64 suffix, and underscores have been stripped - s.chars() - .filter(|c| *c != '-' && *c != '.') - .take_while(|c| *c != 'e' && *c != 'E') - .fold(0, |count, c| { - // leading zeros - if c == '0' && count == 0 { - count - } else { - count + 1 - } - }) -} - -enum FloatFormat { - LowerExp, - UpperExp, - Normal, -} -impl FloatFormat { - #[must_use] - fn new(s: &str) -> Self { - s.chars() - .find_map(|x| match x { - 'e' => Some(Self::LowerExp), - 'E' => Some(Self::UpperExp), - _ => None, - }) - .unwrap_or(Self::Normal) - } - fn format<T>(&self, f: T) -> String - where - T: fmt::UpperExp + fmt::LowerExp + fmt::Display, - { - match self { - Self::LowerExp => format!("{:e}", f), - Self::UpperExp => format!("{:E}", f), - Self::Normal => format!("{}", f), - } - } -} diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs new file mode 100644 index 00000000000..8707259a2c8 --- /dev/null +++ b/clippy_lints/src/float_literal.rs @@ -0,0 +1,183 @@ +use crate::utils::span_lint_and_sugg; +use crate::utils::sugg::format_numeric_literal; +use if_chain::if_chain; +use rustc::ty; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::{f32, f64, fmt}; +use syntax::ast::*; + +declare_clippy_lint! { + /// **What it does:** Checks for float literals with a precision greater + /// than that supported by the underlying type. + /// + /// **Why is this bad?** Rust will truncate the literal silently. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let v: f32 = 0.123_456_789_9; + /// println!("{}", v); // 0.123_456_789 + /// + /// // Good + /// let v: f64 = 0.123_456_789_9; + /// println!("{}", v); // 0.123_456_789_9 + /// ``` + pub EXCESSIVE_PRECISION, + style, + "excessive precision for float literal" +} + +declare_clippy_lint! { + /// **What it does:** Checks for whole number float literals that + /// cannot be represented as the underlying type without loss. + /// + /// **Why is this bad?** Rust will silently lose precision during + /// conversion to a float. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let _: f32 = 16_777_217.0; // 16_777_216.0 + /// + /// // Good + /// let _: f32 = 16_777_216.0; + /// let _: f64 = 16_777_217.0; + /// ``` + pub LOSSY_FLOAT_LITERAL, + restriction, + "lossy whole number float literals" +} + +declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { + if_chain! { + let ty = cx.tables.expr_ty(expr); + if let ty::Float(fty) = ty.kind; + if let hir::ExprKind::Lit(ref lit) = expr.kind; + if let LitKind::Float(sym, lit_float_ty) = lit.node; + then { + let sym_str = sym.as_str(); + let formatter = FloatFormat::new(&sym_str); + // Try to bail out if the float is for sure fine. + // If its within the 2 decimal digits of being out of precision we + // check if the parsed representation is the same as the string + // since we'll need the truncated string anyway. + let digits = count_digits(&sym_str); + let max = max_digits(fty); + let type_suffix = match lit_float_ty { + LitFloatType::Suffixed(FloatTy::F32) => Some("f32"), + LitFloatType::Suffixed(FloatTy::F64) => Some("f64"), + _ => None + }; + let (is_whole, mut float_str) = match fty { + FloatTy::F32 => { + let value = sym_str.parse::<f32>().unwrap(); + + (value.fract() == 0.0, formatter.format(value)) + }, + FloatTy::F64 => { + let value = sym_str.parse::<f64>().unwrap(); + + (value.fract() == 0.0, formatter.format(value)) + }, + }; + + if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { + // Normalize the literal by stripping the fractional portion + if sym_str.split('.').next().unwrap() != float_str { + // If the type suffix is missing the suggestion would be + // incorrectly interpreted as an integer so adding a `.0` + // suffix to prevent that. + if type_suffix.is_none() { + float_str.push_str(".0"); + } + + span_lint_and_sugg( + cx, + LOSSY_FLOAT_LITERAL, + expr.span, + "literal cannot be represented as the underlying type without loss of precision", + "consider changing the type or replacing it with", + format_numeric_literal(&float_str, type_suffix, true), + Applicability::MachineApplicable, + ); + } + } else if digits > max as usize && sym_str != float_str { + span_lint_and_sugg( + cx, + EXCESSIVE_PRECISION, + expr.span, + "float has excessive precision", + "consider changing the type or truncating it to", + format_numeric_literal(&float_str, type_suffix, true), + Applicability::MachineApplicable, + ); + } + } + } + } +} + +#[must_use] +fn max_digits(fty: FloatTy) -> u32 { + match fty { + FloatTy::F32 => f32::DIGITS, + FloatTy::F64 => f64::DIGITS, + } +} + +/// Counts the digits excluding leading zeros +#[must_use] +fn count_digits(s: &str) -> usize { + // Note that s does not contain the f32/64 suffix, and underscores have been stripped + s.chars() + .filter(|c| *c != '-' && *c != '.') + .take_while(|c| *c != 'e' && *c != 'E') + .fold(0, |count, c| { + // leading zeros + if c == '0' && count == 0 { + count + } else { + count + 1 + } + }) +} + +enum FloatFormat { + LowerExp, + UpperExp, + Normal, +} +impl FloatFormat { + #[must_use] + fn new(s: &str) -> Self { + s.chars() + .find_map(|x| match x { + 'e' => Some(Self::LowerExp), + 'E' => Some(Self::UpperExp), + _ => None, + }) + .unwrap_or(Self::Normal) + } + fn format<T>(&self, f: T) -> String + where + T: fmt::UpperExp + fmt::LowerExp + fmt::Display, + { + match self { + Self::LowerExp => format!("{:e}", f), + Self::UpperExp => format!("{:E}", f), + Self::Normal => format!("{}", f), + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8bd0d187061..8584d06b0cc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -205,10 +205,10 @@ pub mod escape; pub mod eta_reduction; pub mod eval_order_dependence; pub mod excessive_bools; -pub mod excessive_precision; pub mod exit; pub mod explicit_write; pub mod fallible_impl_from; +pub mod float_literal; pub mod format; pub mod formatting; pub mod functions; @@ -534,10 +534,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &eval_order_dependence::EVAL_ORDER_DEPENDENCE, &excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, &excessive_bools::STRUCT_EXCESSIVE_BOOLS, - &excessive_precision::EXCESSIVE_PRECISION, &exit::EXIT, &explicit_write::EXPLICIT_WRITE, &fallible_impl_from::FALLIBLE_IMPL_FROM, + &float_literal::EXCESSIVE_PRECISION, + &float_literal::LOSSY_FLOAT_LITERAL, &format::USELESS_FORMAT, &formatting::POSSIBLE_MISSING_COMMA, &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, @@ -836,7 +837,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box eq_op::EqOp); store.register_late_pass(|| box enum_glob_use::EnumGlobUse); store.register_late_pass(|| box enum_clike::UnportableVariant); - store.register_late_pass(|| box excessive_precision::ExcessivePrecision); + store.register_late_pass(|| box float_literal::FloatLiteral); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold)); store.register_late_pass(|| box ptr::Ptr); @@ -1016,6 +1017,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), + LintId::of(&float_literal::LOSSY_FLOAT_LITERAL), LintId::of(&implicit_return::IMPLICIT_RETURN), LintId::of(&indexing_slicing::INDEXING_SLICING), LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL), @@ -1159,8 +1161,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&eta_reduction::REDUNDANT_CLOSURE), LintId::of(&eval_order_dependence::DIVERGING_SUB_EXPRESSION), LintId::of(&eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(&excessive_precision::EXCESSIVE_PRECISION), LintId::of(&explicit_write::EXPLICIT_WRITE), + LintId::of(&float_literal::EXCESSIVE_PRECISION), LintId::of(&format::USELESS_FORMAT), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), @@ -1386,6 +1388,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_variants::MODULE_INCEPTION), LintId::of(&eq_op::OP_REF), LintId::of(&eta_reduction::REDUNDANT_CLOSURE), + LintId::of(&float_literal::EXCESSIVE_PRECISION), LintId::of(&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING), LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), @@ -1566,7 +1569,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(&eq_op::EQ_OP), LintId::of(&erasing_op::ERASING_OP), - LintId::of(&excessive_precision::EXCESSIVE_PRECISION), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8c04afce1d2..51208d74655 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 355] = [ +pub const ALL_LINTS: [Lint; 356] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -492,10 +492,10 @@ pub const ALL_LINTS: [Lint; 355] = [ }, Lint { name: "excessive_precision", - group: "correctness", + group: "style", desc: "excessive precision for float literal", deprecation: None, - module: "excessive_precision", + module: "float_literal", }, Lint { name: "exit", @@ -1001,6 +1001,13 @@ pub const ALL_LINTS: [Lint; 355] = [ deprecation: None, module: "booleans", }, + Lint { + name: "lossy_float_literal", + group: "restriction", + desc: "lossy whole number float literals", + deprecation: None, + module: "float_literal", + }, Lint { name: "main_recursion", group: "style", diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index f32307ce910..bf0325fec79 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -60,26 +60,4 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; - - // Lossy whole-number float literals - let _: f32 = 16_777_216.0; - let _: f32 = 16_777_220.0; - let _: f32 = 16_777_220.0; - let _: f32 = 16_777_220.0; - let _ = 16_777_220.0_f32; - let _: f32 = -16_777_220.0; - let _: f64 = 9_007_199_254_740_992.0; - let _: f64 = 9_007_199_254_740_992.0; - let _: f64 = 9_007_199_254_740_992.0; - let _ = 9_007_199_254_740_992.0_f64; - let _: f64 = -9_007_199_254_740_992.0; - - // Lossless whole number float literals - let _: f32 = 16_777_216.0; - let _: f32 = 16_777_218.0; - let _: f32 = 16_777_220.0; - let _: f32 = -16_777_216.0; - let _: f32 = -16_777_220.0; - let _: f64 = 9_007_199_254_740_992.0; - let _: f64 = -9_007_199_254_740_992.0; } diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index a3d31740027..ce4722a90f9 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -60,26 +60,4 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; - - // Lossy whole-number float literals - let _: f32 = 16_777_217.0; - let _: f32 = 16_777_219.0; - let _: f32 = 16_777_219.; - let _: f32 = 16_777_219.000; - let _ = 16_777_219f32; - let _: f32 = -16_777_219.0; - let _: f64 = 9_007_199_254_740_993.0; - let _: f64 = 9_007_199_254_740_993.; - let _: f64 = 9_007_199_254_740_993.000; - let _ = 9_007_199_254_740_993f64; - let _: f64 = -9_007_199_254_740_993.0; - - // Lossless whole number float literals - let _: f32 = 16_777_216.0; - let _: f32 = 16_777_218.0; - let _: f32 = 16_777_220.0; - let _: f32 = -16_777_216.0; - let _: f32 = -16_777_220.0; - let _: f64 = 9_007_199_254_740_992.0; - let _: f64 = -9_007_199_254_740_992.0; } diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 8941bcfd86d..599773f2f70 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -108,71 +108,5 @@ error: float has excessive precision LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:65:18 - | -LL | let _: f32 = 16_777_217.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:66:18 - | -LL | let _: f32 = 16_777_219.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:67:18 - | -LL | let _: f32 = 16_777_219.; - | ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:68:18 - | -LL | let _: f32 = 16_777_219.000; - | ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:69:13 - | -LL | let _ = 16_777_219f32; - | ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0_f32` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:70:19 - | -LL | let _: f32 = -16_777_219.0; - | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:71:18 - | -LL | let _: f64 = 9_007_199_254_740_993.0; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:72:18 - | -LL | let _: f64 = 9_007_199_254_740_993.; - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:73:18 - | -LL | let _: f64 = 9_007_199_254_740_993.000; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:74:13 - | -LL | let _ = 9_007_199_254_740_993f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0_f64` - -error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/excessive_precision.rs:75:19 - | -LL | let _: f64 = -9_007_199_254_740_993.0; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` - -error: aborting due to 29 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/lossy_float_literal.fixed b/tests/ui/lossy_float_literal.fixed new file mode 100644 index 00000000000..24e372354fc --- /dev/null +++ b/tests/ui/lossy_float_literal.fixed @@ -0,0 +1,35 @@ +// run-rustfix +#![warn(clippy::lossy_float_literal)] + +fn main() { + // Lossy whole-number float literals + let _: f32 = 16_777_216.0; + let _: f32 = 16_777_220.0; + let _: f32 = 16_777_220.0; + let _: f32 = 16_777_220.0; + let _ = 16_777_220_f32; + let _: f32 = -16_777_220.0; + let _: f64 = 9_007_199_254_740_992.0; + let _: f64 = 9_007_199_254_740_992.0; + let _: f64 = 9_007_199_254_740_992.0; + let _ = 9_007_199_254_740_992_f64; + let _: f64 = -9_007_199_254_740_992.0; + + // Lossless whole number float literals + let _: f32 = 16_777_216.0; + let _: f32 = 16_777_218.0; + let _: f32 = 16_777_220.0; + let _: f32 = -16_777_216.0; + let _: f32 = -16_777_220.0; + let _: f64 = 16_777_217.0; + let _: f64 = -16_777_217.0; + let _: f64 = 9_007_199_254_740_992.0; + let _: f64 = -9_007_199_254_740_992.0; + + // Ignored whole number float literals + let _: f32 = 1e25; + let _: f32 = 1E25; + let _: f64 = 1e99; + let _: f64 = 1E99; + let _: f32 = 0.1; +} diff --git a/tests/ui/lossy_float_literal.rs b/tests/ui/lossy_float_literal.rs new file mode 100644 index 00000000000..3dcf98fa0bd --- /dev/null +++ b/tests/ui/lossy_float_literal.rs @@ -0,0 +1,35 @@ +// run-rustfix +#![warn(clippy::lossy_float_literal)] + +fn main() { + // Lossy whole-number float literals + let _: f32 = 16_777_217.0; + let _: f32 = 16_777_219.0; + let _: f32 = 16_777_219.; + let _: f32 = 16_777_219.000; + let _ = 16_777_219f32; + let _: f32 = -16_777_219.0; + let _: f64 = 9_007_199_254_740_993.0; + let _: f64 = 9_007_199_254_740_993.; + let _: f64 = 9_007_199_254_740_993.00; + let _ = 9_007_199_254_740_993f64; + let _: f64 = -9_007_199_254_740_993.0; + + // Lossless whole number float literals + let _: f32 = 16_777_216.0; + let _: f32 = 16_777_218.0; + let _: f32 = 16_777_220.0; + let _: f32 = -16_777_216.0; + let _: f32 = -16_777_220.0; + let _: f64 = 16_777_217.0; + let _: f64 = -16_777_217.0; + let _: f64 = 9_007_199_254_740_992.0; + let _: f64 = -9_007_199_254_740_992.0; + + // Ignored whole number float literals + let _: f32 = 1e25; + let _: f32 = 1E25; + let _: f64 = 1e99; + let _: f64 = 1E99; + let _: f32 = 0.1; +} diff --git a/tests/ui/lossy_float_literal.stderr b/tests/ui/lossy_float_literal.stderr new file mode 100644 index 00000000000..d2193c0c819 --- /dev/null +++ b/tests/ui/lossy_float_literal.stderr @@ -0,0 +1,70 @@ +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:6:18 + | +LL | let _: f32 = 16_777_217.0; + | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` + | + = note: `-D clippy::lossy-float-literal` implied by `-D warnings` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:7:18 + | +LL | let _: f32 = 16_777_219.0; + | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:8:18 + | +LL | let _: f32 = 16_777_219.; + | ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:9:18 + | +LL | let _: f32 = 16_777_219.000; + | ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:10:13 + | +LL | let _ = 16_777_219f32; + | ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:11:19 + | +LL | let _: f32 = -16_777_219.0; + | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:12:18 + | +LL | let _: f64 = 9_007_199_254_740_993.0; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:13:18 + | +LL | let _: f64 = 9_007_199_254_740_993.; + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:14:18 + | +LL | let _: f64 = 9_007_199_254_740_993.00; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:15:13 + | +LL | let _ = 9_007_199_254_740_993f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64` + +error: literal cannot be represented as the underlying type without loss of precision + --> $DIR/lossy_float_literal.rs:16:19 + | +LL | let _: f64 = -9_007_199_254_740_993.0; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` + +error: aborting due to 11 previous errors + -- cgit 1.4.1-3-g733a5 From 4229dbcf335fa7a11b5566d9e916384bf9739c34 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Tue, 7 Jan 2020 17:54:08 +0100 Subject: Run update_lints --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 ++++ src/lintlist/mod.rs | 9 ++++++++- 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ebe97d7b0..4e99342e4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1419,6 +1419,7 @@ Released 2018-09-13 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator [`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies [`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm +[`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports [`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns [`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal [`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline diff --git a/README.md b/README.md index f2ffea7d23c..3103f960839 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 356 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 357 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 325f07eb6cf..77d33e6a0db 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -311,6 +311,7 @@ pub mod unwrap; pub mod use_self; pub mod vec; pub mod wildcard_dependencies; +pub mod wildcard_imports; pub mod write; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -813,6 +814,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &use_self::USE_SELF, &vec::USELESS_VEC, &wildcard_dependencies::WILDCARD_DEPENDENCIES, + &wildcard_imports::WILDCARD_IMPORTS, &write::PRINTLN_EMPTY_STRING, &write::PRINT_LITERAL, &write::PRINT_STDOUT, @@ -1009,6 +1011,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let max_struct_bools = conf.max_struct_bools; store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); + store.register_late_pass(|| box wildcard_imports::WildcardImports); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1105,6 +1108,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unicode::NON_ASCII_LITERAL), LintId::of(&unicode::UNICODE_NOT_NFC), LintId::of(&unused_self::UNUSED_SELF), + LintId::of(&wildcard_imports::WILDCARD_IMPORTS), ]); store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5fdcf08072d..6f6674488b5 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 356] = [ +pub const ALL_LINTS: [Lint; 357] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2415,6 +2415,13 @@ pub const ALL_LINTS: [Lint; 356] = [ deprecation: None, module: "matches", }, + Lint { + name: "wildcard_imports", + group: "pedantic", + desc: "lint `use _::*` statements", + deprecation: None, + module: "wildcard_imports", + }, Lint { name: "wildcard_in_or_patterns", group: "complexity", -- cgit 1.4.1-3-g733a5 From 06a6189376975ddff0d8db2fb20ab407066357b4 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Tue, 14 Jan 2020 13:52:08 +0100 Subject: Move enum_glob_use lint into wildcard_imports pass --- clippy_lints/src/enum_glob_use.rs | 49 ------------------------------------ clippy_lints/src/lib.rs | 6 ++--- clippy_lints/src/wildcard_imports.rs | 35 +++++++++++++++++++++++--- src/lintlist/mod.rs | 2 +- tests/ui/enum_glob_use.fixed | 30 ++++++++++++++++++++++ tests/ui/enum_glob_use.rs | 29 ++++++++++----------- tests/ui/enum_glob_use.stderr | 20 +++++++++------ 7 files changed, 92 insertions(+), 79 deletions(-) delete mode 100644 clippy_lints/src/enum_glob_use.rs create mode 100644 tests/ui/enum_glob_use.fixed (limited to 'src') diff --git a/clippy_lints/src/enum_glob_use.rs b/clippy_lints/src/enum_glob_use.rs deleted file mode 100644 index 4ffc73961a8..00000000000 --- a/clippy_lints/src/enum_glob_use.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! lint on `use`ing all variants of an enum - -use crate::utils::span_lint; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -declare_clippy_lint! { - /// **What it does:** Checks for `use Enum::*`. - /// - /// **Why is this bad?** It is usually better style to use the prefixed name of - /// an enumeration variant, rather than importing variants. - /// - /// **Known problems:** Old-style enumerations that prefix the variants are - /// still around. - /// - /// **Example:** - /// ```rust - /// use std::cmp::Ordering::*; - /// ``` - pub ENUM_GLOB_USE, - pedantic, - "use items that import all variants of an enum" -} - -declare_lint_pass!(EnumGlobUse => [ENUM_GLOB_USE]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse { - fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod<'_>, _: Span, _: HirId) { - let map = cx.tcx.hir(); - // only check top level `use` statements - for item in m.item_ids { - lint_item(cx, map.expect_item(item.id)); - } - } -} - -fn lint_item(cx: &LateContext<'_, '_>, item: &Item<'_>) { - if item.vis.node.is_pub() { - return; // re-exports are fine - } - if let ItemKind::Use(ref path, UseKind::Glob) = item.kind { - if let Res::Def(DefKind::Enum, _) = path.res { - span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); - } - } -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 77d33e6a0db..2b5691f9255 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -197,7 +197,6 @@ pub mod else_if_without_else; pub mod empty_enum; pub mod entry; pub mod enum_clike; -pub mod enum_glob_use; pub mod enum_variants; pub mod eq_op; pub mod erasing_op; @@ -520,7 +519,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &empty_enum::EMPTY_ENUM, &entry::MAP_ENTRY, &enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - &enum_glob_use::ENUM_GLOB_USE, &enum_variants::ENUM_VARIANT_NAMES, &enum_variants::MODULE_INCEPTION, &enum_variants::MODULE_NAME_REPETITIONS, @@ -814,6 +812,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &use_self::USE_SELF, &vec::USELESS_VEC, &wildcard_dependencies::WILDCARD_DEPENDENCIES, + &wildcard_imports::ENUM_GLOB_USE, &wildcard_imports::WILDCARD_IMPORTS, &write::PRINTLN_EMPTY_STRING, &write::PRINT_LITERAL, @@ -837,7 +836,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); store.register_late_pass(|| box booleans::NonminimalBool); store.register_late_pass(|| box eq_op::EqOp); - store.register_late_pass(|| box enum_glob_use::EnumGlobUse); store.register_late_pass(|| box enum_clike::UnportableVariant); store.register_late_pass(|| box float_literal::FloatLiteral); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; @@ -1064,7 +1062,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&doc::DOC_MARKDOWN), LintId::of(&doc::MISSING_ERRORS_DOC), LintId::of(&empty_enum::EMPTY_ENUM), - LintId::of(&enum_glob_use::ENUM_GLOB_USE), LintId::of(&enum_variants::MODULE_NAME_REPETITIONS), LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES), LintId::of(&eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), @@ -1108,6 +1105,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unicode::NON_ASCII_LITERAL), LintId::of(&unicode::UNICODE_NOT_NFC), LintId::of(&unused_self::UNUSED_SELF), + LintId::of(&wildcard_imports::ENUM_GLOB_USE), LintId::of(&wildcard_imports::WILDCARD_IMPORTS), ]); diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 597552f033e..584e7adfccc 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -1,11 +1,32 @@ use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{ + def::{DefKind, Res}, + Item, ItemKind, UseKind, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::BytePos; +declare_clippy_lint! { + /// **What it does:** Checks for `use Enum::*`. + /// + /// **Why is this bad?** It is usually better style to use the prefixed name of + /// an enumeration variant, rather than importing variants. + /// + /// **Known problems:** Old-style enumerations that prefix the variants are + /// still around. + /// + /// **Example:** + /// ```rust + /// use std::cmp::Ordering::*; + /// ``` + pub ENUM_GLOB_USE, + pedantic, + "use items that import all variants of an enum" +} + declare_clippy_lint! { /// **What it does:** Checks for wildcard imports `use _::*`. /// @@ -45,7 +66,7 @@ declare_clippy_lint! { "lint `use _::*` statements" } -declare_lint_pass!(WildcardImports => [WILDCARD_IMPORTS]); +declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]); impl LateLintPass<'_, '_> for WildcardImports { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) { @@ -94,11 +115,17 @@ impl LateLintPass<'_, '_> for WildcardImports { format!("{}::{}", import_source, imports_string) }; + let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res { + (ENUM_GLOB_USE, "usage of wildcard import for enum variants") + } else { + (WILDCARD_IMPORTS, "usage of wildcard import") + }; + span_lint_and_sugg( cx, - WILDCARD_IMPORTS, + lint, span, - "usage of wildcard import", + message, "try", sugg, applicability, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 6f6674488b5..29b5a7ba08a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -460,7 +460,7 @@ pub const ALL_LINTS: [Lint; 357] = [ group: "pedantic", desc: "use items that import all variants of an enum", deprecation: None, - module: "enum_glob_use", + module: "wildcard_imports", }, Lint { name: "enum_variant_names", diff --git a/tests/ui/enum_glob_use.fixed b/tests/ui/enum_glob_use.fixed new file mode 100644 index 00000000000..a98216758bb --- /dev/null +++ b/tests/ui/enum_glob_use.fixed @@ -0,0 +1,30 @@ +// run-rustfix + +#![warn(clippy::enum_glob_use)] +#![allow(unused)] +#![warn(unused_imports)] + +use std::cmp::Ordering::Less; + +enum Enum { + Foo, +} + +use self::Enum::Foo; + +mod in_fn_test { + fn blarg() { + use crate::Enum::Foo; + + let _ = Foo; + } +} + +mod blurg { + pub use std::cmp::Ordering::*; // ok, re-export +} + +fn main() { + let _ = Foo; + let _ = Less; +} diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index e7b2526ca50..5d929c9731d 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,29 +1,30 @@ -#![warn(clippy::all, clippy::pedantic)] -#![allow(unused_imports, dead_code, clippy::missing_docs_in_private_items)] +// run-rustfix + +#![warn(clippy::enum_glob_use)] +#![allow(unused)] +#![warn(unused_imports)] use std::cmp::Ordering::*; enum Enum { - _Foo, + Foo, } use self::Enum::*; -fn blarg() { - use self::Enum::*; // ok, just for a function +mod in_fn_test { + fn blarg() { + use crate::Enum::*; + + let _ = Foo; + } } mod blurg { pub use std::cmp::Ordering::*; // ok, re-export } -mod tests { - use super::*; +fn main() { + let _ = Foo; + let _ = Less; } - -#[allow(non_snake_case)] -mod CamelCaseName {} - -use CamelCaseName::*; - -fn main() {} diff --git a/tests/ui/enum_glob_use.stderr b/tests/ui/enum_glob_use.stderr index a301703c298..69531aed39b 100644 --- a/tests/ui/enum_glob_use.stderr +++ b/tests/ui/enum_glob_use.stderr @@ -1,16 +1,22 @@ -error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:4:1 +error: usage of wildcard import for enum variants + --> $DIR/enum_glob_use.rs:7:5 | LL | use std::cmp::Ordering::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::cmp::Ordering::Less` | = note: `-D clippy::enum-glob-use` implied by `-D warnings` -error: don't use glob imports for enum variants - --> $DIR/enum_glob_use.rs:10:1 +error: usage of wildcard import for enum variants + --> $DIR/enum_glob_use.rs:13:5 | LL | use self::Enum::*; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: try: `self::Enum::Foo` -error: aborting due to 2 previous errors +error: usage of wildcard import for enum variants + --> $DIR/enum_glob_use.rs:17:13 + | +LL | use crate::Enum::*; + | ^^^^^^^^^^^^^^ help: try: `crate::Enum::Foo` + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 8472ecda0f18a2b1045d4b8736e06e774ab1c73a Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Fri, 21 Feb 2020 09:39:38 +0100 Subject: Fix fallout --- clippy_dev/src/main.rs | 5 ++++- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/assign_ops.rs | 4 +++- clippy_lints/src/atomic_ordering.rs | 2 +- clippy_lints/src/attrs.rs | 6 ++++-- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/blacklisted_name.rs | 2 +- clippy_lints/src/block_in_if_condition.rs | 4 ++-- clippy_lints/src/booleans.rs | 10 +++++----- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/cargo_common_metadata.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/consts.rs | 10 ++++------ clippy_lints/src/copies.rs | 2 +- clippy_lints/src/default_trait_access.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc.rs | 8 +++++--- clippy_lints/src/double_comparison.rs | 2 +- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/drop_bounds.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duration_subsec.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/enum_variants.rs | 2 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/functions.rs | 6 +++--- clippy_lints/src/identity_conversion.rs | 2 +- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_let_some_result.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/int_plus_one.rs | 2 +- clippy_lints/src/items_after_statements.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/lifetimes.rs | 12 +++++++++--- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops.rs | 9 ++++++--- clippy_lints/src/matches.rs | 5 ++++- .../src/methods/manual_saturating_arithmetic.rs | 5 ++++- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 5 ++++- clippy_lints/src/misc_early.rs | 5 ++++- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/mul_add.rs | 4 ++-- clippy_lints/src/multiple_crate_versions.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/needless_bool.rs | 6 +++--- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 4 +++- clippy_lints/src/option_env_unwrap.rs | 2 +- clippy_lints/src/overflow_check_conditional.rs | 2 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/precedence.rs | 6 +++--- clippy_lints/src/ptr.rs | 5 ++++- clippy_lints/src/question_mark.rs | 4 ++-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_pattern_matching.rs | 2 +- clippy_lints/src/redundant_static_lifetimes.rs | 2 +- clippy_lints/src/regex.rs | 6 +++--- clippy_lints/src/replace_consts.rs | 2 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/shadow.rs | 7 +++++-- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/trivially_copy_pass_by_ref.rs | 2 +- clippy_lints/src/try_err.rs | 2 +- clippy_lints/src/types.rs | 22 +++++++++++++--------- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unwrap.rs | 4 ++-- clippy_lints/src/use_self.rs | 5 ++++- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 6 +++++- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/utils/mod.rs | 9 ++++++--- clippy_lints/src/utils/ptr.rs | 2 +- clippy_lints/src/utils/sugg.rs | 11 ++++++++--- clippy_lints/src/utils/usage.rs | 4 ++-- clippy_lints/src/vec.rs | 2 +- clippy_lints/src/wildcard_dependencies.rs | 2 +- clippy_lints/src/write.rs | 6 ++++-- clippy_lints/src/zero_div_zero.rs | 2 +- src/driver.rs | 4 ++-- src/main.rs | 2 +- 117 files changed, 219 insertions(+), 162 deletions(-) (limited to 'src') diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index ec0c33109ba..901e663ded3 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,7 +1,10 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, SubCommand}; -use clippy_dev::*; +use clippy_dev::{ + gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list, + replace_region_in_file, Lint, DOCS_LINK, +}; use std::path::Path; mod fmt; diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index 51b6f2f0688..042b83dc386 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -1,5 +1,5 @@ use crate::utils::span_lint; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol; diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index d90a0d67d5a..5c584b18f4c 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -1,7 +1,7 @@ use rustc::lint::in_external_macro; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index e399229b43c..8a7a48aebf9 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, snippet_opt, span_lint_and_help}; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::LitKind; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 7ad0ce23202..bc4e47340c6 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -231,7 +231,9 @@ fn lint_misrefactored_assign_op( #[must_use] fn is_commutative(op: hir::BinOpKind) -> bool { - use rustc_hir::BinOpKind::*; + use rustc_hir::BinOpKind::{ + Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, + }; match op { Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true, Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false, diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 178ee45298e..871ca029b1a 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -2,7 +2,7 @@ use crate::utils::{match_def_path, span_lint_and_help}; use if_chain::if_chain; use rustc::ty; use rustc_hir::def_id::DefId; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6f67acb2921..5c083cefc8d 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,6 +1,6 @@ //! checks for attributes -use crate::reexport::*; +use crate::reexport::Name; use crate::utils::{ first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, without_block_comments, @@ -9,7 +9,9 @@ use if_chain::if_chain; use rustc::lint::in_external_macro; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{ + Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitItem, TraitItemKind, TraitMethod, +}; use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 926b1c63ad1..05f85e92961 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -3,7 +3,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{span_lint, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/blacklisted_name.rs index cb68ba59886..6f26f031431 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/blacklisted_name.rs @@ -1,6 +1,6 @@ use crate::utils::span_lint; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::*; +use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 325e1261714..d004dcddfea 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,10 +1,10 @@ -use crate::utils::*; +use crate::utils::{differing_macro_contexts, higher, snippet_block_with_applicability, span_lint, span_lint_and_sugg}; use matches::matches; use rustc::hir::map::Map; use rustc::lint::in_external_macro; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index d37f77cf6cc..07b4f572dd5 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -5,8 +5,8 @@ use crate::utils::{ use if_chain::if_chain; use rustc::hir::map::Map; use rustc_errors::Applicability; -use rustc_hir::intravisit::*; -use rustc_hir::*; +use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -161,7 +161,7 @@ struct SuggestContext<'a, 'tcx, 'v> { impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { fn recurse(&mut self, suggestion: &Bool) -> Option<()> { - use quine_mc_cluskey::Bool::*; + use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True}; match suggestion { True => { self.output.push_str("true"); @@ -277,7 +277,7 @@ fn suggest(cx: &LateContext<'_, '_>, suggestion: &Bool, terminals: &[&Expr<'_>]) } fn simple_negate(b: Bool) -> Bool { - use quine_mc_cluskey::Bool::*; + use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True}; match b { True => False, False => True, @@ -325,7 +325,7 @@ fn terminal_stats(b: &Bool) -> Stats { &Term(n) => stats.terminals[n as usize] += 1, } } - use quine_mc_cluskey::Bool::*; + use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True}; let mut stats = Stats::default(); recurse(b, &mut stats); stats diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 2adc3b42906..e8168cb7393 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -5,7 +5,7 @@ use crate::utils::{ use if_chain::if_chain; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::{Name, UintTy}; diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index ec53e08f50c..9e0e9d7dd6a 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -6,7 +6,7 @@ use crate::utils::span_lint; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; -use syntax::ast::*; +use syntax::ast::Crate; declare_clippy_lint! { /// **What it does:** Checks to see if all common metadata is defined in diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 88df0772ae5..835f8b7f902 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -3,7 +3,7 @@ use if_chain::if_chain; use rustc::lint::in_external_macro; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::LitKind; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 2b631525501..ecae13a4970 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -2,7 +2,7 @@ use rustc::hir::map::Map; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 684d3448ea4..e0c381ddbfc 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -1,7 +1,7 @@ use crate::utils::{ get_trait_def_id, if_sequence, implements_trait, parent_node_is_if_expr, paths, span_lint_and_help, SpanlessEq, }; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 7efc62d4c2e..edfd2486be2 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -7,13 +7,13 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::{bug, span_bug}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::*; +use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp}; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; use std::convert::TryInto; use std::hash::{Hash, Hasher}; -use syntax::ast::{FloatTy, LitKind}; +use syntax::ast::{FloatTy, LitFloatType, LitKind}; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] @@ -152,8 +152,6 @@ impl Constant { /// Parses a `LitKind` to a `Constant`. pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { - use syntax::ast::*; - match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), @@ -277,7 +275,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { #[allow(clippy::cast_possible_wrap)] fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> { - use self::Constant::*; + use self::Constant::{Bool, Int}; match *o { Bool(b) => Some(Bool(!b)), Int(value) => { @@ -293,7 +291,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> { - use self::Constant::*; + use self::Constant::{Int, F32, F64}; match *o { Int(value) => { let ity = match ty.kind { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index d2d20375daf..996f80a757e 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -2,7 +2,7 @@ use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span use crate::utils::{SpanlessEq, SpanlessHash}; use rustc::ty::Ty; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::*; +use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 0e1380df921..f99e6d96e03 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -1,7 +1,7 @@ use if_chain::if_chain; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index efb44ab6dbb..f130a69778f 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -2,7 +2,7 @@ use crate::utils::paths; use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; use if_chain::if_chain; use rustc::ty::{self, Ty}; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind, TraitRef}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 9b8664c1320..be65fd21a68 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -350,7 +350,7 @@ fn check_attrs<'a>(cx: &LateContext<'_, '_>, valid_idents: &FxHashSet<String>, a let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); // Iterate over all `Events` and combine consecutive events into one let events = parser.coalesce(|previous, current| { - use pulldown_cmark::Event::*; + use pulldown_cmark::Event::Text; let previous_range = previous.1; let current_range = current.1; @@ -374,8 +374,10 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize spans: &[(usize, Span)], ) -> DocHeaders { // true if a safety header was found - use pulldown_cmark::Event::*; - use pulldown_cmark::Tag::*; + use pulldown_cmark::Event::{ + Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, + }; + use pulldown_cmark::Tag::{CodeBlock, Heading, Link}; let mut headers = DocHeaders { safety: false, diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 934e3ccdf87..44f85d1ea6e 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -1,7 +1,7 @@ //! Lint on unnecessary double comparisons. Some examples: use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index d08981e8bad..c4c4758ebb7 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,7 +1,7 @@ use crate::utils::span_lint; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind}; declare_clippy_lint! { /// **What it does:** Checks for unnecessary double parentheses. diff --git a/clippy_lints/src/drop_bounds.rs b/clippy_lints/src/drop_bounds.rs index 1d445a15323..f4966808279 100644 --- a/clippy_lints/src/drop_bounds.rs +++ b/clippy_lints/src/drop_bounds.rs @@ -1,6 +1,6 @@ use crate::utils::{match_def_path, paths, span_lint}; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{GenericBound, GenericParam, WhereBoundPredicate, WherePredicate}; use rustc_lint::LateLintPass; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 29351deea28..bd9bdfef090 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,7 +1,7 @@ use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_lint_and_note}; use if_chain::if_chain; use rustc::ty; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 366996fb381..b35a8facf8b 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -1,6 +1,6 @@ use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index b87900180f2..c41c5aadbee 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -3,7 +3,7 @@ use rustc::lint::in_external_macro; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index c43db68d20f..010d208c9e7 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -1,7 +1,7 @@ //! lint when there is an enum with no variants use crate::utils::span_lint_and_then; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index d32e78798af..19da4c4bc9a 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -5,7 +5,7 @@ use if_chain::if_chain; use rustc::hir::map::Map; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 2e14956ecd7..e8063ac3006 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -5,7 +5,7 @@ use crate::consts::{miri_to_const, Constant}; use crate::utils::span_lint; use rustc::ty; use rustc::ty::util::IntTypeExt; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::convert::TryFrom; diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 75205f96400..0d14b8a75e8 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -6,7 +6,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use syntax::ast::*; +use syntax::ast::{EnumDef, Item, ItemKind, VisibilityKind}; declare_clippy_lint! { /// **What it does:** Detects enumeration variants that are prefixed or suffixed diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 01b04220a06..1df0bcc6b7e 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -2,7 +2,7 @@ use crate::utils::{ implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq, }; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index e08e01c1d67..3ff0506e28d 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -1,4 +1,4 @@ -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 73bd7b3a143..850c7f728bd 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,12 +1,12 @@ use rustc::ty::layout::LayoutOf; use rustc::ty::{self, Ty}; use rustc_hir::intravisit; -use rustc_hir::{self, *}; +use rustc_hir::{self, Body, FnDecl, HirId, HirIdSet, ItemKind, Node}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; -use rustc_typeck::expr_use_visitor::*; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use crate::utils::span_lint; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 5ef93384500..8c324e09df5 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -3,7 +3,7 @@ use matches::matches; use rustc::lint::in_external_macro; use rustc::ty::{self, Ty}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index f143c7462ad..d6b847d1dbb 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -3,7 +3,7 @@ use if_chain::if_chain; use rustc::hir::map::Map; use rustc::ty; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 4aefa941dab..a3005d8bd82 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,7 +1,7 @@ use crate::utils::{is_expn_of, match_function_call, paths, span_lint, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::LitKind; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 87792b9fba4..19a122594cb 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom { fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef<'_>]) { use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; - use rustc_hir::*; + use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath}; struct FindPanicUnwrap<'a, 'tcx> { lcx: &'a LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 8707259a2c8..18006f0534f 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::{f32, f64, fmt}; -use syntax::ast::*; +use syntax::ast::{FloatTy, LitFloatType, LitKind}; declare_clippy_lint! { /// **What it does:** Checks for float literals with a precision greater diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 36ed7c475ed..6c80b6525bb 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -5,7 +5,7 @@ use crate::utils::{ }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, MatchSource, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 31e924e36ab..0ab6b1242b3 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -4,7 +4,7 @@ use rustc::lint::in_external_macro; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use syntax::ast::*; +use syntax::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; declare_clippy_lint! { /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index ce0bfea5160..26b9f2cd613 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -497,7 +497,7 @@ fn is_mutable_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>, tys: &mut FxHash static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]]; fn is_mutable_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet<DefId>) -> bool { - use ty::TyKind::*; + use ty::TyKind::{Adt, Array, Bool, Char, Float, Int, RawPtr, Ref, Slice, Str, Tuple, Uint}; match ty.kind { // primitive types are never mutable Bool | Char | Int(_) | Uint(_) | Float(_) | Str => false, @@ -593,7 +593,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - use hir::ExprKind::*; + use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; if self.mutates_static { return; @@ -631,7 +631,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } fn is_mutated_static(cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) -> bool { - use hir::ExprKind::*; + use hir::ExprKind::{Field, Index, Path}; match e.kind { Path(ref qpath) => { diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index 86478f093c9..3d073421984 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -2,7 +2,7 @@ use crate::utils::{ match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then, }; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 1896751ff6f..abd546870aa 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,5 +1,5 @@ use rustc::ty; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index a9826d58633..33e2471d5b8 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,7 +1,7 @@ use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{print, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 8deed214203..4689e24f368 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -4,7 +4,7 @@ use rustc::lint::in_external_macro; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{BinOpKind, Expr, ExprKind, UnOp}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index ac9442e9607..f4a7b798521 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -3,7 +3,7 @@ use crate::consts::{constant, Constant}; use crate::utils::{higher, span_lint, span_lint_and_help}; use rustc::ty; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::RangeLimits; diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index cee54488df4..cd989c0ea6f 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,4 +1,4 @@ -use rustc_hir::*; +use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index 058ee7265fb..355e75d0d55 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -2,7 +2,7 @@ use crate::utils::{in_macro, span_lint_and_then}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::*; +use rustc_hir::{def_id, Crate, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index ed9a958f91b..85c61ba2396 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -3,7 +3,7 @@ use crate::utils::span_lint_and_then; use crate::utils::sugg::DiagnosticBuilderExt; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{TraitItem, TraitItemKind, TraitMethod}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::{Attribute, Name}; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index cb2d62407ce..c6734427dab 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind}; use crate::utils::{snippet_opt, span_lint_and_then}; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 6d944ae8c33..13da725393b 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -4,7 +4,7 @@ use crate::utils::span_lint; use matches::matches; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Block, ItemKind, StmtKind}; declare_clippy_lint! { /// **What it does:** Checks for items declared after some statement in a block. diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0cd02f21238..39c8c4cfa69 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -3,7 +3,7 @@ use crate::utils::{snippet_opt, span_lint_and_then}; use rustc::ty::layout::LayoutOf; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index aa394c85e30..e08042bcbb2 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,6 +1,6 @@ use rustc::mir::interpret::ConstValue; use rustc::ty::{self, ConstKind}; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index aa538a4be9d..821ca2fefa4 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -3,7 +3,7 @@ use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::*; +use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{Span, Spanned}; diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index c2a404ebee7..5690a12141b 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,6 +1,6 @@ use if_chain::if_chain; use rustc::lint::in_external_macro; -use rustc_hir::*; +use rustc_hir::{PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index f98021bca45..a120e3a7517 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -3,15 +3,21 @@ use rustc::hir::map::Map; use rustc::lint::in_external_macro; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::*; +use rustc_hir::intravisit::{ + walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor, +}; use rustc_hir::FnRetTy::Return; -use rustc_hir::*; +use rustc_hir::{ + BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, + ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitItem, TraitItemKind, TraitMethod, Ty, + TyKind, WhereClause, WherePredicate, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::kw; -use crate::reexport::*; +use crate::reexport::Name; use crate::utils::{last_path_segment, span_lint, trait_ref_of_method}; declare_clippy_lint! { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 2419d42394e..7c8001eebd4 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -7,7 +7,7 @@ use rustc::lint::in_external_macro; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind, Lit, LitFloatType, LitIntType, LitKind}; declare_clippy_lint! { /// **What it does:** Warns if a long integral or floating-point constant does diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 393fbd2aaef..eb15b104bea 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,5 +1,5 @@ use crate::consts::{constant, Constant}; -use crate::reexport::*; +use crate::reexport::Name; use crate::utils::paths; use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ @@ -19,13 +19,16 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{ + def_id, BinOpKind, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, GenericArg, HirId, LoopSource, + MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind, +}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::{BytePos, Symbol}; -use rustc_typeck::expr_use_visitor::*; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; use syntax::ast; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 72131084311..d9d3611bc5a 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -12,7 +12,10 @@ use rustc::lint::in_external_macro; use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; -use rustc_hir::*; +use rustc_hir::{ + print, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, PatKind, QPath, + RangeEnd, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 4e3c95f9f73..19f3c447861 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -23,7 +23,10 @@ pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr< }; if ty.is_signed() { - use self::{MinMax::*, Sign::*}; + use self::{ + MinMax::{Max, Min}, + Sign::{Neg, Pos}, + }; let sign = if let Some(sign) = lit_sign(arith_rhs) { sign diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 80a937aadb0..4df963a4f79 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -4,7 +4,7 @@ use rustc::hir::map::Map; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; -use rustc_hir::{self, *}; +use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index b3431c05378..b02c993de52 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_simple, Constant}; use crate::utils::{match_def_path, paths, span_lint}; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::cmp::Ordering; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 583bdd43df8..85d66db83b1 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -3,7 +3,10 @@ use matches::matches; use rustc::ty; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::*; +use rustc_hir::{ + def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty, + TyKind, UnOp, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{ExpnKind, Span}; diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 3f17ac3de22..6e89f35143b 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -9,7 +9,10 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use syntax::ast::*; +use syntax::ast::{ + Block, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind, + StmtKind, UnOp, +}; use syntax::visit::{walk_expr, FnKind, Visitor}; declare_clippy_lint! { diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 238863e8c67..7446b732c4b 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use crate::utils::{sext, span_lint_and_then}; use if_chain::if_chain; use rustc::ty::{self}; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; diff --git a/clippy_lints/src/mul_add.rs b/clippy_lints/src/mul_add.rs index 5de93663499..57e56d8f959 100644 --- a/clippy_lints/src/mul_add.rs +++ b/clippy_lints/src/mul_add.rs @@ -1,9 +1,9 @@ use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::*; +use crate::utils::{snippet, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for expressions of the form `a * b + c` diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index d07b21bfa99..0bcce04e812 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -4,7 +4,7 @@ use crate::utils::span_lint; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; -use syntax::ast::*; +use syntax::ast::Crate; use itertools::Itertools; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 2d70b65bb1e..aeffcd34110 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,7 +1,7 @@ use crate::utils::span_lint; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty}; -use rustc_hir::*; +use rustc_hir::{print, BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index db4012146df..7282874fdbd 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -5,7 +5,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{higher, parent_node_is_if_expr, span_lint, span_lint_and_sugg}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; @@ -62,7 +62,7 @@ declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) { - use self::Expression::*; + use self::Expression::{Bool, RetBool}; if let Some((ref pred, ref then_block, Some(ref else_expr))) = higher::if_block(&e) { let reduce = |ret, not| { let mut applicability = Applicability::MachineApplicable; @@ -191,7 +191,7 @@ fn check_comparison<'a, 'tcx>( right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>, ) { - use self::Expression::*; + use self::Expression::{Bool, Other}; if let ExprKind::Binary(_, ref left_side, ref right_side) = e.kind { let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side)); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 7a0f3bdd355..10782b9f3b4 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -9,7 +9,7 @@ use rustc::ty::{self, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::intravisit::FnKind; -use rustc_hir::*; +use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, ItemKind, Node, PatKind, QPath, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits; use rustc_infer::traits::misc::can_type_implement_copy; diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index efe5f26c423..65643d89df5 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,6 +1,6 @@ use if_chain::if_chain; use rustc::lint::in_external_macro; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index bd4ada23762..4681e990df8 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,5 +1,5 @@ use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 48ffc113546..46e26b32697 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -7,7 +7,7 @@ use std::ptr; use rustc::ty::adjustment::Adjust; use rustc::ty::{Ty, TypeFlags}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5411e324615..de5ae5d3032 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -4,7 +4,9 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::SymbolStr; use std::cmp::Ordering; -use syntax::ast::*; +use syntax::ast::{ + Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Ident, Item, ItemKind, Local, Mac, Pat, PatKind, +}; use syntax::attr; use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 1af7793499f..6dc6893bf71 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -2,7 +2,7 @@ use crate::utils::{is_direct_expn_of, span_lint_and_help}; use if_chain::if_chain; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind}; declare_clippy_lint! { /// **What it does:** Checks for usage of `option_env!(...).unwrap()` and diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index df3f588f38a..b90fdc232e7 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -1,6 +1,6 @@ use crate::utils::{span_lint, SpanlessEq}; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index b26ad1a5b45..76a77e25de3 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,6 +1,6 @@ use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, paths, span_lint}; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index dfd25f1c9db..1445df41c45 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,6 +1,6 @@ use crate::utils::{is_automatically_derived, span_lint_hir}; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index adaf8bb77a2..775a8ad0b93 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,7 +1,7 @@ use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::path::{Component, Path}; diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 27e67bbe718..8ba4e10c966 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use syntax::ast::*; +use syntax::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; declare_clippy_lint! { /// **What it does:** Checks for operations where precedence may be unclear @@ -123,7 +123,7 @@ fn is_arith_expr(expr: &Expr) -> bool { #[must_use] fn is_bit_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; + use syntax::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr}; match op { BitXor | BitAnd | BitOr | Shl | Shr => true, _ => false, @@ -132,7 +132,7 @@ fn is_bit_op(op: BinOpKind) -> bool { #[must_use] fn is_arith_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; + use syntax::ast::BinOpKind::{Add, Div, Mul, Rem, Sub}; match op { Add | Sub | Mul | Div | Rem => true, _ => false, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d868253b85c..c1aee94aa42 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -8,7 +8,10 @@ use crate::utils::{ use if_chain::if_chain; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{ + BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, + Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitItem, TraitItemKind, TraitMethod, Ty, TyKind, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 46c4746d2f5..f21c2985d19 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,11 +1,11 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::*; +use rustc_hir::{def, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::paths::*; +use crate::utils::paths::{OPTION, OPTION_NONE}; use crate::utils::sugg::Sugg; use crate::utils::{higher, match_def_path, match_type, span_lint_and_then, SpanlessEq}; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 1be59787721..f1a93d508ce 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,6 +1,6 @@ use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index e419ae09a3f..ddb0c748434 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -529,7 +529,7 @@ impl TypeVisitor<'_> for ContainsRegion { } fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { - use rustc::mir::Rvalue::*; + use rustc::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use}; let mut visit_op = |op: &mir::Operand<'_>| match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local), diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 57349715c78..a839a023e52 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -2,7 +2,7 @@ use crate::utils::span_lint_and_sugg; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind}; declare_clippy_lint! { /// **What it does:** Checks for fields in struct literals where shorthands diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs index f0acd993480..c8706c2b363 100644 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ b/clippy_lints/src/redundant_pattern_matching.rs @@ -1,6 +1,6 @@ use crate::utils::{match_qpath, paths, snippet, span_lint_and_then}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use syntax::ast::LitKind; diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 9cebe310d5f..98ec793de7c 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -2,7 +2,7 @@ use crate::utils::{snippet, span_lint_and_then}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use syntax::ast::*; +use syntax::ast::{Item, ItemKind, Ty, TyKind}; declare_clippy_lint! { /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime. diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 5de0e441367..028b89b39b9 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -2,7 +2,7 @@ use crate::consts::{constant, Constant}; use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::*; +use rustc_hir::{Block, BorrowKind, Crate, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, Span}; @@ -145,8 +145,8 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option< } fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { - use regex_syntax::hir::Anchor::*; - use regex_syntax::hir::HirKind::*; + use regex_syntax::hir::Anchor::{EndText, StartText}; + use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; let is_literal = |e: &[regex_syntax::hir::Hir]| { e.iter().all(|e| match *e.kind() { diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index 66e1df72b25..aca1ebbd508 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -2,7 +2,7 @@ use crate::utils::{match_def_path, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index 63fdd599b51..6820d1620bd 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -1,5 +1,5 @@ use crate::utils::{get_trait_def_id, paths, span_lint}; -use rustc_hir::*; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 8e2ede04476..0dc2705550b 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,9 +1,12 @@ -use crate::reexport::*; +use crate::reexport::Name; use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; use rustc::lint::in_external_macro; use rustc::ty; use rustc_hir::intravisit::FnKind; -use rustc_hir::*; +use rustc_hir::{ + Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, + UnOp, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 48d0e53d163..71fcff33544 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc::hir::map::Map; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ffe7c13ec57..20ed4d9aac0 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use rustc::lint::in_external_macro; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 7e699844ef2..a1f5dee2a9c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -7,7 +7,7 @@ use if_chain::if_chain; use matches::matches; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Symbol; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 858b505712d..d343ec4a848 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,6 +1,6 @@ use crate::utils::{in_macro, snippet, span_lint_and_help, SpanlessHash}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::*; +use rustc_hir::{GenericBound, Generics, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index e6a9aa3c9a6..68c924cea47 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -4,7 +4,7 @@ use crate::utils::{ use if_chain::if_chain; use rustc::ty::{self, Ty}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::borrow::Cow; diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 1bacb4683c3..e00bc2e090a 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -8,7 +8,7 @@ use rustc::ty; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; -use rustc_hir::*; +use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 15f77d62201..a6624408ce0 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -3,7 +3,7 @@ use if_chain::if_chain; use rustc::lint::in_external_macro; use rustc::ty::Ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index d23487b5b33..e9c0b0935fa 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -12,7 +12,11 @@ use rustc::ty::{self, InferTy, Ty, TyCtxt, TypeckTables}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{ + BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, + ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitItem, + TraitItemKind, TraitMethod, TyKind, UnOp, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -1679,9 +1683,9 @@ fn detect_absurd_comparison<'a, 'tcx>( lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> { - use crate::types::AbsurdComparisonResult::*; - use crate::types::ExtremeType::*; - use crate::utils::comparisons::*; + use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible}; + use crate::types::ExtremeType::{Maximum, Minimum}; + use crate::utils::comparisons::{normalize_comparison, Rel}; // absurd comparison only makes sense on primitive types // primitive types don't implement comparison operators with each other @@ -1726,7 +1730,7 @@ fn detect_absurd_comparison<'a, 'tcx>( } fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> { - use crate::types::ExtremeType::*; + use crate::types::ExtremeType::{Maximum, Minimum}; let ty = cx.tables.expr_ty(expr); @@ -1755,8 +1759,8 @@ fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - use crate::types::AbsurdComparisonResult::*; - use crate::types::ExtremeType::*; + use crate::types::AbsurdComparisonResult::{AlwaysFalse, AlwaysTrue, InequalityImpossible}; + use crate::types::ExtremeType::{Maximum, Minimum}; if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.kind { if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { @@ -1863,7 +1867,7 @@ impl Ord for FullInt { } fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { - use std::*; + use std::{i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize}; if let ExprKind::Cast(ref cast_exp, _) = expr.kind { let pre_cast_ty = cx.tables.expr_ty(cast_exp); @@ -1963,7 +1967,7 @@ fn upcast_comparison_bounds_err<'a, 'tcx>( rhs: &'tcx Expr<'_>, invert: bool, ) { - use crate::utils::comparisons::*; + use crate::utils::comparisons::Rel; if let Some((lb, ub)) = lhs_bounds { if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index eaf9f2e85cb..355d2ec0f1c 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,6 +1,6 @@ use crate::utils::{is_allowed, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 02309639875..2b2df424150 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -3,7 +3,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::SymbolStr; -use syntax::ast::*; +use syntax::ast::{Ident, Item, ItemKind, UseTree, UseTreeKind}; declare_clippy_lint! { /// **What it does:** Checks for imports that remove "unsafe" from an item's diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 4fd421e4af9..79dd93e64ff 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -2,8 +2,8 @@ use crate::utils::{higher::if_block, match_type, paths, span_lint_and_then, usag use if_chain::if_chain; use rustc::hir::map::Map; use rustc::lint::in_external_macro; -use rustc_hir::intravisit::*; -use rustc_hir::*; +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f1d66c1bc25..4170dcc7fad 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -7,7 +7,10 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{ + def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath, + TyKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 52ccdf95d57..a4dc24cecc2 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -157,7 +157,7 @@ impl PrintVisitor { } fn next(&mut self, s: &'static str) -> String { - use std::collections::hash_map::Entry::*; + use std::collections::hash_map::Entry::{Occupied, Vacant}; match self.ids.entry(s) { // already there: start numbering from `1` Occupied(mut occ) => { diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index f5f35afa9ba..c62f95cd562 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -3,7 +3,11 @@ use crate::utils::differing_macro_contexts; use rustc::ich::StableHashingContextProvider; use rustc::ty::TypeckTables; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::*; +use rustc_hir::{ + BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg, + GenericArgs, Guard, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, + TyKind, TypeBinding, +}; use rustc_lint::LateContext; use std::hash::Hash; use syntax::ast::Name; diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 759feafc75b..85fee84cb3b 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index b13648afda9..2689cab2817 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -40,7 +40,10 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::Node; -use rustc_hir::*; +use rustc_hir::{ + def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, HirId, ImplItem, ImplItemKind, Item, ItemKind, + MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, TyKind, Unsafety, +}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::predicate_for_trait_def; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -52,7 +55,7 @@ use smallvec::SmallVec; use syntax::ast::{self, Attribute, LitKind}; use crate::consts::{constant, Constant}; -use crate::reexport::*; +use crate::reexport::Name; /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). @@ -1289,7 +1292,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - use ty::TyKind::*; + use ty::TyKind::{Adt, Array, Dynamic, Foreign, Opaque, RawPtr, Ref, Slice, Tuple}; match ty.kind { Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index 8a59bcc9854..3d97c18e9b4 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -1,7 +1,7 @@ use crate::utils::{get_pat_name, match_var, snippet}; use rustc::hir::map::Map; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{Body, BodyId, Expr, ExprKind, Param}; use rustc_lint::LateContext; use rustc_span::source_map::Span; use std::borrow::Cow; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 5c9e3ab80bb..278505859b7 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -426,7 +426,10 @@ enum Associativity { /// associative. #[must_use] fn associativity(op: &AssocOp) -> Associativity { - use syntax::util::parser::AssocOp::*; + use syntax::util::parser::AssocOp::{ + Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater, + GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, + }; match *op { Assign | AssignOp(_) => Associativity::Right, @@ -439,7 +442,7 @@ fn associativity(op: &AssocOp) -> Associativity { /// Converts a `hir::BinOp` to the corresponding assigning binary operator. fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { - use syntax::token::BinOpToken::*; + use syntax::token::BinOpToken::{And, Caret, Minus, Or, Percent, Plus, Shl, Shr, Slash, Star}; AssocOp::AssignOp(match op.node { hir::BinOpKind::Add => Plus, @@ -466,7 +469,9 @@ fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { /// Converts an `ast::BinOp` to the corresponding assigning binary operator. fn astbinop2assignop(op: ast::BinOp) -> AssocOp { - use syntax::ast::BinOpKind::*; + use syntax::ast::BinOpKind::{ + Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, + }; use syntax::token::BinOpToken; AssocOp::AssignOp(match op.node { diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 8fff1c7a16c..3e8b29295f3 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -4,11 +4,11 @@ use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::*; +use rustc_hir::{def_id, Expr, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_typeck::expr_use_visitor::*; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use syntax::ast; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index bc2c827b0af..726a34856ae 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -3,7 +3,7 @@ use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_su use if_chain::if_chain; use rustc::ty::{self, Ty}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs index 2aa68842da4..0be168d563a 100644 --- a/clippy_lints/src/wildcard_dependencies.rs +++ b/clippy_lints/src/wildcard_dependencies.rs @@ -2,7 +2,7 @@ use crate::utils::span_lint; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; -use syntax::ast::*; +use syntax::ast::Crate; use if_chain::if_chain; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 0be52c2aa3d..904e2fab07a 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -9,7 +9,7 @@ use rustc_parse::parser; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Span}; -use syntax::ast::*; +use syntax::ast::{Expr, ExprKind, Mac, StrLit, StrStyle}; use syntax::token; use syntax::tokenstream::TokenStream; @@ -317,7 +317,9 @@ fn newline_span(fmtstr: &StrLit) -> Span { /// ``` #[allow(clippy::too_many_lines)] fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) { - use fmt_macros::*; + use fmt_macros::{ + AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, Parser, Piece, + }; let tts = tts.clone(); let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false, None); diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index f36da58843f..42cb9a77db0 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -1,7 +1,7 @@ use crate::consts::{constant_simple, Constant}; use crate::utils::span_lint_and_help; use if_chain::if_chain; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/src/driver.rs b/src/driver.rs index 097b796e785..7865f6bb9dd 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -15,7 +15,7 @@ extern crate rustc_interface; use rustc::ty::TyCtxt; use rustc_interface::interface; -use rustc_tools_util::*; +use rustc_tools_util::VersionInfo; use lazy_static::lazy_static; use std::borrow::Cow; @@ -93,7 +93,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { #[allow(clippy::find_map, clippy::filter_map)] fn describe_lints() { - use lintlist::*; + use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS}; use std::collections::HashSet; println!( diff --git a/src/main.rs b/src/main.rs index 8f9afb95337..93e6996be06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] -use rustc_tools_util::*; +use rustc_tools_util::VersionInfo; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. -- cgit 1.4.1-3-g733a5 From c636c6a55b92daef5af4e1c459c0eaf3f5787945 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 14 Dec 2019 09:28:11 -0800 Subject: Add lints to detect inaccurate and inefficient FP operations Add lints to detect floating point computations that are either inaccurate or inefficient and suggest better alternatives. --- CHANGELOG.md | 1 + clippy_lints/src/floating_point_arithmetic.rs | 228 ++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 3 + src/lintlist/mod.rs | 7 + tests/ui/floating_point_arithmetic.rs | 76 +++++++++ tests/ui/floating_point_arithmetic.stderr | 174 ++++++++++++++++++++ 6 files changed, 489 insertions(+) create mode 100644 clippy_lints/src/floating_point_arithmetic.rs create mode 100644 tests/ui/floating_point_arithmetic.rs create mode 100644 tests/ui/floating_point_arithmetic.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e99342e4a4..55e46bf6d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,6 +1169,7 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`inaccurate_floating_point_computation`]: https://rust-lang.github.io/rust-clippy/master/index.html#inaccurate_floating_point_computation [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs new file mode 100644 index 00000000000..935d8b58146 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -0,0 +1,228 @@ +use crate::consts::{ + constant, + Constant::{F32, F64}, +}; +use crate::utils::*; +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc_errors::Applicability; +use rustc_session::declare_tool_lint; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; + +declare_clippy_lint! { + /// **What it does:** Looks for numerically unstable floating point + /// computations and suggests better alternatives. + /// + /// **Why is this bad?** Numerically unstable floating point computations + /// cause rounding errors to magnify and distorts the results strongly. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// use std::f32::consts::E; + /// + /// let a = 1f32.log(2.0); + /// let b = 1f32.log(10.0); + /// let c = 1f32.log(E); + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// let a = 1f32.log2(); + /// let b = 1f32.log10(); + /// let c = 1f32.ln(); + /// ``` + pub INACCURATE_FLOATING_POINT_COMPUTATION, + nursery, + "checks for numerically unstable floating point computations" +} + +declare_clippy_lint! { + /// **What it does:** Looks for inefficient floating point computations + /// and suggests faster alternatives. + /// + /// **Why is this bad?** Lower performance. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// use std::f32::consts::E; + /// + /// let a = (2f32).powf(3.0); + /// let c = E.powf(3.0); + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// let a = (3f32).exp2(); + /// let b = (3f32).exp(); + /// ``` + pub SLOW_FLOATING_POINT_COMPUTATION, + nursery, + "checks for inefficient floating point computations" +} + +declare_lint_pass!(FloatingPointArithmetic => [ + INACCURATE_FLOATING_POINT_COMPUTATION, + SLOW_FLOATING_POINT_COMPUTATION +]); + +fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { + let recv = &args[0]; + let arg = sugg::Sugg::hir(cx, recv, "..").maybe_par(); + + if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { + let method; + + if F32(2.0) == value || F64(2.0) == value { + method = "log2"; + } else if F32(10.0) == value || F64(10.0) == value { + method = "log10"; + } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + method = "ln"; + } else { + return; + } + + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "logarithm for bases 2, 10 and e can be computed more accurately", + "consider using", + format!("{}.{}()", arg, method), + Applicability::MachineApplicable, + ); + } +} + +// TODO: Lint expressions of the form `(x + 1).ln()` and `(x + y).ln()` +// where y > 1 and suggest usage of `(x + (y - 1)).ln_1p()` instead +fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; + if op.node == BinOpKind::Add; + if let Some((value, _)) = constant(cx, cx.tables, lhs); + if F32(1.0) == value || F64(1.0) == value; + then { + let arg = sugg::Sugg::hir(cx, rhs, "..").maybe_par(); + + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "ln(1 + x) can be computed more accurately", + "consider using", + format!("{}.ln_1p()", arg), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { + // Check receiver + if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { + let method; + + if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + method = "exp"; + } else if F32(2.0) == value || F64(2.0) == value { + method = "exp2"; + } else { + return; + } + + span_lint_and_sugg( + cx, + SLOW_FLOATING_POINT_COMPUTATION, + expr.span, + "exponent for bases 2 and e can be computed more efficiently", + "consider using", + format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method), + Applicability::MachineApplicable, + ); + } + + // Check argument + if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { + let help; + let method; + + if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + help = "square-root of a number can be computer more efficiently"; + method = "sqrt"; + } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { + help = "cube-root of a number can be computer more efficiently"; + method = "cbrt"; + } else { + return; + } + + span_lint_and_sugg( + cx, + SLOW_FLOATING_POINT_COMPUTATION, + expr.span, + help, + "consider using", + format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method), + Applicability::MachineApplicable, + ); + } +} + +// TODO: Lint expressions of the form `x.exp() - y` where y > 1 +// and suggest usage of `x.exp_m1() - (y - 1)` instead +fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; + if op.node == BinOpKind::Sub; + if cx.tables.expr_ty(lhs).is_floating_point(); + if let Some((value, _)) = constant(cx, cx.tables, rhs); + if F32(1.0) == value || F64(1.0) == value; + if let ExprKind::MethodCall(ref path, _, ref method_args) = lhs.kind; + if path.ident.name.as_str() == "exp"; + then { + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "(e.pow(x) - 1) can be computed more accurately", + "consider using", + format!( + "{}.exp_m1()", + sugg::Sugg::hir(cx, &method_args[0], "..") + ), + Applicability::MachineApplicable, + ); + } + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { + let recv_ty = cx.tables.expr_ty(&args[0]); + + if recv_ty.is_floating_point() { + match &*path.ident.name.as_str() { + "ln" => check_ln1p(cx, expr, args), + "log" => check_log_base(cx, expr, args), + "powf" => check_powf(cx, expr, args), + _ => {}, + } + } + } else { + check_expm1(cx, expr); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2b5691f9255..9a904141fcf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1000,6 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); @@ -1648,6 +1649,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&floating_point_arithmetic::INACCURATE_FLOATING_POINT_COMPUTATION), + LintId::of(&floating_point_arithmetic::SLOW_FLOATING_POINT_COMPUTATION), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 29b5a7ba08a..fee59507454 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -749,6 +749,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, + Lint { + name: "inaccurate_floating_point_computation", + group: "nursery", + desc: "checks for numerically unstable floating point computations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs new file mode 100644 index 00000000000..5291e5cf022 --- /dev/null +++ b/tests/ui/floating_point_arithmetic.rs @@ -0,0 +1,76 @@ +#![allow(dead_code)] +#![warn( + clippy::inaccurate_floating_point_computation, + clippy::slow_floating_point_computation +)] + +const TWO: f32 = 2.0; +const E: f32 = std::f32::consts::E; + +fn check_log_base() { + let x = 1f32; + let _ = x.log(2f32); + let _ = x.log(10f32); + let _ = x.log(std::f32::consts::E); + let _ = x.log(TWO); + let _ = x.log(E); + + let x = 1f64; + let _ = x.log(2f64); + let _ = x.log(10f64); + let _ = x.log(std::f64::consts::E); +} + +fn check_ln1p() { + let x = 1f32; + let _ = (1.0 + x).ln(); + let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x.powi(2)).ln(); + let _ = (1.0 + x.powi(2) * 2.0).ln(); + let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); + // Cases where the lint shouldn't be applied + let _ = (x + 1.0).ln(); + let _ = (1.0 + x + 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); + + let x = 1f64; + let _ = (1.0 + x).ln(); + let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x.powi(2)).ln(); + // Cases where the lint shouldn't be applied + let _ = (x + 1.0).ln(); + let _ = (1.0 + x + 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); +} + +fn check_powf() { + let x = 3f32; + let _ = 2f32.powf(x); + let _ = std::f32::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); + + let x = 3f64; + let _ = 2f64.powf(x); + let _ = std::f64::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); +} + +fn check_expm1() { + let x = 2f32; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; + + let x = 2f64; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; +} + +fn main() {} diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr new file mode 100644 index 00000000000..a0663e48835 --- /dev/null +++ b/tests/ui/floating_point_arithmetic.stderr @@ -0,0 +1,174 @@ +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:12:13 + | +LL | let _ = x.log(2f32); + | ^^^^^^^^^^^ help: consider using: `x.log2()` + | + = note: `-D clippy::inaccurate-floating-point-computation` implied by `-D warnings` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:13:13 + | +LL | let _ = x.log(10f32); + | ^^^^^^^^^^^^ help: consider using: `x.log10()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:14:13 + | +LL | let _ = x.log(std::f32::consts::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:15:13 + | +LL | let _ = x.log(TWO); + | ^^^^^^^^^^ help: consider using: `x.log2()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:16:13 + | +LL | let _ = x.log(E); + | ^^^^^^^^ help: consider using: `x.ln()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:19:13 + | +LL | let _ = x.log(2f64); + | ^^^^^^^^^^^ help: consider using: `x.log2()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:20:13 + | +LL | let _ = x.log(10f64); + | ^^^^^^^^^^^^ help: consider using: `x.log10()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:21:13 + | +LL | let _ = x.log(std::f64::consts::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:26:13 + | +LL | let _ = (1.0 + x).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:27:13 + | +LL | let _ = (1.0 + x * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:28:13 + | +LL | let _ = (1.0 + x.powi(2)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:29:13 + | +LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:30:13 + | +LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:37:13 + | +LL | let _ = (1.0 + x).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:38:13 + | +LL | let _ = (1.0 + x * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:39:13 + | +LL | let _ = (1.0 + x.powi(2)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:48:13 + | +LL | let _ = 2f32.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + | + = note: `-D clippy::slow-floating-point-computation` implied by `-D warnings` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:49:13 + | +LL | let _ = std::f32::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:50:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:51:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:54:13 + | +LL | let _ = 2f64.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:55:13 + | +LL | let _ = std::f64::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:56:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:57:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:62:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:63:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:69:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:70:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: aborting due to 28 previous errors + -- cgit 1.4.1-3-g733a5 From 1f4f357bf540f63ece5d11d5ab6cae9a8fb63a21 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy <veerareddy@email.arizona.edu> Date: Sat, 14 Dec 2019 20:10:23 -0800 Subject: Consolidate the accuracy and efficiency lints Merge the accuracy and efficiency lints into a single lint that checks for improvements to accuracy, efficiency and readability of floating-point expressions. --- CHANGELOG.md | 1 - clippy_lints/src/floating_point_arithmetic.rs | 89 +++++++++++---------------- clippy_lints/src/lib.rs | 3 +- src/lintlist/mod.rs | 7 --- tests/ui/floating_point_arithmetic.rs | 5 +- tests/ui/floating_point_arithmetic.stderr | 76 +++++++++++------------ 6 files changed, 76 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e46bf6d20..4e99342e4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,7 +1169,6 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return -[`inaccurate_floating_point_computation`]: https://rust-lang.github.io/rust-clippy/master/index.html#inaccurate_floating_point_computation [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 935d8b58146..da55f1e5f4e 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -13,11 +13,12 @@ use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; declare_clippy_lint! { - /// **What it does:** Looks for numerically unstable floating point - /// computations and suggests better alternatives. + /// **What it does:** Looks for floating-point expressions that + /// can be expressed using built-in methods to improve accuracy, + /// performance and/or succinctness. /// - /// **Why is this bad?** Numerically unstable floating point computations - /// cause rounding errors to magnify and distorts the results strongly. + /// **Why is this bad?** Negatively affects accuracy, performance + /// and/or readability. /// /// **Known problems:** None /// @@ -26,59 +27,43 @@ declare_clippy_lint! { /// ```rust /// use std::f32::consts::E; /// - /// let a = 1f32.log(2.0); - /// let b = 1f32.log(10.0); - /// let c = 1f32.log(E); + /// let a = 3f32; + /// let _ = (2f32).powf(a); + /// let _ = E.powf(a); + /// let _ = a.powf(1.0 / 2.0); + /// let _ = a.powf(1.0 / 3.0); + /// let _ = a.log(2.0); + /// let _ = a.log(10.0); + /// let _ = a.log(E); + /// let _ = (1.0 + a).ln(); + /// let _ = a.exp() - 1.0; /// ``` /// /// is better expressed as /// /// ```rust - /// let a = 1f32.log2(); - /// let b = 1f32.log10(); - /// let c = 1f32.ln(); - /// ``` - pub INACCURATE_FLOATING_POINT_COMPUTATION, - nursery, - "checks for numerically unstable floating point computations" -} - -declare_clippy_lint! { - /// **What it does:** Looks for inefficient floating point computations - /// and suggests faster alternatives. - /// - /// **Why is this bad?** Lower performance. - /// - /// **Known problems:** None - /// - /// **Example:** - /// - /// ```rust /// use std::f32::consts::E; /// - /// let a = (2f32).powf(3.0); - /// let c = E.powf(3.0); - /// ``` - /// - /// is better expressed as - /// - /// ```rust - /// let a = (3f32).exp2(); - /// let b = (3f32).exp(); + /// let a = 3f32; + /// let _ = a.exp2(); + /// let _ = a.exp(); + /// let _ = a.sqrt(); + /// let _ = a.cbrt(); + /// let _ = a.log2(); + /// let _ = a.log10(); + /// let _ = a.ln(); + /// let _ = a.ln_1p(); + /// let _ = a.exp_m1(); /// ``` - pub SLOW_FLOATING_POINT_COMPUTATION, + pub FLOATING_POINT_IMPROVEMENTS, nursery, - "checks for inefficient floating point computations" + "looks for improvements to floating-point expressions" } -declare_lint_pass!(FloatingPointArithmetic => [ - INACCURATE_FLOATING_POINT_COMPUTATION, - SLOW_FLOATING_POINT_COMPUTATION -]); +declare_lint_pass!(FloatingPointArithmetic => [FLOATING_POINT_IMPROVEMENTS]); fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { - let recv = &args[0]; - let arg = sugg::Sugg::hir(cx, recv, "..").maybe_par(); + let arg = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { let method; @@ -95,7 +80,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", @@ -118,7 +103,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -144,9 +129,9 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - SLOW_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, - "exponent for bases 2 and e can be computed more efficiently", + "exponent for bases 2 and e can be computed more accurately", "consider using", format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method), Applicability::MachineApplicable, @@ -159,10 +144,10 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { let method; if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { - help = "square-root of a number can be computer more efficiently"; + help = "square-root of a number can be computed more efficiently and accurately"; method = "sqrt"; } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { - help = "cube-root of a number can be computer more efficiently"; + help = "cube-root of a number can be computed more accurately"; method = "cbrt"; } else { return; @@ -170,7 +155,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - SLOW_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, help, "consider using", @@ -194,7 +179,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { then { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9a904141fcf..9154a0dc3ff 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1649,8 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&floating_point_arithmetic::INACCURATE_FLOATING_POINT_COMPUTATION), - LintId::of(&floating_point_arithmetic::SLOW_FLOATING_POINT_COMPUTATION), + LintId::of(&floating_point_arithmetic::FLOATING_POINT_IMPROVEMENTS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index fee59507454..29b5a7ba08a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -749,13 +749,6 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, - Lint { - name: "inaccurate_floating_point_computation", - group: "nursery", - desc: "checks for numerically unstable floating point computations", - deprecation: None, - module: "floating_point_arithmetic", - }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs index 5291e5cf022..1feeb827621 100644 --- a/tests/ui/floating_point_arithmetic.rs +++ b/tests/ui/floating_point_arithmetic.rs @@ -1,8 +1,5 @@ #![allow(dead_code)] -#![warn( - clippy::inaccurate_floating_point_computation, - clippy::slow_floating_point_computation -)] +#![warn(clippy::floating_point_improvements)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr index a0663e48835..a7db1669745 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_arithmetic.stderr @@ -1,171 +1,169 @@ error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:12:13 + --> $DIR/floating_point_arithmetic.rs:9:13 | LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` | - = note: `-D clippy::inaccurate-floating-point-computation` implied by `-D warnings` + = note: `-D clippy::floating-point-improvements` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:13:13 + --> $DIR/floating_point_arithmetic.rs:10:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:14:13 + --> $DIR/floating_point_arithmetic.rs:11:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:15:13 + --> $DIR/floating_point_arithmetic.rs:12:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:16:13 + --> $DIR/floating_point_arithmetic.rs:13:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:19:13 + --> $DIR/floating_point_arithmetic.rs:16:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:20:13 + --> $DIR/floating_point_arithmetic.rs:17:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:21:13 + --> $DIR/floating_point_arithmetic.rs:18:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:26:13 + --> $DIR/floating_point_arithmetic.rs:23:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:27:13 + --> $DIR/floating_point_arithmetic.rs:24:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:28:13 + --> $DIR/floating_point_arithmetic.rs:25:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:29:13 + --> $DIR/floating_point_arithmetic.rs:26:13 | LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:30:13 + --> $DIR/floating_point_arithmetic.rs:27:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:37:13 + --> $DIR/floating_point_arithmetic.rs:34:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:38:13 + --> $DIR/floating_point_arithmetic.rs:35:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:39:13 + --> $DIR/floating_point_arithmetic.rs:36:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:48:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:45:13 | LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` - | - = note: `-D clippy::slow-floating-point-computation` implied by `-D warnings` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:49:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:46:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` -error: square-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:50:13 +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_arithmetic.rs:47:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` -error: cube-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:51:13 +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:48:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:54:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:51:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:55:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:52:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` -error: square-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:56:13 +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_arithmetic.rs:53:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` -error: cube-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:57:13 +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:54:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:62:13 + --> $DIR/floating_point_arithmetic.rs:59:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:63:13 + --> $DIR/floating_point_arithmetic.rs:60:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:69:13 + --> $DIR/floating_point_arithmetic.rs:66:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:70:13 + --> $DIR/floating_point_arithmetic.rs:67:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` -- cgit 1.4.1-3-g733a5 From 6dacb1aa678046940d3fae7a68bd0112accecfd4 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Mon, 17 Feb 2020 12:56:55 -0800 Subject: Change lint name to `suboptimal_flops` --- CHANGELOG.md | 1 + clippy_lints/src/floating_point_arithmetic.rs | 39 +++++++++++++-------------- clippy_lints/src/lib.rs | 3 ++- src/lintlist/mod.rs | 7 +++++ tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_exp.stderr | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_log.stderr | 2 +- tests/ui/floating_point_powf.rs | 6 +---- tests/ui/floating_point_powf.stderr | 22 +++++++-------- 10 files changed, 45 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e99342e4a4..87ece835f7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1349,6 +1349,7 @@ Released 2018-09-13 [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 17babb46daa..61938405d92 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -4,10 +4,10 @@ use crate::consts::{ }; use crate::utils::*; use if_chain::if_chain; -use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; use rustc::ty; use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; @@ -16,11 +16,10 @@ use syntax::ast; declare_clippy_lint! { /// **What it does:** Looks for floating-point expressions that - /// can be expressed using built-in methods to improve accuracy, - /// performance and/or succinctness. + /// can be expressed using built-in methods to improve both + /// accuracy and performance. /// - /// **Why is this bad?** Negatively affects accuracy, performance - /// and/or readability. + /// **Why is this bad?** Negatively impacts accuracy and performance. /// /// **Known problems:** None /// @@ -59,16 +58,16 @@ declare_clippy_lint! { /// let _ = a.exp_m1(); /// let _ = a.powi(2); /// ``` - pub FLOATING_POINT_IMPROVEMENTS, + pub SUBOPTIMAL_FLOPS, nursery, - "looks for improvements to floating-point expressions" + "usage of sub-optimal floating point operations" } -declare_lint_pass!(FloatingPointArithmetic => [FLOATING_POINT_IMPROVEMENTS]); +declare_lint_pass!(FloatingPointArithmetic => [SUBOPTIMAL_FLOPS]); // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e -fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr) -> Option<&'static str> { +fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr<'_>) -> Option<&'static str> { if let Some((value, _)) = constant(cx, cx.tables, base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); @@ -124,7 +123,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) if let Some(method) = get_specialized_log_method(cx, &args[1]) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", @@ -136,7 +135,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and // suggest usage of `(x + (y - 1)).ln_1p()` instead -fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { +fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { if_chain! { if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; if op.node == BinOpKind::Add; @@ -149,7 +148,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -185,7 +184,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i64> { } } -fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { +fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { let method; @@ -200,7 +199,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", @@ -223,7 +222,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { } else if let Some(exponent) = get_integer_from_float_constant(&value) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "exponentiation with integer powers can be computed more efficiently", "consider using", @@ -238,7 +237,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, help, "consider using", @@ -250,7 +249,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) { // TODO: Lint expressions of the form `x.exp() - y` where y > 1 // and suggest usage of `x.exp_m1() - (y - 1)` instead -fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { +fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; if op.node == BinOpKind::Sub; @@ -263,7 +262,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { then { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", @@ -278,7 +277,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { let recv_ty = cx.tables.expr_ty(&args[0]); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9154a0dc3ff..59ad7e7a651 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -538,6 +538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &fallible_impl_from::FALLIBLE_IMPL_FROM, &float_literal::EXCESSIVE_PRECISION, &float_literal::LOSSY_FLOAT_LITERAL, + &floating_point_arithmetic::SUBOPTIMAL_FLOPS, &format::USELESS_FORMAT, &formatting::POSSIBLE_MISSING_COMMA, &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, @@ -1649,7 +1650,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&floating_point_arithmetic::FLOATING_POINT_IMPROVEMENTS), + LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 29b5a7ba08a..de086f863e0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1960,6 +1960,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "excessive_bools", }, + Lint { + name: "suboptimal_flops", + group: "nursery", + desc: "usage of sub-optimal floating point operations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "suspicious_arithmetic_impl", group: "correctness", diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index 303c6124775..c7fe0d03568 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,4 +1,4 @@ -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 78321899945..83adca8a46c 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -4,7 +4,7 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately --> $DIR/floating_point_exp.rs:6:13 diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 18b7686280e..c26f71f3067 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index c169745ddf9..db2fc999b6c 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -4,7 +4,7 @@ error: logarithm for bases 2, 10 and e can be computed more accurately LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately --> $DIR/floating_point_log.rs:10:13 diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 97a1d93a801..2076821b5b0 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,4 +1,4 @@ -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] fn main() { let x = 3f32; @@ -14,8 +14,6 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); - let _ = x.powf(16_777_217.0); - let _ = x.powf(-16_777_217.0); let x = 3f64; let _ = 2f64.powf(x); @@ -30,6 +28,4 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); - let _ = x.powf(9_007_199_254_740_993.0); - let _ = x.powf(-9_007_199_254_740_993.0); } diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 4e16e7af046..35e0c5e56fd 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -4,7 +4,7 @@ error: exponent for bases 2 and e can be computed more accurately LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: exponent for bases 2 and e can be computed more accurately --> $DIR/floating_point_powf.rs:6:13 @@ -61,61 +61,61 @@ LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:21:13 + --> $DIR/floating_point_powf.rs:19:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:22:13 + --> $DIR/floating_point_powf.rs:20:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:23:13 + --> $DIR/floating_point_powf.rs:21:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:24:13 + --> $DIR/floating_point_powf.rs:22:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:25:13 + --> $DIR/floating_point_powf.rs:23:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:26:13 + --> $DIR/floating_point_powf.rs:24:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:27:13 + --> $DIR/floating_point_powf.rs:25:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:26:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:27:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` -- cgit 1.4.1-3-g733a5 From 4065ca9c8c4586e99688de53c7cf654c7693fc63 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Sun, 23 Feb 2020 00:04:11 -0800 Subject: Move `manual_mul_add` into `suboptimal_flops` lint --- CHANGELOG.md | 1 - clippy_lints/src/floating_point_arithmetic.rs | 59 ++++++++++++-- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/mul_add.rs | 111 -------------------------- src/lintlist/mod.rs | 7 -- tests/ui/floating_point_fma.fixed | 21 +++++ tests/ui/floating_point_fma.rs | 21 +++++ tests/ui/floating_point_fma.stderr | 58 ++++++++++++++ tests/ui/floating_point_log.fixed | 14 ++-- tests/ui/floating_point_log.rs | 14 ++-- tests/ui/floating_point_log.stderr | 20 ++--- tests/ui/mul_add.rs | 16 ---- tests/ui/mul_add.stderr | 34 -------- tests/ui/mul_add_fixable.fixed | 24 ------ tests/ui/mul_add_fixable.rs | 24 ------ tests/ui/mul_add_fixable.stderr | 40 ---------- 16 files changed, 179 insertions(+), 290 deletions(-) delete mode 100644 clippy_lints/src/mul_add.rs create mode 100644 tests/ui/floating_point_fma.fixed create mode 100644 tests/ui/floating_point_fma.rs create mode 100644 tests/ui/floating_point_fma.stderr delete mode 100644 tests/ui/mul_add.rs delete mode 100644 tests/ui/mul_add.stderr delete mode 100644 tests/ui/mul_add_fixable.fixed delete mode 100644 tests/ui/mul_add_fixable.rs delete mode 100644 tests/ui/mul_add_fixable.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ece835f7f..ce696aa8550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1210,7 +1210,6 @@ Released 2018-09-13 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy -[`manual_mul_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_mul_add [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index d342afbc12a..fbc375c655e 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,11 +2,11 @@ use crate::consts::{ constant, Constant, Constant::{F32, F64}, }; -use crate::utils::*; +use crate::utils::{span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; @@ -39,6 +39,7 @@ declare_clippy_lint! { /// let _ = (1.0 + a).ln(); /// let _ = a.exp() - 1.0; /// let _ = a.powf(2.0); + /// let _ = a * 2.0 + 4.0; /// ``` /// /// is better expressed as @@ -57,6 +58,7 @@ declare_clippy_lint! { /// let _ = a.ln_1p(); /// let _ = a.exp_m1(); /// let _ = a.powi(2); + /// let _ = a.mul_add(2.0, 4.0); /// ``` pub SUBOPTIMAL_FLOPS, nursery, @@ -211,12 +213,12 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")) + format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")) + format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -225,7 +227,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "{}.powi({})", Sugg::hir(cx, &args[0], ".."), format_numeric_literal(&exponent.to_string(), None, false) - ) + ), ) } else { return; @@ -272,6 +274,52 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } } +fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = &expr.kind; + if let BinOpKind::Mul = op.node; + if cx.tables.expr_ty(lhs).is_floating_point(); + if cx.tables.expr_ty(rhs).is_floating_point(); + then { + return Some((lhs, rhs)); + } + } + + None +} + +// TODO: Fix rust-lang/rust-clippy#4735 +fn check_fma(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind; + if let BinOpKind::Add = op.node; + then { + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { + (inner_lhs, inner_rhs, rhs) + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { + (inner_lhs, inner_rhs, lhs) + } else { + return; + }; + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "multiply and add expressions can be calculated more efficiently and accurately", + "consider using", + format!( + "{}.mul_add({}, {})", + prepare_receiver_sugg(cx, recv), + Sugg::hir(cx, arg1, ".."), + Sugg::hir(cx, arg2, ".."), + ), + Applicability::MachineApplicable, + ); + } + } +} + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { @@ -287,6 +335,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { } } else { check_expm1(cx, expr); + check_fma(cx, expr); } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 59ad7e7a651..503eb9ec10d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -208,6 +208,7 @@ pub mod exit; pub mod explicit_write; pub mod fallible_impl_from; pub mod float_literal; +pub mod floating_point_arithmetic; pub mod format; pub mod formatting; pub mod functions; @@ -248,7 +249,6 @@ pub mod missing_const_for_fn; pub mod missing_doc; pub mod missing_inline; pub mod modulo_arithmetic; -pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_key; pub mod mut_mut; @@ -691,7 +691,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, &modulo_arithmetic::MODULO_ARITHMETIC, - &mul_add::MANUAL_MUL_ADD, &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, &mut_key::MUTABLE_KEY_TYPE, &mut_mut::MUT_MUT, @@ -967,7 +966,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box inherent_to_string::InherentToString); store.register_late_pass(|| box trait_bounds::TraitBounds); store.register_late_pass(|| box comparison_chain::ComparisonChain); - store.register_late_pass(|| box mul_add::MulAddCheck); store.register_late_pass(|| box mut_key::MutableKeyType); store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); store.register_early_pass(|| box reference::DerefAddrOf); @@ -1652,7 +1650,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), - LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), diff --git a/clippy_lints/src/mul_add.rs b/clippy_lints/src/mul_add.rs deleted file mode 100644 index 57e56d8f959..00000000000 --- a/clippy_lints/src/mul_add.rs +++ /dev/null @@ -1,111 +0,0 @@ -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -use crate::utils::{snippet, span_lint_and_sugg}; - -declare_clippy_lint! { - /// **What it does:** Checks for expressions of the form `a * b + c` - /// or `c + a * b` where `a`, `b`, `c` are floats and suggests using - /// `a.mul_add(b, c)` instead. - /// - /// **Why is this bad?** Calculating `a * b + c` may lead to slight - /// numerical inaccuracies as `a * b` is rounded before being added to - /// `c`. Depending on the target architecture, `mul_add()` may be more - /// performant. - /// - /// **Known problems:** This lint can emit semantic incorrect suggestions. - /// For example, for `a * b * c + d` the suggestion `a * b.mul_add(c, d)` - /// is emitted, which is equivalent to `a * (b * c + d)`. (#4735) - /// - /// **Example:** - /// - /// ```rust - /// # let a = 0_f32; - /// # let b = 0_f32; - /// # let c = 0_f32; - /// let foo = (a * b) + c; - /// ``` - /// - /// can be written as - /// - /// ```rust - /// # let a = 0_f32; - /// # let b = 0_f32; - /// # let c = 0_f32; - /// let foo = a.mul_add(b, c); - /// ``` - pub MANUAL_MUL_ADD, - nursery, - "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`" -} - -declare_lint_pass!(MulAddCheck => [MANUAL_MUL_ADD]); - -fn is_float<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool { - cx.tables.expr_ty(expr).is_floating_point() -} - -// Checks whether expression is multiplication of two floats -fn is_float_mult_expr<'a, 'tcx, 'b>( - cx: &LateContext<'a, 'tcx>, - expr: &'b Expr<'b>, -) -> Option<(&'b Expr<'b>, &'b Expr<'b>)> { - if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { - if let BinOpKind::Mul = op.node { - if is_float(cx, &lhs) && is_float(cx, &rhs) { - return Some((&lhs, &rhs)); - } - } - } - - None -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MulAddCheck { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { - if let BinOpKind::Add = op.node { - //Converts mult_lhs * mult_rhs + rhs to mult_lhs.mult_add(mult_rhs, rhs) - if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, lhs) { - if is_float(cx, rhs) { - span_lint_and_sugg( - cx, - MANUAL_MUL_ADD, - expr.span, - "consider using `mul_add()` for better numerical precision", - "try", - format!( - "{}.mul_add({}, {})", - snippet(cx, mult_lhs.span, "_"), - snippet(cx, mult_rhs.span, "_"), - snippet(cx, rhs.span, "_"), - ), - Applicability::MaybeIncorrect, - ); - } - } - //Converts lhs + mult_lhs * mult_rhs to mult_lhs.mult_add(mult_rhs, lhs) - if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, rhs) { - if is_float(cx, lhs) { - span_lint_and_sugg( - cx, - MANUAL_MUL_ADD, - expr.span, - "consider using `mul_add()` for better numerical precision", - "try", - format!( - "{}.mul_add({}, {})", - snippet(cx, mult_lhs.span, "_"), - snippet(cx, mult_rhs.span, "_"), - snippet(cx, lhs.span, "_"), - ), - Applicability::MaybeIncorrect, - ); - } - } - } - } - } -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index de086f863e0..5b4aad347af 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1022,13 +1022,6 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "loops", }, - Lint { - name: "manual_mul_add", - group: "nursery", - desc: "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`", - deprecation: None, - module: "mul_add", - }, Lint { name: "manual_saturating_arithmetic", group: "style", diff --git a/tests/ui/floating_point_fma.fixed b/tests/ui/floating_point_fma.fixed new file mode 100644 index 00000000000..e343c37740d --- /dev/null +++ b/tests/ui/floating_point_fma.fixed @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let d: f64 = 0.0001; + + let _ = a.mul_add(b, c); + let _ = a.mul_add(b, c); + let _ = 2.0f64.mul_add(4.0, a); + let _ = 2.0f64.mul_add(4., a); + + let _ = a.mul_add(b, c); + let _ = a.mul_add(b, c); + let _ = (a * b).mul_add(c, d); + + let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; + let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); +} diff --git a/tests/ui/floating_point_fma.rs b/tests/ui/floating_point_fma.rs new file mode 100644 index 00000000000..810f929c856 --- /dev/null +++ b/tests/ui/floating_point_fma.rs @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let d: f64 = 0.0001; + + let _ = a * b + c; + let _ = c + a * b; + let _ = a + 2.0 * 4.0; + let _ = a + 2. * 4.; + + let _ = (a * b) + c; + let _ = c + (a * b); + let _ = a * b * c + d; + + let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; +} diff --git a/tests/ui/floating_point_fma.stderr b/tests/ui/floating_point_fma.stderr new file mode 100644 index 00000000000..5c653360ebc --- /dev/null +++ b/tests/ui/floating_point_fma.stderr @@ -0,0 +1,58 @@ +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:10:13 + | +LL | let _ = a * b + c; + | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:11:13 + | +LL | let _ = c + a * b; + | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:12:13 + | +LL | let _ = a + 2.0 * 4.0; + | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:13:13 + | +LL | let _ = a + 2. * 4.; + | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:15:13 + | +LL | let _ = (a * b) + c; + | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:16:13 + | +LL | let _ = c + (a * b); + | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:17:13 + | +LL | let _ = a * b * c + d; + | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:19:13 + | +LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:20:13 + | +LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index ead45fc4a9f..afe72a8dd11 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -24,34 +24,34 @@ fn check_ln1p() { let _ = 2.0f32.ln_1p(); let _ = 2.0f32.ln_1p(); let _ = x.ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); let _ = x.powi(2).ln_1p(); - let _ = (x.powi(2) * 2.0).ln_1p(); + let _ = (x.powi(2) / 2.0).ln_1p(); let _ = ((std::f32::consts::E - 1.0)).ln_1p(); let _ = x.ln_1p(); let _ = x.powi(2).ln_1p(); let _ = (x + 2.0).ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); let x = 1f64; let _ = 2.0f64.ln_1p(); let _ = 2.0f64.ln_1p(); let _ = x.ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); let _ = x.powi(2).ln_1p(); let _ = x.ln_1p(); let _ = x.powi(2).ln_1p(); let _ = (x + 2.0).ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); } diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index f888e1375dc..785b5a3bc48 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -24,34 +24,34 @@ fn check_ln1p() { let _ = (1f32 + 2.).ln(); let _ = (1f32 + 2.0).ln(); let _ = (1.0 + x).ln(); - let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x / 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); - let _ = (1.0 + x.powi(2) * 2.0).ln(); + let _ = (1.0 + x.powi(2) / 2.0).ln(); let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); let _ = (x + 1.0).ln(); let _ = (x.powi(2) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); - let _ = (x * 2.0 + 1.0).ln(); + let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); let x = 1f64; let _ = (1f64 + 2.).ln(); let _ = (1f64 + 2.0).ln(); let _ = (1.0 + x).ln(); - let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x / 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); let _ = (x + 1.0).ln(); let _ = (x.powi(2) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); - let _ = (x * 2.0 + 1.0).ln(); + let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); } diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index c8c32b61ca3..cb0bb6d652a 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -69,8 +69,8 @@ LL | let _ = (1.0 + x).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:27:13 | -LL | let _ = (1.0 + x * 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (1.0 + x / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:28:13 @@ -81,8 +81,8 @@ LL | let _ = (1.0 + x.powi(2)).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:29:13 | -LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` +LL | let _ = (1.0 + x.powi(2) / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:30:13 @@ -111,8 +111,8 @@ LL | let _ = (x + 2.0 + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:34:13 | -LL | let _ = (x * 2.0 + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (x / 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:42:13 @@ -135,8 +135,8 @@ LL | let _ = (1.0 + x).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:45:13 | -LL | let _ = (1.0 + x * 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (1.0 + x / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:46:13 @@ -165,8 +165,8 @@ LL | let _ = (x + 2.0 + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:50:13 | -LL | let _ = (x * 2.0 + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (x / 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: aborting due to 28 previous errors diff --git a/tests/ui/mul_add.rs b/tests/ui/mul_add.rs deleted file mode 100644 index 1322e002c64..00000000000 --- a/tests/ui/mul_add.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Examples of not auto-fixable expressions - let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - let test2 = 1234.567 * 45.67834 + 0.0004; -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add.stderr b/tests/ui/mul_add.stderr deleted file mode 100644 index 3b21646f7c3..00000000000 --- a/tests/ui/mul_add.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:17 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(a * b + c).mul_add((c + a * b), (c + (a * b) + c))` - | - = note: `-D clippy::manual-mul-add` implied by `-D warnings` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:17 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:31 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:46 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:11:17 - | -LL | let test2 = 1234.567 * 45.67834 + 0.0004; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567.mul_add(45.67834, 0.0004)` - -error: aborting due to 5 previous errors - diff --git a/tests/ui/mul_add_fixable.fixed b/tests/ui/mul_add_fixable.fixed deleted file mode 100644 index 4af7c7e3e1a..00000000000 --- a/tests/ui/mul_add_fixable.fixed +++ /dev/null @@ -1,24 +0,0 @@ -// run-rustfix - -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Auto-fixable examples - let test1 = a.mul_add(b, c); - let test2 = a.mul_add(b, c); - - let test3 = a.mul_add(b, c); - let test4 = a.mul_add(b, c); - - let test5 = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; - let test6 = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add_fixable.rs b/tests/ui/mul_add_fixable.rs deleted file mode 100644 index 8b42f6f184a..00000000000 --- a/tests/ui/mul_add_fixable.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-rustfix - -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Auto-fixable examples - let test1 = a * b + c; - let test2 = c + a * b; - - let test3 = (a * b) + c; - let test4 = c + (a * b); - - let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; - let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add_fixable.stderr b/tests/ui/mul_add_fixable.stderr deleted file mode 100644 index 235443f4b02..00000000000 --- a/tests/ui/mul_add_fixable.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:12:17 - | -LL | let test1 = a * b + c; - | ^^^^^^^^^ help: try: `a.mul_add(b, c)` - | - = note: `-D clippy::manual-mul-add` implied by `-D warnings` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:13:17 - | -LL | let test2 = c + a * b; - | ^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:15:17 - | -LL | let test3 = (a * b) + c; - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:16:17 - | -LL | let test4 = c + (a * b); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:18:17 - | -LL | let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:19:17 - | -LL | let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` - -error: aborting due to 6 previous errors - -- cgit 1.4.1-3-g733a5 From ff0d44e45a27e688b5ee5447dc9175d5e72b37c9 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> Date: Sun, 23 Feb 2020 21:06:55 -0800 Subject: Add `imprecise_flops` lint Add lint to detect floating point operations that can be computed more accurately at the cost of performance. `cbrt`, `ln_1p` and `exp_m1` library functions call their equivalent cmath implementations which is slower but more accurate so moving checks for these under this new lint. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 55 +++++++++++++++++++++------ clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 ++++- tests/ui/floating_point_exp.fixed | 2 +- tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_exp.stderr | 2 +- tests/ui/floating_point_log.fixed | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_log.stderr | 2 + tests/ui/floating_point_powf.fixed | 2 +- tests/ui/floating_point_powf.rs | 2 +- tests/ui/floating_point_powf.stderr | 2 + 14 files changed, 67 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index ce696aa8550..99e84ea5193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,6 +1169,7 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/README.md b/README.md index 3103f960839..1300c5ad47b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 357 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 358 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 542ea5132de..eed4f58cf90 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -16,6 +16,39 @@ use std::f64::consts as f64_consts; use sugg::{format_numeric_literal, Sugg}; use syntax::ast; +declare_clippy_lint! { + /// **What it does:** Looks for floating-point expressions that + /// can be expressed using built-in methods to improve accuracy + /// at the cost of performance. + /// + /// **Why is this bad?** Negatively impacts accuracy. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// + /// let a = 3f32; + /// let _ = a.powf(1.0 / 3.0); + /// let _ = (1.0 + a).ln(); + /// let _ = a.exp() - 1.0; + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// + /// let a = 3f32; + /// let _ = a.cbrt(); + /// let _ = a.ln_1p(); + /// let _ = a.exp_m1(); + /// ``` + pub IMPRECISE_FLOPS, + nursery, + "usage of imprecise floating point operations" +} + declare_clippy_lint! { /// **What it does:** Looks for floating-point expressions that /// can be expressed using built-in methods to improve both @@ -34,12 +67,9 @@ declare_clippy_lint! { /// let _ = (2f32).powf(a); /// let _ = E.powf(a); /// let _ = a.powf(1.0 / 2.0); - /// let _ = a.powf(1.0 / 3.0); /// let _ = a.log(2.0); /// let _ = a.log(10.0); /// let _ = a.log(E); - /// let _ = (1.0 + a).ln(); - /// let _ = a.exp() - 1.0; /// let _ = a.powf(2.0); /// let _ = a * 2.0 + 4.0; /// ``` @@ -53,12 +83,9 @@ declare_clippy_lint! { /// let _ = a.exp2(); /// let _ = a.exp(); /// let _ = a.sqrt(); - /// let _ = a.cbrt(); /// let _ = a.log2(); /// let _ = a.log10(); /// let _ = a.ln(); - /// let _ = a.ln_1p(); - /// let _ = a.exp_m1(); /// let _ = a.powi(2); /// let _ = a.mul_add(2.0, 4.0); /// ``` @@ -67,7 +94,10 @@ declare_clippy_lint! { "usage of sub-optimal floating point operations" } -declare_lint_pass!(FloatingPointArithmetic => [SUBOPTIMAL_FLOPS]); +declare_lint_pass!(FloatingPointArithmetic => [ + IMPRECISE_FLOPS, + SUBOPTIMAL_FLOPS +]); // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e @@ -156,7 +186,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + IMPRECISE_FLOPS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -215,18 +245,21 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check argument if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { - let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( + SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( + IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( + SUBOPTIMAL_FLOPS, "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", @@ -240,7 +273,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + lint, expr.span, help, "consider using", @@ -264,7 +297,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { then { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + IMPRECISE_FLOPS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 503eb9ec10d..c732657b2e5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -538,6 +538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &fallible_impl_from::FALLIBLE_IMPL_FROM, &float_literal::EXCESSIVE_PRECISION, &float_literal::LOSSY_FLOAT_LITERAL, + &floating_point_arithmetic::IMPRECISE_FLOPS, &floating_point_arithmetic::SUBOPTIMAL_FLOPS, &format::USELESS_FORMAT, &formatting::POSSIBLE_MISSING_COMMA, @@ -1648,6 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5b4aad347af..15e6a4b6036 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 357] = [ +pub const ALL_LINTS: [Lint; 358] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -749,6 +749,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, + Lint { + name: "imprecise_flops", + group: "nursery", + desc: "usage of imprecise floating point operations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index 1f534e3705d..ae7805fdf01 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::imprecise_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index bed8d312140..27e0b9bcbc9 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::imprecise_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 7882b2c24e3..5cd999ad47c 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -4,7 +4,7 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` | - = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately --> $DIR/floating_point_exp.rs:7:13 diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index afe72a8dd11..42c5e5d2bae 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code, clippy::double_parens)] -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 785b5a3bc48..8be0d9ad56f 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code, clippy::double_parens)] -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index cb0bb6d652a..943fbdb0b83 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -53,6 +53,8 @@ error: ln(1 + x) can be computed more accurately | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:25:13 diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index c5d900de329..78a9d44829b 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index cc75e230f7d..dbc1cac5cb4 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 8f0544d4b58..ad5163f0079 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -47,6 +47,8 @@ error: cube-root of a number can be computed more accurately | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:14:13 -- cgit 1.4.1-3-g733a5 From 2aa14c9beb48ad780412df747b0a64b90eb5f13e Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Sun, 1 Mar 2020 17:36:14 +0100 Subject: Add restrictive pat use in full binded struct --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/matches.rs | 59 +++++++++++++++++++++++-- src/lintlist/mod.rs | 9 +++- tests/ui/rest_pat_in_fully_bound_structs.rs | 30 +++++++++++++ tests/ui/rest_pat_in_fully_bound_structs.stderr | 27 +++++++++++ 7 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 tests/ui/rest_pat_in_fully_bound_structs.rs create mode 100644 tests/ui/rest_pat_in_fully_bound_structs.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 99e84ea5193..4d8e2494389 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1321,6 +1321,7 @@ Released 2018-09-13 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else diff --git a/README.md b/README.md index 1300c5ad47b..6915b1bde02 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 358 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 359 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4157d33079c..327cc56cafa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -610,6 +610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &matches::MATCH_REF_PATS, &matches::MATCH_SINGLE_BINDING, &matches::MATCH_WILD_ERR_ARM, + &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, &matches::SINGLE_MATCH, &matches::SINGLE_MATCH_ELSE, &matches::WILDCARD_ENUM_MATCH_ARM, @@ -1026,6 +1027,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&integer_division::INTEGER_DIVISION), LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), LintId::of(&methods::CLONE_ON_REF_PTR), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 6f1efe0fd85..9668c5d8349 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -14,8 +14,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; use rustc_hir::{ - print, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, PatKind, QPath, - RangeEnd, + print, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Pat, PatKind, + QPath, RangeEnd, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -311,6 +311,36 @@ declare_clippy_lint! { "a match with a single binding instead of using `let` statement" } +declare_clippy_lint! { + /// **What it does:** Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. + /// + /// **Why is this bad?** Correctness and readability. It's like having a wildcard pattern after + /// matching all enum variants explicitly. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # struct A { a: i32 } + /// let a = A { a: 5 }; + /// + /// // Bad + /// match a { + /// A { a: 5, .. } => {}, + /// _ => {}, + /// } + /// + /// // Good + /// match a { + /// A { a: 5 } => {}, + /// _ => {}, + /// } + /// ``` + pub REST_PAT_IN_FULLY_BOUND_STRUCTS, + restriction, + "a match on a struct that binds all fields but still uses the wildcard pattern" +} + #[derive(Default)] pub struct Matches { infallible_destructuring_match_linted: bool, @@ -327,7 +357,8 @@ impl_lint_pass!(Matches => [ WILDCARD_ENUM_MATCH_ARM, WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, - INFALLIBLE_DESTRUCTURING_MATCH + INFALLIBLE_DESTRUCTURING_MATCH, + REST_PAT_IN_FULLY_BOUND_STRUCTS ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { @@ -388,6 +419,28 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches { } } } + + fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat<'_>) { + if_chain! { + if let PatKind::Struct(ref qpath, fields, true) = pat.kind; + if let QPath::Resolved(_, ref path) = qpath; + if let Some(def_id) = path.res.opt_def_id(); + let ty = cx.tcx.type_of(def_id); + if let ty::Adt(def, _) = ty.kind; + if def.is_struct() || def.is_union(); + if fields.len() == def.non_enum_variant().fields.len(); + + then { + span_lint_and_help( + cx, + REST_PAT_IN_FULLY_BOUND_STRUCTS, + pat.span, + "unnecessary use of `..` pattern in struct binding. All fields were already bound", + "consider removing `..` from this binding", + ); + } + } + } } #[rustfmt::skip] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 15e6a4b6036..2b93e4279f0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 358] = [ +pub const ALL_LINTS: [Lint; 359] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1785,6 +1785,13 @@ pub const ALL_LINTS: [Lint; 358] = [ deprecation: None, module: "replace_consts", }, + Lint { + name: "rest_pat_in_fully_bound_structs", + group: "restriction", + desc: "a match on a struct that binds all fields but still uses the wildcard pattern", + deprecation: None, + module: "matches", + }, Lint { name: "result_expect_used", group: "restriction", diff --git a/tests/ui/rest_pat_in_fully_bound_structs.rs b/tests/ui/rest_pat_in_fully_bound_structs.rs new file mode 100644 index 00000000000..22e4d4edd78 --- /dev/null +++ b/tests/ui/rest_pat_in_fully_bound_structs.rs @@ -0,0 +1,30 @@ +#![warn(clippy::rest_pat_in_fully_bound_structs)] + +struct A { + a: i32, + b: i64, + c: &'static str, +} + +fn main() { + let a_struct = A { a: 5, b: 42, c: "A" }; + + match a_struct { + A { a: 5, b: 42, c: "", .. } => {}, // Lint + A { a: 0, b: 0, c: "", .. } => {}, // Lint + _ => {}, + } + + match a_struct { + A { a: 5, b: 42, .. } => {}, + A { a: 0, b: 0, c: "", .. } => {}, // Lint + _ => {}, + } + + // No lint + match a_struct { + A { a: 5, .. } => {}, + A { a: 0, b: 0, .. } => {}, + _ => {}, + } +} diff --git a/tests/ui/rest_pat_in_fully_bound_structs.stderr b/tests/ui/rest_pat_in_fully_bound_structs.stderr new file mode 100644 index 00000000000..effa46b4b0f --- /dev/null +++ b/tests/ui/rest_pat_in_fully_bound_structs.stderr @@ -0,0 +1,27 @@ +error: unnecessary use of `..` pattern in struct binding. All fields were already bound + --> $DIR/rest_pat_in_fully_bound_structs.rs:13:9 + | +LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings` + = help: consider removing `..` from this binding + +error: unnecessary use of `..` pattern in struct binding. All fields were already bound + --> $DIR/rest_pat_in_fully_bound_structs.rs:14:9 + | +LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `..` from this binding + +error: unnecessary use of `..` pattern in struct binding. All fields were already bound + --> $DIR/rest_pat_in_fully_bound_structs.rs:20:9 + | +LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `..` from this binding + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 597e02dcdf28e9cfbb7854bca38c28f2e4d15425 Mon Sep 17 00:00:00 2001 From: Devin R <devin.ragotzy@gmail.com> Date: Wed, 26 Feb 2020 07:40:31 -0500 Subject: warn on macro_use attr --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 +++ clippy_lints/src/macro_use.rs | 53 ++++++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 ++++++- tests/ui/macro_use_import.rs | 11 +++++++++ tests/ui/macro_use_import.stderr | 10 ++++++++ 7 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/macro_use.rs create mode 100644 tests/ui/macro_use_import.rs create mode 100644 tests/ui/macro_use_import.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8e2494389..9ba9fdd4b8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1209,6 +1209,7 @@ Released 2018-09-13 [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal +[`macro_use_import`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_import [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic diff --git a/README.md b/README.md index 6915b1bde02..8635b2b6d5a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 359 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 360 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 327cc56cafa..86ab7d83905 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -234,6 +234,7 @@ pub mod let_underscore; pub mod lifetimes; pub mod literal_representation; pub mod loops; +pub mod macro_use; pub mod main_recursion; pub mod map_clone; pub mod map_unit_fn; @@ -599,6 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &loops::WHILE_IMMUTABLE_CONDITION, &loops::WHILE_LET_LOOP, &loops::WHILE_LET_ON_ITERATOR, + ¯o_use::MACRO_USE_IMPORT, &main_recursion::MAIN_RECURSION, &map_clone::MAP_CLONE, &map_unit_fn::OPTION_MAP_UNIT_FN, @@ -1012,6 +1014,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); store.register_late_pass(|| box wildcard_imports::WildcardImports); + store.register_early_pass(|| box macro_use::MacroUseImport); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1079,6 +1082,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), + LintId::of(¯o_use::MACRO_USE_IMPORT), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs new file mode 100644 index 00000000000..43671d69413 --- /dev/null +++ b/clippy_lints/src/macro_use.rs @@ -0,0 +1,53 @@ +use crate::utils::{snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::edition::Edition; + +declare_clippy_lint! { + /// **What it does:** Checks for `#[macro_use] use...`. + /// + /// **Why is this bad?** Since the Rust 2018 edition you can import + /// macro's directly, this is considered idiomatic. + /// + /// **Known problems:** This lint does not generate an auto-applicable suggestion. + /// + /// **Example:** + /// ```rust + /// #[macro_use] + /// use lazy_static; + /// ``` + pub MACRO_USE_IMPORT, + pedantic, + "#[macro_use] is no longer needed" +} + +declare_lint_pass!(MacroUseImport => [MACRO_USE_IMPORT]); + +impl EarlyLintPass for MacroUseImport { + fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) { + if_chain! { + if ecx.sess.opts.edition == Edition::Edition2018; + if let ast::ItemKind::Use(use_tree) = &item.kind; + if let Some(mac_attr) = item + .attrs + .iter() + .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string())); + then { + let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition"; + let help = format!("use {}::<macro name>", snippet(ecx, use_tree.span, "_")); + span_lint_and_sugg( + ecx, + MACRO_USE_IMPORT, + mac_attr.span, + msg, + "remove the attribute and import the macro directly, try", + help, + Applicability::HasPlaceholders, + ); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2b93e4279f0..1635ff7babd 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 359] = [ +pub const ALL_LINTS: [Lint; 360] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1015,6 +1015,13 @@ pub const ALL_LINTS: [Lint; 359] = [ deprecation: None, module: "float_literal", }, + Lint { + name: "macro_use_import", + group: "pedantic", + desc: "#[macro_use] is no longer needed", + deprecation: None, + module: "macro_use", + }, Lint { name: "main_recursion", group: "style", diff --git a/tests/ui/macro_use_import.rs b/tests/ui/macro_use_import.rs new file mode 100644 index 00000000000..33ce2b524ef --- /dev/null +++ b/tests/ui/macro_use_import.rs @@ -0,0 +1,11 @@ +// compile-flags: --edition 2018 +#![warn(clippy::macro_use_import)] + +use std::collections::HashMap; +#[macro_use] +use std::prelude; + +fn main() { + let _ = HashMap::<u8, u8>::new(); + println!(); +} diff --git a/tests/ui/macro_use_import.stderr b/tests/ui/macro_use_import.stderr new file mode 100644 index 00000000000..1d86ba58441 --- /dev/null +++ b/tests/ui/macro_use_import.stderr @@ -0,0 +1,10 @@ +error: `macro_use` attributes are no longer needed in the Rust 2018 edition + --> $DIR/macro_use_import.rs:5:1 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>` + | + = note: `-D clippy::macro-use-import` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 57393b5106c5475dbe9f99f75013e8ea7f1988d6 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Thu, 5 Mar 2020 19:22:17 +0100 Subject: Rename macro_use_import -> macro_use_imports --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 +++--- clippy_lints/src/macro_use.rs | 8 ++++---- src/lintlist/mod.rs | 2 +- tests/ui/macro_use_import.rs | 11 ----------- tests/ui/macro_use_import.stderr | 10 ---------- tests/ui/macro_use_imports.rs | 11 +++++++++++ tests/ui/macro_use_imports.stderr | 10 ++++++++++ 8 files changed, 30 insertions(+), 30 deletions(-) delete mode 100644 tests/ui/macro_use_import.rs delete mode 100644 tests/ui/macro_use_import.stderr create mode 100644 tests/ui/macro_use_imports.rs create mode 100644 tests/ui/macro_use_imports.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba9fdd4b8a..c3f291bc046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1209,7 +1209,7 @@ Released 2018-09-13 [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal -[`macro_use_import`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_import +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 86ab7d83905..02c016c385d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -600,7 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &loops::WHILE_IMMUTABLE_CONDITION, &loops::WHILE_LET_LOOP, &loops::WHILE_LET_ON_ITERATOR, - ¯o_use::MACRO_USE_IMPORT, + ¯o_use::MACRO_USE_IMPORTS, &main_recursion::MAIN_RECURSION, &map_clone::MAP_CLONE, &map_unit_fn::OPTION_MAP_UNIT_FN, @@ -1014,7 +1014,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); store.register_late_pass(|| box wildcard_imports::WildcardImports); - store.register_early_pass(|| box macro_use::MacroUseImport); + store.register_early_pass(|| box macro_use::MacroUseImports); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1082,7 +1082,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), - LintId::of(¯o_use::MACRO_USE_IMPORT), + LintId::of(¯o_use::MACRO_USE_IMPORTS), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 43671d69413..b1345d0b751 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -19,14 +19,14 @@ declare_clippy_lint! { /// #[macro_use] /// use lazy_static; /// ``` - pub MACRO_USE_IMPORT, + pub MACRO_USE_IMPORTS, pedantic, "#[macro_use] is no longer needed" } -declare_lint_pass!(MacroUseImport => [MACRO_USE_IMPORT]); +declare_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]); -impl EarlyLintPass for MacroUseImport { +impl EarlyLintPass for MacroUseImports { fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) { if_chain! { if ecx.sess.opts.edition == Edition::Edition2018; @@ -40,7 +40,7 @@ impl EarlyLintPass for MacroUseImport { let help = format!("use {}::<macro name>", snippet(ecx, use_tree.span, "_")); span_lint_and_sugg( ecx, - MACRO_USE_IMPORT, + MACRO_USE_IMPORTS, mac_attr.span, msg, "remove the attribute and import the macro directly, try", diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1635ff7babd..4ae4ccc91f0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1016,7 +1016,7 @@ pub const ALL_LINTS: [Lint; 360] = [ module: "float_literal", }, Lint { - name: "macro_use_import", + name: "macro_use_imports", group: "pedantic", desc: "#[macro_use] is no longer needed", deprecation: None, diff --git a/tests/ui/macro_use_import.rs b/tests/ui/macro_use_import.rs deleted file mode 100644 index 33ce2b524ef..00000000000 --- a/tests/ui/macro_use_import.rs +++ /dev/null @@ -1,11 +0,0 @@ -// compile-flags: --edition 2018 -#![warn(clippy::macro_use_import)] - -use std::collections::HashMap; -#[macro_use] -use std::prelude; - -fn main() { - let _ = HashMap::<u8, u8>::new(); - println!(); -} diff --git a/tests/ui/macro_use_import.stderr b/tests/ui/macro_use_import.stderr deleted file mode 100644 index 1d86ba58441..00000000000 --- a/tests/ui/macro_use_import.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_import.rs:5:1 - | -LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>` - | - = note: `-D clippy::macro-use-import` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs new file mode 100644 index 00000000000..094dce17d4b --- /dev/null +++ b/tests/ui/macro_use_imports.rs @@ -0,0 +1,11 @@ +// compile-flags: --edition 2018 +#![warn(clippy::macro_use_imports)] + +use std::collections::HashMap; +#[macro_use] +use std::prelude; + +fn main() { + let _ = HashMap::<u8, u8>::new(); + println!(); +} diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr new file mode 100644 index 00000000000..b5e3dbec572 --- /dev/null +++ b/tests/ui/macro_use_imports.stderr @@ -0,0 +1,10 @@ +error: `macro_use` attributes are no longer needed in the Rust 2018 edition + --> $DIR/macro_use_imports.rs:5:1 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>` + | + = note: `-D clippy::macro-use-imports` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 0f7f30711e4eb2f5f84fe198f325e512e404ee0c Mon Sep 17 00:00:00 2001 From: Jacob Meyers <jacobmeyers065@gmail.com> Date: Wed, 4 Mar 2020 21:13:57 -0500 Subject: add lint on File::read_to_string and File::read_to_end --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 5 +++ clippy_lints/src/utils/paths.rs | 1 + clippy_lints/src/verbose_file_reads.rs | 82 ++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 9 +++- tests/ui/verbose_file_reads.rs | 30 +++++++++++++ tests/ui/verbose_file_reads.stderr | 19 ++++++++ 8 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/verbose_file_reads.rs create mode 100644 tests/ui/verbose_file_reads.rs create mode 100644 tests/ui/verbose_file_reads.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f291bc046..32cbbe80101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1417,6 +1417,7 @@ Released 2018-09-13 [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask +[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator diff --git a/README.md b/README.md index 8635b2b6d5a..2181c296e9b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 360 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 02c016c385d..1eac69678a6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -310,6 +310,7 @@ pub mod unused_self; pub mod unwrap; pub mod use_self; pub mod vec; +pub mod verbose_file_reads; pub mod wildcard_dependencies; pub mod wildcard_imports; pub mod write; @@ -815,6 +816,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap::UNNECESSARY_UNWRAP, &use_self::USE_SELF, &vec::USELESS_VEC, + &verbose_file_reads::VERBOSE_FILE_READS, &wildcard_dependencies::WILDCARD_DEPENDENCIES, &wildcard_imports::ENUM_GLOB_USE, &wildcard_imports::WILDCARD_IMPORTS, @@ -1015,6 +1017,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); store.register_late_pass(|| box wildcard_imports::WildcardImports); store.register_early_pass(|| box macro_use::MacroUseImports); + store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1372,6 +1375,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&vec::USELESS_VEC), + LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), LintId::of(&write::PRINT_WITH_NEWLINE), @@ -1555,6 +1559,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unwrap::UNNECESSARY_UNWRAP), + LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 5ec04d965c8..6cb1f694fd5 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -31,6 +31,7 @@ pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"]; pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; +pub const FILE: [&str; 3] = ["std", "fs", "File"]; pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"]; pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"]; diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs new file mode 100644 index 00000000000..93256790211 --- /dev/null +++ b/clippy_lints/src/verbose_file_reads.rs @@ -0,0 +1,82 @@ +use crate::utils::{match_type, paths, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for use of File::read_to_end and File::read_to_string. + /// + /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust, ignore + /// let mut f = File::open("foo.txt")?; + /// let mut bytes = Vec::new(); + /// f.read_to_end(&mut bytes)?; + /// ``` + /// Can be written more concisely as + /// ```rust, ignore + /// let mut bytes = fs::read("foo.txt")?; + /// ``` + pub VERBOSE_FILE_READS, + complexity, + "use of `File::read_to_end` or `File::read_to_string`" +} + +declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) { + if is_file_read_to_end(cx, expr) { + span_lint_and_help( + cx, + VERBOSE_FILE_READS, + expr.span, + "use of File::read_to_end", + "consider using fs::read instead", + ); + } else if is_file_read_to_string(cx, expr) { + span_lint_and_help( + cx, + VERBOSE_FILE_READS, + expr.span, + "use of File::read_to_string", + "consider using fs::read_to_string instead", + ) + } else { + // Don't care + } + } +} + +fn is_file_read_to_end<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if_chain! { + if let ExprKind::MethodCall(method_name, _, exprs) = expr.kind; + if method_name.ident.as_str() == "read_to_end"; + if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; + let ty = cx.tables.expr_ty(&exprs[0]); + if match_type(cx, ty, &paths::FILE); + then { + return true + } + } + false +} + +fn is_file_read_to_string<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if_chain! { + if let ExprKind::MethodCall(method_name, _, exprs) = expr.kind; + if method_name.ident.as_str() == "read_to_string"; + if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; + let ty = cx.tables.expr_ty(&exprs[0]); + if match_type(cx, ty, &paths::FILE); + then { + return true + } + } + false +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 4ae4ccc91f0..fd948953ea2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 360] = [ +pub const ALL_LINTS: [Lint; 361] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2401,6 +2401,13 @@ pub const ALL_LINTS: [Lint; 360] = [ deprecation: None, module: "bit_mask", }, + Lint { + name: "verbose_file_reads", + group: "complexity", + desc: "use of `File::read_to_end` or `File::read_to_string`", + deprecation: None, + module: "verbose_file_reads", + }, Lint { name: "while_immutable_condition", group: "correctness", diff --git a/tests/ui/verbose_file_reads.rs b/tests/ui/verbose_file_reads.rs new file mode 100644 index 00000000000..3c7c4be84b0 --- /dev/null +++ b/tests/ui/verbose_file_reads.rs @@ -0,0 +1,30 @@ +#![warn(clippy::verbose_file_reads)] +use std::env::temp_dir; +use std::fs::File; +use std::io::Read; + +struct Struct; +// To make sure we only warn on File::{read_to_end, read_to_string} calls +impl Struct { + pub fn read_to_end(&self) {} + + pub fn read_to_string(&self) {} +} + +fn main() -> std::io::Result<()> { + let mut path = temp_dir(); + path.push("test.txt"); + let file = File::create(&path)?; + // Lint shouldn't catch this + let s = Struct; + s.read_to_end(); + s.read_to_string(); + // Should catch this + let mut f = File::open(&path)?; + let mut buffer = Vec::new(); + f.read_to_end(&mut buffer)?; + // ...and this + let mut string_buffer = String::new(); + f.read_to_string(&mut string_buffer)?; + Ok(()) +} diff --git a/tests/ui/verbose_file_reads.stderr b/tests/ui/verbose_file_reads.stderr new file mode 100644 index 00000000000..73dc22fd4db --- /dev/null +++ b/tests/ui/verbose_file_reads.stderr @@ -0,0 +1,19 @@ +error: use of File::read_to_end + --> $DIR/verbose_file_reads.rs:25:5 + | +LL | f.read_to_end(&mut buffer)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::verbose-file-reads` implied by `-D warnings` + = help: consider using fs::read instead + +error: use of File::read_to_string + --> $DIR/verbose_file_reads.rs:28:5 + | +LL | f.read_to_string(&mut string_buffer)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using fs::read_to_string instead + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 52208f3cf3949a4589cbaee69a9cb7d34ee0e9f2 Mon Sep 17 00:00:00 2001 From: Tim Robinson <tim.g.robinson@gmail.com> Date: Sun, 15 Mar 2020 17:38:20 +0000 Subject: Lint for `pub(crate)` items that are not crate visible due to the visibility of the module that contains them Closes #5274. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/lib.rs | 4 + clippy_lints/src/redundant_pub_crate.rs | 67 +++++++++++++++ src/lintlist/mod.rs | 9 +- tests/ui/redundant_pub_crate.rs | 105 +++++++++++++++++++++++ tests/ui/redundant_pub_crate.stderr | 146 ++++++++++++++++++++++++++++++++ 7 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/redundant_pub_crate.rs create mode 100644 tests/ui/redundant_pub_crate.rs create mode 100644 tests/ui/redundant_pub_crate.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d41e3b31d..9fa2dcad4a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1410,6 +1410,7 @@ Released 2018-09-13 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching +[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro diff --git a/README.md b/README.md index 2181c296e9b..7d6fcbc9098 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 791307ba43f..601bbdce704 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -284,6 +284,7 @@ pub mod ranges; pub mod redundant_clone; pub mod redundant_field_names; pub mod redundant_pattern_matching; +pub mod redundant_pub_crate; pub mod redundant_static_lifetimes; pub mod reference; pub mod regex; @@ -744,6 +745,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &redundant_clone::REDUNDANT_CLONE, &redundant_field_names::REDUNDANT_FIELD_NAMES, &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, + &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, &reference::DEREF_ADDROF, &reference::REF_IN_DEREF, @@ -1020,6 +1022,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box wildcard_imports::WildcardImports); store.register_early_pass(|| box macro_use::MacroUseImports); store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); + store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1669,6 +1672,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs new file mode 100644 index 00000000000..4c638da80a8 --- /dev/null +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -0,0 +1,67 @@ +use crate::utils::span_lint_and_help; +use rustc_hir::{Item, ItemKind, VisibilityKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// **What it does:** Checks for items declared `pub(crate)` that are not crate visible because they + /// are inside a private module. + /// + /// **Why is this bad?** Writing `pub(crate)` is misleading when it's redundant due to the parent + /// module's visibility. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// mod internal { + /// pub(crate) fn internal_fn() { } + /// } + /// ``` + /// This function is not visible outside the module and it can be declared with `pub` or + /// private visibility + /// ```rust + /// mod internal { + /// pub fn internal_fn() { } + /// } + /// ``` + pub REDUNDANT_PUB_CRATE, + nursery, + "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them." +} + +#[derive(Default)] +pub struct RedundantPubCrate { + is_exported: Vec<bool>, +} + +impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantPubCrate { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'tcx>) { + if let VisibilityKind::Crate { .. } = item.vis.node { + if !cx.access_levels.is_exported(item.hir_id) { + if let Some(false) = self.is_exported.last() { + span_lint_and_help( + cx, + REDUNDANT_PUB_CRATE, + item.span, + &format!("pub(crate) {} inside private module", item.kind.descr()), + "consider using `pub` instead of `pub(crate)`", + ) + } + } + } + + if let ItemKind::Mod { .. } = item.kind { + self.is_exported.push(cx.access_levels.is_exported(item.hir_id)); + } + } + + fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Mod { .. } = item.kind { + self.is_exported.pop().expect("unbalanced check_item/check_item_post"); + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index fd948953ea2..29d9c8b76d0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 361] = [ +pub const ALL_LINTS: [Lint; 362] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1764,6 +1764,13 @@ pub const ALL_LINTS: [Lint; 361] = [ deprecation: None, module: "redundant_pattern_matching", }, + Lint { + name: "redundant_pub_crate", + group: "nursery", + desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.", + deprecation: None, + module: "redundant_pub_crate", + }, Lint { name: "redundant_static_lifetimes", group: "style", diff --git a/tests/ui/redundant_pub_crate.rs b/tests/ui/redundant_pub_crate.rs new file mode 100644 index 00000000000..c747a07dd90 --- /dev/null +++ b/tests/ui/redundant_pub_crate.rs @@ -0,0 +1,105 @@ +#![warn(clippy::redundant_pub_crate)] + +mod m1 { + fn f() {} + pub(crate) fn g() {} // private due to m1 + pub fn h() {} + + mod m1_1 { + fn f() {} + pub(crate) fn g() {} // private due to m1_1 and m1 + pub fn h() {} + } + + pub(crate) mod m1_2 { + // ^ private due to m1 + fn f() {} + pub(crate) fn g() {} // private due to m1_2 and m1 + pub fn h() {} + } + + pub mod m1_3 { + fn f() {} + pub(crate) fn g() {} // private due to m1 + pub fn h() {} + } +} + +pub(crate) mod m2 { + fn f() {} + pub(crate) fn g() {} // already crate visible due to m2 + pub fn h() {} + + mod m2_1 { + fn f() {} + pub(crate) fn g() {} // private due to m2_1 + pub fn h() {} + } + + pub(crate) mod m2_2 { + // ^ already crate visible due to m2 + fn f() {} + pub(crate) fn g() {} // already crate visible due to m2_2 and m2 + pub fn h() {} + } + + pub mod m2_3 { + fn f() {} + pub(crate) fn g() {} // already crate visible due to m2 + pub fn h() {} + } +} + +pub mod m3 { + fn f() {} + pub(crate) fn g() {} // ok: m3 is exported + pub fn h() {} + + mod m3_1 { + fn f() {} + pub(crate) fn g() {} // private due to m3_1 + pub fn h() {} + } + + pub(crate) mod m3_2 { + // ^ ok + fn f() {} + pub(crate) fn g() {} // already crate visible due to m3_2 + pub fn h() {} + } + + pub mod m3_3 { + fn f() {} + pub(crate) fn g() {} // ok: m3 and m3_3 are exported + pub fn h() {} + } +} + +mod m4 { + fn f() {} + pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` + pub fn h() {} + + mod m4_1 { + fn f() {} + pub(crate) fn g() {} // private due to m4_1 + pub fn h() {} + } + + pub(crate) mod m4_2 { + // ^ private: not re-exported by `pub use m4::*` + fn f() {} + pub(crate) fn g() {} // private due to m4_2 + pub fn h() {} + } + + pub mod m4_3 { + fn f() {} + pub(crate) fn g() {} // ok: m4_3 is re-exported by `pub use m4::*` + pub fn h() {} + } +} + +pub use m4::*; + +fn main() {} diff --git a/tests/ui/redundant_pub_crate.stderr b/tests/ui/redundant_pub_crate.stderr new file mode 100644 index 00000000000..ecc038c7f4e --- /dev/null +++ b/tests/ui/redundant_pub_crate.stderr @@ -0,0 +1,146 @@ +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:5:5 + | +LL | pub(crate) fn g() {} // private due to m1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::redundant-pub-crate` implied by `-D warnings` + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:10:9 + | +LL | pub(crate) fn g() {} // private due to m1_1 and m1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) module inside private module + --> $DIR/redundant_pub_crate.rs:14:5 + | +LL | / pub(crate) mod m1_2 { +LL | | // ^ private due to m1 +LL | | fn f() {} +LL | | pub(crate) fn g() {} // private due to m1_2 and m1 +LL | | pub fn h() {} +LL | | } + | |_____^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:17:9 + | +LL | pub(crate) fn g() {} // private due to m1_2 and m1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:23:9 + | +LL | pub(crate) fn g() {} // private due to m1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:30:5 + | +LL | pub(crate) fn g() {} // already crate visible due to m2 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:35:9 + | +LL | pub(crate) fn g() {} // private due to m2_1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) module inside private module + --> $DIR/redundant_pub_crate.rs:39:5 + | +LL | / pub(crate) mod m2_2 { +LL | | // ^ already crate visible due to m2 +LL | | fn f() {} +LL | | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 +LL | | pub fn h() {} +LL | | } + | |_____^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:42:9 + | +LL | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:48:9 + | +LL | pub(crate) fn g() {} // already crate visible due to m2 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:60:9 + | +LL | pub(crate) fn g() {} // private due to m3_1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:67:9 + | +LL | pub(crate) fn g() {} // already crate visible due to m3_2 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:80:5 + | +LL | pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:85:9 + | +LL | pub(crate) fn g() {} // private due to m4_1 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) module inside private module + --> $DIR/redundant_pub_crate.rs:89:5 + | +LL | / pub(crate) mod m4_2 { +LL | | // ^ private: not re-exported by `pub use m4::*` +LL | | fn f() {} +LL | | pub(crate) fn g() {} // private due to m4_2 +LL | | pub fn h() {} +LL | | } + | |_____^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: pub(crate) function inside private module + --> $DIR/redundant_pub_crate.rs:92:9 + | +LL | pub(crate) fn g() {} // private due to m4_2 + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `pub` instead of `pub(crate)` + +error: aborting due to 16 previous errors + -- cgit 1.4.1-3-g733a5 From 870b9e8139052f7cb1ef1e5717f2f4ce523fb688 Mon Sep 17 00:00:00 2001 From: Tim Robinson <tim.g.robinson@gmail.com> Date: Mon, 23 Mar 2020 16:06:15 +0000 Subject: nursery group -> style --- clippy_lints/src/lib.rs | 5 +++-- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/numeric_literal.rs | 4 ++-- src/lintlist/mod.rs | 2 +- tests/ui/wildcard_imports.fixed | 1 + tests/ui/wildcard_imports.rs | 1 + tests/ui/wildcard_imports.stderr | 30 +++++++++++++++--------------- 8 files changed, 25 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 601bbdce704..33329acb832 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -323,7 +323,7 @@ pub mod zero_div_zero; pub use crate::utils::conf::Conf; mod reexport { - crate use rustc_ast::ast::Name; + pub use rustc_ast::ast::Name; } /// Register all pre expansion lints @@ -1324,6 +1324,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), + LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), @@ -1465,6 +1466,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&question_mark::QUESTION_MARK), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), + LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), @@ -1672,7 +1674,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), - LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index b54d0b0c9a1..af4ab367f5f 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// } /// ``` pub REDUNDANT_PUB_CRATE, - nursery, + style, "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them." } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index a1d7bebc7b5..722104e5b52 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -80,7 +80,7 @@ macro_rules! define_Conf { $( mod $config { use serde::Deserialize; - crate fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> { + pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> { use super::super::{ERRORS, Error}; Ok( <$Ty>::deserialize(deserializer).unwrap_or_else(|e| { diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 8b3492724e1..99413153d49 100644 --- a/clippy_lints/src/utils/numeric_literal.rs +++ b/clippy_lints/src/utils/numeric_literal.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind}; #[derive(Debug, PartialEq)] -pub(crate) enum Radix { +pub enum Radix { Binary, Octal, Decimal, @@ -26,7 +26,7 @@ pub fn format(lit: &str, type_suffix: Option<&str>, float: bool) -> String { } #[derive(Debug)] -pub(crate) struct NumericLiteral<'a> { +pub struct NumericLiteral<'a> { /// Which radix the literal was represented in. pub radix: Radix, /// The radix prefix, if present. diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 29d9c8b76d0..50d5c881952 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1766,7 +1766,7 @@ pub const ALL_LINTS: [Lint; 362] = [ }, Lint { name: "redundant_pub_crate", - group: "nursery", + group: "style", desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.", deprecation: None, module: "redundant_pub_crate", diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index f447a92715d..69ab6e1f8c1 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -2,6 +2,7 @@ // aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] +#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![warn(unused_imports)] diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 3fd66763a9f..e64ac4ce519 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -2,6 +2,7 @@ // aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] +#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![warn(unused_imports)] diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index bebd9c1f852..050e4c6304f 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:10:5 + --> $DIR/wildcard_imports.rs:11:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:11:5 + --> $DIR/wildcard_imports.rs:12:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:13:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:14:5 + --> $DIR/wildcard_imports.rs:15:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:18:5 + --> $DIR/wildcard_imports.rs:19:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:19:5 + --> $DIR/wildcard_imports.rs:20:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:88:13 + --> $DIR/wildcard_imports.rs:89:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:94:75 + --> $DIR/wildcard_imports.rs:95:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:95:13 + --> $DIR/wildcard_imports.rs:96:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:106:20 + --> $DIR/wildcard_imports.rs:107:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:106:30 + --> $DIR/wildcard_imports.rs:107:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:113:13 + --> $DIR/wildcard_imports.rs:114:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:142:9 + --> $DIR/wildcard_imports.rs:143:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:151:9 + --> $DIR/wildcard_imports.rs:152:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:152:9 + --> $DIR/wildcard_imports.rs:153:9 | LL | use crate:: fn_mod:: | _________^ -- cgit 1.4.1-3-g733a5 From 13fcee51e7bcaff23694d845146c6ede2e7834c2 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Mon, 23 Mar 2020 20:08:07 +0100 Subject: Move useless_transmute to nursery --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/transmute.rs | 3 ++- src/lintlist/mod.rs | 2 +- tests/ui/transmute_ptr_to_ptr.stderr | 28 +--------------------------- 4 files changed, 5 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1c81d78a2b9..e3e833000f7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1351,7 +1351,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), @@ -1553,7 +1552,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(&transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&types::BORROWED_BOX), LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::OPTION_OPTION), @@ -1670,6 +1668,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&use_self::USE_SELF), ]); } diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 4d1996ffcef..6dad9eef522 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { "transmutes that are confusing at best, undefined behaviour at worst and always useless" } +// FIXME: Move this to `complexity` again, after #5343 is fixed declare_clippy_lint! { /// **What it does:** Checks for transmutes to the original type of the object /// and transmutes that could be a cast. @@ -42,7 +43,7 @@ declare_clippy_lint! { /// core::intrinsics::transmute(t); // where the result type is the same as `t`'s /// ``` pub USELESS_TRANSMUTE, - complexity, + nursery, "transmutes that have the same to and from types or could be a cast/coercion" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index fd948953ea2..bc5bad401a4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2375,7 +2375,7 @@ pub const ALL_LINTS: [Lint; 361] = [ }, Lint { name: "useless_transmute", - group: "complexity", + group: "nursery", desc: "transmutes that have the same to and from types or could be a cast/coercion", deprecation: None, module: "transmute", diff --git a/tests/ui/transmute_ptr_to_ptr.stderr b/tests/ui/transmute_ptr_to_ptr.stderr index 61fbea1c164..4d1b8fcc199 100644 --- a/tests/ui/transmute_ptr_to_ptr.stderr +++ b/tests/ui/transmute_ptr_to_ptr.stderr @@ -1,17 +1,3 @@ -error: transmute from a type (`&T`) to itself - --> $DIR/transmute_ptr_to_ptr.rs:8:5 - | -LL | std::mem::transmute::<&'a T, &'static T>(t) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - -error: transmute from a type (`&T`) to itself - --> $DIR/transmute_ptr_to_ptr.rs:13:5 - | -LL | std::mem::transmute::<&'a T, &'b T>(t) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: transmute from a pointer to a pointer --> $DIR/transmute_ptr_to_ptr.rs:29:29 | @@ -50,17 +36,5 @@ error: transmute from a reference to a reference LL | let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)` -error: transmute from a type (`&LifetimeParam`) to itself - --> $DIR/transmute_ptr_to_ptr.rs:50:47 - | -LL | let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: transmute from a type (`&GenericParam<&LifetimeParam>`) to itself - --> $DIR/transmute_ptr_to_ptr.rs:51:62 - | -LL | let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors -- cgit 1.4.1-3-g733a5 From b86e8434df5688d68d84434f25e7dacbe8a9247b Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Wed, 25 Mar 2020 18:09:25 +0100 Subject: move redundant_pub_crate to nursery cc #5369 --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/redundant_pub_crate.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/wildcard_imports.fixed | 2 +- tests/ui/wildcard_imports.rs | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e66006ac167..b701f4fee31 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1325,7 +1325,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), - LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), @@ -1466,7 +1465,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&question_mark::QUESTION_MARK), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), - LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), @@ -1673,6 +1671,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&use_self::USE_SELF), ]); diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index af4ab367f5f..b54d0b0c9a1 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// } /// ``` pub REDUNDANT_PUB_CRATE, - style, + nursery, "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them." } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index a17de3e216b..0cf094b8ed3 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1766,7 +1766,7 @@ pub const ALL_LINTS: [Lint; 362] = [ }, Lint { name: "redundant_pub_crate", - group: "style", + group: "nursery", desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.", deprecation: None, module: "redundant_pub_crate", diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 69ab6e1f8c1..ed6cc00ef04 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -2,7 +2,7 @@ // aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] -#![allow(clippy::redundant_pub_crate)] +//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![warn(unused_imports)] diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index e64ac4ce519..c6d6efaece8 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -2,7 +2,7 @@ // aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] -#![allow(clippy::redundant_pub_crate)] +//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![warn(unused_imports)] -- cgit 1.4.1-3-g733a5 From 7a40b5c132abb50801e4f91bd67d05aba1435d54 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Thu, 26 Mar 2020 15:01:03 +0100 Subject: Move verbose_file_reads to restriction --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/verbose_file_reads.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b701f4fee31..48180d9af6c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1062,6 +1062,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), + LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&write::PRINT_STDOUT), LintId::of(&write::USE_DEBUG), ]); @@ -1380,7 +1381,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&vec::USELESS_VEC), - LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), LintId::of(&write::PRINT_WITH_NEWLINE), @@ -1563,7 +1563,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unwrap::UNNECESSARY_UNWRAP), - LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 37885317c58..55d7983249a 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// let mut bytes = fs::read("foo.txt").unwrap(); /// ``` pub VERBOSE_FILE_READS, - complexity, + restriction, "use of `File::read_to_end` or `File::read_to_string`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0cf094b8ed3..2888741cb45 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2410,7 +2410,7 @@ pub const ALL_LINTS: [Lint; 362] = [ }, Lint { name: "verbose_file_reads", - group: "complexity", + group: "restriction", desc: "use of `File::read_to_end` or `File::read_to_string`", deprecation: None, module: "verbose_file_reads", -- cgit 1.4.1-3-g733a5 From 7c479fd8a7af670b8ff55f6d1d5c0d5178e6c196 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Mon, 23 Mar 2020 10:41:19 -0700 Subject: Start work on clippy-fix as subcommand --- src/main.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 93e6996be06..66c1aa4d97c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,11 @@ where let mut args = vec!["check".to_owned()]; for arg in old_args.by_ref() { + if arg == "--fix" { + args[0] = "fix".to_owned(); + continue; + } + if arg == "--" { break; } @@ -96,7 +101,7 @@ where let exit_status = std::process::Command::new("cargo") .args(&args) - .env("RUSTC_WRAPPER", path) + .env("RUSTC_WORKSPACE_WRAPPER", path) .env("CLIPPY_ARGS", clippy_args) .envs(target_dir) .spawn() -- cgit 1.4.1-3-g733a5 From df2d3c82df7ed70de7aa0d8db642b4f454228c4d Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Fri, 27 Mar 2020 12:47:57 -0700 Subject: check for unstable options --- src/main.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 66c1aa4d97c..4749300c3e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,18 +58,36 @@ where { let mut args = vec!["check".to_owned()]; + let mut fix = false; + let mut unstable_options = false; + for arg in old_args.by_ref() { - if arg == "--fix" { - args[0] = "fix".to_owned(); - continue; + match arg { + "--fix" => { + fix = true; + continue; + }, + "--" => break, + // Cover -Zunstable-options and -Z unstable-options + s if s.ends_with("unstable-options") => unstable_options = true, + _ => {}, } - if arg == "--" { - break; - } args.push(arg); } + if fix && !unstable_options { + panic!("Usage of `--fix` requires `-Z unstable-options`"); + } else { + args[0] = "fix".to_owned(); + } + + let env_name = if unstable_options { + "RUSTC_WORKSPACE_WRAPPER" + } else { + "RUSTC_WRAPPER" + }; + let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect(); let mut path = std::env::current_exe() -- cgit 1.4.1-3-g733a5 From 399e0231cd599e20b43ccb62c4ab2c55a730ded3 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Fri, 27 Mar 2020 13:23:06 -0700 Subject: boycott manish --- src/main.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 4749300c3e8..8c4a596cc4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,27 +62,29 @@ where let mut unstable_options = false; for arg in old_args.by_ref() { - match arg { + match arg.as_str() { "--fix" => { fix = true; continue; - }, + } "--" => break, // Cover -Zunstable-options and -Z unstable-options s if s.ends_with("unstable-options") => unstable_options = true, - _ => {}, + _ => {} } args.push(arg); } - if fix && !unstable_options { - panic!("Usage of `--fix` requires `-Z unstable-options`"); - } else { - args[0] = "fix".to_owned(); + if fix { + if !unstable_options { + panic!("Usage of `--fix` requires `-Z unstable-options`"); + } else { + args[0] = "fix".to_owned(); + } } - let env_name = if unstable_options { + let path_env = if unstable_options { "RUSTC_WORKSPACE_WRAPPER" } else { "RUSTC_WRAPPER" @@ -119,7 +121,7 @@ where let exit_status = std::process::Command::new("cargo") .args(&args) - .env("RUSTC_WORKSPACE_WRAPPER", path) + .env(path_env, path) .env("CLIPPY_ARGS", clippy_args) .envs(target_dir) .spawn() -- cgit 1.4.1-3-g733a5 From e190cc5590c0ed6d4691cd83550de744734a8137 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Fri, 27 Mar 2020 13:26:34 -0700 Subject: fix rustfmt issue --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 8c4a596cc4d..5de0d336b6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,11 +66,11 @@ where "--fix" => { fix = true; continue; - } + }, "--" => break, // Cover -Zunstable-options and -Z unstable-options s if s.ends_with("unstable-options") => unstable_options = true, - _ => {} + _ => {}, } args.push(arg); -- cgit 1.4.1-3-g733a5 From 680cc2f25848721eca3a2332c48b13c02e027dbc Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Fri, 27 Mar 2020 14:05:47 -0700 Subject: dogfood tasted bad --- src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 5de0d336b6a..a8ffc84001b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,10 +77,10 @@ where } if fix { - if !unstable_options { - panic!("Usage of `--fix` requires `-Z unstable-options`"); - } else { + if unstable_options { args[0] = "fix".to_owned(); + } else { + panic!("Usage of `--fix` requires `-Z unstable-options`"); } } -- cgit 1.4.1-3-g733a5 From d055b7d61c44b7a401ebc470e3d1e3bd06a4d360 Mon Sep 17 00:00:00 2001 From: Lzu Tao <taolzu@gmail.com> Date: Sun, 29 Mar 2020 12:59:35 +0700 Subject: Deprecate REPLACE_CONSTS lint --- README.md | 2 +- clippy_lints/src/deprecated_lints.rs | 8 ++ clippy_lints/src/lib.rs | 8 +- clippy_lints/src/replace_consts.rs | 103 ------------------------ src/lintlist/mod.rs | 9 +-- tests/ui/replace_consts.fixed | 99 ----------------------- tests/ui/replace_consts.rs | 99 ----------------------- tests/ui/replace_consts.stderr | 152 ----------------------------------- 8 files changed, 14 insertions(+), 466 deletions(-) delete mode 100644 clippy_lints/src/replace_consts.rs delete mode 100644 tests/ui/replace_consts.fixed delete mode 100644 tests/ui/replace_consts.rs delete mode 100644 tests/ui/replace_consts.stderr (limited to 'src') diff --git a/README.md b/README.md index ebdab4c6a1a..5733994a06c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 93c19bf9550..6e8ca647dd7 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -147,3 +147,11 @@ declare_deprecated_lint! { pub UNUSED_LABEL, "this lint has been uplifted to rustc and is now called `unused_labels`" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** Associated-constants are now preferred. + pub REPLACE_CONSTS, + "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 140500afe0f..704b46a87c9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -291,7 +291,6 @@ pub mod redundant_pub_crate; pub mod redundant_static_lifetimes; pub mod reference; pub mod regex; -pub mod replace_consts; pub mod returns; pub mod serde_api; pub mod shadow; @@ -470,6 +469,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::unused_label", "this lint has been uplifted to rustc and is now called `unused_labels`", ); + store.register_removed( + "clippy::replace_consts", + "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -755,7 +758,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ®ex::INVALID_REGEX, ®ex::REGEX_MACRO, ®ex::TRIVIAL_REGEX, - &replace_consts::REPLACE_CONSTS, &returns::LET_AND_RETURN, &returns::NEEDLESS_RETURN, &returns::UNUSED_UNIT, @@ -953,7 +955,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box identity_conversion::IdentityConversion::default()); store.register_late_pass(|| box types::ImplicitHasher); store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); - store.register_late_pass(|| box replace_consts::ReplaceConsts); store.register_late_pass(|| box types::UnitArg); store.register_late_pass(|| box double_comparison::DoubleComparisons); store.register_late_pass(|| box question_mark::QuestionMark); @@ -1110,7 +1111,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), LintId::of(&non_expressive_names::SIMILAR_NAMES), LintId::of(&ranges::RANGE_PLUS_ONE), - LintId::of(&replace_consts::REPLACE_CONSTS), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS), diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs deleted file mode 100644 index aca1ebbd508..00000000000 --- a/clippy_lints/src/replace_consts.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::utils::{match_def_path, span_lint_and_sugg}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, Node}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// **What it does:** Checks for usage of standard library - /// `const`s that could be replaced by `const fn`s. - /// - /// **Why is this bad?** `const fn`s exist - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// let x = std::u32::MIN; - /// let y = std::u32::MAX; - /// ``` - /// - /// Could be written: - /// - /// ```rust - /// let x = u32::min_value(); - /// let y = u32::max_value(); - /// ``` - pub REPLACE_CONSTS, - pedantic, - "Lint usages of standard library `const`s that could be replaced by `const fn`s" -} - -declare_lint_pass!(ReplaceConsts => [REPLACE_CONSTS]); - -fn in_pattern(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { - let map = &cx.tcx.hir(); - let parent_id = map.get_parent_node(expr.hir_id); - - if let Some(node) = map.find(parent_id) { - if let Node::Pat(_) = node { - return true; - } - } - - false -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Path(ref qp) = expr.kind; - if let Res::Def(DefKind::Const, def_id) = cx.tables.qpath_res(qp, expr.hir_id); - // Do not lint within patterns as function calls are disallowed in them - if !in_pattern(cx, expr); - then { - for &(ref const_path, repl_snip) in &REPLACEMENTS { - if match_def_path(cx, def_id, const_path) { - span_lint_and_sugg( - cx, - REPLACE_CONSTS, - expr.span, - &format!("using `{}`", const_path.last().expect("empty path")), - "try this", - repl_snip.to_string(), - Applicability::MachineApplicable, - ); - return; - } - } - } - } - } -} - -const REPLACEMENTS: [([&str; 3], &str); 24] = [ - // Min - (["core", "isize", "MIN"], "isize::min_value()"), - (["core", "i8", "MIN"], "i8::min_value()"), - (["core", "i16", "MIN"], "i16::min_value()"), - (["core", "i32", "MIN"], "i32::min_value()"), - (["core", "i64", "MIN"], "i64::min_value()"), - (["core", "i128", "MIN"], "i128::min_value()"), - (["core", "usize", "MIN"], "usize::min_value()"), - (["core", "u8", "MIN"], "u8::min_value()"), - (["core", "u16", "MIN"], "u16::min_value()"), - (["core", "u32", "MIN"], "u32::min_value()"), - (["core", "u64", "MIN"], "u64::min_value()"), - (["core", "u128", "MIN"], "u128::min_value()"), - // Max - (["core", "isize", "MAX"], "isize::max_value()"), - (["core", "i8", "MAX"], "i8::max_value()"), - (["core", "i16", "MAX"], "i16::max_value()"), - (["core", "i32", "MAX"], "i32::max_value()"), - (["core", "i64", "MAX"], "i64::max_value()"), - (["core", "i128", "MAX"], "i128::max_value()"), - (["core", "usize", "MAX"], "usize::max_value()"), - (["core", "u8", "MAX"], "u8::max_value()"), - (["core", "u16", "MAX"], "u16::max_value()"), - (["core", "u32", "MAX"], "u32::max_value()"), - (["core", "u64", "MAX"], "u64::max_value()"), - (["core", "u128", "MAX"], "u128::max_value()"), -]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2888741cb45..5777e7d90e5 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 362] = [ +pub const ALL_LINTS: [Lint; 361] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1792,13 +1792,6 @@ pub const ALL_LINTS: [Lint; 362] = [ deprecation: None, module: "regex", }, - Lint { - name: "replace_consts", - group: "pedantic", - desc: "Lint usages of standard library `const`s that could be replaced by `const fn`s", - deprecation: None, - module: "replace_consts", - }, Lint { name: "rest_pat_in_fully_bound_structs", group: "restriction", diff --git a/tests/ui/replace_consts.fixed b/tests/ui/replace_consts.fixed deleted file mode 100644 index 108474408e0..00000000000 --- a/tests/ui/replace_consts.fixed +++ /dev/null @@ -1,99 +0,0 @@ -// run-rustfix -#![feature(integer_atomics)] -#![allow(unused_variables, clippy::blacklisted_name)] -#![deny(clippy::replace_consts)] - -use std::sync::atomic::*; - -#[rustfmt::skip] -fn bad() { - // Min - { let foo = isize::min_value(); }; - { let foo = i8::min_value(); }; - { let foo = i16::min_value(); }; - { let foo = i32::min_value(); }; - { let foo = i64::min_value(); }; - { let foo = i128::min_value(); }; - { let foo = usize::min_value(); }; - { let foo = u8::min_value(); }; - { let foo = u16::min_value(); }; - { let foo = u32::min_value(); }; - { let foo = u64::min_value(); }; - { let foo = u128::min_value(); }; - // Max - { let foo = isize::max_value(); }; - { let foo = i8::max_value(); }; - { let foo = i16::max_value(); }; - { let foo = i32::max_value(); }; - { let foo = i64::max_value(); }; - { let foo = i128::max_value(); }; - { let foo = usize::max_value(); }; - { let foo = u8::max_value(); }; - { let foo = u16::max_value(); }; - { let foo = u32::max_value(); }; - { let foo = u64::max_value(); }; - { let foo = u128::max_value(); }; -} - -#[rustfmt::skip] -fn good() { - // Atomic - { let foo = AtomicBool::new(false); }; - { let foo = AtomicIsize::new(0); }; - { let foo = AtomicI8::new(0); }; - { let foo = AtomicI16::new(0); }; - { let foo = AtomicI32::new(0); }; - { let foo = AtomicI64::new(0); }; - { let foo = AtomicUsize::new(0); }; - { let foo = AtomicU8::new(0); }; - { let foo = AtomicU16::new(0); }; - { let foo = AtomicU32::new(0); }; - { let foo = AtomicU64::new(0); }; - // Min - { let foo = isize::min_value(); }; - { let foo = i8::min_value(); }; - { let foo = i16::min_value(); }; - { let foo = i32::min_value(); }; - { let foo = i64::min_value(); }; - { let foo = i128::min_value(); }; - { let foo = usize::min_value(); }; - { let foo = u8::min_value(); }; - { let foo = u16::min_value(); }; - { let foo = u32::min_value(); }; - { let foo = u64::min_value(); }; - { let foo = u128::min_value(); }; - // Max - { let foo = isize::max_value(); }; - { let foo = i8::max_value(); }; - { let foo = i16::max_value(); }; - { let foo = i32::max_value(); }; - { let foo = i64::max_value(); }; - { let foo = i128::max_value(); }; - { let foo = usize::max_value(); }; - { let foo = u8::max_value(); }; - { let foo = u16::max_value(); }; - { let foo = u32::max_value(); }; - { let foo = u64::max_value(); }; - { let foo = u128::max_value(); }; - - let x = 42; - - let _ = match x { - std::i8::MIN => -1, - 1..=std::i8::MAX => 1, - _ => 0 - }; - - let _ = if let std::i8::MIN = x { - -1 - } else if let 1..=std::i8::MAX = x { - 1 - } else { - 0 - }; -} - -fn main() { - bad(); - good(); -} diff --git a/tests/ui/replace_consts.rs b/tests/ui/replace_consts.rs deleted file mode 100644 index dae3422a35f..00000000000 --- a/tests/ui/replace_consts.rs +++ /dev/null @@ -1,99 +0,0 @@ -// run-rustfix -#![feature(integer_atomics)] -#![allow(unused_variables, clippy::blacklisted_name)] -#![deny(clippy::replace_consts)] - -use std::sync::atomic::*; - -#[rustfmt::skip] -fn bad() { - // Min - { let foo = std::isize::MIN; }; - { let foo = std::i8::MIN; }; - { let foo = std::i16::MIN; }; - { let foo = std::i32::MIN; }; - { let foo = std::i64::MIN; }; - { let foo = std::i128::MIN; }; - { let foo = std::usize::MIN; }; - { let foo = std::u8::MIN; }; - { let foo = std::u16::MIN; }; - { let foo = std::u32::MIN; }; - { let foo = std::u64::MIN; }; - { let foo = std::u128::MIN; }; - // Max - { let foo = std::isize::MAX; }; - { let foo = std::i8::MAX; }; - { let foo = std::i16::MAX; }; - { let foo = std::i32::MAX; }; - { let foo = std::i64::MAX; }; - { let foo = std::i128::MAX; }; - { let foo = std::usize::MAX; }; - { let foo = std::u8::MAX; }; - { let foo = std::u16::MAX; }; - { let foo = std::u32::MAX; }; - { let foo = std::u64::MAX; }; - { let foo = std::u128::MAX; }; -} - -#[rustfmt::skip] -fn good() { - // Atomic - { let foo = AtomicBool::new(false); }; - { let foo = AtomicIsize::new(0); }; - { let foo = AtomicI8::new(0); }; - { let foo = AtomicI16::new(0); }; - { let foo = AtomicI32::new(0); }; - { let foo = AtomicI64::new(0); }; - { let foo = AtomicUsize::new(0); }; - { let foo = AtomicU8::new(0); }; - { let foo = AtomicU16::new(0); }; - { let foo = AtomicU32::new(0); }; - { let foo = AtomicU64::new(0); }; - // Min - { let foo = isize::min_value(); }; - { let foo = i8::min_value(); }; - { let foo = i16::min_value(); }; - { let foo = i32::min_value(); }; - { let foo = i64::min_value(); }; - { let foo = i128::min_value(); }; - { let foo = usize::min_value(); }; - { let foo = u8::min_value(); }; - { let foo = u16::min_value(); }; - { let foo = u32::min_value(); }; - { let foo = u64::min_value(); }; - { let foo = u128::min_value(); }; - // Max - { let foo = isize::max_value(); }; - { let foo = i8::max_value(); }; - { let foo = i16::max_value(); }; - { let foo = i32::max_value(); }; - { let foo = i64::max_value(); }; - { let foo = i128::max_value(); }; - { let foo = usize::max_value(); }; - { let foo = u8::max_value(); }; - { let foo = u16::max_value(); }; - { let foo = u32::max_value(); }; - { let foo = u64::max_value(); }; - { let foo = u128::max_value(); }; - - let x = 42; - - let _ = match x { - std::i8::MIN => -1, - 1..=std::i8::MAX => 1, - _ => 0 - }; - - let _ = if let std::i8::MIN = x { - -1 - } else if let 1..=std::i8::MAX = x { - 1 - } else { - 0 - }; -} - -fn main() { - bad(); - good(); -} diff --git a/tests/ui/replace_consts.stderr b/tests/ui/replace_consts.stderr deleted file mode 100644 index 458f63953ef..00000000000 --- a/tests/ui/replace_consts.stderr +++ /dev/null @@ -1,152 +0,0 @@ -error: using `MIN` - --> $DIR/replace_consts.rs:11:17 - | -LL | { let foo = std::isize::MIN; }; - | ^^^^^^^^^^^^^^^ help: try this: `isize::min_value()` - | -note: the lint level is defined here - --> $DIR/replace_consts.rs:4:9 - | -LL | #![deny(clippy::replace_consts)] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: using `MIN` - --> $DIR/replace_consts.rs:12:17 - | -LL | { let foo = std::i8::MIN; }; - | ^^^^^^^^^^^^ help: try this: `i8::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:13:17 - | -LL | { let foo = std::i16::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `i16::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:14:17 - | -LL | { let foo = std::i32::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `i32::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:15:17 - | -LL | { let foo = std::i64::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `i64::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:16:17 - | -LL | { let foo = std::i128::MIN; }; - | ^^^^^^^^^^^^^^ help: try this: `i128::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:17:17 - | -LL | { let foo = std::usize::MIN; }; - | ^^^^^^^^^^^^^^^ help: try this: `usize::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:18:17 - | -LL | { let foo = std::u8::MIN; }; - | ^^^^^^^^^^^^ help: try this: `u8::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:19:17 - | -LL | { let foo = std::u16::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `u16::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:20:17 - | -LL | { let foo = std::u32::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `u32::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:21:17 - | -LL | { let foo = std::u64::MIN; }; - | ^^^^^^^^^^^^^ help: try this: `u64::min_value()` - -error: using `MIN` - --> $DIR/replace_consts.rs:22:17 - | -LL | { let foo = std::u128::MIN; }; - | ^^^^^^^^^^^^^^ help: try this: `u128::min_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:24:17 - | -LL | { let foo = std::isize::MAX; }; - | ^^^^^^^^^^^^^^^ help: try this: `isize::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:25:17 - | -LL | { let foo = std::i8::MAX; }; - | ^^^^^^^^^^^^ help: try this: `i8::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:26:17 - | -LL | { let foo = std::i16::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `i16::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:27:17 - | -LL | { let foo = std::i32::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `i32::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:28:17 - | -LL | { let foo = std::i64::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `i64::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:29:17 - | -LL | { let foo = std::i128::MAX; }; - | ^^^^^^^^^^^^^^ help: try this: `i128::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:30:17 - | -LL | { let foo = std::usize::MAX; }; - | ^^^^^^^^^^^^^^^ help: try this: `usize::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:31:17 - | -LL | { let foo = std::u8::MAX; }; - | ^^^^^^^^^^^^ help: try this: `u8::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:32:17 - | -LL | { let foo = std::u16::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `u16::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:33:17 - | -LL | { let foo = std::u32::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `u32::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:34:17 - | -LL | { let foo = std::u64::MAX; }; - | ^^^^^^^^^^^^^ help: try this: `u64::max_value()` - -error: using `MAX` - --> $DIR/replace_consts.rs:35:17 - | -LL | { let foo = std::u128::MAX; }; - | ^^^^^^^^^^^^^^ help: try this: `u128::max_value()` - -error: aborting due to 24 previous errors - -- cgit 1.4.1-3-g733a5 From aff57e0f43855925eeb747963f6875335eba596b Mon Sep 17 00:00:00 2001 From: Matthias Krüger <matthias.krueger@famsik.de> Date: Mon, 30 Mar 2020 11:02:14 +0200 Subject: rustup https://github.com/rust-lang/rust/pull/70536 --- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/assign_ops.rs | 2 +- clippy_lints/src/atomic_ordering.rs | 2 +- clippy_lints/src/attrs.rs | 4 ++-- clippy_lints/src/block_in_if_condition.rs | 4 ++-- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/consts.rs | 10 +++++----- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/default_trait_access.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/doc.rs | 4 ++-- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_clike.rs | 6 +++--- clippy_lints/src/escape.rs | 6 +++--- clippy_lints/src/eta_reduction.rs | 4 ++-- clippy_lints/src/eval_order_dependence.rs | 4 ++-- clippy_lints/src/fallible_impl_from.rs | 4 ++-- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/functions.rs | 6 +++--- clippy_lints/src/identity_op.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 4 ++-- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/lib.rs | 6 +++--- clippy_lints/src/lifetimes.rs | 4 ++-- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops.rs | 8 ++++---- clippy_lints/src/map_clone.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/matches.rs | 4 ++-- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++--- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- clippy_lints/src/methods/unnecessary_filter_map.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/misc_early.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 6 +++--- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mut_mut.rs | 6 +++--- clippy_lints/src/mut_reference.rs | 4 ++-- clippy_lints/src/mutable_debug_assertion.rs | 4 ++-- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_borrow.rs | 4 ++-- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/new_without_default.rs | 4 ++-- clippy_lints/src/non_copy_const.rs | 4 ++-- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/redundant_clone.rs | 14 +++++++------- clippy_lints/src/returns.rs | 2 +- clippy_lints/src/shadow.rs | 4 ++-- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/transmuting_null.rs | 2 +- clippy_lints/src/trivially_copy_pass_by_ref.rs | 2 +- clippy_lints/src/try_err.rs | 4 ++-- clippy_lints/src/types.rs | 8 ++++---- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unwrap.rs | 4 ++-- clippy_lints/src/use_self.rs | 8 ++++---- clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/utils/higher.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 4 ++-- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/utils/mod.rs | 22 +++++++++++----------- clippy_lints/src/utils/ptr.rs | 2 +- clippy_lints/src/utils/usage.rs | 4 ++-- clippy_lints/src/vec.rs | 2 +- src/driver.rs | 6 +++--- tests/ui/auxiliary/proc_macro_derive.rs | 2 +- tests/ui/default_lint.rs | 2 +- tests/ui/lint_without_lint_pass.rs | 2 +- tests/ui/outer_expn_data.fixed | 2 +- tests/ui/outer_expn_data.rs | 2 +- tests/ui/useless_attribute.fixed | 2 +- tests/ui/useless_attribute.rs | 2 +- 97 files changed, 161 insertions(+), 161 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index 1ec3377193e..4d8bbcd3102 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -1,6 +1,6 @@ -use rustc::lint::in_external_macro; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index b6fb6fdd2cc..b66e8746707 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -3,11 +3,11 @@ use crate::utils::{ }; use crate::utils::{higher, sugg}; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index 871ca029b1a..d9ff1fe0a1d 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -1,9 +1,9 @@ use crate::utils::{match_def_path, span_lint_and_help}; use if_chain::if_chain; -use rustc::ty; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 35cde05e7f5..a406b141c36 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -6,8 +6,6 @@ use crate::utils::{ span_lint_and_then, without_block_comments, }; use if_chain::if_chain; -use rustc::lint::in_external_macro; -use rustc::ty; use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_errors::Applicability; @@ -15,6 +13,8 @@ use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, }; use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 1972c53d648..9e533eaa32c 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -1,10 +1,10 @@ use crate::utils::{differing_macro_contexts, higher, snippet_block_with_applicability, span_lint, span_lint_and_sugg}; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index b580240be17..7c9df141d66 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -3,12 +3,12 @@ use crate::utils::{ span_lint_and_then, SpanlessEq, }; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 9c06eb962d7..91d3e47d787 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -3,11 +3,11 @@ use crate::utils::{ span_lint_and_sugg, walk_ptrs_ty, }; use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast::{Name, UintTy}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 23992ae89a7..88baaea9e56 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,11 +1,11 @@ //! lint on manually implemented checked conversions that could be transformed into `try_from` use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index fcab4590188..b90dd28642b 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,10 +1,10 @@ //! calculate cognitive complexity and warn about overly complex functions -use rustc::hir::map::Map; use rustc_ast::ast::Attribute; use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::BytePos; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index fc26755a375..b1d540c9751 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -2,14 +2,14 @@ use crate::utils::{clip, higher, sext, unsext}; use if_chain::if_chain; -use rustc::ty::subst::{Subst, SubstsRef}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::{bug, span_bug}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::ty::subst::{Subst, SubstsRef}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; use std::convert::TryInto; @@ -333,7 +333,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { .tcx .const_eval_resolve(self.param_env, def_id, substs, None, None) .ok() - .map(|val| rustc::ty::Const::from_value(self.lcx.tcx, val, ty))?; + .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; let result = miri_to_const(&result); if result.is_some() { self.needed_resolution = true; @@ -460,7 +460,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { } pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> { - use rustc::mir::interpret::{ConstValue, Scalar}; + use rustc_middle::mir::interpret::{ConstValue, Scalar}; match result.val { ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => match result.ty.kind { ty::Bool => Some(Constant::Bool(d == 1)), diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 996f80a757e..383ee1164a2 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,9 +1,9 @@ use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_note, span_lint_and_then}; use crate::utils::{SpanlessEq, SpanlessHash}; -use rustc::ty::Ty; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index f99e6d96e03..635d609c382 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -1,8 +1,8 @@ use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{any_parent_is_automatically_derived, match_def_path, paths, span_lint_and_sugg}; diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index eaff716e145..a24cfa89ec2 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,9 +1,9 @@ use crate::utils::paths; use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; use rustc_hir::{Item, ItemKind, TraitRef}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 63b8d519c9d..e015b1b49c6 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,12 +1,12 @@ use crate::utils::{implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint}; use if_chain::if_chain; use itertools::Itertools; -use rustc::lint::in_external_macro; -use rustc::ty; use rustc_ast::ast::{AttrKind, Attribute}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, MultiSpan, Span}; use rustc_span::Pos; diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index bd9bdfef090..9a60b2f027a 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,8 +1,8 @@ use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_lint_and_note}; use if_chain::if_chain; -use rustc::ty; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index ccaa35350cc..fb10ca48074 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -1,8 +1,8 @@ //! Lint on if expressions with an else if, but without a final else branch. -use rustc::lint::in_external_macro; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 88647be0264..65c9d08a6bd 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -2,11 +2,11 @@ use crate::utils::SpanlessEq; use crate::utils::{get_item_name, higher, match_type, paths, snippet, snippet_opt}; use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty}; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 5bc8a446cf0..ace11073a8f 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -3,11 +3,11 @@ use crate::consts::{miri_to_const, Constant}; use crate::utils::span_lint; -use rustc::ty; -use rustc::ty::util::IntTypeExt; use rustc_ast::ast::{IntTy, UintTy}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_middle::ty::util::IntTypeExt; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::convert::TryFrom; @@ -51,7 +51,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { .tcx .const_eval_poly(def_id) .ok() - .map(|val| rustc::ty::Const::from_value(cx.tcx, val, ty)); + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { if let ty::Adt(adt, _) = ty.kind { if adt.is_enum() { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index db55e5ed141..94c458cc6a6 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,9 +1,9 @@ -use rustc::ty::layout::LayoutOf; -use rustc::ty::{self, Ty}; use rustc_hir::intravisit; use rustc_hir::{self, Body, FnDecl, HirId, HirIdSet, ItemKind, Node}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; @@ -92,7 +92,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal { } // TODO: Replace with Map::is_argument(..) when it's fixed -fn is_argument(map: rustc::hir::map::Map<'_>, id: HirId) -> bool { +fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { match map.find(id) { Some(Node::Binding(_)) => (), _ => return false, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index c84ea44901c..1a1a40902c2 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -1,9 +1,9 @@ use if_chain::if_chain; -use rustc::lint::in_external_macro; -use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{ diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 9cf0d3ba26f..48b761260a5 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -1,10 +1,10 @@ use crate::utils::{get_parent_expr, span_lint, span_lint_and_note}; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::ty; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 06608772c8a..d44481dd24a 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,10 +1,10 @@ use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT}; use crate::utils::{is_expn_of, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty}; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::ty::{self, Ty}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 55a9f61242b..79040ebf86d 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -1,10 +1,10 @@ use crate::utils::{numeric_literal, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::{f32, f64, fmt}; diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index cee14dc893b..86317fb8bd5 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -4,10 +4,10 @@ use crate::consts::{ }; use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 10bc2f12f25..30795f537ea 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -91,7 +91,7 @@ fn on_argumentv1_new<'a, 'tcx>( if pats.len() == 1; then { let ty = walk_ptrs_ty(cx.tables.pat_ty(&pats[0])); - if ty.kind != rustc::ty::Str && !match_type(cx, ty, &paths::STRING) { + if ty.kind != rustc_middle::ty::Str && !match_type(cx, ty, &paths::STRING) { return None; } if let ExprKind::Lit(ref lit) = format_args.kind { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index a05f911c4c5..8f5f82b0a2c 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,8 +1,8 @@ use crate::utils::{differing_macro_contexts, snippet_opt, span_lint_and_help, span_lint_and_note}; use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 697486c1af0..cf1b65a0166 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -3,9 +3,6 @@ use crate::utils::{ must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, }; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::ty::{self, Ty}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -13,6 +10,9 @@ use rustc_hir as hir; use rustc_hir::intravisit; use rustc_hir::{def::Res, def_id::DefId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index abd546870aa..088e4ab1921 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,6 +1,6 @@ -use rustc::ty; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 9b6e243f5f0..271df5b03e3 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,9 +1,9 @@ //! lint on if branches that could be swapped so no `!` operation is necessary //! on the condition -use rustc::lint::in_external_macro; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 65d2dd58106..a2b1085a36e 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -2,10 +2,10 @@ use crate::consts::{constant, Constant}; use crate::utils::{higher, span_lint, span_lint_and_help}; -use rustc::ty; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 39c8c4cfa69..429f7440510 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,10 +1,10 @@ //! lint when there is a large size difference between variants on an enum use crate::utils::{snippet_opt, span_lint_and_then}; -use rustc::ty::layout::LayoutOf; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index e08042bcbb2..f67fce9697a 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -1,7 +1,7 @@ -use rustc::mir::interpret::ConstValue; -use rustc::ty::{self, ConstKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir::interpret::ConstValue; +use rustc_middle::ty::{self, ConstKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use if_chain::if_chain; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 00cfb3b718d..a875e58775e 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,11 +1,11 @@ use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; -use rustc::ty; use rustc_ast::ast::{LitKind, Name}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{Span, Spanned}; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index d5343852208..dbf86ba3124 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,12 +1,12 @@ use crate::utils::{higher, qpath_res, snippet, span_lint_and_then}; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 5690a12141b..1f5a6b77ed3 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,7 +1,7 @@ use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_hir::{PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 704b46a87c9..73c05607b0f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -18,8 +18,6 @@ #[allow(unused_extern_crates)] extern crate fmt_macros; #[allow(unused_extern_crates)] -extern crate rustc; -#[allow(unused_extern_crates)] extern crate rustc_ast; #[allow(unused_extern_crates)] extern crate rustc_ast_pretty; @@ -44,6 +42,8 @@ extern crate rustc_lexer; #[allow(unused_extern_crates)] extern crate rustc_lint; #[allow(unused_extern_crates)] +extern crate rustc_middle; +#[allow(unused_extern_crates)] extern crate rustc_mir; #[allow(unused_extern_crates)] extern crate rustc_parse; @@ -82,7 +82,7 @@ use rustc_session::Session; /// ``` /// # #![feature(rustc_private)] /// # #[allow(unused_extern_crates)] -/// # extern crate rustc; +/// # extern crate rustc_middle; /// # #[allow(unused_extern_crates)] /// # extern crate rustc_session; /// # #[macro_use] diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 1cdc48957e7..8a23bedfdbe 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,5 +1,3 @@ -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{ @@ -12,6 +10,8 @@ use rustc_hir::{ TyKind, WhereClause, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 9e6b63fafd0..1b0b111bcfe 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -7,10 +7,10 @@ use crate::utils::{ snippet_opt, span_lint_and_sugg, }; use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2d477653e27..43217b6cc64 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -11,10 +11,6 @@ use crate::utils::{ use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg}; use if_chain::if_chain; use itertools::Itertools; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::middle::region; -use rustc::ty::{self, Ty}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -26,6 +22,10 @@ use rustc_hir::{ }; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::middle::region; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::{BytePos, Symbol}; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 72227555b25..58c94d7208d 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -3,11 +3,11 @@ use crate::utils::{ is_copy, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast::Ident; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index d7ea022d888..c5bb559e18e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,10 +1,10 @@ use crate::utils::paths; use crate::utils::{iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 8d4e8595b12..a124bf8b8db 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -9,8 +9,6 @@ use crate::utils::{ walk_ptrs_ty, }; use if_chain::if_chain; -use rustc::lint::in_external_macro; -use rustc::ty::{self, Ty}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; @@ -19,6 +17,8 @@ use rustc_hir::{ QPath, RangeEnd, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use std::cmp::Ordering; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index d2b1fd3a9e6..35b8842dc45 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -3,10 +3,10 @@ use crate::utils::{ span_lint_and_sugg, span_lint_and_then, }; use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 1079fbf63ea..495f42700ee 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,10 +1,10 @@ use super::INEFFICIENT_TO_STRING; use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty_depth}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn lint<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e6c6cb6f779..527508af8a3 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -8,14 +8,14 @@ use std::fmt; use std::iter; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::ty::{self, Predicate, Ty}; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Predicate, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol, SymbolStr}; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index c40ab7beba4..2fd4bb1db65 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,11 +1,11 @@ use crate::utils::{differing_macro_contexts, paths, snippet_with_applicability, span_lint_and_then}; use crate::utils::{is_copy, match_type}; -use rustc::hir::map::Map; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index ee6c6ef12e5..41c9ce7cda3 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,11 +1,11 @@ use crate::utils::paths; use crate::utils::usage::mutated_variables; use crate::utils::{match_qpath, match_trait_method, span_lint}; -use rustc::hir::map::Map; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; use if_chain::if_chain; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 6dbc33d8729..0dc55b7f7be 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,5 +1,4 @@ use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -8,6 +7,7 @@ use rustc_hir::{ TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{ExpnKind, Span}; diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 718ec1c00bb..b3244453d6b 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -3,7 +3,6 @@ use crate::utils::{ span_lint_and_then, }; use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast::{ BindingMode, Block, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, NodeId, Pat, PatKind, StmtKind, UnOp, @@ -12,6 +11,7 @@ use rustc_ast::visit::{walk_expr, FnKind, Visitor}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bd67302cbf4..0b235bdfe3c 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,9 +1,9 @@ use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method}; -use rustc::lint::in_external_macro; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index e03f9e36095..2eefb6bbaf4 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -7,11 +7,11 @@ use crate::utils::span_lint; use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_ast::attr; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 22b56c28b6b..9fc26047d88 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -81,7 +81,7 @@ declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item<'_>) { - if rustc::lint::in_external_macro(cx.sess(), it.span) || is_executable(cx) { + if rustc_middle::lint::in_external_macro(cx.sess(), it.span) || is_executable(cx) { return; } @@ -130,8 +130,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline { } fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - use rustc::ty::{ImplContainer, TraitContainer}; - if rustc::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable(cx) { + use rustc_middle::ty::{ImplContainer, TraitContainer}; + if rustc_middle::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable(cx) { return; } diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 7446b732c4b..b24d5c1fc8e 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -1,9 +1,9 @@ use crate::consts::{constant, Constant}; use crate::utils::{sext, span_lint_and_then}; use if_chain::if_chain; -use rustc::ty::{self}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index adaf82c7074..0b9b7e1b8cc 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,7 +1,7 @@ use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty}; -use rustc::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 70061f2aa83..f7a20a74b85 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -1,10 +1,10 @@ use crate::utils::{higher, span_lint}; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::ty; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 55cb7e4a087..e5680482e5b 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -1,8 +1,8 @@ use crate::utils::span_lint; -use rustc::ty::subst::Subst; -use rustc::ty::{self, Ty}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index c576fc2c197..80609d5cb1d 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -1,10 +1,10 @@ use crate::utils::{is_direct_expn_of, span_lint}; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::ty; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index bbd2e4d83fa..de8feee76ba 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -3,10 +3,10 @@ //! This lint is **warn** by default use crate::utils::{match_type, paths, span_lint}; -use rustc::ty::{self, Ty}; use rustc_ast::ast; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index dc37c7804fe..422254bb007 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -4,11 +4,11 @@ use crate::utils::{snippet_opt, span_lint_and_then}; use if_chain::if_chain; -use rustc::ty; -use rustc::ty::adjustment::{Adjust, Adjustment}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index dc18a745c26..c352f619927 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -4,7 +4,6 @@ use crate::utils::{ snippet, snippet_opt, span_lint_and_then, }; use if_chain::if_chain; -use rustc::ty::{self, TypeFoldable}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -12,6 +11,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, ItemKind, Node, PatKind, QPath, TyKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index e52b1cbf453..4b2586877e5 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -1,7 +1,7 @@ use crate::utils::span_lint; -use rustc::ty; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 2c4c29913cf..339c460bbd5 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -1,7 +1,7 @@ use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::{self, paths, span_lint}; diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index f69b145fa39..09f4cccf743 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -2,13 +2,13 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_hir_and_then}; use if_chain::if_chain; -use rustc::lint::in_external_macro; -use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 43d76d0cbbd..744cade461c 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -4,11 +4,11 @@ use std::ptr; -use rustc::ty::adjustment::Adjust; -use rustc::ty::{Ty, TypeFlags}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::{Ty, TypeFlags}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 3d420cf8cec..fd07df780e4 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -6,13 +6,13 @@ use crate::utils::{ walk_ptrs_hir_ty, }; use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir::{ BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::{MultiSpan, Symbol}; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 6921613894f..6bb11c8d9d7 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -3,17 +3,17 @@ use crate::utils::{ span_lint_hir_and_then, walk_ptrs_ty_depth, }; use if_chain::if_chain; -use rustc::mir::{ - self, traversal, - visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, -}; -use rustc::ty::{self, fold::TypeVisitor, Ty}; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{def_id, Body, FnDecl, HirId}; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir::{ + self, traversal, + visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, +}; +use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; use rustc_mir::dataflow::BottomValue; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -335,7 +335,7 @@ fn base_local_and_movability<'tcx>( mir: &mir::Body<'tcx>, place: mir::Place<'tcx>, ) -> Option<(mir::Local, CannotMoveOut)> { - use rustc::mir::PlaceRef; + use rustc_middle::mir::PlaceRef; // Dereference. You cannot move things out from a borrowed value. let mut deref = false; @@ -556,7 +556,7 @@ impl TypeVisitor<'_> for ContainsRegion { } fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { - use rustc::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use}; + use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use}; let mut visit_op = |op: &mir::Operand<'_>| match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local), diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index ef1bbfd8fa9..ef1a1d7ac29 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,9 +1,9 @@ use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast; use rustc_ast::visit::FnKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 0ada65ec785..9b5c3306f3a 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,13 +1,13 @@ use crate::reexport::Name; use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then}; -use rustc::lint::in_external_macro; -use rustc::ty; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 61dc7d1c9c5..b308692b849 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,12 +1,12 @@ use crate::utils::sugg::Sugg; use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq}; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index e777adb22cf..bb41e964d13 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,7 +1,7 @@ -use rustc::lint::in_external_macro; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index e39a7b5e2ab..89b57ed1a8d 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -1,9 +1,9 @@ use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method}; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index a909216dccc..e038c3785d5 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -4,10 +4,10 @@ use crate::utils::{ span_lint_and_then, walk_ptrs_ty, SpanlessEq, }; use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Symbol; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 5ec4a82b12e..c6302ca03d9 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -1,9 +1,9 @@ use crate::utils::{match_def_path, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 6dad9eef522..3220bd9b9e2 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -2,11 +2,11 @@ use crate::utils::{ is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then, sugg, }; use if_chain::if_chain; -use rustc::ty::{self, Ty}; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::borrow::Cow; diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 494dd448689..1d0332c5805 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,10 +1,10 @@ use crate::consts::{constant_context, Constant}; use crate::utils::{match_qpath, paths, span_lint}; use if_chain::if_chain; -use rustc::lint::in_external_macro; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 0f00ed6c1fa..52b07fb3401 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -2,12 +2,12 @@ use std::cmp; use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::ty; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::config::Config as SessionConfig; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index a6624408ce0..7018fa6804b 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,10 +1,10 @@ use crate::utils::{match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::lint::in_external_macro; -use rustc::ty::Ty; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index d466924dc68..4ff2947378f 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -5,10 +5,6 @@ use std::cmp::Ordering; use std::collections::BTreeMap; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::ty::layout::LayoutOf; -use rustc::ty::{self, InferTy, Ty, TyCtxt, TypeckTables}; use rustc_ast::ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -19,6 +15,10 @@ use rustc_hir::{ TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TypeckTables}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index a45b4a6869c..c12553312d8 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -1,9 +1,9 @@ use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; use rustc_hir::{AssocItemKind, HirId, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Path}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 767b48d4a09..a3f71be695b 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,10 +1,10 @@ use crate::utils::{higher::if_block, match_type, paths, span_lint_and_then, usage::is_potentially_mutated}; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 73a986b7901..4fcaf3cdb96 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,8 +1,4 @@ use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::lint::in_external_macro; -use rustc::ty; -use rustc::ty::{DefIdTree, Ty}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -12,6 +8,10 @@ use rustc_hir::{ TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; +use rustc_middle::ty::{DefIdTree, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 20f3929251c..0c8f06da9bb 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -2,7 +2,6 @@ //! to generate a clippy lint detecting said code automatically. use crate::utils::{get_attr, higher}; -use rustc::hir::map::Map; use rustc_ast::ast::{Attribute, LitFloatType, LitKind}; use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashMap; @@ -10,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; use rustc_session::Session; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index f27cc57fb54..7dfe666b18e 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -5,10 +5,10 @@ use crate::utils::{is_expn_of, match_def_path, match_qpath, paths}; use if_chain::if_chain; -use rustc::ty; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_middle::ty; /// Converts a hir binary operator to the corresponding `ast` type. #[must_use] diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 8f29b7e1336..02b721fd378 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -1,7 +1,5 @@ use crate::consts::{constant_context, constant_simple}; use crate::utils::differing_macro_contexts; -use rustc::ich::StableHashingContextProvider; -use rustc::ty::TypeckTables; use rustc_ast::ast::Name; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{ @@ -10,6 +8,8 @@ use rustc_hir::{ TyKind, TypeBinding, }; use rustc_lint::LateContext; +use rustc_middle::ich::StableHashingContextProvider; +use rustc_middle::ty::TypeckTables; use std::hash::Hash; /// Type used to check whether two ast are the same. This is different from the diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 7dbb0d5a9ab..bc2200800de 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -3,7 +3,6 @@ use crate::utils::{ walk_ptrs_ty, }; use if_chain::if_chain; -use rustc::hir::map::Map; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -13,6 +12,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Crate, Expr, ExprKind, HirId, Item, MutTy, Mutability, Path, Ty, TyKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::SymbolStr; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 871f7e6c31b..a2c6e0bbd24 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -25,14 +25,6 @@ use std::borrow::Cow; use std::mem; use if_chain::if_chain; -use rustc::hir::map::Map; -use rustc::traits; -use rustc::ty::{ - self, - layout::{self, IntegerExt}, - subst::GenericArg, - Binder, Ty, TyCtxt, TypeFoldable, -}; use rustc_ast::ast::{self, Attribute, LitKind}; use rustc_attr as attr; use rustc_errors::Applicability; @@ -47,6 +39,14 @@ use rustc_hir::{ }; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::traits; +use rustc_middle::ty::{ + self, + layout::{self, IntegerExt}, + subst::GenericArg, + Binder, Ty, TyCtxt, TypeFoldable, +}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; @@ -230,7 +230,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { /// } /// /// if match_path(ty_path, &["rustc", "lint", "Lint"]) { -/// // This is a `rustc::lint::Lint`. +/// // This is a `rustc_middle::lint::Lint`. /// } /// ``` pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { @@ -832,7 +832,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { /// Examples of coercions can be found in the Nomicon at /// <https://doc.rust-lang.org/nomicon/coercions.html>. /// -/// See `rustc::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more /// information on adjustments and coercions. pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool { cx.tables.adjustments().get(e.hir_id).is_some() @@ -1224,7 +1224,7 @@ pub fn match_function_call<'a, 'tcx>( /// to avoid crashes on `layout_of`. pub fn is_normalizable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { cx.tcx.infer_ctxt().enter(|infcx| { - let cause = rustc::traits::ObligationCause::dummy(); + let cause = rustc_middle::traits::ObligationCause::dummy(); infcx.at(&cause, param_env).normalize(&ty).is_ok() }) } diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs index 238c2277a93..240bf2449cb 100644 --- a/clippy_lints/src/utils/ptr.rs +++ b/clippy_lints/src/utils/ptr.rs @@ -1,9 +1,9 @@ use crate::utils::{get_pat_name, match_var, snippet}; -use rustc::hir::map::Map; use rustc_ast::ast::Name; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Body, BodyId, Expr, ExprKind, Param}; use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; use std::borrow::Cow; diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index a08251c1a4e..1838fa5f8ff 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -1,6 +1,4 @@ use crate::utils::match_var; -use rustc::hir::map::Map; -use rustc::ty; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::Res; @@ -8,6 +6,8 @@ use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Expr, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; +use rustc_middle::ty; use rustc_span::symbol::Ident; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 726a34856ae..1174f421577 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,10 +1,10 @@ use crate::consts::constant; use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc::ty::{self, Ty}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; diff --git a/src/driver.rs b/src/driver.rs index 7865f6bb9dd..2c699998ea9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -5,16 +5,16 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) #[allow(unused_extern_crates)] -extern crate rustc; -#[allow(unused_extern_crates)] extern crate rustc_driver; #[allow(unused_extern_crates)] extern crate rustc_errors; #[allow(unused_extern_crates)] extern crate rustc_interface; +#[allow(unused_extern_crates)] +extern crate rustc_middle; -use rustc::ty::TyCtxt; use rustc_interface::interface; +use rustc_middle::ty::TyCtxt; use rustc_tools_util::VersionInfo; use lazy_static::lazy_static; diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index f6d101a0911..21bb5b01e02 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -16,7 +16,7 @@ pub fn derive(_: TokenStream) -> TokenStream { let output = quote! { // Should not trigger `useless_attribute` #[allow(dead_code)] - extern crate rustc; + extern crate rustc_middle; }; output } diff --git a/tests/ui/default_lint.rs b/tests/ui/default_lint.rs index 0c6f29a43c6..053faae02ce 100644 --- a/tests/ui/default_lint.rs +++ b/tests/ui/default_lint.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #[macro_use] -extern crate rustc; +extern crate rustc_middle; #[macro_use] extern crate rustc_session; extern crate rustc_lint; diff --git a/tests/ui/lint_without_lint_pass.rs b/tests/ui/lint_without_lint_pass.rs index 8eb1f7b6461..beaef79a340 100644 --- a/tests/ui/lint_without_lint_pass.rs +++ b/tests/ui/lint_without_lint_pass.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #[macro_use] -extern crate rustc; +extern crate rustc_middle; #[macro_use] extern crate rustc_session; extern crate rustc_lint; diff --git a/tests/ui/outer_expn_data.fixed b/tests/ui/outer_expn_data.fixed index d1bb01ae87c..999a19b289e 100644 --- a/tests/ui/outer_expn_data.fixed +++ b/tests/ui/outer_expn_data.fixed @@ -3,9 +3,9 @@ #![deny(clippy::internal)] #![feature(rustc_private)] -extern crate rustc; extern crate rustc_hir; extern crate rustc_lint; +extern crate rustc_middle; #[macro_use] extern crate rustc_session; use rustc_hir::Expr; diff --git a/tests/ui/outer_expn_data.rs b/tests/ui/outer_expn_data.rs index 56a69982f26..5405d475d1a 100644 --- a/tests/ui/outer_expn_data.rs +++ b/tests/ui/outer_expn_data.rs @@ -3,9 +3,9 @@ #![deny(clippy::internal)] #![feature(rustc_private)] -extern crate rustc; extern crate rustc_hir; extern crate rustc_lint; +extern crate rustc_middle; #[macro_use] extern crate rustc_session; use rustc_hir::Expr; diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index ff626ab3ddf..b222e2f7976 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -11,7 +11,7 @@ #[allow(unused_imports)] #[allow(unused_extern_crates)] #[macro_use] -extern crate rustc; +extern crate rustc_middle; #[macro_use] extern crate proc_macro_derive; diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 822c6b6ea06..3422eace4ab 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -11,7 +11,7 @@ #[allow(unused_imports)] #[allow(unused_extern_crates)] #[macro_use] -extern crate rustc; +extern crate rustc_middle; #[macro_use] extern crate proc_macro_derive; -- cgit 1.4.1-3-g733a5 From b77b219280eb8e511f3ed28bf894ab09fdde1e03 Mon Sep 17 00:00:00 2001 From: Tomasz Miąsko <tomasz.miasko@gmail.com> Date: Thu, 12 Mar 2020 00:00:00 +0000 Subject: Lint unnamed address comparisons --- CHANGELOG.md | 2 + README.md | 2 +- clippy_lints/src/lib.rs | 8 ++ clippy_lints/src/unnamed_address.rs | 133 +++++++++++++++++++++++++++++ clippy_lints/src/utils/paths.rs | 3 + src/lintlist/mod.rs | 16 +++- tests/ui/fn_address_comparisons.rs | 20 +++++ tests/ui/fn_address_comparisons.stderr | 16 ++++ tests/ui/vtable_address_comparisons.rs | 42 +++++++++ tests/ui/vtable_address_comparisons.stderr | 83 ++++++++++++++++++ 10 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/unnamed_address.rs create mode 100644 tests/ui/fn_address_comparisons.rs create mode 100644 tests/ui/fn_address_comparisons.stderr create mode 100644 tests/ui/vtable_address_comparisons.rs create mode 100644 tests/ui/vtable_address_comparisons.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 81a1e276a88..f3b1073988b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1271,6 +1271,7 @@ Released 2018-09-13 [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation @@ -1540,6 +1541,7 @@ Released 2018-09-13 [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads +[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator diff --git a/README.md b/README.md index fefbb3486fd..856058e58b0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 363 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 73c05607b0f..5d5b5d9a6da 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -309,6 +309,7 @@ pub mod trivially_copy_pass_by_ref; pub mod try_err; pub mod types; pub mod unicode; +pub mod unnamed_address; pub mod unsafe_removed_from_name; pub mod unused_io_amount; pub mod unused_self; @@ -818,6 +819,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unicode::NON_ASCII_LITERAL, &unicode::UNICODE_NOT_NFC, &unicode::ZERO_WIDTH_SPACE, + &unnamed_address::FN_ADDRESS_COMPARISONS, + &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, @@ -1027,6 +1030,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box macro_use::MacroUseImports); store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); + store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1378,6 +1382,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1631,6 +1637,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::UNIT_CMP), LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), ]); diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs new file mode 100644 index 00000000000..b6473fc594e --- /dev/null +++ b/clippy_lints/src/unnamed_address.rs @@ -0,0 +1,133 @@ +use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for comparisons with an address of a function item. + /// + /// **Why is this bad?** Function item address is not guaranteed to be unique and could vary + /// between different code generation units. Furthermore different function items could have + /// the same address after being merged together. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// type F = fn(); + /// fn a() {} + /// let f: F = a; + /// if f == a { + /// // ... + /// } + /// ``` + pub FN_ADDRESS_COMPARISONS, + correctness, + "comparison with an address of a function item" +} + +declare_clippy_lint! { + /// **What it does:** Checks for comparisons with an address of a trait vtable. + /// + /// **Why is this bad?** Comparing trait objects pointers compares an vtable addresses which + /// are not guaranteed to be unique and could vary between different code generation units. + /// Furthermore vtables for different types could have the same address after being merged + /// together. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// let a: Rc<dyn Trait> = ... + /// let b: Rc<dyn Trait> = ... + /// if Rc::ptr_eq(&a, &b) { + /// ... + /// } + /// ``` + pub VTABLE_ADDRESS_COMPARISONS, + correctness, + "comparison with an address of a trait vtable" +} + +declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]); + +impl LateLintPass<'_, '_> for UnnamedAddress { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + fn is_comparison(binop: BinOpKind) -> bool { + match binop { + BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true, + _ => false, + } + } + + fn is_trait_ptr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + match cx.tables.expr_ty_adjusted(expr).kind { + ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(), + _ => false, + } + } + + fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + if let ty::FnDef(..) = cx.tables.expr_ty(expr).kind { + true + } else { + false + } + } + + if_chain! { + if let ExprKind::Binary(binop, ref left, ref right) = expr.kind; + if is_comparison(binop.node); + if is_trait_ptr(cx, left) && is_trait_ptr(cx, right); + then { + span_lint_and_help( + cx, + VTABLE_ADDRESS_COMPARISONS, + expr.span, + "comparing trait object pointers compares a non-unique vtable address", + "consider extracting and comparing data pointers only", + ); + } + } + + if_chain! { + if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::PTR_EQ) || + match_def_path(cx, def_id, &paths::RC_PTR_EQ) || + match_def_path(cx, def_id, &paths::ARC_PTR_EQ); + let ty_param = cx.tables.node_substs(func.hir_id).type_at(0); + if ty_param.is_trait(); + then { + span_lint_and_help( + cx, + VTABLE_ADDRESS_COMPARISONS, + expr.span, + "comparing trait object pointers compares a non-unique vtable address", + "consider extracting and comparing data pointers only", + ); + } + } + + if_chain! { + if let ExprKind::Binary(binop, ref left, ref right) = expr.kind; + if is_comparison(binop.node); + if cx.tables.expr_ty_adjusted(left).is_fn_ptr() && + cx.tables.expr_ty_adjusted(right).is_fn_ptr(); + if is_fn_def(cx, left) || is_fn_def(cx, right); + then { + span_lint( + cx, + FN_ADDRESS_COMPARISONS, + expr.span, + "comparing with a non-unique address of a function item", + ); + } + } + } +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 6cb1f694fd5..4a4ee5baf00 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -3,6 +3,7 @@ pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; pub const ARC: [&str; 3] = ["alloc", "sync", "Arc"]; +pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; @@ -74,6 +75,7 @@ pub const PATH: [&str; 3] = ["std", "path", "Path"]; pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; +pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 2] = ["ptr", "null"]; pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"]; pub const RANGE: [&str; 3] = ["core", "ops", "Range"]; @@ -90,6 +92,7 @@ pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"]; pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"]; pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; +pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"]; pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"]; pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5777e7d90e5..fa51af156ef 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 361] = [ +pub const ALL_LINTS: [Lint; 363] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -623,6 +623,13 @@ pub const ALL_LINTS: [Lint; 361] = [ deprecation: None, module: "misc", }, + Lint { + name: "fn_address_comparisons", + group: "correctness", + desc: "comparison with an address of a function item", + deprecation: None, + module: "unnamed_address", + }, Lint { name: "fn_params_excessive_bools", group: "pedantic", @@ -2408,6 +2415,13 @@ pub const ALL_LINTS: [Lint; 361] = [ deprecation: None, module: "verbose_file_reads", }, + Lint { + name: "vtable_address_comparisons", + group: "correctness", + desc: "comparison with an address of a trait vtable", + deprecation: None, + module: "unnamed_address", + }, Lint { name: "while_immutable_condition", group: "correctness", diff --git a/tests/ui/fn_address_comparisons.rs b/tests/ui/fn_address_comparisons.rs new file mode 100644 index 00000000000..362dcb4fd80 --- /dev/null +++ b/tests/ui/fn_address_comparisons.rs @@ -0,0 +1,20 @@ +use std::fmt::Debug; +use std::ptr; +use std::rc::Rc; +use std::sync::Arc; + +fn a() {} + +#[warn(clippy::fn_address_comparisons)] +fn main() { + type F = fn(); + let f: F = a; + let g: F = f; + + // These should fail: + let _ = f == a; + let _ = f != a; + + // These should be fine: + let _ = f == g; +} diff --git a/tests/ui/fn_address_comparisons.stderr b/tests/ui/fn_address_comparisons.stderr new file mode 100644 index 00000000000..9c1b5419a43 --- /dev/null +++ b/tests/ui/fn_address_comparisons.stderr @@ -0,0 +1,16 @@ +error: comparing with a non-unique address of a function item + --> $DIR/fn_address_comparisons.rs:15:13 + | +LL | let _ = f == a; + | ^^^^^^ + | + = note: `-D clippy::fn-address-comparisons` implied by `-D warnings` + +error: comparing with a non-unique address of a function item + --> $DIR/fn_address_comparisons.rs:16:13 + | +LL | let _ = f != a; + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/vtable_address_comparisons.rs b/tests/ui/vtable_address_comparisons.rs new file mode 100644 index 00000000000..c91d96ee18a --- /dev/null +++ b/tests/ui/vtable_address_comparisons.rs @@ -0,0 +1,42 @@ +use std::fmt::Debug; +use std::ptr; +use std::rc::Rc; +use std::sync::Arc; + +#[warn(clippy::vtable_address_comparisons)] +fn main() { + let a: *const dyn Debug = &1 as &dyn Debug; + let b: *const dyn Debug = &1 as &dyn Debug; + + // These should fail: + let _ = a == b; + let _ = a != b; + let _ = a < b; + let _ = a <= b; + let _ = a > b; + let _ = a >= b; + ptr::eq(a, b); + + let a = &1 as &dyn Debug; + let b = &1 as &dyn Debug; + ptr::eq(a, b); + + let a: Rc<dyn Debug> = Rc::new(1); + Rc::ptr_eq(&a, &a); + + let a: Arc<dyn Debug> = Arc::new(1); + Arc::ptr_eq(&a, &a); + + // These should be fine: + let a = &1; + ptr::eq(a, a); + + let a = Rc::new(1); + Rc::ptr_eq(&a, &a); + + let a = Arc::new(1); + Arc::ptr_eq(&a, &a); + + let a: &[u8] = b""; + ptr::eq(a, a); +} diff --git a/tests/ui/vtable_address_comparisons.stderr b/tests/ui/vtable_address_comparisons.stderr new file mode 100644 index 00000000000..76bd57217d7 --- /dev/null +++ b/tests/ui/vtable_address_comparisons.stderr @@ -0,0 +1,83 @@ +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:12:13 + | +LL | let _ = a == b; + | ^^^^^^ + | + = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings` + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:13:13 + | +LL | let _ = a != b; + | ^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:14:13 + | +LL | let _ = a < b; + | ^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:15:13 + | +LL | let _ = a <= b; + | ^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:16:13 + | +LL | let _ = a > b; + | ^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:17:13 + | +LL | let _ = a >= b; + | ^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:18:5 + | +LL | ptr::eq(a, b); + | ^^^^^^^^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:22:5 + | +LL | ptr::eq(a, b); + | ^^^^^^^^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:25:5 + | +LL | Rc::ptr_eq(&a, &a); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: comparing trait object pointers compares a non-unique vtable address + --> $DIR/vtable_address_comparisons.rs:28:5 + | +LL | Arc::ptr_eq(&a, &a); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider extracting and comparing data pointers only + +error: aborting due to 10 previous errors + -- cgit 1.4.1-3-g733a5 From 3155eedb68b4aaefe89731b3e1c788453cee1f80 Mon Sep 17 00:00:00 2001 From: flip1995 <hello@philkrones.com> Date: Tue, 31 Mar 2020 17:23:14 +0200 Subject: Don't use an exact lint counter anymore --- README.md | 2 +- clippy_dev/src/update_lints.rs | 25 ++++++++++++++----------- src/lintlist/mod.rs | 6 +++++- 3 files changed, 20 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 856058e58b0..eaa42aa6962 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 363 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 363 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index f6fc322431c..d30d6f97a2f 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -17,7 +17,7 @@ pub fn run(update_mode: UpdateMode) { let internal_lints = Lint::internal_lints(lint_list.clone().into_iter()); let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect(); - let usable_lint_count = usable_lints.len(); + let usable_lint_count = round_to_fifty(usable_lints.len()); let mut sorted_usable_lints = usable_lints.clone(); sorted_usable_lints.sort_by_key(|lint| lint.name.clone()); @@ -29,27 +29,26 @@ pub fn run(update_mode: UpdateMode) { false, update_mode == UpdateMode::Change, || { - format!( - "pub const ALL_LINTS: [Lint; {}] = {:#?};", - sorted_usable_lints.len(), - sorted_usable_lints - ) - .lines() - .map(ToString::to_string) - .collect::<Vec<_>>() + format!("pub static ref ALL_LINTS: Vec<Lint> = vec!{:#?};", sorted_usable_lints) + .lines() + .map(ToString::to_string) + .collect::<Vec<_>>() }, ) .changed; file_change |= replace_region_in_file( Path::new("README.md"), - &format!(r#"\[There are \d+ lints included in this crate!\]\({}\)"#, DOCS_LINK), + &format!( + r#"\[There are over \d+ lints included in this crate!\]\({}\)"#, + DOCS_LINK + ), "", true, update_mode == UpdateMode::Change, || { vec![format!( - "[There are {} lints included in this crate!]({})", + "[There are over {} lints included in this crate!]({})", usable_lint_count, DOCS_LINK )] }, @@ -161,3 +160,7 @@ pub fn print_lints() { println!("there are {} lints", usable_lint_count); } + +fn round_to_fifty(count: usize) -> usize { + count / 50 * 50 +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index fa51af156ef..3b89f5d1947 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1,12 +1,15 @@ //! This file is managed by `cargo dev update_lints`. Do not edit. +use lazy_static::lazy_static; + pub mod lint; pub use lint::Level; pub use lint::Lint; pub use lint::LINT_LEVELS; +lazy_static! { // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 363] = [ +pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2550,3 +2553,4 @@ pub const ALL_LINTS: [Lint; 363] = [ }, ]; // end lint list, do not remove this comment, it’s used in `update_lints` +} -- cgit 1.4.1-3-g733a5 From 86b0dd419752788c8e63313c9c3ae19d27b3e8e4 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Wed, 1 Apr 2020 12:00:49 -0700 Subject: Downgrade option_option to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/types.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5d5b5d9a6da..4235cd40a22 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1125,6 +1125,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_SIGN_LOSS), LintId::of(&types::INVALID_UPCAST_COMPARISONS), LintId::of(&types::LINKEDLIST), + LintId::of(&types::OPTION_OPTION), LintId::of(&unicode::NON_ASCII_LITERAL), LintId::of(&unicode::UNICODE_NOT_NFC), LintId::of(&unused_self::UNUSED_SELF), @@ -1375,7 +1376,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::LET_UNIT_VALUE), - LintId::of(&types::OPTION_OPTION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), LintId::of(&types::UNIT_CMP), @@ -1565,7 +1565,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::TRANSMUTE_PTR_TO_REF), LintId::of(&types::BORROWED_BOX), LintId::of(&types::CHAR_LIT_AS_U8), - LintId::of(&types::OPTION_OPTION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), LintId::of(&types::UNNECESSARY_CAST), diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 4ff2947378f..7fae477b832 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -108,7 +108,7 @@ declare_clippy_lint! { /// } /// ``` pub OPTION_OPTION, - complexity, + pedantic, "usage of `Option<Option<T>>`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 3b89f5d1947..9d135beae4f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1566,7 +1566,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "option_option", - group: "complexity", + group: "pedantic", desc: "usage of `Option<Option<T>>`", deprecation: None, module: "types", -- cgit 1.4.1-3-g733a5 From f8e892db5ecdc3bd684bddb109470987e422535a Mon Sep 17 00:00:00 2001 From: Jacek Pospychala <jacek.pospychala@gmail.com> Date: Thu, 12 Mar 2020 21:41:13 +0100 Subject: useless Rc<Rc<T>>, Rc<Box<T>>, Rc<&T>, Box<&T> --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/types.rs | 103 +++++++++++++++++++++++++++++++++-- clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 7 +++ tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/redundant_allocation.fixed | 48 ++++++++++++++++ tests/ui/redundant_allocation.rs | 48 ++++++++++++++++ tests/ui/redundant_allocation.stderr | 52 ++++++++++++++++++ 10 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 tests/ui/redundant_allocation.fixed create mode 100644 tests/ui/redundant_allocation.rs create mode 100644 tests/ui/redundant_allocation.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b1073988b..894aab21fb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1433,6 +1433,7 @@ Released 2018-09-13 [`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len +[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4235cd40a22..dfc2a26b06b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -811,6 +811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &types::LET_UNIT_VALUE, &types::LINKEDLIST, &types::OPTION_OPTION, + &types::REDUNDANT_ALLOCATION, &types::TYPE_COMPLEXITY, &types::UNIT_ARG, &types::UNIT_CMP, @@ -1376,6 +1377,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::LET_UNIT_VALUE), + LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), LintId::of(&types::UNIT_CMP), @@ -1660,6 +1662,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&types::BOX_VEC), + LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&vec::USELESS_VEC), ]); diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 7fae477b832..b21c3739265 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -171,11 +171,35 @@ declare_clippy_lint! { "a borrow of a boxed type" } +declare_clippy_lint! { + /// **What it does:** Checks for use of redundant allocations anywhere in the code. + /// + /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>` + /// add an unnecessary level of indirection. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # use std::rc::Rc; + /// fn foo(bar: Rc<&usize>) {} + /// ``` + /// + /// Better: + /// + /// ```rust + /// fn foo(bar: &usize) {} + /// ``` + pub REDUNDANT_ALLOCATION, + perf, + "redundant allocation" +} + pub struct Types { vec_box_size_threshold: u64, } -impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX]); +impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types { fn check_fn( @@ -217,7 +241,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types { } /// Checks if `qpath` has last segment with type parameter matching `path` -fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&str]) -> bool { +fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&str]) -> Option<Span> { let last = last_path_segment(qpath); if_chain! { if let Some(ref params) = last.args; @@ -230,10 +254,27 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id(); if match_def_path(cx, did, path); then { - return true; + return Some(ty.span); } } - false + None +} + +fn match_borrows_parameter(_cx: &LateContext<'_, '_>, qpath: &QPath<'_>) -> Option<Span> { + let last = last_path_segment(qpath); + if_chain! { + if let Some(ref params) = last.args; + if !params.parenthesized; + if let Some(ty) = params.args.iter().find_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }); + if let TyKind::Rptr(..) = ty.kind; + then { + return Some(ty.span); + } + } + None } impl Types { @@ -257,6 +298,7 @@ impl Types { /// The parameter `is_local` distinguishes the context of the type; types from /// local bindings should only be checked for the `BORROWED_BOX` lint. #[allow(clippy::too_many_lines)] + #[allow(clippy::cognitive_complexity)] fn check_ty(&mut self, cx: &LateContext<'_, '_>, hir_ty: &hir::Ty<'_>, is_local: bool) { if hir_ty.span.from_expansion() { return; @@ -267,7 +309,19 @@ impl Types { let res = qpath_res(cx, qpath, hir_id); if let Some(def_id) = res.opt_def_id() { if Some(def_id) == cx.tcx.lang_items().owned_box() { - if match_type_parameter(cx, qpath, &paths::VEC) { + if let Some(span) = match_borrows_parameter(cx, qpath) { + span_lint_and_sugg( + cx, + REDUNDANT_ALLOCATION, + hir_ty.span, + "usage of `Box<&T>`", + "try", + snippet(cx, span, "..").to_string(), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } + if match_type_parameter(cx, qpath, &paths::VEC).is_some() { span_lint_and_help( cx, BOX_VEC, @@ -277,6 +331,43 @@ impl Types { ); return; // don't recurse into the type } + } else if Some(def_id) == cx.tcx.lang_items().rc() { + if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) { + span_lint_and_sugg( + cx, + REDUNDANT_ALLOCATION, + hir_ty.span, + "usage of `Rc<Rc<T>>`", + "try", + snippet(cx, span, "..").to_string(), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } + if let Some(span) = match_type_parameter(cx, qpath, &paths::BOX) { + span_lint_and_sugg( + cx, + REDUNDANT_ALLOCATION, + hir_ty.span, + "usage of `Rc<Box<T>>`", + "try", + snippet(cx, span, "..").to_string(), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } + if let Some(span) = match_borrows_parameter(cx, qpath) { + span_lint_and_sugg( + cx, + REDUNDANT_ALLOCATION, + hir_ty.span, + "usage of `Rc<&T>`", + "try", + snippet(cx, span, "..").to_string(), + Applicability::MachineApplicable, + ); + return; // don't recurse into the type + } } else if cx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) { if_chain! { // Get the _ part of Vec<_> @@ -314,7 +405,7 @@ impl Types { } } } else if match_def_path(cx, def_id, &paths::OPTION) { - if match_type_parameter(cx, qpath, &paths::OPTION) { + if match_type_parameter(cx, qpath, &paths::OPTION).is_some() { span_lint( cx, OPTION_OPTION, diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index d443d63cc18..b79ba345df4 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -10,6 +10,7 @@ pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"]; pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"]; pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; +pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"]; pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"]; pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"]; pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9d135beae4f..8a6d0af5f8a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1725,6 +1725,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "ranges", }, + Lint { + name: "redundant_allocation", + group: "perf", + desc: "redundant allocation", + deprecation: None, + module: "types", + }, Lint { name: "redundant_clone", group: "perf", diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index e2ceb8baded..9556f6f82cc 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,6 +1,6 @@ // run-rustfix #![feature(never_type)] -#![allow(unused_mut)] +#![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 29ef8d1ed9c..37324220171 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,6 +1,6 @@ // run-rustfix #![feature(never_type)] -#![allow(unused_mut)] +#![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/redundant_allocation.fixed b/tests/ui/redundant_allocation.fixed new file mode 100644 index 00000000000..26635833458 --- /dev/null +++ b/tests/ui/redundant_allocation.fixed @@ -0,0 +1,48 @@ +// run-rustfix +#![warn(clippy::all)] +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] +#![allow(clippy::blacklisted_name, unused_variables, dead_code)] + +use std::boxed::Box; +use std::rc::Rc; + +pub struct MyStruct {} + +pub struct SubT<T> { + foo: T, +} + +pub enum MyEnum { + One, + Two, +} + +// Rc<&T> + +pub fn test1<T>(foo: &T) {} + +pub fn test2(foo: &MyStruct) {} + +pub fn test3(foo: &MyEnum) {} + +pub fn test4_neg(foo: Rc<SubT<&usize>>) {} + +// Rc<Rc<T>> + +pub fn test5(a: Rc<bool>) {} + +// Rc<Box<T>> + +pub fn test6(a: Box<bool>) {} + +// Box<&T> + +pub fn test7<T>(foo: &T) {} + +pub fn test8(foo: &MyStruct) {} + +pub fn test9(foo: &MyEnum) {} + +pub fn test10_neg(foo: Box<SubT<&usize>>) {} + +fn main() {} diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs new file mode 100644 index 00000000000..677b3e56d4d --- /dev/null +++ b/tests/ui/redundant_allocation.rs @@ -0,0 +1,48 @@ +// run-rustfix +#![warn(clippy::all)] +#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] +#![allow(clippy::blacklisted_name, unused_variables, dead_code)] + +use std::boxed::Box; +use std::rc::Rc; + +pub struct MyStruct {} + +pub struct SubT<T> { + foo: T, +} + +pub enum MyEnum { + One, + Two, +} + +// Rc<&T> + +pub fn test1<T>(foo: Rc<&T>) {} + +pub fn test2(foo: Rc<&MyStruct>) {} + +pub fn test3(foo: Rc<&MyEnum>) {} + +pub fn test4_neg(foo: Rc<SubT<&usize>>) {} + +// Rc<Rc<T>> + +pub fn test5(a: Rc<Rc<bool>>) {} + +// Rc<Box<T>> + +pub fn test6(a: Rc<Box<bool>>) {} + +// Box<&T> + +pub fn test7<T>(foo: Box<&T>) {} + +pub fn test8(foo: Box<&MyStruct>) {} + +pub fn test9(foo: Box<&MyEnum>) {} + +pub fn test10_neg(foo: Box<SubT<&usize>>) {} + +fn main() {} diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr new file mode 100644 index 00000000000..eaa57ce3024 --- /dev/null +++ b/tests/ui/redundant_allocation.stderr @@ -0,0 +1,52 @@ +error: usage of `Rc<&T>` + --> $DIR/redundant_allocation.rs:22:22 + | +LL | pub fn test1<T>(foo: Rc<&T>) {} + | ^^^^^^ help: try: `&T` + | + = note: `-D clippy::redundant-allocation` implied by `-D warnings` + +error: usage of `Rc<&T>` + --> $DIR/redundant_allocation.rs:24:19 + | +LL | pub fn test2(foo: Rc<&MyStruct>) {} + | ^^^^^^^^^^^^^ help: try: `&MyStruct` + +error: usage of `Rc<&T>` + --> $DIR/redundant_allocation.rs:26:19 + | +LL | pub fn test3(foo: Rc<&MyEnum>) {} + | ^^^^^^^^^^^ help: try: `&MyEnum` + +error: usage of `Rc<Rc<T>>` + --> $DIR/redundant_allocation.rs:32:17 + | +LL | pub fn test5(a: Rc<Rc<bool>>) {} + | ^^^^^^^^^^^^ help: try: `Rc<bool>` + +error: usage of `Rc<Box<T>>` + --> $DIR/redundant_allocation.rs:36:17 + | +LL | pub fn test6(a: Rc<Box<bool>>) {} + | ^^^^^^^^^^^^^ help: try: `Box<bool>` + +error: usage of `Box<&T>` + --> $DIR/redundant_allocation.rs:40:22 + | +LL | pub fn test7<T>(foo: Box<&T>) {} + | ^^^^^^^ help: try: `&T` + +error: usage of `Box<&T>` + --> $DIR/redundant_allocation.rs:42:19 + | +LL | pub fn test8(foo: Box<&MyStruct>) {} + | ^^^^^^^^^^^^^^ help: try: `&MyStruct` + +error: usage of `Box<&T>` + --> $DIR/redundant_allocation.rs:44:19 + | +LL | pub fn test9(foo: Box<&MyEnum>) {} + | ^^^^^^^^^^^^ help: try: `&MyEnum` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From adcaa1b86ddbf51659d5f7e4e7471427682649ba Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Thu, 2 Apr 2020 18:22:18 -0700 Subject: Downgrade let_unit_value to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/types.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/doc_unsafe.rs | 1 - tests/ui/redundant_pattern_matching.fixed | 2 +- tests/ui/redundant_pattern_matching.rs | 2 +- tests/ui/uninit.rs | 1 - tests/ui/uninit.stderr | 4 ++-- 8 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..84b89311fa0 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1125,6 +1125,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_PRECISION_LOSS), LintId::of(&types::CAST_SIGN_LOSS), LintId::of(&types::INVALID_UPCAST_COMPARISONS), + LintId::of(&types::LET_UNIT_VALUE), LintId::of(&types::LINKEDLIST), LintId::of(&types::OPTION_OPTION), LintId::of(&unicode::NON_ASCII_LITERAL), @@ -1376,7 +1377,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&types::IMPLICIT_HASHER), - LintId::of(&types::LET_UNIT_VALUE), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), @@ -1489,7 +1489,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(&types::IMPLICIT_HASHER), - LintId::of(&types::LET_UNIT_VALUE), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 8c151f2277c..171852d41e3 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -593,7 +593,7 @@ declare_clippy_lint! { /// }; /// ``` pub LET_UNIT_VALUE, - style, + pedantic, "creating a `let` binding to a value of unit type, which usually can't be used afterwards" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..79e337f5530 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -999,7 +999,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "let_unit_value", - group: "style", + group: "pedantic", desc: "creating a `let` binding to a value of unit type, which usually can\'t be used afterwards", deprecation: None, module: "types", diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index c44f3c62a98..484aa72d59a 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -88,7 +88,6 @@ very_unsafe!(); // we don't lint code from external macros undocd_unsafe!(); -#[allow(clippy::let_unit_value)] fn main() { unsafe { you_dont_see_me(); diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 776c9444566..538fa1ed9cb 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, clippy::let_unit_value, unused_must_use)] +#![allow(clippy::unit_arg, unused_must_use)] fn main() { Ok::<i32, i32>(42).is_ok(); diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 2b2d5b1c1ec..34d2cd62e54 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, clippy::let_unit_value, unused_must_use)] +#![allow(clippy::unit_arg, unused_must_use)] fn main() { if let Ok(_) = Ok::<i32, i32>(42) {} diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index a4424c490e7..f42b884e0f0 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -2,7 +2,6 @@ use std::mem::MaybeUninit; -#[allow(clippy::let_unit_value)] fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index f4c45354aef..a37233ecdda 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -1,5 +1,5 @@ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:7:29 + --> $DIR/uninit.rs:6:29 | LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; = note: `#[deny(clippy::uninit_assumed_init)]` on by default error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:10:31 + --> $DIR/uninit.rs:9:31 | LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 94154cad20d4687461fcbb4901a1252576329d13 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Thu, 2 Apr 2020 18:46:01 -0700 Subject: Downgrade trivially_copy_pass_by_ref to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/trivially_copy_pass_by_ref.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui-toml/toml_trivially_copy/test.rs | 1 + tests/ui-toml/toml_trivially_copy/test.stderr | 10 ++++--- tests/ui/clone_on_copy_mut.rs | 1 - tests/ui/debug_assert_with_mut_call.rs | 2 +- tests/ui/eta.fixed | 3 +-- tests/ui/eta.rs | 3 +-- tests/ui/eta.stderr | 24 ++++++++--------- tests/ui/extra_unused_lifetimes.rs | 3 +-- tests/ui/extra_unused_lifetimes.stderr | 8 +++--- tests/ui/float_arithmetic.rs | 3 +-- tests/ui/float_arithmetic.stderr | 34 ++++++++++++------------ tests/ui/infinite_iter.rs | 1 - tests/ui/infinite_iter.stderr | 32 +++++++++++------------ tests/ui/infinite_loop.rs | 2 -- tests/ui/infinite_loop.stderr | 22 ++++++++-------- tests/ui/integer_arithmetic.rs | 3 +-- tests/ui/integer_arithmetic.stderr | 34 ++++++++++++------------ tests/ui/mut_from_ref.rs | 2 +- tests/ui/mut_reference.rs | 2 +- tests/ui/needless_borrow.fixed | 1 - tests/ui/needless_borrow.rs | 1 - tests/ui/needless_borrow.stderr | 8 +++--- tests/ui/needless_lifetimes.rs | 2 +- tests/ui/new_ret_no_self.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 1 + tests/ui/trivially_copy_pass_by_ref.stderr | 36 ++++++++++++++------------ tests/ui/useless_asref.fixed | 1 - tests/ui/useless_asref.rs | 1 - tests/ui/useless_asref.stderr | 22 ++++++++-------- tests/ui/wrong_self_convention.rs | 2 +- 33 files changed, 135 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..ece9efded46 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1119,6 +1119,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS), + LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&types::CAST_LOSSLESS), LintId::of(&types::CAST_POSSIBLE_TRUNCATION), LintId::of(&types::CAST_POSSIBLE_WRAP), @@ -1365,7 +1366,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), - LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&try_err::TRY_ERR), LintId::of(&types::ABSURD_EXTREME_COMPARISONS), LintId::of(&types::BORROWED_BOX), @@ -1660,7 +1660,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mutex_atomic::MUTEX_ATOMIC), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&types::BOX_VEC), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&vec::USELESS_VEC), diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 52b07fb3401..2c101220c5d 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { /// fn foo(v: u32) {} /// ``` pub TRIVIALLY_COPY_PASS_BY_REF, - perf, + pedantic, "functions taking small copyable arguments by reference" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..62e7fe42110 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2161,7 +2161,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "trivially_copy_pass_by_ref", - group: "perf", + group: "pedantic", desc: "functions taking small copyable arguments by reference", deprecation: None, module: "trivially_copy_pass_by_ref", diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index 6dcbae04075..19019a25416 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,6 +1,7 @@ // normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +#![deny(clippy::trivially_copy_pass_by_ref)] #![allow(clippy::many_single_char_names)] #[derive(Copy, Clone)] diff --git a/tests/ui-toml/toml_trivially_copy/test.stderr b/tests/ui-toml/toml_trivially_copy/test.stderr index d2b55eff16d..912761a8f00 100644 --- a/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/tests/ui-toml/toml_trivially_copy/test.stderr @@ -1,13 +1,17 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:14:11 + --> $DIR/test.rs:15:11 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` | - = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/test.rs:4:9 + | +LL | #![deny(clippy::trivially_copy_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:14:20 + --> $DIR/test.rs:15:20 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `Foo` diff --git a/tests/ui/clone_on_copy_mut.rs b/tests/ui/clone_on_copy_mut.rs index 3cbbcb7c083..5bfa256623b 100644 --- a/tests/ui/clone_on_copy_mut.rs +++ b/tests/ui/clone_on_copy_mut.rs @@ -5,7 +5,6 @@ pub fn dec_read_dec(i: &mut i32) -> i32 { ret } -#[allow(clippy::trivially_copy_pass_by_ref)] pub fn minus_1(i: &i32) -> i32 { dec_read_dec(&mut i.clone()) } diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs index 3db7e0164fa..b061fff6b9e 100644 --- a/tests/ui/debug_assert_with_mut_call.rs +++ b/tests/ui/debug_assert_with_mut_call.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![rustfmt::skip] #![warn(clippy::debug_assert_with_mut_call)] -#![allow(clippy::trivially_copy_pass_by_ref, clippy::cognitive_complexity, clippy::redundant_closure_call)] +#![allow(clippy::cognitive_complexity, clippy::redundant_closure_call)] struct S; diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index 5d62a6d9b01..1b34c2f74eb 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -6,8 +6,7 @@ clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, - clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref + clippy::option_map_unit_fn )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index a9c4b209960..4f050bd8479 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -6,8 +6,7 @@ clippy::redundant_closure_call, clippy::many_single_char_names, clippy::needless_pass_by_value, - clippy::option_map_unit_fn, - clippy::trivially_copy_pass_by_ref + clippy::option_map_unit_fn )] #![warn( clippy::redundant_closure, diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index d19d21eec0d..c4713ca8083 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure found - --> $DIR/eta.rs:21:27 + --> $DIR/eta.rs:20:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` @@ -7,13 +7,13 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:22:10 + --> $DIR/eta.rs:21:10 | LL | meta(|a| foo(a)); | ^^^^^^^^^^ help: remove closure as shown: `foo` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/eta.rs:25:21 + --> $DIR/eta.rs:24:21 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^ help: change this to: `&2` @@ -21,13 +21,13 @@ LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted = note: `-D clippy::needless-borrow` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:32:27 + --> $DIR/eta.rs:31:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` error: redundant closure found - --> $DIR/eta.rs:75:51 + --> $DIR/eta.rs:74:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: remove closure as shown: `TestStruct::foo` @@ -35,43 +35,43 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure found - --> $DIR/eta.rs:77:51 + --> $DIR/eta.rs:76:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `TestTrait::trait_foo` error: redundant closure found - --> $DIR/eta.rs:80:42 + --> $DIR/eta.rs:79:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: remove closure as shown: `std::vec::Vec::clear` error: redundant closure found - --> $DIR/eta.rs:85:29 + --> $DIR/eta.rs:84:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string` error: redundant closure found - --> $DIR/eta.rs:87:27 + --> $DIR/eta.rs:86:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_uppercase` error: redundant closure found - --> $DIR/eta.rs:90:65 + --> $DIR/eta.rs:89:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase` error: redundant closure found - --> $DIR/eta.rs:173:27 + --> $DIR/eta.rs:172:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `foo_ptr` error: redundant closure found - --> $DIR/eta.rs:178:27 + --> $DIR/eta.rs:177:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `closure` diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index ba95fd63bf9..26df71ddcb0 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -2,8 +2,7 @@ unused, dead_code, clippy::needless_lifetimes, - clippy::needless_pass_by_value, - clippy::trivially_copy_pass_by_ref + clippy::needless_pass_by_value )] #![warn(clippy::extra_unused_lifetimes)] diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr index ebdb8e74952..e997951346f 100644 --- a/tests/ui/extra_unused_lifetimes.stderr +++ b/tests/ui/extra_unused_lifetimes.stderr @@ -1,5 +1,5 @@ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:14:14 + --> $DIR/extra_unused_lifetimes.rs:13:14 | LL | fn unused_lt<'a>(x: u8) {} | ^^ @@ -7,19 +7,19 @@ LL | fn unused_lt<'a>(x: u8) {} = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:16:25 + --> $DIR/extra_unused_lifetimes.rs:15:25 | LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:41:10 + --> $DIR/extra_unused_lifetimes.rs:40:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:67:22 + --> $DIR/extra_unused_lifetimes.rs:66:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ diff --git a/tests/ui/float_arithmetic.rs b/tests/ui/float_arithmetic.rs index 5ad320c6209..60fa7569eb9 100644 --- a/tests/ui/float_arithmetic.rs +++ b/tests/ui/float_arithmetic.rs @@ -5,8 +5,7 @@ clippy::shadow_unrelated, clippy::no_effect, clippy::unnecessary_operation, - clippy::op_ref, - clippy::trivially_copy_pass_by_ref + clippy::op_ref )] #[rustfmt::skip] diff --git a/tests/ui/float_arithmetic.stderr b/tests/ui/float_arithmetic.stderr index 809392529fd..1ceffb35bee 100644 --- a/tests/ui/float_arithmetic.stderr +++ b/tests/ui/float_arithmetic.stderr @@ -1,5 +1,5 @@ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:16:5 + --> $DIR/float_arithmetic.rs:15:5 | LL | f * 2.0; | ^^^^^^^ @@ -7,97 +7,97 @@ LL | f * 2.0; = note: `-D clippy::float-arithmetic` implied by `-D warnings` error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:18:5 + --> $DIR/float_arithmetic.rs:17:5 | LL | 1.0 + f; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:19:5 + --> $DIR/float_arithmetic.rs:18:5 | LL | f * 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:20:5 + --> $DIR/float_arithmetic.rs:19:5 | LL | f / 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:21:5 + --> $DIR/float_arithmetic.rs:20:5 | LL | f - 2.0 * 4.2; | ^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:22:5 + --> $DIR/float_arithmetic.rs:21:5 | LL | -f; | ^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:24:5 + --> $DIR/float_arithmetic.rs:23:5 | LL | f += 1.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:25:5 + --> $DIR/float_arithmetic.rs:24:5 | LL | f -= 1.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:26:5 + --> $DIR/float_arithmetic.rs:25:5 | LL | f *= 2.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:27:5 + --> $DIR/float_arithmetic.rs:26:5 | LL | f /= 2.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:33:5 + --> $DIR/float_arithmetic.rs:32:5 | LL | 3.1_f32 + &1.2_f32; | ^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:34:5 + --> $DIR/float_arithmetic.rs:33:5 | LL | &3.4_f32 + 1.5_f32; | ^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:35:5 + --> $DIR/float_arithmetic.rs:34:5 | LL | &3.5_f32 + &1.3_f32; | ^^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:40:5 + --> $DIR/float_arithmetic.rs:39:5 | LL | a + f | ^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:44:5 + --> $DIR/float_arithmetic.rs:43:5 | LL | f1 + f2 | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:48:5 + --> $DIR/float_arithmetic.rs:47:5 | LL | f1 + f2 | ^^^^^^^ error: floating-point arithmetic detected - --> $DIR/float_arithmetic.rs:52:5 + --> $DIR/float_arithmetic.rs:51:5 | LL | (&f1 + &f2) | ^^^^^^^^^^^ diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index c324eb95777..1fe68897765 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,5 +1,4 @@ use std::iter::repeat; -#[allow(clippy::trivially_copy_pass_by_ref)] fn square_is_lower_64(x: &u32) -> bool { x * x < 64 } diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index 4750316d3f4..5f5e7ac9f25 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,29 +1,29 @@ error: infinite iteration detected - --> $DIR/infinite_iter.rs:10:5 + --> $DIR/infinite_iter.rs:9:5 | LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/infinite_iter.rs:8:8 + --> $DIR/infinite_iter.rs:7:8 | LL | #[deny(clippy::infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:11:5 + --> $DIR/infinite_iter.rs:10:5 | LL | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:12:5 + --> $DIR/infinite_iter.rs:11:5 | LL | (0..8_u64).chain(0..).max(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:17:5 + --> $DIR/infinite_iter.rs:16:5 | LL | / (0..8_u32) LL | | .rev() @@ -33,37 +33,37 @@ LL | | .for_each(|x| println!("{}", x)); // infinite iter | |________________________________________^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:23:5 + --> $DIR/infinite_iter.rs:22:5 | LL | (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:24:5 + --> $DIR/infinite_iter.rs:23:5 | LL | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:31:5 + --> $DIR/infinite_iter.rs:30:5 | LL | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/infinite_iter.rs:29:8 + --> $DIR/infinite_iter.rs:28:8 | LL | #[deny(clippy::maybe_infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:32:5 + --> $DIR/infinite_iter.rs:31:5 | LL | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:33:5 + --> $DIR/infinite_iter.rs:32:5 | LL | / (1..) LL | | .scan(0, |state, x| { @@ -74,31 +74,31 @@ LL | | .min(); // maybe infinite iter | |______________^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:39:5 + --> $DIR/infinite_iter.rs:38:5 | LL | (0..).find(|x| *x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:40:5 + --> $DIR/infinite_iter.rs:39:5 | LL | (0..).position(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:41:5 + --> $DIR/infinite_iter.rs:40:5 | LL | (0..).any(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:42:5 + --> $DIR/infinite_iter.rs:41:5 | LL | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:65:31 + --> $DIR/infinite_iter.rs:64:31 | LL | let _: HashSet<i32> = (0..).collect(); // Infinite iter | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 09f47adc46e..72591f12baf 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -1,5 +1,3 @@ -#![allow(clippy::trivially_copy_pass_by_ref)] - fn fn_val(i: i32) -> i32 { unimplemented!() } diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 2736753c14b..1fcb29eff18 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:23:11 + --> $DIR/infinite_loop.rs:21:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ LL | while y < 10 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:28:11 + --> $DIR/infinite_loop.rs:26:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:35:11 + --> $DIR/infinite_loop.rs:33:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ LL | while !cond { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:79:11 + --> $DIR/infinite_loop.rs:77:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:84:11 + --> $DIR/infinite_loop.rs:82:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:88:11 + --> $DIR/infinite_loop.rs:86:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:103:11 + --> $DIR/infinite_loop.rs:101:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:108:11 + --> $DIR/infinite_loop.rs:106:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:174:15 + --> $DIR/infinite_loop.rs:172:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | while self.count < n { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:182:11 + --> $DIR/infinite_loop.rs:180:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ LL | while y < 10 { = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:189:11 + --> $DIR/infinite_loop.rs:187:11 | LL | while y < 10 { | ^^^^^^ diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index 31a07e7c35b..2fe32c6ace8 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -5,8 +5,7 @@ clippy::shadow_unrelated, clippy::no_effect, clippy::unnecessary_operation, - clippy::op_ref, - clippy::trivially_copy_pass_by_ref + clippy::op_ref )] #[rustfmt::skip] diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr index 0b8d0b767bf..64c44d7ecc7 100644 --- a/tests/ui/integer_arithmetic.stderr +++ b/tests/ui/integer_arithmetic.stderr @@ -1,5 +1,5 @@ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:15:5 + --> $DIR/integer_arithmetic.rs:14:5 | LL | 1 + i; | ^^^^^ @@ -7,98 +7,98 @@ LL | 1 + i; = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 + --> $DIR/integer_arithmetic.rs:15:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:17:5 + --> $DIR/integer_arithmetic.rs:16:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line | |_________^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:19:5 + --> $DIR/integer_arithmetic.rs:18:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 + --> $DIR/integer_arithmetic.rs:19:5 | LL | -i; | ^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:32:5 + --> $DIR/integer_arithmetic.rs:31:5 | LL | i += 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 + --> $DIR/integer_arithmetic.rs:32:5 | LL | i -= 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 + --> $DIR/integer_arithmetic.rs:33:5 | LL | i *= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 + --> $DIR/integer_arithmetic.rs:34:5 | LL | i /= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:36:5 + --> $DIR/integer_arithmetic.rs:35:5 | LL | i %= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:82:5 + --> $DIR/integer_arithmetic.rs:81:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:83:5 + --> $DIR/integer_arithmetic.rs:82:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:84:5 + --> $DIR/integer_arithmetic.rs:83:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 + --> $DIR/integer_arithmetic.rs:88:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:93:5 + --> $DIR/integer_arithmetic.rs:92:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:97:5 + --> $DIR/integer_arithmetic.rs:96:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:101:5 + --> $DIR/integer_arithmetic.rs:100:5 | LL | (&x + &y) | ^^^^^^^^^ diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 8f9ed7ed637..a9a04c8f56b 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::trivially_copy_pass_by_ref)] +#![allow(unused)] #![warn(clippy::mut_from_ref)] struct Foo; diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index c4379e0ea1c..73906121c40 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::trivially_copy_pass_by_ref)] +#![allow(unused_variables)] fn takes_an_immutable_reference(a: &i32) {} fn takes_a_mutable_reference(a: &mut i32) {} diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 50f9b7c7ba6..5ae4a0e79b9 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -2,7 +2,6 @@ #![allow(clippy::needless_borrowed_reference)] -#[allow(clippy::trivially_copy_pass_by_ref)] fn x(y: &i32) -> i32 { *y } diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 8677b957e4c..1e281316c8a 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -2,7 +2,6 @@ #![allow(clippy::needless_borrowed_reference)] -#[allow(clippy::trivially_copy_pass_by_ref)] fn x(y: &i32) -> i32 { *y } diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 49df9cd072b..0bfeda7914d 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:15:15 + --> $DIR/needless_borrow.rs:14:15 | LL | let c = x(&&a); | ^^^ help: change this to: `&a` @@ -7,19 +7,19 @@ LL | let c = x(&&a); = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:22:17 + --> $DIR/needless_borrow.rs:21:17 | LL | if let Some(ref cake) = Some(&5) {} | ^^^^^^^^ help: change this to: `cake` error: this expression borrows a reference that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:29:15 + --> $DIR/needless_borrow.rs:28:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:52:31 + --> $DIR/needless_borrow.rs:51:31 | LL | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^ help: change this to: `a` diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index f3fdd48633f..913cd004f19 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code, clippy::needless_pass_by_value)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index a31f046c084..35aaecc9ac4 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -1,5 +1,5 @@ #![warn(clippy::new_ret_no_self)] -#![allow(dead_code, clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] fn main() {} diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index bd23aa99ceb..316426f1cf1 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,6 +1,7 @@ // normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +#![deny(clippy::trivially_copy_pass_by_ref)] #![allow( clippy::many_single_char_names, clippy::blacklisted_name, diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 1addc3d7195..be0914e4a79 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,91 +1,95 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:11 + --> $DIR/trivially_copy_pass_by_ref.rs:51:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` | - = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/trivially_copy_pass_by_ref.rs:4:9 + | +LL | #![deny(clippy::trivially_copy_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:20 + --> $DIR/trivially_copy_pass_by_ref.rs:51:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:50:29 + --> $DIR/trivially_copy_pass_by_ref.rs:51:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:12 + --> $DIR/trivially_copy_pass_by_ref.rs:58:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:22 + --> $DIR/trivially_copy_pass_by_ref.rs:58:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:31 + --> $DIR/trivially_copy_pass_by_ref.rs:58:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:57:40 + --> $DIR/trivially_copy_pass_by_ref.rs:58:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:16 + --> $DIR/trivially_copy_pass_by_ref.rs:60:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:25 + --> $DIR/trivially_copy_pass_by_ref.rs:60:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:59:34 + --> $DIR/trivially_copy_pass_by_ref.rs:60:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:16 + --> $DIR/trivially_copy_pass_by_ref.rs:72:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:25 + --> $DIR/trivially_copy_pass_by_ref.rs:72:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:71:34 + --> $DIR/trivially_copy_pass_by_ref.rs:72:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:75:34 + --> $DIR/trivially_copy_pass_by_ref.rs:76:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:79:37 + --> $DIR/trivially_copy_pass_by_ref.rs:80:37 | LL | fn trait_method2(&self, _color: &Color); | ^^^^^^ help: consider passing by value instead: `Color` diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index c6fce5df210..e356f13d087 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -1,7 +1,6 @@ // run-rustfix #![deny(clippy::useless_asref)] -#![allow(clippy::trivially_copy_pass_by_ref)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index 1d23760bd14..2a80291f5d8 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,7 +1,6 @@ // run-rustfix #![deny(clippy::useless_asref)] -#![allow(clippy::trivially_copy_pass_by_ref)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index b21c67bb364..5876b54aca8 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -1,5 +1,5 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:44:18 + --> $DIR/useless_asref.rs:43:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:46:20 + --> $DIR/useless_asref.rs:45:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:50:21 + --> $DIR/useless_asref.rs:49:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:52:20 + --> $DIR/useless_asref.rs:51:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:59:20 + --> $DIR/useless_asref.rs:58:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:61:18 + --> $DIR/useless_asref.rs:60:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:66:21 + --> $DIR/useless_asref.rs:65:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:68:20 + --> $DIR/useless_asref.rs:67:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:72:16 + --> $DIR/useless_asref.rs:71:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:122:13 + --> $DIR/useless_asref.rs:121:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:124:12 + --> $DIR/useless_asref.rs:123:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 7567fa7158c..99652ca4470 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,6 +1,6 @@ #![warn(clippy::wrong_self_convention)] #![warn(clippy::wrong_pub_self_convention)] -#![allow(dead_code, clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] fn main() {} -- cgit 1.4.1-3-g733a5 From e26ae7a0ff54cbb229790011df1031df68d258bb Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Thu, 2 Apr 2020 20:00:12 -0700 Subject: Downgrade inefficient_to_string to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/methods/mod.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..7648225f9c6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1105,6 +1105,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), LintId::of(&methods::FIND_MAP), + LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::MAP_FLATTEN), LintId::of(&methods::OPTION_MAP_UNWRAP_OR), LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE), @@ -1259,7 +1260,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::EXPECT_FUN_CALL), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), - LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), @@ -1652,7 +1652,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::NEEDLESS_COLLECT), LintId::of(&methods::EXPECT_FUN_CALL), - LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::ITER_NTH), LintId::of(&methods::OR_FUN_CALL), LintId::of(&methods::SINGLE_CHAR_PATTERN), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 527508af8a3..9064d2a41b5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -698,7 +698,7 @@ declare_clippy_lint! { /// ["foo", "bar"].iter().map(|&s| s.to_string()); /// ``` pub INEFFICIENT_TO_STRING, - perf, + pedantic, "using `to_string` on `&&T` where `T: ToString`" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..4ea974ec6e8 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -789,7 +789,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "inefficient_to_string", - group: "perf", + group: "pedantic", desc: "using `to_string` on `&&T` where `T: ToString`", deprecation: None, module: "methods", -- cgit 1.4.1-3-g733a5 From 91d8a804d34b44a414b02ea5eba5305573748fff Mon Sep 17 00:00:00 2001 From: Nick Torres <nickrtorres@icloud.com> Date: Fri, 3 Apr 2020 23:59:52 -0700 Subject: result_map_or_into_option: add lint to catch manually adpating Result -> Option Result<T, E> has an `ok()` method that adapts a Result<T,E> into an Option<T>. It's possible to get around this adapter by writing Result<T,E>.map_or(None, Some). This lint is implemented as a new variant of the existing [`option_map_none` lint](https://github.com/rust-lang/rust-clippy/pull/2128) --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/methods/mod.rs | 105 +++++++++++++++++++++++------- src/lintlist/mod.rs | 7 ++ tests/ui/result_map_or_into_option.fixed | 16 +++++ tests/ui/result_map_or_into_option.rs | 14 ++++ tests/ui/result_map_or_into_option.stderr | 10 +++ 7 files changed, 131 insertions(+), 25 deletions(-) create mode 100644 tests/ui/result_map_or_into_option.fixed create mode 100644 tests/ui/result_map_or_into_option.rs create mode 100644 tests/ui/result_map_or_into_option.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 894aab21fb3..b7ac3cace20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1448,6 +1448,7 @@ Released 2018-09-13 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..83dcb350e18 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -666,6 +666,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::OPTION_UNWRAP_USED, &methods::OR_FUN_CALL, &methods::RESULT_EXPECT_USED, + &methods::RESULT_MAP_OR_INTO_OPTION, &methods::RESULT_MAP_UNWRAP_OR_ELSE, &methods::RESULT_UNWRAP_USED, &methods::SEARCH_IS_SOME, @@ -1273,6 +1274,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::OR_FUN_CALL), + LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), LintId::of(&methods::SINGLE_CHAR_PATTERN), @@ -1453,6 +1455,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_MAP_OR_NONE), + LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 527508af8a3..e8d642ed71e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -330,6 +330,24 @@ declare_clippy_lint! { "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.map_or(None, Some)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely as + /// `_.ok()`. + /// + /// **Known problems:** + /// + /// **Example:** + /// ```rust + /// # let opt = Some(1); + /// # let r = opt.map_or(None, Some); + /// ``` + pub RESULT_MAP_OR_INTO_OPTION, + style, + "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`" +} + declare_clippy_lint! { /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`. /// @@ -1248,6 +1266,7 @@ declare_lint_pass!(Methods => [ OPTION_MAP_UNWRAP_OR, OPTION_MAP_UNWRAP_OR_ELSE, RESULT_MAP_UNWRAP_OR_ELSE, + RESULT_MAP_OR_INTO_OPTION, OPTION_MAP_OR_NONE, OPTION_AND_THEN_SOME, OR_FUN_CALL, @@ -2517,37 +2536,73 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( } } -/// lint use of `_.map_or(None, _)` for `Option`s +/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s fn lint_map_or_none<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>], ) { - if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) { - // check if the first non-self argument to map_or() is None - let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind { - match_qpath(qpath, &paths::OPTION_NONE) - } else { - false - }; + let is_option = match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION); + let is_result = match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::RESULT); + + // There are two variants of this `map_or` lint: + // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>` + // (2) using `map_or` as a combinator instead of `and_then` + // + // (For this lint) we don't care if any other type calls `map_or` + if !is_option && !is_result { + return; + } - if map_or_arg_is_none { - // lint message - let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \ - `and_then(f)` instead"; - let map_or_self_snippet = snippet(cx, map_or_args[0].span, ".."); - let map_or_func_snippet = snippet(cx, map_or_args[2].span, ".."); - let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet); - span_lint_and_sugg( - cx, - OPTION_MAP_OR_NONE, - expr.span, - msg, - "try using `and_then` instead", - hint, - Applicability::MachineApplicable, - ); - } + let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind { + match_qpath(qpath, &paths::OPTION_NONE) + } else { + false + }; + + // This is really only needed if `is_result` holds. Computing it here + // makes `mess`'s assignment a bit easier, so just compute it here. + let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind { + match_qpath(qpath, &paths::OPTION_SOME) + } else { + false + }; + + let mess = if is_option && default_arg_is_none { + let self_snippet = snippet(cx, map_or_args[0].span, ".."); + let func_snippet = snippet(cx, map_or_args[2].span, ".."); + let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \ + `and_then(f)` instead"; + Some(( + OPTION_MAP_OR_NONE, + msg, + "try using `and_then` instead", + format!("{0}.and_then({1})", self_snippet, func_snippet), + )) + } else if is_result && f_arg_is_some { + let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ + `ok()` instead"; + let self_snippet = snippet(cx, map_or_args[0].span, ".."); + Some(( + RESULT_MAP_OR_INTO_OPTION, + msg, + "try using `ok` instead", + format!("{0}.ok()", self_snippet), + )) + } else { + None + }; + + if let Some((lint, msg, instead, hint)) = mess { + span_lint_and_sugg( + cx, + lint, + expr.span, + msg, + instead, + hint, + Applicability::MachineApplicable, + ); } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..01d1d1a0672 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1823,6 +1823,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "methods", }, + Lint { + name: "result_map_or_into_option", + group: "style", + desc: "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`", + deprecation: None, + module: "methods", + }, Lint { name: "result_map_unit_fn", group: "complexity", diff --git a/tests/ui/result_map_or_into_option.fixed b/tests/ui/result_map_or_into_option.fixed new file mode 100644 index 00000000000..948eb6a3aca --- /dev/null +++ b/tests/ui/result_map_or_into_option.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![warn(clippy::result_map_or_into_option)] + +fn main() { + let opt: Result<u32, &str> = Ok(1); + let _ = opt.ok(); + + let rewrap = |s: u32| -> Option<u32> { + Some(s) + }; + + // A non-Some `f` arg should not emit the lint + let opt: Result<u32, &str> = Ok(1); + let _ = opt.map_or(None, rewrap); +} diff --git a/tests/ui/result_map_or_into_option.rs b/tests/ui/result_map_or_into_option.rs new file mode 100644 index 00000000000..d097c19e44b --- /dev/null +++ b/tests/ui/result_map_or_into_option.rs @@ -0,0 +1,14 @@ +// run-rustfix + +#![warn(clippy::result_map_or_into_option)] + +fn main() { + let opt: Result<u32, &str> = Ok(1); + let _ = opt.map_or(None, Some); + + let rewrap = |s: u32| -> Option<u32> { Some(s) }; + + // A non-Some `f` arg should not emit the lint + let opt: Result<u32, &str> = Ok(1); + let _ = opt.map_or(None, rewrap); +} diff --git a/tests/ui/result_map_or_into_option.stderr b/tests/ui/result_map_or_into_option.stderr new file mode 100644 index 00000000000..febf32147d1 --- /dev/null +++ b/tests/ui/result_map_or_into_option.stderr @@ -0,0 +1,10 @@ +error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead + --> $DIR/result_map_or_into_option.rs:7:13 + | +LL | let _ = opt.map_or(None, Some); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + | + = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From be34bc46ed7699c598e4525b07e04067e19e49aa Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Sat, 4 Apr 2020 12:47:16 -0700 Subject: Downgrade unreadable_literal to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/literal_representation.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/approx_const.rs | 2 +- tests/ui/inconsistent_digit_grouping.fixed | 1 + tests/ui/inconsistent_digit_grouping.rs | 1 + tests/ui/inconsistent_digit_grouping.stderr | 26 +++++++++++++++----------- 7 files changed, 21 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..2e0a77068ac 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1098,6 +1098,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), + LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), @@ -1219,7 +1220,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&lifetimes::NEEDLESS_LIFETIMES), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::FOR_KV_MAP), @@ -1428,7 +1428,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&len_zero::LEN_ZERO), LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::FOR_KV_MAP), LintId::of(&loops::NEEDLESS_RANGE_LOOP), diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 1b0b111bcfe..0a6ffc1130a 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// let x: u64 = 61864918973511; /// ``` pub UNREADABLE_LITERAL, - style, + pedantic, "long integer literal without underscores" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..e24169bd350 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2294,7 +2294,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "unreadable_literal", - group: "style", + group: "pedantic", desc: "long integer literal without underscores", deprecation: None, module: "literal_representation", diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index e1c150fdefd..fb57a0becbb 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,5 +1,5 @@ #[warn(clippy::approx_constant)] -#[allow(unused, clippy::shadow_unrelated, clippy::similar_names, clippy::unreadable_literal)] +#[allow(unused, clippy::shadow_unrelated, clippy::similar_names)] fn main() { let my_e = 2.7182; let almost_e = 2.718; diff --git a/tests/ui/inconsistent_digit_grouping.fixed b/tests/ui/inconsistent_digit_grouping.fixed index f10673adfb2..ae4d1806af4 100644 --- a/tests/ui/inconsistent_digit_grouping.fixed +++ b/tests/ui/inconsistent_digit_grouping.fixed @@ -1,5 +1,6 @@ // run-rustfix #[warn(clippy::inconsistent_digit_grouping)] +#[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] fn main() { macro_rules! mac1 { diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index b97df0865ee..a1ac21746f6 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,5 +1,6 @@ // run-rustfix #[warn(clippy::inconsistent_digit_grouping)] +#[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] fn main() { macro_rules! mac1 { diff --git a/tests/ui/inconsistent_digit_grouping.stderr b/tests/ui/inconsistent_digit_grouping.stderr index 37211efcab5..b8ac9155462 100644 --- a/tests/ui/inconsistent_digit_grouping.stderr +++ b/tests/ui/inconsistent_digit_grouping.stderr @@ -1,5 +1,5 @@ error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:25:16 + --> $DIR/inconsistent_digit_grouping.rs:26:16 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^ help: consider: `123_456` @@ -7,57 +7,61 @@ LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:25:26 + --> $DIR/inconsistent_digit_grouping.rs:26:26 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^ help: consider: `12_345_678` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:25:38 + --> $DIR/inconsistent_digit_grouping.rs:26:38 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^ help: consider: `1_234_567` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:25:48 + --> $DIR/inconsistent_digit_grouping.rs:26:48 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:25:64 + --> $DIR/inconsistent_digit_grouping.rs:26:64 | LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); | ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32` error: long literal lacking separators - --> $DIR/inconsistent_digit_grouping.rs:28:13 + --> $DIR/inconsistent_digit_grouping.rs:29:13 | LL | let _ = 0x100000; | ^^^^^^^^ help: consider: `0x0010_0000` | - = note: `-D clippy::unreadable-literal` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/inconsistent_digit_grouping.rs:3:8 + | +LL | #[deny(clippy::unreadable_literal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: long literal lacking separators - --> $DIR/inconsistent_digit_grouping.rs:29:13 + --> $DIR/inconsistent_digit_grouping.rs:30:13 | LL | let _ = 0x1000000; | ^^^^^^^^^ help: consider: `0x0100_0000` error: long literal lacking separators - --> $DIR/inconsistent_digit_grouping.rs:30:13 + --> $DIR/inconsistent_digit_grouping.rs:31:13 | LL | let _ = 0x10000000; | ^^^^^^^^^^ help: consider: `0x1000_0000` error: long literal lacking separators - --> $DIR/inconsistent_digit_grouping.rs:31:13 + --> $DIR/inconsistent_digit_grouping.rs:32:13 | LL | let _ = 0x100000000_u64; | ^^^^^^^^^^^^^^^ help: consider: `0x0001_0000_0000_u64` error: digits grouped inconsistently by underscores - --> $DIR/inconsistent_digit_grouping.rs:34:18 + --> $DIR/inconsistent_digit_grouping.rs:35:18 | LL | let _: f32 = 1_23_456.; | ^^^^^^^^^ help: consider: `123_456.` -- cgit 1.4.1-3-g733a5 From 560c8c9c701c0f84cdc725e00562c560b48dd0c2 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Sat, 4 Apr 2020 12:58:18 -0700 Subject: Downgrade new_ret_no_self to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/methods/mod.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dfc2a26b06b..f6942f18476 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1106,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FILTER_MAP_NEXT), LintId::of(&methods::FIND_MAP), LintId::of(&methods::MAP_FLATTEN), + LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OPTION_MAP_UNWRAP_OR), LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE), LintId::of(&methods::RESULT_MAP_UNWRAP_OR_ELSE), @@ -1267,7 +1268,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AND_THEN_SOME), LintId::of(&methods::OPTION_AS_REF_DEREF), @@ -1450,7 +1450,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 527508af8a3..7d7a375ddac 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -721,7 +721,7 @@ declare_clippy_lint! { /// } /// ``` pub NEW_RET_NO_SELF, - style, + pedantic, "not returning `Self` in a `new` method" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..0a565f4466f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1447,7 +1447,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "new_ret_no_self", - group: "style", + group: "pedantic", desc: "not returning `Self` in a `new` method", deprecation: None, module: "methods", -- cgit 1.4.1-3-g733a5 From 51bb1d28c510b6833066561a2b5709e21b172c5c Mon Sep 17 00:00:00 2001 From: Linus Färnstrand <faern@faern.net> Date: Tue, 7 Apr 2020 23:41:00 +0200 Subject: Use assoc const NAN for zero_div_zero lint --- clippy_lints/src/utils/diagnostics.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 9 ++++----- src/lintlist/mod.rs | 2 +- tests/ui/zero_div_zero.stderr | 8 ++++---- 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index cc519d52552..409bb2043d4 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -60,7 +60,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult /// 6 | let other_f64_nan = 0.0f64 / 0.0; /// | ^^^^^^^^^^^^ /// | -/// = help: Consider using `std::f64::NAN` if you would like a constant representing NaN +/// = help: Consider using `f64::NAN` if you would like a constant representing NaN /// ``` pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) { cx.struct_span_lint(lint, span, |ldb| { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 42cb9a77db0..afd10d9ed53 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -8,8 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Checks for `0.0 / 0.0`. /// - /// **Why is this bad?** It's less readable than `std::f32::NAN` or - /// `std::f64::NAN`. + /// **Why is this bad?** It's less readable than `f32::NAN` or `f64::NAN`. /// /// **Known problems:** None. /// @@ -19,7 +18,7 @@ declare_clippy_lint! { /// ``` pub ZERO_DIVIDED_BY_ZERO, complexity, - "usage of `0.0 / 0.0` to obtain NaN instead of `std::f32::NAN` or `std::f64::NAN`" + "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`" } declare_lint_pass!(ZeroDiv => [ZERO_DIVIDED_BY_ZERO]); @@ -38,7 +37,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ZeroDiv { if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value; if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value; then { - // since we're about to suggest a use of std::f32::NaN or std::f64::NaN, + // since we're about to suggest a use of f32::NAN or f64::NAN, // match the precision of the literals that are given. let float_type = match (lhs_value, rhs_value) { (Constant::F64(_), _) @@ -51,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ZeroDiv { expr.span, "constant division of `0.0` with `0.0` will always result in NaN", &format!( - "Consider using `std::{}::NAN` if you would like a constant representing NaN", + "Consider using `{}::NAN` if you would like a constant representing NaN", float_type, ), ); diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8a6d0af5f8a..0e5757fe588 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2526,7 +2526,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "zero_divided_by_zero", group: "complexity", - desc: "usage of `0.0 / 0.0` to obtain NaN instead of `std::f32::NAN` or `std::f64::NAN`", + desc: "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`", deprecation: None, module: "zero_div_zero", }, diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index e4d6f168038..d0e88f3c5a5 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -13,7 +13,7 @@ LL | let nan = 0.0 / 0.0; | ^^^^^^^^^ | = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings` - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + = help: Consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:5:19 @@ -27,7 +27,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let f64_nan = 0.0 / 0.0f64; | ^^^^^^^^^^^^ | - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + = help: Consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:6:25 @@ -41,7 +41,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ | - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + = help: Consider using `f64::NAN` if you would like a constant representing NaN error: equal expressions as operands to `/` --> $DIR/zero_div_zero.rs:7:28 @@ -55,7 +55,7 @@ error: constant division of `0.0` with `0.0` will always result in NaN LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | ^^^^^^^^^^^^^^^ | - = help: Consider using `std::f64::NAN` if you would like a constant representing NaN + = help: Consider using `f64::NAN` if you would like a constant representing NaN error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 899a1b559805fa46c18b8165e2f59f77eb843585 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Mon, 6 Apr 2020 15:46:40 -0700 Subject: Move cognitive_complexity to nursery --- clippy_lints/src/assign_ops.rs | 1 - clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 1 - clippy_lints/src/types.rs | 1 - src/lintlist/mod.rs | 2 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/debug_assert_with_mut_call.rs | 2 +- tests/ui/for_loop_fixable.fixed | 1 - tests/ui/for_loop_fixable.rs | 1 - tests/ui/for_loop_fixable.stderr | 40 ++++++++++++++--------------- tests/ui/for_loop_unfixable.rs | 1 - tests/ui/for_loop_unfixable.stderr | 2 +- tests/ui/if_same_then_else2.rs | 1 - tests/ui/if_same_then_else2.stderr | 24 ++++++++--------- tests/ui/rename.fixed | 1 - tests/ui/rename.rs | 1 - tests/ui/rename.stderr | 10 ++++---- tests/ui/while_let_on_iterator.rs | 2 +- 23 files changed, 48 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index b66e8746707..c60577e8b2d 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -77,7 +77,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps { }, hir::ExprKind::Assign(assignee, e, _) => { if let hir::ExprKind::Binary(op, l, r) = &e.kind { - #[allow(clippy::cognitive_complexity)] let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { let ty = cx.tables.expr_ty(assignee); let rty = cx.tables.expr_ty(rhs); diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index b90dd28642b..98abc801302 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// /// **Example:** No. You'll see it when you get the warning. pub COGNITIVE_COMPLEXITY, - complexity, + nursery, "functions that should be split up into multiple functions" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2cd22633bc8..3e8ce4006f6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1174,7 +1174,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&booleans::LOGIC_BUG), LintId::of(&booleans::NONMINIMAL_BOOL), LintId::of(&bytecount::NAIVE_BYTECOUNT), - LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), LintId::of(&collapsible_if::COLLAPSIBLE_IF), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&copies::IFS_SAME_COND), @@ -1509,7 +1508,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), LintId::of(&attrs::DEPRECATED_CFG_ATTR), LintId::of(&booleans::NONMINIMAL_BOOL), - LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), LintId::of(&double_comparison::DOUBLE_COMPARISONS), LintId::of(&double_parens::DOUBLE_PARENS), LintId::of(&duration_subsec::DURATION_SUBSEC), @@ -1678,6 +1676,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), + LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3b2f96e4d09..3f49849ba32 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1317,7 +1317,7 @@ declare_lint_pass!(Methods => [ ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { - #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] + #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { if in_macro(expr.span) { return; diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 80609d5cb1d..119e0905ff4 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -53,7 +53,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall { } //HACK(hellow554): remove this when #4694 is implemented -#[allow(clippy::cognitive_complexity)] fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> { if_chain! { if let ExprKind::Block(ref block, _) = e.kind; diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index e2b16079f8f..13e275b3291 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -315,7 +315,6 @@ impl Types { /// The parameter `is_local` distinguishes the context of the type; types from /// local bindings should only be checked for the `BORROWED_BOX` lint. #[allow(clippy::too_many_lines)] - #[allow(clippy::cognitive_complexity)] fn check_ty(&mut self, cx: &LateContext<'_, '_>, hir_ty: &hir::Ty<'_>, is_local: bool) { if hir_ty.span.from_expansion() { return; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 00add20b7ae..3b275f43e17 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -250,7 +250,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "cognitive_complexity", - group: "complexity", + group: "nursery", desc: "functions that should be split up into multiple functions", deprecation: None, module: "cognitive_complexity", diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index c4149ad19c1..ce2a1c28c8a 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 79a27aafc4d..99c40b8d38e 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 076771f5c57..561283fc8e7 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index 503cb35f858..dc9d9b451c0 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs index b061fff6b9e..477a47118d4 100644 --- a/tests/ui/debug_assert_with_mut_call.rs +++ b/tests/ui/debug_assert_with_mut_call.rs @@ -2,7 +2,7 @@ #![feature(custom_inner_attributes)] #![rustfmt::skip] #![warn(clippy::debug_assert_with_mut_call)] -#![allow(clippy::cognitive_complexity, clippy::redundant_closure_call)] +#![allow(clippy::redundant_closure_call)] struct S; diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index 6717899ed09..5fc84ada9ef 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -28,7 +28,6 @@ impl Unrelated { clippy::linkedlist, clippy::shadow_unrelated, clippy::unnecessary_mut_passed, - clippy::cognitive_complexity, clippy::similar_names )] #[allow(clippy::many_single_char_names, unused_variables)] diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 7c08d383420..4165b0dc004 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -28,7 +28,6 @@ impl Unrelated { clippy::linkedlist, clippy::shadow_unrelated, clippy::unnecessary_mut_passed, - clippy::cognitive_complexity, clippy::similar_names )] #[allow(clippy::many_single_char_names, unused_variables)] diff --git a/tests/ui/for_loop_fixable.stderr b/tests/ui/for_loop_fixable.stderr index f84b7a660ff..cffb4b9f0a9 100644 --- a/tests/ui/for_loop_fixable.stderr +++ b/tests/ui/for_loop_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:39:14 + --> $DIR/for_loop_fixable.rs:38:14 | LL | for i in 10..0 { | ^^^^^ @@ -11,7 +11,7 @@ LL | for i in (0..10).rev() { | ^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:43:14 + --> $DIR/for_loop_fixable.rs:42:14 | LL | for i in 10..=0 { | ^^^^^^ @@ -22,7 +22,7 @@ LL | for i in (0..=10).rev() { | ^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:47:14 + --> $DIR/for_loop_fixable.rs:46:14 | LL | for i in MAX_LEN..0 { | ^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for i in (0..MAX_LEN).rev() { | ^^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:72:14 + --> $DIR/for_loop_fixable.rs:71:14 | LL | for i in 10..5 + 4 { | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | for i in (5 + 4..10).rev() { | ^^^^^^^^^^^^^^^^^ error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:76:14 + --> $DIR/for_loop_fixable.rs:75:14 | LL | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | for i in ((3 - 1)..(5 + 2)).rev() { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:98:15 + --> $DIR/for_loop_fixable.rs:97:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -63,13 +63,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:100:15 + --> $DIR/for_loop_fixable.rs:99:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:103:15 + --> $DIR/for_loop_fixable.rs:102:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -77,73 +77,73 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:108:15 + --> $DIR/for_loop_fixable.rs:107:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:112:15 + --> $DIR/for_loop_fixable.rs:111:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:117:15 + --> $DIR/for_loop_fixable.rs:116:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:120:15 + --> $DIR/for_loop_fixable.rs:119:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:123:15 + --> $DIR/for_loop_fixable.rs:122:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:126:15 + --> $DIR/for_loop_fixable.rs:125:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:129:15 + --> $DIR/for_loop_fixable.rs:128:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:132:15 + --> $DIR/for_loop_fixable.rs:131:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:135:15 + --> $DIR/for_loop_fixable.rs:134:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:310:18 + --> $DIR/for_loop_fixable.rs:309:18 | LL | for i in iterator.into_iter() { | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:330:18 + --> $DIR/for_loop_fixable.rs:329:18 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:332:18 + --> $DIR/for_loop_fixable.rs:331:18 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/tests/ui/for_loop_unfixable.rs b/tests/ui/for_loop_unfixable.rs index 20a93a22282..179b255e08c 100644 --- a/tests/ui/for_loop_unfixable.rs +++ b/tests/ui/for_loop_unfixable.rs @@ -12,7 +12,6 @@ clippy::linkedlist, clippy::shadow_unrelated, clippy::unnecessary_mut_passed, - clippy::cognitive_complexity, clippy::similar_names, unused, dead_code diff --git a/tests/ui/for_loop_unfixable.stderr b/tests/ui/for_loop_unfixable.stderr index e88bfffaae6..1da8e0f3588 100644 --- a/tests/ui/for_loop_unfixable.stderr +++ b/tests/ui/for_loop_unfixable.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find function `f` in this scope - --> $DIR/for_loop_unfixable.rs:37:12 + --> $DIR/for_loop_unfixable.rs:36:12 | LL | if f(&vec[i], &vec[i]) { | ^ help: a local variable with a similar name exists: `i` diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index cbec56324dc..3cc21809264 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -1,7 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( clippy::blacklisted_name, - clippy::cognitive_complexity, clippy::collapsible_if, clippy::ifs_same_cond, clippy::needless_return diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index da2be6c8aa5..f5d087fe128 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:20:12 + --> $DIR/if_same_then_else2.rs:19:12 | LL | } else { | ____________^ @@ -13,7 +13,7 @@ LL | | } | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else2.rs:11:13 + --> $DIR/if_same_then_else2.rs:10:13 | LL | if true { | _____________^ @@ -26,7 +26,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:34:12 + --> $DIR/if_same_then_else2.rs:33:12 | LL | } else { | ____________^ @@ -36,7 +36,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:32:13 + --> $DIR/if_same_then_else2.rs:31:13 | LL | if true { | _____________^ @@ -45,7 +45,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:41:12 + --> $DIR/if_same_then_else2.rs:40:12 | LL | } else { | ____________^ @@ -55,7 +55,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:39:13 + --> $DIR/if_same_then_else2.rs:38:13 | LL | if true { | _____________^ @@ -64,7 +64,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:91:12 + --> $DIR/if_same_then_else2.rs:90:12 | LL | } else { | ____________^ @@ -74,7 +74,7 @@ LL | | }; | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:89:21 + --> $DIR/if_same_then_else2.rs:88:21 | LL | let _ = if true { | _____________________^ @@ -83,7 +83,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:98:12 + --> $DIR/if_same_then_else2.rs:97:12 | LL | } else { | ____________^ @@ -93,7 +93,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:96:13 + --> $DIR/if_same_then_else2.rs:95:13 | LL | if true { | _____________^ @@ -102,7 +102,7 @@ LL | | } else { | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:123:12 + --> $DIR/if_same_then_else2.rs:122:12 | LL | } else { | ____________^ @@ -112,7 +112,7 @@ LL | | } | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:120:20 + --> $DIR/if_same_then_else2.rs:119:20 | LL | } else if true { | ____________________^ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 947914aa123..13fbb6e2a6e 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -5,7 +5,6 @@ // allow the new lint name here, to test if the new name works #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] -#![allow(clippy::cognitive_complexity)] #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cognitive_complexity)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index e2c8c223fc7..cbd3b1e9166 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -5,7 +5,6 @@ // allow the new lint name here, to test if the new name works #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] -#![allow(clippy::cognitive_complexity)] #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cyclomatic_complexity)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 83c7f26ba5f..a9e80394604 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:11:9 + --> $DIR/rename.rs:10:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` @@ -7,25 +7,25 @@ LL | #![warn(clippy::cyclomatic_complexity)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:13:8 + --> $DIR/rename.rs:12:8 | LL | #[warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:16:8 + --> $DIR/rename.rs:15:8 | LL | #[warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:19:8 + --> $DIR/rename.rs:18:8 | LL | #[warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:11:9 + --> $DIR/rename.rs:10:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 01838ee202e..84dfc34db15 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,5 +1,5 @@ #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, clippy::cognitive_complexity)] +#![allow(clippy::never_loop)] fn main() { let mut iter = 1..20; -- cgit 1.4.1-3-g733a5 From 5f92faec6d0cbaac6c6afa93efc7298de6765afc Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Thu, 2 Apr 2020 19:09:30 -0700 Subject: Downgrade implicit_hasher to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/types.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/crashes/ice-3717.rs | 2 ++ tests/ui/crashes/ice-3717.stderr | 8 ++++++-- tests/ui/implicit_hasher.rs | 1 + tests/ui/implicit_hasher.stderr | 26 +++++++++++++++----------- tests/ui/mut_key.rs | 2 -- tests/ui/mut_key.stderr | 8 ++++---- 9 files changed, 31 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2cd22633bc8..e21d619119f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1135,6 +1135,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_POSSIBLE_WRAP), LintId::of(&types::CAST_PRECISION_LOSS), LintId::of(&types::CAST_SIGN_LOSS), + LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::INVALID_UPCAST_COMPARISONS), LintId::of(&types::LET_UNIT_VALUE), LintId::of(&types::LINKEDLIST), @@ -1384,7 +1385,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::REDUNDANT_ALLOCATION), LintId::of(&types::TYPE_COMPLEXITY), LintId::of(&types::UNIT_ARG), @@ -1495,7 +1495,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&try_err::TRY_ERR), LintId::of(&types::FN_TO_NUMERIC_CAST), LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(&types::IMPLICIT_HASHER), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index e2b16079f8f..455f71656fb 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -2170,7 +2170,7 @@ declare_clippy_lint! { /// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { } /// ``` pub IMPLICIT_HASHER, - style, + pedantic, "missing generalization over different hashers" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 00add20b7ae..9af2c76323e 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -747,7 +747,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "implicit_hasher", - group: "style", + group: "pedantic", desc: "missing generalization over different hashers", deprecation: None, module: "types", diff --git a/tests/ui/crashes/ice-3717.rs b/tests/ui/crashes/ice-3717.rs index 21c48f4749c..f50714643fd 100644 --- a/tests/ui/crashes/ice-3717.rs +++ b/tests/ui/crashes/ice-3717.rs @@ -1,3 +1,5 @@ +#![deny(clippy::implicit_hasher)] + use std::collections::HashSet; fn main() {} diff --git a/tests/ui/crashes/ice-3717.stderr b/tests/ui/crashes/ice-3717.stderr index 08c53c399c2..296c95abb96 100644 --- a/tests/ui/crashes/ice-3717.stderr +++ b/tests/ui/crashes/ice-3717.stderr @@ -1,10 +1,14 @@ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/ice-3717.rs:5:21 + --> $DIR/ice-3717.rs:7:21 | LL | pub fn ice_3717(_: &HashSet<usize>) { | ^^^^^^^^^^^^^^ | - = note: `-D clippy::implicit-hasher` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/ice-3717.rs:1:9 + | +LL | #![deny(clippy::implicit_hasher)] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding a type parameter | LL | pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) { diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index c0ffa6879ce..fdcc9a33f55 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,4 +1,5 @@ // aux-build:implicit_hasher_macros.rs +#![deny(clippy::implicit_hasher)] #![allow(unused)] #[macro_use] diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 252e9eb5dd8..2b06d661772 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,10 +1,14 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:15:35 + --> $DIR/implicit_hasher.rs:16:35 | LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> { | ^^^^^^^^^^^^^ | - = note: `-D clippy::implicit-hasher` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/implicit_hasher.rs:2:9 + | +LL | #![deny(clippy::implicit_hasher)] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding a type parameter | LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> { @@ -15,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:24:36 + --> $DIR/implicit_hasher.rs:25:36 | LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) { | ^^^^^^^^^^^^^ @@ -30,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:29:19 + --> $DIR/implicit_hasher.rs:30:19 | LL | impl Foo<i16> for HashMap<String, String> { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:46:32 + --> $DIR/implicit_hasher.rs:47:32 | LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> { | ^^^^^^^^^^ @@ -60,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:51:19 + --> $DIR/implicit_hasher.rs:52:19 | LL | impl Foo<i16> for HashSet<String> { | ^^^^^^^^^^^^^^^ @@ -75,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:68:23 + --> $DIR/implicit_hasher.rs:69:23 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -86,7 +90,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:68:53 + --> $DIR/implicit_hasher.rs:69:53 | LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ @@ -97,7 +101,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:72:43 + --> $DIR/implicit_hasher.rs:73:43 | LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> { | ^^^^^^^^^^^^^ @@ -116,7 +120,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:80:33 + --> $DIR/implicit_hasher.rs:81:33 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^^^^^^ @@ -131,7 +135,7 @@ LL | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:80:63 + --> $DIR/implicit_hasher.rs:81:63 | LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {} | ^^^^^^^^^^^^ diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index d45cf8278a8..2d227e6654c 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -1,5 +1,3 @@ -#![allow(clippy::implicit_hasher)] - use std::collections::{HashMap, HashSet}; use std::hash::{Hash, Hasher}; use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 5af28f18d3d..8d6a259c7e3 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -1,5 +1,5 @@ error: mutable key type - --> $DIR/mut_key.rs:29:32 + --> $DIR/mut_key.rs:27:32 | LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash = note: `#[deny(clippy::mutable_key_type)]` on by default error: mutable key type - --> $DIR/mut_key.rs:29:72 + --> $DIR/mut_key.rs:27:72 | LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> { | ^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:30:5 + --> $DIR/mut_key.rs:28:5 | LL | let _other: HashMap<Key, bool> = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:49:22 + --> $DIR/mut_key.rs:47:22 | LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 380f7218b3876225e726617531d9f02d42da0e38 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Sat, 29 Feb 2020 18:41:18 +0100 Subject: Add lint on large const arrays --- CHANGELOG.md | 1 + clippy_lints/src/large_const_arrays.rs | 85 ++++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 ++ src/lintlist/mod.rs | 7 +++ tests/ui/large_const_arrays.fixed | 37 +++++++++++++++ tests/ui/large_const_arrays.rs | 37 +++++++++++++++ tests/ui/large_const_arrays.stderr | 76 ++++++++++++++++++++++++++++++ 7 files changed, 247 insertions(+) create mode 100644 clippy_lints/src/large_const_arrays.rs create mode 100644 tests/ui/large_const_arrays.fixed create mode 100644 tests/ui/large_const_arrays.rs create mode 100644 tests/ui/large_const_arrays.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index b7ac3cace20..cbc7d98c878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1319,6 +1319,7 @@ Released 2018-09-13 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups [`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs new file mode 100644 index 00000000000..2f62e6ad9dc --- /dev/null +++ b/clippy_lints/src/large_const_arrays.rs @@ -0,0 +1,85 @@ +use crate::rustc_target::abi::LayoutOf; +use crate::utils::span_lint_and_then; +use if_chain::if_chain; +use rustc::mir::interpret::ConstValue; +use rustc::ty::{self, ConstKind}; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{BytePos, Pos, Span}; +use rustc_typeck::hir_ty_to_ty; + +declare_clippy_lint! { + /// **What it does:** Checks for large `const` arrays that should + /// be defined as `static` instead. + /// + /// **Why is this bad?** Performance: const variables are inlined upon use. + /// Static items result in only one instance and has a fixed location in memory. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// // Bad + /// pub const a = [0u32; 1_000_000]; + /// + /// // Good + /// pub static a = [0u32; 1_000_000]; + /// ``` + pub LARGE_CONST_ARRAYS, + perf, + "large non-scalar const array may cause performance overhead" +} + +pub struct LargeConstArrays { + maximum_allowed_size: u64, +} + +impl LargeConstArrays { + #[must_use] + pub fn new(maximum_allowed_size: u64) -> Self { + Self { maximum_allowed_size } + } +} + +impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeConstArrays { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) { + if_chain! { + if !item.span.from_expansion(); + if let ItemKind::Const(hir_ty, _) = &item.kind; + let ty = hir_ty_to_ty(cx.tcx, hir_ty); + if let ty::Array(element_type, cst) = ty.kind; + if let ConstKind::Value(val) = cst.val; + if let ConstValue::Scalar(element_count) = val; + if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); + if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); + if self.maximum_allowed_size < element_count * element_size; + + then { + let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); + let sugg_span = Span::new( + hi_pos - BytePos::from_usize("const".len()), + hi_pos, + item.span.ctxt(), + ); + span_lint_and_then( + cx, + LARGE_CONST_ARRAYS, + item.span, + "large array defined as const", + |db| { + db.span_suggestion( + sugg_span, + "make this a static item", + "static".to_string(), + Applicability::MachineApplicable, + ); + } + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b106113c2a9..909115f7a3a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -580,6 +580,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &int_plus_one::INT_PLUS_ONE, &integer_division::INTEGER_DIVISION, &items_after_statements::ITEMS_AFTER_STATEMENTS, + &large_const_arrays::LARGE_CONST_ARRAYS, &large_enum_variant::LARGE_ENUM_VARIANT, &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, @@ -1024,6 +1025,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); @@ -1222,6 +1224,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), LintId::of(&int_plus_one::INT_PLUS_ONE), + LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), @@ -1651,6 +1654,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&bytecount::NAIVE_BYTECOUNT), LintId::of(&entry::MAP_ENTRY), LintId::of(&escape::BOXED_LOCAL), + LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::NEEDLESS_COLLECT), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b3c77f3f481..771b6d49634 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -941,6 +941,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "non_expressive_names", }, + Lint { + name: "large_const_arrays", + group: "perf", + desc: "large non-scalar const array may cause performance overhead", + deprecation: None, + module: "large_const_arrays", + }, Lint { name: "large_digit_groups", group: "pedantic", diff --git a/tests/ui/large_const_arrays.fixed b/tests/ui/large_const_arrays.fixed new file mode 100644 index 00000000000..c5af07c8a17 --- /dev/null +++ b/tests/ui/large_const_arrays.fixed @@ -0,0 +1,37 @@ +// run-rustfix + +#![warn(clippy::large_const_arrays)] +#![allow(dead_code)] + +#[derive(Clone, Copy)] +pub struct S { + pub data: [u64; 32], +} + +// Should lint +pub(crate) static FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; +pub static FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; +static FOO: [u32; 1_000_000] = [0u32; 1_000_000]; + +// Good +pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000]; +pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000]; +const G_FOO: [u32; 1_000] = [0u32; 1_000]; + +fn main() { + // Should lint + pub static BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + static BAR: [u32; 1_000_000] = [0u32; 1_000_000]; + pub static BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + static BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + pub static BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; + static BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; + + // Good + pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000]; + const G_BAR: [u32; 1_000] = [0u32; 1_000]; + pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500]; + const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500]; + pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200]; + const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200]; +} diff --git a/tests/ui/large_const_arrays.rs b/tests/ui/large_const_arrays.rs new file mode 100644 index 00000000000..a160b9f8ad5 --- /dev/null +++ b/tests/ui/large_const_arrays.rs @@ -0,0 +1,37 @@ +// run-rustfix + +#![warn(clippy::large_const_arrays)] +#![allow(dead_code)] + +#[derive(Clone, Copy)] +pub struct S { + pub data: [u64; 32], +} + +// Should lint +pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; +pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; +const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; + +// Good +pub(crate) const G_FOO_PUB_CRATE: [u32; 1_000] = [0u32; 1_000]; +pub const G_FOO_PUB: [u32; 1_000] = [0u32; 1_000]; +const G_FOO: [u32; 1_000] = [0u32; 1_000]; + +fn main() { + // Should lint + pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + const BAR: [u32; 1_000_000] = [0u32; 1_000_000]; + pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; + const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; + + // Good + pub const G_BAR_PUB: [u32; 1_000] = [0u32; 1_000]; + const G_BAR: [u32; 1_000] = [0u32; 1_000]; + pub const G_BAR_STRUCT_PUB: [S; 500] = [S { data: [0; 32] }; 500]; + const G_BAR_STRUCT: [S; 500] = [S { data: [0; 32] }; 500]; + pub const G_BAR_S_PUB: [Option<&str>; 200] = [Some("str"); 200]; + const G_BAR_S: [Option<&str>; 200] = [Some("str"); 200]; +} diff --git a/tests/ui/large_const_arrays.stderr b/tests/ui/large_const_arrays.stderr new file mode 100644 index 00000000000..3fb0acbca67 --- /dev/null +++ b/tests/ui/large_const_arrays.stderr @@ -0,0 +1,76 @@ +error: large array defined as const + --> $DIR/large_const_arrays.rs:12:1 + | +LL | pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; + | ^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + | + = note: `-D clippy::large-const-arrays` implied by `-D warnings` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:13:1 + | +LL | pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:14:1 + | +LL | const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:23:5 + | +LL | pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:24:5 + | +LL | const BAR: [u32; 1_000_000] = [0u32; 1_000_000]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:25:5 + | +LL | pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:26:5 + | +LL | const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:27:5 + | +LL | pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; + | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: large array defined as const + --> $DIR/large_const_arrays.rs:28:5 + | +LL | const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + +error: aborting due to 9 previous errors + -- cgit 1.4.1-3-g733a5 From 90fb50fabfcc03f3ee6fd0f7b614638791899c87 Mon Sep 17 00:00:00 2001 From: Philipp Krones <hello@philkrones.com> Date: Thu, 9 Apr 2020 19:38:20 +0200 Subject: Revert "Downgrade new_ret_no_self to pedantic" --- clippy_lints/src/lib.rs | 3 ++- clippy_lints/src/methods/mod.rs | 2 +- src/lintlist/mod.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b106113c2a9..cb9fcfca8a1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1115,7 +1115,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FIND_MAP), LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::MAP_FLATTEN), - LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OPTION_MAP_UNWRAP_OR), LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE), LintId::of(&methods::RESULT_MAP_UNWRAP_OR_ELSE), @@ -1277,6 +1276,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AND_THEN_SOME), LintId::of(&methods::OPTION_AS_REF_DEREF), @@ -1456,6 +1456,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c539e0360fb..be9b369112a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -748,7 +748,7 @@ declare_clippy_lint! { /// } /// ``` pub NEW_RET_NO_SELF, - pedantic, + style, "not returning `Self` in a `new` method" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b3c77f3f481..edebaff9f14 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1447,7 +1447,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "new_ret_no_self", - group: "pedantic", + group: "style", desc: "not returning `Self` in a `new` method", deprecation: None, module: "methods", -- cgit 1.4.1-3-g733a5 From e98c7a45d44cfed922699fbc1d61f3802d08b867 Mon Sep 17 00:00:00 2001 From: Emerentius <emerentius@arcor.de> Date: Sun, 12 Apr 2020 23:47:58 +0200 Subject: update lints --- src/lintlist/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index edebaff9f14..935ea180ebe 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1448,7 +1448,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "new_ret_no_self", group: "style", - desc: "not returning `Self` in a `new` method", + desc: "not returning type containing `Self` in a `new` method", deprecation: None, module: "methods", }, -- cgit 1.4.1-3-g733a5 From 23df4a0183e0d954d47db98824295411d50f742e Mon Sep 17 00:00:00 2001 From: Michael Sproul <michael@sigmaprime.io> Date: Mon, 13 Apr 2020 13:11:19 +1000 Subject: Disallow bit-shifting in `integer_arithmetic` lint With this change, the lint checks all operations that are defined as being capable of overflow in the Rust Reference. --- clippy_lints/src/arithmetic.rs | 18 ++++++++++------- src/lintlist/mod.rs | 2 +- tests/ui/integer_arithmetic.rs | 10 ++++------ tests/ui/integer_arithmetic.stderr | 40 ++++++++++++++++++++++++++++++-------- 4 files changed, 48 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index a138c9d3545..6cbe10a5352 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -6,11 +6,17 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; declare_clippy_lint! { - /// **What it does:** Checks for plain integer arithmetic. + /// **What it does:** Checks for integer arithmetic operations which could overflow or panic. /// - /// **Why is this bad?** This is only checked against overflow in debug builds. - /// In some applications one wants explicitly checked, wrapping or saturating - /// arithmetic. + /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable + /// of overflowing according to the [Rust + /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), + /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is + /// attempted. + /// + /// **Why is this bad?** Integer overflow will trigger a panic in debug builds or will wrap in + /// release mode. Division by zero will cause a panic in either mode. In some applications one + /// wants explicitly checked, wrapping or saturating arithmetic. /// /// **Known problems:** None. /// @@ -21,7 +27,7 @@ declare_clippy_lint! { /// ``` pub INTEGER_ARITHMETIC, restriction, - "any integer arithmetic statement" + "any integer arithmetic expression which could overflow or panic" } declare_clippy_lint! { @@ -71,8 +77,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic { | hir::BinOpKind::BitAnd | hir::BinOpKind::BitOr | hir::BinOpKind::BitXor - | hir::BinOpKind::Shl - | hir::BinOpKind::Shr | hir::BinOpKind::Eq | hir::BinOpKind::Lt | hir::BinOpKind::Le diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index edebaff9f14..8712f07e9e0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -846,7 +846,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "integer_arithmetic", group: "restriction", - desc: "any integer arithmetic statement", + desc: "any integer arithmetic expression which could overflow or panic", deprecation: None, module: "arithmetic", }, diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index 2fe32c6ace8..7b1b64f390a 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -17,6 +17,8 @@ fn main() { i / 2; // no error, this is part of the expression in the preceding line i - 2 + 2 - i; -i; + i >> 1; + i << 1; // no error, overflows are checked by `overflowing_literals` -1; @@ -25,18 +27,16 @@ fn main() { i & 1; // no wrapping i | 1; i ^ 1; - i >> 1; - i << 1; i += 1; i -= 1; i *= 2; i /= 2; i %= 2; - - // no errors i <<= 3; i >>= 2; + + // no errors i |= 1; i &= 1; i ^= i; @@ -72,8 +72,6 @@ fn main() { 1 + 1 }; } - - } // warn on references as well! (#5328) diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr index 64c44d7ecc7..83e8a9cde3f 100644 --- a/tests/ui/integer_arithmetic.stderr +++ b/tests/ui/integer_arithmetic.stderr @@ -31,6 +31,18 @@ error: integer arithmetic detected LL | -i; | ^^ +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:20:5 + | +LL | i >> 1; + | ^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:21:5 + | +LL | i << 1; + | ^^^^^^ + error: integer arithmetic detected --> $DIR/integer_arithmetic.rs:31:5 | @@ -62,46 +74,58 @@ LL | i %= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:81:5 + --> $DIR/integer_arithmetic.rs:36:5 + | +LL | i <<= 3; + | ^^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:37:5 + | +LL | i >>= 2; + | ^^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:79:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:82:5 + --> $DIR/integer_arithmetic.rs:80:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:83:5 + --> $DIR/integer_arithmetic.rs:81:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:88:5 + --> $DIR/integer_arithmetic.rs:86:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:92:5 + --> $DIR/integer_arithmetic.rs:90:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:96:5 + --> $DIR/integer_arithmetic.rs:94:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:100:5 + --> $DIR/integer_arithmetic.rs:98:5 | LL | (&x + &y) | ^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 21 previous errors -- cgit 1.4.1-3-g733a5 From 6b4ab827469529f4eda5f1e9492abcb9ad9d209a Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Thu, 23 Jan 2020 16:28:01 +0100 Subject: Global rework + fix imports --- CHANGELOG.md | 1 + clippy_lints/src/dereference.rs | 60 ++++++++++++++++++++++------------------- clippy_lints/src/lib.rs | 7 +++-- src/lintlist/mod.rs | 7 +++++ tests/ui/dereference.rs | 59 +++++++++++++++------------------------- tests/ui/dereference.stderr | 48 ++++++++++++++++----------------- 6 files changed, 89 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index b7ac3cace20..eb5a6af97d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1256,6 +1256,7 @@ Released 2018-09-13 [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call [`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy [`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop +[`explicit_deref_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_method [`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop [`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop [`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index c29c0d466d1..dea00e5aa3b 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,47 +1,51 @@ -use crate::rustc::hir::{Expr, ExprKind, QPath}; -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_errors::Applicability; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, declare_lint_pass}; use crate::utils::{in_macro, span_lint_and_sugg}; use if_chain::if_chain; -/// **What it does:** Checks for explicit deref() or deref_mut() method calls. -/// -/// **Why is this bad?** Derefencing by &*x or &mut *x is clearer and more concise, -/// when not part of a method chain. -/// -/// **Example:** -/// ```rust -/// let b = a.deref(); -/// let c = a.deref_mut(); -/// -/// // excludes -/// let e = d.unwrap().deref(); -/// ``` declare_clippy_lint! { + /// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls. + /// + /// **Why is this bad?** Derefencing by `&*x` or `&mut *x` is clearer and more concise, + /// when not part of a method chain. + /// + /// **Example:** + /// ```rust + /// let b = a.deref(); + /// let c = a.deref_mut(); + /// ``` + /// Could be written as: + /// ```rust + /// let b = &*a; + /// let c = &mut *a; + /// ``` + /// + /// This lint excludes + /// ```rust + /// let e = d.unwrap().deref(); + /// ``` pub EXPLICIT_DEREF_METHOD, pedantic, "Explicit use of deref or deref_mut method while not in a method chain." } -pub struct Pass; +declare_lint_pass!(Dereferencing => [ + EXPLICIT_DEREF_METHOD +]); -impl LintPass for Pass { - fn get_lints(&self) -> LintArray { - lint_array!(EXPLICIT_DEREF_METHOD) - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if in_macro(expr.span) { return; } if_chain! { // if this is a method call - if let ExprKind::MethodCall(ref method_name, _, ref args) = &expr.node; + if let ExprKind::MethodCall(ref method_name, _, ref args) = &expr.kind; // on a Path (i.e. a variable/name, not another method) - if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].node; + if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; then { let name = method_name.ident.as_str(); // alter help slightly to account for _mut @@ -54,6 +58,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "explicit deref method call", "try this", format!("&*{}", path), + Applicability::MachineApplicable ); }, "deref_mut" => { @@ -64,6 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "explicit deref_mut method call", "try this", format!("&mut *{}", path), + Applicability::MachineApplicable ); }, _ => () diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a6ddd6573a8..6443caa89d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,7 +391,7 @@ pub fn read_conf(args: &[rustc_ast::ast::NestedMetaItem], sess: &Session) -> Con } conf - } + }, Err((err, span)) => { sess.struct_span_err(span, err) .span_note(span, "Clippy will use default configuration") @@ -513,7 +513,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ©_iterator::COPY_ITERATOR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, - &dereference::DEREF_METHOD_EXPLICIT, + &dereference::EXPLICIT_DEREF_METHOD, &derive::DERIVE_HASH_XOR_EQ, &derive::EXPL_IMPL_CLONE_ON_COPY, &doc::DOC_MARKDOWN, @@ -1040,7 +1040,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_late_pass(|| box unnamed_address::UnnamedAddress); - store.register_late_pass(|| box dereference::DerefMethodExplicit); + store.register_late_pass(|| box dereference::Dereferencing); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1181,7 +1181,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), - LintId::of(&dereference::EXPLICIT_DEREF_METHOD), LintId::of(&derive::DERIVE_HASH_XOR_EQ), LintId::of(&doc::MISSING_SAFETY_DOC), LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 935ea180ebe..3f1d31f0302 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -528,6 +528,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "loops", }, + Lint { + name: "explicit_deref_method", + group: "pedantic", + desc: "Explicit use of deref or deref_mut method while not in a method chain.", + deprecation: None, + module: "dereference", + }, Lint { name: "explicit_into_iter_loop", group: "pedantic", diff --git a/tests/ui/dereference.rs b/tests/ui/dereference.rs index 7800cd84c24..07421eb715d 100644 --- a/tests/ui/dereference.rs +++ b/tests/ui/dereference.rs @@ -1,55 +1,38 @@ -#![feature(tool_lints)] +#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)] +#![warn(clippy::explicit_deref_method)] use std::ops::{Deref, DerefMut}; -#[allow(clippy::many_single_char_names, clippy::clone_double_ref)] -#[allow(unused_variables)] -#[warn(clippy::explicit_deref_method)] fn main() { let a: &mut String = &mut String::from("foo"); // these should require linting - { - let b: &str = a.deref(); - } + let b: &str = a.deref(); - { - let b: &mut str = a.deref_mut(); - } + let b: &mut str = a.deref_mut(); - { - let b: String = a.deref().clone(); - } - - { - let b: usize = a.deref_mut().len(); - } - - { - let b: &usize = &a.deref().len(); - } + let b: String = a.deref().clone(); - { - // only first deref should get linted here - let b: &str = a.deref().deref(); - } + let b: usize = a.deref_mut().len(); - { - // both derefs should get linted here - let b: String = format!("{}, {}", a.deref(), a.deref()); - } + let b: &usize = &a.deref().len(); + + // only first deref should get linted here + let b: &str = a.deref().deref(); + + // both derefs should get linted here + let b: String = format!("{}, {}", a.deref(), a.deref()); // these should not require linting - { - let b: &str = &*a; - } - { - let b: &mut str = &mut *a; - } + let b: &str = &*a; + + let b: &mut str = &mut *a; - { - macro_rules! expr_deref { ($body:expr) => { $body.deref() } } - let b: &str = expr_deref!(a); + macro_rules! expr_deref { + ($body:expr) => { + $body.deref() + }; } + let b: &str = expr_deref!(a); } diff --git a/tests/ui/dereference.stderr b/tests/ui/dereference.stderr index a4c2487d06b..7169b689a86 100644 --- a/tests/ui/dereference.stderr +++ b/tests/ui/dereference.stderr @@ -1,52 +1,52 @@ error: explicit deref method call - --> $DIR/dereference.rs:13:23 + --> $DIR/dereference.rs:10:19 | -13 | let b: &str = a.deref(); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: &str = a.deref(); + | ^^^^^^^^^ help: try this: `&*a` | = note: `-D clippy::explicit-deref-method` implied by `-D warnings` error: explicit deref_mut method call - --> $DIR/dereference.rs:17:27 + --> $DIR/dereference.rs:12:23 | -17 | let b: &mut str = a.deref_mut(); - | ^^^^^^^^^^^^^ help: try this: `&mut *a` +LL | let b: &mut str = a.deref_mut(); + | ^^^^^^^^^^^^^ help: try this: `&mut *a` error: explicit deref method call - --> $DIR/dereference.rs:21:25 + --> $DIR/dereference.rs:14:21 | -21 | let b: String = a.deref().clone(); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: String = a.deref().clone(); + | ^^^^^^^^^ help: try this: `&*a` error: explicit deref_mut method call - --> $DIR/dereference.rs:25:24 + --> $DIR/dereference.rs:16:20 | -25 | let b: usize = a.deref_mut().len(); - | ^^^^^^^^^^^^^ help: try this: `&mut *a` +LL | let b: usize = a.deref_mut().len(); + | ^^^^^^^^^^^^^ help: try this: `&mut *a` error: explicit deref method call - --> $DIR/dereference.rs:29:26 + --> $DIR/dereference.rs:18:22 | -29 | let b: &usize = &a.deref().len(); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: &usize = &a.deref().len(); + | ^^^^^^^^^ help: try this: `&*a` error: explicit deref method call - --> $DIR/dereference.rs:34:23 + --> $DIR/dereference.rs:21:19 | -34 | let b: &str = a.deref().deref(); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: &str = a.deref().deref(); + | ^^^^^^^^^ help: try this: `&*a` error: explicit deref method call - --> $DIR/dereference.rs:39:43 + --> $DIR/dereference.rs:24:39 | -39 | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: String = format!("{}, {}", a.deref(), a.deref()); + | ^^^^^^^^^ help: try this: `&*a` error: explicit deref method call - --> $DIR/dereference.rs:39:54 + --> $DIR/dereference.rs:24:50 | -39 | let b: String = format!("{}, {}", a.deref(), a.deref()); - | ^^^^^^^^^ help: try this: `&*a` +LL | let b: String = format!("{}, {}", a.deref(), a.deref()); + | ^^^^^^^^^ help: try this: `&*a` error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 72b9ae2a10b13a209f09c5ace0a7b9763b740e62 Mon Sep 17 00:00:00 2001 From: ThibsG <Thibs@debian.com> Date: Sat, 7 Mar 2020 15:33:27 +0100 Subject: Use only check_expr with parent expr and precedence --- CHANGELOG.md | 2 +- clippy_lints/src/dereference.rs | 103 +++++++++++----------------------------- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/utils/paths.rs | 2 - src/lintlist/mod.rs | 2 +- tests/ui/dereference.fixed | 20 ++++---- tests/ui/dereference.rs | 18 +++---- tests/ui/dereference.stderr | 28 ++++++++++- 8 files changed, 79 insertions(+), 100 deletions(-) (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index eb5a6af97d3..2c4bb42566d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1256,7 +1256,7 @@ Released 2018-09-13 [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call [`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy [`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop -[`explicit_deref_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_method +[`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods [`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop [`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop [`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d11614d489d..f5d82c54916 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,10 +1,8 @@ -use crate::utils::{ - get_parent_expr, get_trait_def_id, implements_trait, method_calls, paths, snippet, span_lint_and_sugg, -}; +use crate::utils::{get_parent_expr, implements_trait, snippet, span_lint_and_sugg}; use if_chain::if_chain; +use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, QPath, StmtKind}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -31,100 +29,52 @@ declare_clippy_lint! { /// ```rust,ignore /// let _ = d.unwrap().deref(); /// ``` - pub EXPLICIT_DEREF_METHOD, + pub EXPLICIT_DEREF_METHODS, pedantic, "Explicit use of deref or deref_mut method while not in a method chain." } declare_lint_pass!(Dereferencing => [ - EXPLICIT_DEREF_METHOD + EXPLICIT_DEREF_METHODS ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing { - fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt<'_>) { - if_chain! { - if let StmtKind::Local(ref local) = stmt.kind; - if let Some(ref init) = local.init; - - then { - match init.kind { - ExprKind::Call(ref _method, args) => { - for arg in args { - if_chain! { - // Caller must call only one other function (deref or deref_mut) - // otherwise it can lead to error prone suggestions (ie: &*a.len()) - let (method_names, arg_list, _) = method_calls(arg, 2); - if method_names.len() == 1; - // Caller must be a variable - let variables = arg_list[0]; - if variables.len() == 1; - if let ExprKind::Path(QPath::Resolved(None, _)) = variables[0].kind; - - then { - let name = method_names[0].as_str(); - lint_deref(cx, &*name, &variables[0], variables[0].span, arg.span); - } - } - } - } - ExprKind::MethodCall(ref method_name, _, ref args) => { - if init.span.from_expansion() { - return; - } - if_chain! { - if args.len() == 1; - if let ExprKind::Path(QPath::Resolved(None, _)) = args[0].kind; - // Caller must call only one other function (deref or deref_mut) - // otherwise it can lead to error prone suggestions (ie: &*a.len()) - let (method_names, arg_list, _) = method_calls(init, 2); - if method_names.len() == 1; - // Caller must be a variable - let variables = arg_list[0]; - if variables.len() == 1; - if let ExprKind::Path(QPath::Resolved(None, _)) = variables[0].kind; - - then { - let name = method_name.ident.as_str(); - lint_deref(cx, &*name, init, args[0].span, init.span); - } - } - } - _ => () - } - } - } - } - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { + if !expr.span.from_expansion(); if let ExprKind::MethodCall(ref method_name, _, ref args) = &expr.kind; if args.len() == 1; - if let ExprKind::Path(QPath::Resolved(None, _)) = args[0].kind; - if let Some(parent) = get_parent_expr(cx, &expr); then { - match parent.kind { - // Already linted using statements - ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _) => (), - _ => { - let name = method_name.ident.as_str(); - lint_deref(cx, &*name, &args[0], args[0].span, expr.span); + if let Some(parent_expr) = get_parent_expr(cx, expr) { + // Check if we have the whole call chain here + if let ExprKind::MethodCall(..) = parent_expr.kind { + return; + } + // Check for unary precedence + if let ExprPrecedence::Unary = parent_expr.precedence() { + return; } } + let name = method_name.ident.as_str(); + lint_deref(cx, &*name, &args[0], args[0].span, expr.span); } } } } -fn lint_deref(cx: &LateContext<'_, '_>, fn_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) { - match fn_name { +fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) { + match method_name { "deref" => { - if get_trait_def_id(cx, &paths::DEREF_TRAIT) + if cx + .tcx + .lang_items() + .deref_trait() .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[])) { span_lint_and_sugg( cx, - EXPLICIT_DEREF_METHOD, + EXPLICIT_DEREF_METHODS, expr_span, "explicit deref method call", "try this", @@ -134,12 +84,15 @@ fn lint_deref(cx: &LateContext<'_, '_>, fn_name: &str, call_expr: &Expr<'_>, var } }, "deref_mut" => { - if get_trait_def_id(cx, &paths::DEREF_MUT_TRAIT) + if cx + .tcx + .lang_items() + .deref_mut_trait() .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[])) { span_lint_and_sugg( cx, - EXPLICIT_DEREF_METHOD, + EXPLICIT_DEREF_METHODS, expr_span, "explicit deref_mut method call", "try this", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6443caa89d6..b6b6a0e7d21 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -513,7 +513,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ©_iterator::COPY_ITERATOR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, - &dereference::EXPLICIT_DEREF_METHOD, + &dereference::EXPLICIT_DEREF_METHODS, &derive::DERIVE_HASH_XOR_EQ, &derive::EXPL_IMPL_CLONE_ON_COPY, &doc::DOC_MARKDOWN, @@ -1091,7 +1091,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(©_iterator::COPY_ITERATOR), LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), - LintId::of(&dereference::EXPLICIT_DEREF_METHOD), + LintId::of(&dereference::EXPLICIT_DEREF_METHODS), LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), LintId::of(&doc::DOC_MARKDOWN), LintId::of(&doc::MISSING_ERRORS_DOC), diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index a49299e5f6f..d93f8a1e560 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -25,9 +25,7 @@ pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; -pub const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; -pub const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"]; pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"]; pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 3f1d31f0302..1d147e01066 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -529,7 +529,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "loops", }, Lint { - name: "explicit_deref_method", + name: "explicit_deref_methods", group: "pedantic", desc: "Explicit use of deref or deref_mut method while not in a method chain.", deprecation: None, diff --git a/tests/ui/dereference.fixed b/tests/ui/dereference.fixed index 292324eeacb..51e3d512cdb 100644 --- a/tests/ui/dereference.fixed +++ b/tests/ui/dereference.fixed @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)] -#![warn(clippy::explicit_deref_method)] +#![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; @@ -34,11 +34,18 @@ fn main() { let b: String = concat(&*a); - // following should not require linting + let b = &*just_return(a); + + let b: String = concat(&*just_return(a)); - let b = just_return(a).deref(); + let b: &str = &*a.deref(); - let b: String = concat(just_return(a).deref()); + let opt_a = Some(a.clone()); + let b = &*opt_a.unwrap(); + + // following should not require linting + + let b: &str = &*a.deref(); let b: String = a.deref().clone(); @@ -46,8 +53,6 @@ fn main() { let b: &usize = &a.deref().len(); - let b: &str = a.deref().deref(); - let b: &str = &*a; let b: &mut str = &mut *a; @@ -59,9 +64,6 @@ fn main() { } let b: &str = expr_deref!(a); - let opt_a = Some(a); - let b = opt_a.unwrap().deref(); - // The struct does not implement Deref trait #[derive(Copy, Clone)] struct NoLint(u32); diff --git a/tests/ui/dereference.rs b/tests/ui/dereference.rs index 25e1c29e7fa..3a595337411 100644 --- a/tests/ui/dereference.rs +++ b/tests/ui/dereference.rs @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)] -#![warn(clippy::explicit_deref_method)] +#![warn(clippy::explicit_deref_methods)] use std::ops::{Deref, DerefMut}; @@ -34,20 +34,25 @@ fn main() { let b: String = concat(a.deref()); - // following should not require linting - let b = just_return(a).deref(); let b: String = concat(just_return(a).deref()); + let b: &str = a.deref().deref(); + + let opt_a = Some(a.clone()); + let b = opt_a.unwrap().deref(); + + // following should not require linting + + let b: &str = &*a.deref(); + let b: String = a.deref().clone(); let b: usize = a.deref_mut().len(); let b: &usize = &a.deref().len(); - let b: &str = a.deref().deref(); - let b: &str = &*a; let b: &mut str = &mut *a; @@ -59,9 +64,6 @@ fn main() { } let b: &str = expr_deref!(a); - let opt_a = Some(a); - let b = opt_a.unwrap().deref(); - // The struct does not implement Deref trait #[derive(Copy, Clone)] struct NoLint(u32); diff --git a/tests/ui/dereference.stderr b/tests/ui/dereference.stderr index 97fab3a34e0..d159214db2f 100644 --- a/tests/ui/dereference.stderr +++ b/tests/ui/dereference.stderr @@ -4,7 +4,7 @@ error: explicit deref method call LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try this: `&*a` | - = note: `-D clippy::explicit-deref-method` implied by `-D warnings` + = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` error: explicit deref_mut method call --> $DIR/dereference.rs:23:23 @@ -42,5 +42,29 @@ error: explicit deref method call LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try this: `&*a` -error: aborting due to 7 previous errors +error: explicit deref method call + --> $DIR/dereference.rs:37:13 + | +LL | let b = just_return(a).deref(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)` + +error: explicit deref method call + --> $DIR/dereference.rs:39:28 + | +LL | let b: String = concat(just_return(a).deref()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*just_return(a)` + +error: explicit deref method call + --> $DIR/dereference.rs:41:19 + | +LL | let b: &str = a.deref().deref(); + | ^^^^^^^^^^^^^^^^^ help: try this: `&*a.deref()` + +error: explicit deref method call + --> $DIR/dereference.rs:44:13 + | +LL | let b = opt_a.unwrap().deref(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` + +error: aborting due to 11 previous errors -- cgit 1.4.1-3-g733a5 From 216371d42412192ebee5bb94106b40d5ad77fc70 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 09:06:57 -0700 Subject: split it up for testing but the merge broke tests --- src/driver.rs | 2 +- src/main.rs | 168 ++++++++++++++++++++++++++++---------------- tests/compile-test.rs | 4 +- tests/missing-test-files.rs | 2 +- 4 files changed, 111 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index 2c699998ea9..e62ddf2c5f5 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -43,7 +43,7 @@ fn arg_value<'a, T: Deref<Target = str>>( match arg.next().or_else(|| args.next()) { Some(v) if pred(v) => return Some(v), - _ => {}, + _ => {} } } None diff --git a/src/main.rs b/src/main.rs index a8ffc84001b..6a06ef7437c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,10 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use rustc_tools_util::VersionInfo; +use std::env; +use std::path::PathBuf; +use std::process::{self, Command}; +use std::ffi::OsString; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -37,93 +41,135 @@ fn show_version() { pub fn main() { // Check for version and help flags even when invoked as 'cargo-clippy' - if std::env::args().any(|a| a == "--help" || a == "-h") { + if env::args().any(|a| a == "--help" || a == "-h") { show_help(); return; } - if std::env::args().any(|a| a == "--version" || a == "-V") { + if env::args().any(|a| a == "--version" || a == "-V") { show_version(); return; } - if let Err(code) = process(std::env::args().skip(2)) { - std::process::exit(code); + if let Err(code) = process(env::args().skip(2)) { + process::exit(code); } } -fn process<I>(mut old_args: I) -> Result<(), i32> -where - I: Iterator<Item = String>, +struct ClippyCmd { + unstable_options: bool, + cmd: &'static str, + args: Vec<String>, + clippy_args: String +} + +impl ClippyCmd { - let mut args = vec!["check".to_owned()]; - - let mut fix = false; - let mut unstable_options = false; - - for arg in old_args.by_ref() { - match arg.as_str() { - "--fix" => { - fix = true; - continue; - }, - "--" => break, - // Cover -Zunstable-options and -Z unstable-options - s if s.ends_with("unstable-options") => unstable_options = true, - _ => {}, + fn new<I>(mut old_args: I) -> Self + where + I: Iterator<Item = String>, + { + let mut cmd = "check"; + let mut unstable_options = false; + let mut args = vec![]; + + for arg in old_args.by_ref() { + match arg.as_str() { + "--fix" => { + cmd = "fix"; + continue; + } + "--" => break, + // Cover -Zunstable-options and -Z unstable-options + s if s.ends_with("unstable-options") => unstable_options = true, + _ => {} + } + + args.push(arg); + } + + if cmd == "fix" && !unstable_options { + panic!("Usage of `--fix` requires `-Z unstable-options`"); } - args.push(arg); + // Run the dogfood tests directly on nightly cargo. This is required due + // to a bug in rustup.rs when running cargo on custom toolchains. See issue #3118. + if env::var_os("CLIPPY_DOGFOOD").is_some() && cfg!(windows) { + args.insert(0, "+nightly".to_string()); + } + + let clippy_args: String = + old_args + .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) + .collect(); + + ClippyCmd { + unstable_options, + cmd, + args, + clippy_args, + } } - if fix { - if unstable_options { - args[0] = "fix".to_owned(); + fn path_env(&self) -> &'static str { + if self.unstable_options { + "RUSTC_WORKSPACE_WRAPPER" } else { - panic!("Usage of `--fix` requires `-Z unstable-options`"); + "RUSTC_WRAPPER" } } - let path_env = if unstable_options { - "RUSTC_WORKSPACE_WRAPPER" - } else { - "RUSTC_WRAPPER" - }; + fn path(&self) -> PathBuf { + let mut path = env::current_exe() + .expect("current executable path invalid") + .with_file_name("clippy-driver"); - let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect(); + if cfg!(windows) { + path.set_extension("exe"); + } + + path + } - let mut path = std::env::current_exe() - .expect("current executable path invalid") - .with_file_name("clippy-driver"); - if cfg!(windows) { - path.set_extension("exe"); + fn target_dir() -> Option<(&'static str, OsString)> { + env::var_os("CLIPPY_DOGFOOD") + .map(|_| { + env::var_os("CARGO_MANIFEST_DIR").map_or_else( + || std::ffi::OsString::from("clippy_dogfood"), + |d| { + std::path::PathBuf::from(d) + .join("target") + .join("dogfood") + .into_os_string() + }, + ) + }) + .map(|p| ("CARGO_TARGET_DIR", p)) } - let target_dir = std::env::var_os("CLIPPY_DOGFOOD") - .map(|_| { - std::env::var_os("CARGO_MANIFEST_DIR").map_or_else( - || std::ffi::OsString::from("clippy_dogfood"), - |d| { - std::path::PathBuf::from(d) - .join("target") - .join("dogfood") - .into_os_string() - }, - ) - }) - .map(|p| ("CARGO_TARGET_DIR", p)); - - // Run the dogfood tests directly on nightly cargo. This is required due - // to a bug in rustup.rs when running cargo on custom toolchains. See issue #3118. - if std::env::var_os("CLIPPY_DOGFOOD").is_some() && cfg!(windows) { - args.insert(0, "+nightly".to_string()); + fn to_std_cmd(self) -> Command { + let mut cmd = Command::new("cargo"); + + cmd.env(self.path_env(), self.path()) + .envs(ClippyCmd::target_dir()) + .env("CLIPPY_ARGS", self.clippy_args) + .arg(self.cmd) + .args(&self.args); + + cmd } +} + + +fn process<I>(old_args: I) -> Result<(), i32> +where + I: Iterator<Item = String>, +{ + let cmd = ClippyCmd::new(old_args); + + let mut cmd = cmd.to_std_cmd(); - let exit_status = std::process::Command::new("cargo") - .args(&args) - .env(path_env, path) - .env("CLIPPY_ARGS", clippy_args) - .envs(target_dir) + let exit_status = cmd .spawn() .expect("could not run cargo") .wait() diff --git a/tests/compile-test.rs b/tests/compile-test.rs index de2cf6d7873..1f737ee90ae 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -145,11 +145,11 @@ fn run_ui_toml(config: &mut compiletest::Config) { let res = run_ui_toml_tests(&config, tests); match res { - Ok(true) => {}, + Ok(true) => {} Ok(false) => panic!("Some tests failed"), Err(e) => { println!("I/O failure during tests: {:?}", e); - }, + } } } diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index d87bb4be3c3..a26f43d0eff 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -46,7 +46,7 @@ fn explore_directory(dir: &Path) -> Vec<String> { if file_stem != current_file { missing_files.push(path.to_str().unwrap().to_string()); } - }, + } _ => continue, }; } -- cgit 1.4.1-3-g733a5 From a3ce88b4d71ebee0a4aa991420906ec5c5edf0ad Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 09:20:41 -0700 Subject: add some tests --- src/main.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 6a06ef7437c..3e29c02e4b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,3 +181,40 @@ where Err(exit_status.code().unwrap_or(-1)) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn fix_without_unstable() { + let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string); + let _ = ClippyCmd::new(args); + } + + #[test] + fn fix_unstable() { + let args = "cargo clippy --fix -Zunstable-options".split_whitespace().map(ToString::to_string); + let cmd = ClippyCmd::new(args); + assert_eq!("fix", cmd.cmd); + assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); + assert!(cmd.args.iter().find(|arg| arg.ends_with("unstable-options")).is_some()); + } + + #[test] + fn check() { + let args = "cargo clippy".split_whitespace().map(ToString::to_string); + let cmd = ClippyCmd::new(args); + assert_eq!("check", cmd.cmd); + assert_eq!("RUSTC_WRAPPER", cmd.path_env()); + } + + #[test] + fn check_unstable() { + let args = "cargo clippy -Zunstable-options".split_whitespace().map(ToString::to_string); + let cmd = ClippyCmd::new(args); + assert_eq!("check", cmd.cmd); + assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); + } +} -- cgit 1.4.1-3-g733a5 From 625011081b9c0e53878ba0c36c225998f564f55d Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 09:22:45 -0700 Subject: revert the damn fmt changes --- src/driver.rs | 2 +- tests/compile-test.rs | 4 ++-- tests/missing-test-files.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/driver.rs b/src/driver.rs index e62ddf2c5f5..2c699998ea9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -43,7 +43,7 @@ fn arg_value<'a, T: Deref<Target = str>>( match arg.next().or_else(|| args.next()) { Some(v) if pred(v) => return Some(v), - _ => {} + _ => {}, } } None diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 1f737ee90ae..de2cf6d7873 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -145,11 +145,11 @@ fn run_ui_toml(config: &mut compiletest::Config) { let res = run_ui_toml_tests(&config, tests); match res { - Ok(true) => {} + Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { println!("I/O failure during tests: {:?}", e); - } + }, } } diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index a26f43d0eff..d87bb4be3c3 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -46,7 +46,7 @@ fn explore_directory(dir: &Path) -> Vec<String> { if file_stem != current_file { missing_files.push(path.to_str().unwrap().to_string()); } - } + }, _ => continue, }; } -- cgit 1.4.1-3-g733a5 From b3030e1b9020460c4a716c2c909ada01258736d1 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 12:31:40 -0700 Subject: rename field --- src/main.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 3e29c02e4b2..d82b0a3cf6b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,7 +58,7 @@ pub fn main() { struct ClippyCmd { unstable_options: bool, - cmd: &'static str, + cargo_subcommand: &'static str, args: Vec<String>, clippy_args: String } @@ -69,14 +69,14 @@ impl ClippyCmd where I: Iterator<Item = String>, { - let mut cmd = "check"; + let mut cargo_subcommand = "check"; let mut unstable_options = false; let mut args = vec![]; for arg in old_args.by_ref() { match arg.as_str() { "--fix" => { - cmd = "fix"; + cargo_subcommand = "fix"; continue; } "--" => break, @@ -88,7 +88,7 @@ impl ClippyCmd args.push(arg); } - if cmd == "fix" && !unstable_options { + if cargo_subcommand == "fix" && !unstable_options { panic!("Usage of `--fix` requires `-Z unstable-options`"); } @@ -105,7 +105,7 @@ impl ClippyCmd ClippyCmd { unstable_options, - cmd, + cargo_subcommand, args, clippy_args, } @@ -153,7 +153,7 @@ impl ClippyCmd cmd.env(self.path_env(), self.path()) .envs(ClippyCmd::target_dir()) .env("CLIPPY_ARGS", self.clippy_args) - .arg(self.cmd) + .arg(self.cargo_subcommand) .args(&self.args); cmd @@ -197,7 +197,7 @@ mod tests { fn fix_unstable() { let args = "cargo clippy --fix -Zunstable-options".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("fix", cmd.cmd); + assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); assert!(cmd.args.iter().find(|arg| arg.ends_with("unstable-options")).is_some()); } @@ -206,7 +206,7 @@ mod tests { fn check() { let args = "cargo clippy".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cmd); + assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WRAPPER", cmd.path_env()); } @@ -214,7 +214,7 @@ mod tests { fn check_unstable() { let args = "cargo clippy -Zunstable-options".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cmd); + assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); } } -- cgit 1.4.1-3-g733a5 From 0397e46ea549b640173f059ae8cfae72c4746f28 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 13:04:04 -0700 Subject: fmt --- src/main.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index d82b0a3cf6b..61875b11095 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,9 @@ use rustc_tools_util::VersionInfo; use std::env; +use std::ffi::OsString; use std::path::PathBuf; use std::process::{self, Command}; -use std::ffi::OsString; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -60,11 +60,10 @@ struct ClippyCmd { unstable_options: bool, cargo_subcommand: &'static str, args: Vec<String>, - clippy_args: String + clippy_args: String, } -impl ClippyCmd -{ +impl ClippyCmd { fn new<I>(mut old_args: I) -> Self where I: Iterator<Item = String>, @@ -98,10 +97,7 @@ impl ClippyCmd args.insert(0, "+nightly".to_string()); } - let clippy_args: String = - old_args - .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) - .collect(); + let clippy_args: String = old_args.map(|arg| format!("{}__CLIPPY_HACKERY__", arg)).collect(); ClippyCmd { unstable_options, @@ -160,7 +156,6 @@ impl ClippyCmd } } - fn process<I>(old_args: I) -> Result<(), i32> where I: Iterator<Item = String>, @@ -195,7 +190,9 @@ mod tests { #[test] fn fix_unstable() { - let args = "cargo clippy --fix -Zunstable-options".split_whitespace().map(ToString::to_string); + let args = "cargo clippy --fix -Zunstable-options" + .split_whitespace() + .map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); @@ -212,7 +209,9 @@ mod tests { #[test] fn check_unstable() { - let args = "cargo clippy -Zunstable-options".split_whitespace().map(ToString::to_string); + let args = "cargo clippy -Zunstable-options" + .split_whitespace() + .map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("check", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); -- cgit 1.4.1-3-g733a5 From 664ad33faf5f0a32eeec6cbec3335e9dd47e907a Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby@yaah.dev> Date: Wed, 15 Apr 2020 13:08:33 -0700 Subject: manually fixing formatting at this point lol --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 61875b11095..e299cf4febf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,11 +77,11 @@ impl ClippyCmd { "--fix" => { cargo_subcommand = "fix"; continue; - } + }, "--" => break, // Cover -Zunstable-options and -Z unstable-options s if s.ends_with("unstable-options") => unstable_options = true, - _ => {} + _ => {}, } args.push(arg); -- cgit 1.4.1-3-g733a5 From 5cfb9ec1d7d66ecebd86761cef091766c65c09d9 Mon Sep 17 00:00:00 2001 From: Jane Lusby <jlusby42@gmail.com> Date: Wed, 15 Apr 2020 14:25:42 -0700 Subject: Apply suggestions from code review Co-Authored-By: Philipp Krones <hello@philkrones.com> --- src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index e299cf4febf..bc43a34ed5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,7 @@ impl ClippyCmd { } } - fn path(&self) -> PathBuf { + fn path() -> PathBuf { let mut path = env::current_exe() .expect("current executable path invalid") .with_file_name("clippy-driver"); @@ -143,10 +143,10 @@ impl ClippyCmd { .map(|p| ("CARGO_TARGET_DIR", p)) } - fn to_std_cmd(self) -> Command { + fn into_std_cmd(self) -> Command { let mut cmd = Command::new("cargo"); - cmd.env(self.path_env(), self.path()) + cmd.env(self.path_env(), Self::path()) .envs(ClippyCmd::target_dir()) .env("CLIPPY_ARGS", self.clippy_args) .arg(self.cargo_subcommand) @@ -162,7 +162,7 @@ where { let cmd = ClippyCmd::new(old_args); - let mut cmd = cmd.to_std_cmd(); + let mut cmd = cmd.into_std_cmd(); let exit_status = cmd .spawn() @@ -179,7 +179,7 @@ where #[cfg(test)] mod tests { - use super::*; + use super::ClippyCmd; #[test] #[should_panic] @@ -196,7 +196,7 @@ mod tests { let cmd = ClippyCmd::new(args); assert_eq!("fix", cmd.cargo_subcommand); assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); - assert!(cmd.args.iter().find(|arg| arg.ends_with("unstable-options")).is_some()); + assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); } #[test] -- cgit 1.4.1-3-g733a5 From d2cbbff217c71f70ef18304784958eec45c49430 Mon Sep 17 00:00:00 2001 From: Roland Kuhn <rk@rkuhn.info> Date: Tue, 7 Apr 2020 15:39:07 +0200 Subject: add lint futures_not_send --- CHANGELOG.md | 1 + clippy_lints/src/future_not_send.rs | 113 ++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 ++ src/lintlist/mod.rs | 7 ++ tests/ui/future_not_send.rs | 79 +++++++++++++++++++++++ tests/ui/future_not_send.stderr | 125 ++++++++++++++++++++++++++++++++++++ 6 files changed, 329 insertions(+) create mode 100644 clippy_lints/src/future_not_send.rs create mode 100644 tests/ui/future_not_send.rs create mode 100644 tests/ui/future_not_send.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 65eab69667f..60ad855d7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1281,6 +1281,7 @@ Released 2018-09-13 [`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs new file mode 100644 index 00000000000..57f47bc9bc9 --- /dev/null +++ b/clippy_lints/src/future_not_send.rs @@ -0,0 +1,113 @@ +use crate::utils; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl, HirId}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Opaque, Predicate::Trait, ToPolyTraitRef}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Span}; +use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; +use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine}; + +declare_clippy_lint! { + /// **What it does:** This lint requires Future implementations returned from + /// functions and methods to implement the `Send` marker trait. It is mostly + /// used by library authors (public and internal) that target an audience where + /// multithreaded executors are likely to be used for running these Futures. + /// + /// **Why is this bad?** A Future implementation captures some state that it + /// needs to eventually produce its final value. When targeting a multithreaded + /// executor (which is the norm on non-embedded devices) this means that this + /// state may need to be transported to other threads, in other words the + /// whole Future needs to implement the `Send` marker trait. If it does not, + /// then the resulting Future cannot be submitted to a thread pool in the + /// end user’s code. + /// + /// Especially for generic functions it can be confusing to leave the + /// discovery of this problem to the end user: the reported error location + /// will be far from its cause and can in many cases not even be fixed without + /// modifying the library where the offending Future implementation is + /// produced. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// async fn not_send(bytes: std::rc::Rc<[u8]>) {} + /// ``` + /// Use instead: + /// ```rust + /// async fn is_send(bytes: std::sync::Arc<[u8]>) {} + /// ``` + pub FUTURE_NOT_SEND, + nursery, + "public Futures must be Send" +} + +declare_lint_pass!(FutureNotSend => [FUTURE_NOT_SEND]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FutureNotSend { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + _: Span, + hir_id: HirId, + ) { + if let FnKind::Closure(_) = kind { + return; + } + let def_id = cx.tcx.hir().local_def_id(hir_id); + let fn_sig = cx.tcx.fn_sig(def_id); + let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig); + let ret_ty = fn_sig.output(); + if let Opaque(id, subst) = ret_ty.kind { + let preds = cx.tcx.predicates_of(id).instantiate(cx.tcx, subst); + let mut is_future = false; + for p in preds.predicates { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if Some(trait_ref.def_id()) == cx.tcx.lang_items().future_trait() { + is_future = true; + break; + } + } + } + if is_future { + let send_trait = cx.tcx.get_diagnostic_item(sym::send_trait).unwrap(); + let span = decl.output.span(); + let send_result = cx.tcx.infer_ctxt().enter(|infcx| { + let cause = traits::ObligationCause::misc(span, hir_id); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause); + fulfillment_cx.select_all_or_error(&infcx) + }); + if let Err(send_errors) = send_result { + utils::span_lint_and_then( + cx, + FUTURE_NOT_SEND, + span, + "future cannot be sent between threads safely", + |db| { + cx.tcx.infer_ctxt().enter(|infcx| { + for FulfillmentError { obligation, .. } in send_errors { + infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); + if let Trait(trait_pred, _) = obligation.predicate { + let trait_ref = trait_pred.to_poly_trait_ref(); + db.note(&*format!( + "`{}` doesn't implement `{}`", + trait_ref.self_ty(), + trait_ref.print_only_trait_path(), + )); + } + } + }) + }, + ); + } + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1158e70b7a3..a5b55d2ab70 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -218,6 +218,7 @@ mod floating_point_arithmetic; mod format; mod formatting; mod functions; +mod future_not_send; mod get_last_with_len; mod identity_conversion; mod identity_op; @@ -566,6 +567,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &functions::NOT_UNSAFE_PTR_ARG_DEREF, &functions::TOO_MANY_ARGUMENTS, &functions::TOO_MANY_LINES, + &future_not_send::FUTURE_NOT_SEND, &get_last_with_len::GET_LAST_WITH_LEN, &identity_conversion::IDENTITY_CONVERSION, &identity_op::IDENTITY_OP, @@ -1045,6 +1047,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_late_pass(|| box dereference::Dereferencing); + store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1689,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), + LintId::of(&future_not_send::FUTURE_NOT_SEND), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_INTEGER), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index d4602a3ad8e..cf2537e6d66 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -696,6 +696,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "drop_forget_ref", }, + Lint { + name: "future_not_send", + group: "nursery", + desc: "public Futures must be Send", + deprecation: None, + module: "future_not_send", + }, Lint { name: "get_last_with_len", group: "complexity", diff --git a/tests/ui/future_not_send.rs b/tests/ui/future_not_send.rs new file mode 100644 index 00000000000..6d09d71a630 --- /dev/null +++ b/tests/ui/future_not_send.rs @@ -0,0 +1,79 @@ +// edition:2018 +#![warn(clippy::future_not_send)] + +use std::cell::Cell; +use std::rc::Rc; +use std::sync::Arc; + +async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + async { true }.await +} + +pub async fn public_future(rc: Rc<[u8]>) { + async { true }.await; +} + +pub async fn public_send(arc: Arc<[u8]>) -> bool { + async { false }.await +} + +async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + true +} + +pub async fn public_future2(rc: Rc<[u8]>) {} + +pub async fn public_send2(arc: Arc<[u8]>) -> bool { + false +} + +struct Dummy { + rc: Rc<[u8]>, +} + +impl Dummy { + async fn private_future(&self) -> usize { + async { true }.await; + self.rc.len() + } + + pub async fn public_future(&self) { + self.private_future().await; + } + + pub fn public_send(&self) -> impl std::future::Future<Output = bool> { + async { false } + } +} + +async fn generic_future<T>(t: T) -> T +where + T: Send, +{ + let rt = &t; + async { true }.await; + t +} + +async fn generic_future_send<T>(t: T) +where + T: Send, +{ + async { true }.await; +} + +async fn unclear_future<T>(t: T) {} + +fn main() { + let rc = Rc::new([1, 2, 3]); + private_future(rc.clone(), &Cell::new(42)); + public_future(rc.clone()); + let arc = Arc::new([4, 5, 6]); + public_send(arc); + generic_future(42); + generic_future_send(42); + + let dummy = Dummy { rc }; + dummy.public_future(); + dummy.public_send(); +} diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr new file mode 100644 index 00000000000..3b4968ef0a6 --- /dev/null +++ b/tests/ui/future_not_send.stderr @@ -0,0 +1,125 @@ +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:8:62 + | +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + | ^^^^ future returned by `private_future` is not `Send` + | + = note: `-D clippy::future-not-send` implied by `-D warnings` +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:9:5 + | +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + | -- has type `std::rc::Rc<[u8]>` which is not `Send` +LL | async { true }.await + | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later +LL | } + | - `rc` is later dropped here + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:9:5 + | +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + | ---- has type `&std::cell::Cell<usize>` which is not `Send` +LL | async { true }.await + | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later +LL | } + | - `cell` is later dropped here + = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:12:42 + | +LL | pub async fn public_future(rc: Rc<[u8]>) { + | ^ future returned by `public_future` is not `Send` + | +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:13:5 + | +LL | pub async fn public_future(rc: Rc<[u8]>) { + | -- has type `std::rc::Rc<[u8]>` which is not `Send` +LL | async { true }.await; + | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later +LL | } + | - `rc` is later dropped here + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:20:63 + | +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { + | ^^^^ + | + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` + = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:24:43 + | +LL | pub async fn public_future2(rc: Rc<[u8]>) {} + | ^ + | + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:35:39 + | +LL | async fn private_future(&self) -> usize { + | ^^^^^ future returned by `private_future` is not `Send` + | +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:36:9 + | +LL | async fn private_future(&self) -> usize { + | ----- has type `&Dummy` which is not `Send` +LL | async { true }.await; + | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later +LL | self.rc.len() +LL | } + | - `&self` is later dropped here + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:40:39 + | +LL | pub async fn public_future(&self) { + | ^ future returned by `public_future` is not `Send` + | +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:41:9 + | +LL | pub async fn public_future(&self) { + | ----- has type `&Dummy` which is not `Send` +LL | self.private_future().await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later +LL | } + | - `&self` is later dropped here + = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:49:37 + | +LL | async fn generic_future<T>(t: T) -> T + | ^ future returned by `generic_future` is not `Send` + | +note: future is not `Send` as this value is used across an await + --> $DIR/future_not_send.rs:54:5 + | +LL | let rt = &t; + | -- has type `&T` which is not `Send` +LL | async { true }.await; + | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later +LL | t +LL | } + | - `rt` is later dropped here + = note: `T` doesn't implement `std::marker::Sync` + +error: future cannot be sent between threads safely + --> $DIR/future_not_send.rs:65:34 + | +LL | async fn unclear_future<T>(t: T) {} + | ^ + | + = note: `T` doesn't implement `std::marker::Send` + +error: aborting due to 8 previous errors + -- cgit 1.4.1-3-g733a5 From 7c52e51d79696ae99e4f8499bb51f81b464d5a1a Mon Sep 17 00:00:00 2001 From: pmk21 <prithvikrishna49@gmail.com> Date: Mon, 6 Apr 2020 23:37:57 +0530 Subject: Added basic lint and tests --- CHANGELOG.md | 1 + clippy_lints/src/implicit_saturating_sub.rs | 90 +++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 ++ src/lintlist/mod.rs | 7 +++ tests/ui/implicit_saturating_sub.rs | 21 +++++++ 5 files changed, 123 insertions(+) create mode 100644 clippy_lints/src/implicit_saturating_sub.rs create mode 100644 tests/ui/implicit_saturating_sub.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ad855d7f8..e513787a53a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1293,6 +1293,7 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs new file mode 100644 index 00000000000..e2dff92834d --- /dev/null +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -0,0 +1,90 @@ +use crate::utils::{higher, in_macro, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for implicit saturating subtraction. + /// + /// **Why is this bad?** Simplicity and readability. Instead we can easily use an inbuilt function. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let end = 10; + /// let start = 5; + /// + /// let mut i = end - start; + /// + /// // Bad + /// if i != 0 { + /// i -= 1; + /// } + /// ``` + /// Use instead: + /// ```rust + /// let end = 10; + /// let start = 5; + /// + /// let mut i = end - start; + /// + /// // Good + /// i.saturating_sub(1); + /// ``` + pub IMPLICIT_SATURATING_SUB, + pedantic, + "Perform saturating subtraction instead of implicitly checking lower bound of data type" +} + +declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitSaturatingSub { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) { + if in_macro(expr.span) { + return; + } + if_chain! { + if let Some((ref cond, ref then, None)) = higher::if_block(&expr); + // Check if the conditional expression is a binary operation + if let ExprKind::Binary(ref op, ref left, ref right) = cond.kind; + // Ensure that the binary operator is > or != + if BinOpKind::Ne == op.node || BinOpKind::Gt == op.node; + if let ExprKind::Path(ref cond_path) = left.kind; + // Get the literal on the right hand side + if let ExprKind::Lit(ref lit) = right.kind; + if let LitKind::Int(0, _) = lit.node; + // Check if the true condition block has only one statement + if let ExprKind::Block(ref block, _) = then.kind; + if block.stmts.len() == 1; + // Check if assign operation is done + if let StmtKind::Semi(ref e) = block.stmts[0].kind; + if let ExprKind::AssignOp(ref op1, ref target, ref value) = e.kind; + if BinOpKind::Sub == op1.node; + if let ExprKind::Path(ref assign_path) = target.kind; + // Check if the variable in the condition and assignment statement are the same + if let (QPath::Resolved(_, ref cres_path), QPath::Resolved(_, ref ares_path)) = (cond_path, assign_path); + if cres_path.res == ares_path.res; + if let ExprKind::Lit(ref lit1) = value.kind; + if let LitKind::Int(assign_lit, _) = lit1.node; + then { + // Get the variable name + let var_name = ares_path.segments[0].ident.name.as_str(); + let applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + IMPLICIT_SATURATING_SUB, + expr.span, + "Implicitly performing saturating subtraction", + "try", + format!("{}.saturating_sub({});", var_name, assign_lit.to_string()), + applicability + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a5b55d2ab70..b8415fa3af1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -225,6 +225,7 @@ mod identity_op; mod if_let_some_result; mod if_not_else; mod implicit_return; +mod implicit_saturating_sub; mod indexing_slicing; mod infinite_iter; mod inherent_impl; @@ -574,6 +575,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &if_let_some_result::IF_LET_SOME_RESULT, &if_not_else::IF_NOT_ELSE, &implicit_return::IMPLICIT_RETURN, + &implicit_saturating_sub::IMPLICIT_SATURATING_SUB, &indexing_slicing::INDEXING_SLICING, &indexing_slicing::OUT_OF_BOUNDS_INDEXING, &infinite_iter::INFINITE_ITER, @@ -888,6 +890,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unicode::Unicode); store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); + store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); store.register_late_pass(|| box methods::Methods); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box shadow::Shadow); @@ -1111,6 +1114,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&functions::MUST_USE_CANDIDATE), LintId::of(&functions::TOO_MANY_LINES), LintId::of(&if_not_else::IF_NOT_ELSE), + LintId::of(&implicit_saturating_sub::IMPLICIT_SATURATING_SUB), LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index cf2537e6d66..213d054e403 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -773,6 +773,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "implicit_return", }, + Lint { + name: "implicit_saturating_sub", + group: "pedantic", + desc: "Perform saturating subtraction instead of implicitly checking lower bound of data type", + deprecation: None, + module: "implicit_saturating_sub", + }, Lint { name: "imprecise_flops", group: "nursery", diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs new file mode 100644 index 00000000000..c1cc00bb685 --- /dev/null +++ b/tests/ui/implicit_saturating_sub.rs @@ -0,0 +1,21 @@ +#![warn(clippy::implicit_saturating_sub)] + +fn main() { + let mut end = 10; + let mut start = 5; + let mut i: u32 = end - start; + + if i > 0 { + i -= 1; + } + + match end { + 10 => { + if i > 0 { + i -= 1; + } + }, + 11 => i += 1, + _ => i = 0, + } +} -- cgit 1.4.1-3-g733a5 From 00b4f2819fa4786bb54bd2c4091767f64268d528 Mon Sep 17 00:00:00 2001 From: Eduardo Broto <ebroto@tutanota.com> Date: Sun, 19 Apr 2020 23:11:30 +0200 Subject: Implement unsafe_derive_deserialize lint --- CHANGELOG.md | 1 + clippy_lints/src/derive.rs | 158 ++++++++++++++++++++++++++++-- clippy_lints/src/lib.rs | 3 + clippy_lints/src/utils/diagnostics.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 7 ++ tests/ui/unsafe_derive_deserialize.rs | 60 ++++++++++++ tests/ui/unsafe_derive_deserialize.stderr | 39 ++++++++ 9 files changed, 263 insertions(+), 10 deletions(-) create mode 100644 tests/ui/unsafe_derive_deserialize.rs create mode 100644 tests/ui/unsafe_derive_deserialize.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index e513787a53a..b97452873a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1524,6 +1524,7 @@ Released 2018-09-13 [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal +[`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index f5a358d424f..2f7d30674e1 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -1,8 +1,13 @@ use crate::utils::paths; -use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_note, span_lint_and_then}; +use crate::utils::{ + is_automatically_derived, is_copy, match_path, span_lint_and_help, span_lint_and_note, span_lint_and_then, +}; use if_chain::if_chain; -use rustc_hir::{Item, ItemKind, TraitRef}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -62,11 +67,45 @@ declare_clippy_lint! { "implementing `Clone` explicitly on `Copy` types" } -declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ]); +declare_clippy_lint! { + /// **What it does:** Checks for deriving `serde::Deserialize` on a type that + /// has methods using `unsafe`. + /// + /// **Why is this bad?** Deriving `serde::Deserialize` will create a constructor + /// that may violate invariants hold by another constructor. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// use serde::Deserialize; + /// + /// #[derive(Deserialize)] + /// pub struct Foo { + /// // .. + /// } + /// + /// impl Foo { + /// pub fn new() -> Self { + /// // setup here .. + /// } + /// + /// pub unsafe fn parts() -> (&str, &str) { + /// // assumes invariants hold + /// } + /// } + /// ``` + pub UNSAFE_DERIVE_DESERIALIZE, + correctness, + "deriving `serde::Deserialize` on a type that has methods using `unsafe`" +} + +declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ, UNSAFE_DERIVE_DESERIALIZE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) { + if let hir::ItemKind::Impl { of_trait: Some(ref trait_ref), .. } = item.kind @@ -76,7 +115,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); - if !is_automatically_derived { + if is_automatically_derived { + check_unsafe_derive_deserialize(cx, item, trait_ref, ty); + } else { check_copy_clone(cx, item, trait_ref, ty); } } @@ -87,7 +128,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { fn check_hash_peq<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, span: Span, - trait_ref: &TraitRef<'_>, + trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>, hash_is_automatically_derived: bool, ) { @@ -134,7 +175,12 @@ fn check_hash_peq<'a, 'tcx>( } /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. -fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) { +fn check_copy_clone<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + item: &hir::Item<'_>, + trait_ref: &hir::TraitRef<'_>, + ty: Ty<'tcx>, +) { if match_path(&trait_ref.path, &paths::CLONE_TRAIT) { if !is_copy(cx, ty) { return; @@ -173,3 +219,99 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item<'_>, trait ); } } + +/// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint. +fn check_unsafe_derive_deserialize<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + item: &hir::Item<'_>, + trait_ref: &hir::TraitRef<'_>, + ty: Ty<'tcx>, +) { + fn item_from_def_id<'tcx>(cx: &LateContext<'_, 'tcx>, def_id: DefId) -> &'tcx hir::Item<'tcx> { + let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap(); + cx.tcx.hir().expect_item(hir_id) + } + + fn has_unsafe<'tcx>(cx: &LateContext<'_, 'tcx>, item: &'tcx hir::Item<'_>) -> bool { + let mut visitor = UnsafeVisitor { cx, has_unsafe: false }; + walk_item(&mut visitor, item); + visitor.has_unsafe + } + + if_chain! { + if match_path(&trait_ref.path, &paths::SERDE_DESERIALIZE); + if let ty::Adt(def, _) = ty.kind; + if def.did.is_local(); + if cx.tcx.inherent_impls(def.did) + .iter() + .map(|imp_did| item_from_def_id(cx, *imp_did)) + .any(|imp| has_unsafe(cx, imp)); + then { + span_lint_and_help( + cx, + UNSAFE_DERIVE_DESERIALIZE, + item.span, + "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`", + None, + "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html" + ); + } + } +} + +struct UnsafeVisitor<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + has_unsafe: bool, +} + +impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { + type Map = Map<'tcx>; + + fn visit_fn( + &mut self, + kind: FnKind<'tcx>, + decl: &'tcx hir::FnDecl<'_>, + body_id: hir::BodyId, + span: Span, + id: hir::HirId, + ) { + if self.has_unsafe { + return; + } + + if_chain! { + if let Some(header) = kind.header(); + if let hir::Unsafety::Unsafe = header.unsafety; + then { + self.has_unsafe = true; + } + } + + walk_fn(self, kind, decl, body_id, span, id); + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + if self.has_unsafe { + return; + } + + if let hir::ExprKind::Block(block, _) = expr.kind { + use hir::{BlockCheckMode, UnsafeSource}; + + match block.rules { + BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + | BlockCheckMode::PushUnsafeBlock(UnsafeSource::UserProvided) + | BlockCheckMode::PopUnsafeBlock(UnsafeSource::UserProvided) => { + self.has_unsafe = true; + }, + _ => {}, + } + } + + walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::All(self.cx.tcx.hir()) + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 19c46476263..d105afe5931 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -520,6 +520,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &dereference::EXPLICIT_DEREF_METHODS, &derive::DERIVE_HASH_XOR_EQ, &derive::EXPL_IMPL_CLONE_ON_COPY, + &derive::UNSAFE_DERIVE_DESERIALIZE, &doc::DOC_MARKDOWN, &doc::MISSING_ERRORS_DOC, &doc::MISSING_SAFETY_DOC, @@ -1196,6 +1197,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), LintId::of(&derive::DERIVE_HASH_XOR_EQ), + LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&doc::MISSING_SAFETY_DOC), LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), LintId::of(&double_comparison::DOUBLE_COMPARISONS), @@ -1608,6 +1610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), LintId::of(&derive::DERIVE_HASH_XOR_EQ), + LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&drop_bounds::DROP_BOUNDS), LintId::of(&drop_forget_ref::DROP_COPY), LintId::of(&drop_forget_ref::DROP_REF), diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 093ef319108..24a1bdf1883 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -49,7 +49,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult /// Use this if you want to provide some general help but /// can't provide a specific machine applicable suggestion. /// -/// The `help` message is not attached to any `Span`. +/// The `help` message can be optionally attached to a `Span`. /// /// # Example /// diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f7a91fcdd21..a0543a8dcf9 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -241,7 +241,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { /// /// # Examples /// ```rust,ignore -/// match_qpath(path, &["std", "rt", "begin_unwind"]) +/// match_path_ast(path, &["std", "rt", "begin_unwind"]) /// ``` pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { path.segments diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index d93f8a1e560..f85845be56d 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -108,6 +108,7 @@ pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"]; pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"]; +pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"]; pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 213d054e403..c7c851a8032 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2334,6 +2334,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "literal_representation", }, + Lint { + name: "unsafe_derive_deserialize", + group: "correctness", + desc: "deriving `serde::Deserialize` on a type that has methods using `unsafe`", + deprecation: None, + module: "derive", + }, Lint { name: "unsafe_removed_from_name", group: "style", diff --git a/tests/ui/unsafe_derive_deserialize.rs b/tests/ui/unsafe_derive_deserialize.rs new file mode 100644 index 00000000000..7bee9c499e1 --- /dev/null +++ b/tests/ui/unsafe_derive_deserialize.rs @@ -0,0 +1,60 @@ +#![warn(clippy::unsafe_derive_deserialize)] +#![allow(unused, clippy::missing_safety_doc)] + +extern crate serde; + +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct A {} +impl A { + pub unsafe fn new(_a: i32, _b: i32) -> Self { + Self {} + } +} + +#[derive(Deserialize)] +pub struct B {} +impl B { + pub unsafe fn unsafe_method(&self) {} +} + +#[derive(Deserialize)] +pub struct C {} +impl C { + pub fn unsafe_block(&self) { + unsafe {} + } +} + +#[derive(Deserialize)] +pub struct D {} +impl D { + pub fn inner_unsafe_fn(&self) { + unsafe fn inner() {} + } +} + +// Does not derive `Deserialize`, should be ignored +pub struct E {} +impl E { + pub unsafe fn new(_a: i32, _b: i32) -> Self { + Self {} + } + + pub unsafe fn unsafe_method(&self) {} + + pub fn unsafe_block(&self) { + unsafe {} + } + + pub fn inner_unsafe_fn(&self) { + unsafe fn inner() {} + } +} + +// Does not have methods using `unsafe`, should be ignored +#[derive(Deserialize)] +pub struct F {} + +fn main() {} diff --git a/tests/ui/unsafe_derive_deserialize.stderr b/tests/ui/unsafe_derive_deserialize.stderr new file mode 100644 index 00000000000..1978bd95a67 --- /dev/null +++ b/tests/ui/unsafe_derive_deserialize.stderr @@ -0,0 +1,39 @@ +error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` + --> $DIR/unsafe_derive_deserialize.rs:8:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings` + = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` + --> $DIR/unsafe_derive_deserialize.rs:16:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` + --> $DIR/unsafe_derive_deserialize.rs:22:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe` + --> $DIR/unsafe_derive_deserialize.rs:30:10 + | +LL | #[derive(Deserialize)] + | ^^^^^^^^^^^ + | + = help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 001a42e632573abca10b2f8272f50a3999846e70 Mon Sep 17 00:00:00 2001 From: Devin R <devin.ragotzy@gmail.com> Date: Thu, 5 Mar 2020 08:36:19 -0500 Subject: progress work on suggestion for auto fix --- CHANGELOG.md | 1 + clippy_lints/src/if_let_mutex.rs | 135 +++++++++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 5 ++ src/lintlist/mod.rs | 7 ++ tests/ui/if_let_mutex.rs | 16 +++++ 5 files changed, 164 insertions(+) create mode 100644 clippy_lints/src/if_let_mutex.rs create mode 100644 tests/ui/if_let_mutex.rs (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index e513787a53a..2668c89bdc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1286,6 +1286,7 @@ Released 2018-09-13 [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching [`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs new file mode 100644 index 00000000000..34f0b22f65e --- /dev/null +++ b/clippy_lints/src/if_let_mutex.rs @@ -0,0 +1,135 @@ +use crate::utils::{ + match_type, method_calls, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc::ty; +use rustc_errors::Applicability; +use rustc_hir::{print, Expr, ExprKind, MatchSource, PatKind, QPath, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for `Mutex::lock` calls in `if let` expression + /// with lock calls in any of the else blocks. + /// + /// **Why is this bad?** The Mutex lock remains held for the whole + /// `if let ... else` block and deadlocks. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # use std::sync::Mutex; + /// let mutex = Mutex::new(10); + /// if let Ok(thing) = mutex.lock() { + /// do_thing(); + /// } else { + /// mutex.lock(); + /// } + /// ``` + pub IF_LET_MUTEX, + correctness, + "locking a `Mutex` in an `if let` block can cause deadlock" +} + +declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); + +impl LateLintPass<'_, '_> for IfLetMutex { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, ex: &'_ Expr<'_>) { + if_chain! { + if let ExprKind::Match(ref op, ref arms, MatchSource::IfLetDesugar { + contains_else_clause: true, + }) = ex.kind; // if let ... {} else {} + if let ExprKind::MethodCall(_, _, ref args) = op.kind; + let ty = cx.tables.expr_ty(&args[0]); + if let ty::Adt(_, subst) = ty.kind; + if match_type(cx, ty, &paths::MUTEX); // make sure receiver is Mutex + if method_chain_names(op, 10).iter().any(|s| s == "lock"); // and lock is called + + let mut suggestion = String::from(&format!("if let _ = {} {{\n", snippet(cx, op.span, "_"))); + + if arms.iter().any(|arm| if_chain! { + if let ExprKind::Block(ref block, _l) = arm.body.kind; + if block.stmts.iter().any(|stmt| match stmt.kind { + StmtKind::Local(l) => if_chain! { + if let Some(ex) = l.init; + if let ExprKind::MethodCall(_, _, ref args) = op.kind; + if method_chain_names(ex, 10).iter().any(|s| s == "lock"); // and lock is called + then { + let ty = cx.tables.expr_ty(&args[0]); + // // make sure receiver is Result<MutexGuard<...>> + match_type(cx, ty, &paths::RESULT) + } else { + suggestion.push_str(&format!(" {}\n", snippet(cx, l.span, "_"))); + false + } + }, + StmtKind::Expr(e) => if_chain! { + if let ExprKind::MethodCall(_, _, ref args) = e.kind; + if method_chain_names(e, 10).iter().any(|s| s == "lock"); // and lock is called + then { + let ty = cx.tables.expr_ty(&args[0]); + // // make sure receiver is Result<MutexGuard<...>> + match_type(cx, ty, &paths::RESULT) + } else { + suggestion.push_str(&format!(" {}\n", snippet(cx, e.span, "_"))); + false + } + }, + StmtKind::Semi(e) => if_chain! { + if let ExprKind::MethodCall(_, _, ref args) = e.kind; + if method_chain_names(e, 10).iter().any(|s| s == "lock"); // and lock is called + then { + let ty = cx.tables.expr_ty(&args[0]); + // // make sure receiver is Result<MutexGuard<...>> + match_type(cx, ty, &paths::RESULT) + } else { + suggestion.push_str(&format!(" {}\n", snippet(cx, e.span, "_"))); + false + } + }, + _ => { suggestion.push_str(&format!(" {}\n", snippet(cx, stmt.span, "_"))); false }, + }); + then { + true + } else { + suggestion.push_str(&format!("else {}\n", snippet(cx, arm.span, "_"))); + false + } + }); + then { + println!("{}", suggestion); + span_lint_and_sugg( + cx, + IF_LET_MUTEX, + ex.span, + "using a `Mutex` in inner scope of `.lock` call", + "try", + format!("{:?}", "hello"), + Applicability::MachineApplicable, + ); + } + } + } +} + +fn method_chain_names<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> Vec<String> { + let mut method_names = Vec::with_capacity(max_depth); + + let mut current = expr; + for _ in 0..max_depth { + if let ExprKind::MethodCall(path, span, args) = ¤t.kind { + if args.iter().any(|e| e.span.from_expansion()) { + break; + } + method_names.push(path.ident.to_string()); + println!("{:?}", method_names); + current = &args[0]; + } else { + break; + } + } + + method_names +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 19c46476263..819230b6a61 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -222,6 +222,7 @@ mod future_not_send; mod get_last_with_len; mod identity_conversion; mod identity_op; +mod if_let_mutex; mod if_let_some_result; mod if_not_else; mod implicit_return; @@ -572,6 +573,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &get_last_with_len::GET_LAST_WITH_LEN, &identity_conversion::IDENTITY_CONVERSION, &identity_op::IDENTITY_OP, + &if_let_mutex::IF_LET_MUTEX, &if_let_some_result::IF_LET_SOME_RESULT, &if_not_else::IF_NOT_ELSE, &implicit_return::IMPLICIT_RETURN, @@ -1053,6 +1055,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); + store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1231,6 +1234,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), LintId::of(&identity_conversion::IDENTITY_CONVERSION), LintId::of(&identity_op::IDENTITY_OP), + LintId::of(&if_let_mutex::IF_LET_MUTEX), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(&infinite_iter::INFINITE_ITER), @@ -1618,6 +1622,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&erasing_op::ERASING_OP), LintId::of(&formatting::POSSIBLE_MISSING_COMMA), LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(&if_let_mutex::IF_LET_MUTEX), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(&infinite_iter::INFINITE_ITER), LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 213d054e403..229fd3ac824 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -731,6 +731,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "identity_op", }, + Lint { + name: "if_let_mutex", + group: "correctness", + desc: "default lint description", + deprecation: None, + module: "if_let_mutex", + }, Lint { name: "if_let_some_result", group: "style", diff --git a/tests/ui/if_let_mutex.rs b/tests/ui/if_let_mutex.rs new file mode 100644 index 00000000000..13fe44eed2c --- /dev/null +++ b/tests/ui/if_let_mutex.rs @@ -0,0 +1,16 @@ +#![warn(clippy::if_let_mutex)] + +use std::sync::Mutex; + +fn do_stuff() {} +fn foo() { + let m = Mutex::new(1u8); + + if let Ok(locked) = m.lock() { + do_stuff(); + } else { + m.lock().unwrap(); + }; +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 40bbdffc89edb4c3841a8b23c41d4092206e940c Mon Sep 17 00:00:00 2001 From: Devin R <devin.ragotzy@gmail.com> Date: Tue, 17 Mar 2020 21:51:43 -0400 Subject: use span_lint_and_help, cargo dev fmt --- clippy_lints/src/if_let_mutex.rs | 82 ++++++++++++++++++++-------------------- src/lintlist/mod.rs | 2 +- tests/ui/if_let_mutex.rs | 9 +++-- tests/ui/if_let_mutex.stderr | 16 ++++++++ 4 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 tests/ui/if_let_mutex.stderr (limited to 'src') diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 52e5b12c933..2238821ab70 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,10 +1,6 @@ -use crate::utils::{ - match_type, method_calls, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg, -}; +use crate::utils::{match_type, paths, span_lint_and_help}; use if_chain::if_chain; -use rustc::ty; -use rustc_errors::Applicability; -use rustc_hir::{print, Expr, ExprKind, MatchSource, PatKind, QPath, StmtKind}; +use rustc_hir::{Expr, ExprKind, MatchSource, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -15,19 +11,26 @@ declare_clippy_lint! { /// **Why is this bad?** The Mutex lock remains held for the whole /// `if let ... else` block and deadlocks. /// - /// **Known problems:** None. + /// **Known problems:** This lint does not generate an auto-applicable suggestion. /// /// **Example:** /// - /// ```rust - /// # use std::sync::Mutex; - /// let mutex = Mutex::new(10); + /// ```rust,ignore /// if let Ok(thing) = mutex.lock() { /// do_thing(); /// } else { /// mutex.lock(); /// } /// ``` + /// Should be written + /// ```rust,ignore + /// let locked = mutex.lock(); + /// if let Ok(thing) = locked { + /// do_thing(thing); + /// } else { + /// use_locked(locked); + /// } + /// ``` pub IF_LET_MUTEX, correctness, "locking a `Mutex` in an `if let` block can cause deadlocks" @@ -43,93 +46,92 @@ impl LateLintPass<'_, '_> for IfLetMutex { }) = ex.kind; // if let ... {} else {} if let ExprKind::MethodCall(_, _, ref args) = op.kind; let ty = cx.tables.expr_ty(&args[0]); - if let ty::Adt(_, subst) = ty.kind; if match_type(cx, ty, &paths::MUTEX); // make sure receiver is Mutex if method_chain_names(op, 10).iter().any(|s| s == "lock"); // and lock is called - let mut suggestion = String::from(&format!("if let _ = {} {{\n", snippet(cx, op.span, "_"))); - if arms.iter().any(|arm| if_chain! { if let ExprKind::Block(ref block, _l) = arm.body.kind; if block.stmts.iter().any(|stmt| match stmt.kind { StmtKind::Local(l) => if_chain! { if let Some(ex) = l.init; - if let ExprKind::MethodCall(_, _, ref args) = op.kind; + if let ExprKind::MethodCall(_, _, _) = op.kind; if method_chain_names(ex, 10).iter().any(|s| s == "lock"); // and lock is called then { - let ty = cx.tables.expr_ty(&args[0]); - // // make sure receiver is Result<MutexGuard<...>> - match_type(cx, ty, &paths::RESULT) + match_type_method_chain(cx, ex, 5) } else { - suggestion.push_str(&format!(" {}\n", snippet(cx, l.span, "_"))); false } }, StmtKind::Expr(e) => if_chain! { - if let ExprKind::MethodCall(_, _, ref args) = e.kind; + if let ExprKind::MethodCall(_, _, _) = e.kind; if method_chain_names(e, 10).iter().any(|s| s == "lock"); // and lock is called then { - let ty = cx.tables.expr_ty(&args[0]); - // // make sure receiver is Result<MutexGuard<...>> - match_type(cx, ty, &paths::RESULT) + match_type_method_chain(cx, ex, 5) } else { - suggestion.push_str(&format!(" {}\n", snippet(cx, e.span, "_"))); false } }, StmtKind::Semi(e) => if_chain! { - if let ExprKind::MethodCall(_, _, ref args) = e.kind; + if let ExprKind::MethodCall(_, _, _) = e.kind; if method_chain_names(e, 10).iter().any(|s| s == "lock"); // and lock is called then { - let ty = cx.tables.expr_ty(&args[0]); - // // make sure receiver is Result<MutexGuard<...>> - match_type(cx, ty, &paths::RESULT) + match_type_method_chain(cx, ex, 5) } else { - suggestion.push_str(&format!(" {}\n", snippet(cx, e.span, "_"))); false } }, - _ => { suggestion.push_str(&format!(" {}\n", snippet(cx, stmt.span, "_"))); false }, + _ => { + false + }, }); then { true } else { - suggestion.push_str(&format!("else {}\n", snippet(cx, arm.span, "_"))); false } }); then { - println!("{}", suggestion); - span_lint_and_sugg( + span_lint_and_help( cx, IF_LET_MUTEX, ex.span, - "using a `Mutex` in inner scope of `.lock` call", - "try", - format!("{:?}", "hello"), - Applicability::MachineApplicable, + "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock", + "move the lock call outside of the `if let ...` expression", ); } } } } +/// Return the names of `max_depth` number of methods called in the chain. fn method_chain_names<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> Vec<String> { let mut method_names = Vec::with_capacity(max_depth); - let mut current = expr; for _ in 0..max_depth { - if let ExprKind::MethodCall(path, span, args) = ¤t.kind { + if let ExprKind::MethodCall(path, _, args) = ¤t.kind { if args.iter().any(|e| e.span.from_expansion()) { break; } method_names.push(path.ident.to_string()); - println!("{:?}", method_names); current = &args[0]; } else { break; } } - method_names } + +/// Check that lock is called on a `Mutex`. +fn match_type_method_chain<'tcx>(cx: &LateContext<'_, '_>, expr: &'tcx Expr<'tcx>, max_depth: usize) -> bool { + let mut current = expr; + for _ in 0..max_depth { + if let ExprKind::MethodCall(_, _, args) = ¤t.kind { + let ty = cx.tables.expr_ty(&args[0]); + if match_type(cx, ty, &paths::MUTEX) { + return true; + } + current = &args[0]; + } + } + false +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 229fd3ac824..6088f9b9ef8 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -734,7 +734,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "if_let_mutex", group: "correctness", - desc: "default lint description", + desc: "locking a `Mutex` in an `if let` block can cause deadlocks", deprecation: None, module: "if_let_mutex", }, diff --git a/tests/ui/if_let_mutex.rs b/tests/ui/if_let_mutex.rs index 13fe44eed2c..059764e9b21 100644 --- a/tests/ui/if_let_mutex.rs +++ b/tests/ui/if_let_mutex.rs @@ -2,14 +2,15 @@ use std::sync::Mutex; -fn do_stuff() {} +fn do_stuff<T>(_: T) {} fn foo() { let m = Mutex::new(1u8); - if let Ok(locked) = m.lock() { - do_stuff(); + if let Err(locked) = m.lock() { + do_stuff(locked); } else { - m.lock().unwrap(); + let lock = m.lock().unwrap(); + do_stuff(lock); }; } diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr new file mode 100644 index 00000000000..84c19ed03d5 --- /dev/null +++ b/tests/ui/if_let_mutex.stderr @@ -0,0 +1,16 @@ +error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock + --> $DIR/if_let_mutex.rs:9:5 + | +LL | / if let Err(locked) = m.lock() { +LL | | do_stuff(locked); +LL | | } else { +LL | | let lock = m.lock().unwrap(); +LL | | do_stuff(lock); +LL | | }; + | |_____^ + | + = note: `-D clippy::if-let-mutex` implied by `-D warnings` + = help: move the lock call outside of the `if let ...` expression + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From b7f85e8706b1cafa02868c853ed5c05550ef2ffe Mon Sep 17 00:00:00 2001 From: Eduardo Broto <ebroto@tutanota.com> Date: Mon, 20 Apr 2020 20:05:15 +0200 Subject: Apply suggestions from PR review * Move the lint to pedantic * Import used types instead of prefixing with `hir::` --- clippy_lints/src/derive.rs | 44 ++++++++++++++++---------------------------- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 2 +- 3 files changed, 18 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 2f7d30674e1..16300db0974 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -3,9 +3,11 @@ use crate::utils::{ is_automatically_derived, is_copy, match_path, span_lint_and_help, span_lint_and_note, span_lint_and_then, }; use if_chain::if_chain; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{ + BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, TraitRef, UnsafeSource, Unsafety, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty::{self, Ty}; @@ -97,15 +99,15 @@ declare_clippy_lint! { /// } /// ``` pub UNSAFE_DERIVE_DESERIALIZE, - correctness, + pedantic, "deriving `serde::Deserialize` on a type that has methods using `unsafe`" } declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ, UNSAFE_DERIVE_DESERIALIZE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { - fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) { - if let hir::ItemKind::Impl { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) { + if let ItemKind::Impl { of_trait: Some(ref trait_ref), .. } = item.kind @@ -128,7 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive { fn check_hash_peq<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, span: Span, - trait_ref: &hir::TraitRef<'_>, + trait_ref: &TraitRef<'_>, ty: Ty<'tcx>, hash_is_automatically_derived: bool, ) { @@ -175,12 +177,7 @@ fn check_hash_peq<'a, 'tcx>( } /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. -fn check_copy_clone<'a, 'tcx>( - cx: &LateContext<'a, 'tcx>, - item: &hir::Item<'_>, - trait_ref: &hir::TraitRef<'_>, - ty: Ty<'tcx>, -) { +fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) { if match_path(&trait_ref.path, &paths::CLONE_TRAIT) { if !is_copy(cx, ty) { return; @@ -223,16 +220,16 @@ fn check_copy_clone<'a, 'tcx>( /// Implementation of the `UNSAFE_DERIVE_DESERIALIZE` lint. fn check_unsafe_derive_deserialize<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - item: &hir::Item<'_>, - trait_ref: &hir::TraitRef<'_>, + item: &Item<'_>, + trait_ref: &TraitRef<'_>, ty: Ty<'tcx>, ) { - fn item_from_def_id<'tcx>(cx: &LateContext<'_, 'tcx>, def_id: DefId) -> &'tcx hir::Item<'tcx> { + fn item_from_def_id<'tcx>(cx: &LateContext<'_, 'tcx>, def_id: DefId) -> &'tcx Item<'tcx> { let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap(); cx.tcx.hir().expect_item(hir_id) } - fn has_unsafe<'tcx>(cx: &LateContext<'_, 'tcx>, item: &'tcx hir::Item<'_>) -> bool { + fn has_unsafe<'tcx>(cx: &LateContext<'_, 'tcx>, item: &'tcx Item<'_>) -> bool { let mut visitor = UnsafeVisitor { cx, has_unsafe: false }; walk_item(&mut visitor, item); visitor.has_unsafe @@ -267,21 +264,14 @@ struct UnsafeVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { type Map = Map<'tcx>; - fn visit_fn( - &mut self, - kind: FnKind<'tcx>, - decl: &'tcx hir::FnDecl<'_>, - body_id: hir::BodyId, - span: Span, - id: hir::HirId, - ) { + fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, span: Span, id: HirId) { if self.has_unsafe { return; } if_chain! { if let Some(header) = kind.header(); - if let hir::Unsafety::Unsafe = header.unsafety; + if let Unsafety::Unsafe = header.unsafety; then { self.has_unsafe = true; } @@ -290,14 +280,12 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { walk_fn(self, kind, decl, body_id, span, id); } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if self.has_unsafe { return; } - if let hir::ExprKind::Block(block, _) = expr.kind { - use hir::{BlockCheckMode, UnsafeSource}; - + if let ExprKind::Block(block, _) = expr.kind { match block.rules { BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) | BlockCheckMode::PushUnsafeBlock(UnsafeSource::UserProvided) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d105afe5931..c04e0884b19 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1106,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), LintId::of(&dereference::EXPLICIT_DEREF_METHODS), LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), + LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&doc::DOC_MARKDOWN), LintId::of(&doc::MISSING_ERRORS_DOC), LintId::of(&empty_enum::EMPTY_ENUM), @@ -1197,7 +1198,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), LintId::of(&derive::DERIVE_HASH_XOR_EQ), - LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&doc::MISSING_SAFETY_DOC), LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), LintId::of(&double_comparison::DOUBLE_COMPARISONS), @@ -1610,7 +1610,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), LintId::of(&derive::DERIVE_HASH_XOR_EQ), - LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), LintId::of(&drop_bounds::DROP_BOUNDS), LintId::of(&drop_forget_ref::DROP_COPY), LintId::of(&drop_forget_ref::DROP_REF), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c7c851a8032..9b3f0d7182b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2336,7 +2336,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "unsafe_derive_deserialize", - group: "correctness", + group: "pedantic", desc: "deriving `serde::Deserialize` on a type that has methods using `unsafe`", deprecation: None, module: "derive", -- cgit 1.4.1-3-g733a5 From 6c25c3c381ccfa0bf9b7bc7386a09cc4421fd790 Mon Sep 17 00:00:00 2001 From: Andy Weiss <dragonbear@google.com> Date: Tue, 7 Apr 2020 21:20:37 -0700 Subject: Lint for holding locks across await points Fixes #4226 This introduces the lint await_holding_lock. For async functions, we iterate over all types in generator_interior_types and look for types named MutexGuard, RwLockReadGuard, or RwLockWriteGuard. If we find one then we emit a lint. --- CHANGELOG.md | 1 + clippy_lints/src/await_holding_lock.rs | 100 +++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 4 ++ src/lintlist/mod.rs | 7 +++ tests/ui/await_holding_lock.rs | 42 ++++++++++++++ tests/ui/await_holding_lock.stderr | 35 ++++++++++++ 6 files changed, 189 insertions(+) create mode 100644 clippy_lints/src/await_holding_lock.rs create mode 100644 tests/ui/await_holding_lock.rs create mode 100644 tests/ui/await_holding_lock.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index d244f8aa167..abd7167502b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1188,6 +1188,7 @@ Released 2018-09-13 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name [`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs new file mode 100644 index 00000000000..ae4c5bfc9f7 --- /dev/null +++ b/clippy_lints/src/await_holding_lock.rs @@ -0,0 +1,100 @@ +use crate::utils::span_lint_and_note; +use if_chain::if_chain; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl, HirId, IsAsync}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{Span, Symbol}; + +declare_clippy_lint! { + /// **What it does:** Checks for calls to await while holding a MutexGuard. + /// + /// **Why is this bad?** This is almost certainly an error which can result + /// in a deadlock because the reactor will invoke code not visible to the + /// currently visible scope. + /// + /// **Known problems:** Detects only specifically named guard types: + /// MutexGuard, RwLockReadGuard, and RwLockWriteGuard. + /// + /// **Example:** + /// + /// ```rust + /// use std::sync::Mutex; + /// + /// async fn foo(x: &Mutex<u32>) { + /// let guard = x.lock().unwrap(); + /// *guard += 1; + /// bar.await; + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::sync::Mutex; + /// + /// async fn foo(x: &Mutex<u32>) { + /// { + /// let guard = x.lock().unwrap(); + /// *guard += 1; + /// } + /// bar.await; + /// } + /// ``` + pub AWAIT_HOLDING_LOCK, + pedantic, + "Inside an async function, holding a MutexGuard while calling await" +} + +const MUTEX_GUARD_TYPES: [&str; 3] = ["MutexGuard", "RwLockReadGuard", "RwLockWriteGuard"]; + +declare_lint_pass!(AwaitHoldingLock => [AWAIT_HOLDING_LOCK]); + +impl LateLintPass<'_, '_> for AwaitHoldingLock { + fn check_fn( + &mut self, + cx: &LateContext<'_, '_>, + fn_kind: FnKind<'_>, + _: &FnDecl<'_>, + _: &Body<'_>, + span: Span, + _: HirId, + ) { + if !is_async_fn(fn_kind) { + return; + } + + for ty_clause in &cx.tables.generator_interior_types { + if_chain! { + if let rustc_middle::ty::Adt(adt, _) = ty_clause.ty.kind; + if let Some(&sym) = cx.get_def_path(adt.did).iter().last(); + if is_symbol_mutex_guard(sym); + then { + span_lint_and_note( + cx, + AWAIT_HOLDING_LOCK, + ty_clause.span, + "this MutexGuard is held across an 'await' point", + ty_clause.scope_span.unwrap_or(span), + "these are all the await points this lock is held through" + ); + } + } + } + } +} + +fn is_async_fn(fn_kind: FnKind<'_>) -> bool { + fn_kind.header().map_or(false, |h| match h.asyncness { + IsAsync::Async => true, + IsAsync::NotAsync => false, + }) +} + +fn is_symbol_mutex_guard(sym: Symbol) -> bool { + let sym_str = sym.as_str(); + for ty in &MUTEX_GUARD_TYPES { + if sym_str == *ty { + return true; + } + } + false +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f3f73835e84..dee4188b75f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -177,6 +177,7 @@ mod assertions_on_constants; mod assign_ops; mod atomic_ordering; mod attrs; +mod await_holding_lock; mod bit_mask; mod blacklisted_name; mod block_in_if_condition; @@ -497,6 +498,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &attrs::INLINE_ALWAYS, &attrs::UNKNOWN_CLIPPY_LINTS, &attrs::USELESS_ATTRIBUTE, + &await_holding_lock::AWAIT_HOLDING_LOCK, &bit_mask::BAD_BIT_MASK, &bit_mask::INEFFECTIVE_BIT_MASK, &bit_mask::VERBOSE_BIT_MASK, @@ -864,6 +866,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ]); // end register lints, do not remove this comment, it’s used in `update_lints` + store.register_late_pass(|| box await_holding_lock::AwaitHoldingLock); store.register_late_pass(|| box serde_api::SerdeAPI); store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); @@ -1102,6 +1105,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), + LintId::of(&await_holding_lock::AWAIT_HOLDING_LOCK), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::MATCH_SAME_ARMS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 95931be7341..2c466aa20c6 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -52,6 +52,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "assign_ops", }, + Lint { + name: "await_holding_lock", + group: "pedantic", + desc: "Inside an async function, holding a MutexGuard while calling await", + deprecation: None, + module: "await_holding_lock", + }, Lint { name: "bad_bit_mask", group: "correctness", diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs new file mode 100644 index 00000000000..fab31f37ffc --- /dev/null +++ b/tests/ui/await_holding_lock.rs @@ -0,0 +1,42 @@ +// edition:2018 +#![warn(clippy::await_holding_lock)] + +use std::sync::Mutex; + +async fn bad(x: &Mutex<u32>) -> u32 { + let guard = x.lock().unwrap(); + baz().await +} + +async fn good(x: &Mutex<u32>) -> u32 { + { + let guard = x.lock().unwrap(); + let y = *guard + 1; + } + baz().await; + let guard = x.lock().unwrap(); + 47 +} + +async fn baz() -> u32 { + 42 +} + +async fn also_bad(x: &Mutex<u32>) -> u32 { + let first = baz().await; + + let guard = x.lock().unwrap(); + + let second = baz().await; + + let third = baz().await; + + first + second + third +} + +fn main() { + let m = Mutex::new(100); + good(&m); + bad(&m); + also_bad(&m); +} diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr new file mode 100644 index 00000000000..8d4fd0c20a9 --- /dev/null +++ b/tests/ui/await_holding_lock.stderr @@ -0,0 +1,35 @@ +error: this MutexGuard is held across an 'await' point + --> $DIR/await_holding_lock.rs:7:9 + | +LL | let guard = x.lock().unwrap(); + | ^^^^^ + | + = note: `-D clippy::await-holding-lock` implied by `-D warnings` +note: these are all the await points this lock is held through + --> $DIR/await_holding_lock.rs:7:5 + | +LL | / let guard = x.lock().unwrap(); +LL | | baz().await +LL | | } + | |_^ + +error: this MutexGuard is held across an 'await' point + --> $DIR/await_holding_lock.rs:28:9 + | +LL | let guard = x.lock().unwrap(); + | ^^^^^ + | +note: these are all the await points this lock is held through + --> $DIR/await_holding_lock.rs:28:5 + | +LL | / let guard = x.lock().unwrap(); +LL | | +LL | | let second = baz().await; +LL | | +... | +LL | | first + second + third +LL | | } + | |_^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From ef28361293b39b63f313aa756fce1b9c74f9eb28 Mon Sep 17 00:00:00 2001 From: David Tolnay <dtolnay@gmail.com> Date: Thu, 2 Apr 2020 17:36:49 -0700 Subject: Downgrade match_bool to pedantic --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/matches.rs | 2 +- src/lintlist/mod.rs | 2 +- tests/ui/implicit_return.fixed | 3 +-- tests/ui/implicit_return.rs | 3 +-- tests/ui/implicit_return.stderr | 16 ++++++++-------- tests/ui/match_bool.rs | 2 ++ tests/ui/match_bool.stderr | 22 +++++++++++++--------- tests/ui/needless_return.fixed | 2 +- tests/ui/needless_return.rs | 2 +- 10 files changed, 30 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dee4188b75f..f9d1ddf049c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1134,6 +1134,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), + LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), @@ -1279,7 +1280,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), - LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_SINGLE_BINDING), @@ -1470,7 +1470,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&map_clone::MAP_CLONE), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_WILD_ERR_ARM), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 270e306e15f..8f86535ef1e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -138,7 +138,7 @@ declare_clippy_lint! { /// } /// ``` pub MATCH_BOOL, - style, + pedantic, "a `match` on a boolean expression instead of an `if..else` block" } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2c466aa20c6..9b67bacc35d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1139,7 +1139,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "match_bool", - group: "style", + group: "pedantic", desc: "a `match` on a boolean expression instead of an `if..else` block", deprecation: None, module: "matches", diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index dd42f06664e..9066dc3fedf 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -21,7 +21,6 @@ fn test_if_block() -> bool { } } -#[allow(clippy::match_bool)] #[rustfmt::skip] fn test_match(x: bool) -> bool { match x { @@ -30,7 +29,7 @@ fn test_match(x: bool) -> bool { } } -#[allow(clippy::match_bool, clippy::needless_return)] +#[allow(clippy::needless_return)] fn test_match_with_unreachable(x: bool) -> bool { match x { true => return false, diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 5abbf6a5583..c0d70ecf502 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -21,7 +21,6 @@ fn test_if_block() -> bool { } } -#[allow(clippy::match_bool)] #[rustfmt::skip] fn test_match(x: bool) -> bool { match x { @@ -30,7 +29,7 @@ fn test_match(x: bool) -> bool { } } -#[allow(clippy::match_bool, clippy::needless_return)] +#[allow(clippy::needless_return)] fn test_match_with_unreachable(x: bool) -> bool { match x { true => return false, diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr index 411b98067d0..fb2ec902764 100644 --- a/tests/ui/implicit_return.stderr +++ b/tests/ui/implicit_return.stderr @@ -19,49 +19,49 @@ LL | false | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:28:17 + --> $DIR/implicit_return.rs:27:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:29:20 + --> $DIR/implicit_return.rs:28:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:44:9 + --> $DIR/implicit_return.rs:43:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:52:13 + --> $DIR/implicit_return.rs:51:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:61:13 + --> $DIR/implicit_return.rs:60:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:79:18 + --> $DIR/implicit_return.rs:78:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:80:16 + --> $DIR/implicit_return.rs:79:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:88:5 + --> $DIR/implicit_return.rs:87:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")` diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index 811aff2a8d4..9ed55ca7ae7 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -1,3 +1,5 @@ +#![deny(clippy::match_bool)] + fn match_bool() { let test: bool = true; diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index d0c20eb2696..1ad78c740c6 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/match_bool.rs:29:11 + --> $DIR/match_bool.rs:31:11 | LL | match test && test { | ^^^^^^^^^^^^ help: try: `test` @@ -7,7 +7,7 @@ LL | match test && test { = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:4:5 + --> $DIR/match_bool.rs:6:5 | LL | / match test { LL | | true => 0, @@ -15,10 +15,14 @@ LL | | false => 42, LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if test { 0 } else { 42 }` | - = note: `-D clippy::match-bool` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/match_bool.rs:1:9 + | +LL | #![deny(clippy::match_bool)] + | ^^^^^^^^^^^^^^^^^^ error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:10:5 + --> $DIR/match_bool.rs:12:5 | LL | / match option == 1 { LL | | true => 1, @@ -27,7 +31,7 @@ LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if option == 1 { 1 } else { 0 }` error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:15:5 + --> $DIR/match_bool.rs:17:5 | LL | / match test { LL | | true => (), @@ -45,7 +49,7 @@ LL | }; | error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:22:5 + --> $DIR/match_bool.rs:24:5 | LL | / match test { LL | | false => { @@ -63,7 +67,7 @@ LL | }; | error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:29:5 + --> $DIR/match_bool.rs:31:5 | LL | / match test && test { LL | | false => { @@ -81,7 +85,7 @@ LL | }; | error: equal expressions as operands to `&&` - --> $DIR/match_bool.rs:29:11 + --> $DIR/match_bool.rs:31:11 | LL | match test && test { | ^^^^^^^^^^^^ @@ -89,7 +93,7 @@ LL | match test && test { = note: `#[deny(clippy::eq_op)]` on by default error: you seem to be trying to match on a boolean expression - --> $DIR/match_bool.rs:36:5 + --> $DIR/match_bool.rs:38:5 | LL | / match test { LL | | false => { diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 70af5c19614..ad20e238107 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused, clippy::needless_bool, clippy::match_bool)] +#![allow(unused, clippy::needless_bool)] #![allow(clippy::if_same_then_else, clippy::single_match)] #![warn(clippy::needless_return)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index a1f8321ac6e..af0cdfb207f 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused, clippy::needless_bool, clippy::match_bool)] +#![allow(unused, clippy::needless_bool)] #![allow(clippy::if_same_then_else, clippy::single_match)] #![warn(clippy::needless_return)] -- cgit 1.4.1-3-g733a5 From 96e2bc80f556e54b95ae224dc2f59cfa47397a38 Mon Sep 17 00:00:00 2001 From: CrazyRoka <rokarostuk@gmail.com> Date: Fri, 24 Apr 2020 00:28:18 +0300 Subject: Added lint `match_vec_item` --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 ++ clippy_lints/src/match_vec_item.rs | 111 +++++++++++++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 +++ tests/ui/match_vec_item.rs | 109 ++++++++++++++++++++++++++++++++++++ tests/ui/match_vec_item.stderr | 27 +++++++++ 6 files changed, 260 insertions(+) create mode 100644 clippy_lints/src/match_vec_item.rs create mode 100644 tests/ui/match_vec_item.rs create mode 100644 tests/ui/match_vec_item.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index abd7167502b..3ba2c51623b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1352,6 +1352,7 @@ Released 2018-09-13 [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding +[`match_vec_item`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_vec_item [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dee4188b75f..79bf13a1005 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -249,6 +249,7 @@ mod macro_use; mod main_recursion; mod map_clone; mod map_unit_fn; +mod match_vec_item; mod matches; mod mem_discriminant; mod mem_forget; @@ -629,6 +630,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &map_clone::MAP_CLONE, &map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN, + &match_vec_item::MATCH_VEC_ITEM, &matches::INFALLIBLE_DESTRUCTURING_MATCH, &matches::MATCH_AS_REF, &matches::MATCH_BOOL, @@ -1060,6 +1062,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); + store.register_late_pass(|| box match_vec_item::MatchVecItem); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1277,6 +1280,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(&match_vec_item::MATCH_VEC_ITEM), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), LintId::of(&matches::MATCH_BOOL), @@ -1469,6 +1473,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::WHILE_LET_ON_ITERATOR), LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&map_clone::MAP_CLONE), + LintId::of(&match_vec_item::MATCH_VEC_ITEM), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), diff --git a/clippy_lints/src/match_vec_item.rs b/clippy_lints/src/match_vec_item.rs new file mode 100644 index 00000000000..7ea5a24abbd --- /dev/null +++ b/clippy_lints/src/match_vec_item.rs @@ -0,0 +1,111 @@ +use crate::utils::{is_wild, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, AdtDef}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. + /// + /// **Why is this bad?** This can panic at runtime. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust, no_run + /// let arr = vec![0, 1, 2, 3]; + /// let idx = 1; + /// + /// // Bad + /// match arr[idx] { + /// 0 => println!("{}", 0), + /// 1 => println!("{}", 3), + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust, no_run + /// let arr = vec![0, 1, 2, 3]; + /// let idx = 1; + /// + /// // Good + /// match arr.get(idx) { + /// Some(0) => println!("{}", 0), + /// Some(1) => println!("{}", 3), + /// _ => {}, + /// } + /// ``` + pub MATCH_VEC_ITEM, + style, + "match vector by indexing can panic" +} + +declare_lint_pass!(MatchVecItem => [MATCH_VEC_ITEM]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchVecItem { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if !in_external_macro(cx.sess(), expr.span); + if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind; + if contains_wild_arm(arms); + if is_vec_indexing(cx, ex); + + then { + span_lint_and_help( + cx, + MATCH_VEC_ITEM, + expr.span, + "indexing vector may panic", + None, + "consider using `get(..)` instead.", + ); + } + } + } +} + +fn contains_wild_arm(arms: &[Arm<'_>]) -> bool { + arms.iter().any(|arm| is_wild(&arm.pat) && is_unit_expr(arm.body)) +} + +fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if_chain! { + if let ExprKind::Index(ref array, _) = expr.kind; + let ty = cx.tables.expr_ty(array); + if let ty::Adt(def, _) = ty.kind; + if is_vec(cx, def); + + then { + return true; + } + } + + false +} + +fn is_vec<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, def: &'a AdtDef) -> bool { + if_chain! { + let def_path = cx.tcx.def_path(def.did); + if def_path.data.len() == 2; + if let Some(module) = def_path.data.get(0); + if module.data.as_symbol() == sym!(vec); + if let Some(name) = def_path.data.get(1); + if name.data.as_symbol() == sym!(Vec); + + then { + return true; + } + } + + false +} + +fn is_unit_expr(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Tup(ref v) if v.is_empty() => true, + ExprKind::Block(ref b, _) if b.stmts.is_empty() && b.expr.is_none() => true, + _ => false, + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 2c466aa20c6..7c9e0448950 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1172,6 +1172,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "matches", }, + Lint { + name: "match_vec_item", + group: "style", + desc: "match vector by indexing can panic", + deprecation: None, + module: "match_vec_item", + }, Lint { name: "match_wild_err_arm", group: "style", diff --git a/tests/ui/match_vec_item.rs b/tests/ui/match_vec_item.rs new file mode 100644 index 00000000000..8e7c098d75c --- /dev/null +++ b/tests/ui/match_vec_item.rs @@ -0,0 +1,109 @@ +#![warn(clippy::match_vec_item)] + +fn main() { + match_with_wildcard(); + match_without_wildcard(); + match_wildcard_and_action(); + match_with_get(); + match_with_array(); +} + +fn match_with_wildcard() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 1; + + // Lint, may panic + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => {}, + } + + // Lint, may panic + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => {}, + } +} + +fn match_without_wildcard() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 2; + + // Ok + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + num => {}, + } + + // Ok + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + [ref sub @ ..] => {}, + } +} + +fn match_wildcard_and_action() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Ok + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => println!("Hello, World!"), + } + + // Ok + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => println!("Hello, World!"), + } +} + +fn match_with_get() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Ok + match arr.get(idx) { + Some(0) => println!("0"), + Some(1) => println!("1"), + _ => {}, + } + + // Ok + match arr.get(range) { + Some(&[0, 1]) => println!("0 1"), + Some(&[1, 2]) => println!("1 2"), + _ => {}, + } +} + +fn match_with_array() { + let arr = [0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Ok + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => {}, + } + + // Ok + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => {}, + } +} diff --git a/tests/ui/match_vec_item.stderr b/tests/ui/match_vec_item.stderr new file mode 100644 index 00000000000..2494c3143f8 --- /dev/null +++ b/tests/ui/match_vec_item.stderr @@ -0,0 +1,27 @@ +error: indexing vector may panic + --> $DIR/match_vec_item.rs:17:5 + | +LL | / match arr[idx] { +LL | | 0 => println!("0"), +LL | | 1 => println!("1"), +LL | | _ => {}, +LL | | } + | |_____^ + | + = note: `-D clippy::match-vec-item` implied by `-D warnings` + = help: consider using `get(..)` instead. + +error: indexing vector may panic + --> $DIR/match_vec_item.rs:24:5 + | +LL | / match arr[range] { +LL | | [0, 1] => println!("0 1"), +LL | | [1, 2] => println!("1 2"), +LL | | _ => {}, +LL | | } + | |_____^ + | + = help: consider using `get(..)` instead. + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 63b451ea25c7797530c84b82781e0800c9bda68d Mon Sep 17 00:00:00 2001 From: CrazyRoka <RokaRostuk@gmail.com> Date: Sat, 25 Apr 2020 11:33:40 +0300 Subject: Renamed lint to `match_on_vec_items` --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 10 +-- clippy_lints/src/match_on_vec_items.rs | 88 ++++++++++++++++++++++ clippy_lints/src/match_vec_item.rs | 88 ---------------------- src/lintlist/mod.rs | 14 ++-- tests/ui/match_on_vec_items.rs | 130 +++++++++++++++++++++++++++++++++ tests/ui/match_on_vec_items.stderr | 52 +++++++++++++ tests/ui/match_vec_item.rs | 130 --------------------------------- tests/ui/match_vec_item.stderr | 52 ------------- 9 files changed, 283 insertions(+), 283 deletions(-) create mode 100644 clippy_lints/src/match_on_vec_items.rs delete mode 100644 clippy_lints/src/match_vec_item.rs create mode 100644 tests/ui/match_on_vec_items.rs create mode 100644 tests/ui/match_on_vec_items.stderr delete mode 100644 tests/ui/match_vec_item.rs delete mode 100644 tests/ui/match_vec_item.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ba2c51623b..f49980f712b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1348,11 +1348,11 @@ Released 2018-09-13 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool +[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding -[`match_vec_item`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_vec_item [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 79bf13a1005..a72fad86227 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -249,7 +249,7 @@ mod macro_use; mod main_recursion; mod map_clone; mod map_unit_fn; -mod match_vec_item; +mod match_on_vec_items; mod matches; mod mem_discriminant; mod mem_forget; @@ -630,7 +630,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &map_clone::MAP_CLONE, &map_unit_fn::OPTION_MAP_UNIT_FN, &map_unit_fn::RESULT_MAP_UNIT_FN, - &match_vec_item::MATCH_VEC_ITEM, + &match_on_vec_items::MATCH_ON_VEC_ITEMS, &matches::INFALLIBLE_DESTRUCTURING_MATCH, &matches::MATCH_AS_REF, &matches::MATCH_BOOL, @@ -1062,7 +1062,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); - store.register_late_pass(|| box match_vec_item::MatchVecItem); + store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1280,7 +1280,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&map_clone::MAP_CLONE), LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(&match_vec_item::MATCH_VEC_ITEM), + LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_AS_REF), LintId::of(&matches::MATCH_BOOL), @@ -1473,7 +1473,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::WHILE_LET_ON_ITERATOR), LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&map_clone::MAP_CLONE), - LintId::of(&match_vec_item::MATCH_VEC_ITEM), + LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs new file mode 100644 index 00000000000..167b4abd93d --- /dev/null +++ b/clippy_lints/src/match_on_vec_items.rs @@ -0,0 +1,88 @@ +use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. + /// + /// **Why is this bad?** This can panic at runtime. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust, no_run + /// let arr = vec![0, 1, 2, 3]; + /// let idx = 1; + /// + /// // Bad + /// match arr[idx] { + /// 0 => println!("{}", 0), + /// 1 => println!("{}", 3), + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust, no_run + /// let arr = vec![0, 1, 2, 3]; + /// let idx = 1; + /// + /// // Good + /// match arr.get(idx) { + /// Some(0) => println!("{}", 0), + /// Some(1) => println!("{}", 3), + /// _ => {}, + /// } + /// ``` + pub MATCH_ON_VEC_ITEMS, + style, + "matching on vector elements can panic" +} + +declare_lint_pass!(MatchOnVecItems => [MATCH_ON_VEC_ITEMS]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchOnVecItems { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if !in_external_macro(cx.sess(), expr.span); + if let ExprKind::Match(ref match_expr, _, MatchSource::Normal) = expr.kind; + if let Some(idx_expr) = is_vec_indexing(cx, match_expr); + if let ExprKind::Index(vec, idx) = idx_expr.kind; + + then { + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + MATCH_ON_VEC_ITEMS, + match_expr.span, + "indexing vector may panic. Consider using `get`", + "try this", + format!( + "{}.get({})", + snippet_with_applicability(cx, vec.span, "..", &mut applicability), + snippet_with_applicability(cx, idx.span, "..", &mut applicability) + ), + applicability + ); + } + } + } +} + +fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + if_chain! { + if let ExprKind::Index(ref array, _) = expr.kind; + let ty = cx.tables.expr_ty(array); + let ty = walk_ptrs_ty(ty); + if is_type_diagnostic_item(cx, ty, sym!(vec_type)); + + then { + return Some(expr); + } + } + + None +} diff --git a/clippy_lints/src/match_vec_item.rs b/clippy_lints/src/match_vec_item.rs deleted file mode 100644 index 07121dedefe..00000000000 --- a/clippy_lints/src/match_vec_item.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, MatchSource}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. - /// - /// **Why is this bad?** This can panic at runtime. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust, no_run - /// let arr = vec![0, 1, 2, 3]; - /// let idx = 1; - /// - /// // Bad - /// match arr[idx] { - /// 0 => println!("{}", 0), - /// 1 => println!("{}", 3), - /// _ => {}, - /// } - /// ``` - /// Use instead: - /// ```rust, no_run - /// let arr = vec![0, 1, 2, 3]; - /// let idx = 1; - /// - /// // Good - /// match arr.get(idx) { - /// Some(0) => println!("{}", 0), - /// Some(1) => println!("{}", 3), - /// _ => {}, - /// } - /// ``` - pub MATCH_VEC_ITEM, - style, - "match vector by indexing can panic" -} - -declare_lint_pass!(MatchVecItem => [MATCH_VEC_ITEM]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchVecItem { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if !in_external_macro(cx.sess(), expr.span); - if let ExprKind::Match(ref match_expr, _, MatchSource::Normal) = expr.kind; - if let Some(idx_expr) = is_vec_indexing(cx, match_expr); - if let ExprKind::Index(vec, idx) = idx_expr.kind; - - then { - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - MATCH_VEC_ITEM, - match_expr.span, - "indexing vector may panic. Consider using `get`", - "try this", - format!( - "{}.get({})", - snippet_with_applicability(cx, vec.span, "..", &mut applicability), - snippet_with_applicability(cx, idx.span, "..", &mut applicability) - ), - applicability - ); - } - } - } -} - -fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { - if_chain! { - if let ExprKind::Index(ref array, _) = expr.kind; - let ty = cx.tables.expr_ty(array); - let ty = walk_ptrs_ty(ty); - if is_type_diagnostic_item(cx, ty, sym!(vec_type)); - - then { - return Some(expr); - } - } - - None -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 7c9e0448950..17f94411298 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1144,6 +1144,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "matches", }, + Lint { + name: "match_on_vec_items", + group: "style", + desc: "matching on vector elements can panic", + deprecation: None, + module: "match_on_vec_items", + }, Lint { name: "match_overlapping_arm", group: "style", @@ -1172,13 +1179,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "matches", }, - Lint { - name: "match_vec_item", - group: "style", - desc: "match vector by indexing can panic", - deprecation: None, - module: "match_vec_item", - }, Lint { name: "match_wild_err_arm", group: "style", diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs new file mode 100644 index 00000000000..02b6da03439 --- /dev/null +++ b/tests/ui/match_on_vec_items.rs @@ -0,0 +1,130 @@ +#![warn(clippy::match_on_vec_items)] + +fn main() { + match_with_wildcard(); + match_without_wildcard(); + match_wildcard_and_action(); + match_vec_ref(); + match_with_get(); + match_with_array(); +} + +fn match_with_wildcard() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 1; + + // Lint, may panic + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => {}, + } + + // Lint, may panic + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => {}, + } +} + +fn match_without_wildcard() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 2; + + // Lint, may panic + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + num => {}, + } + + // Lint, may panic + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + [ref sub @ ..] => {}, + } +} + +fn match_wildcard_and_action() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Lint, may panic + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => println!("Hello, World!"), + } + + // Lint, may panic + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => println!("Hello, World!"), + } +} + +fn match_vec_ref() { + let arr = &vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Lint, may panic + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => {}, + } + + // Lint, may panic + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => {}, + } +} + +fn match_with_get() { + let arr = vec![0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Ok + match arr.get(idx) { + Some(0) => println!("0"), + Some(1) => println!("1"), + _ => {}, + } + + // Ok + match arr.get(range) { + Some(&[0, 1]) => println!("0 1"), + Some(&[1, 2]) => println!("1 2"), + _ => {}, + } +} + +fn match_with_array() { + let arr = [0, 1, 2, 3]; + let range = 1..3; + let idx = 3; + + // Ok + match arr[idx] { + 0 => println!("0"), + 1 => println!("1"), + _ => {}, + } + + // Ok + match arr[range] { + [0, 1] => println!("0 1"), + [1, 2] => println!("1 2"), + _ => {}, + } +} diff --git a/tests/ui/match_on_vec_items.stderr b/tests/ui/match_on_vec_items.stderr new file mode 100644 index 00000000000..0e53a58f141 --- /dev/null +++ b/tests/ui/match_on_vec_items.stderr @@ -0,0 +1,52 @@ +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:18:11 + | +LL | match arr[idx] { + | ^^^^^^^^ help: try this: `arr.get(idx)` + | + = note: `-D clippy::match-on-vec-items` implied by `-D warnings` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:25:11 + | +LL | match arr[range] { + | ^^^^^^^^^^ help: try this: `arr.get(range)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:38:11 + | +LL | match arr[idx] { + | ^^^^^^^^ help: try this: `arr.get(idx)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:45:11 + | +LL | match arr[range] { + | ^^^^^^^^^^ help: try this: `arr.get(range)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:58:11 + | +LL | match arr[idx] { + | ^^^^^^^^ help: try this: `arr.get(idx)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:65:11 + | +LL | match arr[range] { + | ^^^^^^^^^^ help: try this: `arr.get(range)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:78:11 + | +LL | match arr[idx] { + | ^^^^^^^^ help: try this: `arr.get(idx)` + +error: indexing vector may panic. Consider using `get` + --> $DIR/match_on_vec_items.rs:85:11 + | +LL | match arr[range] { + | ^^^^^^^^^^ help: try this: `arr.get(range)` + +error: aborting due to 8 previous errors + diff --git a/tests/ui/match_vec_item.rs b/tests/ui/match_vec_item.rs deleted file mode 100644 index d00d0bc2fe5..00000000000 --- a/tests/ui/match_vec_item.rs +++ /dev/null @@ -1,130 +0,0 @@ -#![warn(clippy::match_vec_item)] - -fn main() { - match_with_wildcard(); - match_without_wildcard(); - match_wildcard_and_action(); - match_vec_ref(); - match_with_get(); - match_with_array(); -} - -fn match_with_wildcard() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 1; - - // Lint, may panic - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Lint, may panic - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} - -fn match_without_wildcard() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 2; - - // Lint, may panic - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - num => {}, - } - - // Lint, may panic - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - [ref sub @ ..] => {}, - } -} - -fn match_wildcard_and_action() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Lint, may panic - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - _ => println!("Hello, World!"), - } - - // Lint, may panic - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => println!("Hello, World!"), - } -} - -fn match_vec_ref() { - let arr = &vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Lint, may panic - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Lint, may panic - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} - -fn match_with_get() { - let arr = vec![0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Ok - match arr.get(idx) { - Some(0) => println!("0"), - Some(1) => println!("1"), - _ => {}, - } - - // Ok - match arr.get(range) { - Some(&[0, 1]) => println!("0 1"), - Some(&[1, 2]) => println!("1 2"), - _ => {}, - } -} - -fn match_with_array() { - let arr = [0, 1, 2, 3]; - let range = 1..3; - let idx = 3; - - // Ok - match arr[idx] { - 0 => println!("0"), - 1 => println!("1"), - _ => {}, - } - - // Ok - match arr[range] { - [0, 1] => println!("0 1"), - [1, 2] => println!("1 2"), - _ => {}, - } -} diff --git a/tests/ui/match_vec_item.stderr b/tests/ui/match_vec_item.stderr deleted file mode 100644 index 2da2eaeee9b..00000000000 --- a/tests/ui/match_vec_item.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:18:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` - | - = note: `-D clippy::match-vec-item` implied by `-D warnings` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:25:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:38:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:45:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:58:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:65:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:78:11 - | -LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` - -error: indexing vector may panic. Consider using `get` - --> $DIR/match_vec_item.rs:85:11 - | -LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` - -error: aborting due to 8 previous errors - -- cgit 1.4.1-3-g733a5 From b574941dcbf34b529b5c1eb1fa75ca6b1496b666 Mon Sep 17 00:00:00 2001 From: CrazyRoka <RokaRostuk@gmail.com> Date: Sun, 26 Apr 2020 18:11:21 +0300 Subject: Updated lint info in lib.rs --- clippy_lints/src/lib.rs | 2 +- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a72fad86227..f7d8314ccee 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1473,7 +1473,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::WHILE_LET_ON_ITERATOR), LintId::of(&main_recursion::MAIN_RECURSION), LintId::of(&map_clone::MAP_CLONE), - LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_OVERLAPPING_ARM), @@ -1646,6 +1645,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::NEVER_LOOP), LintId::of(&loops::REVERSE_RANGE_LOOP), LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::CLONE_DOUBLE_REF), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 17f94411298..fbcf4fde5e5 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1146,7 +1146,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "match_on_vec_items", - group: "style", + group: "correctness", desc: "matching on vector elements can panic", deprecation: None, module: "match_on_vec_items", -- cgit 1.4.1-3-g733a5 From 149f6d6046013619bc5a600341eee3ce2b6df9a6 Mon Sep 17 00:00:00 2001 From: Eduardo Broto <ebroto@tutanota.com> Date: Wed, 22 Apr 2020 23:01:25 +0200 Subject: Implement mismatched_target_os lint --- CHANGELOG.md | 1 + clippy_lints/src/attrs.rs | 157 +++++++++++++++++++++++++++++------ clippy_lints/src/lib.rs | 5 +- src/lintlist/mod.rs | 7 ++ tests/ui/mismatched_target_os.fixed | 41 +++++++++ tests/ui/mismatched_target_os.rs | 41 +++++++++ tests/ui/mismatched_target_os.stderr | 83 ++++++++++++++++++ 7 files changed, 307 insertions(+), 28 deletions(-) create mode 100644 tests/ui/mismatched_target_os.fixed create mode 100644 tests/ui/mismatched_target_os.rs create mode 100644 tests/ui/mismatched_target_os.stderr (limited to 'src') diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aab249621c..847a8d86e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1444,6 +1444,7 @@ Released 2018-09-13 [`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit [`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 6768501145d..7cdc3aa0145 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -20,6 +20,30 @@ use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; use semver::Version; +// NOTE: windows is excluded from the list because it's also a valid target family. +static OPERATING_SYSTEMS: &[&str] = &[ + "android", + "cloudabi", + "dragonfly", + "emscripten", + "freebsd", + "fuchsia", + "haiku", + "hermit", + "illumos", + "ios", + "l4re", + "linux", + "macos", + "netbsd", + "none", + "openbsd", + "redox", + "solaris", + "vxworks", + "wasi", +]; + declare_clippy_lint! { /// **What it does:** Checks for items annotated with `#[inline(always)]`, /// unless the annotated function is empty or simply panics. @@ -189,6 +213,38 @@ declare_clippy_lint! { "usage of `cfg_attr(rustfmt)` instead of tool attributes" } +declare_clippy_lint! { + /// **What it does:** Checks for cfg attributes having operating systems used in target family position. + /// + /// **Why is this bad?** The configuration option will not be recognised and the related item will not be included + /// by the conditional compilation engine. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// Bad: + /// ```rust + /// #[cfg(linux)] + /// fn conditional() { } + /// ``` + /// + /// Good: + /// ```rust + /// #[cfg(target_os = "linux")] + /// fn conditional() { } + /// ``` + /// + /// Or: + /// ```rust + /// #[cfg(unix)] + /// fn conditional() { } + /// ``` + pub MISMATCHED_TARGET_OS, + correctness, + "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" +} + declare_lint_pass!(Attributes => [ INLINE_ALWAYS, DEPRECATED_SEMVER, @@ -496,35 +552,82 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { } } -declare_lint_pass!(DeprecatedCfgAttribute => [DEPRECATED_CFG_ATTR]); +declare_lint_pass!(EarlyAttributes => [DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS]); -impl EarlyLintPass for DeprecatedCfgAttribute { +impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { - if_chain! { - // check cfg_attr - if attr.check_name(sym!(cfg_attr)); - if let Some(items) = attr.meta_item_list(); - if items.len() == 2; - // check for `rustfmt` - if let Some(feature_item) = items[0].meta_item(); - if feature_item.check_name(sym!(rustfmt)); - // check for `rustfmt_skip` and `rustfmt::skip` - if let Some(skip_item) = &items[1].meta_item(); - if skip_item.check_name(sym!(rustfmt_skip)) || - skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym!(skip); - // Only lint outer attributes, because custom inner attributes are unstable - // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - if let AttrStyle::Outer = attr.style; - then { - span_lint_and_sugg( - cx, - DEPRECATED_CFG_ATTR, - attr.span, - "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", - "use", - "#[rustfmt::skip]".to_string(), - Applicability::MachineApplicable, - ); + check_deprecated_cfg_attr(cx, attr); + check_mismatched_target_os(cx, attr); + } +} + +fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { + if_chain! { + // check cfg_attr + if attr.check_name(sym!(cfg_attr)); + if let Some(items) = attr.meta_item_list(); + if items.len() == 2; + // check for `rustfmt` + if let Some(feature_item) = items[0].meta_item(); + if feature_item.check_name(sym!(rustfmt)); + // check for `rustfmt_skip` and `rustfmt::skip` + if let Some(skip_item) = &items[1].meta_item(); + if skip_item.check_name(sym!(rustfmt_skip)) || + skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym!(skip); + // Only lint outer attributes, because custom inner attributes are unstable + // Tracking issue: https://github.com/rust-lang/rust/issues/54726 + if let AttrStyle::Outer = attr.style; + then { + span_lint_and_sugg( + cx, + DEPRECATED_CFG_ATTR, + attr.span, + "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", + "use", + "#[rustfmt::skip]".to_string(), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { + fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> { + let mut mismatched = Vec::new(); + for item in items { + if let NestedMetaItem::MetaItem(meta) = item { + match &meta.kind { + MetaItemKind::List(list) => { + mismatched.extend(find_mismatched_target_os(&list)); + }, + MetaItemKind::Word => { + if let Some(ident) = meta.ident() { + let name = &*ident.name.as_str(); + if let Some(os) = OPERATING_SYSTEMS.iter().find(|&&os| os == name) { + mismatched.push((os, ident.span)); + } + } + }, + _ => {}, + } + } + } + mismatched + } + + if_chain! { + if attr.check_name(sym!(cfg)); + if let Some(list) = attr.meta_item_list(); + then { + let mismatched = find_mismatched_target_os(&list); + for (os, span) in mismatched { + let mess = format!("`{}` is not a valid target family", os); + let sugg = format!("target_os = \"{}\"", os); + + span_lint_and_then(cx, MISMATCHED_TARGET_OS, span, &mess, |diag| { + diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); + diag.help("Did you mean `unix`?"); + }); } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ac867cc4e4a..4daaf9a9820 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -350,7 +350,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &Co store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, }); - store.register_pre_expansion_pass(|| box attrs::DeprecatedCfgAttribute); + store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); } @@ -496,6 +496,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &attrs::DEPRECATED_SEMVER, &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, &attrs::INLINE_ALWAYS, + &attrs::MISMATCHED_TARGET_OS, &attrs::UNKNOWN_CLIPPY_LINTS, &attrs::USELESS_ATTRIBUTE, &await_holding_lock::AWAIT_HOLDING_LOCK, @@ -1190,6 +1191,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_CFG_ATTR), LintId::of(&attrs::DEPRECATED_SEMVER), + LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&attrs::USELESS_ATTRIBUTE), LintId::of(&bit_mask::BAD_BIT_MASK), @@ -1610,6 +1612,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&approx_const::APPROX_CONSTANT), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_SEMVER), + LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::USELESS_ATTRIBUTE), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9b67bacc35d..c6c388ee9f0 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1228,6 +1228,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ deprecation: None, module: "minmax", }, + Lint { + name: "mismatched_target_os", + group: "correctness", + desc: "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`", + deprecation: None, + module: "attrs", + }, Lint { name: "misrefactored_assign_op", group: "complexity", diff --git a/tests/ui/mismatched_target_os.fixed b/tests/ui/mismatched_target_os.fixed new file mode 100644 index 00000000000..b68b0e449e7 --- /dev/null +++ b/tests/ui/mismatched_target_os.fixed @@ -0,0 +1,41 @@ +// run-rustfix + +#![warn(clippy::mismatched_target_os)] +#![allow(unused)] + +#[cfg(target_os = "linux")] +fn linux() {} + +#[cfg(target_os = "freebsd")] +fn freebsd() {} + +#[cfg(target_os = "dragonfly")] +fn dragonfly() {} + +#[cfg(target_os = "openbsd")] +fn openbsd() {} + +#[cfg(target_os = "netbsd")] +fn netbsd() {} + +#[cfg(target_os = "macos")] +fn macos() {} + +#[cfg(target_os = "ios")] +fn ios() {} + +#[cfg(target_os = "android")] +fn android() {} + +#[cfg(all(not(any(windows, target_os = "linux")), target_os = "freebsd"))] +fn list() {} + +// windows is a valid target family, should be ignored +#[cfg(windows)] +fn windows() {} + +// correct use, should be ignored +#[cfg(target_os = "freebsd")] +fn freebsd() {} + +fn main() {} diff --git a/tests/ui/mismatched_target_os.rs b/tests/ui/mismatched_target_os.rs new file mode 100644 index 00000000000..deeb547e99a --- /dev/null +++ b/tests/ui/mismatched_target_os.rs @@ -0,0 +1,41 @@ +// run-rustfix + +#![warn(clippy::mismatched_target_os)] +#![allow(unused)] + +#[cfg(linux)] +fn linux() {} + +#[cfg(freebsd)] +fn freebsd() {} + +#[cfg(dragonfly)] +fn dragonfly() {} + +#[cfg(openbsd)] +fn openbsd() {} + +#[cfg(netbsd)] +fn netbsd() {} + +#[cfg(macos)] +fn macos() {} + +#[cfg(ios)] +fn ios() {} + +#[cfg(android)] +fn android() {} + +#[cfg(all(not(any(windows, linux)), freebsd))] +fn list() {} + +// windows is a valid target family, should be ignored +#[cfg(windows)] +fn windows() {} + +// correct use, should be ignored +#[cfg(target_os = "freebsd")] +fn freebsd() {} + +fn main() {} diff --git a/tests/ui/mismatched_target_os.stderr b/tests/ui/mismatched_target_os.stderr new file mode 100644 index 00000000000..bb14061dff9 --- /dev/null +++ b/tests/ui/mismatched_target_os.stderr @@ -0,0 +1,83 @@ +error: `linux` is not a valid target family + --> $DIR/mismatched_target_os.rs:6:7 + | +LL | #[cfg(linux)] + | ^^^^^ help: try: `target_os = "linux"` + | + = note: `-D clippy::mismatched-target-os` implied by `-D warnings` + = help: Did you mean `unix`? + +error: `freebsd` is not a valid target family + --> $DIR/mismatched_target_os.rs:9:7 + | +LL | #[cfg(freebsd)] + | ^^^^^^^ help: try: `target_os = "freebsd"` + | + = help: Did you mean `unix`? + +error: `dragonfly` is not a valid target family + --> $DIR/mismatched_target_os.rs:12:7 + | +LL | #[cfg(dragonfly)] + | ^^^^^^^^^ help: try: `target_os = "dragonfly"` + | + = help: Did you mean `unix`? + +error: `openbsd` is not a valid target family + --> $DIR/mismatched_target_os.rs:15:7 + | +LL | #[cfg(openbsd)] + | ^^^^^^^ help: try: `target_os = "openbsd"` + | + = help: Did you mean `unix`? + +error: `netbsd` is not a valid target family + --> $DIR/mismatched_target_os.rs:18:7 + | +LL | #[cfg(netbsd)] + | ^^^^^^ help: try: `target_os = "netbsd"` + | + = help: Did you mean `unix`? + +error: `macos` is not a valid target family + --> $DIR/mismatched_target_os.rs:21:7 + | +LL | #[cfg(macos)] + | ^^^^^ help: try: `target_os = "macos"` + | + = help: Did you mean `unix`? + +error: `ios` is not a valid target family + --> $DIR/mismatched_target_os.rs:24:7 + | +LL | #[cfg(ios)] + | ^^^ help: try: `target_os = "ios"` + | + = help: Did you mean `unix`? + +error: `android` is not a valid target family + --> $DIR/mismatched_target_os.rs:27:7 + | +LL | #[cfg(android)] + | ^^^^^^^ help: try: `target_os = "android"` + | + = help: Did you mean `unix`? + +error: `linux` is not a valid target family + --> $DIR/mismatched_target_os.rs:30:28 + | +LL | #[cfg(all(not(any(windows, linux)), freebsd))] + | ^^^^^ help: try: `target_os = "linux"` + | + = help: Did you mean `unix`? + +error: `freebsd` is not a valid target family + --> $DIR/mismatched_target_os.rs:30:37 + | +LL | #[cfg(all(not(any(windows, linux)), freebsd))] + | ^^^^^^^ help: try: `target_os = "freebsd"` + | + = help: Did you mean `unix`? + +error: aborting due to 10 previous errors + -- cgit 1.4.1-3-g733a5 From a1824505d8ddada2598356eaeace3ae17ee5ec30 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Wed, 1 Apr 2020 13:18:06 +0200 Subject: Gate on clippy on CI --- src/bootstrap/dist.rs | 77 ++++++++++++++++++------------------------------ src/bootstrap/install.rs | 6 ++-- src/bootstrap/test.rs | 4 +-- src/bootstrap/tool.rs | 6 ++-- 4 files changed, 33 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8215211ea1c..bae90411496 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1330,7 +1330,7 @@ pub struct Clippy { } impl Step for Clippy { - type Output = Option<PathBuf>; + type Output = PathBuf; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1348,7 +1348,7 @@ impl Step for Clippy { }); } - fn run(self, builder: &Builder<'_>) -> Option<PathBuf> { + fn run(self, builder: &Builder<'_>) -> PathBuf { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -1368,16 +1368,10 @@ impl Step for Clippy { // state for clippy isn't testing. let clippy = builder .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() }) - .or_else(|| { - missing_tool("clippy", builder.build.config.missing_tools); - None - })?; + .expect("clippy expected to build - essential tool"); let cargoclippy = builder .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() }) - .or_else(|| { - missing_tool("cargo clippy", builder.build.config.missing_tools); - None - })?; + .expect("clippy expected to build - essential tool"); builder.install(&clippy, &image.join("bin"), 0o755); builder.install(&cargoclippy, &image.join("bin"), 0o755); @@ -1416,7 +1410,7 @@ impl Step for Clippy { builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target)); let _time = timeit(builder); builder.run(&mut cmd); - Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } } @@ -1683,7 +1677,7 @@ impl Step for Extended { tarballs.push(rustc_installer); tarballs.push(cargo_installer); tarballs.extend(rls_installer.clone()); - tarballs.extend(clippy_installer.clone()); + tarballs.push(clippy_installer); tarballs.extend(miri_installer.clone()); tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer); @@ -1761,9 +1755,6 @@ impl Step for Extended { if rls_installer.is_none() { contents = filter(&contents, "rls"); } - if clippy_installer.is_none() { - contents = filter(&contents, "clippy"); - } if miri_installer.is_none() { contents = filter(&contents, "miri"); } @@ -1805,13 +1796,11 @@ impl Step for Extended { prepare("rust-docs"); prepare("rust-std"); prepare("rust-analysis"); + prepare("clippy"); if rls_installer.is_some() { prepare("rls"); } - if clippy_installer.is_some() { - prepare("clippy"); - } if miri_installer.is_some() { prepare("miri"); } @@ -1863,12 +1852,10 @@ impl Step for Extended { prepare("rust-analysis"); prepare("rust-docs"); prepare("rust-std"); + prepare("clippy"); if rls_installer.is_some() { prepare("rls"); } - if clippy_installer.is_some() { - prepare("clippy"); - } if miri_installer.is_some() { prepare("miri"); } @@ -1989,25 +1976,23 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")), ); } - if clippy_installer.is_some() { - builder.run( - Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("clippy") - .args(&heat_flags) - .arg("-cg") - .arg("ClippyGroup") - .arg("-dr") - .arg("Clippy") - .arg("-var") - .arg("var.ClippyDir") - .arg("-out") - .arg(exe.join("ClippyGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - } + builder.run( + Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("clippy") + .args(&heat_flags) + .arg("-cg") + .arg("ClippyGroup") + .arg("-dr") + .arg("Clippy") + .arg("-var") + .arg("var.ClippyDir") + .arg("-out") + .arg(exe.join("ClippyGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")), + ); if miri_installer.is_some() { builder.run( Command::new(&heat) @@ -2073,6 +2058,7 @@ impl Step for Extended { .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-dAnalysisDir=rust-analysis") + .arg("-dClippyDir=clippy") .arg("-arch") .arg(&arch) .arg("-out") @@ -2083,9 +2069,6 @@ impl Step for Extended { if rls_installer.is_some() { cmd.arg("-dRlsDir=rls"); } - if clippy_installer.is_some() { - cmd.arg("-dClippyDir=clippy"); - } if miri_installer.is_some() { cmd.arg("-dMiriDir=miri"); } @@ -2101,12 +2084,10 @@ impl Step for Extended { candle("DocsGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); + candle("ClippyGroup.wxs".as_ref()); if rls_installer.is_some() { candle("RlsGroup.wxs".as_ref()); } - if clippy_installer.is_some() { - candle("ClippyGroup.wxs".as_ref()); - } if miri_installer.is_some() { candle("MiriGroup.wxs".as_ref()); } @@ -2138,14 +2119,12 @@ impl Step for Extended { .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .arg("AnalysisGroup.wixobj") + .arg("ClippyGroup.wixobj") .current_dir(&exe); if rls_installer.is_some() { cmd.arg("RlsGroup.wixobj"); } - if clippy_installer.is_some() { - cmd.arg("ClippyGroup.wixobj"); - } if miri_installer.is_some() { cmd.arg("MiriGroup.wixobj"); } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 6549262811b..fafd3cdf927 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -214,10 +214,8 @@ install!((self, builder, _config), } }; Clippy, "clippy", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Clippy { - compiler: self.compiler, - target: self.target, - }).is_some() || Self::should_install(builder) { + builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target }); + if Self::should_install(builder) { install_clippy(builder, self.compiler.stage, self.target); } else { builder.info( diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 125563b7b60..90b8b5eea94 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -548,9 +548,7 @@ impl Step for Clippy { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(builder, &mut cargo.into()) { - builder.save_toolstate("clippy-driver", ToolState::TestPass); - } + try_run(builder, &mut cargo.into()); } else { eprintln!("failed to test clippy: could not build"); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index f756b1235ab..8ebad95ea17 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -652,14 +652,12 @@ tool_extended!((self, builder), Miri, miri, "src/tools/miri", "miri", {}; CargoMiri, miri, "src/tools/miri", "cargo-miri", {}; Rls, rls, "src/tools/rls", "rls", { - let clippy = builder.ensure(Clippy { + builder.ensure(Clippy { compiler: self.compiler, target: self.target, extra_features: Vec::new(), }); - if clippy.is_some() { - self.extra_features.push("clippy".to_owned()); - } + self.extra_features.push("clippy".to_owned()); }; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; ); -- cgit 1.4.1-3-g733a5 From 1ef5a93af69f0cce59ed54591635cdf46028ff74 Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Wed, 1 Apr 2020 15:57:48 +0200 Subject: Also build clippy with `./x.py check` --- src/bootstrap/builder.rs | 2 +- src/bootstrap/check.rs | 142 ++++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 69 deletions(-) (limited to 'src') diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4a664205bff..b77b1b0d20a 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -351,7 +351,7 @@ impl<'a> Builder<'a> { native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { - describe!(check::Std, check::Rustc, check::Rustdoc) + describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy) } Kind::Test => describe!( crate::toolstate::ToolStateCheck, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 586a362b5e3..7a8bfb2d5d8 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -112,83 +112,89 @@ impl Step for Rustc { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rustdoc { - pub target: Interned<String>, +macro_rules! tool_check_step { + ($name:ident, $path:expr) => { + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub struct $name { + pub target: Interned<String>, + } + + impl Step for $name { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path($path) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure($name { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let compiler = builder.compiler(0, builder.config.build); + let target = self.target; + + builder.ensure(Rustc { target }); + + let cargo = prepare_tool_cargo( + builder, + compiler, + Mode::ToolRustc, + target, + cargo_subcommand(builder.kind), + $path, + SourceType::InTree, + &[], + ); + + println!( + "Checking {} artifacts ({} -> {})", + stringify!($name).to_lowercase(), + &compiler.host, + target + ); + run_cargo( + builder, + cargo, + args(builder.kind), + &stamp(builder, compiler, target), + vec![], + true, + ); + + let libdir = builder.sysroot_libdir(compiler, target); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target)); + + /// Cargo's output path in a given stage, compiled by a particular + /// compiler for the specified target. + fn stamp( + builder: &Builder<'_>, + compiler: Compiler, + target: Interned<String>, + ) -> PathBuf { + builder + .cargo_out(compiler, Mode::ToolRustc, target) + .join(format!(".{}-check.stamp", stringify!($name).to_lowercase())) + } + } + } + }; } -impl Step for Rustdoc { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rustdoc") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustdoc { target: run.target }); - } - - fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); - let target = self.target; - - builder.ensure(Rustc { target }); - - let cargo = prepare_tool_cargo( - builder, - compiler, - Mode::ToolRustc, - target, - cargo_subcommand(builder.kind), - "src/tools/rustdoc", - SourceType::InTree, - &[], - ); - - println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); - run_cargo( - builder, - cargo, - args(builder.kind), - &rustdoc_stamp(builder, compiler, target), - vec![], - true, - ); - - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(&builder, &libdir, &hostdir, &rustdoc_stamp(builder, compiler, target)); - } -} +tool_check_step!(Rustdoc, "src/tools/rustdoc"); +tool_check_step!(Clippy, "src/tools/clippy"); /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -pub fn libstd_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned<String>, -) -> PathBuf { +fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. -pub fn librustc_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned<String>, -) -> PathBuf { +fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf { builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp") } - -/// Cargo's output path for rustdoc in a given stage, compiled by a particular -/// compiler for the specified target. -pub fn rustdoc_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned<String>, -) -> PathBuf { - builder.cargo_out(compiler, Mode::ToolRustc, target).join(".rustdoc-check.stamp") -} -- cgit 1.4.1-3-g733a5 From 06c44816c1532e5ff08ad072f581fc068eb60e2e Mon Sep 17 00:00:00 2001 From: Oliver Scherer <github35764891676564198441@oli-obk.de> Date: Wed, 1 Apr 2020 12:27:30 +0200 Subject: Delete the clippy submodule --- .gitmodules | 3 --- src/tools/clippy | 1 - 2 files changed, 4 deletions(-) delete mode 160000 src/tools/clippy (limited to 'src') diff --git a/.gitmodules b/.gitmodules index b2b580d08bc..5f2e8272cd2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,9 +16,6 @@ [submodule "src/tools/rls"] path = src/tools/rls url = https://github.com/rust-lang/rls.git -[submodule "src/tools/clippy"] - path = src/tools/clippy - url = https://github.com/rust-lang/rust-clippy.git [submodule "src/tools/rustfmt"] path = src/tools/rustfmt url = https://github.com/rust-lang/rustfmt.git diff --git a/src/tools/clippy b/src/tools/clippy deleted file mode 160000 index 28197b62261..00000000000 --- a/src/tools/clippy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 28197b622611ba3a6367648974ccf59127c287bb -- cgit 1.4.1-3-g733a5